Forráskód Böngészése

add config + widget

Noah Vogt 5 hónapja
szülő
commit
e6579ecdf9
2 módosított fájl, 329 hozzáadás és 0 törlés
  1. 240 0
      ConfigEditorApp.py
  2. 89 0
      widget.py

+ 240 - 0
ConfigEditorApp.py

@@ -0,0 +1,240 @@
+import yaml
+from os import path, getenv, name
+from kivy.app import App
+from kivy.uix.gridlayout import GridLayout
+from kivy.uix.button import Button
+from kivy.uix.boxlayout import BoxLayout
+from kivy.uix.textinput import TextInput
+from kivy.uix.label import Label
+from kivy.uix.popup import Popup
+from kivy.uix.filechooser import FileChooserIconView
+from kivy.core.window import Window
+from kivy.uix.widget import Widget
+from kivy.properties import ObjectProperty, ListProperty
+
+
+class DraggableButton(Button):
+    """A button that can be dragged."""
+
+    original_pos = ListProperty([0, 0])
+
+    def __init__(self, **kwargs):
+        super().__init__(**kwargs)
+        self.dragged = False
+
+    def on_touch_down(self, touch):
+        if self.collide_point(*touch.pos):
+            self.dragged = True
+            self.original_pos = self.pos
+            return True
+        return super().on_touch_down(touch)
+
+    def on_touch_move(self, touch):
+        if self.dragged:
+            self.center = touch.pos
+            return True
+        return super().on_touch_move(touch)
+
+    def on_touch_up(self, touch):
+        if self.dragged:
+            self.dragged = False
+            self.parent.handle_drop(self, touch)
+            return True
+        return super().on_touch_up(touch)
+
+
+class DraggableGridLayout(GridLayout):
+    """A grid layout that supports drag-and-drop."""
+
+    def __init__(self, app, **kwargs):
+        super().__init__(**kwargs)
+        self.app = app  # Reference to the main app
+
+    def handle_drop(self, dragged_button, touch):
+        """Handle the drop of a button."""
+        for child in self.children:
+            if child.collide_point(*touch.pos) and child != dragged_button:
+                # Swap buttons
+                dragged_index = self.children.index(dragged_button)
+                target_index = self.children.index(child)
+                self.children[dragged_index], self.children[target_index] = (
+                    self.children[target_index],
+                    self.children[dragged_index],
+                )
+
+                # Update the config
+                self.app.swap_button_positions(dragged_index, target_index)
+                break
+
+        # Reset position of dragged button
+        dragged_button.pos = dragged_button.original_pos
+
+
+class ConfigEditorApp(App):
+    def __init__(self, **kwargs):
+        super().__init__(**kwargs)
+        self.config_data = {}
+        self.current_file = None
+        self.selected_button = None
+
+    def load_config_file(self, file_path):
+        """Load the configuration file."""
+        try:
+            with open(file_path, "r", encoding="utf-8") as f:
+                self.config_data = yaml.safe_load(f)
+                self.current_file = file_path
+                return True
+        except Exception as e:
+            self.show_popup("Error", f"Failed to load config: {e}")
+            return False
+
+    def save_config(self):
+        """Save the updated configuration file."""
+        if self.current_file:
+            try:
+                with open(self.current_file, "w", encoding="utf-8") as f:
+                    yaml.dump(self.config_data, f)
+                self.show_popup("Success", "Configuration saved successfully!")
+            except Exception as e:
+                self.show_popup("Error", f"Failed to save config: {e}")
+        else:
+            self.show_popup("Error", "No file loaded to save.")
+
+    def show_popup(self, title, message):
+        """Display a popup message."""
+        popup_layout = BoxLayout(orientation="vertical", padding=10, spacing=10)
+        popup_label = Label(text=message)
+        popup_close = Button(text="Close", size_hint=(1, 0.3))
+        popup_layout.add_widget(popup_label)
+        popup_layout.add_widget(popup_close)
+
+        popup = Popup(title=title, content=popup_layout, size_hint=(0.5, 0.5))
+        popup_close.bind(on_release=popup.dismiss)
+        popup.open()
+
+    def build(self):
+        """Build the main UI."""
+        root_layout = BoxLayout(orientation="vertical", spacing=10, padding=10)
+
+        # Top: File Controls
+        file_controls = BoxLayout(size_hint_y=0.1, spacing=10)
+        load_button = Button(text="Load Config", size_hint_x=0.3)
+        save_button = Button(text="Save Config", size_hint_x=0.3)
+        file_controls.add_widget(load_button)
+        file_controls.add_widget(save_button)
+        root_layout.add_widget(file_controls)
+
+        # Middle: Grid Layout for Buttons
+        self.grid = DraggableGridLayout(cols=4, spacing=5, padding=5, app=self)
+        root_layout.add_widget(self.grid)
+
+        # Bottom: Property Editor
+        self.property_editor = BoxLayout(size_hint_y=0.2, spacing=10, padding=5)
+        self.property_editor.add_widget(Label(text="Text:"))
+        self.text_input = TextInput(hint_text="Button Text")
+        self.property_editor.add_widget(self.text_input)
+
+        self.property_editor.add_widget(Label(text="BG Color:"))
+        self.color_input = TextInput(hint_text="Hex Color (e.g., #FFFFFF)")
+        self.property_editor.add_widget(self.color_input)
+
+        save_changes_button = Button(text="Save Changes", size_hint_x=0.3)
+        self.property_editor.add_widget(save_changes_button)
+        root_layout.add_widget(self.property_editor)
+
+        # Bindings
+        load_button.bind(on_release=self.show_file_chooser)
+        save_button.bind(on_release=lambda _: self.save_config())
+        save_changes_button.bind(on_release=self.update_button_properties)
+
+        return root_layout
+
+    def show_file_chooser(self, instance):
+        """Open a file chooser to load a configuration file."""
+        chooser_layout = BoxLayout(
+            orientation="vertical", spacing=10, padding=10
+        )
+        file_chooser = FileChooserIconView(filters=["*.yml", "*.yaml"])
+        chooser_layout.add_widget(file_chooser)
+
+        chooser_buttons = BoxLayout(size_hint_y=0.2)
+        load_button = Button(text="Load")
+        cancel_button = Button(text="Cancel")
+        chooser_buttons.add_widget(load_button)
+        chooser_buttons.add_widget(cancel_button)
+        chooser_layout.add_widget(chooser_buttons)
+
+        popup = Popup(
+            title="Load Config File",
+            content=chooser_layout,
+            size_hint=(0.8, 0.8),
+        )
+        cancel_button.bind(on_release=popup.dismiss)
+        load_button.bind(
+            on_release=lambda _: self.load_config_and_refresh(
+                file_chooser.selection[0], popup
+            )
+        )
+        popup.open()
+
+    def load_config_and_refresh(self, file_path, popup):
+        """Load the configuration and refresh the UI."""
+        if self.load_config_file(file_path):
+            self.refresh_buttons()
+        popup.dismiss()
+
+    def refresh_buttons(self):
+        """Refresh the grid with buttons from the configuration."""
+        self.grid.clear_widgets()
+        if not self.config_data.get("buttons"):
+            return
+
+        for button_data in self.config_data["buttons"]:
+            btn = DraggableButton(
+                text=button_data.get("txt", ""),
+                background_color=self.hex_to_rgba(
+                    button_data.get("bg_color", "#cccccc")
+                ),
+            )
+            btn.bind(
+                on_release=lambda instance, data=button_data: self.select_button(
+                    instance, data
+                )
+            )
+            self.grid.add_widget(btn)
+
+    def select_button(self, button, data):
+        """Select a button to edit its properties."""
+        self.selected_button = data
+        self.text_input.text = data.get("txt", "")
+        self.color_input.text = data.get("bg_color", "#cccccc")
+
+    def update_button_properties(self, instance):
+        """Update the selected button's properties."""
+        if not self.selected_button:
+            self.show_popup("Error", "No button selected!")
+            return
+
+        self.selected_button["txt"] = self.text_input.text
+        self.selected_button["bg_color"] = self.color_input.text
+        self.refresh_buttons()
+
+    def swap_button_positions(self, index1, index2):
+        """Swap button positions in the configuration."""
+        (
+            self.config_data["buttons"][index1],
+            self.config_data["buttons"][index2],
+        ) = (
+            self.config_data["buttons"][index2],
+            self.config_data["buttons"][index1],
+        )
+
+    @staticmethod
+    def hex_to_rgba(hex_color):
+        """Convert hex color to RGBA."""
+        hex_color = hex_color.lstrip("#")
+        return [int(hex_color[i : i + 2], 16) / 255 for i in (0, 2, 4)] + [1]
+
+
+if __name__ == "__main__":
+    ConfigEditorApp().run()

+ 89 - 0
widget.py

@@ -0,0 +1,89 @@
+# Kivy example for the Popup widget
+
+# Program to Show how to create a switch
+# import kivy module
+import kivy
+
+# base Class of your App inherits from the App class.
+# app:always refers to the instance of your application
+from kivy.app import App
+
+# this restrict the kivy version i.e
+# below this kivy version you cannot
+# use the app or software
+kivy.require("1.9.0")
+
+# The Button is a Label with associated actions
+# that is triggered when the button
+# is pressed (or released after a click/touch).
+from kivy.uix.button import Button
+
+
+# The GridLayout arranges children in a matrix.
+# It takes the available space and
+# divides it into columns and rows,
+# then adds widgets to the resulting “cells”.
+from kivy.uix.gridlayout import GridLayout
+
+# Popup widget is used to create popups.
+# By default, the popup will cover
+# the whole “parent” window.
+# When you are creating a popup,
+# you must at least set a Popup.title and Popup.content.
+from kivy.uix.popup import Popup
+
+# The Label widget is for rendering text.
+from kivy.uix.label import Label
+
+# to change the kivy default settings we use this module config
+from kivy.config import Config
+
+# 0 being off 1 being on as in true / false
+# you can use 0 or 1 && True or False
+Config.set("graphics", "resizable", True)
+
+
+# Make an app by deriving from the kivy provided app class
+class PopupExample(App):
+    # override the build method and return the root widget of this App
+
+    def build(self):
+        # Define a grid layout for this App
+        self.layout = GridLayout(cols=1, padding=10)
+
+        # Add a button
+        self.button = Button(text="Click for pop-up")
+        self.layout.add_widget(self.button)
+
+        # Attach a callback for the button press event
+        self.button.bind(on_press=self.onButtonPress)
+
+        return self.layout
+
+    # On button press - Create a popup dialog with a label and a close button
+    def onButtonPress(self, button):
+
+        layout = GridLayout(cols=1, padding=10)
+
+        popupLabel = Label(text="Click for pop-up")
+        closeButton = Button(text="Close the pop-up")
+
+        layout.add_widget(popupLabel)
+        layout.add_widget(closeButton)
+
+        # Instantiate the modal popup and display
+        popup = Popup(
+            title="Demo Popup",
+            content=layout,
+            size_hint=(None, None),
+            size=(200, 200),
+        )
+        popup.open()
+
+        # Attach close button press with popup.dismiss action
+        closeButton.bind(on_press=popup.dismiss)
+
+
+# Run the app
+if __name__ == "__main__":
+    PopupExample().run()