Skip to content

0.3 cleanup 2/4: Button, ImageButton, IconButton, IconToggle and Label - #9

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

Times0 merged 2 commits into
masterfrom
cleanup/buttons

Conversation

@Times0

@Times0 Times0 commented Oct 28, 2026

Copy link
Copy Markdown
Owner

Stacked on #8.

Summary

Second of four stacked PRs for the 0.3.0 cleanup: buttons and label.

  • button.py now has four classes on one small private base, _Clickable(Widget): a click is a left press and a release both inside the button, window focus loss cancels it, handle_event returns True when consumed, and the cursor is the hand. pressed replaces clicked, and the on_click attribute replaces onclick_f/connect().
    • Button(text, on_click=None, *, color, text_color=None, border_radius=6, outline_color=None, padding=(16, 8), font=None, width=None, align="center"): draws a rounded rect directly with pg.draw.rect. The hover and pressed shades come from color via utils.shade. Text is black or white via utils.best_contrast_color unless text_color is set. It sizes itself to its Label unless width is given. text is a settable property that resizes the button.
    • ImageButton(image, on_click=None, *, hover_image=None, text="", text_color="white", font=None): merges ButtonImage and ButtonImageText. Text is centered.
    • IconButton(image, on_click=None, *, hover_color, hover_alpha=128, padding=6, border_radius=6): replaces ButtonPngIcon. It shows a translucent backdrop on hover, stronger while pressed. The clickable area is the icon plus padding, starting at (x, y).
    • IconToggle(image_off, image_on, on_change=None, *, value=False, ...): replaces ButtonTwoStates. on_change(value: bool) gets the new value; setting value doesn't fire it.
    • Removed: ButtonRect, ButtonText, ButtonImage, ButtonImageText, ButtonPngIcon, ButtonTwoStates, ButtonThreadImage, ButtonThreadText.
  • Label(text, color="white", *, font=None, align="left") draws exactly at (x, y) with no hidden 10 px offset. draw(surface, x, y, width=None) aligns within width. Setting text/color re-renders only on change. TextAlignment and bounding_rect are removed, and align is validated.
  • Constructors validate their arguments before Widget.__init__, so a bad widget never joins a group.
  • utils: new shade(color, amount). best_contrast_color now uses perceived brightness and returns a pg.Color. make_surface_darker is removed because nothing uses it anymore.
  • ComboBox now subclasses Button. The changes are minimal; it gets rewritten as Dropdown in the next PR.
  • Exports, demo (minimal: IconToggle/IconButton plus one Button), README snippet and widget list, and CHANGELOG upgrade notes are updated.

Breaking changes

Everything is in CHANGELOG.md under "Upgrading from 0.2", with an old → new mapping for every removed button class. For the ButtonThread* classes, the replacement is to set button.text from your own state each frame. Labels lose their implicit 10 px padding, and IconButton draws the icon at (x + padding, y + padding).

How tested

uv run ruff check . && uv run ruff format --check . && uv run pytest && uv run pygameuikit-demo --frames 5 passes (58 tests). The old button/label tests are replaced with tests for:

  • click semantics (inside/outside release, focus loss, consumption, reassigning on_click) across all four classes
  • IconToggle on_change(value) and silent programmatic value
  • auto sizing and Button.text resizing, fixed width
  • auto text contrast and the normal > hover > pressed shading
  • validation before joining a group
  • IconButton padding area
  • Label position, alignment math and re-render-on-change

I also rendered the button states, outlines, alignments, icon hover/pressed, toggle on/off and Label alignments headlessly and inspected the image.

A shared _Clickable base handles press-and-release-inside clicks, focus
loss, the hand cursor and the consumed-event return value. Button draws
a rounded rect with hover/pressed shades derived from its color, sizes
itself to a Label (or a fixed width with align) and has a settable text
property. ImageButton merges ButtonImage and ButtonImageText, IconButton
replaces ButtonPngIcon and IconToggle replaces ButtonTwoStates with
on_change(value). ButtonRect and the ButtonThread* classes are removed.

Label now takes (text, color="white", *, font, align), draws exactly at
(x, y) and aligns within an optional draw width; TextAlignment and
bounding_rect are gone. Constructors validate before joining a group.
ComboBox subclasses Button with minimal changes until it is rewritten.
@Times0
Times0 changed the base branch from cleanup/core to master October 28, 2026 10:23
@Times0
Times0 merged commit bf4e2cd into master Oct 28, 2026
9 checks passed
@Times0
Times0 deleted the cleanup/buttons 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