Skip to content

Commit

Permalink
Merge pull request #41 from fabaindaiz/main
Browse files Browse the repository at this point in the history
Dev: update contributions
  • Loading branch information
fabaindaiz authored Oct 21, 2023
2 parents a9b3817 + b54bf85 commit ffc5529
Show file tree
Hide file tree
Showing 12 changed files with 553 additions and 336 deletions.
131 changes: 131 additions & 0 deletions src/interfaces/board.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
from typing import List, Tuple, Dict

from src.config import SWAP
from src.interfaces.baseui import BaseUI
from src.interfaces.boardbutton import BoardButton
from src.interfaces.boardlabel import BoardLabel
from src.interfaces.boardtile import BoardTile
from src.modules.resultlist import ResultWord
from src.utils.utils import aux_to_indices


class Board:
"""Represents an abstract board
Args:
app (BaseUI): The base user interface for the board.
Attributes:
app (BaseUI): The base user interface for the board.
double_swap (bool): A boolean indicating whether SWAP is greater than or equal to 2.
buttons (List[BoardButton]): A list of board buttons.
labels (List[BoardLabel]): A list of board labels.
tiles (Dict[Tuple[int, int], BoardTile]): A dictionary mapping coordinates to board tiles.
"""

def __init__(self, app: BaseUI) -> None:
"""Initialize the Board with a BaseUI instance.
Args:
app (BaseUI): The base user interface for the board.
"""

self.app: BaseUI = app
self.double_swap: bool = SWAP >= 2

self.buttons: List[BoardButton] = []
self.labels: List[BoardLabel] = []
self.tiles: Dict[Tuple[int, int], BoardTile] = {}

self.initialize_components()

def initialize_components(self) -> None:
"""Initialize the components of the board: buttons, tiles, and labels."""

self.initialize_buttons()
self.initialize_tiles()
self.initialize_labels()

def initialize_buttons(self) -> None:
"""Initialize board buttons based on the value of SWAP."""

swap_options = [0, 1]

if self.double_swap:
swap_options.append(2)

for option in swap_options:
button = self.create_button(option)

self.buttons.append(button)

def create_button(self, swap_count: int) -> BoardButton:
"""Create a board button for a specific swap count.
Args:
swap_count (int): The number of swaps represented by the button.
Returns:
BoardButton: The created board button.
"""

return BoardButton(
parent=self.app,
double_swap=self.double_swap,
swap_count=swap_count,
command=lambda: self.button_command(swap_count),
)

def initialize_tiles(self) -> None:
"""Initialize board tiles on the board."""

for tile_index in range(25):
coord_index = aux_to_indices(tile_index)

self.tiles[coord_index] = BoardTile(self, tile_index)

def initialize_labels(self) -> None:
"""Initialize board labels on the board."""

for label_index in range(10):
label = BoardLabel(self, label_index)

self.labels.append(label)

def set_results(self, word_list: List[ResultWord]) -> None:
"""Set results on the board labels.
Args:
word_list (List[ResultWord]): A list of result words to be displayed on the labels.
"""

self.reset_labels()
self.update_labels(word_list)

def reset_labels(self) -> None:
"""Reset the text on all board labels."""

for label in self.labels:
label.reset()

def update_labels(self, word_list: List[ResultWord]) -> None:
"""Update the text and paths on board labels.
Args:
word_list (List[ResultWord]): A list of result words to be displayed on the labels.
"""

for label, result in zip(self.labels, word_list):
text = result.text()
path = result.path

label.set_hover(text, path)

def button_command(self, swap: int) -> None:
"""Handle a button click action, to be implemented in subclasses.
Args:
swap (int): The number of swaps represented by the clicked button.
"""

raise NotImplementedError()
163 changes: 163 additions & 0 deletions src/interfaces/boardbutton.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
from tkinter import ttk
from typing import Callable


class BoardButton:
"""
Represents a button on a game board.
Attributes:
INITIAL_HORIZONTAL_POSITION (int): The initial horizontal position for buttons.
INITIAL_VERTICAL_POSITION (int): The initial vertical position for buttons.
DOUBLE_SWAP_HORIZONTAL_POSITION (int): The horizontal position for buttons when double swapping.
BUTTON_HEIGHT (int): The height of the button.
Args:
parent: The parent widget that contains the button.
double_swap (bool): Whether it's a double swap button.
swap_count (int): The number of swaps associated with the button.
command (Callable): The function to execute when the button is clicked.
"""

INITIAL_HORIZONTAL_POSITION = 100
INITIAL_VERTICAL_POSITION = 210
DOUBLE_SWAP_HORIZONTAL_POSITION = 67
BUTTON_HEIGHT = 30

def __init__(self, parent, double_swap: bool, swap_count: int, command: Callable):
"""
Initializes a BoardButton instance.
Args:
parent: The parent widget that contains the button.
double_swap (bool): Whether it's a double swap button.
swap_count (int): The number of swaps associated with the button.
command (Callable): The function to execute when the button is clicked.
"""

self.parent = parent
self.double_swap = double_swap
self.swap_count = swap_count
self.command = command
self.button = self.initialize()

def initialize(self):
"""
Initializes the button, sets its style, and positions it on the screen.
Returns:
ttk.Button: The initialized button.
"""
master = self.parent.window
text = self.get_label()
command = self.command

button = ttk.Button(master=master, text=text, command=command)

self.configure_style()
self.set_position(button)

return button

def get_label(self):
"""
Generates the label text for the button based on the swap count.
Returns:
str: The label text.
"""
return (
f"{self.swap_count} Swap"
if self.swap_count == 1
else f"{self.swap_count} Swaps"
)

def set_position(self, button):
"""
Sets the position of the button on the screen.
Args:
button (ttk.Button): The button to position.
"""
width, height = self.calculate_size()
horizontal_position, vertical_position = self.calculate_position()

button.place(
x=horizontal_position, y=vertical_position, width=width, height=height
)

def horizontal_position(self):
"""
Calculates the horizontal position based on double swap and swap count.
Returns:
int: The horizontal position.
"""
return (
self.DOUBLE_SWAP_HORIZONTAL_POSITION * self.swap_count
if self.double_swap
else self.INITIAL_HORIZONTAL_POSITION * self.swap_count
)

def calculate_width(self):
"""
Calculates the button width based on double swap.
Returns:
int: The button width.
"""
return (
self.DOUBLE_SWAP_HORIZONTAL_POSITION
if self.double_swap
else self.INITIAL_HORIZONTAL_POSITION
)

def calculate_size(self):
"""
Calculates the button size (width and height).
Returns:
Tuple[int, int]: The button width and height.
"""
width = self.calculate_width()
height = self.BUTTON_HEIGHT

return width, height

def calculate_padding(self):
"""
Calculates the horizontal and vertical padding for button positioning.
Returns:
Tuple[int, int]: The horizontal and vertical padding.
"""
horizontal_padding = self.parent.HORIZONTAL_PADDING
vertical_padding = self.parent.VERTICAL_PADDING

return horizontal_padding, vertical_padding

def calculate_position(self):
"""
Calculates the position of the button on the screen.
Returns:
Tuple[int, int]: The horizontal and vertical position.
"""
horizontal_padding, vertical_padding = self.calculate_padding()

horizontal_position = horizontal_padding + self.horizontal_position()
vertical_position = vertical_padding + self.INITIAL_VERTICAL_POSITION

return horizontal_position, vertical_position

@staticmethod
def configure_style():
"""
Configures the style of the ttk button.
"""
style = ttk.Style()
style.configure(
style="TButton",
background="#e9e9ed",
font=("Times", 12),
foreground="#000000",
)
47 changes: 47 additions & 0 deletions src/interfaces/boardentry.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import tkinter as tk

from src.utils.utils import aux_to_indices


class BoardEntry:
"""Represents a square tile in the board"""

def __init__(self, board, menu, stringvar: tk.StringVar, aux_cord: int) -> None:
self.board = board
app = board.app

cord = aux_to_indices(aux_cord)
next = aux_to_indices(aux_cord + 1)
x, y = cord

def on_validate(input: str) -> bool:
"""Validate the value in the entry"""
if len(input) > 1:
self.board.tiles[cord].entry.focus()
return False
if len(input) == 1:
self.board.tiles[next].entry.focus()
return True

self.entry: tk.Entry = tk.Entry(
app.window,
textvariable=stringvar,
validate="key",
highlightthickness=2,
)
self.entry["borderwidth"] = "1px"
self.entry["fg"] = "#333333"
self.entry["justify"] = "center"
self.entry["validatecommand"] = (self.entry.register(on_validate), "%P")
self.entry.bind("<Button-3>", lambda event: menu.popup(event))
self.entry.place(
x=app.HORIZONTAL_PADDING + 40 * x,
y=app.VERTICAL_PADDING + 40 * y,
width=40,
height=40,
)

def focus(self) -> None:
"""Set the focus on the entry"""
self.entry.focus_set()
self.entry.select_range(0, "end")
Loading

0 comments on commit ffc5529

Please sign in to comment.