require 'glimmer-dsl-libui' class AreaBasedCustomControls include Glimmer attr_accessor :label_width, :label_height, :label_font_descriptor, :label_text_color, :label_background_fill, :label_border_stroke, :label_text_x, :label_text_y, :button_width, :button_height, :button_font_descriptor, :button_text_color, :button_background_fill, :button_border_stroke, :button_text_x, :button_text_y def initialize self.label_width = 335 self.label_height = 50 self.label_font_descriptor = {family: OS.linux? ? 'Monospace Bold Italic' : 'Courier New', size: 16, weight: :bold, italic: :italic} self.label_text_color = :red self.label_background_fill = :yellow self.label_border_stroke = :limegreen self.button_width = 150 self.button_height = 50 self.button_font_descriptor = {family: OS.linux? ? 'Monospace Bold Italic' : 'Courier New', size: 36, weight: OS.linux? ? :normal : :bold, italic: :italic} self.button_text_color = :green self.button_background_fill = :yellow self.button_border_stroke = :limegreen end def rebuild_text_label @text_label.destroy @text_label_vertical_box.content { # re-open vertical box content and shove in a new label @text_label = text_label('This is a text label.', width: label_width, height: label_height, font_descriptor: label_font_descriptor, background_fill: label_background_fill, text_color: label_text_color, border_stroke: label_border_stroke, text_x: label_text_x, text_y: label_text_y) } end def rebuild_push_button @push_button.destroy @push_button_vertical_box.content { # re-open vertical box content and shove in a new button @push_button = push_button('Push', width: button_width, height: button_height, font_descriptor: button_font_descriptor, background_fill: button_background_fill, text_color: button_text_color, border_stroke: button_border_stroke, text_x: button_text_x, text_y: button_text_y) { on_mouse_up do message_box('Button Pushed', 'Thank you for pushing the button!') end } } end def launch window('Area-Based Custom Controls', 385, 385) { |w| margined true tab { tab_item('Text Label') { @text_label_vertical_box = vertical_box { vertical_box { text_label('Text Label Form:', width: 385, height: 30, background_fill: OS.windows? ? :white : {a: 0}, border_stroke: OS.windows? ? :white : {a: 0}, font_descriptor: {size: 16, weight: :bold}, text_x: 0, text_y: OS.windows? ? 0 : 5) horizontal_box { label('Width') spinbox(1, 1000) { value <=> [self, :label_width, after_write: method(:rebuild_text_label)] } } horizontal_box { label('Height') spinbox(1, 1000) { value <=> [self, :label_height, after_write: method(:rebuild_text_label)] } } horizontal_box { label('Font') font_button { font <=> [self, :label_font_descriptor, after_write: method(:rebuild_text_label)] } } horizontal_box { label('Text Color') color_button { color <=> [self, :label_text_color, after_write: method(:rebuild_text_label)] } } horizontal_box { label('Background Color') color_button { color <=> [self, :label_background_fill, after_write: method(:rebuild_text_label)] } } horizontal_box { label('Border Color') color_button { color <=> [self, :label_border_stroke, after_write: method(:rebuild_text_label)] } } horizontal_box { label('Text X (0=centered)') spinbox(0, 1000) { value <=> [self, :label_text_x, on_read: ->(x) {x.nil? ? 0 : x}, on_write: ->(x) {x == 0 ? nil : x}, after_write: method(:rebuild_text_label)] } } horizontal_box { label('Text Y (0=centered)') spinbox(0, 1000) { value <=> [self, :label_text_y, on_read: ->(y) {y.nil? ? 0 : y}, on_write: ->(y) {y == 0 ? nil : y}, after_write: method(:rebuild_text_label)] } } } @text_label = text_label('This is a text label.', width: label_width, height: label_height, font_descriptor: label_font_descriptor, background_fill: label_background_fill, text_color: label_text_color, border_stroke: label_border_stroke, text_x: label_text_x, text_y: label_text_y) } } tab_item('Push Button') { @push_button_vertical_box = vertical_box { vertical_box { text_label('Push Button Form:', width: 385, height: 30, background_fill: OS.windows? ? :white : {a: 0}, border_stroke: OS.windows? ? :white : {a: 0}, font_descriptor: {size: 16, weight: :bold}, text_x: 0, text_y: OS.windows? ? 0 : 5) horizontal_box { label('Width') spinbox(1, 1000) { value <=> [self, :button_width, after_write: method(:rebuild_push_button)] } } horizontal_box { label('Height') spinbox(1, 1000) { value <=> [self, :button_height, after_write: method(:rebuild_push_button)] } } horizontal_box { label('Font') font_button { font <=> [self, :button_font_descriptor, after_write: method(:rebuild_push_button)] } } horizontal_box { label('Text Color') color_button { color <=> [self, :button_text_color, after_write: method(:rebuild_push_button)] } } horizontal_box { label('Background Color') color_button { color <=> [self, :button_background_fill, after_write: method(:rebuild_push_button)] } } horizontal_box { label('Border Color') color_button { color <=> [self, :button_border_stroke, after_write: method(:rebuild_push_button)] } } horizontal_box { label('Text X (0=centered)') spinbox(0, 1000) { value <=> [self, :button_text_x, on_read: ->(x) {x.nil? ? 0 : x}, on_write: ->(x) {x == 0 ? nil : x}, after_write: method(:rebuild_push_button)] } } horizontal_box { label('Text Y (0=centered)') spinbox(0, 1000) { value <=> [self, :button_text_y, on_read: ->(y) {y.nil? ? 0 : y}, on_write: ->(y) {y == 0 ? nil : y}, after_write: method(:rebuild_push_button)] } } } @push_button = push_button('Push', width: button_width, height: button_height, font_descriptor: button_font_descriptor, background_fill: button_background_fill, text_color: button_text_color, border_stroke: button_border_stroke, text_x: button_text_x, text_y: button_text_y) { on_mouse_up do message_box('Button Pushed', 'Thank you for pushing the button!') end } } } } }.show end # text label (area-based custom control) built with vector graphics on top of area. # # background_fill is transparent by default. # background_fill can accept a single color or gradient stops just as per `fill` property in README. # border_stroke is transparent by default. # border_stroke can accept thickness and dashes in addition to color just as per `stroke` property in README. # text_x and text_y are the offset of the label text in relation to its top-left corner. # When text_x, text_y are left nil, the text is automatically centered in the label area. # Sometimes, the centering calculation is not perfect due to using a custom font, so # in that case, pass in text_x, and text_y manually. def text_label(label_text, width: 80, height: 30, font_descriptor: {}, background_fill: {a: 0}, text_color: :black, border_stroke: {a: 0}, text_x: nil, text_y: nil, &content) area { |the_area| rectangle(1, 1, width, height) { fill background_fill } rectangle(1, 1, width, height) { stroke border_stroke } text_height = (font_descriptor[:size] || 12) * (OS.mac? ? 0.75 : 1.35) text_width = (text_height * label_text.size) * (OS.mac? ? 0.75 : 0.60) text_x ||= (width - text_width) / 2.0 text_y ||= (height - 4 - text_height) / 2.0 text(text_x, text_y, width) { string(label_text) { color text_color font font_descriptor } } content&.call(the_area) } end # push button (area-based custom control) built with vector graphics on top of area. # # background_fill is white by default. # background_fill can accept a single color or gradient stops just as per `fill` property in README. # border_stroke is black by default. # border_stroke can accept thickness and dashes in addition to color just as per `stroke` property in README. # text_x and text_y are the offset of the button text in relation to its top-left corner. # When text_x, text_y are left nil, the text is automatically centered in the button area. # Sometimes, the centering calculation is not perfect due to using a custom font, so # in that case, pass in text_x, and text_y manually. # # reuses the text_label custom control def push_button(button_text, width: 80, height: 30, font_descriptor: {}, background_fill: :white, text_color: :black, border_stroke: {r: 201, g: 201, b: 201}, text_x: nil, text_y: nil, &content) text_label(button_text, width: width, height: height, font_descriptor: font_descriptor, background_fill: background_fill, text_color: text_color, border_stroke: border_stroke, text_x: text_x, text_y: text_y) { |the_area| # dig into the_area content and grab elements to modify in mouse listeners below background_rectangle = the_area.children[0] button_string = the_area.children[2].children[0] on_mouse_down do background_rectangle.fill = {x0: 0, y0: 0, x1: 0, y1: height, stops: [{pos: 0, r: 72, g: 146, b: 247}, {pos: 1, r: 12, g: 85, b: 214}]} button_string.color = :white end on_mouse_up do background_rectangle.fill = background_fill button_string.color = text_color end content&.call(the_area) } end end AreaBasedCustomControls.new.launch