class AddMissingBonesDialog(wx.Dialog): def __init__(self, parent, missing_bones, *args, **kw): super().__init__(parent, *args, **kw) self.SetTitle("Add Missing Bones") self.missing_bones = missing_bones self.bone_list = TreeListCtrl(self, size=(-1, 250), style=TL_MULTIPLE | TL_CHECKBOX) self.bone_list.AppendColumn("Bone") root = self.bone_list.GetRootItem() for bone in missing_bones: item = self.bone_list.AppendItem(root, bone.name, data=bone) self.bone_list.CheckItem(item) add_button = wx.Button(self, wx.ID_OK, "Add") add_button.SetDefault() no_add_button = wx.Button(self, wx.ID_CANCEL, "Don't Add") button_sizer = wx.BoxSizer(wx.HORIZONTAL) button_sizer.Add(add_button, 0, wx.LEFT | wx.RIGHT, 2) button_sizer.Add(no_add_button, 0, wx.LEFT | wx.RIGHT, 5) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add( wx.StaticText( self, -1, 'The current EAN is missing the following bones.\n' 'Do you want to add them?'), 0, wx.ALL, 10) sizer.Add(self.bone_list, 1, wx.ALL | wx.EXPAND, 10) sizer.Add(wx.StaticLine(self), 0, wx.EXPAND | wx.ALL, 10) sizer.Add(button_sizer, 0, wx.ALIGN_CENTER | wx.TOP | wx.BOTTOM, 10) self.SetSizer(sizer) sizer.Fit(self) self.Layout() def GetValues(self): missing_bones = [] item = self.bone_list.GetFirstItem() while item.IsOk(): if self.bone_list.GetCheckedState(item) == wx.CHK_CHECKED: missing_bones.append(self.bone_list.GetItemData(item)) item = self.bone_list.GetNextItem(item) return missing_bones
class MainPanel(wx.Panel): def __init__(self, parent): wx.Panel.__init__(self, parent) self.bdm = None self.parent = parent self.entry_list = TreeListCtrl(self, style=TL_MULTIPLE) self.entry_list.AppendColumn("Entry") self.entry_list.Bind(EVT_TREELIST_ITEM_CONTEXT_MENU, self.on_right_click) self.entry_list.Bind(EVT_TREELIST_SELECTION_CHANGED, self.on_select) self.cdo = wx.CustomDataObject("BDMEntry") self.Bind(wx.EVT_MENU, self.on_delete, id=wx.ID_DELETE) self.Bind(wx.EVT_MENU, self.on_copy, id=wx.ID_COPY) self.Bind(wx.EVT_MENU, self.on_paste, id=wx.ID_PASTE) self.Bind(wx.EVT_MENU, self.on_new, id=wx.ID_NEW) accelerator_table = wx.AcceleratorTable([ (wx.ACCEL_CTRL, ord('c'), wx.ID_COPY), (wx.ACCEL_CTRL, ord('v'), wx.ID_PASTE), (wx.ACCEL_NORMAL, wx.WXK_DELETE, wx.ID_DELETE), ]) self.entry_list.SetAcceleratorTable(accelerator_table) pub.subscribe(self.on_select, 'on_select') pub.subscribe(self.convert_for_skill_creator, 'convert_for_skill_creator') # Use some sizers to see layout options sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(self.entry_list, 1, wx.ALL | wx.EXPAND, 10) # Layout sizers self.SetSizer(sizer) self.SetAutoLayout(1) def build_tree(self): self.entry_list.DeleteAllItems() root = self.entry_list.GetRootItem() for entry in sorted(self.bdm.entries, key=lambda e: e.id): self.entry_list.AppendItem(root, f'{entry.id}: Entry', data=entry) def get_current_entry_ids(self): entry_ids = [] item = self.entry_list.GetFirstItem() while item.IsOk(): data = self.entry_list.GetItemData(item) entry_ids.append(data.id) item = self.entry_list.GetNextItem(item) return entry_ids def get_previous_entry(self, entry_id): item = self.entry_list.GetFirstItem() prev = TLI_FIRST while item.IsOk(): data = self.entry_list.GetItemData(item) if data.id > entry_id: break prev, item = item, self.entry_list.GetNextItem(item) return prev def on_right_click(self, _): selected = self.entry_list.GetSelections() if not selected: return menu = wx.Menu() menu.Append(wx.ID_NEW) menu.Append(wx.ID_DELETE) menu.Append(wx.ID_COPY) paste = menu.Append(wx.ID_PASTE) add = menu.Append(wx.ID_ADD, '&Add Copied Entry') success = False # Check Clipboard if wx.TheClipboard.Open(): success = wx.TheClipboard.IsSupported(wx.DataFormat("BDMEntry")) wx.TheClipboard.Close() add.Enable(success) paste.Enable(success) self.PopupMenu(menu) menu.Destroy() def on_select(self, _): selected = self.entry_list.GetSelections() if len(selected) != 1: pub.sendMessage('disable') return pub.sendMessage('load_entry', entry=self.entry_list.GetItemData(selected[0])) def add_entry(self, entry): root = self.entry_list.GetRootItem() prev = self.get_previous_entry(entry.id) item = self.entry_list.InsertItem(root, prev, f'{entry.id}: Entry', data=entry) self.entry_list.Select(item) self.on_select(None) def on_new(self, _): # Ask for ID if self.bdm is None: return with NewEntryDialog(self, self.get_current_entry_ids()) as dlg: if dlg.ShowModal() != wx.ID_OK: return entry_id = dlg.GetValue() self.entry_list.UnselectAll() # Add it entry = Entry(entry_id=entry_id) self.add_entry(entry) pub.sendMessage('set_status_bar', text='Added new entry') def on_add(self, _): if self.bdm is None: return cdo = wx.CustomDataObject("BDMEntry") success = False if wx.TheClipboard.Open(): success = wx.TheClipboard.GetData(cdo) wx.TheClipboard.Close() if not success: with wx.MessageDialog(self, 'Unable to get copied data') as dlg: dlg.ShowModal() return paste_data = pickle.loads(cdo.GetData()) # Get new Id's with NewEntryDialog(self, self.get_current_entry_ids()) as dlg: if dlg.ShowModal() != wx.ID_OK: return entry_id = dlg.GetValue() current_entry_ids = self.get_current_entry_ids() self.entry_list.UnselectAll() # Paste for paste in paste_data: while entry_id in current_entry_ids: entry_id += 1 entry = Entry(entry_id=entry_id) entry.paste(paste) self.add_entry(entry) entry_id += 1 self.on_select(None) pub.sendMessage(f'Pasted {len(paste_data)} new entry(s)') def on_delete(self, _): selected = self.entry_list.GetSelections() if not selected: return for item in selected: self.entry_list.DeleteItem(item) pub.sendMessage('disable') pub.sendMessage('set_status_bar', text=f'Deleted {len(selected)} entries') def on_copy(self, _): selected = self.entry_list.GetSelections() self.cdo = wx.CustomDataObject("BDMEntry") self.cdo.SetData( pickle.dumps( [self.entry_list.GetItemData(item) for item in selected])) if wx.TheClipboard.Open(): wx.TheClipboard.SetData(self.cdo) wx.TheClipboard.Flush() wx.TheClipboard.Close() pub.sendMessage('set_status_bar', text=f'Copied {len(selected)} entries') def on_paste(self, _): selected = self.entry_list.GetSelections() if not selected: return success = False cdo = wx.CustomDataObject("BDMEntry") if wx.TheClipboard.Open(): success = wx.TheClipboard.GetData(cdo) wx.TheClipboard.Close() if success: paste_data = pickle.loads(cdo.GetData()) paste_length = len(paste_data) selected_length = len(selected) if selected_length > paste_length: for item in selected[paste_length:]: self.entry_list.Unselect(item) selected = selected[:paste_length] item = selected[-1] self.entry_list.Select(item) for n in range(paste_length - selected_length): item = self.entry_list.GetNextItem(item) if not item.IsOk(): with wx.MessageDialog( self, f'Not enough entries to paste over. Expected {paste_length}' ) as dlg: dlg.ShowModal() return self.entry_list.Select(item) selected.append(item) if len(selected) > 1: msg = '\n'.join([ f' * {self.entry_list.GetItemData(item).id}: Entry' for item in selected ]) with MultiMessageDialog( self, 'Are you sure you want to replace the following entries?', 'Warning', msg, wx.YES | wx.NO) as dlg: if dlg.ShowModal() != wx.ID_YES: return for n, paste in enumerate(paste_data): data = self.entry_list.GetItemData(selected[n]) data.paste(paste) self.on_select(None) pub.sendMessage('set_status_bar', text=f'Pasted {len(paste_data)} entry(s)') def convert_for_skill_creator(self): if not self.bdm: with wx.MessageDialog(self, "No BDM loaded!", "Error") as dlg: dlg.ShowModal() return # Get choices choices = set() item = self.entry_list.GetFirstItem() effect_ids = [ 'effect_1_skill_id', 'effect_2_skill_id', 'effect_3_skill_id' ] while item.IsOk(): data = self.entry_list.GetItemData(item) item = self.entry_list.GetNextItem(item) for sub_entry in data.sub_entries: for effect_id in effect_ids: try: if sub_entry[effect_id] != 0 and sub_entry[ effect_id] != 0xFFFF and sub_entry[ effect_id] != 0xBACA: choices.update([str(sub_entry[effect_id])]) except Exception as e: pass if not choices: with wx.MessageDialog(self, "Cannot find any Skill IDs to convert", "Error") as dlg: dlg.ShowModal() return # Show Dialog with ConvertDialog(self, list(choices)) as dlg: if dlg.ShowModal() != wx.ID_OK: return skill_id = dlg.GetValue() # Do Conversion item = self.entry_list.GetFirstItem() changed = 0 while item.IsOk(): data = self.entry_list.GetItemData(item) item = self.entry_list.GetNextItem(item) for sub_entry in data.sub_entries: for effect_id in effect_ids: if sub_entry[effect_id] == skill_id: try: sub_entry[effect_id] = 0xBACA changed += 1 except Exception: pass self.on_select(None) pub.sendMessage('set_status_bar', text=f'Changed {changed} skill ids to 0xBACA') def reindex(self): selected = self.entry_list.GetSelections() if len(selected) != 1: return item = selected[0] entry = self.entry_list.GetItemData(item) self.entry_list.DeleteItem(item) self.add_entry(entry)
class SidePanel(wx.Panel): def __init__(self, parent): wx.Panel.__init__(self, parent) self.code = '' self.bac = None self.bdm = None self.ean = None self.cam_ean = None self.parent = parent self.dirname = '' # Name self.name = wx.StaticText(self, -1, '(No file loaded)') self.font = wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD) self.name.SetFont(self.font) # Buttons self.open = wx.Button(self, wx.ID_OPEN, "Load") self.copy = wx.Button(self, wx.ID_COPY, "Copy") self.copy.Disable() # Entry List self.entry_list = TreeListCtrl(self, style=TL_MULTIPLE) self.entry_list.AppendColumn("BAC Entry") self.entry_list.AppendColumn("Copied", width=64) self.entry_list.Bind(EVT_TREELIST_ITEM_CONTEXT_MENU, self.on_right_click) # self.cdo = wx.CustomDataObject("BDMEntry") self.Bind(wx.EVT_BUTTON, self.on_open, id=wx.ID_OPEN) self.Bind(wx.EVT_BUTTON, self.on_copy, id=wx.ID_COPY) self.Bind(wx.EVT_MENU, self.on_copy, id=wx.ID_COPY) accelerator_table = wx.AcceleratorTable([ (wx.ACCEL_CTRL, ord('c'), wx.ID_COPY), ]) self.entry_list.SetAcceleratorTable(accelerator_table) self.SetDropTarget(FileDropTarget(self, "load_side_moveset")) # Button Sizer button_sizer = wx.BoxSizer(wx.HORIZONTAL) button_sizer.Add(self.open) button_sizer.AddSpacer(5) button_sizer.Add(self.copy) # Use some sizers to see layout options sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(self.name, 0, wx.CENTER) sizer.Add(button_sizer) sizer.Add(self.entry_list, 1, wx.ALL | wx.EXPAND, 10) # Layout sizers self.SetSizer(sizer) self.SetAutoLayout(1) def on_open(self, _): pub.sendMessage('open_side_moveset') def build_tree(self): self.entry_list.DeleteAllItems() root = self.entry_list.GetRootItem() for i, entry in enumerate(self.bac.entries): if not entry.sub_entries: continue self.entry_list.AppendItem( root, f'{entry.index}: {KNOWN_ENTRIES.get(entry.index, "Unknown")}', data=entry) self.copy.Enable() self.parent.copied = None def on_right_click(self, _): selected = self.entry_list.GetSelections() if not selected: return menu = wx.Menu() menu.Append(wx.ID_COPY) self.PopupMenu(menu) menu.Destroy() def on_copy(self, _): selected = self.entry_list.GetSelections() if not selected: return # Deselect all item = self.entry_list.GetFirstItem() while item.IsOk(): self.entry_list.SetItemText(item, 1, '') item = self.entry_list.GetNextItem(item) # Check and add to copied copied = [] for item in selected: copied.append(self.entry_list.GetItemData(item)) self.entry_list.SetItemText(item, 1, CHECK) self.parent.copied = pickle.dumps(copied) pub.sendMessage('set_status_bar', text=f'Copied {len(selected)} entries')