reactive-wx 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|