mirror of
https://github.com/akuker/RASCSI.git
synced 2026-04-21 02:17:25 +00:00
Auto-format Python sources with black, fix all issues reported by flake8 (#1010)
* Update config for black and flake8 * Auto-format Python sources with black * Fix issues reported by flake8 * Exclude protobuf files from black * Address formatting feedback
This commit is contained in:
@@ -5,6 +5,7 @@ from menu.screensaver import ScreenSaver
|
||||
class BlankScreenSaver(ScreenSaver):
|
||||
"""Class implementing a blank screen safer that simply blanks the screen after a
|
||||
configured activation delay"""
|
||||
|
||||
def __init__(self, activation_delay, menu_renderer):
|
||||
super().__init__(activation_delay, menu_renderer)
|
||||
self._initial_draw_call = None
|
||||
|
||||
@@ -8,9 +8,17 @@ class Cycler:
|
||||
"""Class implementing button cycling functionality. Message is shown at the center of
|
||||
the screen where repeated button presses cycle through the available selection
|
||||
possibilities. Inactivity (cycle_timeout) actives cycle entry last shown on the screen."""
|
||||
def __init__(self, menu_controller, sock_cmd, ractl_cmd,
|
||||
cycle_timeout=3, return_string="Return ->",
|
||||
return_entry=True, empty_messages=True):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
menu_controller,
|
||||
sock_cmd,
|
||||
ractl_cmd,
|
||||
cycle_timeout=3,
|
||||
return_string="Return ->",
|
||||
return_entry=True,
|
||||
empty_messages=True,
|
||||
):
|
||||
self._cycle_profile_timer_flag = Timer(activation_delay=cycle_timeout)
|
||||
self._menu_controller = menu_controller
|
||||
self.sock_cmd = sock_cmd
|
||||
@@ -39,7 +47,7 @@ class Cycler:
|
||||
"""Perform the return action, i.e., when no selection is chosen"""
|
||||
|
||||
def update(self):
|
||||
""" Returns True if object has completed its task and can be deleted """
|
||||
"""Returns True if object has completed its task and can be deleted"""
|
||||
|
||||
if self._cycle_profile_timer_flag is None:
|
||||
return None
|
||||
|
||||
@@ -4,6 +4,7 @@ from typing import List
|
||||
|
||||
class Menu:
|
||||
"""Class implement the Menu class"""
|
||||
|
||||
def __init__(self, name: str):
|
||||
self.entries: List = []
|
||||
self.item_selection = 0
|
||||
@@ -17,11 +18,11 @@ class Menu:
|
||||
|
||||
def get_current_text(self):
|
||||
"""Returns the text content of the currently selected text in the menu."""
|
||||
return self.entries[self.item_selection]['text']
|
||||
return self.entries[self.item_selection]["text"]
|
||||
|
||||
def get_current_info_object(self):
|
||||
"""Returns the data object to the currently selected menu item"""
|
||||
return self.entries[self.item_selection]['data_object']
|
||||
return self.entries[self.item_selection]["data_object"]
|
||||
|
||||
def __repr__(self):
|
||||
print("entries: " + str(self.entries))
|
||||
|
||||
@@ -6,6 +6,7 @@ from menu.menu import Menu
|
||||
# pylint: disable=too-few-public-methods
|
||||
class MenuBuilder(ABC):
|
||||
"""Base class for menu builders"""
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ from menu.screensaver import ScreenSaver
|
||||
class MenuRenderer(ABC):
|
||||
"""The abstract menu renderer class provides the base for concrete menu
|
||||
renderer classes that implement functionality based on conrete hardware or available APIs."""
|
||||
|
||||
def __init__(self, config: MenuRendererConfig):
|
||||
self.message = ""
|
||||
self.mini_message = ""
|
||||
@@ -25,7 +26,7 @@ class MenuRenderer(ABC):
|
||||
self._config = config
|
||||
self.disp = self.display_init()
|
||||
|
||||
self.image = Image.new('1', (self.disp.width, self.disp.height))
|
||||
self.image = Image.new("1", (self.disp.width, self.disp.height))
|
||||
self.draw = ImageDraw.Draw(self.image)
|
||||
self.font = ImageFont.truetype(config.font_path, size=config.font_size)
|
||||
# just a sample text to work with the font height
|
||||
@@ -83,14 +84,21 @@ class MenuRenderer(ABC):
|
||||
def draw_row(self, row_number: int, text: str, selected: bool):
|
||||
"""Draws a single row of the menu."""
|
||||
x_pos = 0
|
||||
y_pos = row_number*self.font_height
|
||||
y_pos = row_number * self.font_height
|
||||
if selected:
|
||||
selection_extension = 0
|
||||
if row_number < self.rows_per_screen():
|
||||
selection_extension = self._config.row_selection_pixel_extension
|
||||
self.draw.rectangle((x_pos, y_pos, self.disp.width,
|
||||
y_pos+self._config.font_size+selection_extension),
|
||||
outline=0, fill=255)
|
||||
self.draw.rectangle(
|
||||
(
|
||||
x_pos,
|
||||
y_pos,
|
||||
self.disp.width,
|
||||
y_pos + self._config.font_size + selection_extension,
|
||||
),
|
||||
outline=0,
|
||||
fill=255,
|
||||
)
|
||||
|
||||
# in stage 1, we initialize scrolling for the currently selected line
|
||||
if self._perform_scrolling_stage == 1:
|
||||
@@ -99,9 +107,9 @@ class MenuRenderer(ABC):
|
||||
|
||||
# in stage 2, we know the details and can thus perform the scrolling to the left
|
||||
if self._perform_scrolling_stage == 2:
|
||||
if self._current_line_horizontal_overlap+self._x_scrolling > 0:
|
||||
if self._current_line_horizontal_overlap + self._x_scrolling > 0:
|
||||
self._x_scrolling -= 1
|
||||
if self._current_line_horizontal_overlap+self._x_scrolling == 0:
|
||||
if self._current_line_horizontal_overlap + self._x_scrolling == 0:
|
||||
self._stage_timestamp = int(time.time())
|
||||
self._perform_scrolling_stage = 3
|
||||
|
||||
@@ -115,11 +123,12 @@ class MenuRenderer(ABC):
|
||||
|
||||
# in stage 4, we scroll back to the right
|
||||
if self._perform_scrolling_stage == 4:
|
||||
if self._current_line_horizontal_overlap+self._x_scrolling >= 0:
|
||||
if self._current_line_horizontal_overlap + self._x_scrolling >= 0:
|
||||
self._x_scrolling += 1
|
||||
|
||||
if (self._current_line_horizontal_overlap +
|
||||
self._x_scrolling) == self._current_line_horizontal_overlap:
|
||||
if (
|
||||
self._current_line_horizontal_overlap + self._x_scrolling
|
||||
) == self._current_line_horizontal_overlap:
|
||||
self._stage_timestamp = int(time.time())
|
||||
self._perform_scrolling_stage = 5
|
||||
|
||||
@@ -131,8 +140,14 @@ class MenuRenderer(ABC):
|
||||
self._stage_timestamp = None
|
||||
self._perform_scrolling_stage = 2
|
||||
|
||||
self.draw.text((x_pos+self._x_scrolling, y_pos), text, font=self.font,
|
||||
spacing=0, stroke_fill=0, fill=0)
|
||||
self.draw.text(
|
||||
(x_pos + self._x_scrolling, y_pos),
|
||||
text,
|
||||
font=self.font,
|
||||
spacing=0,
|
||||
stroke_fill=0,
|
||||
fill=0,
|
||||
)
|
||||
else:
|
||||
self.draw.text((x_pos, y_pos), text, font=self.font, spacing=0, stroke_fill=0, fill=255)
|
||||
|
||||
@@ -143,8 +158,15 @@ class MenuRenderer(ABC):
|
||||
centered_height = (self.disp.height - font_height) / 2
|
||||
|
||||
self.draw.rectangle((0, 0, self.disp.width, self.disp.height), outline=0, fill=255)
|
||||
self.draw.text((centered_width, centered_height), text, align="center", font=self.font,
|
||||
stroke_fill=0, fill=0, textsize=20)
|
||||
self.draw.text(
|
||||
(centered_width, centered_height),
|
||||
text,
|
||||
align="center",
|
||||
font=self.font,
|
||||
stroke_fill=0,
|
||||
fill=0,
|
||||
textsize=20,
|
||||
)
|
||||
|
||||
def draw_mini_message(self, text: str):
|
||||
"""Draws a fullscreen message, i.e., a message covering only the center portion of
|
||||
@@ -153,16 +175,33 @@ class MenuRenderer(ABC):
|
||||
centered_width = (self.disp.width - font_width) / 2
|
||||
centered_height = (self.disp.height - self.font_height) / 2
|
||||
|
||||
self.draw.rectangle((0, centered_height-4, self.disp.width,
|
||||
centered_height+self.font_height+4), outline=0, fill=255)
|
||||
self.draw.text((centered_width, centered_height), text, align="center", font=self.font,
|
||||
stroke_fill=0, fill=0, textsize=20)
|
||||
self.draw.rectangle(
|
||||
(
|
||||
0,
|
||||
centered_height - 4,
|
||||
self.disp.width,
|
||||
centered_height + self.font_height + 4,
|
||||
),
|
||||
outline=0,
|
||||
fill=255,
|
||||
)
|
||||
self.draw.text(
|
||||
(centered_width, centered_height),
|
||||
text,
|
||||
align="center",
|
||||
font=self.font,
|
||||
stroke_fill=0,
|
||||
fill=0,
|
||||
textsize=20,
|
||||
)
|
||||
|
||||
def draw_menu(self):
|
||||
"""Method draws the menu set to the class instance."""
|
||||
if self._menu.item_selection >= self.frame_start_row + self.rows_per_screen():
|
||||
if self._config.scroll_behavior == "page":
|
||||
self.frame_start_row = self.frame_start_row + (round(self.rows_per_screen()/2)) + 1
|
||||
self.frame_start_row = (
|
||||
self.frame_start_row + (round(self.rows_per_screen() / 2)) + 1
|
||||
)
|
||||
if self.frame_start_row > len(self._menu.entries) - self.rows_per_screen():
|
||||
self.frame_start_row = len(self._menu.entries) - self.rows_per_screen()
|
||||
else: # extend as default behavior
|
||||
@@ -170,13 +209,15 @@ class MenuRenderer(ABC):
|
||||
|
||||
if self._menu.item_selection < self.frame_start_row:
|
||||
if self._config.scroll_behavior == "page":
|
||||
self.frame_start_row = self.frame_start_row - (round(self.rows_per_screen()/2)) - 1
|
||||
self.frame_start_row = (
|
||||
self.frame_start_row - (round(self.rows_per_screen() / 2)) - 1
|
||||
)
|
||||
if self.frame_start_row < 0:
|
||||
self.frame_start_row = 0
|
||||
else: # extend as default behavior
|
||||
self.frame_start_row = self._menu.item_selection
|
||||
|
||||
self.draw_menu_frame(self.frame_start_row, self.frame_start_row+self.rows_per_screen())
|
||||
self.draw_menu_frame(self.frame_start_row, self.frame_start_row + self.rows_per_screen())
|
||||
|
||||
def draw_menu_frame(self, frame_start_row: int, frame_end_row: int):
|
||||
"""Draws row frame_start_row to frame_end_row of the class instance menu, i.e., it
|
||||
|
||||
@@ -11,8 +11,9 @@ class MenuRendererAdafruitSSD1306(MenuRenderer):
|
||||
|
||||
def display_init(self):
|
||||
i2c = busio.I2C(SCL, SDA)
|
||||
self.disp = adafruit_ssd1306.SSD1306_I2C(self._config.width, self._config.height, i2c,
|
||||
addr=self._config.i2c_address)
|
||||
self.disp = adafruit_ssd1306.SSD1306_I2C(
|
||||
self._config.width, self._config.height, i2c, addr=self._config.i2c_address
|
||||
)
|
||||
self.disp.rotation = self._config.get_mapped_rotation()
|
||||
self.disp.fill(0)
|
||||
self.disp.show()
|
||||
|
||||
@@ -5,20 +5,16 @@
|
||||
class MenuRendererConfig:
|
||||
"""Class for configuring menu renderer instances. Provides configuration options
|
||||
such as width, height, i2c address, font, transitions, etc."""
|
||||
_rotation_mapper = {
|
||||
0: 0,
|
||||
90: 1,
|
||||
180: 2,
|
||||
270: 3
|
||||
}
|
||||
|
||||
_rotation_mapper = {0: 0, 90: 1, 180: 2, 270: 3}
|
||||
|
||||
def __init__(self):
|
||||
self.width = 128
|
||||
self.height = 64
|
||||
self.i2c_address = 0x3c
|
||||
self.i2c_address = 0x3C
|
||||
self.i2c_port = 1
|
||||
self.display_type = "ssd1306" # luma-oled supported devices, "sh1106", "ssd1306", ...
|
||||
self.font_path = 'resources/DejaVuSansMono-Bold.ttf'
|
||||
self.font_path = "resources/DejaVuSansMono-Bold.ttf"
|
||||
self.font_size = 12
|
||||
self.row_selection_pixel_extension = 2
|
||||
self.scroll_behavior = "page" # "extend" or "page"
|
||||
|
||||
@@ -5,14 +5,19 @@ from menu.menu_renderer import MenuRenderer
|
||||
|
||||
class MenuRendererLumaOled(MenuRenderer):
|
||||
"""Class implementing the luma oled menu renderer"""
|
||||
|
||||
def display_init(self):
|
||||
serial = i2c(port=self._config.i2c_port, address=self._config.i2c_address)
|
||||
import luma.oled.device
|
||||
|
||||
device = getattr(luma.oled.device, self._config.display_type)
|
||||
|
||||
self.disp = device(serial_interface=serial, width=self._config.width,
|
||||
height=self._config.height,
|
||||
rotate=self._config.get_mapped_rotation())
|
||||
self.disp = device(
|
||||
serial_interface=serial,
|
||||
width=self._config.width,
|
||||
height=self._config.height,
|
||||
rotate=self._config.get_mapped_rotation(),
|
||||
)
|
||||
|
||||
self.disp.clear()
|
||||
self.disp.show()
|
||||
|
||||
@@ -5,6 +5,7 @@ import time
|
||||
class Timer:
|
||||
"""Class implementing a timer class. Takes an activation delay and
|
||||
sets a flag if the activation delay exprires."""
|
||||
|
||||
def __init__(self, activation_delay):
|
||||
self.start_timestamp = int(time.time())
|
||||
self.activation_delay = activation_delay
|
||||
|
||||
@@ -17,6 +17,7 @@ class Transition:
|
||||
|
||||
class PushTransition(Transition):
|
||||
"""Class implementing a push left/right transition."""
|
||||
|
||||
PUSH_LEFT_TRANSITION = "push_left"
|
||||
PUSH_RIGHT_TRANSITION = "push_right"
|
||||
|
||||
@@ -32,7 +33,7 @@ class PushTransition(Transition):
|
||||
if transition_attributes is not None and transition_attributes != {}:
|
||||
direction = transition_attributes["direction"]
|
||||
|
||||
transition_image = Image.new('1', (self.disp.width, self.disp.height))
|
||||
transition_image = Image.new("1", (self.disp.width, self.disp.height))
|
||||
|
||||
if direction == PushTransition.PUSH_LEFT_TRANSITION:
|
||||
self.perform_push_left(end_image, start_image, transition_image)
|
||||
@@ -57,8 +58,8 @@ class PushTransition(Transition):
|
||||
"""Implements a push right transition. Is called by perform depending on the transition
|
||||
attribute 'direction'."""
|
||||
for x_pos in range(0, 128, self.transition_attributes["transition_speed"]):
|
||||
left_region = start_image.crop((0, 0, 128-x_pos, 64))
|
||||
right_region = end_image.crop((128-x_pos, 0, 128, 64))
|
||||
left_region = start_image.crop((0, 0, 128 - x_pos, 64))
|
||||
right_region = end_image.crop((128 - x_pos, 0, 128, 64))
|
||||
transition_image.paste(left_region, (x_pos, 0, 128, 64))
|
||||
transition_image.paste(right_region, (0, 0, x_pos, 64))
|
||||
self.disp.display(transition_image)
|
||||
|
||||
Reference in New Issue
Block a user