agentleFS
ceccopierangiolieugenioceccopierangiolieugenio/pyTermTk/.github/skills/widget-creation/SKILL.md

widget-creation

Skill921 starsChanged 4 months agoMITView on GitHub

Use when: creating new TTkWidget subclasses with proper structure, signals, slots, and documentation

The file

We split this skill into the rules it gives an agent

4 rules. About 0 are common, 0 are distinctive, and 4 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈0

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 4

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Add to demo/showcase/ or tutorial/examples/ if creating showcase:

    line 185
  2. Very specific:

    Keep signal entries in __slots__ and type-annotate them there

    line 219
  3. Very specific:

    All non-signal slot names must start with _.

    line 238
  4. Very specific:

    Add a class-level type annotation for each slot entry immediately below __slots__.

    line 240

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Widget Creation Skill

Overview

This skill scaffolds new pyTermTk widgets following project patterns:

  • Proper class structure with __slots__
  • Signal definitions with type hints
  • Event handlers with correct return semantics
  • Sphinx documentation with ASCII art
  • Test file structure
  • Example/demo integration

When to Use

  • Building new interactive widgets (button, input, selector variants)
  • Creating container widgets (custom layouts, panels)
  • Adding display widgets (custom text renderers, charts)

File Structure

1. Widget File

Location: libs/pyTermTk/TermTk/TTkWidgets/ttk_<widget_name>.py

Template:

"""
Module: TTkMyWidget
Implements a custom widget for [purpose]
"""

from TermTk import TTkWidget, TTkColor, pyTTkSignal, pyTTkSlot

class TTkMyWidget(TTkWidget):
    '''TTkMyWidget: [One-line description]

    [Longer description of purpose and behavior]

    (`demo <https://ceccopierangiolieugenio.github.io/pyTermTk-Docs/sandbox/...>`__)

    ::

        [ASCII art showing visual representation]
        [Multiple lines if needed]

    .. code:: python

        import TermTk as ttk

        root = ttk.TTk()
        widget = ttk.TTkMyWidget(parent=root)
        root.mainloop()
    '''

    # Performance: always use __slots__
    __slots__ = (
        '_privateVar',
        '_anotherVar',
        'stateChanged',
    )

    _privateVar: int
    _anotherVar: int
    stateChanged: pyTTkSignal
    '''
    Emitted when widget state changes.

    :param value: new state value
    :type value: [type]
    '''

    # Class-level styling
    classStyle = {
        'default':  {'color': TTkColor.fg("#dddd88"), 'borderColor': TTkColor.RST},
        'hover':    {'color': TTkColor.fg("#ffffff"), 'borderColor': TTkColor.BOLD},
        'focus':    {'borderColor': TTkColor.fg("#ffff00")},
        'disabled': {'color': TTkColor.fg('#888888')}
    }

    def __init__(self, **kwargs):
        '''Initialize the widget.

        :param parent: parent widget
        :type parent: TTkWidget
        [Other parameters as needed]
        '''
        # Instantiate signals in __init__ (do not instantiate at class level)
        self.stateChanged = pyTTkSignal(int)

        # Initialize private variables
        self._privateVar = 0  # Replace with appropriate default for your widget

        # Call parent with merged kwargs and default size
        super().__init__(**kwargs|{'size': (10, 3)})  # Replace with appropriate default dimensions

    # Property getters/setters
    def getValue(self) -> int:
        '''Get the current value.

        :return: current value
        :rtype: int
        '''
        return self._privateVar

    def setValue(self, value: int) -> None:
        '''Set the value.

        :param value: new value
        :type value: int
        '''
        if self._privateVar != value:
            self._privateVar = value
            self.stateChanged.emit(value)
            self.update()

    # Return True when this widget fully processes the event; otherwise return False to let parent widgets handle it.
    def keyEvent(self, evt) -> bool:
        '''Handle keyboard events.'''
        if evt.key == 'Enter':
            self.stateChanged.emit(self._privateVar)
            return True
        return False

    def mousePressEvent(self, evt) -> bool:
        '''Handle mouse press events.'''
        # Handle click, return True if consumed
        return False

    def paintEvent(self) -> None:
        '''Render the widget.'''
        # Use currentStyle() for theme-aware colors
        canvas = self.canvas
        style = self.currentStyle()

        # Draw widget content
        canvas.drawText(pos=(0, 0), text="MyWidget")

__all__ = ['TTkMyWidget']

2. Test File

Location: tests/pytest/widgets/<widget_name>/test_<widget_name>.py

Template:

import pytest
from TermTk import TTkMyWidget

class TestTTkMyWidget:
    '''Test suite for TTkMyWidget'''

    def test_initialization(self):
        """Widget initializes with defaults"""
        widget = TTkMyWidget()
        assert widget.getValue() == 0  # Or expected default

    def test_signal_emission(self):
        """Signal emits when state changes"""
        widget = TTkMyWidget()
        emitted = []
        widget.stateChanged.connect(lambda val: emitted.append(val))

        widget.setValue(42)
        assert emitted == [42]

    def test_key_event_handling(self):
        """Key events handled correctly"""
        widget = TTkMyWidget()
        from TermTk import TTkKeyEvent

        evt = TTkKeyEvent(key='Enter')
        result = widget.keyEvent(evt)
        assert result == True  # Event was handled

    def test_disabled_state(self):
        """Widget respects disabled state"""
        widget = TTkMyWidget()
        widget.setDisabled(True)
        # Verify widget doesn't respond to events, etc.

3. Example/Demo

Add to demo/showcase/ or tutorial/examples/ if creating showcase:

"""
Example: TTkMyWidget

Demonstrates the TTkMyWidget in action.
"""

import TermTk as ttk

def main():
    root = ttk.TTk()

    # Create and configure widget
    widget = ttk.TTkMyWidget(parent=root)
    widget.setValue(10)

    # Connect signal
    @ttk.pyTTkSlot(int)
    def on_state_changed(value):
        print(f"State changed to: {value}")

    widget.stateChanged.connect(on_state_changed)

    root.mainloop()

if __name__ == '__main__':
    main()

Key Patterns to Follow

Signals

  • Keep signal entries in __slots__ and type-annotate them there
  • Instantiate signals in __init__ with specific type: pyTTkSignal(int) not pyTTkSignal()
  • Emit with actual value: self.stateChanged.emit(value)

slots

__slots__ = (
    '_variable1',
    '_variable2',
    'valueChanged',
    # Always use slots for memory efficiency
)

_variable1: int
_variable2: int
valueChanged: pyTTkSignal

Rules:

  • All non-signal slot names must start with _.
  • Public (non-underscore) slot names are allowed only for exposed signals.
  • Add a class-level type annotation for each slot entry immediately below __slots__.

Class Styling

classStyle = {
    'default':  {...},
    'hover':    {...},
    'focus':    {...},
    'disabled': {...}
}

Event Return Values

  • Return True if event fully handled (don't propagate)
  • Return False to let event propagate up widget tree

Documentation

  • ASCII art for visual widgets
  • Demo/sandbox links
  • Runnable code examples
  • Sphinx cross-references: :py:class:, :py:meth:

Checklist

File and Class Structure

  • File location: libs/pyTermTk/TermTk/TTkWidgets/ttk_*.py
  • Inherits from TTkWidget or TTkContainer
  • __slots__ defined
  • Non-signal slot names use leading _
  • Public slot names are signals only
  • Every slot entry has a class-level type annotation
  • __all__ export defined
  • Register the widget export in libs/pyTermTk/TermTk/TTkWidgets/__init__.py with from .ttk_<widget_name> import TTkMyWidget

Signals and Events

  • Signals with type hints
  • Signals initialized in __init__
  • Event methods return bool

Documentation and Examples

  • Sphinx docstring with ASCII art
  • Example added to demo or tutorial

Testing and Quality

  • Test file created
  • Tests cover initialization, signals, events, edge cases
  • Flake8 passes

Common Mistakes to Avoid

  • ❌ Signals instantiated at class level instead of __init__
  • ❌ Event handlers don't return bool (should always return True/False)
  • ❌ Missing __slots__ (memory waste)
  • ❌ Hardcoded colors instead of using theme via currentStyle()
  • ❌ Tests that only check implementation, not behavior
  • ❌ No documentation or examples

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.