Files
infinitefusion-e18/Data/Scripts/801_UI controls/Control elements/001_BaseControl.rb

203 lines
5.5 KiB
Ruby

#===============================================================================
#
#===============================================================================
class UIControls::BaseControl < BitmapSprite
attr_reader :value
attr_accessor :disabled
TEXT_COLOR = Color.black
TEXT_SIZE = 18 # Default is 22 if size isn't explicitly set
TEXT_OFFSET_Y = 5
HOVER_COLOR = Color.new(224, 255, 255) # For clickable area when hovering over it; light blue
CAPTURE_COLOR = Color.new(255, 64, 128) # For area you clicked in but aren't hovering over; hot pink
DISABLED_COLOR = Color.gray
DISABLED_COLOR_DARK = Color.new(128, 128, 128)
def initialize(width, height, viewport)
super(width, height, viewport)
self.bitmap.font.color = TEXT_COLOR
self.bitmap.font.size = TEXT_SIZE
@disabled = false
@hover_area = nil # Is a symbol from the keys for @interactions if the mouse is hovering over that interaction
@captured_area = nil # Is a symbol from the keys for @interactions (or :none) if this control is clicked in
clear_changed
invalidate
end
def width
return self.bitmap.width
end
def height
return self.bitmap.height
end
def mouse_pos
mouse_coords = Mouse.getMousePos
return nil, nil if !mouse_coords
ret_x = mouse_coords[0] - self.viewport.rect.x - self.x
ret_y = mouse_coords[1] - self.viewport.rect.y - self.y
return ret_x, ret_y
end
def set_interactive_rects
@interactions = {}
end
def mouse_in_control?
return false if !@interactions || @interactions.empty?
mouse_x, mouse_y = mouse_pos
return false if !mouse_x || !mouse_y
return @interactions.any? { |area, rect| rect.contains?(mouse_x, mouse_y) }
end
#-----------------------------------------------------------------------------
def disabled?
return @disabled
end
def disable
return if disabled?
@disabled = true
@hover_area = nil
invalidate
end
def enable
return if !disabled?
@disabled = false
invalidate
end
def invalid?
return @invalid
end
# Marks that the control must be redrawn to reflect current logic.
def invalidate
@invalid = true
end
# Makes the control no longer invalid. Called after repainting.
def validate
@invalid = false
end
def busy?
return !@captured_area.nil?
end
def changed?
return @changed
end
def set_changed
@changed = true
end
def clear_changed
@changed = false
end
#-----------------------------------------------------------------------------
def draw_text(this_bitmap, text_x, text_y, this_text)
text_size = this_bitmap.text_size(this_text)
this_bitmap.draw_text(text_x, text_y, text_size.width, text_size.height, this_text, 0)
end
def draw_text_centered(this_bitmap, text_x, text_y, wid, this_text)
text_size = this_bitmap.text_size(this_text)
this_bitmap.draw_text(text_x, text_y, wid, text_size.height, this_text, 1)
end
# Redraws the control only if it is invalid.
def repaint
return if !invalid?
refresh
validate
end
def refresh
self.bitmap.clear
draw_area_highlight
end
def draw_area_highlight
return if !@interactions || @interactions.empty?
if !@captured_area || @hover_area == @captured_area
# Draw mouse hover over area highlight
rect = @interactions[@hover_area]
self.bitmap.fill_rect(rect.x, rect.y, rect.width, rect.height, HOVER_COLOR) if rect
elsif @captured_area
# Draw captured area highlight
rect = @interactions[@captured_area]
self.bitmap.fill_rect(rect.x, rect.y, rect.width, rect.height, CAPTURE_COLOR) if rect
end
end
#-----------------------------------------------------------------------------
# This method is only called if the mouse is in the game window and this
# control has interactive elements.
def on_mouse_press
return if !@interactions || @interactions.empty?
return if @captured_area
@captured_area = nil
mouse_x, mouse_y = mouse_pos
return if !mouse_x || !mouse_y
@interactions.each_pair do |area, rect|
next if !rect.contains?(mouse_x, mouse_y)
@captured_area = area
invalidate
break
end
end
def on_mouse_release
@captured_area = nil
invalidate
end
def update_hover_highlight
# Remove the hover highlight if there are no interactions for this control
# or if the mouse is off-screen
mouse_x, mouse_y = mouse_pos
if !@interactions || @interactions.empty? || !mouse_x || !mouse_y
invalidate if @hover_area
@hover_area = nil
return
end
# Check each interactive area for whether the mouse is hovering over it, and
# set @hover_area accordingly
in_area = false
@interactions.each_pair do |area, rect|
next if !rect.contains?(mouse_x, mouse_y)
invalidate if @hover_area != area
@hover_area = area
in_area = true
break
end
if !in_area
invalidate if @hover_area
@hover_area = nil
end
end
# Updates the logic on the control, invalidating it if necessary.
def update
return if !self.visible
return if disabled? && !busy? # This control still works if it becomes disabled while using it
update_hover_highlight
# Detect a mouse press/release
if @interactions && !@interactions.empty?
if Input.trigger?(Input::MOUSELEFT)
on_mouse_press
elsif busy? && Input.release?(Input::MOUSELEFT)
on_mouse_release
end
end
end
end