class WildEditorGUI(ttk.Frame): def __init__(self, *args, **kwargs): ttk.Frame.__init__(self, *args, **kwargs) title = ttk.Label(self, text='Wild Pokemon Editor', style='Title.TLabel') self.entry_id = EntryLabel(self, text='ID') self.entry_min = EntryLabel(self, text='Minimum Level') self.entry_max = EntryLabel(self, text='Maximum Level') self.entry_rarity = EntryLabel(self, text='Rarity (1-?)') sep = ttk.Separator(self, orient=tk.HORIZONTAL) override_lbl = ttk.Label(self, text='Overrides', style='Subtitle.TLabel') self.string = EntryLabel(self, text='String Code') self.code = EntryLabel(self, text='Value') self.choices = ListChoice(self) self.add = ttk.Button(self, text='Add') for entry in (self.entry_id, self.entry_min, self.entry_max, self.entry_rarity, self.code): intValidate(entry.entry, 'u16') title.pack(padx=10) self.entry_id.pack(fill=tk.X) self.entry_min.pack(fill=tk.X) self.entry_max.pack(fill=tk.X) self.entry_rarity.pack(fill=tk.X) sep.pack(fill=tk.X, pady=(12, 0), padx=5) override_lbl.pack() self.string.pack(fill=tk.X) self.code.pack(fill=tk.X) self.choices.pack(pady=(10, 5), expand=tk.YES, fill=tk.BOTH) self.add.pack(pady=(5, 0))
class ItemEditorGUI(ttk.Frame): def __init__(self, parent=None): ttk.Frame.__init__(self, parent) title = ttk.Label(self, text='Item Database Editor', style='Title.TLabel') self.sort = SortBox(self) self.items = ListChoice(self) sep = ttk.Separator(self) self.add_button = ttk.Button(self, text='Add') grid = WidgetGrid(self, 2) self.id = grid.add_widget(EntryLabel, text='ID', expand=tk.YES) self.price = grid.add_widget(EntryLabel, text='Sell Price', expand=tk.YES) self.name = grid.add_widget(EntryLabel, text='Name', expand=tk.YES) description_label = ttk.Label(self, text='Description') self.description = VariableText(self, height=10, width=50) title.pack() self.sort.pack(expand=tk.YES, fill=tk.X, pady=5) self.items.pack(expand=tk.YES, fill=tk.BOTH) self.add_button.pack() sep.pack(fill=tk.X, pady=(10, 0), padx=10) grid.pack(fill=tk.X) description_label.pack() self.description.pack(fill=tk.BOTH) intValidate(self.id.entry, 'u16') intValidate(self.price.entry, 'u32')
class CreditsEditorGUI(ttk.Frame): def __init__(self, parent=None): ttk.Frame.__init__(self, parent) title = ttk.Label(self, text='Credits Editor', style='Title.TLabel') self.checkVar = tk.IntVar() chk = ttk.Checkbutton(self, text='Add Before?', variable=self.checkVar) self.list = ListChoice(self) butFrame = ttk.Frame(self) self.add_text_button = ttk.Button(butFrame, text='Add Text', width=14) self.add_image_button = ttk.Button(butFrame, text='Add Image', width=14) entry_frm = ttk.Frame(self) self.x_pos = EntryLabel(entry_frm, text='X Position') self.y_buf = EntryLabel(entry_frm, text='Y Buffer') self.multi_widget = MultiWidget(self) title.pack() chk.pack() self.list.pack(expand=tk.YES, fill=tk.BOTH) butFrame.pack(fill=tk.X, pady=(5, 5)) self.add_text_button.pack(side=tk.LEFT, padx=10, expand=tk.YES) self.add_image_button.pack(side=tk.LEFT, padx=10, expand=tk.YES) entry_frm.pack(fill=tk.X) self.x_pos.pack(side=tk.LEFT, expand=tk.YES, fill=tk.X, padx=5) self.y_buf.pack(side=tk.LEFT, expand=tk.YES, fill=tk.X, padx=5) self.multi_widget.pack(fill=tk.BOTH) intValidate(self.x_pos.entry, 'u16') intValidate(self.y_buf.entry, 'u16')
class PlaylistEditorGUI(ttk.Frame): def __init__(self, parent=None): ttk.Frame.__init__(self, parent) title = ttk.Label(self, text='Playlist Editor', style='Title.TLabel') self.songs = ListChoice(self) self.name = EntryLabel(self, text='Song Name', width=50) self.button = ttk.Button(self, text='Add') title.pack() self.songs.pack(expand=tk.YES, fill=tk.BOTH) self.name.pack(fill=tk.X, pady=10) self.button.pack(fill=tk.X)
class TravelEditorGUI(ttk.Frame): def __init__(self, parent=None): ttk.Frame.__init__(self, parent) self.entries = [] title = ttk.Label(self, text='Travel Map Editor', style='Title.TLabel') self.maps = ListChoice(self) self.add_button = ttk.Button(self, text='Add') sep = ttk.Separator(self, orient=tk.HORIZONTAL) top = ttk.Frame(self) mid = ttk.Frame(self) bot = ttk.Frame(self) self.entry_x = EntryLabel(top, text='X Position') self.entry_y = EntryLabel(top, text='Y Position') self.entry_display = EntryLabel(mid, text='Display Name') self.entry_ref = EntryLabel(mid, text='Reference Name') self.entry_map = EntryLabel(bot, text='Map Name') self.entry_spawn = EntryLabel(bot, text='Spawn ID') self.entries += self.entry_x, self.entry_y, self.entry_display, self.entry_ref, self.entry_map, self.entry_spawn title.pack() self.maps.pack(expand=tk.YES, fill=tk.BOTH) self.add_button.pack(pady=10) sep.pack(fill=tk.X, padx=10) top.pack(fill=tk.BOTH) mid.pack(fill=tk.BOTH) bot.pack(fill=tk.BOTH) self.entry_x.pack(expand=tk.YES, fill=tk.X, side=tk.LEFT, padx=(0, 5)) self.entry_y.pack(expand=tk.YES, fill=tk.X, side=tk.LEFT, padx=(5, 0)) self.entry_display.pack(expand=tk.YES, fill=tk.X, side=tk.LEFT, padx=(0, 5)) self.entry_ref.pack(expand=tk.YES, fill=tk.X, side=tk.LEFT, padx=(5, 0)) self.entry_map.pack(expand=tk.YES, fill=tk.X, side=tk.LEFT, padx=(0, 5)) self.entry_spawn.pack(expand=tk.YES, fill=tk.X, side=tk.LEFT, padx=(5, 0), pady=(10, 2)) for entry in self.entry_x, self.entry_y, self.entry_spawn: intValidate(entry.entry, 'u16')
class OptionEdit(SimpleLine): LABEL = 'Display Line:' def __init__(self, parent): SimpleLine.__init__(self, parent) option_lbl = ttk.Label(self, text='Options', style='Subtitl.TLabel') self.options = ListChoice(self) self.add_option = ttk.Button(self, text='Add') self.option_display = EntryLabel(self, text='Option Line') self.jump = EntryLabel(self, text='Jump Point') option_lbl.pack() self.options.pack(expand=tk.YES, fill=tk.BOTH) self.add_option.pack() self.option_display.pack(expand=tk.YES, fill=tk.X) self.jump.pack(expand=tk.YES, fill=tk.X)
class FollowPath(ttk.Frame): def __init__(self, parent=None): ttk.Frame.__init__(self, parent) self.nodes = [] self.check = ttk.Checkbutton(self, text='Reverse loop') self.node_list = ListChoice(self) lbl = ttk.Label(self, text='Direction') self.direction = ttk.Combobox(self, justify=tk.CENTER, value=(D_UP, D_LEFT, D_RIGHT, D_DOWN)) self.steps = EntryLabel(self, text='Number of Steps') self.add_button = ttk.Button(self, text='Add') self.check.pack() self.node_list.pack(expand=tk.YES, fill=tk.BOTH) lbl.pack() self.direction.pack(fill=tk.X) self.steps.pack(fill=tk.X) self.add_button.pack(pady=5) self.direction.state(['readonly']) intValidate(self.steps.entry, 'u8')
class PeoplemonEditorGUI(ttk.Frame): def __init__(self, parent=None): ttk.Frame.__init__(self, parent) lft_frm = ttk.Frame(self) title = ttk.Label(lft_frm, text='Move Database Editor', style='Title.TLabel') self.sort = SortBox(lft_frm) self.items = ListChoice(lft_frm, width=50, height=12) self.add_button = ttk.Button(lft_frm, text='Add') sep6 = ttk.Separator(lft_frm) desc_lbl = ttk.Label(lft_frm, text='Description', style='Subtitle.TLabel') self.description = VariableText(lft_frm, width=40, height=10) sep = ttk.Separator(self, orient=tk.VERTICAL) middle_frm = ttk.Frame(self) grid = WidgetGrid(middle_frm, 4) self.id = grid.add_widget(EntryLabel, text='ID', expand=tk.YES) self.name = grid.add_widget(EntryLabel, text='Name', expand=tk.YES) self.base_xp = grid.add_widget(EntryLabel, text='Base XP Yield', expand=tk.YES) self.xp_group = grid.add_widget(ComboLabel, text='XP Group', expand=tk.YES) self.special_id = grid.add_widget(EntryLabel, text='Special Ability ID', expand=tk.YES) self.type = grid.add_widget(EntryLabel, text='Type', expand=tk.YES) self.evolve_level = grid.add_widget(EntryLabel, text='Evolve Level', expand=tk.YES) self.evolve_id = grid.add_widget(EntryLabel, text='Evolve ID', expand=tk.YES) sep2 = ttk.Separator(middle_frm) base_frm = ttk.Frame(middle_frm) self.base_stats = StatsGUI(base_frm, title='Base Stats') sep3 = ttk.Separator(base_frm, orient=tk.VERTICAL) self.ev_stats = StatsGUI(base_frm, title='EV Awards') sep4 = ttk.Separator(middle_frm) learn_move_frm = ttk.Frame(middle_frm) move_lbl = ttk.Label(learn_move_frm, text='Learned Moves', style='Subtitle.TLabel') self.learn_list = ListChoice(learn_move_frm, width=40, height=8) self.add_learn_move = ttk.Button(learn_move_frm, text='Add') move_frm = ttk.Frame(learn_move_frm) self.learn_move_id = EntryLabel(move_frm, text='Move ID') self.learn_level = EntryLabel(move_frm, text='Learn Level') sep5 = ttk.Separator(middle_frm, orient=tk.VERTICAL) available_frm = ttk.Frame(middle_frm) available_lbl = ttk.Label(available_frm, text='Available Moves', style='Subtitle.TLabel') self.available_list = ListChoice(available_frm, width=40, height=8) self.add_available_button = ttk.Button(available_frm, text='Add') self.available_move_id = EntryLabel(available_frm, text='Move ID') lft_frm.pack(side=tk.LEFT, expand=tk.YES, fill=tk.BOTH) title.pack() self.sort.pack(fill=tk.X, pady=5) self.items.pack(expand=tk.YES, fill=tk.BOTH) self.add_button.pack() sep6.pack(fill=tk.X, padx=10, pady=10) desc_lbl.pack() self.description.pack(expand=tk.YES, fill=tk.BOTH) sep.pack(side=tk.LEFT, fill=tk.Y, padx=10, pady=10) middle_frm.pack(side=tk.LEFT, fill=tk.BOTH) grid.pack(fill=tk.X) sep2.pack(fill=tk.X, pady=(10, 0), padx=10) base_frm.pack(fill=tk.X) self.base_stats.pack(side=tk.LEFT, expand=tk.YES, fill=tk.X) sep3.pack(side=tk.LEFT, fill=tk.Y, padx=10, pady=10) self.ev_stats.pack(side=tk.LEFT, expand=tk.YES, fill=tk.X) sep4.pack(fill=tk.X, pady=10, padx=10) learn_move_frm.pack(side=tk.LEFT, fill=tk.BOTH) move_lbl.pack() self.learn_list.pack(expand=tk.YES, fill=tk.BOTH) self.add_learn_move.pack(pady=(3, 0)) move_frm.pack(fill=tk.X) self.learn_move_id.pack(side=tk.LEFT, expand=tk.YES, fill=tk.X, padx=2) self.learn_level.pack(side=tk.LEFT, expand=tk.YES, fill=tk.X, padx=2) sep5.pack(side=tk.LEFT, fill=tk.Y, padx=10, pady=10) available_frm.pack(side=tk.LEFT, fill=tk.BOTH) available_lbl.pack() self.available_list.pack(expand=tk.YES, fill=tk.BOTH) self.add_available_button.pack(pady=(3, 0)) self.available_move_id.pack(fill=tk.X) for widget in self.type, self.special_id, self.learn_level, self.evolve_level, self.evolve_id: intValidate(widget.entry, 'u8') for widget in self.id, self.base_xp, self.available_move_id, self.learn_move_id: intValidate(widget.entry, 'u16')
class MoveEditorGUI(ttk.Frame): def __init__(self, parent=None): ttk.Frame.__init__(self, parent) lft_frm = ttk.Frame(self) title = ttk.Label(lft_frm, text='Move Database Editor', style='Title.TLabel') self.sort = SortBox(lft_frm) self.items = ListChoice(lft_frm, width=50) self.add_button = ttk.Button(lft_frm, text='Add') right_frm = ttk.Frame(self) sep2 = ttk.Separator(self, orient=tk.VERTICAL) self.name = EntryLabel(right_frm, text='Name') id_frm = ttk.Frame(right_frm) self.id = EntryLabel(id_frm, text='ID') self.classification = ComboLabel(id_frm, text='Move Classification', values=list(CLASSIFICATIONS.keys())) grid = WidgetGrid(right_frm, 3) self.attack = grid.add_widget(EntryLabel, text='Attack') self.accuracy = grid.add_widget(EntryLabel, text='Accuracy') self.effect = grid.add_widget(EntryLabel, text='Effect') self.priority = grid.add_widget(EntryLabel, text='Priority') self.pp = grid.add_widget(EntryLabel, text='PP') self.type = grid.add_widget(EntryLabel, text='Type') self.chance = grid.add_widget(EntryLabel, text='Chance of Effect') self.intensity = grid.add_widget(EntryLabel, text='Effect Intensity') self.score = grid.add_widget(EntryLabel, text='Effect Score') self.attacker_anim = grid.add_widget(EntryLabel, text='Attacker Anim', expand=tk.YES) self.defender_anim = grid.add_widget(EntryLabel, text='Defender Anim', expand=tk.YES) chk_frm = ttk.Frame(right_frm) self.is_special = ttk.Checkbutton(chk_frm, text='Is Special') self.targets_self = ttk.Checkbutton(chk_frm, text='Targets Self') description_label = ttk.Label(right_frm, text='Description') self.description = VariableText(right_frm, height=10, width=40) lft_frm.pack(side=tk.LEFT, expand=tk.YES, fill=tk.BOTH) title.pack() self.sort.pack(fill=tk.X, pady=5) self.items.pack(expand=tk.YES, fill=tk.BOTH) self.add_button.pack() right_frm.pack(fill=tk.BOTH, side=tk.RIGHT) sep2.pack(expand=tk.YES, fill=tk.Y, padx=10, pady=10) self.name.pack(fill=tk.X) id_frm.pack(fill=tk.X) self.id.pack(side=tk.LEFT, fill=tk.X, padx=2) self.classification.pack(side=tk.LEFT, expand=tk.YES, fill=tk.X, padx=(2, 2)) grid.pack(fill=tk.BOTH) chk_frm.pack() self.is_special.pack(side=tk.LEFT, fill=tk.X) self.targets_self.pack(side=tk.LEFT, fill=tk.X) description_label.pack() self.description.pack(expand=tk.YES, fill=tk.BOTH) self.classification.state(('readonly', )) for widget in self.id, self.attack, self.accuracy, self.priority, self.pp: intValidate(widget.entry, 'u16') for widget in self.type, self.effect, self.intensity, self.score, self.chance: intValidate(widget.entry, 'u8')
class TrainerEditorGUI(ttk.Frame): def __init__(self, parent=None): ttk.Frame.__init__(self, parent) self.aiTypes = { AI_RANDOM: 0, AI_DUMB: 1, AI_SMART: 2, AI_SUICIDAL: 3, AI_AGGRESSIVE: 4, AI_DEFENSIVE: 5, AI_AVERAGE: 6, AI_ADAPTIVE: 7 } title = ttk.Label(self, text='Trainer Editor', style='Title.TLabel') left_frm = ttk.Frame(self) grid = WidgetGrid(left_frm, 2) self.name = grid.add_widget(EntryLabel, text='Trainer Name') self.anim_name = grid.add_widget(EntryLabel, text='Animation Name') self.before_convo = grid.add_widget(EntryLabel, text='Before Battle Convo') self.after_convo = grid.add_widget(EntryLabel, text='After Battle Convo') self.lost_text = grid.add_widget(EntryLabel, text='Lost Battle Text') self.sight_range = grid.add_widget(EntryLabel, text='Sight Range') self.playlist = grid.add_widget(EntryLabel, text='Playlist') self.background = grid.add_widget(EntryLabel, text='Background Image') grid.add_widget(ttk.Label, text='AI Type', width=12, anchor=tk.CENTER) grid.add_widget(ttk.Label, text='Motion Type', width=12, anchor=tk.CENTER) self.ai_type = grid.add_widget( ttk.Combobox, values=(AI_RANDOM, AI_DUMB, AI_SMART, AI_SUICIDAL, AI_AGGRESSIVE, AI_DEFENSIVE, AI_AVERAGE, AI_ADAPTIVE), justify=tk.CENTER) self.motion_type = grid.add_widget(ttk.Combobox, values=(B_STILL, B_SPIN, B_FOLLOW, B_WANDER), justify=tk.CENTER) sep = ttk.Separator(left_frm) second_row = ttk.Frame(left_frm) col1 = ttk.Frame(second_row) peoplemon_lbl = ttk.Label(col1, text='Peoplemon List') self.peoplemon_list = ListChoice(col1) self.file_name = EntryLabel(col1, text='Filename') self.add_peoplemon = ttk.Button(col1, text='Add') col2 = ttk.Frame(second_row) item_lbl = ttk.Label(col2, text='Item List') self.item_list = ListChoice(col2) self.item_id = EntryLabel(col2, text='Item ID') self.add_item = ttk.Button(col2, text='Add') self.right_frm = ttk.Frame(self) sep2 = ttk.Separator(self.right_frm, orient=tk.VERTICAL) motion_lbl = ttk.Label(self.right_frm, text='Motion Options', style='Subtitle.TLabel') self.behavior_widget = BehaviorWidget(self.right_frm) title.pack() left_frm.pack(expand=tk.YES, fill=tk.BOTH, side=tk.LEFT) grid.pack(expand=tk.YES, fill=tk.X) sep.pack(expand=tk.YES, fill=tk.X, padx=10, pady=5) second_row.pack(expand=tk.YES, fill=tk.BOTH, padx=20) col1.pack(side=tk.LEFT, expand=tk.YES, fill=tk.BOTH, padx=(0, 20)) col2.pack(side=tk.LEFT, expand=tk.YES, fill=tk.BOTH, padx=(20, 0)) peoplemon_lbl.pack() self.peoplemon_list.pack(expand=tk.YES, fill=tk.BOTH) self.file_name.pack(expand=tk.YES, fill=tk.X) self.add_peoplemon.pack(pady=(10, 0)) item_lbl.pack() self.item_list.pack(expand=tk.YES, fill=tk.BOTH) self.item_id.pack(expand=tk.YES, fill=tk.X) self.add_item.pack(pady=(10, 0)) self.right_frm.pack(fill=tk.BOTH, side=tk.LEFT) sep2.pack(fill=tk.Y, padx=(10, 0), side=tk.LEFT) motion_lbl.pack(padx=10) self.behavior_widget.pack(expand=tk.YES, fill=tk.BOTH) self.ai_type.state(['readonly']) self.motion_type.state(['readonly']) intValidate(self.sight_range.entry, 'u8') intValidate(self.item_id.entry, 'u16')
class Editor(ttk.Frame): UP = 1 DOWN = 2 LEFT = 3 RIGHT = 4 def __init__(self, parent, controller): ttk.Frame.__init__(self, parent) self.controller = controller self.sidebar = ttk.Frame(self) self.center_side = ttk.Frame(self) self.right_side = ttk.Frame(self) self.image_list = ListChoice(self.sidebar) self.preview = CanvasPlus(self.sidebar, width=1, height=200, borderwidth=2, relief=tk.SUNKEN, background='white') self.frame_select = ttk.Scale(self.center_side, from_=1, to=1, command=self.on_frame_scale_changed) self.frame_label = ttk.Label(self.center_side, text='Frame', style='Title.TLabel') self.canvas = CanvasPlus(self.center_side, width=SIZE[0], height=SIZE[1], highlightthickness=0, background='white') self.length_var = tk.IntVar(self) self.frame_trace = self.length_var.trace_variable( 'w', self.change_length) self.length = EntryLabel(self.right_side, text="Frame Length", entry_variable=self.length_var) intValidate(self.length.entry, 'u16') self.trans_var = tk.IntVar(self) self.transparency = ttk.Scale(self.right_side, from_=0, to=255, command=self.change_transparency) self.transparency_alt = ttk.Entry(self.right_side, width=15, justify=tk.CENTER, textvariable=self.trans_var) intValidate(self.transparency_alt, 'u8') self.apply = ttk.Button(self.right_side, text='Apply', command=self.apply_transparency) self.sidebar.pack(side=tk.LEFT, expand=tk.YES, fill=tk.BOTH) ttk.Label(self.sidebar, text='Images', style='Title.TLabel').pack() self.image_list.pack(side=tk.TOP, expand=tk.YES, fill=tk.BOTH) self.preview.pack(side=tk.TOP, expand=tk.YES, fill=tk.BOTH) ttk.Button(self.sidebar, text='Insert Image', command=self.insert_image).pack(pady=(3, 5)) self.center_side.pack(side=tk.LEFT, fill=tk.Y) self.frame_label.pack() self.frame_select.pack(fill=tk.X) self.canvas.pack() self.canvas.bind('<Control-Prior>', self.move_forward) self.canvas.bind('<Control-Next>', self.move_backward) self.canvas.bind('<Prior>', lambda event: self.handle_next(event, False)) self.canvas.bind('<Next>', lambda event: self.handle_next(event, True)) self.canvas.bind('<Delete>', self.on_delete_click) self.canvas.bind('<Control-Button-1>', self.on_ctrl_click) self.canvas.bind('<Control-B1-Motion>', self.on_ctrl_drag) self.canvas.bind('<Button-1>', self.on_left_click) self.canvas.bind('<Button-3>', self.on_right_click) self.canvas.bind('<Up>', lambda event: self.move(Editor.UP)) self.canvas.bind('<Down>', lambda event: self.move(Editor.DOWN)) self.canvas.bind('<Left>', lambda event: self.move(Editor.LEFT)) self.canvas.bind('<Right>', lambda event: self.move(Editor.RIGHT)) self.canvas.bind('<Control-c >', self.copy) self.canvas.bind('<Control-v >', self.paste) self.right_side.pack(side=tk.LEFT, fill=tk.Y) ttk.Label(self.right_side, text='Frame Settings', style='Title.TLabel').pack(pady=(10, 10)) self.length.pack() ttk.Label(self.right_side, text='Selection Transparency').pack(pady=(10, 0)) self.transparency.pack(fill=tk.X, padx=(3, 3)) self.transparency_alt.pack() self.apply.pack(pady=(5, 0)) ttk.Button(self.right_side, text='Preview', command=self.preview_anim).pack(pady=(30, 0)) self.cur_preview = None # Stores current preview image to prevent garbage collection self.outline = None # Stores the current outline object self.copied = None # Stroes a DrawnImage object that was copied # Create the background photo image = Image.open('resources\\layout.png') self.background = ImageTk.PhotoImage(image) self.canvas.create_image(image.size[0] // 2, image.size[1] // 2, image=self.background) self.transparency.set(255) self.toggle_transparency() self.controller.animation.frames.signal_add.connect( self.on_frame_add_or_remove) self.controller.animation.frames.signal_remove.connect( self.on_frame_add_or_remove) self.controller.animation.images.signal_add.connect( self.on_preview_add) self.controller.animation.images.signal_remove.connect( self.on_preview_remove) self.image_list.signal_select.connect(self.on_preview_selected) self.image_list.signal_delete.connect(self.on_preview_deleted) self.controller.editor_model.signal_frame_changed.connect( self.on_frame_change) self.on_frame_change(0) def on_left_click(self, event): clicked_image = self.selected_image(self.canvas.canvasx(event.x), self.canvas.canvasy(event.y)) if type(clicked_image ) == DrawnImage and clicked_image != self.get_selected(): self.select(clicked_image) def on_right_click(self, event): pos = (self.canvas.canvasx(event.x), self.canvas.canvasy(event.y)) selected = self.selected_image(*pos) is not None self.on_left_click(event) menu = SimpleMenu(self, tearoff=0) if self.cur_preview is not None: menu.add_action('Insert', lambda: self.insert_image(pos)) if selected: menu.add_action('Copy', self.copy) if self.copied is not None: menu.add_action('Paste', lambda: self.paste_at(pos)) if selected: menu.add_action('Move Back', self.move_backward) menu.add_action('Move Forward', self.move_forward) menu.add_action('Delete', self.on_delete_click) menu.tk_popup(event.x_root, event.y_root) def on_ctrl_click(self, event): self.canvas.scan_mark(event.x, event.y) def on_ctrl_drag(self, event): self.canvas.scan_dragto(event.x, event.y, gain=1) def on_delete_click(self, event=None): if self.get_selected() is None: return self.controller.animation.frames[ self.controller.editor_model.current_frame].images.remove( self.get_selected()) self.set_selected(None) self.toggle_transparency() def move_backward(self, event=None): self.move_depth(operator.sub) def move_forward(self, event=None): self.move_depth(operator.add) def move_depth(self, op): if self.get_selected(): frame = self.controller.animation.frames[ self.controller.editor_model.current_frame] ind = frame.images.index(self.get_selected()) next_ind = max(0, min(op(ind, 1), len(frame.images))) print(ind, next_ind) frame.images.remove(self.get_selected()) frame.images.insert(next_ind, self.get_selected()) self.outline.draw(self.canvas) def on_preview_add(self, ind, anim_img): logging.info("Loading Image " + anim_img.name) img = DrawnImage(anim_img) self.image_list.append(img) self.image_list.set_selection(-1) def on_preview_remove(self, ind, anim_img): to_remove = (ind for ind, img in enumerate(self.image_list) if img.anim_img == anim_img) for ind in to_remove: img = self.image_list.pop(ind) if self.preview: img.destroy(self.preview) self.controller.editor_model.current_frame = self.controller.editor_model.current_frame def on_preview_selected(self, ind): if ind is None: if self.cur_preview is not None: self.cur_preview.destroy(self.preview) return img = self.image_list[ind] img.scale_max(self.preview) img.center(self.preview) if self.cur_preview: self.preview.delete(tk.ALL) img.draw(self.preview) self.cur_preview = img def on_preview_deleted(self): ind = self.image_list.get_selection() if ind is None: return anim_image = self.controller.animation.images[ind] answer = None for frame in self.controller.animation.frames: new = [ image for image in frame.images if image.anim_img == anim_image ] if len(new) and answer is None: answer = askokcancel( title='Delete Image', message='Deleting this image will also delete it ' 'from all frames of the animation') if answer is False: return for image in new: frame.images.remove(image) self.controller.animation.images.pop(ind) def on_image_add(self, ind, image): logging.info("Adding {} level: {}".format(image.name, image.level)) frame = self.controller.animation.frames[ self.controller.editor_model.current_frame] image.level = ind image.draw(self.canvas) for i in range(ind + 1, len(frame.images)): img = frame.images[i] img.level = i img.redraw(self.canvas) self.select(image) def on_image_remove(self, ind, image): logging.info("Removing {} level: {}".format(image.name, image.level)) frame = self.controller.animation.frames[ self.controller.editor_model.current_frame] if image == self.get_selected(): self.outline.destroy(self.canvas) image.destroy(self.canvas) for i in range(ind, len(frame.images)): img = frame.images[i] img.level = ind img.redraw(self.canvas) def on_frame_add_or_remove(self, ind, frame): self.frame_select.config(to=len(self.controller.animation.frames)) def on_frame_scale_changed(self, event): """ Event handler for when the frame selector scale is moved event -> The event object pre-conditions: self.cur_frame is valid index into self.frames post-conditions: Frame changed if number changed enough return -> None """ num = self.frame_select.get() rounded = round(num) if rounded != num: self.frame_select.set(rounded) return if num - 1 != self.controller.editor_model.current_frame: self.controller.editor_model.current_frame = num - 1 def on_frame_change(self, ind): if self.outline: self.outline.destroy(self.canvas) self.frame_label.config(text='Frame {}'.format(ind + 1)) self.canvas.delete('drawn_image') self.canvas.delete('outline') self.frame_select.set(ind + 1) if self.controller.editor_model.current_frame != 0: last_frm = self.controller.animation.frames[ind - 1] last_frm.draw_half_transparent(self.canvas) frame = self.controller.animation.frames[ind] self.length_var.set(frame.length) frame.draw(self.canvas) frame.images.signal_add.connect(self.on_image_add) frame.images.signal_remove.connect(self.on_image_remove) if self.get_selected(): self.select(self.get_selected()) self.toggle_transparency() def insert_image(self, pos=None): """ Inserts the currently selected image into the current frame pre-conditions: self.cur_preview is a CanvasImage object self.cur_frame is a valid index of a Frame in self.frames post-conditions: Image is inserted into current frame return -> None """ if self.cur_preview is None: return frame = self.controller.animation.frames[ self.controller.editor_model.current_frame] img = self.cur_preview new = img.copy() new.canvas = self.canvas new.scale_original() if pos is not None: new.x = int(pos[0] - new.width / 2) new.y = int(pos[1] - new.height / 2) else: new.center(self.canvas) frame.images.append(new) def selected_image(self, x, y): self.canvas.focus_set() references = self.canvas.find_overlapping_references(x, y, x, y) for ref in reversed(references): if type(ref) == Outline: return ref if type(ref) == DrawnImage: center_x, center_y = ref.get_center() top_left_x = center_x - (ref.scaled_img.size[0] / 2) top_left_y = center_y - (ref.scaled_img.size[1] / 2) x_, y_ = int(x - top_left_x), int(y - top_left_y) transparency = ref.scaled_img.load()[x_, y_][3] if transparency > 0: return ref return None def select(self, image): """ Selects an image on the canvas for editing. Draws outline around image image -> The CanvasImage object to select pre-conditions: Image is drawn on the canvas post-conditions: The image is selected return -> None """ if self.outline: self.outline.destroy(self.canvas) self.set_selected(image) self.controller.animation.frames[ self.controller.editor_model.current_frame].last_selected = image self.outline = Outline(self.canvas, image) self.outline.draw(self.canvas) self.toggle_transparency() self.transparency.set(image.transparency) self.trans_var.set(image.transparency) def copy(self, event=None): self.copied = self.get_selected().copy() def paste(self, event): self.paste_at() def paste_at(self, location=None): if self.copied: frm = self.controller.animation.frames[ self.controller.editor_model.current_frame] cpy = self.copied.copy() if location: cpy.x = int(location[0] - cpy.width / 2) cpy.y = int(location[1] - cpy.height / 2) frm.images.append(cpy) self.select(cpy) def toggle_transparency(self): if self.get_selected(): self.transparency.state(['!disabled']) self.transparency_alt.state(['!disabled']) self.apply.state(['!disabled']) else: self.transparency.state(['disabled']) self.transparency_alt.state(['disabled']) self.apply.state(['disabled']) def handle_next(self, event, prev): """ Event handler for toggling selection to the next image event -> The event object prev -> True if the previous image should actually be selected, otherwise false pre-conditions: self.cur_frame is a valid index of self.frames post-conditions: Current selected object is changed """ images = self.controller.animation.frames[ self.controller.editor_model.current_frame].images if self.get_selected(): ind = images.index(self.get_selected()) if prev: ind -= 1 else: ind += 1 img = images[ind % len(images)] self.select(img) elif len(images) != 0: self.select(images[0]) def change_length(self, name, empty, mode): try: num = int(self.length_var.get()) except ValueError: return if num != self.controller.animation.frames[ self.controller.editor_model.current_frame].length: self.controller.animation.frames[ self.controller.editor_model.current_frame].length = num def change_transparency(self, event): if self.get_selected(): transparency = round(self.transparency.get()) self.get_selected().transparency = transparency self.trans_var.set(transparency) self.get_selected().destroy(self.canvas) self.get_selected().draw(self.canvas) self.outline.destroy(self.canvas) self.outline.draw(self.canvas) def apply_transparency(self): if self.outline: transparency = self.trans_var.get() self.transparency.set(transparency) self.change_transparency(None) def move(self, direction): if not self.get_selected(): return if direction == Editor.UP: self.get_selected().y -= 1 self.outline.move(0, -1) elif direction == Editor.DOWN: self.get_selected().y += 1 self.outline.move(0, 1) elif direction == Editor.RIGHT: self.get_selected().x += 1 self.outline.move(1, 0) elif direction == Editor.LEFT: self.get_selected().x -= 1 self.outline.move(-1, 0) self.outline.redraw(self.canvas) def preview_anim(self): def clear_canvas(): self.canvas.delete('drawn_image') self.canvas.delete('outline') clear_canvas() for frame in self.controller.animation.frames: start = time.time() clear_canvas() frame.draw(self.canvas) self.canvas.update_idletasks() self.canvas.update() end = time.time() wait = frame.length / 1000 - (end - start) wait = 0 if wait < 0 else wait time.sleep(wait) self.controller.editor_model.current_frame = self.controller.editor_model.current_frame def set_selected(self, img): self.controller.animation.frames[ self.controller.editor_model.current_frame].last_selected = img def get_selected(self): return self.controller.animation.frames[ self.controller.editor_model.current_frame].last_selected