import os import re from tkinter import TclError import customtkinter as ctk try: import arabic_reshaper from bidi.algorithm import get_display except ImportError: arabic_reshaper = None get_display = None ctk.set_appearance_mode("light") ctk.set_default_color_theme("blue") PRIMARY = "#175B4B" PRIMARY_DARK = "#0E4236" PRIMARY_SOFT = "#DFF1E8" ACCENT = "#E8A04D" ACCENT_DARK = "#C97E2D" BACKGROUND = "#F5EFE7" CARD = "#FFFDFC" SURFACE = "#FBF7F2" INPUT_BG = "#FFFCF8" TEXT = "#16312A" MUTED = "#6B7A77" DANGER = "#B6465F" WARNING = "#9A6C3C" BORDER = "#E5DCCE" KEYBOARD_BG = "#D4DCE2" KEY_FACE = "#FFFFFF" KEY_MUTED = "#BCC1C9" KEY_TEXT = "#000000" SIDEBAR = "#1B5A4A" SIDEBAR_SOFT = "#245E4E" FONT_BODY = "Tahoma" if os.name == "nt" else "DejaVu Sans" FONT_TITLE = "Tahoma" if os.name == "nt" else "DejaVu Sans" RTL_PATTERN = re.compile(r"[\u0600-\u06FF]") def ui_text(value): if not isinstance(value, str) or not value: return value if arabic_reshaper is None or get_display is None or not RTL_PATTERN.search(value): return value return get_display(arabic_reshaper.reshape(value)) class _RTLTextMixin: @staticmethod def _normalize_kwargs(kwargs): normalized = dict(kwargs) if "text" in normalized: normalized["text"] = ui_text(normalized["text"]) if "placeholder_text" in normalized: normalized["placeholder_text"] = ui_text(normalized["placeholder_text"]) if "label_text" in normalized: normalized["label_text"] = ui_text(normalized["label_text"]) return normalized class RTLLabel(_RTLTextMixin, ctk.CTkLabel): def __init__(self, *args, **kwargs): super().__init__(*args, **self._normalize_kwargs(kwargs)) def configure(self, require_redraw=False, **kwargs): return super().configure(require_redraw=require_redraw, **self._normalize_kwargs(kwargs)) class RTLButton(_RTLTextMixin, ctk.CTkButton): def __init__(self, *args, **kwargs): kwargs.setdefault("corner_radius", 16) super().__init__(*args, **self._normalize_kwargs(kwargs)) def configure(self, require_redraw=False, **kwargs): return super().configure(require_redraw=require_redraw, **self._normalize_kwargs(kwargs)) class RTLEntry(_RTLTextMixin, ctk.CTkEntry): def __init__(self, *args, **kwargs): kwargs.setdefault("justify", "right") kwargs.setdefault("fg_color", INPUT_BG) kwargs.setdefault("border_color", BORDER) kwargs.setdefault("corner_radius", 16) super().__init__(*args, **self._normalize_kwargs(kwargs)) def configure(self, require_redraw=False, **kwargs): return super().configure(require_redraw=require_redraw, **self._normalize_kwargs(kwargs)) class RTLTextbox(ctk.CTkTextbox): def insert(self, index, text, *tags): return super().insert(index, ui_text(text), *tags) class RTLScrollableFrame(_RTLTextMixin, ctk.CTkScrollableFrame): def __init__(self, *args, **kwargs): super().__init__(*args, **self._normalize_kwargs(kwargs)) def configure(self, require_redraw=False, **kwargs): return super().configure(require_redraw=require_redraw, **self._normalize_kwargs(kwargs))