Skip to content

0.3 cleanup 3/4: Slider, TextInput, Dropdown and BarChart - #10

Merged
Times0 merged 2 commits into
masterfrom
cleanup/inputs
Oct 28, 2026
Merged

Times0 merged 2 commits into
masterfrom
cleanup/inputs

Conversation

@Times0

@Times0 Times0 commented Oct 28, 2026

Copy link
Copy Markdown
Owner

Stacked on #9.

Summary

Third of four stacked PRs for the 0.3.0 cleanup: the input widgets and the chart.

  • Slider(min, max, step=1, *, value=None, on_change=None, show_value=False, font=None, fill_color, track_color, knob_color, text_color)
    • value is a property. The setter clamps and snaps to step without float drift (0.1 * 3 is 0.3) and doesn't fire the callback. on_change(value) fires only when a drag, click or key changes the value.
    • draw(surface, x, y, width=200, height=6) draws a rounded track and fill. The knob grows on hover and while dragging.
    • Left/Right move one step and Home/End jump to the ends while the slider is hovered or dragged. Left from an off-grid max goes to the last grid value.
    • show_value formats with the decimals that min and step need (value_text): step 0.1 → 0.3, step 0.25 → 0.50, integer steps → 50. This replaces the str() check.
  • TextInput(text="", *, placeholder="", width=200, font=None, text_color, placeholder_color, background_color, border_color, focus_color, border_radius=4, on_change=None, on_submit=None)
    • The width is fixed; auto-grow is removed.
    • text (setter moves the caret to the end, no callback) and focused (was active) are settable. on_change(text) runs after each edit that changes the text. Enter calls on_submit(text) and keeps focus; Escape unfocuses.
    • Unicode TEXTINPUT, the custom key repeat, scrolling to the caret, and event priority 1 while focused are unchanged. The text is re-rendered at draw time, so changing colors or the placeholder applies immediately.
  • combobox.ComboBox → dropdown.Dropdown(options, *, index=0, on_change=None, width=None, font=None, color, text_color, highlight_color, outline_color, border_radius)
    • Rewritten as a standalone Widget (no Button inheritance). It draws its own box, a chevron drawn with pg.draw.lines, and a menu below with a small shadow. The hovered option uses highlight_color and the selected one a light shade. The combo_box_arrow.png asset is deleted; no packaging change is needed because uv_build ships the package directory.
    • value (str; settable to an existing option, otherwise ValueError) and index (settable, IndexError out of range) don't fire callbacks. on_change(value) runs when the user picks a different option.
    • While open: event priority 1. It consumes every mouse event over the box and menu (all buttons), and Up/Down + Enter/Space choose an option. Escape, window focus loss or a click elsewhere closes it; the outside click is not consumed, so it still reaches the widget under it.
  • Hover occlusion (PR 1 open question): Group.handle_event still stops dispatching at the first consumer. For MOUSEMOTION, it now also sets hovered = False on every widget after the consumer. Only an open dropdown consumes motion, and only while the pointer is over it. So widgets under the menu lose hover, and the cursor comes from the menu. This was the smallest correct option. The alternative was passing motion to every widget with an extra "occluded" flag, which would change every widget's handle_event.
  • BarChart(values, *, labels=None, max_value=None, colors=None, font=None, label_color="black", speed=200)
    • set_value(index, value) updates one bar. The values property returns a tuple. Its setter replaces all bars: new bars animate from 0, and automatic colors are regenerated when the count changes. Given colors are kept and cycle.
    • Bars are solid with rounded tops (no alpha fade). The arguments are validated: non-negative finite values, matching label count, non-empty colors, positive max_value/speed.
  • All constructors validate before Widget.__init__, so invalid widgets never join a group.
  • Exports, the demo (minimal adaptation; the showcase rewrite is next), the README widget list and the CHANGELOG (features plus upgrade notes for every rename/removal) are updated.

Breaking changes

See CHANGELOG.md, "Upgrading from 0.2". In short:

  • Slider: get_value()/current_value/change_value_to()/connect() → value / on_change.
  • TextInput: fixed_width → width, active → focused, get_text()/set_text() → text, font_color → text_color.
  • combobox.ComboBox → dropdown.Dropdown: elements → options, selected_index → index, add_action → on_change.
  • BarChart: change_value → set_value, labels_color → label_color, keyword-only options.

How tested

uv run ruff check . && uv run ruff format --check . && uv run pytest && uv run pygameuikit-demo --frames 5 passes (78 tests). New and updated tests cover:

  • callbacks firing only on interaction, never from setters, for all four widgets
  • slider range and clamping, keys while hovered, knob growth, decimal formatting and float drift
  • text input Enter/Escape, on_change on edits, Unicode, key repeat and scrolling
  • dropdown mouse selection, unmatched release, outside click, Escape, focus loss, keyboard navigation, consuming clicks over widgets underneath, and hover/cursor occlusion
  • the chart values setter (colors, animation from 0, custom colors kept), speed, and validation before joining a group

I also rendered the slider (normal, hover with show_value, step 0.1), the text input (placeholder, focused with text, hovered), the dropdown (closed, open with hover over another widget, dark variant) and the bar chart headlessly and inspected the image. I simulated a demo flow too: selecting a dropdown option fills the text input, and the slider shuffles the chart.

Slider takes (min, max, step=1, *, value, on_change, show_value, font,
colors), exposes a clamped, snapped value property and calls
on_change(value) only when interaction changes the value. The knob grows
on hover and drag, Left/Right/Home/End adjust it while hovered, and the
shown value uses the decimals that min and step need.

TextInput takes (text="", *, placeholder, width=200, font, colors,
border_radius, on_change, on_submit). It has a fixed width, a settable
text property and focused flag, calls on_change(text) after each edit,
submits on Enter and unfocuses on Escape.

combobox.ComboBox becomes dropdown.Dropdown, a standalone widget with
value and index properties, on_change(value) on user selection, keyboard
navigation, a drawn chevron instead of the arrow asset, and a menu that
consumes pointer events while open. Group marks widgets after a consumed
MOUSEMOTION as not hovered, so nothing under an open menu stays hovered.

BarChart takes keyword-only options plus colors and speed, has a values
property whose setter replaces all bars, and set_value(index, value).
@Times0
Times0 changed the base branch from cleanup/buttons to master October 28, 2026 10:23
@Times0
Times0 merged commit 3539a78 into master Oct 28, 2026
9 checks passed
@Times0
Times0 deleted the cleanup/inputs branch October 28, 2026 10:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant