Skip to content

Commit d32f35a

Browse files
authored
Merge pull request #10 from Wdude04/multiple-button-layouts
Multiple button layouts This pull request refactors GUI code to inherit from a new AbstractBaseWidget class that shares common functionality, including creation and re-creation upon resizing. It also adds a new ButtonLayout class that can be used to define button layouts for the calculator, as well as two default layouts: LAYOUT_STANDARD_WIDE and LAYOUT_STANDARD_TALL, which are used depending on the aspect ratio of the window.
2 parents 59a067c + a5806ad commit d32f35a

File tree

4 files changed

+105
-31
lines changed

4 files changed

+105
-31
lines changed

calculator/gui/base_widget.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import api
2+
import tkinter as tk
3+
from abc import ABC, abstractmethod
4+
5+
class AbstractBaseWidget(ABC):
6+
def __init__(self, calculator: api.Calculator):
7+
self.parent = None
8+
self.frame = None
9+
self.calculator = calculator
10+
self.prev_window_resolution = (0,0)
11+
12+
def get_window_resolution(self):
13+
return (self.parent.winfo_width(), self.parent.winfo_height())
14+
15+
def init_gui(self, parent):
16+
self.parent = parent
17+
self.frame = tk.Frame(parent)
18+
self.prev_window_resolution = self.get_window_resolution()
19+
self._create_layout(self.prev_window_resolution)
20+
21+
@abstractmethod
22+
def _create_layout(self, window_resolution: tuple):
23+
pass
24+
25+
def _destroy_layout(self):
26+
for child in self.frame.winfo_children():
27+
child.destroy()
28+
29+
@abstractmethod
30+
def _update(self):
31+
pass
32+
33+
def update(self):
34+
window_resolution = self.get_window_resolution()
35+
if self.prev_window_resolution != window_resolution:
36+
self._destroy_layout()
37+
self._create_layout(window_resolution)
38+
self._update()
39+
self.prev_window_resolution = window_resolution

calculator/gui/button.py

Lines changed: 58 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,71 @@
11
import api
22
import tkinter as tk
3+
from dataclasses import dataclass, field
4+
from gui.base_widget import AbstractBaseWidget
35

4-
LAYOUT_STANDARD = ["AC", "CE", "%", "/",
5-
"7", "8", "9", "x",
6-
"4", "5", "6", "-",
7-
"1", "2", "3", "+",
8-
"+/-", "0", ".", "="]
6+
NO_BUTTON = "NO_BUTTON"
7+
8+
@dataclass
9+
class ButtonLayout:
10+
width: int
11+
buttons: list[str]
12+
size_overrides: dict = field(default_factory=dict)
13+
14+
LAYOUT_STANDARD_TALL = ButtonLayout(4,
15+
["AC", "CE", "%", "/",
16+
"7", "8", "9", "x",
17+
"4", "5", "6", "-",
18+
"1", "2", "3", "+",
19+
"+/-", "0", ".", "="])
20+
21+
LAYOUT_STANDARD_WIDE = ButtonLayout(5,
22+
["AC", "7", "8", "9", "/",
23+
"CE", "4", "5", "6", "x",
24+
"%", "1", "2", "3", "-",
25+
"+/-", "0", ".", "=", "+"])
926

1027
def calc_button(root, calculator: api.Calculator, display_text):
1128
button = tk.Button(root, text=display_text, command=lambda: calculator.input_button(display_text))
1229
return button
1330

14-
class CalculatorButtons:
15-
def __init__(self, calculator: api.Calculator):
16-
self.calculator = calculator
17-
self.frame = None
18-
self.buttons = []
31+
class CalculatorButtons(AbstractBaseWidget):
32+
def __init__(self, calculator):
33+
super().__init__(calculator)
34+
self.prev_column_count = 0
1935

20-
def create_gui(self, root, layout=LAYOUT_STANDARD, width=4):
21-
self.frame = tk.Frame(root)
36+
def _create_layout(self, window_resolution):
37+
aspect_ratio = window_resolution[0] / window_resolution[1]
38+
if aspect_ratio > 1:
39+
self.create_buttons(LAYOUT_STANDARD_WIDE)
40+
self.prev_column_count = LAYOUT_STANDARD_WIDE.width
41+
else:
42+
self.create_buttons(LAYOUT_STANDARD_TALL)
43+
self.prev_column_count = LAYOUT_STANDARD_TALL.width
44+
45+
def _destroy_layout(self):
46+
super()._destroy_layout()
47+
for i in range(self.prev_column_count):
48+
self.frame.columnconfigure(i, weight=0)
49+
50+
def _update(self):
51+
pass
2252

23-
for i, label in enumerate(layout):
53+
def create_buttons(self, layout: ButtonLayout):
54+
for i, label in enumerate(layout.buttons):
55+
if label == NO_BUTTON:
56+
continue
57+
x = i%layout.width
58+
y = int(i/layout.width)
59+
size_x = 1
60+
size_y = 1
61+
if (x,y) in layout.size_overrides:
62+
size_x, size_y = layout.size_overrides[(x,y)]
63+
2464
button = calc_button(self.frame, self.calculator, label)
25-
button.grid(column=i%width, row=int(i/width), sticky=tk.NSEW)
26-
self.buttons.append(button)
65+
button.grid(column=x, row=y, sticky=tk.NSEW, columnspan=size_x, rowspan=size_y)
2766

28-
for i in range(width):
29-
self.frame.grid_columnconfigure(i, uniform="calc_buttons", weight=1)
67+
for i in range(layout.width):
68+
self.frame.grid_columnconfigure(i, weight=1)
3069

31-
for i in range(int(len(layout)/width)):
32-
self.frame.grid_rowconfigure(i, weight=1)
33-
34-
def update(self):
35-
pass
70+
for i in range(int(len(layout.buttons)/layout.width)):
71+
self.frame.grid_rowconfigure(i, weight=1)

calculator/gui/display.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,20 @@
11
import api
22
import tkinter as tk
3+
from gui.base_widget import AbstractBaseWidget
34

4-
class CalculatorDisplay:
5+
class CalculatorDisplay(AbstractBaseWidget):
56
def __init__(self, calculator: api.Calculator):
6-
self.calculator = calculator
7-
self.frame = None
7+
super().__init__(calculator)
88
self.upper_entry = None
99
self.lower_entry = None
1010

11-
def create_gui(self, root):
12-
self.frame = tk.Frame(root)
11+
def _create_layout(self, window_resolution):
1312
self.upper_entry = tk.Entry(self.frame, state=tk.DISABLED, justify=tk.RIGHT)
1413
self.lower_entry = tk.Entry(self.frame, state=tk.DISABLED, justify=tk.RIGHT)
1514
self.upper_entry.pack(fill=tk.BOTH,expand=True,side=tk.TOP)
1615
self.lower_entry.pack(fill=tk.BOTH,expand=True,side=tk.BOTTOM)
17-
18-
def update(self):
16+
17+
def _update(self):
1918
self.upper_entry.configure(state=tk.NORMAL)
2019
self.lower_entry.configure(state=tk.NORMAL)
2120

calculator/main.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ def create_gui(self):
1515
self.display = gui.CalculatorDisplay(self.calculator)
1616
self.buttons = gui.CalculatorButtons(self.calculator)
1717

18-
self.display.create_gui(self.window)
19-
self.buttons.create_gui(self.window)
18+
self.display.init_gui(self.window)
19+
self.buttons.init_gui(self.window)
2020

2121
self.display.frame.pack(fill=tk.BOTH,expand=True,side=tk.TOP,padx=10,pady=(10,0))
2222
self.buttons.frame.pack(fill=tk.BOTH,expand=True,side=tk.BOTTOM,padx=10,pady=(0,10))

0 commit comments

Comments
 (0)