Last active
August 30, 2024 14:13
-
-
Save oeloeloel/9689594b5451780ccd37f8ce65f4c788 to your computer and use it in GitHub Desktop.
DragonRuby Button Experiment (low responsibility three-state button)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # A small POC experiment with buttons (it doesn't attempt to solve all the problems) | |
| # the button method implements behaviour for a three-state button | |
| # it accounts for button "layers" that can be formed from multiple primitives | |
| # it doesn't impose other constraints on the dev, so the dev is free to make | |
| # the buttons any way they like. This code shows: | |
| # • A button made from a basic rect and label (with a bonus arbitrary rect for the active state) | |
| # • A resizable button with rounded ends and a 2 pixel outline (1 label, 6 sprites) | |
| def tick args | |
| args.outputs.background_color = {r: 88, g: 124, b: 204} | |
| $gtk.set_system_cursor(:arrow) | |
| button_rect = { x: 640, y: 460, w: 400, h: 70, anchor_x: 0.5, anchor_y: 0.5 } | |
| button_action = -> { $gtk.notify 'Stop that' } | |
| button_state_enabled = [ | |
| { path: :solid, r: 255, g: 255, b: 0 }, | |
| { text: 'I am an enabled button', r: 0, g: 0, b: 255, size_enum: 6 } | |
| ] | |
| button_state_focused = [ | |
| { path: :solid, r: 0, g: 255, b: 255 }, | |
| { text: 'I am a focused button', r: 255, g: 0, b: 0, size_enum: 6 } | |
| ] | |
| button_state_active = [ | |
| { w: 410 + args.tick_count.*(3).sin * 10, h: 80 + args.tick_count.*(3).cos * 10, path: :solid, r: 0, g: 0, b: 255 }, | |
| { path: :solid, r: 255, g: 0, b: 255 }, | |
| { text: 'I am an active button', r: 0, g: 255, b: 0, size_enum: 6 } | |
| ] | |
| args.outputs.primitives << button( | |
| args, | |
| rect: button_rect, # required | |
| action: button_action, # required | |
| enabled: button_state_enabled, # required | |
| focused: button_state_focused, # optional | |
| active: button_state_active # optional | |
| ) | |
| pill_button_base = { x: 640, y: 300, w: 300, h: 70, anchor_x: 0.5, anchor_y: 0.5, text: "Click Me" } | |
| args.outputs.primitives << button( | |
| args, | |
| rect: pill_button_base, | |
| action: button_action, | |
| enabled: pill_button_layer(args, rect: pill_button_base, color: {r: 0, g: 0, b: 0}, bg: {r: 153, g: 153, b: 153}), | |
| focused: pill_button_layer(args, rect: pill_button_base, color: {r: 188, g: 51, b: 51}, bg: {r: 204, g: 204, b: 204}), | |
| active: pill_button_layer(args, rect: pill_button_base, color: {r: 204, g: 204, b: 204}, bg: {r: 188, g: 51, b: 51}) | |
| ) | |
| end | |
| def button args, **kwargs | |
| if (kwargs.keys & [:rect, :action, :enabled]).size < 3 | |
| raise "Missing argument(s). Provide required rect, action and enabled state." | |
| end | |
| within = args.inputs.mouse.inside_rect? kwargs.rect | |
| was_pushed_within = args.inputs.mouse.previous_click&.inside_rect? kwargs.rect | |
| active = within && was_pushed_within && args.inputs.mouse.held | |
| args.gtk.set_system_cursor(:hand) if within | |
| kwargs.action.call if args.inputs.mouse.up && within && was_pushed_within | |
| primitives = if active && kwargs.active | |
| kwargs.active | |
| elsif within && kwargs.focused | |
| kwargs.focused | |
| else | |
| kwargs.enabled | |
| end | |
| primitives.map do |prim| | |
| { | |
| **prim, | |
| **kwargs.rect, | |
| x: (prim.x || 0) + kwargs.rect.x, | |
| w: prim.w || kwargs.rect.w, | |
| h: prim.h || kwargs.rect.h | |
| } | |
| end | |
| end | |
| def pill_button_layer args, **params | |
| [ | |
| { | |
| path: 'sprites/circles/path1.png', | |
| x: -params.rect.w.half + params.rect.h.half, | |
| w: params.rect.h, h: params.rect.h, | |
| **params.color, | |
| }.sprite!, | |
| { | |
| path: 'sprites/circles/path1.png', | |
| x: params.rect.w.half - params.rect.h.half, | |
| w: params.rect.h, h: params.rect.h, | |
| **params.color | |
| }.sprite!, | |
| { | |
| path: :solid, **params.color, | |
| w: params.rect.w - params.rect.h | |
| }.sprite!, | |
| { | |
| path: 'sprites/circles/path1.png', | |
| x: -params.rect.w.half + params.rect.h.half, | |
| w: params.rect.h - 4, h: params.rect.h - 4, | |
| **params.bg, | |
| }.sprite!, | |
| { | |
| path: 'sprites/circles/path1.png', | |
| x: params.rect.w.half - params.rect.h.half, | |
| w: params.rect.h - 4, h: params.rect.h - 4, | |
| **params.bg | |
| }.sprite!, | |
| { | |
| path: :solid, **params.bg, | |
| w: params.rect.w - params.rect.h, | |
| h: params.rect.h - 4 | |
| }.sprite!, | |
| { | |
| text: params.text, **params.color, size_enum: 6 | |
| } | |
| ] | |
| end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment