Jelajahi Sumber

re-add fg color support + working autostart

Noah Vogt 2 bulan lalu
induk
melakukan
06772e5cde
5 mengubah file dengan 129 tambahan dan 59 penghapusan
  1. 29 15
      VulcanBoard.py
  2. 2 1
      config/__init__.py
  3. 21 0
      config/const.py
  4. 34 43
      config/load.py
  5. 43 0
      config/state.py

+ 29 - 15
VulcanBoard.py

@@ -36,6 +36,12 @@ from config import (
     Config,
     get_state_from_id,
     get_state_id_from_exit_code,
+    contains_id,
+    DEFAULT_BUTTON_BG_COLOR,
+    DEFAULT_BUTTON_FG_COLOR,
+    EMPTY_BUTTON_BG_COLOR,
+    DEFAULT_STATE_ID,
+    ERROR_SINK_STATE_ID,
 )
 from ui import AutoResizeButton
 
@@ -73,26 +79,29 @@ class VulcanBoardApp(App):
                     defined_button = button_map.get((row, col))
                     if defined_button:
                         states = defined_button.get("states", [])
-                        print("STATES")
-                        print(states)
-                        state_id = [0]
+                        state_id = [DEFAULT_STATE_ID]
                         state = get_state_from_id(states, state_id[0])
-                        print("STATE")
-                        print(state)
 
                         btn = AutoResizeButton(
                             text=state.get("txt", ""),
                             background_color=get_color_from_hex(
-                                state.get("bg_color", "aaaaff")
+                                state.get("bg_color", DEFAULT_BUTTON_BG_COLOR)
                             ),
                             color=get_color_from_hex(
-                                state.get("fg_color", "ffffff")
+                                state.get("fg_color", DEFAULT_BUTTON_FG_COLOR)
                             ),
                             halign="center",
                             valign="middle",
                             background_normal="",
                         )
 
+                        if defined_button.get("autostart", False):
+                            self.async_task(
+                                self.execute_command_async(
+                                    states, state_id, btn
+                                )
+                            )
+
                         # pylint: disable=no-member
                         btn.bind(  # pyright: ignore
                             on_release=lambda btn_instance, states=states, state_id=state_id: self.async_task(
@@ -101,9 +110,12 @@ class VulcanBoardApp(App):
                                 )
                             )
                         )
+
                     else:
                         btn = AutoResizeButton(
-                            background_color=get_color_from_hex("cccccc"),
+                            background_color=get_color_from_hex(
+                                EMPTY_BUTTON_BG_COLOR
+                            ),
                         )
                     layout.add_widget(btn)
 
@@ -136,13 +148,15 @@ class VulcanBoardApp(App):
         try:
             print(states[new_state_id]["cmd"])
             process = await asyncio.create_subprocess_shell(
-                states[new_state_id]["cmd"], shell=True
+                get_state_from_id(states, new_state_id)["cmd"], shell=True
             )
             exit_code = await process.wait()
             print(f"EXIT {exit_code}")
-            log(f"Executed command: {states[new_state_id]['cmd']}")
+            log(
+                f"Executed command: {get_state_from_id(states, new_state_id)['cmd']}"
+            )
         except Exception as e:
-            exit_code = 1
+            exit_code = ERROR_SINK_STATE_ID
             log(f"Error executing command: {e}", color="yellow")
 
         if len(states) != 1:
@@ -163,11 +177,11 @@ class VulcanBoardApp(App):
 
         btn.text = state.get("txt", "")
         btn.background_color = get_color_from_hex(
-            state.get("bg_color", "cc0000")
+            state.get("bg_color", DEFAULT_BUTTON_BG_COLOR)
+        )
+        btn.color = get_color_from_hex(
+            state.get("fg_color", DEFAULT_BUTTON_FG_COLOR)
         )
-        # btn.foreground_color = get_color_from_hex(
-        #     state.get("bg_color", "cc0000")
-        #         )
 
 
 def start_asyncio_loop():

+ 2 - 1
config/__init__.py

@@ -16,4 +16,5 @@
 from .path import get_config_path
 from .classes import Config
 from .load import ConfigLoader
-from .load import get_state_from_id, get_state_id_from_exit_code
+from .state import get_state_from_id, get_state_id_from_exit_code, contains_id
+from .const import *

+ 21 - 0
config/const.py

@@ -0,0 +1,21 @@
+# Copyright © 2025 Noah Vogt <noah@noahvogt.com>
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+DEFAULT_BUTTON_BG_COLOR = "aaaaff"
+DEFAULT_BUTTON_FG_COLOR = "ffffff"
+EMPTY_BUTTON_BG_COLOR = "cccccc"
+
+DEFAULT_STATE_ID = 0
+ERROR_SINK_STATE_ID = 1

+ 34 - 43
config/load.py

@@ -21,29 +21,11 @@ from util import CustomException
 
 from .classes import Config
 from .validate import is_valid_hexcolor
-
-
-def get_state_from_id(states: list, state_id: int) -> dict:
-    for state in states:
-        possible_id = state.get("id", None)
-        if isinstance(possible_id, int):
-            if possible_id == state_id:
-                return state
-
-    return {}
-
-
-def get_state_id_from_exit_code(states: list, exit_code: int) -> int:
-    found_state_id = False
-    for found_states in states:
-        if found_states["id"] == exit_code:
-            found_state_id = True
-            break
-
-    if not found_state_id:
-        exit_code = 1
-
-    return exit_code
+from .const import (
+    DEFAULT_BUTTON_BG_COLOR,
+    DEFAULT_BUTTON_FG_COLOR,
+    DEFAULT_STATE_ID,
+)
 
 
 @dataclass
@@ -122,6 +104,11 @@ class ConfigLoader:
                     f"invalid {btn_dims} 'states' subentry: list cannot be empty"
                 )
 
+            if not isinstance(button.get("autostart", False), bool):
+                raise CustomException(
+                    f"invalid {btn_dims} 'autostart' entry: must be boolean"
+                )
+
             defined_state_ids = set()
             for state in states:
                 if not (
@@ -133,26 +120,30 @@ class ConfigLoader:
                     raise CustomException(
                         f"invalid {btn_dims}: invalid state detected"
                     )
-                defined_state_ids.add(state.get("id", None))
-
-                if not isinstance(
-                    bg_color := state.get("bg_color", "cccccc"), str
-                ) or not is_valid_hexcolor(bg_color):
-                    raise CustomException(
-                        f"invalid {btn_dims} 'bg_color' subentry: '{bg_color}'"
-                    )
-
-                if not isinstance(
-                    fg_color := state.get("fg_color", "ffffff"), str
-                ) or not is_valid_hexcolor(fg_color):
-                    raise CustomException(
-                        f"invalid {btn_dims} 'fg_color' subentry: '{fg_color}'"
-                    )
-
-            print(defined_state_ids)
-            # TODO: add const or rethink needed state id's
-            if not 0 in defined_state_ids:
-                raise CustomException(f"invalid {btn_dims}: missing state id 0")
+                state_id = state.get("id", None)
+                if isinstance(state_id, int):
+                    if state_id in defined_state_ids:
+                        raise CustomException(
+                            f"invalid {btn_dims}: tried to define state {state_id} twice"
+                        )
+                    defined_state_ids.add(state_id)
+
+                for color_pair in ("bg_color", DEFAULT_BUTTON_BG_COLOR), (
+                    "fg_color",
+                    DEFAULT_BUTTON_FG_COLOR,
+                ):
+                    if not isinstance(
+                        color := state.get(color_pair[0], color_pair[1]),
+                        str,
+                    ) or not is_valid_hexcolor(color):
+                        raise CustomException(
+                            f"invalid {btn_dims} '{color_pair[0]}' subentry: '{color}'"
+                        )
+
+            if not DEFAULT_STATE_ID in defined_state_ids:
+                raise CustomException(
+                    f"invalid {btn_dims}: missing default state id '{DEFAULT_STATE_ID}'"
+                )
 
     def __validate_dimensions(self) -> None:
         for dimension in (self.columns, self.rows):

+ 43 - 0
config/state.py

@@ -0,0 +1,43 @@
+# Copyright © 2025 Noah Vogt <noah@noahvogt.com>
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+from .const import ERROR_SINK_STATE_ID
+
+
+def get_state_from_id(states: list, state_id: int) -> dict:
+    for state in states:
+        possible_id = state.get("id", None)
+        if isinstance(possible_id, int):
+            if possible_id == state_id:
+                return state
+
+    return {}
+
+
+def contains_id(states: list, state_id: int) -> bool:
+    found_id = False
+    for found_states in states:
+        if found_states["id"] == state_id:
+            found_id = True
+            break
+
+    return found_id
+
+
+def get_state_id_from_exit_code(states: list, exit_code: int) -> int:
+    if not contains_id(states, exit_code):
+        exit_code = ERROR_SINK_STATE_ID
+
+    return exit_code