class BackgroundOption(dictobj.Spec): type = dictobj.Field(sb.string_choice_spec(["specified", "current"]), default="specified") hue = dictobj.Field(sb.float_spec, default=0) saturation = dictobj.Field(sb.float_spec, default=0) brightness = dictobj.Field(sb.float_spec, default=0) kelvin = dictobj.Field(sb.float_spec, default=3500) @property def default_color(self): return Color(self.hue, self.saturation, self.brightness, self.kelvin)
class TileGameOfLifeOptions(AnimationOptions): user_coords = dictobj.Field(sb.boolean, default=True) num_iterations = dictobj.Field(sb.integer_spec, default=-1) new_color_style = dictobj.Field(sb.string_choice_spec( ["random", "average"]), default="average") iteration_delay = dictobj.Field(sb.float_spec, default=0.1) def final_iteration(self, iteration): if self.num_iterations == -1: return False return self.num_iterations <= iteration def make_new_color(self, surrounding): if self.new_color_style == "random": return Color(random.randrange(0, 360), 1, 1, 3500) else: return Color.average(surrounding)
class Options(dictobj.Spec): changer = dictobj.Field(lambda: sb.string_choice_spec(list(changers)), default="vertical_morph") brightness = dictobj.Field(sb.float_spec, default=0.5) saturation = dictobj.Field(sb.float_spec, default=1)
self.assertSignature(sb.integer_spec(), "integer") it "knows about float_spec": self.assertSignature(sb.float_spec(), "float") it "knows about string_spec": self.assertSignature(sb.string_spec(), "string") it "knows about boolean": self.assertSignature(sb.boolean(), "boolean") it "knows about dictionary_spec": self.assertSignature(sb.dictionary_spec(), "dictionary") it "knows about string_choice_spec": self.assertSignature(sb.string_choice_spec(["one", "two"]), "choice of (one | two)") it "knows about optional_spec": self.assertSignature(sb.optional_spec(sb.integer_spec()), "integer (optional)") self.assertSignature(sb.optional_spec(sb.any_spec()), "(optional)") it "knows about defaulted": self.assertSignature(sb.defaulted(sb.integer_spec(), 20), "integer (default 20)") self.assertSignature(sb.defaulted(sb.any_spec(), True), "(default True)") it "knows about required": self.assertSignature(sb.required(sb.integer_spec()), "integer (required)") self.assertSignature(sb.required(sb.any_spec()), "(required)") it "knows about listof": self.assertSignature(sb.listof(sb.integer_spec()), "[ integer , ... ]")
class PresetAnimation(dictobj.Spec): animation = dictobj.Field(sb.string_choice_spec( list(dict(Animations.animators()))), wrapper=sb.required) options = dictobj.Field(sb.dictionary_spec())
def normalise_filled(self, meta, val): animations = meta.everything["animations"] available = list(animations.presets) + list(animations.animators) return sb.string_choice_spec(available).normalise(meta, val)
def normalise_filled(self, meta, val): val = sb.string_choice_spec(list(palettes)).normalise(meta, val) return palettes[val]
class RunOptions(dictobj.Spec): pauser = dictobj.Field( semaphore_spec, help="A semaphore that when set will pause the animation", ) combined = dictobj.Field( sb.boolean, default=True, help="Whether to join all found tiles into one animation") reinstate_on_end = dictobj.Field( sb.boolean, default=False, help= "Whether to return the tiles to how they were before the animation", ) reinstate_duration = dictobj.Field( sb.float_spec, default=1, help="The duration used when reinstating state") noisy_network = dictobj.Field( noisy_network_spec(), help=""" If this value is non 0, then we assume the network is a noisy network and we'll make some effort to make sure the tiles can keep up. The number provided is the max number of messages per device that is "inflight" before we drop messages before sending them. if this value is 0 (default) then we just send all the messgaes. """, ) rediscover_every = dictobj.Field( sb.integer_spec, default=20, help=""" This value is the number of seconds it should take before we try and rediscover devices on the network to add to the animation. """, ) animation_limit = dictobj.Field( sb.integer_spec(), default=0, help=""" This is the number of animations to run before stop running new animations. It defaults to no limit """, ) animation_chooser = dictobj.Field( sb.string_choice_spec(["random", "cycle"]), default="cycle", help=""" This decides how we determine which feature animation to run next. If the option is random (default) then the next feature will be the next feature in the animations list. Otherwise if it's set to random, then the next one will be chosen at random. """, ) transition_chooser = dictobj.Field( sb.string_choice_spec(["random", "cycle"]), default="cycle", help=""" This decides how we determine which transition animation to use next. If the option is random (default) then the next transition will be the next transition in the animations list. Otherwise if it's set to random, then the next one will be chosen at random. """, ) transitions = dictobj.Field( TransitionOptions.FieldSpec, help=""" The options for transitions run_first Run a transition before the first feature animation run_last Run a transition after the last feature animation (unless animations are cancelled) run_between Run transitions between feature animations animations Same option as in the ``animations`` option of the root options. """, ) animations = dictobj.Field( sb.listof(animation_spec()), help=""" The different animations you wish to run. These are a list of (name, ), (name, options); or (name, background, options) ``name`` This is the name of the registered animation. If it's a tuple of (Animation, Options) where those are the classes that represent the animation, then a new animation is created from those options. ``background`` If this value is not not specified, or null or true, then the current colors on the tiles are used as the starting canvas for the animation. If this value is False, then the starting canvas for the animation will be empty. options A dictionary of options relevant to the animation. """, ) @property def animations_iter(self, register=None): features = [] transitions = [] for a in self.animations: make_animation, background = a.resolve() features.append((make_animation, background)) for t in self.transitions.animations: make_animation, background = a.resolve() transitions.append((make_animation, background)) features = iter(Chooser(self.animation_chooser, features)) transitions = iter(Chooser(self.transition_chooser, transitions)) def itr(): if not features and transitions: if self.transitions.run_first or self.transitions.run_last: yield next(transitions) return if transitions and self.transitions.run_first: yield next(transitions) if features: count = 0 while True: if self.animation_limit and count >= self.animation_limit: break count += 1 animation = yield next(features) if animation.skip_next_transition: continue if transitions and self.transitions.run_between: yield next(transitions) if transitions and self.transitions.run_last: yield next(transitions) return itr
class Options(dictobj.Spec): colors = dictobj.Field(colors_spec, wrapper=sb.required) theme = dictobj.Field(sb.string_choice_spec(appliers.keys()), default="SPLOTCH") duration = dictobj.Field(sb.float_spec(), default=1) overrides = dictobj.Field(sb.dictionary_spec)