reactive_view_wx 0.1.0

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.
Files changed (38) hide show
  1. data/History.txt +3 -0
  2. data/MIT-LICENSE +21 -0
  3. data/Manifest.txt +37 -0
  4. data/README.txt +19 -0
  5. data/Rakefile +16 -0
  6. data/lib/action_view_init.rb +13 -0
  7. data/lib/base.rb +59 -0
  8. data/lib/binder.rb +20 -0
  9. data/lib/helpers/model_edit_ctrl_class.rb +124 -0
  10. data/lib/helpers/model_list_ctrl_class.rb +82 -0
  11. data/lib/helpers/model_main_frame_class.rb +132 -0
  12. data/lib/helpers/model_show_ctrl_class.rb +35 -0
  13. data/lib/reactive_view_wx.rb +22 -0
  14. data/lib/request.rb +14 -0
  15. data/lib/template.rb +114 -0
  16. data/lib/version.rb +13 -0
  17. data/lib/xrc_pepper.rb +253 -0
  18. data/reactive_generators/application_view/USAGE +7 -0
  19. data/reactive_generators/application_view/application_view_generator.rb +49 -0
  20. data/reactive_generators/application_view/templates/application_helper.rb +40 -0
  21. data/reactive_generators/application_view/templates/application_layout.rb +2 -0
  22. data/reactive_generators/application_view/templates/application_view.rb +9 -0
  23. data/reactive_generators/application_view/templates/assets/delete16.png +0 -0
  24. data/reactive_generators/application_view/templates/assets/edit16.png +0 -0
  25. data/reactive_generators/application_view/templates/assets/show16.png +0 -0
  26. data/reactive_generators/application_view/templates/record_toolbar.rb +46 -0
  27. data/reactive_generators/view/USAGE +16 -0
  28. data/reactive_generators/view/templates/create.rb +1 -0
  29. data/reactive_generators/view/templates/delete.rb +3 -0
  30. data/reactive_generators/view/templates/destroy.rb +0 -0
  31. data/reactive_generators/view/templates/edit.rb +8 -0
  32. data/reactive_generators/view/templates/index.rb +4 -0
  33. data/reactive_generators/view/templates/layout.rb +2 -0
  34. data/reactive_generators/view/templates/new.rb +8 -0
  35. data/reactive_generators/view/templates/show.rb +4 -0
  36. data/reactive_generators/view/templates/update.rb +1 -0
  37. data/reactive_generators/view/view_generator.rb +69 -0
  38. metadata +146 -0
@@ -0,0 +1,35 @@
1
+ require 'wx_sugar'
2
+
3
+ module Reactive::View::Wx
4
+ module Helpers
5
+
6
+ class ModelShowCtrl < Wx::Panel
7
+ attr_reader :model
8
+
9
+ def selected_records
10
+ [@record]
11
+ end
12
+
13
+ def initialize(parent, record, options = {})
14
+ super(parent, options)
15
+ @model, @record = record.class, record
16
+
17
+ fill_controls(record)
18
+ end
19
+
20
+ protected
21
+
22
+ def fill_controls(record)
23
+ arrange_grid(:cols => 2, :padding => 5, :proportion => 1) {|sizer| sizer.add_growable_col(1, 1)}
24
+ read_only = Wx::SystemSettings.get_colour(Wx::SYS_COLOUR_BTNFACE)
25
+ @model.content_columns.each do |column|
26
+ nest(Wx::StaticText.new(self, :label => "#{column.human_name} :"), :pad => 'ALIGN_CENTER_VERTICAL,ALIGN_RIGHT')
27
+ nest(ctrl = Wx::TextCtrl.new(self, :value => record.send(column.name).to_s, :style => Wx::TE_READONLY), :proportion => 1, :align => 'CENTER_VERTICAL')
28
+ ctrl.set_background_colour(read_only)
29
+ end
30
+ end
31
+
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,22 @@
1
+ require 'activesupport'
2
+ require 'reactive'
3
+ require 'wx'
4
+
5
+ #require 'wx_pepper'
6
+ require 'xrc_pepper'
7
+
8
+ require 'request'
9
+ require 'binder'
10
+ require 'template'
11
+ require 'base'
12
+
13
+ Wx::EvtHandler.send(:include, Reactive::View::Wx::Binder)
14
+
15
+ # Let the controller know our temlate class
16
+ #Reactive::Controller::Base.template_class = Reactive::View::Wx::Template
17
+
18
+ # We want the ::Wx namespace to be directly available for our templates. Since ActionView compiles the template
19
+ # and hosts the compiled code into the ActionView::Base::CompiledTemplates, we have to inject ::Wx there.
20
+ ActionView::Base::CompiledTemplates.send(:include, ::Wx)
21
+
22
+ Reactive::View::Wx::Template.load_helpers
data/lib/request.rb ADDED
@@ -0,0 +1,14 @@
1
+ require 'reactive'
2
+
3
+ module Reactive
4
+ module View
5
+ module Wx
6
+
7
+ class Request < Reactive::Request
8
+ attr_accessor :local_assigns
9
+ end
10
+
11
+ end
12
+ end
13
+ end
14
+
data/lib/template.rb ADDED
@@ -0,0 +1,114 @@
1
+ require 'action_view_init'
2
+
3
+ module Reactive
4
+ module View
5
+ module Wx
6
+
7
+ class RubyCodeTemplateHandler < ActionView::TemplateHandler
8
+ def compile(template)
9
+ template
10
+ end
11
+ end
12
+
13
+ class Template < ActionView::Base
14
+ register_default_template_handler(:rb, RubyCodeTemplateHandler)
15
+
16
+ def self.load_helpers #:nodoc:
17
+ # First load classes (all hosted under the Helper module)
18
+ Dir.entries("#{File.dirname(__FILE__)}/helpers").sort.each do |file|
19
+ next unless file =~ /^([a-z][a-z_]*_class|_classes).rb$/
20
+ require "helpers/#{$1}"
21
+ end
22
+ include Helpers
23
+ ActionView::Base::CompiledTemplates.send(:include, Helpers)
24
+ # Then helper modules
25
+ Dir.entries("#{File.dirname(__FILE__)}/helpers").sort.each do |file|
26
+ next unless file =~ /^([a-z][a-z_]*_helper).rb$/
27
+ require "helpers/#{$1}"
28
+ helper_module_name = $1.camelize
29
+ if Helpers.const_defined?(helper_module_name)
30
+ include Helpers.const_get(helper_module_name)
31
+ ActionView::Base::CompiledTemplates.send(:include, Helpers.const_get(helper_module_name))
32
+ end
33
+ end
34
+ end
35
+
36
+ # ActionView returns :html by default, we don't have any
37
+ def template_format
38
+ @template_format ||= :rb
39
+ end
40
+
41
+ def do_request(hash)
42
+ Base.do_request(hash)
43
+ end
44
+
45
+ # We accept the rendering of a plain file (not a partial) that lies in the current view directory
46
+ # For this, simply pass the name of the view like: render "create.xrc"
47
+ def render(options = {}, old_local_assigns = {}, &block)
48
+ if options.is_a?(String) && !options.include?('/')
49
+ super(File.join(controller.class.controller_path, options), old_local_assigns, &block)
50
+ else
51
+ super
52
+ end
53
+ end
54
+
55
+ # handles format specification in the template_path.
56
+ # So it is possible to say: render "show.xrc", meaning XRC is the format and any available handler will
57
+ # be used. So the file may either be "show.xrc.erb" or "show.src.builder" or any custum registered handler.
58
+ def render_file(template_path, use_full_path = true, local_assigns = {}) #:nodoc:
59
+ if controller && controller.request.respond_to?(:local_assigns) && controller.request.local_assigns
60
+ local_assigns.merge!(controller.request.local_assigns)
61
+ end
62
+
63
+ template_path_without_format, template_format = path_and_extension(template_path)
64
+ if template_format && !File.basename(template_path_without_format).include?('.')
65
+ @template_format = template_format.to_sym
66
+ super(template_path_without_format, use_full_path, local_assigns)
67
+ else
68
+ super
69
+ end
70
+ end
71
+
72
+ # The result of the rendering is used to create a Wx object (except when the format is :rb which means it is code)
73
+ def render_template(template_extension, template, file_path = nil, local_assigns = {}) #:nodoc:
74
+ output = super
75
+ if template_format == :xrc
76
+ template_key = file_path || template
77
+ parent = local_assigns[:parent_window]
78
+ load_xrc(template_key, output, parent)
79
+ else
80
+ output
81
+ end
82
+ end
83
+
84
+ # The controller may extend this object, especially with helpers
85
+ # Because we have compiled templates, when rendering such templates they
86
+ # are hosted in the ActionView::Base::CompiledTemplates module.
87
+ # This becomes a problem when a compiled template wants to access helper constants,
88
+ # they are hosted under XXXHelper and also in the controller master_helper_module.
89
+ # This method will also include the passed module into CompiledTemplates, so that everything
90
+ # is accessable. Note that this may break the class unloading feature for development mode.
91
+ def extend(*modules)
92
+ ActionView::Base::CompiledTemplates.send(:include, *modules)
93
+ super
94
+ end
95
+
96
+ private
97
+
98
+ def load_xrc(template_key, data, parent)
99
+ return nil # Not implemented.... not on my priority list
100
+ Xrc.instance.unload_object(template_key)
101
+ Xrc.instance.load_data(template_key, data)
102
+ each_toplevel_object(data) do |klass, name|
103
+ Xrc.instance.load_object(parent, name, klass)
104
+ end
105
+ end
106
+
107
+ def each_toplevel_object(xml)
108
+ end
109
+
110
+ end
111
+
112
+ end
113
+ end
114
+ end
data/lib/version.rb ADDED
@@ -0,0 +1,13 @@
1
+ module Reactive
2
+ module View
3
+ module Wx
4
+ module VERSION #:nodoc:
5
+ MAJOR = 0
6
+ MINOR = 1
7
+ TINY = 0
8
+
9
+ STRING = [MAJOR, MINOR, TINY].join('.')
10
+ end
11
+ end
12
+ end
13
+ end
data/lib/xrc_pepper.rb ADDED
@@ -0,0 +1,253 @@
1
+ #
2
+ # wxRuby extensions for XRC
3
+ #
4
+ # Author: Pascal Hurni
5
+ # License: MIT
6
+ #
7
+
8
+ require 'wx'
9
+ require 'wx_sugar/event_connector' # for listen()
10
+ require 'singleton'
11
+
12
+ #
13
+ # Access to Window children
14
+ # Injected into Wx::Window
15
+ #
16
+
17
+ module WindowEnumerable
18
+ include Enumerable
19
+
20
+ # ruby way to iterate over children
21
+ def each
22
+ get_children.each {|item| yield item}
23
+ end
24
+
25
+ # iterate over children and all descendant
26
+ def each_descendant(&block)
27
+ each {|item| block.call(item); item.each_descendant(block) }
28
+ end
29
+
30
+ # access children window by name directly as attribute reader
31
+ def method_missing(name, *args)
32
+ if [:ok, :cancel, :yes, :no].include?(name)
33
+ win = Wx::Window.find_window_by_name("wxID_#{name.to_s.upcase}", self)
34
+ return win if win
35
+ end
36
+ Wx::Window.find_window_by_name(name.to_s, self) || super
37
+ end
38
+ end
39
+
40
+ module MenuBarEnumerable
41
+ include Enumerable
42
+
43
+ def each
44
+ index = 0
45
+ while index < get_menu_count
46
+ yield get_menu(index)
47
+ index += 1
48
+ end
49
+ end
50
+
51
+ # find a menu_item in any of the bar's menu
52
+ def method_missing(name, *args)
53
+ each do |menu|
54
+ item = menu.find_item_by_name(name)
55
+ return item if item
56
+ end
57
+ super
58
+ end
59
+ end
60
+
61
+ module MenuEnumerable
62
+ include Enumerable
63
+
64
+ def each
65
+ index = 0
66
+ while index < get_menu_item_count
67
+ yield find_item_by_position(index)
68
+ index += 1
69
+ end
70
+ end
71
+
72
+ def find_item_by_name(name)
73
+ item = find_item(Wx::xrcid(name.to_s))
74
+ item == Wx::NOT_FOUND ? nil : item
75
+ end
76
+
77
+ def method_missing(name, *args)
78
+ find_item_by_name(name.to_s) || super
79
+ end
80
+ end
81
+
82
+ module AuiManagerEnumerable
83
+ include Enumerable
84
+
85
+ # alias_method :each, :each_pane
86
+
87
+ def method_missing(name, *args)
88
+ pi = get_pane(name.to_s)
89
+ pi.ok? ? pi : super
90
+ end
91
+ end
92
+
93
+
94
+ #
95
+ # Easily bind method named after this pattern: on_#{control_name}_#{event_name}
96
+ # to the corresponding event.
97
+ # Injected into Wx::EvtHandler
98
+ #
99
+ module EventBinder
100
+
101
+ def load_and_bind(options = {})
102
+ options[:name] ||= self.class.to_s
103
+ options[:class] ||= "wx" + self.class.ancestors.find {|ancestor| ancestor.to_s =~ /Wxruby2::/}.to_s.split("Wxruby2::")[1]
104
+ Xrc.instance.bind_object_subclass(self, options[:parent], options[:name], options[:class])
105
+
106
+ # needed anymore? Xrc.instance.bind_menu_bar(self, options[:menu]) if options[:menu]
107
+ end
108
+
109
+ #
110
+ # A little more rubyesque version of wxSugar#listen method
111
+ # Pass the window (control) to be bound and then a hash with event name as keys and method name as value
112
+ # (You may also pass a Proc as value)
113
+ #
114
+ def _bind(window, events)
115
+ events.each do |event, method|
116
+ case method
117
+ when Symbol
118
+ listen(event, window, method)
119
+ when Proc
120
+ listen(event, window, nil, &method)
121
+ end
122
+ end
123
+ end
124
+
125
+ def bind_standard_buttons
126
+ # bind the close button (something like a cross on top-right corner)
127
+ if respond_to? :on_close
128
+ arity = method(:on_close).arity
129
+ evt_close {|event| arity == 0 ? on_close : on_close(event)}
130
+ end
131
+
132
+ # bind the buttons with standard wxID_*
133
+ select{|item| item.kind_of?(Wx::Button) && item.name[0..4] == "wxID_"}.each do |button|
134
+ method_name = "on_#{button.name[5..-1].downcase}"
135
+ arity = method(method_name).arity
136
+ evt_button(button.get_id) {|event| arity == 0 ? send(method_name) : send(method_name, event)} if respond_to? method_name
137
+ end
138
+ end
139
+
140
+ def bind_events
141
+ # get all methods that are named 'on_*'
142
+ methods = self.methods.select{|method| method[0..2] == "on_" }
143
+
144
+ # for each control in this window
145
+ each do |control|
146
+ # iterate over the methods that target the current control (named 'on_#{control.name}_*')
147
+ methods.grep(Regexp.new("^on_#{control.name}_(.*)")) {|method| [$1,method]}.each do |event,method|
148
+ # bind the found method with the event
149
+ listen(event, control, method)
150
+ end
151
+ end
152
+ end
153
+
154
+ def bind_menus
155
+ # get all methods that are named 'on_*_menu'
156
+ self.methods.grep(/^on_(.*)_menu$/) {|method| [$1,method]}.each do |name,method|
157
+ # bind the found method with the event
158
+ evt_menu(Wx::xrcid(name), method)
159
+ end
160
+ end
161
+
162
+ end
163
+
164
+ =begin obsolete
165
+ #
166
+ # XrcDialog
167
+ # subclass your dialog from this class instead of Wx::Dialog
168
+ # so that button events are automatically bound to methods +on_XXX+ where XXX is the button name
169
+ #
170
+ class XrcFrame < Wx::Frame
171
+ def initialize(*args)
172
+ super
173
+ Xrc.instance.bind_frame_subclass(self)
174
+ end
175
+ end
176
+
177
+ class XrcDialog < Wx::Dialog
178
+ def initialize(*args)
179
+ super
180
+ Xrc.instance.bind_dialog_subclass(self)
181
+ end
182
+ end
183
+ =end
184
+
185
+ #
186
+ # Class to handle XRC
187
+ # This is a Singleton, so access it from everywhere with Xrc.instance
188
+ #
189
+ class Xrc < Wx::XmlResource
190
+ include ::Singleton
191
+
192
+ def initialize
193
+ super
194
+ init_all_handlers
195
+ end
196
+
197
+ def bind_object_subclass(win, parent = nil, name = win.class.to_s, klass = "wx#{win.class.to_s}")
198
+ raise StandardError unless load_object(win, parent, name, klass)
199
+ bind(win)
200
+ true
201
+ end
202
+
203
+ def bind_dialog_subclass(win, parent = nil, name = win.class.to_s)
204
+ raise StandardError unless load_dialog_subclass(win, parent, name)
205
+ bind(win)
206
+ true
207
+ end
208
+
209
+ def bind_frame_subclass(win, parent = nil, name = win.class.to_s)
210
+ raise StandardError unless load_frame_subclass(win, parent, name)
211
+ bind(win)
212
+ true
213
+ end
214
+
215
+ def bind_menu_bar(win, name)
216
+ load_menu_bar(win, name)
217
+ win.send(:bind_menus)
218
+ end
219
+
220
+ protected
221
+ def bind(win)
222
+ win.send(:bind_events)
223
+ win.send(:bind_standard_buttons)
224
+ win.send(:bind_menus)
225
+ end
226
+
227
+ end
228
+
229
+ module Accessors
230
+ module ControlWithItems
231
+ def value
232
+ val = get_item_data(get_selection)
233
+ val.kind_of?(ActiveRecord::Base) ? val.id : val
234
+ end
235
+ end
236
+ end
237
+
238
+
239
+
240
+ # WARNING: module WxRubyStyleAccessors is a mixin which also redefines method_missing. So it catches first.
241
+ # Thus, we first extend Dialog so that our sugar is before in the chain!
242
+ Wx::Dialog.send(:include, WindowEnumerable)
243
+ Wx::Panel.send(:include, WindowEnumerable)
244
+ Wx::Frame.send(:include, WindowEnumerable)
245
+ Wx::Window.send(:include, WindowEnumerable)
246
+
247
+ Wx::MenuBar.send(:include, MenuBarEnumerable)
248
+ Wx::Menu.send(:include, MenuEnumerable)
249
+
250
+ # Our EventBinder is useful for any class that has events
251
+ Wx::EvtHandler.send(:include, EventBinder)
252
+
253
+ Wx::ControlWithItems.send(:include, Accessors::ControlWithItems)