cmd/PGUI.pyw

145 lines
4.3 KiB
Python
Raw Normal View History

import tkinter
2020-01-07 22:52:22 +00:00
import os
import subprocess
import sys
2020-01-07 22:52:22 +00:00
from voussoirkit import pathclass
from voussoirkit import vlogging
log = vlogging.get_logger(__name__, 'pgui')
BUTTON_WIDTH = 12
MAIN_BG = '#000'
MAIN_FG = '#FFF'
ENTRY_BG = '#222'
BUTTON_BG_NORMAL = '#000'
BUTTON_BG_HIGHLIGHT = '#00aa00'
2020-01-07 22:52:22 +00:00
def load_programs():
directory = pathclass.Path(__file__).parent.with_child('PGUI')
log.debug('Loading programs from %s.', directory.absolute_path)
shortcuts = directory.glob_files('*.lnk')
shortcuts.sort()
return shortcuts
2020-01-07 22:52:22 +00:00
class PGUILauncher(tkinter.Frame):
2020-01-07 22:52:22 +00:00
def __init__(self, parent):
super().__init__(parent, bg=MAIN_BG)
2020-01-07 22:52:22 +00:00
self._init_filter_entry()
self._init_buttons()
2020-01-07 22:52:22 +00:00
self.ready_to_launch = None
2020-01-07 22:52:22 +00:00
self.pack()
self.update()
def _init_buttons(self):
shortcuts = load_programs()
# This keeps the grid looking mostly square regardless of input count.
column_count = int(len(shortcuts) ** 0.5)
column_count = max(column_count, 1)
2020-01-07 22:52:22 +00:00
self.buttons = []
for (index, shortcut) in enumerate(shortcuts):
button = tkinter.Button(
self,
bg=BUTTON_BG_NORMAL,
command=lambda sc=shortcut: self.launch_program(sc),
fg=MAIN_FG,
height=2,
text=shortcut.replace_extension('').basename,
width=BUTTON_WIDTH,
)
button.shortcut = shortcut
print(f'Creating button for {shortcut.basename}')
# Plus 1 because row 0 is the search box.
button.grid(
row=(index // column_count) + 1,
column=index % column_count,
padx=1,
pady=1,
)
self.buttons.append(button)
2020-01-07 22:52:22 +00:00
def _init_filter_entry(self):
# The only way to add padding around the text entry is to put it in its
# own frame element. Thanks Kevin
# https://stackoverflow.com/a/51823093/5430534
self.filter_var = tkinter.StringVar()
self.filter_var.trace('w', self.filter)
self.filter_frame = tkinter.Frame(self, bg=ENTRY_BG)
self.filter_entry = tkinter.Entry(
self.filter_frame,
bg=ENTRY_BG,
fg=MAIN_FG,
insertbackground=MAIN_FG,
relief=tkinter.FLAT,
textvariable=self.filter_var,
)
self.filter_entry.bind('<Return>', self.launch_filtered)
self.filter_entry.bind('<Escape>', self.quit)
self.filter_frame.grid(row=0, column=0, columnspan=999, sticky='ew', padx=8, pady=8)
self.filter_entry.pack(fill='both', expand=True, padx=2, pady=2)
return self.filter_entry
2020-01-07 22:52:22 +00:00
def filter(self, *args):
text = self.filter_entry.get().lower()
enabled = []
for button in self.buttons:
button.configure(bg=BUTTON_BG_NORMAL)
if text == '' or text in button['text'].lower():
button['state'] = 'normal'
enabled.append(button)
else:
button['state'] = 'disabled'
if len(enabled) == 1:
enabled[0].configure(bg=BUTTON_BG_HIGHLIGHT)
self.ready_to_launch = enabled[0]
else:
self.ready_to_launch = None
def launch_filtered(self, *args):
if self.ready_to_launch is None:
return
self.launch_program(self.ready_to_launch.shortcut)
def launch_program(self, shortcut):
print('opening application', shortcut.basename)
os.chdir(shortcut.parent.absolute_path)
command = f'"{shortcut.absolute_path}"'
subprocess.Popen(command, shell=True)
self.quit()
2020-01-07 22:52:22 +00:00
2021-07-05 05:22:10 +00:00
def quit(self, *args):
return super().quit()
@vlogging.main_decorator
def main(argv):
2021-02-27 21:27:43 +00:00
root = tkinter.Tk()
2021-09-01 02:19:55 +00:00
root.withdraw()
root.title('PGUI')
root.resizable(0,0)
pgui = PGUILauncher(root)
pgui.pack(fill=tkinter.BOTH, expand=True)
pgui.filter_entry.focus()
width = root.winfo_reqwidth()
height = root.winfo_reqheight()
x_offset = (root.winfo_screenwidth() - width) / 2
y_offset = (root.winfo_screenheight() - height) / 2
root.geometry('%dx%d+%d+%d' % (width, height, x_offset, y_offset-50))
2021-09-01 02:19:55 +00:00
root.deiconify()
2020-01-07 22:52:22 +00:00
root.mainloop()
if __name__ == '__main__':
raise SystemExit(main(sys.argv[1:]))