-
-
Notifications
You must be signed in to change notification settings - Fork 21
Advanced documentation
Fancygotchi exposes a powerful mechanism for other plugins to dynamically interact with and modify the user interface. This is primarily achieved through two attributes injected into the ui object:
-
ui._update: A dictionary that acts as a command queue to request UI changes. -
ui.fancy._state: A read-only dictionary that provides the current state of all theme widgets managed by Fancygotchi.
Let's explore how to use these, using the fancyshow.py plugin as a guide.
To request a change to a widget's properties (like its position, color, or font), you need to populate the ui._update dictionary with specific keys. Fancygotchi checks this dictionary on every on_ui_update cycle and applies the requested changes.
The structure of the ui._update dictionary for a partial update is as follows:
ui._update.update({
'update': True, # Required: Signals that an update is pending.
'partial': True, # Required: Specifies that this is a partial theme update, not a full reload.
'dict_part': { # A dictionary containing the changes.
'widget': {
'name_of_widget': {
'property_to_change': new_value,
'another_property': another_value
}
}
}
})Example from fancyshow.py:
The fancyshow plugin dynamically changes the position and color of the name widget.
# From fancyshow.py
# The new widget properties we want to apply.
self.widget_options = {
'position': ["center", "center"],
'color': ["lime", "red"]
}
# ... inside on_ui_update(self, ui) ...
# Request a partial theme update to change the 'name' widget.
ui._update.update({
'update': True,
'partial': True,
'dict_part': {'widget': {'name': self.widget_options}}
})
self.position_set = True
logging.info(f"fancyshow: setting 'name' options to {self.widget_options}")In this snippet:
-
'update': Truetells Fancygotchi to process an update. -
'partial': Trueensures that only the specified properties are changed, leaving the rest of the theme intact. -
'dict_part'contains the payload. It specifies that for the'widget'named'name', its properties should be updated according to theself.widget_optionsdictionary.
After Fancygotchi processes this update, it will automatically reset ui._update['update'] to False. Your plugin should check this flag to avoid sending redundant update requests on every cycle.
To make intelligent changes, your plugin needs to know the current state of the UI. Fancygotchi provides a read-only snapshot of its internal theme configuration via ui.fancy._state.
This is crucial for:
- Getting Initial Values: Before modifying a widget, you should store its original properties to revert them later (e.g., when your plugin is unloaded).
-
Verifying Changes: After requesting an update, you can check
ui.fancy._stateon subsequent cycles to confirm that your changes have been applied. - Adapting to Other Changes: If another plugin or a theme reload changes the UI, your plugin can detect this by comparing the current state with its expected state.
The ui.fancy._state is a dictionary where keys are widget names, and values are dictionaries of their properties.
Example from fancyshow.py:
-
Getting the original properties: The
_get_initial_optionshelper function reads the initial state of the properties it intends to modify.# From fancyshow.py def _get_initial_options(self, ui): # `ui.fancy._state` is a special attribute injected by Fancygotchi if hasattr(ui, 'fancy') and hasattr(ui.fancy, '_state') and 'name' in ui.fancy._state: name_state = ui.fancy._state['name'] new_original_options = {} # We only care about the properties we intend to modify. for prop in self.widget_options.keys(): if prop in name_state: current_original_value = name_state.get(prop) new_original_options[prop] = current_original_value if not self.original_widget_options: self.original_widget_options = new_original_options logging.info(f"fancyshow: Stored initial 'name' options: {self.original_widget_options}")
-
Verifying changes have been applied: After setting the new position, the plugin continuously verifies that the
namewidget's properties match what it expects.# From fancyshow.py if self.position_set and hasattr(ui, 'fancy') and hasattr(ui.fancy, '_state') and 'name' in ui.fancy._state: name_state = ui.fancy._state['name'] for prop, expected_value in self.widget_options.items(): current_value = name_state.get(prop) # Normalize for comparison if isinstance(expected_value, list): expected_value = tuple(expected_value) if isinstance(current_value, list): current_value = tuple(current_value) if current_value != expected_value: # Handle the discrepancy...
-
Reverting changes on unload: The
on_unloadmethod uses the storedself.original_widget_optionsto request another partial update, reverting the widget to its original state.# From fancyshow.py def on_unload(self, ui): logging.info("fancyshow plugin unloading...") self.reverting = True if self.original_widget_options and hasattr(ui, '_update'): # Use Fancygotchi's partial update mechanism to revert the 'name' widget. ui._update.update({ 'update': True, 'partial': True, 'dict_part': {'widget': {'name': self.original_widget_options}} }) logging.info(f"fancyshow: attempting to revert 'name' options to {self.original_widget_options}") # ... includes logic to wait and verify the reversion.
By using ui._update to write changes and ui.fancy._state to read them, you can create robust plugins that interact cleanly and predictably with the Fancygotchi theme engine.