def __init__(self, parent, macro: Macro = None): tk.Toplevel.__init__(self, parent) self.attributes("-topmost", 1) self.title("Create a Macro") icon = GetResourcePath('.\\Resources\\keystone.ico') if (icon != None): self.iconbitmap(icon) self.protocol("WM_DELETE_WINDOW", self.OnClose) self.columnconfigure(0, weight=1) self.rowconfigure(0, weight=1) frame = KeystoneFrame(self) frame.columnconfigure(0, weight=0) frame.columnconfigure(1, weight=1, minsize='205') frame.rowconfigure(0, weight=1) frame.rowconfigure(1, weight=0) if (macro == None): macro = Macro("Name", [SlashCommand(repr="powexec_name power")]) self.Editor = EditMacro(frame, macro) self.Editor.grid(column = 1, row = 0, rowspan=2, sticky='nsew') self.Close = KeystoneButton(frame) self.Close.configure(text="Close", command=self.OnClose) self.Close.Color('red', 'black') self.Close.grid(column=0, row=1, sticky='nsew') self.Copy = KeystoneButton(frame, text="Copy to Clipboard", command=self.OnCopy) self.Copy.Color('green', 'black') self.Copy.grid(column=0, row=0, sticky='nsew') frame.grid(column=0, row=0, sticky='nsew')
def __init__(self, parent, *args, **kwargs): tk.Toplevel.__init__(self, parent, *args, **kwargs) self.maxsize(324, 180) self.attributes("-toolwindow", 1) self.attributes("-topmost", 1) icon = GetResourcePath('.\\Resources\\keystone.ico') if (icon != None): self.iconbitmap(icon) self.title("About") frame = KeystoneFrame(self) #setup grid self.columnconfigure(0, weight=1, minsize=324) self.rowconfigure(0, weight=1, minsize=180) frame.columnconfigure(0, minsize=108) frame.columnconfigure(1, minsize=216) frame.rowconfigure(0, minsize=60) frame.rowconfigure(1, minsize=120) frame.grid(row=0, column=0, sticky='nsew') #logo imgPath = GetResourcePath('.\\Resources\\Keystone.png') if (imgPath != None): img = Image.open(imgPath) img = img.resize((54, 54)) self.Logo = ImageTk.PhotoImage(img) logoLabel = KeystoneLabel(frame, image=self.Logo) logoLabel.grid(row=0, column=0, padx=3, pady=3) #name nameLabel = KeystoneLabel(frame, text='Keystone', font=(TEXT_FONT, LARGE_FONT_SIZE)) nameLabel.grid(row=0, column=1, sticky='nw') subtextLabel = KeystoneLabel(frame, text='City of Heroes Keybind Editor') subtextLabel.grid(row=0, column=1, sticky='sw') #version versionPath = GetResourcePath('VERSION.txt') if (versionPath != None): file = open(versionPath, "r") try: version = file.read() finally: file.close() version = version.split("\n") versionLabel = KeystoneLabel(frame, text=version[0], font=(TEXT_FONT, LARGE_FONT_SIZE)) versionLabel.grid(row=1, column=0, columnspan=2) dateLabel = KeystoneLabel(frame, text=version[1]) dateLabel.grid(row=1, column=0, columnspan=2, sticky='s', pady=3)
class EditMacro(KeystoneFrame): def Load(self, macro: Macro): self.Name.set(macro.Name) self.Commands.Load(SlashCommandEditor, macro.Commands, SlashCommand(repr=DEFAULT_COMMAND)) def Get(self) -> Macro: commands = [item.Item.Get() for item in self.Commands.Items] if (self.CommandOnly.get()): name = None else: name = self.Name.get() return Macro(name, commands) def __init__(self, parent, macro: Macro): KeystoneFrame.__init__(self, parent) #StringVar for Name self.Name = "" #List of commands view frame self.Commands = None #layout grid self.columnconfigure(0, weight=1, minsize=200) self.columnconfigure(1, weight=0) self.columnconfigure(2, weight=7) self.rowconfigure(0, weight=1) #add controls self.NameFrame = KeystoneFrame(self) self.NameFrame.columnconfigure(1, weight=1) self.NameFrame.columnconfigure(2, weight=0) self.NameFrame.rowconfigure(4, weight=1) self.NameFrame.grid(row=0, column=0, sticky='nsew') self.CommandsFrame=KeystoneFrame(self) self.CommandsFrame.columnconfigure(0, weight=1) self.CommandsFrame.grid(row=0, column=2, sticky='nsew', padx="3", pady="3") self.Commands = FrameListView(self.CommandsFrame) self.Commands.grid(row=0, column=0, sticky='new') nameLabel = KeystoneLabel(self.NameFrame, anchor='nw', text="Name", width=5) nameLabel.grid(row=1, column=0, sticky="nw", padx="3", pady="3") self.Name = tk.StringVar() self.NameBox = KeystoneEntry(self.NameFrame, textvariable=self.Name) self.NameBox.grid(row=1, column=1, sticky="nsew", padx="3", pady="3") self.CommandOnly = tk.BooleanVar(value=False) self.CommandOnlyCheck = KeystoneCheckbutton(self.NameFrame, variable=self.CommandOnly) self.CommandOnlyCheck.grid(row=2, column=0, sticky="ne", padx="3", pady="3") commandOnlyLabel = KeystoneLabel(self.NameFrame, anchor='nw', text='Copy command only') commandOnlyLabel.grid(row=2, column=1, sticky="nw", padx="3", pady="3") self.Load(macro)
def __init__(self, parent, showScroll=False): KeystoneFrame.__init__(self, parent) self.columnconfigure(0, weight=1) self.columnconfigure(1, weight=0) self.rowconfigure(0, weight=0) self.rowconfigure(1, weight=1) # creating a scrollbars self.yscrlbr = ttk.Scrollbar(self) if showScroll: self.yscrlbr.grid(column=1, row=1, sticky='ns') #create tree self.Tree = KeystoneTree(self, selectmode=tk.BROWSE, yscrollcommand=self.yscrlbr.set) self.Tree.grid(row=1, column=0, sticky='nsew') self.Tree['columns'] = ('bound_files') self.Tree.heading("#0", text="Keybind Collection", anchor='w') self.Tree.column("#0", stretch=True, width=300) self.Tree.column("#1", stretch=False, width=0) # accociating scrollbar comands to tree scroling self.yscrlbr.config(command=self.Tree.yview) self.yscrlbr.lift(self.Tree) #create file browse frame browseFrame = KeystoneFrame(self) browseFrame.grid(row=0, column=0, columnspan=2, sticky='nsew') browseFrame.columnconfigure(0, weight=1) browseFrame.columnconfigure(1, weight=0) self.Directory = "" self.Tree.OnSelect.append(self.OnSelectItem)
class KeystoneWizard(tk.Toplevel): def __init__(self, parent, title=None, icon=None, onBack=None, onNext=None, onClose=None, *args, **kwargs): #initialize tk.Toplevel.__init__(self, parent, *args, **kwargs) if (title == None): title = type(parent).__name__ + " Wizard" self.title(title) if (icon == None): icon = GetResourcePath('.\\Resources\\keystone.ico') if (icon != None): self.iconbitmap(icon) self.Frame = KeystoneFrame(self) self.Pages = None self.CurrentPage = None self.PageIndex = tk.IntVar(value=0) self.PageIndex.trace("w", self.ShowPage) #callbacks self.OnBackCallback = onBack self.OnNexCallback = onNext self.OnCloseCallback = onClose #setup grid self.rowconfigure(0, weight=1, minsize=200) self.columnconfigure(0, weight=1, minsize=400) self.Frame.columnconfigure(0, weight=0, minsize=50) self.Frame.columnconfigure(1, weight=1) self.Frame.columnconfigure(2, weight=0, minsize=50) self.Frame.columnconfigure(3, weight=1) self.Frame.columnconfigure(4, weight=0, minsize=50) self.Frame.rowconfigure(0, weight=1) self.Frame.rowconfigure(1, weight=0) #setup controls self.Frame.grid(row=0, column=0, sticky='nsew') self.Back = KeystoneButton(self.Frame, text="Back", command=self.OnBack) self.Back.Color('green', 'black') self.ShowBack = tk.BooleanVar(value=False) self.ShowBack.trace("w", self.OnShowBack) self.Next = KeystoneButton(self.Frame, text="Next", command=self.OnNext) self.Next.Color('green', 'black') self.ShowNext = tk.BooleanVar(value=False) self.ShowNext.trace("w", self.OnShowNext) self.Close = KeystoneButton(self.Frame, text="Close", command=self.OnClose) self.Close.Color('red', 'black') self.ShowClose = tk.BooleanVar(value=False) self.ShowClose.trace("w", self.OnShowClose) def LoadPages(self, pages: [KeystoneWizardPage]): if (self.CurrentPage != None): self.CurrentPage.grid_forget() self.CurrentPage = None self.Pages = pages for eachPage in pages: eachPage.Wizard = self self.PageIndex.set(0) def PageCount(self) -> int: if (self.Pages == None): return 0 return len(self.Pages) def OnShowBack(self, *args): if (self.PageIndex.get() == 0): show = False else: show = self.ShowBack.get() if (show): self.Back.grid(column=0, row=1, sticky='nsew') else: self.Back.grid_forget() def OnShowNext(self, *args): if (self.PageIndex.get() == (self.PageCount() - 1)): show = False else: show = self.ShowNext.get() if (show): self.Next.grid(column=4, row=1, sticky='nsew') else: self.Next.grid_forget() def OnShowClose(self, *args): show = self.ShowClose.get() if (show): self.Close.grid(column=2, row=1, sticky='nsew') else: self.Close.grid_forget() def ShowPage(self, *args): if (self.PageCount() == 0): return #get index index = self.PageIndex.get() if (index >= self.PageCount()): index = self.PageCount() - 1 self.PageIndex.set(index) return #as set will callback due to trace elif (index < 0): index = 0 self.PageIndex.set(index) return #as set will callback due to trace #drop current page if (self.CurrentPage != None): self.CurrentPage.grid_forget() #show page and buttons page = self.Pages[index] page.grid(row=0, column=0, columnspan=5, sticky='nsew') self.CurrentPage = page self.ShowBack.set(page.AllowBack.get()) self.ShowNext.set(page.AllowNext.get()) self.ShowClose.set(page.AllowClose.get()) def _onButton(self, callback, pageCallback, allowVar, showVar, indexChange): if (pageCallback != None): pageCallback(self, self.CurrentPage) allow = allowVar.get() showVar.set(allow) index = self.PageIndex.get() + indexChange if (index > self.PageCount()): index = self.PageCount() - 1 elif (index < 0): index = 0 if (index != self.PageIndex.get()): self.PageIndex.set(index) if (callback != None): callback(self) def OnBack(self, *args): page = self.CurrentPage self._onButton(self.OnBackCallback, page.OnBack, page.AllowBack, self.ShowBack, -1) def OnNext(self, *args): page = self.CurrentPage self._onButton(self.OnNexCallback, page.OnNext, page.AllowClose, self.ShowClose, 1) def OnClose(self, *args): page = self.CurrentPage if (page.OnClose != None): page.OnClose(self) if (page.AllowClose.get()): self.destroy() if (self.OnCloseCallback != None): self.OnCloseCallback(self)
class SelectKeybindImportWindow(tk.Toplevel): def OnImportCallback(self, fileName, *args): if (self.ImportCallback != None): filePath = os.path.join(self.ResourceDir, fileName) SetTopmost(self, 0) try: self.ImportCallback(self, filePath) finally: SetTopmost(self, 1) def __init__(self, parent, resourceDir=None, importCallback=None, *args, **kwargs): tk.Toplevel.__init__(self, parent, *args, **kwargs) self.maxsize(900, 700) self.attributes("-toolwindow", 1) self.attributes("-topmost", 1) icon = GetResourcePath('.\\Resources\\keystone.ico') if (icon != None): self.iconbitmap(icon) self.title("Some Key Binds...") #setup grid self.columnconfigure(0, weight=1) self.rowconfigure(0, weight=1) self.scroll = ScrollingFrame(self) self.scroll.grid(row=0, column=0, sticky='nsew') self.frame = KeystoneFrame(self.scroll.scrollwindow) self.frame.pack(fill=tk.BOTH, expand=1) self.frame.columnconfigure(0) self.frame.columnconfigure(1) self.frame.columnconfigure(2, weight=1) row = 0 self.frame.grid(row=0, column=0, sticky='nsew') #get list of kst files from Resources if (resourceDir == None): self.ResourceDir = os.path.abspath( GetResourcePath('.\\Resources\\')) else: self.ResourceDir = resourceDir self.fileList = [ f for f in os.listdir(self.ResourceDir) if f.endswith(".kst") ] self.buttons = [] self.labels = [] self.descriptions = [] for filename in self.fileList: filePath = os.path.join(self.ResourceDir, filename) with open(filePath, "r") as json_file: data = json.load(json_file) self.buttons.append( KeystoneButton(self.frame, text="Import", command=lambda row=row: self.OnImportCallback( self.fileList[row]))) self.buttons[-1].Color('yellow', 'black') self.buttons[-1].grid(row=row, column=0, sticky='nw', padx=3, pady=3) self.labels.append(KeystoneLabel(self.frame, text=filename)) self.labels[-1].grid(row=row, column=1, sticky='new', padx=3, pady=3) self.descriptions.append( KeystoneMoreLabel(self.frame, text=data[DESCRIPTION])) self.descriptions[-1].grid(row=row, column=2, sticky='nsew') row = row + 1 self.ImportCallback = importCallback
class EditBindFileCollection(KeystoneEditFrame): def SetEditedItem(self, *args): editor = args[0] item = self.viewFrame.GetEditedItem(editor) self.viewFrame.SetEdited(item, True) hasChildren = (not (self.viewFrame.Dictionary[KEY_CHAINS] == NONE)) self.ShowTree.set(hasChildren) if (self.EditedItems == None): self.EditedItems = [editor] elif (not (editor in self.EditedItems)): self.EditedItems.append(editor) self.SetDirty() def ClearEditedItem(self, *args): editor = args[0] item = self.viewFrame.GetEditedItem(editor) self.viewFrame.SetEdited(item, False) if (self.EditedItems != None): if (editor in self.EditedItems): self.EditedItems.remove(editor) if (len(self.EditedItems) == 0): self.EditedItems = None self.SetClean() def selectItem(self, *args): self.selectedItem = self.viewFrame.Tree.focus() if (self.selectedItem == self.lastItem): return if (not self.viewFrame.Tree.HasTag(self.selectedItem, FILE_TAG)): self.lastItem = None if (self.editor != None): self.editor.grid_forget() self.editor = None return self.lastItem = self.selectedItem fileTag = self.viewFrame.Tree.GetTags(self.selectedItem)[1] editor = self.viewFrame.GetEditor(fileTag) if (self.editor != None): self.editor.grid_forget() if (editor != None): self.editor = editor else: bindFile = self.viewFrame.Get(fileTag) self.editor = EditBindFile(self.editFrame, bindFile) self.editor.OnSetDirty.append(self.SetEditedItem) self.editor.OnSetClean.append(self.ClearEditedItem) self.viewFrame.SetEditor(fileTag, self.editor) self.editor.grid(row=0, column=0, sticky='nsew') def OnShowTree(self, *args): value = self.ShowTree.get() if (value and (self._showingTree != True)): self.Pane.insert(0, self.viewFrame) self._showingTree = True elif ((not value) and (self._showingTree != False)): self.Pane.forget(self.viewFrame) self._showingTree = False def Reset(self): if (self.editor != None): self.editor.grid_forget() self.EditedItems = None self.FilePath = None self.viewFrame.Reset() self.ShowTree.set(False) def Load(self, bindFileCollection): self.Reset() self.FilePath = bindFileCollection.FilePath self.viewFrame.Load(bindFileCollection) self.viewFrame.SelectRoot() hasChildren = (not (self.viewFrame.Dictionary[KEY_CHAINS] == NONE)) self.ShowTree.set(hasChildren) if ((self.FilePath != None) and os.path.exists(self.FilePath)): self.SetClean(self) else: self.SetDirty(self) def Get(self): return self.viewFrame.GetCollection() def New(self, defaults: bool = False): editor = EditBindFile(self.editFrame) editor.New(defaults) bindFile = editor.Get() collection = BindFileCollection(None, bindFile) self.Load(collection) def Open(self, fileName=None): if (fileName == None): options = {} filePath = self.FilePath if (filePath != None): options['initialfile'] = filePath options['initialdir'] = os.path.dirname(filePath) options['title'] = "Open Keybind File" options['filetypes'] = (("Text Files", "*.txt"), ("All Files", "*.*")) options['defaultextension'] = "txt" options['multiple'] = False self.master.update() fileName = filedialog.askopenfilename(**options) self.master.update() if (fileName != ''): self.Reset() collection = BindFileCollection() collection.Load(fileName) self.Load(collection) def Save(self, promptForPath: bool = False): if (self.viewFrame.Dictionary == None): return currentFilePath = self.FilePath if (promptForPath or (currentFilePath == None)): options = {} options['initialfile'] = "keybinds.txt" options['title'] = "Save Keybind File As" options['filetypes'] = (("Text Files", "*.txt"), ("All Files", "*.*")) options['defaultextension'] = "txt" self.master.update() filePath = filedialog.asksaveasfilename(**options) self.master.update() if (filePath == ''): return else: filePath = currentFilePath self.FilePath = os.path.abspath(filePath) collection = self.Get() collection.Save(filePath) self.Reset() self.Load(collection) if (self.SaveCallback != None): self.SaveCallback(self) def ImportBinds(self, filePath): if (self.editor == None): return importCollection = BindFileCollection() importCollection.Deserialize(filePath) boundFiles = importCollection.GetBoundFiles() if (((self.editor.FilePath == None) or (self.editor.FilePath == NEW_FILE)) and (len(boundFiles) > 0)): response = messagebox.askokcancel( 'Path Needed For Linked Files', 'You must choose a target path for this file to set paths for linked files.\n' + 'The paths will be set, but no files will be saved yet.') if (not response): return options = {} options['initialfile'] = "keybinds.txt" options['title'] = "Select Target Destination for Linked Files" options['filetypes'] = (("Keybind Files", "*.txt"), ("All Files", "*.*")) options['defaultextension'] = "txt" self.master.update() pointPath = filedialog.asksaveasfilename(**options) self.master.update() if (pointPath == ''): return False self.FilePath = pointPath else: pointPath = self.editor.FilePath importCollection.RepointFilePaths(pointPath) if (pointPath != None): self.editor.FilePath = pointPath self.editor.PathLabel.configure(text=self.editor.FilePath) self.FilePath = self.editor.FilePath self.viewFrame.Directory = os.path.dirname(self.editor.FilePath) self.viewFrame.Dictionary[PATH] = self.editor.FilePath boundFiles = importCollection.GetBoundFiles() if (len(boundFiles) > 0): #put them in the orphange so refresh can find them orphans = [{ PATH: boundFile.FilePath, REPR: boundFile.__repr__(), EDITOR: None, SELECTED_TAG: False } for boundFile in boundFiles] self.viewFrame.GetOrphanage(True, orphans) for bind in importCollection.File.Binds: self.editor.NewBindCallback(True, bind) def __init__(self, parent, saveCallback=None): KeystoneEditFrame.__init__(self, parent) self.lastItem = None self.editor = None self.selectedItem = None self.EditedItems = None self.SaveCallback = saveCallback self.Pane = KeystonePanedWindow(self, orient=tk.HORIZONTAL) self.Pane.pack(fill=tk.BOTH, expand=1) self.viewFrame = BindFileCollectionView(self.Pane) self.viewFrame.Tree.OnSelect.append(self.selectItem) self.Pane.add(self.viewFrame) self.editFrame = KeystoneFrame(self.Pane, style='editStyle.TFrame', width=1000) self.editFrame.columnconfigure(0, weight=1) self.editFrame.rowconfigure(0, weight=1) self.Pane.add(self.editFrame) self._showingTree = None self.ShowTree = tk.BooleanVar(value=False) self.ShowTree.trace("w", self.OnShowTree) self.Reset()
class BindFileEditorWindow(tk.Tk): def _isOpenFile(self, path): if (self.Notebook.Items == None): return None thisPath = ComparableFilePath(path) for item in self.Notebook.Items: openPath = item.FilePath if (openPath == None): continue openPath = ComparableFilePath(openPath) if (thisPath == openPath): return item return None def NewTab(self, mode, path=None, bindFile=None): with self.TabLock: setDirty = False self.config(cursor="wait") self.update() try: if ((mode == "open") and (path != None) and (self.Notebook.Items != None)): if (self._isOpenFile(path) != None): return self.Notebook.NewFrame("") editor = self.Notebook.SelectedFrame() if (mode == "open"): editor.Open(fileName=path) if (editor.FilePath == None): self.Notebook.RemoveSelectedFrame() return elif (mode == "new"): editor.New(defaults=False) if (bindFile != None): editor.Load(bindFile) setDirty = True elif (mode == "default"): editor.New(defaults=True) self.SetTabName() if setDirty: editor.SetDirty() finally: self.config(cursor="") self._showNotebook() print("Unlock") def SetTabName(self, editor=None): if (editor == None): editor = self.Notebook.SelectedFrame() if (editor == None): return else: tab = self.Notebook.GetTabNameFromItem(editor) self.Notebook.select(tab) filePath = editor.FilePath if (filePath == None): fileName = NEW_FILE else: fileName = GetFileName(filePath) self.Notebook.tab(self.Notebook.select(), text=fileName) def OnFileOpen(self): self.NewTab("open") def OnFileNew(self): self.NewTab("new") def OnFileNewDefaults(self): self.NewTab("default") def OnSaveCallback(self, editor, *args): self.SetTabName(editor=editor) def OnFileSave(self): collectionEditor = self.Notebook.SelectedFrame() if (collectionEditor == None): return editor = self.Notebook.SelectedFrame() if (editor == None): return editor.Save() def OnFileSaveAs(self): collectionEditor = self.Notebook.SelectedFrame() if (collectionEditor == None): return editor = self.Notebook.SelectedFrame() if (editor == None): return editor.Save(True) def CancelFromSavePrompt(self) -> bool: collectionEditor = self.Notebook.SelectedFrame() if (collectionEditor == None): return editor = self.Notebook.SelectedFrame() if (editor == None): return False if (editor.Dirty.get()): response = messagebox.askyesnocancel( "Edited File", "Save changes before proceeding?") if (response): self.OnFileSaveAs() if (editor.Dirty.get()): #didn't save, abort return True elif (response == None): return True return False def OnFileClose(self): collectionEditor = self.Notebook.SelectedFrame() if (collectionEditor == None): return editor = self.Notebook.SelectedFrame() if (editor == None): return if (self.CancelFromSavePrompt()): return self.Notebook.RemoveSelectedFrame() def OnDownloadFile(self): options = {} options['initialfile'] = "keybinds.txt" options['title'] = "Select File Destination" options['filetypes'] = (("Text Files", "*.txt"), ("All Files", "*.*")) options['defaultextension'] = "txt" self.update() filePath = filedialog.asksaveasfilename(**options) self.update() if (filePath == ''): return command = SlashCommand(name=SAVE_COMMAND, text="\"%s\"" % os.path.abspath(filePath)) self.clipboard_clear() self.clipboard_append("/" + str(command)) response = messagebox.askokcancel( "Download from City of Heroes", "The command:\n\n" + "/%s\n\n" % str(command) + "has been copied to the clipboard.\n\n" + "Paste and execute this command in the game to save the current keybinds to the selected location\n\n" + "Click OK to open the saved file.") if (response): self.NewTab("open", filePath) def OnUploadFile(self): collectionEditor = self.Notebook.SelectedFrame() if (collectionEditor == None): return editor = self.Notebook.SelectedFrame().editor if (editor == None): return if (self.CancelFromSavePrompt()): return if (editor.FilePath == None): return filePath = os.path.abspath(editor.FilePath) command = SlashCommand(name=LOAD_COMMAND, text="\"%s\"" % os.path.abspath(filePath)) self.clipboard_clear() self.clipboard_append("/" + str(command)) messagebox.showinfo( "Upload to City of Heroes", "The command:\n\n" + "/%s\n\n" % str(command) + "has been copied to the clipboard.\n\n" + "Paste and execute this command in the game to load the current keybinds from the selected location\n" + "You can add this command as a bind using the Add Upload Bind menu item." ) def OnAddUploadBind(self): collectionEditor = self.Notebook.SelectedFrame() if (collectionEditor == None): return editor = self.Notebook.SelectedFrame().editor if (editor == None): return if ((editor.FilePath == None) and self.CancelFromSavePrompt()): return if (editor.FilePath == None): return editor.AddUploadBind() def OnClosing(self): if (self.Notebook.Dirty == True): response = messagebox.askyesnocancel( "Edited Files", "Save all changes before closing?") if (response): self.OnSaveAll() elif (response == None): return self.destroy() def OnSaveAll(self): if (self.Notebook.Dirty == True): if (self.Notebook.Items != None): for editor in self.Notebook.Items: if editor.Dirty.get(): editor.Save() def OnCloseAll(self): while ((self.Notebook.Items != None) and (len(self.Notebook.Items) > 0)): self.CancelFromSavePrompt() self.Notebook.RemoveSelectedFrame() def _getBoundFilesSource(self): return [e.Get() for e in self.Notebook.Items if e.FilePath != None] def _onSelectCallback(self, binds, *args): editor = self.Notebook.SelectedFrame().editor bindFilePath = editor.FilePath options = {} options['initialfile'] = "keybinds.kst" options['title'] = "Select File Destination" options['filetypes'] = (("Keybind Export Files", "*.kst"), ("All Files", "*.*")) options['defaultextension'] = "kst" self.update() filePath = filedialog.asksaveasfilename(**options) self.update() if (filePath == ''): return False bindFile = BindFile(binds, filePath=bindFilePath) boundFilesSource = self._getBoundFilesSource() bindFileCollection = BindFileCollection() bindFileCollection.Load(bindFilePath, bindFile=bindFile, boundFilesSource=boundFilesSource) bindFileCollection.Serialize(filePath) return True def OnImportBinds(self): collectionEditor = self.Notebook.SelectedFrame() if (collectionEditor == None): return bindFileEditor = self.Notebook.SelectedFrame().editor if (bindFileEditor == None): return if (self.CancelFromSavePrompt()): return options = {} options['title'] = "Open Keybind Export File" options['filetypes'] = (("Keybind Export Files", "*.kst"), ("All Files", "*.*")) options['defaultextension'] = "kst" options['multiple'] = False self.update() fileName = filedialog.askopenfilename(**options) self.update() if (fileName == ''): return collectionEditor.ImportBinds(fileName) self.SetTabName(collectionEditor) def OnExportBinds(self): collectionEditor = self.Notebook.SelectedFrame() if (collectionEditor == None): return editor = self.Notebook.SelectedFrame().editor if (editor == None): return if (self.CancelFromSavePrompt()): return editor.OnSelectCallback = self._onSelectCallback editor.SetSelectMode(not editor.SelectMode) def OnCreateMacro(self): EditMacroWindow(self) def OnPredefinedBindsCallback(self, importWindow, filePath): collectionEditor = self.Notebook.SelectedFrame() if (collectionEditor == None): return bindFileEditor = self.Notebook.SelectedFrame().editor if (bindFileEditor == None): return if (self.CancelFromSavePrompt()): return collectionEditor.ImportBinds(filePath) self.SetTabName(collectionEditor) def AddCommand(self, menu: tk.Menu, frame, label, command): menu.add_command(label=label, command=command) KeystoneButton(frame, text=label, command=command).pack(anchor='nw', side=tk.LEFT) def _openLinkedFileCallback(self, path): if not self.SuppressCallback: self.NewTab("open", path) def _showNotebook(self): if (not self.ShowingNotebook): self.Notebook.pack(fill=tk.BOTH, expand=True, side=tk.TOP) self.FirstFrame.pack_forget() self.ShowingNotebook = True def __init__(self, *args, **kwargs): tk.Tk.__init__(self, *args, **kwargs) win = self win.title("Keystone") icon = GetResourcePath('.\\Resources\\keystone.ico') if (icon != None): win.iconbitmap(icon) speedBar = KeystoneFrame(win) speedBar.config(height=45) speedBar.pack(anchor='n', fill=tk.X, expand=False, side=tk.TOP) menu = tk.Menu(win) fileMenu = tk.Menu(menu, tearoff=0) self.AddCommand(menu=fileMenu, frame=speedBar, label="Open", command=self.OnFileOpen) self.AddCommand(menu=fileMenu, frame=speedBar, label="New (Empty)", command=self.OnFileNew) self.AddCommand(menu=fileMenu, frame=speedBar, label="New (Defaults)", command=self.OnFileNewDefaults) self.AddCommand(menu=fileMenu, frame=speedBar, label="Save", command=self.OnFileSave) self.AddCommand(menu=fileMenu, frame=speedBar, label="Save As...", command=self.OnFileSaveAs) fileMenu.add_command(label="Save All", command=self.OnSaveAll) self.AddCommand(menu=fileMenu, frame=speedBar, label="Close", command=self.OnFileClose) fileMenu.add_command(label="Close All", command=self.OnCloseAll) menu.add_cascade(label="File", menu=fileMenu) cohMenu = tk.Menu(menu, tearoff=0) cohMenu.add_command(label="Download File", command=self.OnDownloadFile) cohMenu.add_command(label="Upload File", command=self.OnUploadFile) cohMenu.add_command(label="Create Macro", command=self.OnCreateMacro) menu.add_cascade(label="Game Commands", menu=cohMenu) importExportMenu = tk.Menu(menu, tearoff=0) importExportMenu.add_command(label="Import Binds", command=self.OnImportBinds) importExportMenu.add_command(label="Export Binds", command=self.OnExportBinds) importExportMenu.add_command(label="Add Upload Bind", command=self.OnAddUploadBind) importExportMenu.add_command( label="Predefined Binds...", command=lambda parent=win, callback=self.OnPredefinedBindsCallback: ShowSelectKeybindImportWindow(parent, importCallback=callback)) menu.add_cascade(label="Import\\Export", menu=importExportMenu) helpMenu = tk.Menu(menu, tearoff=0) helpMenu.add_command( label='Getting Started', command=lambda parent=win: ShowWalkthrough(parent)) helpMenu.add_command(label='Import and Export', command=lambda parent=win: ShowWalkthrough( parent, title="Import and Export Walkthrough", walkthrough=IMPORT_EXPORT_WALKTHROUGH)) helpMenu.add_command( label='Collections and Loaded Files', command=lambda parent=win: ShowWalkthrough( parent, title="Collections and Loaded Files Walkthrough", walkthrough=COLLECTIONS_AND_KEYCHAINS_WALKTHROUGH, endPages=COLLECTIONS_AND_KEYCHAINS_WALKTHROUGH_END_PAGES)) self.AddCommand(menu=helpMenu, frame=speedBar, label="About", command=lambda parent=win: ShowHelpAbout(parent)) menu.add_cascade(label='Help', menu=helpMenu) SetOpenLinkedFileCallback(self._openLinkedFileCallback) self.FirstFrame = KeystoneFrame(win) self.FirstFrame.columnconfigure(0, weight=1, minsize=800) self.FirstFrame.rowconfigure(0, weight=1, minsize=400) walkthroughButton = KeystoneButton( self.FirstFrame, text='Intro Walkthrough', command=lambda parent=win: ShowWalkthrough(parent)) walkthroughButton.Color('lightskyblue', 'black') walkthroughButton.configure(relief=tk.RAISED) walkthroughButton.grid() self.FirstFrame.pack(fill=tk.BOTH, expand=True, side=tk.TOP) self.Notebook = FrameNotebook(win, EditBindFileCollection, [self.OnSaveCallback]) self.ShowingNotebook = False self.SuppressCallback = False win.config(menu=menu, width=800, height=400) win.protocol("WM_DELETE_WINDOW", self.OnClosing) self.TabLock = threading.Lock()
def __init__(self, parent, command: SlashCommand): KeystoneEditFrame.__init__(self, parent) #Frame for formatting controls self.FormatFrame = None #Frame for decscription self.DescriptionFrame = None #StringVar for command name self.CommandName = None #text entry object self.TextEntry = None #color entry objects self.ColorEntry = None self.BackgroundEntry = None self.BorderEntry = None #StringVar for transparency self.TransparencyEntryText = None #StringVar for scale self.ScaleEntryText = None #StringVar for repeat selection self.RepeatText = None #StringVar for duration self.DurationText = None #StringVar for power description text self.DescriptionText = None #The text prompt for the last selected command, e.g. "power" for powexec_name self.TextPrompt = None #layout grid and frames self.columnconfigure(0, weight=1) self.rowconfigure(0, weight=0) self.rowconfigure(1, weight=0) self.rowconfigure(2, weight=1) commandFrame = KeystoneFrame(self) commandFrame.grid(row=0, column=0, sticky='nsew') commandFrame.columnconfigure(0, weight=0) commandFrame.columnconfigure(1, weight=1) commandFrame.columnconfigure(2, weight=0) commandFrame.columnconfigure(3, weight=0) self.FormatFrame = formatFrame = KeystoneFrame(self) self.DescriptionFrame = descriptionFrame = KeystoneFrame(self) #add controls self.CommandName = tk.StringVar() commandBox = KeystoneCombo(commandFrame, textvariable=self.CommandName, values=" ".join([ c[0] for c in LIST_OF_SLASH_COMMANDS]), postcommand=self.LockShowFormat) commandBox.grid(row=0, column=0, sticky="w", padx="3", pady="3") self.CommandName.trace("w", self.SelectCommand) self.CommandName.trace("w", self.SetDirty) self.TextEntry = KeystoneTextEntry(commandFrame) self.TextEntry.grid(row=0, column=1, sticky="nsew", padx="3", pady="3") self.TextEntry.bind("<Key>", self.SetDirty) self.BrowseButton = KeystoneButton(commandFrame, text=" ... ", command=self.OnBrowseButton) self.NewButton = KeystoneButton(commandFrame, text="New", command=self.OnNewButton) self.IsLoadFileCommand = tk.BooleanVar() self.IsLoadFileCommand.set(False) self.IsLoadFileCommand.trace("w", self.OnSetIsLoadFileCommand) label = KeystoneLabel(formatFrame, text="Repeat Mode", anchor='n') label.grid(row=0, column=0, pady="3") repeatModes = [("Once", ""), ("Repeat [%s]" % REPEAT_STR, REPEAT_STR), ("Toggle [%s]" %TOGGLE_STR , TOGGLE_STR)] self.RepeatText = tk.StringVar() for idx, (text, mode) in enumerate(repeatModes): b = KeystoneRadio(formatFrame, text=text, value=mode, variable=self.RepeatText) b.grid(row=1+idx, column=0, sticky='w') self.RepeatText.set("") self.RepeatText.trace("w", self.SetDirty) editLabels = ["Text Color", "Background Color", "Transparency", "Border Color", "Scale", "Duration"] for idx, text in enumerate(editLabels): label = KeystoneLabel(formatFrame, text=text, anchor='n', width=30) if (idx < 3): row = 1 else: row = 3 label.grid(row=row, column=1+(idx % 3)) self.ColorEntry = ColorPicker(formatFrame) self.ColorEntry.Combo.configure(postcommand=self.LockShowFormat) self.ColorEntry.grid(row=0, column=1, padx="3", pady="3") self.ColorEntry.ColorEntryText.trace("w", self.FormatText) self.BackgroundEntry = ColorPicker(formatFrame) self.BackgroundEntry.Combo.configure(postcommand=self.LockShowFormat) self.BackgroundEntry.grid(row=0, column=2, padx="3", pady="3") self.BackgroundEntry.ColorEntryText.trace("w", self.FormatText) self.TransparencyEntryText = tk.StringVar() self.TransparencyEntry = KeystoneCombo(formatFrame, textvariable=self.TransparencyEntryText, values=" ".join([str(p) for p in range(0,101)]), width=3, postcommand=self.LockShowFormat) self.TransparencyEntry.grid(row=0, column=3) self.TransparencyEntryText.trace("w", self.FormatText) self.BorderEntry = ColorPicker(formatFrame) self.BorderEntry.Combo.configure(postcommand=self.LockShowFormat) self.BorderEntry.grid(row=2, column=1, padx="3", pady="3") self.BorderEntry.ColorEntryText.trace("w", self.FormatText) self.ScaleEntryText = tk.StringVar() scaleEntry = KeystoneEntry(formatFrame, textvariable=self.ScaleEntryText, width=5) scaleEntry.grid(row=2, column=2) self.ScaleEntryText.trace("w", self.FormatText) self.DurationText = tk.StringVar() durationEntry = KeystoneEntry(formatFrame, textvariable=self.DurationText, width=5) durationEntry.grid(row=2, column=3) self.DurationText.trace("w", self.FormatText) self.DescriptionText = tk.StringVar() description = KeystoneLabel(descriptionFrame, anchor="nw", textvariable=self.DescriptionText, wraplength=800) description.grid(sticky="nsew", padx="3", pady="3") #load model self.Load(command) #bind to hide format and desc self.BindWidgetToShowFormat(self)
class BindEditor(KeystoneEditFrame): DELETE_TEXT = 'UNBIND' DELETE_COLOR = 'black' DELETE_TEXT_COLOR = 'red' DELETE_STYLE = tk.FLAT ASSIGN_TEXT = 'BIND' UNASSIGN_TEXT = 'Unassign Bind' UNASSIGN_MESSAGE = 'Include no assignment? Use "nop" to assign a key to do nothing. Use /unbind <key> to restore a default in the UI' DEFAULT_TEXT = 'Default Bind' DEFAULT_COLOR = 'yellow' DEFAULT_TEXT_COLOR = 'black' CANCEL_TEXT = 'Cancel' ASSIGN_COLOR = 'black' ASSIGN_TEXT_COLOR = 'green' def SetKeyDescription(self, keyVar: tk.StringVar, descVar: tk.StringVar, list): keyName = keyVar.get() key = MatchKeyName(keyName, list) if (key != None): desc = key[2] altname = key[1] if ((desc == '') and (altname != '')): desc = altname descVar.set(desc) else: descVar.set('') def SelectKey(self, *args): self.SetKeyDescription(self.Key, self.KeyDescription, KEY_NAMES) def SelectChord(self, *args): self.SetKeyDescription(self.Chord, self.ChordDescription, CHORD_KEYS) def AssignCommand(self, *args): model = Bind(key=self.Key.get(), chord=self.Chord.get(), commands=[SlashCommand(repr=DEFAULT_COMMAND)]) self.Load(model) self.SetDirty() def UnassignCommand(self, *args): text = args[0] if (text == self.UNASSIGN_TEXT): self.ShowCommands.set(False) self.SetDirty() elif (text == self.DEFAULT_TEXT): bind = GetDefaultBindForKey(self.Key.get(), self.Chord.get()) self.Commands.Load(SlashCommandEditor, bind.Commands, SlashCommand(repr=DEFAULT_COMMAND)) self.ShowCommands.set(True) self.SetDirty() else: #Cancel self.ShowCommands.set(True) def OnDelete(self, *args): self.CommandsFrame.grid_forget() self.Delete.grid_forget() buttons = [self.UNASSIGN_TEXT, self.DEFAULT_TEXT, self.CANCEL_TEXT] colors = [[self.DELETE_TEXT_COLOR, self.DELETE_COLOR], [self.DEFAULT_COLOR, self.DEFAULT_TEXT_COLOR], [self.ASSIGN_TEXT_COLOR, self.ASSIGN_COLOR]] results = [self.UNASSIGN_TEXT, self.DEFAULT_TEXT, self.CANCEL_TEXT] commands = [ self.UnassignCommand, self.UnassignCommand, self.UnassignCommand ] unassignPrompt = KeystonePromptFrame(self, self.UNASSIGN_MESSAGE, buttons=buttons, colors=colors, results=results, commands=commands) unassignPrompt.grid(row=0, column=1, sticky='nsew') def OnShowCommands(self, *args): show = self.ShowCommands.get() if (show): self.Assign.grid_forget() self.Delete.grid(row=0, column=1, sticky='nsw') self.CommandsFrame.grid(row=0, column=2, sticky='nsew', padx="3", pady="3") else: self.Assign.grid(row=0, column=1, sticky='nsw') self.CommandsFrame.grid_forget() self.Delete.grid_forget() def OnShowTextEditor(self, *args): show = self.ShowTextEditor.get() if (show): self.Assign.grid_forget() self.Delete.grid_forget() self.KeyFrame.grid_forget() self.CommandsFrame.grid_forget() self.UIToTextButton.grid_forget() self.UnlockKeysButton.grid_forget() self.TextFrame.grid(row=0, column=0, rowspan="2", columnspan="3", sticky='nsew') else: self.TextFrame.grid_forget() self.KeyFrame.grid(row=0, column=0, sticky='nsew') if (self._lockKey): self.UIToTextButton.grid(row=1, column=1, columnspan="2", sticky="nsew", padx="3", pady="3") self.UnlockKeysButton.grid(row=1, column=0, sticky="sw") else: self.UIToTextButton.grid(row=1, column=0, columnspan="3", sticky="nsew", padx="3", pady="3") self.OnShowCommands() def UnlockKeys(self, unlock=True): if unlock: self._lockKey = False self.KeyBox.grid(row=1, column=1, sticky="nsew", padx="3", pady="3") self.ChordBox.grid(row=3, column=1, sticky="nsew", padx="3", pady="3") self.KeyValue.grid_forget() self.ChordValue.grid_forget() self.UnlockKeysButton.grid_forget() else: self._lockKey = True self.KeyBox.grid_forget() self.ChordBox.grid_forget() self.KeyValue.grid(row=1, column=1, sticky="nsew", padx="3", pady="3") self.ChordValue.grid(row=3, column=1, sticky="nsew", padx="3", pady="3") def Load(self, bind: Bind): self.Loading = True try: if (self._lockKey): self.TextEntry.SetText(bind.GetCommands()) else: self.TextEntry.SetText(bind.__repr__()) self.SynchTextToUI() finally: self.Loading = False self.SetClean(self) def SynchTextToUI(self): key = self.Key.get() chord = self.Chord.get() text = self.TextEntry.GetText() if (self._lockKey): text = "%s %s" % (FormatKeyWithChord(key, chord), text) bind = Bind(repr=text) if (key != bind.Key): self.Key.set(bind.Key) if (chord != bind.Chord): self.Chord.set(bind.Chord) if (bind.Commands != None): self.Commands.Load(SlashCommandEditor, bind.Commands, SlashCommand(repr=DEFAULT_COMMAND)) self.ShowCommands.set(True) else: self.ShowCommands.set(False) self.ShowTextEditor.set(False) def SynchUIToText(self): bind = self.GetBindFromUI() if (self._lockKey): self.TextEntry.SetText(bind.GetCommands()) else: self.TextEntry.SetText(bind) self.ShowTextEditor.set(True) def GetBindFromUI(self) -> Bind: bind = Bind() if (self.ShowCommands.get()): bind.Commands = [item.Item.Get() for item in self.Commands.Items] else: bind.Commands = None bind.Key = self.Key.get() bind.Chord = self.Chord.get() return bind def Get(self) -> Bind: if (self.ShowTextEditor.get()): self.SynchTextToUI() model = self.GetBindFromUI() return model def __init__(self, parent, bind: Bind, lockKey=False, dirty=False): KeystoneEditFrame.__init__(self, parent) #StringVar for Key self.Key = None #StringVar for Chord self.Chord = None #StringVar for Key Description self.KeyDescription = None #StringVar for Chord Description self.ChordDescription = None #List of commands view frame self.Commands = None #Indicates keys cannot be edited self._lockKey = lockKey #layout grid self.columnconfigure(0, weight=1, minsize=200) self.columnconfigure(1, weight=0) self.columnconfigure(2, weight=7) self.rowconfigure(0, weight=1) #add controls self.KeyFrame = KeystoneFrame(self) self.KeyFrame.columnconfigure(1, weight=1) self.KeyFrame.columnconfigure(2, weight=0) self.KeyFrame.rowconfigure(4, weight=1) self.CommandsFrame = KeystoneFrame(self) self.CommandsFrame.columnconfigure(0, weight=1) self.Commands = FrameListView(self.CommandsFrame) self.Commands.OnSetDirty.append(self.SetDirty) self.Commands.grid(row=0, column=0, sticky='new') self.TextFrame = KeystoneFrame(self) self.TextFrame.rowconfigure(0, weight=1, minsize='55') self.TextFrame.columnconfigure(0, weight=1, minsize='405') self.Delete = tk.Button(self, text=self.DELETE_TEXT, background=self.DELETE_COLOR, foreground=self.DELETE_TEXT_COLOR, font=(TEXT_FONT, 7, "bold"), relief=self.DELETE_STYLE, width=1, wraplength=1, command=self.OnDelete) self.Assign = tk.Button(self, text=self.ASSIGN_TEXT, background=self.ASSIGN_COLOR, foreground=self.ASSIGN_TEXT_COLOR, font=(TEXT_FONT, 7, "bold"), relief=self.DELETE_STYLE, width=1, wraplength=1, command=self.AssignCommand) self.UIToTextButton = KeystoneButton(self, text="Edit As Text", command=self.SynchUIToText) keyLabel = KeystoneLabel(self.KeyFrame, anchor='nw', text="Key", width=5) keyLabel.grid(row=1, column=0, sticky="nw", padx="3", pady="3") self.Key = tk.StringVar() self.KeyValue = KeystoneLabel(self.KeyFrame, anchor='nw', textvariable=self.Key, width=5) self.KeyBox = KeystoneKeyCombo(self.KeyFrame, textvariable=self.Key, values=" ".join( [c[0] for c in KEY_NAMES])) self.Key.trace("w", self.SelectKey) self.KeyDescription = tk.StringVar() keyDescription = KeystoneLabel(self.KeyFrame, anchor="nw", textvariable=self.KeyDescription, wraplength=200) keyDescription.grid(row=2, column=0, columnspan=2, sticky="nsew", padx="3", pady="3") self.Key.set(bind.Key) self.Key.trace("w", self.SetDirty) chordLabel = KeystoneLabel(self.KeyFrame, anchor='nw', text="Chord", width=5) chordLabel.grid(row=3, column=0, sticky="nw", padx="3", pady="3") self.Chord = tk.StringVar() self.ChordValue = KeystoneLabel(self.KeyFrame, anchor='nw', textvariable=self.Chord, width=5) self.ChordBox = KeystoneKeyCombo(self.KeyFrame, textvariable=self.Chord, values=" ".join( [c[0] for c in CHORD_KEYS])) self.Chord.trace("w", self.SelectChord) self.ChordDescription = tk.StringVar() chordDescription = KeystoneLabel(self.KeyFrame, anchor="nw", textvariable=self.ChordDescription, wraplength=200) chordDescription.grid(row=4, column=0, columnspan=2, sticky="nsew", padx="3", pady="3") self.Chord.set(bind.Chord) self.Chord.trace("w", self.SetDirty) self.UnlockKeysButton = KeystoneButton(self, text="Change Assigned Key", command=self.UnlockKeys) self.UnlockKeysButton.Color(FOREGROUND, BACKGROUND) self.ShowCommands = tk.BooleanVar() self.ShowCommands.trace("w", self.OnShowCommands) self.TextEntry = KeystoneTextEntry(self.TextFrame, height=5) self.TextEntry.grid(row=0, column=0, sticky="nsew", padx="3", pady="3") self.TextEntry.bind("<Key>", self.SetDirty) self.ShowTextEditor = tk.BooleanVar() self.ShowTextEditor.set(False) self.ShowTextEditor.trace("w", self.OnShowTextEditor) self.TextToUIButton = KeystoneButton(self.TextFrame, text="Editor", command=self.SynchTextToUI) self.TextToUIButton.grid(row=1, column=0, sticky="nsew", padx="3", pady="3") self.OnShowTextEditor() self.UnlockKeys(not lockKey) self.Load(bind) self.Dirty.set(dirty)