colstrom-fidgit 0.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +8 -0
- data/.rspec +2 -0
- data/CHANGELOG.md +31 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +20 -0
- data/README.md +154 -0
- data/Rakefile +38 -0
- data/config/default_schema.yml +216 -0
- data/examples/_all_examples.rb +9 -0
- data/examples/align_example.rb +56 -0
- data/examples/button_and_toggle_button_example.rb +38 -0
- data/examples/color_picker_example.rb +17 -0
- data/examples/color_well_example.rb +25 -0
- data/examples/combo_box_example.rb +24 -0
- data/examples/file_dialog_example.rb +42 -0
- data/examples/grid_packer_example.rb +29 -0
- data/examples/helpers/example_window.rb +17 -0
- data/examples/label_example.rb +23 -0
- data/examples/list_example.rb +23 -0
- data/examples/media/images/head_icon.png +0 -0
- data/examples/menu_pane_example.rb +27 -0
- data/examples/message_dialog_example.rb +65 -0
- data/examples/radio_button_example.rb +37 -0
- data/examples/readme_example.rb +32 -0
- data/examples/scroll_window_example.rb +49 -0
- data/examples/slider_example.rb +34 -0
- data/examples/splash_example.rb +42 -0
- data/examples/text_area_example.rb +33 -0
- data/fidgit.gemspec +35 -0
- data/lib/fidgit.rb +51 -0
- data/lib/fidgit/chingu_ext/window.rb +6 -0
- data/lib/fidgit/cursor.rb +38 -0
- data/lib/fidgit/elements/button.rb +113 -0
- data/lib/fidgit/elements/color_picker.rb +63 -0
- data/lib/fidgit/elements/color_well.rb +39 -0
- data/lib/fidgit/elements/combo_box.rb +115 -0
- data/lib/fidgit/elements/composite.rb +17 -0
- data/lib/fidgit/elements/container.rb +210 -0
- data/lib/fidgit/elements/element.rb +298 -0
- data/lib/fidgit/elements/file_browser.rb +152 -0
- data/lib/fidgit/elements/grid.rb +227 -0
- data/lib/fidgit/elements/group.rb +64 -0
- data/lib/fidgit/elements/horizontal.rb +12 -0
- data/lib/fidgit/elements/image_frame.rb +65 -0
- data/lib/fidgit/elements/label.rb +85 -0
- data/lib/fidgit/elements/list.rb +47 -0
- data/lib/fidgit/elements/main_packer.rb +25 -0
- data/lib/fidgit/elements/menu_pane.rb +163 -0
- data/lib/fidgit/elements/packer.rb +42 -0
- data/lib/fidgit/elements/radio_button.rb +86 -0
- data/lib/fidgit/elements/scroll_area.rb +68 -0
- data/lib/fidgit/elements/scroll_bar.rb +128 -0
- data/lib/fidgit/elements/scroll_window.rb +83 -0
- data/lib/fidgit/elements/slider.rb +125 -0
- data/lib/fidgit/elements/text_area.rb +494 -0
- data/lib/fidgit/elements/text_line.rb +92 -0
- data/lib/fidgit/elements/toggle_button.rb +67 -0
- data/lib/fidgit/elements/tool_tip.rb +35 -0
- data/lib/fidgit/elements/vertical.rb +12 -0
- data/lib/fidgit/event.rb +159 -0
- data/lib/fidgit/gosu_ext/color.rb +136 -0
- data/lib/fidgit/gosu_ext/gosu_module.rb +25 -0
- data/lib/fidgit/history.rb +91 -0
- data/lib/fidgit/redirector.rb +83 -0
- data/lib/fidgit/schema.rb +123 -0
- data/lib/fidgit/selection.rb +106 -0
- data/lib/fidgit/standard_ext/hash.rb +21 -0
- data/lib/fidgit/states/dialog_state.rb +52 -0
- data/lib/fidgit/states/file_dialog.rb +24 -0
- data/lib/fidgit/states/gui_state.rb +331 -0
- data/lib/fidgit/states/message_dialog.rb +61 -0
- data/lib/fidgit/version.rb +5 -0
- data/lib/fidgit/window.rb +19 -0
- data/media/images/arrow.png +0 -0
- data/media/images/combo_arrow.png +0 -0
- data/media/images/file_directory.png +0 -0
- data/media/images/file_file.png +0 -0
- data/media/images/pixel.png +0 -0
- data/spec/fidgit/elements/helpers/helper.rb +3 -0
- data/spec/fidgit/elements/helpers/tex_play_helper.rb +9 -0
- data/spec/fidgit/elements/image_frame_spec.rb +69 -0
- data/spec/fidgit/elements/label_spec.rb +37 -0
- data/spec/fidgit/event_spec.rb +210 -0
- data/spec/fidgit/gosu_ext/color_spec.rb +130 -0
- data/spec/fidgit/gosu_ext/helpers/helper.rb +3 -0
- data/spec/fidgit/helpers/helper.rb +4 -0
- data/spec/fidgit/history_spec.rb +153 -0
- data/spec/fidgit/redirector_spec.rb +78 -0
- data/spec/fidgit/schema_spec.rb +67 -0
- data/spec/fidgit/schema_test.yml +32 -0
- metadata +320 -0
@@ -0,0 +1,25 @@
|
|
1
|
+
module Gosu
|
2
|
+
class << self
|
3
|
+
alias_method :register_entity_fidgit, :register_entity
|
4
|
+
|
5
|
+
protected
|
6
|
+
def init_entities
|
7
|
+
@entities = {}
|
8
|
+
end
|
9
|
+
|
10
|
+
public
|
11
|
+
def register_entity(name, image)
|
12
|
+
name = name.to_sym
|
13
|
+
register_entity_fidgit(name, image)
|
14
|
+
@entities[name] = image
|
15
|
+
nil
|
16
|
+
end
|
17
|
+
|
18
|
+
public
|
19
|
+
def entity(name)
|
20
|
+
@entities[name.to_sym]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
init_entities
|
25
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Fidgit
|
4
|
+
# Manages a history of actions, along with doing, undoing and redoing those actions.
|
5
|
+
class History
|
6
|
+
# Maximum number of actions in the History before Actions are deleted.
|
7
|
+
DEFAULT_MAX_SIZE = 250
|
8
|
+
|
9
|
+
# An action in the History. Inherit actions from this in order to add them to a History.
|
10
|
+
class Action
|
11
|
+
# Perform the action.
|
12
|
+
def do; raise NotImplementedError, "#{self.class} does not have a do method defined"; end
|
13
|
+
|
14
|
+
# Reverse the action.
|
15
|
+
def undo; raise NotImplementedError, "#{self.class} does not have an undo method defined"; end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Is there an action that can be undone?
|
19
|
+
def can_undo?; @last_done >= 0; end
|
20
|
+
|
21
|
+
# Is there an action that has been undone that can now be redone?
|
22
|
+
def can_redo?; @last_done < (@actions.size - 1); end
|
23
|
+
|
24
|
+
def initialize(max_size = DEFAULT_MAX_SIZE)
|
25
|
+
@max_size = max_size
|
26
|
+
@actions = []
|
27
|
+
@last_done = -1 # Last command that was performed.
|
28
|
+
end
|
29
|
+
|
30
|
+
# Perform a History::Action, adding it to the history.
|
31
|
+
# If there are currently any actions that have been undone, they will be permanently lost and cannot be redone.
|
32
|
+
#
|
33
|
+
# @param [History::Action] action Action to be performed
|
34
|
+
def do(action)
|
35
|
+
raise ArgumentError, "Parameter, 'action', expected to be a #{Action}, but received: #{action}" unless action.is_a? Action
|
36
|
+
|
37
|
+
# Remove all undone actions when a new one is performed.
|
38
|
+
if can_redo?
|
39
|
+
if @last_done == -1
|
40
|
+
@actions.clear
|
41
|
+
else
|
42
|
+
@actions = @actions[0..@last_done]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# If history is too big, remove the oldest action.
|
47
|
+
if @actions.size >= @max_size
|
48
|
+
@actions.shift
|
49
|
+
end
|
50
|
+
|
51
|
+
@last_done = @actions.size
|
52
|
+
@actions << action
|
53
|
+
action.do
|
54
|
+
|
55
|
+
nil
|
56
|
+
end
|
57
|
+
|
58
|
+
# Perform a History::Action, replacing the last action that was performed.
|
59
|
+
#
|
60
|
+
# @param [History::Action] action Action to be performed
|
61
|
+
def replace_last(action)
|
62
|
+
raise ArgumentError, "Parameter, 'action', expected to be a #{Action}, but received: #{action}" unless action.is_a? Action
|
63
|
+
|
64
|
+
@actions[@last_done].undo
|
65
|
+
@actions[@last_done] = action
|
66
|
+
action.do
|
67
|
+
|
68
|
+
nil
|
69
|
+
end
|
70
|
+
|
71
|
+
# Undo the last action that was performed.
|
72
|
+
def undo
|
73
|
+
raise "Can't undo unless there are commands in past" unless can_undo?
|
74
|
+
|
75
|
+
@actions[@last_done].undo
|
76
|
+
@last_done -= 1
|
77
|
+
|
78
|
+
nil
|
79
|
+
end
|
80
|
+
|
81
|
+
# Redo the last action that was undone.
|
82
|
+
def redo
|
83
|
+
raise "Can't redo if there are no commands in the future" unless can_redo?
|
84
|
+
|
85
|
+
@last_done += 1
|
86
|
+
@actions[@last_done].do
|
87
|
+
|
88
|
+
nil
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module Fidgit
|
2
|
+
# Redirects methods to an object, but does not mask methods and ivars from the calling context.
|
3
|
+
module RedirectorMethods
|
4
|
+
# Evaluate a block accessing methods and ivars from the calling context, but calling public methods
|
5
|
+
# (not ivars or non-public methods) on this object in preference.
|
6
|
+
def instance_methods_eval(&block)
|
7
|
+
raise ArgumentError, "block required" unless block_given?
|
8
|
+
|
9
|
+
context = eval('self', block.binding)
|
10
|
+
|
11
|
+
context.send :push_redirection_target, self
|
12
|
+
|
13
|
+
begin
|
14
|
+
yield context
|
15
|
+
ensure
|
16
|
+
context.send :pop_redirection_target
|
17
|
+
end
|
18
|
+
|
19
|
+
self
|
20
|
+
end
|
21
|
+
|
22
|
+
protected
|
23
|
+
def push_redirection_target(target)
|
24
|
+
meta_class = class << self; self; end
|
25
|
+
base_methods = Object.public_instance_methods
|
26
|
+
|
27
|
+
# Redirect just the public methods of the target, less those that are on Object.
|
28
|
+
methods_to_redirect = target.public_methods - base_methods
|
29
|
+
|
30
|
+
# Only hide those public/private/protected methods that are being redirected.
|
31
|
+
methods_overridden = []
|
32
|
+
[:public, :protected, :private].each do |access|
|
33
|
+
methods_to_hide = meta_class.send("#{access}_instance_methods", false) & methods_to_redirect
|
34
|
+
methods_to_hide.each do |meth|
|
35
|
+
# Take a reference to the method we are about to override.
|
36
|
+
methods_overridden.push [meth, method(meth), access]
|
37
|
+
meta_class.send :remove_method, meth
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Add a method, to redirect calls to the target.
|
42
|
+
methods_to_redirect.each do |meth|
|
43
|
+
meta_class.send :define_method, meth do |*args, &block|
|
44
|
+
target.send meth, *args, &block
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
redirection_stack.push [target, methods_overridden, methods_to_redirect]
|
49
|
+
|
50
|
+
target
|
51
|
+
end
|
52
|
+
|
53
|
+
protected
|
54
|
+
def pop_redirection_target
|
55
|
+
meta_class = class << self; self; end
|
56
|
+
|
57
|
+
target, methods_to_recreate, methods_to_remove = redirection_stack.pop
|
58
|
+
|
59
|
+
# Remove the redirection methods
|
60
|
+
methods_to_remove.reverse_each do |meth|
|
61
|
+
meta_class.send :remove_method, meth
|
62
|
+
end
|
63
|
+
|
64
|
+
# Replace with the previous versions of the methods.
|
65
|
+
methods_to_recreate.reverse_each do |meth, reference, access|
|
66
|
+
meta_class.send :define_method, meth, reference
|
67
|
+
meta_class.send access, meth unless access == :public
|
68
|
+
end
|
69
|
+
|
70
|
+
target
|
71
|
+
end
|
72
|
+
|
73
|
+
# Direct access to the redirection stack.
|
74
|
+
private
|
75
|
+
def redirection_stack
|
76
|
+
@_redirection_stack ||= []
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
class Object
|
82
|
+
include Fidgit::RedirectorMethods
|
83
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Fidgit
|
4
|
+
# An object that manages Schema values. Usually loaded from a YAML file.
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# schema = Schema.new(YAML.load(file.read('default_schema.yml')))
|
8
|
+
# default_color = schema.default(Element, :disabled, :color)
|
9
|
+
# schema.merge_schema!(YAML.load(file.read('override_schema.yml'))
|
10
|
+
# overridden_color = schema.default(Element, :disabled, :color)
|
11
|
+
class Schema
|
12
|
+
CONSTANT_PREFIX = '?'
|
13
|
+
|
14
|
+
# @param [Hash<Symbol => Hash>] schema data containing
|
15
|
+
def initialize(schema)
|
16
|
+
@constants = {}
|
17
|
+
@elements = {}
|
18
|
+
|
19
|
+
merge_schema! schema
|
20
|
+
end
|
21
|
+
|
22
|
+
# Merge in a hash containing constant values.
|
23
|
+
#
|
24
|
+
# @param [Hash<Symbol => Hash>] constants_hash Containing :colors, :constants and :elements hashes.
|
25
|
+
def merge_schema!(schema)
|
26
|
+
merge_constants!(schema[:constants]) if schema[:constants]
|
27
|
+
merge_elements!(schema[:elements]) if schema[:elements]
|
28
|
+
|
29
|
+
self
|
30
|
+
end
|
31
|
+
|
32
|
+
# Merge in a hash containing constant values. Arrays will be resolved as colors in RGBA or RGB format.
|
33
|
+
#
|
34
|
+
# @param [Hash<Symbol => Object>] constants_hash
|
35
|
+
def merge_constants!(constants_hash)
|
36
|
+
constants_hash.each_pair do |name, value|
|
37
|
+
@constants[name] = case value
|
38
|
+
when Array
|
39
|
+
case value.size
|
40
|
+
when 3 then Gosu::Color.rgb(*value)
|
41
|
+
when 4 then Gosu::Color.rgba(*value)
|
42
|
+
else
|
43
|
+
raise "Colors must be in 0..255, RGB or RGBA array format"
|
44
|
+
end
|
45
|
+
else
|
46
|
+
value
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
self
|
51
|
+
end
|
52
|
+
|
53
|
+
# Merge in a hash containing default values for each element.
|
54
|
+
#
|
55
|
+
# @param [Hash<Symbol => Hash>] elements_hash
|
56
|
+
def merge_elements!(elements_hash)
|
57
|
+
elements_hash.each_pair do |klass_names, data|
|
58
|
+
klass = Fidgit
|
59
|
+
klass_names.to_s.split('::').each do |klass_name|
|
60
|
+
klass = klass.const_get klass_name
|
61
|
+
end
|
62
|
+
|
63
|
+
raise "elements must be names of classes derived from #{Element}" unless klass.ancestors.include? Fidgit::Element
|
64
|
+
@elements[klass] ||= {}
|
65
|
+
@elements[klass].deep_merge! data
|
66
|
+
end
|
67
|
+
|
68
|
+
self
|
69
|
+
end
|
70
|
+
|
71
|
+
# Get the constant value associated with +name+.
|
72
|
+
#
|
73
|
+
# @param [Symbol] name
|
74
|
+
# @return [Object]
|
75
|
+
def constant(name)
|
76
|
+
@constants[name]
|
77
|
+
end
|
78
|
+
|
79
|
+
# @param [Class] klass Class to look for defaults for.
|
80
|
+
# @param [Symbol, Array<Symbol>] names Hash names to search for in that class's schema.
|
81
|
+
def default(klass, names)
|
82
|
+
raise ArgumentError, "#{klass} is not a descendent of the #{Element} class" unless klass.ancestors.include? Element
|
83
|
+
value = default_internal(klass, Array(names), true)
|
84
|
+
raise("Failed to find named value #{names.inspect} for class #{klass}") unless value
|
85
|
+
value
|
86
|
+
end
|
87
|
+
|
88
|
+
protected
|
89
|
+
# @param [Class] klass Class to look for defaults for.
|
90
|
+
# @param [Array<Symbol>] names Hash names to search for in that class's schema.
|
91
|
+
# @param [Boolean] default_to_outer Whether to default to an outer value (used internally)
|
92
|
+
def default_internal(klass, names, default_to_outer)
|
93
|
+
# Find the value by moving through the nested hash via the names.
|
94
|
+
value = @elements[klass]
|
95
|
+
|
96
|
+
names.each do |name|
|
97
|
+
break unless value.is_a? Hash
|
98
|
+
value = value.has_key?(name) ? value[name] : nil
|
99
|
+
end
|
100
|
+
|
101
|
+
# Convert the value to a color/constant if they are symbols.
|
102
|
+
value = if value.is_a? String and value[0] == CONSTANT_PREFIX
|
103
|
+
str = value[1..-1]
|
104
|
+
constant(str.to_sym) || value # If the value isn't a constant, return the string.
|
105
|
+
else
|
106
|
+
value
|
107
|
+
end
|
108
|
+
|
109
|
+
# If we didn't find the value for this class, default to parent class value.
|
110
|
+
if value.nil? and klass != Element and klass.ancestors.include? Element
|
111
|
+
# Check if any ancestors define the fully named value.
|
112
|
+
value = default_internal(klass.superclass, names, false)
|
113
|
+
end
|
114
|
+
|
115
|
+
if value.nil? and default_to_outer and names.size > 1
|
116
|
+
# Check the outer values (e.g. if [:hover, :color] is not defined, try [:color]).
|
117
|
+
value = default_internal(klass, names[1..-1], true)
|
118
|
+
end
|
119
|
+
|
120
|
+
value
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Fidgit
|
4
|
+
class Selection
|
5
|
+
MIN_DRAG_DISTANCE = 2
|
6
|
+
|
7
|
+
def size; @items.size; end
|
8
|
+
def empty?; @items.empty?; end
|
9
|
+
def [](index); @items[index]; end
|
10
|
+
def each(&block); @items.each(&block); end
|
11
|
+
def to_a; @items.dup; end
|
12
|
+
def include?(object); @items.include? object; end
|
13
|
+
|
14
|
+
# Current being dragged?
|
15
|
+
def dragging?; @dragging; end
|
16
|
+
|
17
|
+
# Actually moved during a dragging operation?
|
18
|
+
def moved?; @moved; end
|
19
|
+
|
20
|
+
def initialize
|
21
|
+
@items = []
|
22
|
+
@moved = false
|
23
|
+
@dragging = false
|
24
|
+
end
|
25
|
+
|
26
|
+
def add(object)
|
27
|
+
object.selected = true
|
28
|
+
@items.push(object)
|
29
|
+
|
30
|
+
self
|
31
|
+
end
|
32
|
+
|
33
|
+
def remove(object)
|
34
|
+
@items.delete(object)
|
35
|
+
object.selected = false
|
36
|
+
object.dragging = false
|
37
|
+
|
38
|
+
self
|
39
|
+
end
|
40
|
+
|
41
|
+
def clear
|
42
|
+
end_drag if dragging?
|
43
|
+
@items.each { |o| o.selected = false; o.dragging = false }
|
44
|
+
@items.clear
|
45
|
+
|
46
|
+
self
|
47
|
+
end
|
48
|
+
|
49
|
+
def begin_drag(x, y)
|
50
|
+
@initial_x, @initial_y = x, y
|
51
|
+
@last_x, @last_y = x, y
|
52
|
+
@dragging = true
|
53
|
+
@moved = false
|
54
|
+
|
55
|
+
self
|
56
|
+
end
|
57
|
+
|
58
|
+
def end_drag
|
59
|
+
@items.each do |object|
|
60
|
+
object.x, object.y = object.x.round, object.y.round
|
61
|
+
object.dragging = false
|
62
|
+
end
|
63
|
+
@dragging = false
|
64
|
+
@moved = false
|
65
|
+
|
66
|
+
self
|
67
|
+
end
|
68
|
+
|
69
|
+
# Move all dragged object back to original positions.
|
70
|
+
def reset_drag
|
71
|
+
if moved?
|
72
|
+
@items.each do |o|
|
73
|
+
o.x += @initial_x - @last_x
|
74
|
+
o.y += @initial_y - @last_y
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
self.end_drag
|
79
|
+
|
80
|
+
self
|
81
|
+
end
|
82
|
+
|
83
|
+
def update_drag(x, y)
|
84
|
+
x, y = x.round, y.round
|
85
|
+
|
86
|
+
# If the mouse has been dragged far enough from the initial click position, then 'pick up' the objects and drag.
|
87
|
+
unless moved?
|
88
|
+
if distance(@initial_x, @initial_y, x, y) > MIN_DRAG_DISTANCE
|
89
|
+
@items.each { |o| o.dragging = true }
|
90
|
+
@moved = true
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
if moved?
|
95
|
+
@items.each do |o|
|
96
|
+
o.x += x - @last_x
|
97
|
+
o.y += y - @last_y
|
98
|
+
end
|
99
|
+
|
100
|
+
@last_x, @last_y = x, y
|
101
|
+
end
|
102
|
+
|
103
|
+
self
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class Hash
|
2
|
+
# Merge not only the hashes, but all nested hashes as well.
|
3
|
+
# Written by Stefan Rusterholz (apeiros) from http://www.ruby-forum.com/topic/142809
|
4
|
+
def deep_merge!(other)
|
5
|
+
merger = lambda do |key, a, b|
|
6
|
+
(a.is_a?(Hash) && b.is_a?(Hash)) ? a.merge!(b, &merger) : b
|
7
|
+
end
|
8
|
+
|
9
|
+
merge!(other, &merger)
|
10
|
+
end
|
11
|
+
|
12
|
+
# Merge not only the hashes, but all nested hashes as well.
|
13
|
+
# Written by Stefan Rusterholz (apeiros) from http://www.ruby-forum.com/topic/142809
|
14
|
+
def deep_merge(other)
|
15
|
+
merger = lambda do |key, a, b|
|
16
|
+
(a.is_a?(Hash) && b.is_a?(Hash)) ? a.merge(b, &merger) : b
|
17
|
+
end
|
18
|
+
|
19
|
+
merge(other, &merger)
|
20
|
+
end
|
21
|
+
end
|