190 lines
6.5 KiB
Python
Executable File
190 lines
6.5 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
import argparse
|
|
import sys
|
|
import time
|
|
import tkinter as tk
|
|
import tkinter.messagebox
|
|
import tkinter.simpledialog
|
|
import tkinter.ttk
|
|
from threading import Thread
|
|
|
|
|
|
class StdinBox(tk.Toplevel):
|
|
def __init__(self, title="", message="", geometry="800x80"):
|
|
tk.Toplevel.__init__(self)
|
|
self.geometry(geometry)
|
|
self.title(title)
|
|
self.exit = False
|
|
self.my_message = message
|
|
self.my_title = title
|
|
self.messageLabel = tk.Label(self, text=message, bg="#222", fg="#fff", font="TkFixedFont")
|
|
self.messageLabel.pack(expand=True, fill=tk.BOTH)
|
|
|
|
daemon = Thread(target=self.stream_stdin)
|
|
daemon.start()
|
|
self.update_timer()
|
|
self.mainloop()
|
|
|
|
def update_message(self, message):
|
|
self.messageLabel.configure(text=message)
|
|
|
|
def update_title(self, title):
|
|
self.title(title)
|
|
|
|
def update_timer(self):
|
|
if self.exit:
|
|
self.quit()
|
|
return
|
|
self.messageLabel.configure(text=self.my_message)
|
|
self.update()
|
|
self.after(333, self.update_timer)
|
|
|
|
def stream_stdin(self):
|
|
with open(sys.stdin.fileno(), mode="rt", encoding="utf-8", newline=None, buffering=1, closefd=True) as fp:
|
|
for line in fp:
|
|
self.my_message = line.rstrip("\r\n")
|
|
self.exit = True
|
|
|
|
|
|
class ListBox(tk.Toplevel):
|
|
def __init__(self, title="", message="", geometry="800x800"):
|
|
tk.Toplevel.__init__(self)
|
|
self.geometry(geometry) # Must change these accordingly
|
|
self.configure(background="#222")
|
|
self.title(title)
|
|
self.messageLabel = tk.Label(self, text=message, bg="#222", fg="#fff", font="TkFixedFont")
|
|
self.choose = tk.Listbox(self, bg="#222", fg="#fff", font="TkFixedFont", selectmode="browse")
|
|
with open(sys.stdin.fileno(), mode="rt", encoding="utf-8", newline=None, buffering=1, closefd=True) as fp:
|
|
for i, line in enumerate(fp):
|
|
self.choose.insert(i, line.rstrip("\r\n"))
|
|
self.last_element = i
|
|
self.choose.select_set(0)
|
|
|
|
self.labelframe = tk.Frame(self, bg="#222")
|
|
self.cancel_b = tk.Button(self.labelframe, text="Cancel", command=self.quit)
|
|
self.ok_b = tk.Button(self.labelframe, text="OK", command=self.selected)
|
|
|
|
self.messageLabel.pack() # expand=True, fill=tk.BOTH)
|
|
self.choose.pack(expand=True, fill=tk.BOTH)
|
|
self.cancel_b.pack(side="left")
|
|
self.ok_b.pack(side="right")
|
|
self.labelframe.pack()
|
|
self.choose.focus_set()
|
|
self.choose.bind("<Return>", self.selected)
|
|
self.choose.bind("<Double-Button-1>", self.selected)
|
|
self.choose.bind("<Key>", self.key_handler)
|
|
|
|
self.ok_b.bind("<Return>", self.selected)
|
|
self.cancel_b.bind("<Return>", self.handle_exit)
|
|
self.bind_all("<Control-c>", self.handle_exit)
|
|
self.bind_all("<Escape>", self.handle_exit)
|
|
|
|
self.mainloop()
|
|
|
|
def set_position(self, index):
|
|
index = max(0, min(self.last_element, index))
|
|
self.choose.selection_clear(0, tk.END)
|
|
self.choose.activate(index)
|
|
self.choose.selection_set(index)
|
|
|
|
def key_handler(self, event):
|
|
if len(event.char) == 1 and event.char.isalnum():
|
|
# ~ print(event.char, event.keysym, event.keycode)
|
|
for i in list(range(self.choose.curselection()[0] + 1, self.last_element + 1)) + list(
|
|
range(0, self.choose.curselection()[0] + 1)
|
|
):
|
|
if self.choose.get(i).lower().startswith(event.char):
|
|
self.set_position(i)
|
|
return
|
|
if event.keysym == "Up":
|
|
self.set_position(self.choose.curselection()[0])
|
|
if event.keysym == "Down":
|
|
self.set_position(self.choose.curselection()[0])
|
|
if event.keysym == "Next":
|
|
self.set_position(self.choose.curselection()[0] + 10)
|
|
if event.keysym == "Prior":
|
|
self.set_position(self.choose.curselection()[0] - 10)
|
|
if event.keysym == "Home":
|
|
self.set_position(0)
|
|
if event.keysym == "End":
|
|
self.set_position(self.last_element)
|
|
|
|
def selected(self, *args):
|
|
for i in self.choose.curselection():
|
|
print(self.choose.get(i), end="")
|
|
self.quit()
|
|
|
|
def handle_exit(self, *args):
|
|
self.quit()
|
|
|
|
|
|
def get_opts():
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument(
|
|
"--title",
|
|
action="store",
|
|
default=None,
|
|
help="Window title",
|
|
)
|
|
parser.add_argument("--text", action="store", default=None, help="Description text", nargs="?")
|
|
parser.add_argument(
|
|
"--geometry",
|
|
action="store",
|
|
default=None,
|
|
help="Geometry (not valid for all commands), ex. 800x200+50+50",
|
|
nargs="?",
|
|
)
|
|
parser.add_argument(
|
|
"mode",
|
|
action="store",
|
|
default="info",
|
|
const="info",
|
|
nargs="?",
|
|
choices=["info", "password", "entry", "stream", "list", "question"],
|
|
help="operation mode. Note: stream mode expects stdin to update text and line starting with #.",
|
|
)
|
|
parsed = parser.parse_args()
|
|
|
|
return parsed
|
|
|
|
|
|
def set_defaults(opts, title, text, geometry=None):
|
|
if opts.text is None:
|
|
opts.text = text
|
|
if opts.title is None:
|
|
opts.title = title
|
|
if opts.geometry is None:
|
|
opts.geometry = geometry
|
|
return opts
|
|
|
|
|
|
def main():
|
|
opts = get_opts()
|
|
tk.Tk().withdraw()
|
|
if opts.mode == "password":
|
|
opts = set_defaults(opts, "Password", "Type password:")
|
|
pw = tkinter.simpledialog.askstring(opts.title, opts.text, show="*")
|
|
print(pw, end="")
|
|
if opts.mode == "info":
|
|
opts = set_defaults(opts, "Info", "Message")
|
|
tkinter.messagebox.showinfo(title=opts.title, message=opts.text)
|
|
if opts.mode == "entry":
|
|
opts = set_defaults(opts, "Entry", "Type message:")
|
|
msg = tkinter.simpledialog.askstring(title=opts.title, prompt=opts.text)
|
|
print(msg, end="")
|
|
if opts.mode == "stream":
|
|
opts = set_defaults(opts, "Info", "", "800x80-50-50")
|
|
StdinBox(title=opts.title, message=opts.text, geometry=opts.geometry)
|
|
if opts.mode == "list":
|
|
opts = set_defaults(opts, "Select", "Select from list:")
|
|
ListBox(title=opts.title, message=opts.text)
|
|
if opts.mode == "question":
|
|
opts = set_defaults(opts, "Entry", "Question")
|
|
msg = tkinter.messagebox.askokcancel(title=opts.title, message=opts.text)
|
|
print(msg, end="")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|