diff --git a/calculator/gui/base_widget.py b/calculator/gui/base_widget.py new file mode 100644 index 0000000..f3cf9fb --- /dev/null +++ b/calculator/gui/base_widget.py @@ -0,0 +1,39 @@ +import api +import tkinter as tk +from abc import ABC, abstractmethod + +class AbstractBaseWidget(ABC): + def __init__(self, calculator: api.Calculator): + self.parent = None + self.frame = None + self.calculator = calculator + self.prev_window_resolution = (0,0) + + def get_window_resolution(self): + return (self.parent.winfo_width(), self.parent.winfo_height()) + + def init_gui(self, parent): + self.parent = parent + self.frame = tk.Frame(parent) + self.prev_window_resolution = self.get_window_resolution() + self._create_layout(self.prev_window_resolution) + + @abstractmethod + def _create_layout(self, window_resolution: tuple): + pass + + def _destroy_layout(self): + for child in self.frame.winfo_children(): + child.destroy() + + @abstractmethod + def _update(self): + pass + + def update(self): + window_resolution = self.get_window_resolution() + if self.prev_window_resolution != window_resolution: + self._destroy_layout() + self._create_layout(window_resolution) + self._update() + self.prev_window_resolution = window_resolution \ No newline at end of file diff --git a/calculator/gui/button.py b/calculator/gui/button.py index c345078..77f2338 100644 --- a/calculator/gui/button.py +++ b/calculator/gui/button.py @@ -1,35 +1,71 @@ import api import tkinter as tk +from dataclasses import dataclass, field +from gui.base_widget import AbstractBaseWidget -LAYOUT_STANDARD = ["AC", "CE", "%", "/", - "7", "8", "9", "x", - "4", "5", "6", "-", - "1", "2", "3", "+", - "+/-", "0", ".", "="] +NO_BUTTON = "NO_BUTTON" + +@dataclass +class ButtonLayout: + width: int + buttons: list[str] + size_overrides: dict = field(default_factory=dict) + +LAYOUT_STANDARD_TALL = ButtonLayout(4, + ["AC", "CE", "%", "/", + "7", "8", "9", "x", + "4", "5", "6", "-", + "1", "2", "3", "+", + "+/-", "0", ".", "="]) + +LAYOUT_STANDARD_WIDE = ButtonLayout(5, + ["AC", "7", "8", "9", "/", + "CE", "4", "5", "6", "x", + "%", "1", "2", "3", "-", + "+/-", "0", ".", "=", "+"]) def calc_button(root, calculator: api.Calculator, display_text): button = tk.Button(root, text=display_text, command=lambda: calculator.input_button(display_text)) return button -class CalculatorButtons: - def __init__(self, calculator: api.Calculator): - self.calculator = calculator - self.frame = None - self.buttons = [] +class CalculatorButtons(AbstractBaseWidget): + def __init__(self, calculator): + super().__init__(calculator) + self.prev_column_count = 0 - def create_gui(self, root, layout=LAYOUT_STANDARD, width=4): - self.frame = tk.Frame(root) + def _create_layout(self, window_resolution): + aspect_ratio = window_resolution[0] / window_resolution[1] + if aspect_ratio > 1: + self.create_buttons(LAYOUT_STANDARD_WIDE) + self.prev_column_count = LAYOUT_STANDARD_WIDE.width + else: + self.create_buttons(LAYOUT_STANDARD_TALL) + self.prev_column_count = LAYOUT_STANDARD_TALL.width + + def _destroy_layout(self): + super()._destroy_layout() + for i in range(self.prev_column_count): + self.frame.columnconfigure(i, weight=0) + + def _update(self): + pass - for i, label in enumerate(layout): + def create_buttons(self, layout: ButtonLayout): + for i, label in enumerate(layout.buttons): + if label == NO_BUTTON: + continue + x = i%layout.width + y = int(i/layout.width) + size_x = 1 + size_y = 1 + if (x,y) in layout.size_overrides: + size_x, size_y = layout.size_overrides[(x,y)] + button = calc_button(self.frame, self.calculator, label) - button.grid(column=i%width, row=int(i/width), sticky=tk.NSEW) - self.buttons.append(button) + button.grid(column=x, row=y, sticky=tk.NSEW, columnspan=size_x, rowspan=size_y) - for i in range(width): - self.frame.grid_columnconfigure(i, uniform="calc_buttons", weight=1) + for i in range(layout.width): + self.frame.grid_columnconfigure(i, weight=1) - for i in range(int(len(layout)/width)): - self.frame.grid_rowconfigure(i, weight=1) - - def update(self): - pass \ No newline at end of file + for i in range(int(len(layout.buttons)/layout.width)): + self.frame.grid_rowconfigure(i, weight=1) \ No newline at end of file diff --git a/calculator/gui/display.py b/calculator/gui/display.py index b02a9b0..1719132 100644 --- a/calculator/gui/display.py +++ b/calculator/gui/display.py @@ -1,21 +1,20 @@ import api import tkinter as tk +from gui.base_widget import AbstractBaseWidget -class CalculatorDisplay: +class CalculatorDisplay(AbstractBaseWidget): def __init__(self, calculator: api.Calculator): - self.calculator = calculator - self.frame = None + super().__init__(calculator) self.upper_entry = None self.lower_entry = None - def create_gui(self, root): - self.frame = tk.Frame(root) + def _create_layout(self, window_resolution): self.upper_entry = tk.Entry(self.frame, state=tk.DISABLED, justify=tk.RIGHT) self.lower_entry = tk.Entry(self.frame, state=tk.DISABLED, justify=tk.RIGHT) self.upper_entry.pack(fill=tk.BOTH,expand=True,side=tk.TOP) self.lower_entry.pack(fill=tk.BOTH,expand=True,side=tk.BOTTOM) - - def update(self): + + def _update(self): self.upper_entry.configure(state=tk.NORMAL) self.lower_entry.configure(state=tk.NORMAL) diff --git a/calculator/main.py b/calculator/main.py index 3d05c65..9a1099b 100644 --- a/calculator/main.py +++ b/calculator/main.py @@ -15,8 +15,8 @@ def create_gui(self): self.display = gui.CalculatorDisplay(self.calculator) self.buttons = gui.CalculatorButtons(self.calculator) - self.display.create_gui(self.window) - self.buttons.create_gui(self.window) + self.display.init_gui(self.window) + self.buttons.init_gui(self.window) self.display.frame.pack(fill=tk.BOTH,expand=True,side=tk.TOP,padx=10,pady=(10,0)) self.buttons.frame.pack(fill=tk.BOTH,expand=True,side=tk.BOTTOM,padx=10,pady=(0,10))