diff --git a/EDMarketConnector.py b/EDMarketConnector.py index 7e92212c..2edc383c 100644 --- a/EDMarketConnector.py +++ b/EDMarketConnector.py @@ -483,7 +483,7 @@ class AppWindow: PADX = 5 - def __init__(self, master: tk.Tk): # noqa: CCR001, C901 # TODO - can possibly factor something out + def __init__(self, master: tk.Tk): # noqa: CCR001 TODO - can possibly factor something out query_time = config.get_int('querytime', default=0) fleetcarrier_time = config.get_int('fleetcarrierquerytime', default=0) @@ -675,47 +675,45 @@ class AppWindow: # Alternate title bar and menu for dark theme self.theme_menubar = tk.Frame(frame, name="alternate_menubar") self.theme_menubar.columnconfigure(2, weight=1) - self.theme_titlebar = tk.Label( + theme_titlebar = tk.Label( self.theme_menubar, name="alternate_titlebar", text=applongname, image=self.theme_icon, cursor='fleur', anchor=tk.W, compound=tk.LEFT ) - self.theme_titlebar.grid(columnspan=3, padx=2, sticky=tk.NSEW) + theme_titlebar.grid(columnspan=3, padx=2, sticky=tk.NSEW) self.drag_offset: tuple[int | None, int | None] = (None, None) - self.theme_titlebar.bind('', self.drag_start) - self.theme_titlebar.bind('', self.drag_continue) - self.theme_titlebar.bind('', self.drag_end) - self.theme_minimize = tk.Label(self.theme_menubar, image=self.img_theme_minimize) - self.theme_minimize.grid(row=0, column=3, padx=2) - theme.button_bind(self.theme_minimize, self.oniconify, image=self.img_theme_minimize) - self.theme_close = tk.Label(self.theme_menubar, image=self.img_theme_close) - self.theme_close.grid(row=0, column=4, padx=2) - theme.button_bind(self.theme_close, self.onexit, image=self.img_theme_close) - if config.get_int('theme') != theme.THEME_TRANSPARENT: - self.theme_titlebar.grid_remove() - self.theme_minimize.grid_remove() - self.theme_close.grid_remove() - menu_map = { - 'file': self.file_menu, - 'edit': self.edit_menu, - 'help': self.help_menu, - } - self.theme_menus = {} - - for col, (name, menu) in enumerate(menu_map.items()): - lbl = tk.Label(self.theme_menubar, anchor=tk.W) - lbl.grid(row=1, column=col, sticky=tk.W, padx=self.PADX) - theme.button_bind(lbl, lambda e, m=menu: m.tk_popup(e.widget.winfo_rootx(), - e.widget.winfo_rooty() + e.widget.winfo_height())) - self.theme_menus[name] = lbl - self.theme_file_menu = self.theme_menus['file'] - self.theme_edit_menu = self.theme_menus['edit'] - self.theme_help_menu = self.theme_menus['help'] + theme_titlebar.bind('', self.drag_start) + theme_titlebar.bind('', self.drag_continue) + theme_titlebar.bind('', self.drag_end) + theme_minimize = tk.Label(self.theme_menubar, image=self.img_theme_minimize) + theme_minimize.grid(row=0, column=3, padx=2) + theme.button_bind(theme_minimize, self.oniconify, image=self.img_theme_minimize) + theme_close = tk.Label(self.theme_menubar, image=self.img_theme_close) + theme_close.grid(row=0, column=4, padx=2) + theme.button_bind(theme_close, self.onexit, image=self.img_theme_close) + self.theme_file_menu = tk.Label(self.theme_menubar, anchor=tk.W) + self.theme_file_menu.grid(row=1, column=0, padx=self.PADX, sticky=tk.W) + theme.button_bind(self.theme_file_menu, + lambda e: self.file_menu.tk_popup(e.widget.winfo_rootx(), + e.widget.winfo_rooty() + + e.widget.winfo_height())) + self.theme_edit_menu = tk.Label(self.theme_menubar, anchor=tk.W) + self.theme_edit_menu.grid(row=1, column=1, sticky=tk.W) + theme.button_bind(self.theme_edit_menu, + lambda e: self.edit_menu.tk_popup(e.widget.winfo_rootx(), + e.widget.winfo_rooty() + + e.widget.winfo_height())) + self.theme_help_menu = tk.Label(self.theme_menubar, anchor=tk.W) + self.theme_help_menu.grid(row=1, column=2, sticky=tk.W) + theme.button_bind(self.theme_help_menu, + lambda e: self.help_menu.tk_popup(e.widget.winfo_rootx(), + e.widget.winfo_rooty() + + e.widget.winfo_height())) tk.Frame(self.theme_menubar, highlightthickness=1).grid(columnspan=5, padx=self.PADX, sticky=tk.EW) - theme.register(self.theme_minimize) # images aren't automatically registered - theme.register(self.theme_close) + theme.register(self.img_theme_minimize) # images aren't automatically registered + theme.register(self.img_theme_close) self.blank_menubar = tk.Frame(frame, name="blank_menubar") tk.Label(self.blank_menubar).grid() tk.Label(self.blank_menubar).grid() @@ -779,6 +777,56 @@ class AppWindow: protocol.protocolhandler.start(self.w) self.postprefs(False) # Companion login happens in callback from monitor + def _set_grabber(self, frame: tk.Frame | ttk.Frame) -> None: + print(type(frame)) + if config.get_int("theme") != theme.THEME_DEFAULT: + grip_size = 14 + + self.resize_grip = tk.Canvas( + self.w, + width=grip_size, + height=grip_size, + highlightthickness=0, + bg=frame.cget("background"), + ) + + # draw diagonal grip lines + for i in range(4, grip_size, 4): + self.resize_grip.create_line(i, grip_size, grip_size, i, fill="#404040") + + self.resize_grip.bind( + "", + lambda e: self.resize_grip.configure(bg=frame.cget("background")), + ) + self.resize_grip.bind( + "", + lambda e: self.resize_grip.configure(bg=frame.cget("background")), + ) + + self.resize_grip.place(relx=1.0, rely=1.0, anchor="se") + + def _resize_drag(event): + dx = event.x_root - self._resize_start_x + dy = event.y_root - self._resize_start_y + self.w.geometry( + f"{self._resize_start_w + dx}x{self._resize_start_h + dy}" + ) + + def _resize_start(event): + self._resize_start_x = event.x_root + self._resize_start_y = event.y_root + self._resize_start_w = self.w.winfo_width() + self._resize_start_h = self.w.winfo_height() + + self.resize_grip.bind("", _resize_start) + self.resize_grip.bind("", _resize_drag) + else: + try: + if self.resize_grip: + self.resize_grip.place_forget() + except AttributeError: + pass + def update_suit_text(self) -> None: """Update the suit text for current type and loadout.""" if not monitor.state['Odyssey']: @@ -849,6 +897,8 @@ class AppWindow: if dologin and monitor.cmdr: self.login() # Login if not already logged in with this Cmdr + self._set_grabber(root.nametowidget(".edmarketconnector")) + if postargs.get('Update') and postargs.get('Track'): track = postargs.get('Track') # LANG: Inform the user the Update Track has changed @@ -1999,9 +2049,6 @@ class AppWindow: self.w.attributes("-transparentcolor", '') self.blank_menubar.grid_remove() self.theme_menubar.grid(row=0, columnspan=2, sticky=tk.NSEW) - self.theme_titlebar.grid() - self.theme_minimize.grid() - self.theme_close.grid() def onleave(self, event=None) -> None: """Handle when our window loses focus.""" @@ -2009,9 +2056,6 @@ class AppWindow: self.w.attributes("-transparentcolor", 'grey4') self.theme_menubar.grid_remove() self.blank_menubar.grid(row=0, columnspan=2, sticky=tk.NSEW) - self.theme_titlebar.grid_remove() - self.theme_minimize.grid_remove() - self.theme_close.grid_remove() def test_logging() -> None: diff --git a/theme.py b/theme.py index 00dd827f..68a1a391 100644 --- a/theme.py +++ b/theme.py @@ -32,7 +32,7 @@ if sys.platform == "linux": if sys.platform == 'win32': import ctypes - from ctypes.wintypes import DWORD, LPCVOID, LPCWSTR, BOOL + from ctypes.wintypes import DWORD, LPCVOID, LPCWSTR import win32gui AddFontResourceEx = ctypes.windll.gdi32.AddFontResourceExW AddFontResourceEx.argtypes = [LPCWSTR, DWORD, LPCVOID] @@ -43,17 +43,6 @@ if sys.platform == 'win32': if not AddFontResourceEx(font_path, FR_PRIVATE, None): raise RuntimeError(f"Failed to load font {font_path}") - DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 = 19 - DWMWA_USE_IMMERSIVE_DARK_MODE = 20 - - def set_dark_titlebar(hwnd: int, enable: bool = True) -> None: - """Use a Dark Windows Title Bar on Win10+.""" - value = BOOL(enable) - dwmapi = ctypes.WinDLL("dwmapi") - - for attr in (DWMWA_USE_IMMERSIVE_DARK_MODE, DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1): - dwmapi.DwmSetWindowAttribute(hwnd, attr, ctypes.byref(value), ctypes.sizeof(value)) - elif sys.platform == 'linux': # pyright: reportUnboundVariable=false XID = c_ulong # from X.h: typedef unsigned long XID @@ -404,7 +393,7 @@ class _Theme: # Apply configured theme - def apply(self, root: tk.Tk) -> None: # noqa: CCR001 + def apply(self, root: tk.Tk) -> None: # noqa: CCR001, C901 theme = config.get_int('theme') self._colors(root, theme) @@ -439,40 +428,32 @@ class _Theme: if sys.platform == 'win32': import win32con - if theme == self.THEME_TRANSPARENT: + # FIXME: Lose the "treat this like a boolean" bullshit + if theme == self.THEME_DEFAULT: + root.overrideredirect(False) + + else: root.overrideredirect(True) + + if theme == self.THEME_TRANSPARENT: root.attributes("-transparentcolor", 'grey4') else: - root.overrideredirect(False) root.attributes("-transparentcolor", '') root.withdraw() root.update_idletasks() # Size and windows styles get recalculated here - hwnd = ctypes.windll.user32.GetParent(root.winfo_id()) - set_dark_titlebar(hwnd, theme == self.THEME_DARK) hwnd = win32gui.GetParent(root.winfo_id()) win32gui.SetWindowLong(hwnd, win32con.GWL_STYLE, win32gui.GetWindowLong(hwnd, win32con.GWL_STYLE) & ~win32con.WS_MAXIMIZEBOX) # disable maximize - win32gui.SetWindowPos(hwnd, None, 0, 0, 0, 0, - win32con.SWP_NOMOVE | win32con.SWP_NOSIZE | - win32con.SWP_NOZORDER | win32con.SWP_FRAMECHANGED - ) + if theme == self.THEME_TRANSPARENT: win32gui.SetWindowLong(hwnd, win32con.GWL_EXSTYLE, win32con.WS_EX_APPWINDOW | win32con.WS_EX_LAYERED) # Add to taskbar - win32gui.SetWindowPos(hwnd, None, 0, 0, 0, 0, - win32con.SWP_NOMOVE | win32con.SWP_NOSIZE | - win32con.SWP_NOZORDER | win32con.SWP_FRAMECHANGED - ) else: win32gui.SetWindowLong(hwnd, win32con.GWL_EXSTYLE, win32con.WS_EX_APPWINDOW) # Add to taskbar - win32gui.SetWindowPos(hwnd, None, 0, 0, 0, 0, - win32con.SWP_NOMOVE | win32con.SWP_NOSIZE | - win32con.SWP_NOZORDER | win32con.SWP_FRAMECHANGED - ) root.deiconify() root.wait_visibility() # need main window to be displayed before returning @@ -499,7 +480,11 @@ class _Theme: XFlush(dpy) else: - root.overrideredirect(theme == self.THEME_TRANSPARENT) + if theme == self.THEME_DEFAULT: + root.overrideredirect(False) + + else: # Dark *or* Transparent + root.overrideredirect(True) root.deiconify() root.wait_visibility() # need main window to be displayed before returning