From 0ee058216e5394a49744732e5cec41352d8810aa Mon Sep 17 00:00:00 2001 From: Isaiah Odhner Date: Wed, 19 Apr 2023 00:09:40 -0400 Subject: [PATCH] Position submenu --- localization/i18n.py | 8 +++++++ menus.py | 52 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/localization/i18n.py b/localization/i18n.py index 2b0bb33..1e63612 100644 --- a/localization/i18n.py +++ b/localization/i18n.py @@ -3,6 +3,13 @@ import json import re translations = {} +current_language = "en" + +def get_direction() -> str: + """Get the text direction for the current language.""" + if current_language in ["ar", "he"]: + return "rtl" + return "ltr" def load_language(language_code: str): """Load a language from the translations directory.""" @@ -16,6 +23,7 @@ def load_language(language_code: str): end = js.rfind("}") # parse the JSON object translations = json.loads(js[start:end + 1]) + current_language = language_code except FileNotFoundError: print(f"Could not find language file for '{language_code}'.") except json.decoder.JSONDecodeError as e: diff --git a/menus.py b/menus.py index 60f0d74..70bfd8c 100644 --- a/menus.py +++ b/menus.py @@ -9,7 +9,7 @@ from textual.geometry import Offset, Region, Size from textual.reactive import var, reactive from textual.widget import Widget from textual.widgets import Button, Static -from localization.i18n import markup_hotkey +from localization.i18n import markup_hotkey, get_direction def to_snake_case(name): name = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name) @@ -81,7 +81,55 @@ class Menu(Container): self.parent_menu = parent_menu self.parent_menu_item = parent_menu_item self.add_class("menu_popup") - self.styles.offset = (parent_menu_item.region.x, parent_menu_item.region.y + parent_menu_item.region.height) + + if parent_menu.has_class("menu_bar"): + self.styles.offset = (parent_menu_item.region.x, parent_menu_item.region.y + parent_menu_item.region.height) + else: + # JS code for reference + # https://github.com/1j01/os-gui/blob/bb4df0f0c26969c089858118130975cd137cdac8/MenuBar.js#L618-L644 + # submenu_popup_el corresponds to self + # submenu_popup_rect corresponds to self.region + # rect corresponds to parent_menu_item.region + # scroll offset doesn't apply here + + # const rect = item_el.getBoundingClientRect(); + # let submenu_popup_rect = submenu_popup_el.getBoundingClientRect(); + # submenu_popup_el.style.left = `${(get_direction() === "rtl" ? rect.left - submenu_popup_rect.width : rect.right) + window.scrollX}px`; + # submenu_popup_el.style.top = `${rect.top + window.scrollY}px`; + # submenu_popup_rect = submenu_popup_el.getBoundingClientRect(); + # if (get_direction() === "rtl") { + # if (submenu_popup_rect.left < 0) { + # submenu_popup_el.style.left = `${rect.right}px`; + # submenu_popup_rect = submenu_popup_el.getBoundingClientRect(); + # if (submenu_popup_rect.right > innerWidth) { + # submenu_popup_el.style.left = `${innerWidth - submenu_popup_rect.width}px`; + # } + # } + # } else { + # if (submenu_popup_rect.right > innerWidth) { + # submenu_popup_el.style.left = `${rect.left - submenu_popup_rect.width}px`; + # submenu_popup_rect = submenu_popup_el.getBoundingClientRect(); + # if (submenu_popup_rect.left < 0) { + # submenu_popup_el.style.left = "0"; + # } + # } + # } + + rect = parent_menu_item.region + self.styles.offset = ( + rect.x - self.region.width if get_direction() == "rtl" else rect.x + rect.width, + rect.y + ) + if get_direction() == "rtl": + if self.region.x < 0: + self.styles.offset = (rect.x + rect.width, rect.y) + if self.region.x + self.region.width > self.screen.size.width: + self.styles.offset = (self.screen.size.width - self.region.width, rect.y) + else: + if self.region.x + self.region.width > self.screen.size.width: + self.styles.offset = (rect.x - self.region.width, rect.y) + if self.region.x < 0: + self.styles.offset = (0, rect.y) # Find the widest label max_width = 0