Files
infinitefusion-e18/Data/Scripts/801_UI controls/002_ControlsContainer.rb

224 lines
6.8 KiB
Ruby

#===============================================================================
# Controls are arranged in a list in self's bitmap. Each control is given an
# area of size "self's bitmap's width" x LINE_SPACING to draw itself in.
# TODO: The act of "capturing" a control makes other controls in this container
# not update themselves, i.e. they won't colour themselves with a hover
# highlight if the mouse happens to move over it while another control is
# captured. Is there a better way of dealing with this? I'm leaning
# towards the control itself deciding if it's captured, and it being
# treated as uncaptured once it says its value has changed, but I think
# this would require manually telling all other controls in this container
# that something else is captured and they shouldn't show a hover
# highlight when updated (perhaps as a parameter in def update), which I
# don't think is ideal.
#===============================================================================
class UIControls::ControlsContainer
attr_reader :x, :y
attr_reader :controls
attr_reader :values
attr_reader :visible
attr_reader :viewport
LINE_SPACING = 28
OFFSET_FROM_LABEL_X = 90
OFFSET_FROM_LABEL_Y = 0
def initialize(x, y, width, height)
@viewport = Viewport.new(x, y, width, height)
@viewport.z = 99999
@x = x
@y = y
@width = width
@height = height
@controls = []
@row_count = 0
@pixel_offset = 0
@captured = nil
@visible = true
end
def dispose
@controls.each { |c| c[1]&.dispose }
@controls.clear
@viewport.dispose
end
def busy?
return !@captured.nil?
end
def changed?
return !@values.nil?
end
def clear_changed
@values = nil
end
def visible=(value)
@visible = value
@controls.each { |c| c[1].visible = value }
repaint if @visible
end
def get_control(id)
ret = nil
@controls.each do |c|
ret = c[1] if c[0] == id
break if ret
end
return ret
end
#-----------------------------------------------------------------------------
def add_label(id, label, has_label = false)
id = (id.to_s + "_label").to_sym if !has_label
add_control(id, UIControls::Label.new(*control_size(has_label), @viewport, label), has_label)
end
def add_labelled_label(id, label, text)
add_label(id, label)
add_label(id, text, true)
end
def add_header_label(id, label)
ctrl = UIControls::Label.new(*control_size, @viewport, label)
ctrl.header = true
add_control(id, ctrl)
end
def add_checkbox(id, value, has_label = false)
add_control(id, UIControls::Checkbox.new(*control_size(has_label), @viewport, value), has_label)
end
def add_labelled_checkbox(id, label, value)
add_label(id, label)
add_checkbox(id, value, true)
end
def add_text_box(id, value, has_label = false)
add_control(id, UIControls::TextBox.new(*control_size(has_label), @viewport, value), has_label)
end
def add_labelled_text_box(id, label, value)
add_label(id, label)
add_text_box(id, value, true)
end
def add_number_slider(id, min_value, max_value, value, has_label = false)
add_control(id, UIControls::NumberSlider.new(*control_size(has_label), @viewport, min_value, max_value, value), has_label)
end
def add_labelled_number_slider(id, label, min_value, max_value, value)
add_label(id, label)
add_number_slider(id, min_value, max_value, value, true)
end
def add_number_text_box(id, min_value, max_value, value, has_label = false)
add_control(id, UIControls::NumberTextBox.new(*control_size(has_label), @viewport, min_value, max_value, value), has_label)
end
def add_labelled_number_text_box(id, label, min_value, max_value, value)
add_label(id, label)
add_number_text_box(id, min_value, max_value, value, true)
end
def add_button(id, button_text, has_label = false)
add_control(id, UIControls::Button.new(*control_size(has_label), @viewport, button_text), has_label)
end
def add_labelled_button(id, label, button_text)
add_label(id, label)
add_button(id, button_text, true)
end
def add_list(id, rows, options, has_label = false)
size = control_size(has_label)
size[0] -= 8
size[1] = rows * UIControls::List::ROW_HEIGHT
add_control(id, UIControls::List.new(*size, @viewport, options), has_label, rows)
end
def add_labelled_list(id, label, rows, options)
add_label(id, label)
add_list(id, rows, options, true)
end
def add_dropdown_list(id, options, value, has_label = false)
add_control(id, UIControls::DropdownList.new(*control_size(has_label), @viewport, options, value), has_label)
end
def add_labelled_dropdown_list(id, label, options, value)
add_label(id, label)
add_dropdown_list(id, options, value, true)
end
#-----------------------------------------------------------------------------
def repaint
@controls.each { |ctrl| ctrl[1].repaint }
end
def refresh; end
#-----------------------------------------------------------------------------
def update
return if !@visible
# Update controls
if @captured
# TODO: Ideally all controls will be updated here, if only to redraw
# themselves if they happen to be invalidated somehow. But that
# involves telling each control whether any other control is busy,
# to ensure that they don't show their hover colours or anything,
# which is fiddly and I'm not sure if it's the best approach.
@captured.update
@captured = nil if !@captured.busy?
else
@controls.each do |ctrl|
ctrl[1].update
@captured = ctrl[1] if ctrl[1].busy?
end
end
# Check for updated controls
@controls.each do |ctrl|
next if !ctrl[1].changed?
@values ||= {}
@values[ctrl[0]] = ctrl[1].value
ctrl[1].clear_changed
end
# Redraw controls if needed
repaint
end
#-----------------------------------------------------------------------------
def control_size(has_label = false)
if has_label
return @width - OFFSET_FROM_LABEL_X, LINE_SPACING - OFFSET_FROM_LABEL_Y
end
return @width, LINE_SPACING
end
def add_control_at(id, control, x, y)
control.x = x
control.y = y
control.set_interactive_rects
@controls.push([id, control])
repaint
end
def add_control(id, control, add_offset = false, rows = 1)
i = @controls.length
row_x = 0
row_y = (add_offset ? @row_count - 1 : @row_count) * LINE_SPACING
ctrl_x = row_x + (add_offset ? OFFSET_FROM_LABEL_X : 0)
ctrl_x += 4 if control.is_a?(UIControls::List)
ctrl_y = row_y + (add_offset ? OFFSET_FROM_LABEL_Y : 0) + @pixel_offset
add_control_at(id, control, ctrl_x, ctrl_y)
@row_count += rows if !add_offset
@pixel_offset -= (LINE_SPACING - UIControls::List::ROW_HEIGHT) * (rows - 1) if control.is_a?(UIControls::List)
end
end