def __init__(self, canvas, swapfile, mode_get_cb=None): Manager.__init__(self) self._canvas = canvas self._swapfile = swapfile # FIXME: this is a temporary hack to let deeper objects know the # state we're at. Find a better place for it self._mode_get_cb = mode_get_cb self._group = "" self.__edje = None self.part = EditablePart(self) self.animation = EditableAnimation(self) self.signal = EditableProgram(self) self._size = None self._size_init() self._modification_init() self._parts_init() self._programs_init() self._animations_init() self._signals_init() self._error_msg = None
def program_get(self, program): if not program in self.programs: return None prg = EditableProgram(self) prg.name = program return prg
def __init__(self, editable): Manager.__init__(self) self._edit_grp = editable self._name = None self._parts_init() self._states_init() self.program = EditableProgram(self._edit_grp) self._edit_grp.callback_add("group.changed", self._group_changed_cb) self._edit_grp.callback_add("animation.removed", self._animation_removed_cb)
def __init__(self, editable): Manager.__init__(self) self._edit_grp = editable self._name = None self._parts_init() self._states_init() self.program = EditableProgram(self._edit_grp) self._edit_grp.callback_add("group.changed", self._group_changed_cb) self._edit_grp.callback_add( "animation.removed", self._animation_removed_cb)
class Editable(Manager): default_display_size = (500, 500) pref_size_key = "pref_size" def __init__(self, canvas, swapfile, mode_get_cb=None): Manager.__init__(self) self._canvas = canvas self._swapfile = swapfile # FIXME: this is a temporary hack to let deeper objects know the # state we're at. Find a better place for it self._mode_get_cb = mode_get_cb self._group = "" self.__edje = None self.part = EditablePart(self) self.animation = EditableAnimation(self) self.signal = EditableProgram(self) self._size = None self._size_init() self._modification_init() self._parts_init() self._programs_init() self._animations_init() self._signals_init() self._error_msg = None def _mode_get(self): return self._mode_get_cb() mode = property(fget=_mode_get) # Edje def _edje_get(self): return self.__edje edje = property(_edje_get) # Filename def _filename_get(self): return self._swapfile.file filename = property(_filename_get) def _workfile_get(self): return self._swapfile.workfile workfile = property(_workfile_get) # Group Name def _group_get(self): return self._group def _group_set(self, value): if not value: value = "" self.event_emit("group.changed", value) self.__edje and self.__edje.delete() self.__edje = None self._edje_group = None else: old_group = self.__edje self.__edje = EdjeEdit(self._canvas, file=self._swapfile.workfile, group=value) self._edje_group = self.__edje.current_group self.event_emit("group.changed", value) old_group and old_group.delete() self._group = value group = property(_group_get, _group_set) def group_add(self, grp_name): if not self.__edje: self.__edje = EdjeEdit(self._canvas, file=self._swapfile.workfile, group=edje.file_collection_list( self._swapfile.workfile)[0]) self.event_emit("group.changed", self.group) return self.__edje.group_add(grp_name) def group_exists(self, grp_name): if not self.__edje: self.__edje = EdjeEdit(self._canvas, file=self._swapfile.workfile, group=edje.file_collection_list( self._swapfile.workfile)[0]) self.event_emit("group.changed", self.group) return self.__edje.group_exist(grp_name) def group_del(self, grp_name): dummy_grp = None all_grps = edje.file_collection_list(self._swapfile.workfile) for g in all_grps: if g != grp_name: dummy_grp = g break if not dummy_grp: self.error = "Can not delete the only group in file" return False if not self.__edje or self._group == grp_name: self.group = "" dummy_edje = EdjeEdit(self._canvas, file=self._swapfile.workfile, group=dummy_grp) r = dummy_edje.group_del(grp_name) self.error = dummy_edje.error dummy_edje.delete() return r r = self.__edje.group_del(grp_name) self.error = self.__edje.error return r def _error_set(self, msg=None): self._error_msg = msg def _error_get(self): return self._error_msg error = property(_error_get, _error_set) def group_rename(self, name): if not self._group: return False if not name: raise InvalidGroupNameError() if re.match(r'[\s].*|.*[\s]$', name): raise InvalidGroupNameError() if self.__edje.group_exist(name): return False self._edje_group.rename(name) self._group = name return True # GROUP Min/Max def _size_init(self): self._group_size_update(self, None) self.callback_add("group.changed", self._group_size_update) def _group_size_update(self, emissor, grp_name): self._size = None if not grp_name: self._max = None self._min = None return self._max = (self._edje_group.w_max, self._edje_group.h_max) self.event_emit("group.max.changed", self._max) self._min = (self._edje_group.w_min, self._edje_group.h_min) self.event_emit("group.min.changed", self._min) data = self.__edje.group_data_get(self.pref_size_key) if not data: w, h = self.default_display_size else: w, h = data.split("x") w = int(w) h = int(h) self.group_size = (w, h) def _verify_max_w(self, w, group_w, group_h, min_w, group): if w <= 0: return 0 if w and w < min_w: w = min_w if w < group_w: group.resize(w, group_h) return w def _verify_max_h(self, h, group_w, group_h, min_h, group): if h <= 0: return 0 if h and h < min_h: h = min_h if h < group_h: group.resize(group_w, h) return h def _max_get(self): return self._max def _max_set(self, value): if self._max == value: return w, h = value group_w, group_h = self.group_size min_w, min_h = self._min w = self._verify_max_w(w, group_w, group_h, min_w, self.__edje) h = self._verify_max_h(h, group_w, group_h, min_h, self.__edje) self._edje_group.w_max = w self._edje_group.h_max = h self._max = (w, h) self.event_emit("group.max.changed", self._max) group_max = property(_max_get, _max_set) def _verify_min_w(self, w, group_w, group_h, max_w, group): if w < 0: w = 0 if max_w and w > max_w: w = max_w if w > group_w: group.resize(w, group_h) return w def _verify_min_h(self, h, group_w, group_h, max_h, group): if h < 0: h = 0 if max_h and h > max_h: h = max_h if h > group_h: group.resize(group_w, h) return h def _min_get(self): return self._min def _min_set(self, value): if self._min == value: return w, h = value group_w, group_h = self.group_size max_w, max_h = self._max w = self._verify_min_w(w, group_w, group_h, max_w, self.__edje) h = self._verify_min_h(h, group_w, group_h, max_h, self.__edje) self._edje_group.w_min = w self._edje_group.h_min = h self._min = (w, h) self.event_emit("group.min.changed", self._min) group_min = property(_min_get, _min_set) def _size_get(self): return self._size def _size_set(self, value): if self._size == value: return w, h = value max_w, max_h = self._max min_w, min_h = self._min if min_w and w < min_w: w = min_w elif max_w and w > max_w: w = max_w if min_h and h < min_h: h = min_h elif max_h and h > max_h: h = max_h self._size = (w, h) self.__edje.size = (w, h) value = self.__edje.group_data_get(self.pref_size_key) if not value: self.__edje.group_data_add(self.pref_size_key, "0x0") self.__edje.group_data_set(self.pref_size_key, "%dx%d" % self._size) self.event_emit("group.size.changed", self._size) group_size = property(_size_get, _size_set) #Images def images_get(self): return self.__edje.images def image_id_get(self, name): return self.__edje.image_id_get(name) def image_add(self, img): if os.path.basename(img) not in self.images_get(): return self.__edje.image_add(img) #Fonts def fonts_get(self): return self.__edje.fonts def font_add(self, fnt): if os.path.basename(fnt) not in self.fonts_get(): self.__edje.font_add(fnt) # Modifications def _modification_init(self): self._modification_clear_cb(self, None) self.callback_add("saved", self._modification_clear_cb) self.callback_add("group.changed", self._modification_clear_cb) def _modification_clear_cb(self, emissor, data): self._modified = False def close(self): self._swapfile.close() def _empty_animations_clear(self): anim_del_lst = [] for anim in self.animations: prog = self.program_get("@%[email protected]" % anim) if not prog.targets: anim_del_lst.append(anim) for a in anim_del_lst: self.animation_del(a) # Save def save(self, success_cb=None, fail_cb=None): def save_ok(sf): if success_cb: success_cb(sf) self.event_emit("saved") def save_error(err): if fail_cb: fail_cb(err) self.event_emit("save.error") self._empty_animations_clear() if self.__edje.save_all(): self._swapfile.save(save_ok, save_error) else: self.event_emit("save.error") def save_as(self, path, success_cb=None, fail_cb=None, mode=None): def save_as_ok(sf): if success_cb: success_cb(sf) self.event_emit("filename.changed", sf.file) self.event_emit("saved") def save_as_error(err): if fail_cb: fail_cb(err) self.event_emit("save.error") self._empty_animations_clear() if self.__edje.save_all(): self._swapfile.save(save_as_ok, save_as_error, filepath=path, mode=mode) else: self.event_emit("save.error") # Parts def _parts_get(self): return self.__edje.parts parts = property(_parts_get) def _parts_init(self): self.callback_add("group.changed", self._parts_reload_cb) self.callback_add("part.added", self._parts_reload_cb) self.callback_add("part.removed", self._parts_reload_cb) self.part.callback_add("name.changed", self._parts_reload_cb) def _parts_reload_cb(self, emissor, data): if data: self.event_emit("parts.changed", self.parts) else: self.event_emit("parts.changed", []) # TODO: externals API may change in near future # besides being totally annoying this use (part_add + external_add, when # when type is external), there is no external_del (not even indirectly # called def external_add(self, module): return self.__edje.external_add(module) def _part_add(self, name, edje_type, source): if edje_type == edje.EDJE_PART_TYPE_EXTERNAL: external = edje.external_type_get(source) if external: self.__edje.external_add(external.module) return self.__edje.part_add(name, edje_type, source) def part_add(self, name, edje_type, source="", init=None): if not self._part_add(name, edje_type, source): return False part = self._part_init(name) if init: init(part) self._modified = True self.event_emit("part.added", name) return True def part_add_bydata(self, part_data, relatives=None, name=None): source = part_data["source"] if source is None: source = '' if not name: name = part_data.name if not self._part_add(name, part_data.type, source): return False part = self.__edje.part_get(name) part_data.apply_to(part) if relatives: for p, st in relatives.iteritems(): part = self.part_get(p) for (st_name, st_value), rels in st.iteritems(): state = part.state_get(st_name, st_value) if rels[0]: state.rel1_to_x_set(name) if rels[1]: state.rel1_to_y_set(name) if rels[2]: state.rel2_to_x_set(name) if rels[3]: state.rel2_to_y_set(name) self.event_emit("part.added", name) return True def _part_init(self, name): part = self.__edje.part_get(name) edje_type = part.type state = part.state_get(*part.state_selected_get()) w, h = self.__edje.size state.rel1_to = (None, None) state.rel1_relative = (0.0, 0.0) state.rel1_offset = (w / 4, h / 4) state.rel2_to = (None, None) state.rel2_relative = (0.0, 0.0) state.rel2_offset = (w * 3 / 4, h * 3 / 4) if edje_type == edje.EDJE_PART_TYPE_RECTANGLE: part.mouse_events = False elif edje_type == edje.EDJE_PART_TYPE_TEXT: part.mouse_events = False state.color = (0, 0, 0, 255) state.text = "YOUR TEXT HERE" state.font = "Sans" state.text_size = 16 return part def part_get(self, part_name): return self.__edje.part_get(part_name) def part_object_get(self, part_name): return self.__edje.part_object_get(part_name) def part_del(self, name): if self.__edje.part_del(name): self._modified = True self.event_emit("part.removed", name) return True return False # Programs def _programs_get(self): if not self.__edje: return [] return self.__edje.programs programs = property(_programs_get) def _programs_init(self): self.callback_add("group.changed", self._programs_reload_cb) self.signal.callback_add("program.name.changed", self._programs_reload_cb) def _programs_reload_cb(self, emissor, data): if data: self.event_emit("programs.changed", self.programs) else: self.event_emit("programs.changed", []) def program_add(self, name): if not self.__edje.program_add(name): return False self._modified = True self.event_emit("program.added", name) return True def program_del(self, name): if not self.__edje.program_del(name): return False self._modified = True self.event_emit("program.removed", name) return True def program_get(self, program): if not program in self.programs: return None prg = EditableProgram(self) prg.name = program return prg # Animations def _animation_get(self): return self._animations animations = property(_animation_get) def _animations_init(self): self._animations = None self.callback_add("programs.changed", self._animations_reload_cb) def _animations_reload_cb(self, emissor, data): self._animations = \ map(lambda x: x[1:x.rindex("@")], filter(lambda x: x.startswith("@") and x.endswith("@end"), self.programs)) self.event_emit("animations.changed", self.animations) def animation_add(self, name, parts=None): if name in self._animations: return False self._modified = True # END endname = "@%s@end" % name self.program_add(endname) prog = self.program_get(endname) prog.signal_emit_action_set(("animation,end", name)) # START startname = "@%[email protected]" % name self.program_add(startname) prog = self.program_get(startname) prog.state_set_action_set(startname) prog.signal = "animation,play" prog.source = name prog.after_add("@%s@end" % name) prevstatename = "default" statename = startname if not parts: parts = self.parts for p in parts: prog.target_add(p) part = self.__edje.part_get(p) if not part.state_add(startname): return False state = part.state_get(statename) state.copy_from(prevstatename) # STOP stopname = "@%s@stop" % name self.program_add(stopname) prog = self.program_get(stopname) prog.action = edje.EDJE_ACTION_TYPE_ACTION_STOP prog.signal = "animation,stop" prog.source = name prog.target_add(startname) prog.target_add(endname) self._animations.append(name) self.event_emit("animation.added", name) return True def animation_del(self, name): stopname = "@%s@stop" % name stopprog = self.program_get(stopname) if not stopprog: return False for p in stopprog.targets: prog = self.program_get(p) for pp in prog.targets: part = self.__edje.part_get(pp) if part: part.state_selected_set("default") if not part.state_del(p): return False self.program_del(p) self.program_del(stopname) self.event_emit("animation.removed", name) self._animations.pop(self._animations.index(name)) self._modified = True return True # Signals def _signal_get(self): return self._signals signals = property(_signal_get) def _signals_init(self): self._signals = None self.callback_add("programs.changed", self._signals_reload_cb) self.callback_add("signal.added", self._signals_reload_cb) self.callback_add("signal.removed", self._signals_reload_cb) def _signals_reload_cb(self, emissor, data): self._signals = [e for e in self.programs if not e.startswith("@")] self.event_emit("signals.changed", self._signals) def _signal_add(self, name): if not name or name.startswith("@"): return False if not self.program_add(name): return False return True def signal_add(self, name, action_type): if not self._signal_add(name): return False program = self.__edje.program_get(name) program.action_set(action_type) self.event_emit("signal.added", name) return True def signal_add_bydata(self, sig_data): name = sig_data.name if not self._signal_add(name): return False program = self.__edje.program_get(name) sig_data.apply_to(program) self.event_emit("signal.added", name) return True def signal_del(self, name): if not name in self._signals: return False if not self.program_del(name): return False self.event_emit("signal.removed", name) return True def relative_parts_get(self, part_name): relatives = dict() for p in self.parts: saved_states = dict() part = self.__edje.part_get(p) for st in part.states: st_name, value = st.split() st_value = float(value) state = part.state_get(st_name, st_value) if part_name in (state.rel1_to_get()[0], state.rel1_to_get()[1], state.rel2_to_get()[0], state.rel2_to_get()[1]): saved_states[st_name, st_value] = ( part_name == state.rel1_to_get()[0], part_name == state.rel1_to_get()[1], part_name == state.rel2_to_get()[0], part_name == state.rel2_to_get()[1]) if saved_states: relatives[p] = saved_states return relatives def _groups_get(self): return edje.file_collection_list(self._swapfile.workfile) groups = property(_groups_get)
class EditableAnimation(Manager, object): def __init__(self, editable): Manager.__init__(self) self._edit_grp = editable self._name = None self._parts_init() self._states_init() self.program = EditableProgram(self._edit_grp) self._edit_grp.callback_add("group.changed", self._group_changed_cb) self._edit_grp.callback_add( "animation.removed", self._animation_removed_cb) def _group_changed_cb(self, emissor, data): self.name = None def _animation_removed_cb(self, emissor, data): if self._name == data: self.name = None for p in self._edit_grp.parts: part = self._edit_grp.part_get(p) part.state_selected_set("default", 0.00) # Name def _name_set(self, value): if not self._edit_grp.edje: return if not value: self._name = None self.event_emit("animation.unselected") elif self._name != value: if value in self._edit_grp.animations: self._name = value self.event_emit("animation.changed", self._name) else: self._name = None for p in self._edit_grp.parts: part = self._edit_grp.part_get(p) #FIXME: is this really desired? part.state_selected_set("default") self.event_emit("animation.unselected") def _name_get(self): return self._name name = property(_name_get, _name_set) def name_set(self, name): if not name: return # stop program stopname = "@%s@stop" % self._name stopprog = self._edit_grp.edje.program_get(stopname) if not stopprog or not stopprog.rename("@%s@stop" % name): return stopprog.source_set(name) # others programs for p in stopprog.targets_get(): prog = self._edit_grp.edje.program_get(p) time = re_anim_program.match(p).group(2) p2 = "@%s@%s" % (name, time) if time == "end": prog.state2_set(name) else: for pp in prog.targets_get(): part = self._edit_grp.part_get(pp) if not part: #prog.target_del(pp) TODO: binding continue state = part.state_get(p) if not state: continue state.name_set(p2) if time == "0.00": prog.source_set(name) prog.state_set(p2) prog.rename(p2) # Hack to force reload animation list # self._name = name state = self.state self._edit_grp._programs_reload_cb(self, True) self.name = name self.state = state return # Play def play(self): if self.name: self._edit_grp.edje.signal_callback_add( "animation,end", self._name, self._play_end) self._edit_grp.edje.program_get(self.program.afters[0]).run() def _play_end(self, obj, emission, source): self._edit_grp.edje.signal_callback_del( "animation,end", self._name, self._play_end) self._playback_state_update() self.event_emit("animation.play.end") def stop(self): self._edit_grp.edje.signal_emit("animation,stop", self._name) self._playback_state_update() def _playback_state_update(self): if not self.parts: return # got to fetch the exact state we're at edje.message_signal_process() p = self.parts.keys()[0] st = self._edit_grp.part_get(p).state_selected_get()[0] time = re_anim_program_time.match(st).group(2) if time: self.state = float(time) # Parts def _parts_init(self): self.parts = {} self._edit_grp.part.callback_add("name.changed", self._part_rename_cb) self.callback_add("animation.changed", self._parts_reload_cb) self.callback_add("animation.unselected", self._parts_reload_cb) def _parts_reload_cb(self, emissor, data): self.parts = {} if not data: return prog = self._edit_grp.program_get("@%[email protected]" % self._name) for t in prog.targets: self.parts[t] = True def _part_rename_cb(self, emissor, data): old_name, new_name = data p = self.parts.get(old_name) if not p: return self.parts[new_name] = True del self.parts[old_name] def part_add(self, part): if part in self.parts: return progname = "@%[email protected]" % self._name prog = self._edit_grp.program_get(progname) prog.target_add(part) p = self._edit_grp.part_get(part) p.state_copy("default", 0.0, progname, 0.0) self.parts[part] = True # Re-set current state to make sure everything is consistent curr = self._current self._current = None self._state_set(curr) self.event_emit("part.added", part) def part_remove(self, part): if part not in self.parts: return p = self._edit_grp.part_get(part) p.state_selected_set("default", 0.00) if p.name == self._edit_grp.part.name: self._edit_grp.part.state.name = None for t in self.timestops: progname = "@%s@%.2f" % (self._name, t) st = progname prog = self._edit_grp.program_get(progname) prog.target_del(part) if p.state_exist(st): if not p.state_del(st): return del self.parts[part] self.event_emit("part.removed", part) def part_belongs(self, part): return part in self.parts # States def _states_init(self): self.timestops = [] self.callback_add("animation.changed", self._states_reload_cb) self.callback_add("animation.unselected", self._states_reload_cb) self.callback_add("animation.changed", self._state_reload_cb) self.callback_add("animation.unselected", self._state_reload_cb) def _states_reload_cb(self, emissor, data): self.timestops = [] if not data: return p = self._edit_grp.program_get("@%[email protected]" % self._name) t = p.name[-4:] while t != "@end": self.timestops.append(float(t)) p = self._edit_grp.program_get(p.afters[0]) t = p.name[-4:] self.event_emit("states.changed", self.timestops) def state_add(self, time): if not self._name: return if time < 0.0: return # Search idx = 0 for t in self.timestops: if time == t: return idx if t > time: break idx += 1 # Defines prev = self.timestops[idx - 1] prevname = "@%s@%.2f" % (self._name, prev) name = "@%s@%.2f" % (self._name, time) # States prevstatename = prevname statename = name # Create self._edit_grp.program_add(name) prog = self._edit_grp.program_get(name) prog.state_set_action_set(name) prog.transition = edje.EDJE_TWEEN_MODE_LINEAR prog.transition_time = time - prev for p in self.parts.iterkeys(): prog.target_add(p) part = self._edit_grp.part_get(p) if not part.state_add(name): return state = part.state_get(statename) state.copy_from(prevstatename) # Link Prev prevprog = self._edit_grp.program_get(prevname) nextname = prevprog.afters[0] prog.after_add(nextname) prevprog.afters_clear() prevprog.after_add(name) # Link Next next = nextname[-4:] if not next == "@end": next = float(next) nextprog = self._edit_grp.program_get(nextname) nextprog.transition_time = next - time # Stop stopname = "@%s@stop" % self._name self._edit_grp.program_add(stopname) prog = self._edit_grp.program_get(stopname) prog.action = edje.EDJE_ACTION_TYPE_ACTION_STOP prog.signal = "animation,stop" prog.target_add(name) self.timestops.insert(idx, time) self.event_emit("state.added", time) return idx def state_del(self, time): if time == 0.0 or time == "end": return # Search idx = self.timestops.index(time) progname = "@%s@%.2f" % (self._name, time) prog = self._edit_grp.program_get(progname) # Unlink prev = self.timestops[idx - 1] prevname = "@%s@%.2f" % (self._name, prev) prevprog = self._edit_grp.program_get(prevname) nextname = prog.afters[0] prevprog.afters_clear() prevprog.after_add(nextname) # Fix Next next = nextname[-4:] if not next == "@end": next = float(next) nextprog = self._edit_grp.program_get(nextname) nextprog.transition_time = next - prev # Delete states from parts statename = progname for p in self.parts.iterkeys(): part = self._edit_grp.part_get(p) if not part.state_del(statename, 0.0): return self.timestops.pop(idx) self.event_emit("state.removed", time) def _part_state_create(self, part): statename = self.program.name orig_state = "default" time_idx = 0 while time_idx <= self._current_idx: time = self.timestops[time_idx] name = "@%s@%.2f" % (self._name, time) if part.state_exist(name): orig_state = name else: part.state_copy(orig_state, 0.0, statename, 0.0) time_idx += 1 self.program.target_add(part.name) def _state_set(self, time): if not self._name or time == self._current: return self._current_idx = self.timestops.index(time) self._current = time self.program.name = "@%s@%.2f" % (self._name, time) statename = self.program.name for p in self.parts.iterkeys(): part = self._edit_grp.part_get(p) if part.state_exist(statename): part.state_selected_set(statename) else: self._part_state_create(part) part.state_selected_set(statename) if self._edit_grp.part.name in self.parts: self._edit_grp.part.state.name = statename self.event_emit("frame.changed", self._edit_grp.part.state.name) def _state_get(self): return self._current state = property(_state_get, _state_set) def state_next(self): if not self._name: return None if self._current_idx == len(self.timestops) - 1: return None return self.timestops[self._current_idx + 1] def state_next_goto(self): state = self.state_next() if state is not None: self.state = state def state_prev(self): if not self._name: return None if self._current_idx == 0: return None return self.timestops[self._current_idx - 1] def state_prev_goto(self): state = self.state_prev() if state is not None: self.state = state def _state_reload_cb(self, emissor, data): self._current = None if data and self.timestops: self.state = 0.0 # Info def _length_get(self): if self.timestops: return self.timestops[-1] return 0.0 length = property(_length_get)
class Editable(Manager): default_display_size = (500, 500) pref_size_key = "pref_size" def __init__(self, canvas, swapfile, mode_get_cb=None): Manager.__init__(self) self._canvas = canvas self._swapfile = swapfile # FIXME: this is a temporary hack to let deeper objects know the # state we're at. Find a better place for it self._mode_get_cb = mode_get_cb self._group = "" self.__edje = None self.part = EditablePart(self) self.animation = EditableAnimation(self) self.signal = EditableProgram(self) self._size = None self._size_init() self._modification_init() self._parts_init() self._programs_init() self._animations_init() self._signals_init() self._error_msg = None def _mode_get(self): return self._mode_get_cb() mode = property(fget=_mode_get) # Edje def _edje_get(self): return self.__edje edje = property(_edje_get) # Filename def _filename_get(self): return self._swapfile.file filename = property(_filename_get) def _workfile_get(self): return self._swapfile.workfile workfile = property(_workfile_get) # Group Name def _group_get(self): return self._group def _group_set(self, value): if not value: value = "" self.event_emit("group.changed", value) self.__edje and self.__edje.delete() self.__edje = None self._edje_group = None else: old_group = self.__edje self.__edje = EdjeEdit( self._canvas, file=self._swapfile.workfile, group=value) self._edje_group = self.__edje.current_group self.event_emit("group.changed", value) old_group and old_group.delete() self._group = value group = property(_group_get, _group_set) def group_add(self, grp_name): if not self.__edje: self.__edje = EdjeEdit( self._canvas, file=self._swapfile.workfile, group=edje.file_collection_list(self._swapfile.workfile)[0]) self.event_emit("group.changed", self.group) return self.__edje.group_add(grp_name) def group_exists(self, grp_name): if not self.__edje: self.__edje = EdjeEdit( self._canvas, file=self._swapfile.workfile, group=edje.file_collection_list(self._swapfile.workfile)[0]) self.event_emit("group.changed", self.group) return self.__edje.group_exist(grp_name) def group_del(self, grp_name): dummy_grp = None all_grps = edje.file_collection_list(self._swapfile.workfile) for g in all_grps: if g != grp_name: dummy_grp = g break if not dummy_grp: self.error = "Can not delete the only group in file" return False if not self.__edje or self._group == grp_name: self.group = "" dummy_edje = EdjeEdit( self._canvas, file=self._swapfile.workfile, group=dummy_grp) r = dummy_edje.group_del(grp_name) self.error = dummy_edje.error dummy_edje.delete() return r r = self.__edje.group_del(grp_name) self.error = self.__edje.error return r def _error_set(self, msg=None): self._error_msg = msg def _error_get(self): return self._error_msg error = property(_error_get, _error_set) def group_rename(self, name): if not self._group: return False if not name: raise InvalidGroupNameError() if re.match(r'[\s].*|.*[\s]$', name): raise InvalidGroupNameError() if self.__edje.group_exist(name): return False self._edje_group.rename(name) self._group = name return True # GROUP Min/Max def _size_init(self): self._group_size_update(self, None) self.callback_add("group.changed", self._group_size_update) def _group_size_update(self, emissor, grp_name): self._size = None if not grp_name: self._max = None self._min = None return self._max = (self._edje_group.w_max, self._edje_group.h_max) self.event_emit("group.max.changed", self._max) self._min = (self._edje_group.w_min, self._edje_group.h_min) self.event_emit("group.min.changed", self._min) data = self.__edje.group_data_get(self.pref_size_key) if not data: w, h = self.default_display_size else: w, h = data.split("x") w = int(w) h = int(h) self.group_size = (w, h) def _verify_max_w(self, w, group_w, group_h, min_w, group): if w <= 0: return 0 if w and w < min_w: w = min_w if w < group_w: group.resize(w, group_h) return w def _verify_max_h(self, h, group_w, group_h, min_h, group): if h <= 0: return 0 if h and h < min_h: h = min_h if h < group_h: group.resize(group_w, h) return h def _max_get(self): return self._max def _max_set(self, value): if self._max == value: return w, h = value group_w, group_h = self.group_size min_w, min_h = self._min w = self._verify_max_w(w, group_w, group_h, min_w, self.__edje) h = self._verify_max_h(h, group_w, group_h, min_h, self.__edje) self._edje_group.w_max = w self._edje_group.h_max = h self._max = (w, h) self.event_emit("group.max.changed", self._max) group_max = property(_max_get, _max_set) def _verify_min_w(self, w, group_w, group_h, max_w, group): if w < 0: w = 0 if max_w and w > max_w: w = max_w if w > group_w: group.resize(w, group_h) return w def _verify_min_h(self, h, group_w, group_h, max_h, group): if h < 0: h = 0 if max_h and h > max_h: h = max_h if h > group_h: group.resize(group_w, h) return h def _min_get(self): return self._min def _min_set(self, value): if self._min == value: return w, h = value group_w, group_h = self.group_size max_w, max_h = self._max w = self._verify_min_w(w, group_w, group_h, max_w, self.__edje) h = self._verify_min_h(h, group_w, group_h, max_h, self.__edje) self._edje_group.w_min = w self._edje_group.h_min = h self._min = (w, h) self.event_emit("group.min.changed", self._min) group_min = property(_min_get, _min_set) def _size_get(self): return self._size def _size_set(self, value): if self._size == value: return w, h = value max_w, max_h = self._max min_w, min_h = self._min if min_w and w < min_w: w = min_w elif max_w and w > max_w: w = max_w if min_h and h < min_h: h = min_h elif max_h and h > max_h: h = max_h self._size = (w, h) self.__edje.size = (w, h) value = self.__edje.group_data_get(self.pref_size_key) if not value: self.__edje.group_data_add(self.pref_size_key, "0x0") self.__edje.group_data_set(self.pref_size_key, "%dx%d" % self._size) self.event_emit("group.size.changed", self._size) group_size = property(_size_get, _size_set) #Images def images_get(self): return self.__edje.images def image_id_get(self, name): return self.__edje.image_id_get(name) def image_add(self, img): if os.path.basename(img) not in self.images_get(): return self.__edje.image_add(img) #Fonts def fonts_get(self): return self.__edje.fonts def font_add(self, fnt): if os.path.basename(fnt) not in self.fonts_get(): self.__edje.font_add(fnt) # Modifications def _modification_init(self): self._modification_clear_cb(self, None) self.callback_add("saved", self._modification_clear_cb) self.callback_add("group.changed", self._modification_clear_cb) def _modification_clear_cb(self, emissor, data): self._modified = False def close(self): self._swapfile.close() def _empty_animations_clear(self): anim_del_lst = [] for anim in self.animations: prog = self.program_get("@%[email protected]" % anim) if not prog.targets: anim_del_lst.append(anim) for a in anim_del_lst: self.animation_del(a) # Save def save(self, success_cb=None, fail_cb=None): def save_ok(sf): if success_cb: success_cb(sf) self.event_emit("saved") def save_error(err): if fail_cb: fail_cb(err) self.event_emit("save.error") self._empty_animations_clear() if self.__edje.save_all(): self._swapfile.save(save_ok, save_error) else: self.event_emit("save.error") def save_as(self, path, success_cb=None, fail_cb=None, mode=None): def save_as_ok(sf): if success_cb: success_cb(sf) self.event_emit("filename.changed", sf.file) self.event_emit("saved") def save_as_error(err): if fail_cb: fail_cb(err) self.event_emit("save.error") self._empty_animations_clear() if self.__edje.save_all(): self._swapfile.save(save_as_ok, save_as_error, filepath=path, mode=mode) else: self.event_emit("save.error") # Parts def _parts_get(self): return self.__edje.parts parts = property(_parts_get) def _parts_init(self): self.callback_add("group.changed", self._parts_reload_cb) self.callback_add("part.added", self._parts_reload_cb) self.callback_add("part.removed", self._parts_reload_cb) self.part.callback_add("name.changed", self._parts_reload_cb) def _parts_reload_cb(self, emissor, data): if data: self.event_emit("parts.changed", self.parts) else: self.event_emit("parts.changed", []) # TODO: externals API may change in near future # besides being totally annoying this use (part_add + external_add, when # when type is external), there is no external_del (not even indirectly # called def external_add(self, module): return self.__edje.external_add(module) def _part_add(self, name, edje_type, source): if edje_type == edje.EDJE_PART_TYPE_EXTERNAL: external = edje.external_type_get(source) if external: self.__edje.external_add(external.module) return self.__edje.part_add(name, edje_type, source) def part_add(self, name, edje_type, source="", init=None): if not self._part_add(name, edje_type, source): return False part = self._part_init(name) if init: init(part) self._modified = True self.event_emit("part.added", name) return True def part_add_bydata(self, part_data, relatives=None, name=None): source = part_data["source"] if source is None: source = '' if not name: name = part_data.name if not self._part_add(name, part_data.type, source): return False part = self.__edje.part_get(name) part_data.apply_to(part) if relatives: for p, st in relatives.iteritems(): part = self.part_get(p) for (st_name, st_value), rels in st.iteritems(): state = part.state_get(st_name, st_value) if rels[0]: state.rel1_to_x_set(name) if rels[1]: state.rel1_to_y_set(name) if rels[2]: state.rel2_to_x_set(name) if rels[3]: state.rel2_to_y_set(name) self.event_emit("part.added", name) return True def _part_init(self, name): part = self.__edje.part_get(name) edje_type = part.type state = part.state_get(*part.state_selected_get()) w, h = self.__edje.size state.rel1_to = (None, None) state.rel1_relative = (0.0, 0.0) state.rel1_offset = (w / 4, h / 4) state.rel2_to = (None, None) state.rel2_relative = (0.0, 0.0) state.rel2_offset = (w * 3 / 4, h * 3 / 4) if edje_type == edje.EDJE_PART_TYPE_RECTANGLE: part.mouse_events = False elif edje_type == edje.EDJE_PART_TYPE_TEXT: part.mouse_events = False state.color = (0, 0, 0, 255) state.text = "YOUR TEXT HERE" state.font = "Sans" state.text_size = 16 return part def part_get(self, part_name): return self.__edje.part_get(part_name) def part_object_get(self, part_name): return self.__edje.part_object_get(part_name) def part_del(self, name): if self.__edje.part_del(name): self._modified = True self.event_emit("part.removed", name) return True return False # Programs def _programs_get(self): if not self.__edje: return [] return self.__edje.programs programs = property(_programs_get) def _programs_init(self): self.callback_add("group.changed", self._programs_reload_cb) self.signal.callback_add( "program.name.changed", self._programs_reload_cb) def _programs_reload_cb(self, emissor, data): if data: self.event_emit("programs.changed", self.programs) else: self.event_emit("programs.changed", []) def program_add(self, name): if not self.__edje.program_add(name): return False self._modified = True self.event_emit("program.added", name) return True def program_del(self, name): if not self.__edje.program_del(name): return False self._modified = True self.event_emit("program.removed", name) return True def program_get(self, program): if not program in self.programs: return None prg = EditableProgram(self) prg.name = program return prg # Animations def _animation_get(self): return self._animations animations = property(_animation_get) def _animations_init(self): self._animations = None self.callback_add("programs.changed", self._animations_reload_cb) def _animations_reload_cb(self, emissor, data): self._animations = \ map(lambda x: x[1:x.rindex("@")], filter(lambda x: x.startswith("@") and x.endswith("@end"), self.programs)) self.event_emit("animations.changed", self.animations) def animation_add(self, name, parts=None): if name in self._animations: return False self._modified = True # END endname = "@%s@end" % name self.program_add(endname) prog = self.program_get(endname) prog.signal_emit_action_set(("animation,end", name)) # START startname = "@%[email protected]" % name self.program_add(startname) prog = self.program_get(startname) prog.state_set_action_set(startname) prog.signal = "animation,play" prog.source = name prog.after_add("@%s@end" % name) prevstatename = "default" statename = startname if not parts: parts = self.parts for p in parts: prog.target_add(p) part = self.__edje.part_get(p) if not part.state_add(startname): return False state = part.state_get(statename) state.copy_from(prevstatename) # STOP stopname = "@%s@stop" % name self.program_add(stopname) prog = self.program_get(stopname) prog.action = edje.EDJE_ACTION_TYPE_ACTION_STOP prog.signal = "animation,stop" prog.source = name prog.target_add(startname) prog.target_add(endname) self._animations.append(name) self.event_emit("animation.added", name) return True def animation_del(self, name): stopname = "@%s@stop" % name stopprog = self.program_get(stopname) if not stopprog: return False for p in stopprog.targets: prog = self.program_get(p) for pp in prog.targets: part = self.__edje.part_get(pp) if part: part.state_selected_set("default") if not part.state_del(p): return False self.program_del(p) self.program_del(stopname) self.event_emit("animation.removed", name) self._animations.pop(self._animations.index(name)) self._modified = True return True # Signals def _signal_get(self): return self._signals signals = property(_signal_get) def _signals_init(self): self._signals = None self.callback_add("programs.changed", self._signals_reload_cb) self.callback_add("signal.added", self._signals_reload_cb) self.callback_add("signal.removed", self._signals_reload_cb) def _signals_reload_cb(self, emissor, data): self._signals = [e for e in self.programs if not e.startswith("@")] self.event_emit("signals.changed", self._signals) def _signal_add(self, name): if not name or name.startswith("@"): return False if not self.program_add(name): return False return True def signal_add(self, name, action_type): if not self._signal_add(name): return False program = self.__edje.program_get(name) program.action_set(action_type) self.event_emit("signal.added", name) return True def signal_add_bydata(self, sig_data): name = sig_data.name if not self._signal_add(name): return False program = self.__edje.program_get(name) sig_data.apply_to(program) self.event_emit("signal.added", name) return True def signal_del(self, name): if not name in self._signals: return False if not self.program_del(name): return False self.event_emit("signal.removed", name) return True def relative_parts_get(self, part_name): relatives = dict() for p in self.parts: saved_states = dict() part = self.__edje.part_get(p) for st in part.states: st_name, value = st.split() st_value = float(value) state = part.state_get(st_name, st_value) if part_name in (state.rel1_to_get()[0], state.rel1_to_get()[1], state.rel2_to_get()[0], state.rel2_to_get()[1]): saved_states[st_name, st_value] = ( part_name == state.rel1_to_get()[0], part_name == state.rel1_to_get()[1], part_name == state.rel2_to_get()[0], part_name == state.rel2_to_get()[1]) if saved_states: relatives[p] = saved_states return relatives def _groups_get(self): return edje.file_collection_list(self._swapfile.workfile) groups = property(_groups_get)
class EditableAnimation(Manager, object): def __init__(self, editable): Manager.__init__(self) self._edit_grp = editable self._name = None self._parts_init() self._states_init() self.program = EditableProgram(self._edit_grp) self._edit_grp.callback_add("group.changed", self._group_changed_cb) self._edit_grp.callback_add("animation.removed", self._animation_removed_cb) def _group_changed_cb(self, emissor, data): self.name = None def _animation_removed_cb(self, emissor, data): if self._name == data: self.name = None for p in self._edit_grp.parts: part = self._edit_grp.part_get(p) part.state_selected_set("default", 0.00) # Name def _name_set(self, value): if not self._edit_grp.edje: return if not value: self._name = None self.event_emit("animation.unselected") elif self._name != value: if value in self._edit_grp.animations: self._name = value self.event_emit("animation.changed", self._name) else: self._name = None for p in self._edit_grp.parts: part = self._edit_grp.part_get(p) #FIXME: is this really desired? part.state_selected_set("default") self.event_emit("animation.unselected") def _name_get(self): return self._name name = property(_name_get, _name_set) def name_set(self, name): if not name: return # stop program stopname = "@%s@stop" % self._name stopprog = self._edit_grp.edje.program_get(stopname) if not stopprog or not stopprog.rename("@%s@stop" % name): return stopprog.source_set(name) # others programs for p in stopprog.targets_get(): prog = self._edit_grp.edje.program_get(p) time = re_anim_program.match(p).group(2) p2 = "@%s@%s" % (name, time) if time == "end": prog.state2_set(name) else: for pp in prog.targets_get(): part = self._edit_grp.part_get(pp) if not part: #prog.target_del(pp) TODO: binding continue state = part.state_get(p) if not state: continue state.name_set(p2) if time == "0.00": prog.source_set(name) prog.state_set(p2) prog.rename(p2) # Hack to force reload animation list # self._name = name state = self.state self._edit_grp._programs_reload_cb(self, True) self.name = name self.state = state return # Play def play(self): if self.name: self._edit_grp.edje.signal_callback_add("animation,end", self._name, self._play_end) self._edit_grp.edje.program_get(self.program.afters[0]).run() def _play_end(self, obj, emission, source): self._edit_grp.edje.signal_callback_del("animation,end", self._name, self._play_end) self._playback_state_update() self.event_emit("animation.play.end") def stop(self): self._edit_grp.edje.signal_emit("animation,stop", self._name) self._playback_state_update() def _playback_state_update(self): if not self.parts: return # got to fetch the exact state we're at edje.message_signal_process() p = self.parts.keys()[0] st = self._edit_grp.part_get(p).state_selected_get()[0] time = re_anim_program_time.match(st).group(2) if time: self.state = float(time) # Parts def _parts_init(self): self.parts = {} self._edit_grp.part.callback_add("name.changed", self._part_rename_cb) self.callback_add("animation.changed", self._parts_reload_cb) self.callback_add("animation.unselected", self._parts_reload_cb) def _parts_reload_cb(self, emissor, data): self.parts = {} if not data: return prog = self._edit_grp.program_get("@%[email protected]" % self._name) for t in prog.targets: self.parts[t] = True def _part_rename_cb(self, emissor, data): old_name, new_name = data p = self.parts.get(old_name) if not p: return self.parts[new_name] = True del self.parts[old_name] def part_add(self, part): if part in self.parts: return progname = "@%[email protected]" % self._name prog = self._edit_grp.program_get(progname) prog.target_add(part) p = self._edit_grp.part_get(part) p.state_copy("default", 0.0, progname, 0.0) self.parts[part] = True # Re-set current state to make sure everything is consistent curr = self._current self._current = None self._state_set(curr) self.event_emit("part.added", part) def part_remove(self, part): if part not in self.parts: return p = self._edit_grp.part_get(part) p.state_selected_set("default", 0.00) if p.name == self._edit_grp.part.name: self._edit_grp.part.state.name = None for t in self.timestops: progname = "@%s@%.2f" % (self._name, t) st = progname prog = self._edit_grp.program_get(progname) prog.target_del(part) if p.state_exist(st): if not p.state_del(st): return del self.parts[part] self.event_emit("part.removed", part) def part_belongs(self, part): return part in self.parts # States def _states_init(self): self.timestops = [] self.callback_add("animation.changed", self._states_reload_cb) self.callback_add("animation.unselected", self._states_reload_cb) self.callback_add("animation.changed", self._state_reload_cb) self.callback_add("animation.unselected", self._state_reload_cb) def _states_reload_cb(self, emissor, data): self.timestops = [] if not data: return p = self._edit_grp.program_get("@%[email protected]" % self._name) t = p.name[-4:] while t != "@end": self.timestops.append(float(t)) p = self._edit_grp.program_get(p.afters[0]) t = p.name[-4:] self.event_emit("states.changed", self.timestops) def state_add(self, time): if not self._name: return if time < 0.0: return # Search idx = 0 for t in self.timestops: if time == t: return idx if t > time: break idx += 1 # Defines prev = self.timestops[idx - 1] prevname = "@%s@%.2f" % (self._name, prev) name = "@%s@%.2f" % (self._name, time) # States prevstatename = prevname statename = name # Create self._edit_grp.program_add(name) prog = self._edit_grp.program_get(name) prog.state_set_action_set(name) prog.transition = edje.EDJE_TWEEN_MODE_LINEAR prog.transition_time = time - prev for p in self.parts.iterkeys(): prog.target_add(p) part = self._edit_grp.part_get(p) if not part.state_add(name): return state = part.state_get(statename) state.copy_from(prevstatename) # Link Prev prevprog = self._edit_grp.program_get(prevname) nextname = prevprog.afters[0] prog.after_add(nextname) prevprog.afters_clear() prevprog.after_add(name) # Link Next next = nextname[-4:] if not next == "@end": next = float(next) nextprog = self._edit_grp.program_get(nextname) nextprog.transition_time = next - time # Stop stopname = "@%s@stop" % self._name self._edit_grp.program_add(stopname) prog = self._edit_grp.program_get(stopname) prog.action = edje.EDJE_ACTION_TYPE_ACTION_STOP prog.signal = "animation,stop" prog.target_add(name) self.timestops.insert(idx, time) self.event_emit("state.added", time) return idx def state_del(self, time): if time == 0.0 or time == "end": return # Search idx = self.timestops.index(time) progname = "@%s@%.2f" % (self._name, time) prog = self._edit_grp.program_get(progname) # Unlink prev = self.timestops[idx - 1] prevname = "@%s@%.2f" % (self._name, prev) prevprog = self._edit_grp.program_get(prevname) nextname = prog.afters[0] prevprog.afters_clear() prevprog.after_add(nextname) # Fix Next next = nextname[-4:] if not next == "@end": next = float(next) nextprog = self._edit_grp.program_get(nextname) nextprog.transition_time = next - prev # Delete states from parts statename = progname for p in self.parts.iterkeys(): part = self._edit_grp.part_get(p) if not part.state_del(statename, 0.0): return self.timestops.pop(idx) self.event_emit("state.removed", time) def _part_state_create(self, part): statename = self.program.name orig_state = "default" time_idx = 0 while time_idx <= self._current_idx: time = self.timestops[time_idx] name = "@%s@%.2f" % (self._name, time) if part.state_exist(name): orig_state = name else: part.state_copy(orig_state, 0.0, statename, 0.0) time_idx += 1 self.program.target_add(part.name) def _state_set(self, time): if not self._name or time == self._current: return self._current_idx = self.timestops.index(time) self._current = time self.program.name = "@%s@%.2f" % (self._name, time) statename = self.program.name for p in self.parts.iterkeys(): part = self._edit_grp.part_get(p) if part.state_exist(statename): part.state_selected_set(statename) else: self._part_state_create(part) part.state_selected_set(statename) if self._edit_grp.part.name in self.parts: self._edit_grp.part.state.name = statename self.event_emit("frame.changed", self._edit_grp.part.state.name) def _state_get(self): return self._current state = property(_state_get, _state_set) def state_next(self): if not self._name: return None if self._current_idx == len(self.timestops) - 1: return None return self.timestops[self._current_idx + 1] def state_next_goto(self): state = self.state_next() if state is not None: self.state = state def state_prev(self): if not self._name: return None if self._current_idx == 0: return None return self.timestops[self._current_idx - 1] def state_prev_goto(self): state = self.state_prev() if state is not None: self.state = state def _state_reload_cb(self, emissor, data): self._current = None if data and self.timestops: self.state = 0.0 # Info def _length_get(self): if self.timestops: return self.timestops[-1] return 0.0 length = property(_length_get)