reactive-wx 0.2.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.
- data/LICENSE +20 -0
- data/Manifest +45 -0
- data/README +22 -0
- data/Rakefile +5 -0
- data/lib/reactive-wx.rb +19 -0
- data/lib/reactive-wx/accessors.rb +15 -0
- data/lib/reactive-wx/accessors/control_with_items.rb +22 -0
- data/lib/reactive-wx/accessors/date_picker_ctrl.rb +17 -0
- data/lib/reactive-wx/accessors/text_ctrl.rb +17 -0
- data/lib/reactive-wx/binder.rb +49 -0
- data/lib/reactive-wx/default_handler.rb +50 -0
- data/lib/reactive-wx/helpers.rb +10 -0
- data/lib/reactive-wx/helpers/asset_helper.rb +21 -0
- data/lib/reactive-wx/helpers/exception_helper.rb +82 -0
- data/lib/reactive-wx/helpers/forms.rb +40 -0
- data/lib/reactive-wx/request.rb +13 -0
- data/lib/reactive-wx/wx_ext.rb +42 -0
- data/lib/reactive-wx/wx_ext/arranger.rb +33 -0
- data/lib/reactive-wx/wx_ext/aui_toolbar.rb +22 -0
- data/lib/reactive-wx/wx_ext/event_binder.rb +11 -0
- data/lib/reactive-wx/wx_ext/form_grid_sizer.rb +54 -0
- data/lib/reactive-wx/wx_ext/message_dialog.rb +62 -0
- data/lib/reactive-wx/wx_ext/panel_dialog.rb +14 -0
- data/lib/reactive-wx/wx_ext/semi_modal.rb +233 -0
- data/lib/reactive-wx/wx_ext/toolbar.rb +29 -0
- data/lib/reactive-wx/wx_ext/window.rb +16 -0
- data/reactive_app_generators/wx/USAGE +6 -0
- data/reactive_app_generators/wx/templates/application_helper.wx.rb +8 -0
- data/reactive_app_generators/wx/templates/layout.wx.erb +2 -0
- data/reactive_app_generators/wx/templates/main_controller.rb +10 -0
- data/reactive_app_generators/wx/templates/main_helper.wx.rb +9 -0
- data/reactive_app_generators/wx/templates/run.wx.erb +22 -0
- data/reactive_app_generators/wx/templates/show.wx.erb +2 -0
- data/reactive_app_generators/wx/wx_generator.rb +54 -0
- data/reactive_generators/view/USAGE +11 -0
- data/reactive_generators/view/templates/create.wx.rb +0 -0
- data/reactive_generators/view/templates/delete.wx.rb +0 -0
- data/reactive_generators/view/templates/destroy.wx.rb +0 -0
- data/reactive_generators/view/templates/edit.wx.rb +0 -0
- data/reactive_generators/view/templates/index.wx.rb +0 -0
- data/reactive_generators/view/templates/layout.wx.rb +0 -0
- data/reactive_generators/view/templates/new.wx.rb +0 -0
- data/reactive_generators/view/templates/show.wx.rb +0 -0
- data/reactive_generators/view/templates/update.wx.rb +0 -0
- data/reactive_generators/view/view_generator.rb +25 -0
- metadata +134 -0
@@ -0,0 +1,42 @@
|
|
1
|
+
#
|
2
|
+
# wxRuby extensions
|
3
|
+
# Currently at experimental stage, sparingly tested on Win32 only.
|
4
|
+
#
|
5
|
+
# Author: Pascal Hurni
|
6
|
+
# License: MIT
|
7
|
+
#
|
8
|
+
|
9
|
+
module WxExtensions # :nodoc: all
|
10
|
+
end
|
11
|
+
|
12
|
+
require 'wx'
|
13
|
+
require 'reactive-wx/wx_ext/window'
|
14
|
+
require 'reactive-wx/wx_ext/event_binder'
|
15
|
+
require 'reactive-wx/wx_ext/message_dialog'
|
16
|
+
require 'reactive-wx/wx_ext/panel_dialog'
|
17
|
+
require 'reactive-wx/wx_ext/semi_modal'
|
18
|
+
require 'reactive-wx/wx_ext/toolbar'
|
19
|
+
require 'reactive-wx/wx_ext/aui_toolbar'
|
20
|
+
require 'reactive-wx/wx_ext/form_grid_sizer'
|
21
|
+
require 'reactive-wx/wx_ext/arranger'
|
22
|
+
|
23
|
+
# WARNING: module WxRubyStyleAccessors is a mixin which also redefines method_missing. So it catches first.
|
24
|
+
# Thus, we first extend Dialog so that our sugar is before in the chain!
|
25
|
+
Wx::Dialog.send(:include, WxExtensions::Window)
|
26
|
+
Wx::Window.send(:include, WxExtensions::Window)
|
27
|
+
|
28
|
+
Wx::EvtHandler.send(:include, WxExtensions::EventBinder)
|
29
|
+
Wx::Dialog.send(:include, WxExtensions::SemiModalDialog)
|
30
|
+
silence_warnings { Wx::const_set(:MessageDialog, WxExtensions::MessageDialog) }
|
31
|
+
Wx::ToolBar.send(:include, WxExtensions::ToolBar)
|
32
|
+
Wx::AuiToolBar.send(:include, WxExtensions::AuiToolBar) if defined? Wx::AuiToolBar
|
33
|
+
|
34
|
+
# WARNING: module WxSugar::Arranger was monkey patched in wx_ext/arranger.rb
|
35
|
+
|
36
|
+
unless Wx::Window.instance_methods.include? 'bring_to_front'
|
37
|
+
# simple solution for feature request #1227
|
38
|
+
class Wx::Window
|
39
|
+
alias_method :bring_to_front, :raise
|
40
|
+
remove_method :raise
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# TODO: Currently uses monkey patching, because WxSugar::Arranger is already a mix-in module.
|
2
|
+
module WxSugar # :nodoc: all
|
3
|
+
module Arranger
|
4
|
+
# takes hash arguments +layout+
|
5
|
+
#
|
6
|
+
# :rows - integer, number of rows (mandatory, see below)
|
7
|
+
# :cols - integer, number of columns (mandatory, see below)
|
8
|
+
# :vgap - integer, extra vertical space between each child (optional)
|
9
|
+
# :hgap - integer, extra horizontal space between each child (optional)
|
10
|
+
#
|
11
|
+
# At least one of +:rows+ and +:cols+ must be specified. If one is not
|
12
|
+
# specified, the other will be calculated dynamically based on the
|
13
|
+
# total number of child widgets added.
|
14
|
+
#
|
15
|
+
def arrange_formgrid(layout, &block)
|
16
|
+
Kernel.raise ArgumentError, "Pass eihter :cols or :rows, not both!" if layout[:cols] && layout[:rows]
|
17
|
+
# if layout[:padding]
|
18
|
+
# layout[:vgap] = layout[:hgap] = layout[:padding]
|
19
|
+
# end
|
20
|
+
|
21
|
+
# wxruby wants them in this order, and with nought if null
|
22
|
+
args = [ :vgap, :hgap ].map { | arg | layout[arg] or 0 }
|
23
|
+
sizer = WxExtensions::FormGridSizer.new(layout[:rows], layout[:cols], *args)
|
24
|
+
arrange( sizer, layout, &block )
|
25
|
+
end
|
26
|
+
|
27
|
+
def hints_to_constants_with_formgrid(layout_hints)
|
28
|
+
hints_to_constants_without_formgrid(layout_hints) + (layout_hints[:span] ? 0x10000000 : 0)
|
29
|
+
end
|
30
|
+
|
31
|
+
alias_method_chain :hints_to_constants, :formgrid
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module WxExtensions
|
2
|
+
module AuiToolBar
|
3
|
+
def self.included(base) #:nodoc:
|
4
|
+
# base.send :alias_method_chain, :initialize, :extension
|
5
|
+
base.send :alias_method_chain, :add_tool, :extension
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize_with_extension(*args)
|
9
|
+
initialize_without_extension(*args)
|
10
|
+
if block_given?
|
11
|
+
yield self
|
12
|
+
realize
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def add_tool_with_extension(*args, &block)
|
17
|
+
item = add_tool_without_extension(*args)
|
18
|
+
evt_tool(item.get_id, &block) if block
|
19
|
+
item
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module WxExtensions
|
2
|
+
# Adds a cooked way of connecting events to handler.
|
3
|
+
# Will be injected into Wx::EvtHandler
|
4
|
+
module EventBinder
|
5
|
+
def cooked_connect(event_name, window_or_id, meth = nil, &block)
|
6
|
+
handler = acquire_handler(meth, block)
|
7
|
+
id = acquire_id(window_or_id)
|
8
|
+
connect(id, Wx::ID_ANY, self.class.event_type_for_name("evt_#{event_name}".to_sym), &handler)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module WxExtensions
|
2
|
+
class FormGridSizer < Wx::GridBagSizer
|
3
|
+
def initialize(rows, cols, hgap, vgap)
|
4
|
+
super(hgap, vgap)
|
5
|
+
|
6
|
+
@cols, @rows = cols, rows
|
7
|
+
@cols = 1 if @cols.nil? && @rows.nil?
|
8
|
+
#puts "#{self} arrange: c:#{@cols} r:#{@rows}"
|
9
|
+
|
10
|
+
@span = @cols ? Wx::GBSpan.new(1,2) : Wx::GBSpan.new(2,1)
|
11
|
+
@defaultspan = Wx::GBSpan.new(1,1)
|
12
|
+
|
13
|
+
@row = @col = 0
|
14
|
+
|
15
|
+
if @cols
|
16
|
+
1.step(@cols*2, 2) {|i| add_growable_col(i, 1); "puts grow: #{i}"}
|
17
|
+
else
|
18
|
+
add_growable_col(1, 1)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def add(child, prop = 0, flag = 0, border = 0, userdata = nil)
|
23
|
+
span = (flag & 0x10000000 == 0x10000000) || child.is_a?(FormGridSizer)
|
24
|
+
#puts "#{self} putting at r:#{@row}, c:#{@col} #{child.class} #{flag} #{span}"
|
25
|
+
item = super(child, Wx::GBPosition.new(@row, @col), span ? @span : @defaultspan, flag, border, userdata)
|
26
|
+
add_growable_row(@row, prop) if span
|
27
|
+
move_next
|
28
|
+
move_next if span
|
29
|
+
item
|
30
|
+
end
|
31
|
+
|
32
|
+
protected
|
33
|
+
|
34
|
+
def move_next()
|
35
|
+
if @cols
|
36
|
+
if (@col += 1) >= @cols * 2
|
37
|
+
@row += 1
|
38
|
+
@col = 0
|
39
|
+
end
|
40
|
+
else
|
41
|
+
if (@col += 1) % 2 == 0
|
42
|
+
if (@row += 1) % @rows == 0
|
43
|
+
@row = 0
|
44
|
+
#puts "grow: #{@col+1}"
|
45
|
+
add_growable_col(@col+1, 1)
|
46
|
+
else
|
47
|
+
@col -=2
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module WxExtensions
|
2
|
+
# A class to allow modeless message dialogs
|
3
|
+
# The code is ugly as it is a quick translation of the generic MessageDialog C source code
|
4
|
+
class MessageDialog < Wx::Dialog
|
5
|
+
|
6
|
+
def initialize(parent, *args)
|
7
|
+
message = args[0] if args[0]
|
8
|
+
caption = args[1] ? args[1] : 'Message'
|
9
|
+
style = args[2] ? args[2] : Wx::OK | Wx::CENTRE
|
10
|
+
pos = args[3] ? args[3] : Wx::DEFAULT_POSITION
|
11
|
+
if (options = args.last).is_a? Hash
|
12
|
+
message = options[:message] if options[:message]
|
13
|
+
caption = options[:caption] if options[:caption]
|
14
|
+
style = options[:style] if options[:style]
|
15
|
+
pos = options[:pos] if options[:pos]
|
16
|
+
end
|
17
|
+
|
18
|
+
dialog_style = (style & (Wx::OK|Wx::CANCEL|Wx::YES|Wx::NO|Wx::HELP|Wx::NO_DEFAULT)) == 0 ? Wx::CAPTION : Wx::DEFAULT_DIALOG_STYLE
|
19
|
+
super(parent, Wx::ID_ANY, caption, pos, Wx::DEFAULT_SIZE, dialog_style)
|
20
|
+
@parent = parent # for SemiModalDialog
|
21
|
+
|
22
|
+
top_sizer = Wx::BoxSizer.new(Wx::VERTICAL)
|
23
|
+
icon_text = Wx::BoxSizer.new(Wx::HORIZONTAL)
|
24
|
+
|
25
|
+
if (style & Wx::ICON_MASK) != 0
|
26
|
+
@@icon_map ||= {Wx::ICON_ERROR => Wx::ART_ERROR, Wx::ICON_INFORMATION => Wx::ART_INFORMATION, Wx::ICON_WARNING => Wx::ART_WARNING, Wx::ICON_QUESTION => Wx::ART_QUESTION}
|
27
|
+
@@icon_map.default ||= Wx::ART_ERROR
|
28
|
+
icon_text.add(Wx::StaticBitmap.new(self, Wx::ID_ANY, Wx::ArtProvider.get_icon(@@icon_map[style & Wx::ICON_MASK], Wx::ART_MESSAGE_BOX)), 0, Wx::CENTER)
|
29
|
+
end
|
30
|
+
|
31
|
+
icon_text.add(Wx::StaticText.new(self, Wx::ID_ANY, message.gsub('&','&&')), 0, Wx::ALIGN_CENTER | Wx::LEFT, 10)
|
32
|
+
top_sizer.add(icon_text, 1, Wx::CENTER | Wx::LEFT|Wx::RIGHT|Wx::TOP, 10)
|
33
|
+
|
34
|
+
center_flag = Wx::EXPAND
|
35
|
+
center_flag = Wx::ALIGN_CENTRE if (style & Wx::YES_NO) != 0
|
36
|
+
center_flag = Wx::ALIGN_CENTRE if RUBY_PLATFORM =~ /win/
|
37
|
+
sizer_btn = create_button_sizer(style & (Wx::OK|Wx::CANCEL|Wx::YES|Wx::NO|Wx::HELP|Wx::NO_DEFAULT))
|
38
|
+
top_sizer.add(sizer_btn, 0, center_flag | Wx::ALL, 10)
|
39
|
+
|
40
|
+
set_auto_layout(true)
|
41
|
+
set_sizer(top_sizer)
|
42
|
+
|
43
|
+
top_sizer.set_size_hints(self)
|
44
|
+
top_sizer.fit(self)
|
45
|
+
size = get_size
|
46
|
+
if size.get_width < size.get_height*3/2
|
47
|
+
size.set_width(size.get_height*3/2)
|
48
|
+
set_size(size)
|
49
|
+
end
|
50
|
+
|
51
|
+
centre(Wx::BOTH | Wx::CENTER_FRAME)
|
52
|
+
|
53
|
+
evt_button(Wx::ID_YES) { end_modal(Wx::ID_YES) }
|
54
|
+
evt_button(Wx::ID_NO) { end_modal(Wx::ID_NO) }
|
55
|
+
evt_button(Wx::ID_CANCEL) do
|
56
|
+
# Allow cancellation via ESC/Close button except if only YES and NO are specified.
|
57
|
+
end_modal(Wx::ID_CANCEL) if (style & Wx::YES_NO) != Wx::YES_NO || (style & Wx::CANCEL) != 0
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module WxExtensions
|
2
|
+
class PanelDialog < Wx::Dialog
|
3
|
+
attr_reader :panel
|
4
|
+
|
5
|
+
def initialize(*args)
|
6
|
+
super(*args, &nil) # We explicitely pass a nil block because WxSugar would call the block (We'll call it with a return value...)
|
7
|
+
arrange_vertically
|
8
|
+
@panel = yield self
|
9
|
+
nest(@panel, :proportion => 1)
|
10
|
+
# TODO: set size to the best size
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,233 @@
|
|
1
|
+
module WxExtensions
|
2
|
+
# This class acts like a Wx::Panel but will be the root for semi-modal windows (or dialogs)
|
3
|
+
# When any children of this RootPanel invokes semi-modal, all the children of this panel will be disabled,
|
4
|
+
# and only the semi-modal window will be active.
|
5
|
+
class RootPanel < Wx::Panel
|
6
|
+
|
7
|
+
# Look for the topmost RootPanel in the ancestors
|
8
|
+
def self.find_root_panel(current)
|
9
|
+
# If current is already a top level, look for a RootPanel in his parent
|
10
|
+
current = current.get_parent if current.is_a? Wx::TopLevelWindow
|
11
|
+
|
12
|
+
root_panel = nil
|
13
|
+
begin
|
14
|
+
case current
|
15
|
+
when nil
|
16
|
+
break
|
17
|
+
when RootPanel
|
18
|
+
root_panel = current
|
19
|
+
when Wx::TopLevelWindow
|
20
|
+
break
|
21
|
+
end
|
22
|
+
current = current.get_parent
|
23
|
+
end while current
|
24
|
+
|
25
|
+
raise StandardError.new("There are no RootPanel in the ancestors!") if root_panel.nil?
|
26
|
+
root_panel
|
27
|
+
end
|
28
|
+
|
29
|
+
def disable_children
|
30
|
+
@screener = Wx::Frame.new(self, :style => #Wx::FRAME_TOOL_WINDOW |
|
31
|
+
Wx::FRAME_FLOAT_ON_PARENT |
|
32
|
+
Wx::FRAME_NO_TASKBAR |
|
33
|
+
#Wx::NO_BORDER |
|
34
|
+
0,
|
35
|
+
:size => self.size, :pos => self.get_screen_position)
|
36
|
+
@screener.set_background_colour(Wx::SystemSettings.get_colour(Wx::SYS_COLOUR_ACTIVECAPTION))
|
37
|
+
@screener.set_transparent(128)
|
38
|
+
@screener.show
|
39
|
+
|
40
|
+
top_level = find_top_level
|
41
|
+
|
42
|
+
# Hooks to handle moving and resizing
|
43
|
+
resize_block = proc do |event|
|
44
|
+
update_screener
|
45
|
+
@user_resize_block.call if @user_resize_block
|
46
|
+
event.skip
|
47
|
+
end
|
48
|
+
top_level.evt_moving() {|event| update_screener; event.skip}
|
49
|
+
top_level.evt_move() {|event| update_screener; event.skip}
|
50
|
+
evt_sizing(&resize_block)
|
51
|
+
evt_size(&resize_block)
|
52
|
+
|
53
|
+
# Hooks for handling showing/hiding
|
54
|
+
@screener.evt_activate() do |event|
|
55
|
+
@user_visible_block.call(true) if @user_visible_block && event.get_active
|
56
|
+
event.skip
|
57
|
+
end
|
58
|
+
evt_set_focus() do |event|
|
59
|
+
@user_visible_block.call(true) if @user_visible_block
|
60
|
+
event.skip # TODO: Not sure if this is wanted... to be checked on the different platforms
|
61
|
+
end
|
62
|
+
@timer = Wx::Timer.every(100) do
|
63
|
+
# TODO: This timer may tick after window deletion (when the app exits) and thus crash on the *is_shown* method. DONE with evt_window_destroy
|
64
|
+
if (shown = is_shown) != @shown
|
65
|
+
@shown = shown
|
66
|
+
# handle screener
|
67
|
+
if @screener
|
68
|
+
update_screener if shown
|
69
|
+
@screener.show(shown)
|
70
|
+
end
|
71
|
+
# handler user window
|
72
|
+
@user_resize_block.call if @user_resize_block && shown
|
73
|
+
@user_visible_block.call(shown) if @user_visible_block
|
74
|
+
end
|
75
|
+
end
|
76
|
+
evt_window_destroy() do |event|
|
77
|
+
@timer.stop if @timer
|
78
|
+
event.skip
|
79
|
+
end
|
80
|
+
|
81
|
+
# Hook to handle client closing
|
82
|
+
# TODO: BUG: event handler used to be on the top_level window, now on the root panel. Test it. This change moves wxruby to be unstable
|
83
|
+
evt_close() do |event|
|
84
|
+
veto = nil
|
85
|
+
veto = @user_close_block.call(event) if @user_close_block
|
86
|
+
veto ? event.veto : event.skip
|
87
|
+
end
|
88
|
+
|
89
|
+
=begin only when the patched version of wxAui will be commited in wxWidgets trunk
|
90
|
+
# Is the TopLevelWindow of this root panel managed by Aui?
|
91
|
+
handler = top_level.get_event_handler
|
92
|
+
begin
|
93
|
+
# puts "PROCESSING handler #{handler}"
|
94
|
+
aui_manager = case handler
|
95
|
+
when Wx::AuiManager
|
96
|
+
handler
|
97
|
+
when Wx::AuiFloatingFrame
|
98
|
+
handler.get_owner_manager
|
99
|
+
else
|
100
|
+
nil
|
101
|
+
end
|
102
|
+
if aui_manager
|
103
|
+
# puts "MANAGED by #{aui_manager}"
|
104
|
+
pi = aui_manager.get_pane(self)
|
105
|
+
# puts "WITH PI #{pi}"
|
106
|
+
if pi
|
107
|
+
@aui_manager = aui_manager
|
108
|
+
@pi_floatable = pi.is_floatable
|
109
|
+
@pi_dockable = pi.is_dockable
|
110
|
+
pi.set_floatable(false).set_dockable(false)
|
111
|
+
#@aui_manager.update
|
112
|
+
end
|
113
|
+
break
|
114
|
+
end
|
115
|
+
end while handler = handler.get_next_handler
|
116
|
+
=end
|
117
|
+
end
|
118
|
+
|
119
|
+
def enable_children
|
120
|
+
if @aui_manager
|
121
|
+
if pi = @aui_manager.get_pane(self)
|
122
|
+
pi.set_floatable(@pi_floatable).set_dockable(@pi_dockable)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
top_level = find_top_level
|
127
|
+
top_level.disconnect(Wx::ID_ANY, Wx::ID_ANY, :evt_moving)
|
128
|
+
top_level.disconnect(Wx::ID_ANY, Wx::ID_ANY, :evt_move)
|
129
|
+
disconnect(Wx::ID_ANY, Wx::ID_ANY, :evt_close)
|
130
|
+
disconnect(Wx::ID_ANY, Wx::ID_ANY, :evt_sizing)
|
131
|
+
disconnect(Wx::ID_ANY, Wx::ID_ANY, :evt_size)
|
132
|
+
|
133
|
+
@timer.stop if @timer
|
134
|
+
@user_resize_block = nil
|
135
|
+
@user_visible_block = nil
|
136
|
+
|
137
|
+
@screener.destroy
|
138
|
+
@screener = nil
|
139
|
+
end
|
140
|
+
|
141
|
+
# The passed block will be called when the RootPanel is resized.
|
142
|
+
def on_resize(&block)
|
143
|
+
@user_resize_block = block
|
144
|
+
end
|
145
|
+
|
146
|
+
# The passed block will be called when the RootPanel is activated or gains focus.
|
147
|
+
# The block should receive one argument which will be a boolean indicating if it should be made visible.
|
148
|
+
# Note that setting your window visible may not be enough, #raise should put it in front.
|
149
|
+
def on_visible(&block)
|
150
|
+
@user_visible_block = block
|
151
|
+
end
|
152
|
+
|
153
|
+
# The passed block will be called when the TopLevel window of this RootPanel is requested
|
154
|
+
# to close. The return code of the block is a boolean value indicating if the close should be vetoed.
|
155
|
+
# (Thus the normal block is: { not close }
|
156
|
+
def on_close(&block)
|
157
|
+
@user_close_block = block
|
158
|
+
end
|
159
|
+
|
160
|
+
protected
|
161
|
+
|
162
|
+
def update_screener
|
163
|
+
@screener.set_size(Wx::Rect.new(get_screen_position, size))
|
164
|
+
end
|
165
|
+
|
166
|
+
# don't memoize this method, because the top level may change when docking/floating this panel
|
167
|
+
def find_top_level
|
168
|
+
# Look for the first top_level window in the ancestors
|
169
|
+
top_level = self
|
170
|
+
top_level = top_level.get_parent until top_level.is_top_level
|
171
|
+
top_level
|
172
|
+
end
|
173
|
+
|
174
|
+
end
|
175
|
+
|
176
|
+
# Extension for the Dialog class to allow semi-modal dialogs
|
177
|
+
module SemiModalDialog
|
178
|
+
|
179
|
+
def self.included(base) #:nodoc:
|
180
|
+
base.send :alias_method_chain, :end_modal, :semi_handling
|
181
|
+
base.send :alias_method_chain, :is_modal, :semi_handling
|
182
|
+
end
|
183
|
+
|
184
|
+
# shows the dialog semi-modally.
|
185
|
+
# This method will return immediately, you should pass a block to allow processing
|
186
|
+
# when the dialog is dismissed. The block will be passed the returned ID
|
187
|
+
# Example:
|
188
|
+
# dlg.show_semi_modal do |id|
|
189
|
+
# case id
|
190
|
+
# when Wx::ID_OK
|
191
|
+
# ...
|
192
|
+
# when Wx::ID_CANCEL
|
193
|
+
# ...
|
194
|
+
# end
|
195
|
+
# end
|
196
|
+
def show_semi_modal(destroy_on_close = true, &block)
|
197
|
+
@root_panel = RootPanel.find_root_panel(@parent || self) # @parent may be set by MessageDialog
|
198
|
+
|
199
|
+
@semi_modal_block = block
|
200
|
+
@showing_semi_modal = true
|
201
|
+
@destroy_on_close = destroy_on_close
|
202
|
+
|
203
|
+
# FIXME: Until wxRuby 2.0.0 fix the issue #, we have to handle the dismiss ourselves
|
204
|
+
evt_close { end_modal_with_semi_handling(Wx::ID_CANCEL) }
|
205
|
+
evt_button(Wx::ID_CANCEL) { end_modal_with_semi_handling(Wx::ID_CANCEL) }
|
206
|
+
# END OF FIXME
|
207
|
+
|
208
|
+
@root_panel.on_visible {|visible| show(visible); bring_to_front if visible }
|
209
|
+
@root_panel.on_resize { set_size(get_rect.centre_in(@root_panel.get_screen_rect)) }
|
210
|
+
@root_panel.on_close { !close }
|
211
|
+
@root_panel.disable_children
|
212
|
+
|
213
|
+
# Show dialog
|
214
|
+
centre_on_parent
|
215
|
+
show
|
216
|
+
end
|
217
|
+
|
218
|
+
def is_modal_with_semi_handling
|
219
|
+
@showing_semi_modal || is_modal_without_semi_handling
|
220
|
+
end
|
221
|
+
|
222
|
+
def end_modal_with_semi_handling(code)
|
223
|
+
return end_modal_without_semi_handling(code) unless @showing_semi_modal
|
224
|
+
|
225
|
+
@root_panel.enable_children
|
226
|
+
|
227
|
+
@semi_modal_block.call(code) if @semi_modal_block
|
228
|
+
@showing_semi_modal = false
|
229
|
+
@destroy_on_close ? destroy : hide
|
230
|
+
end
|
231
|
+
|
232
|
+
end
|
233
|
+
end
|