tkxxs 0.1.1 → 0.1.2

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 CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- ZjhkMTczM2I5YzdkZTkwZTQ0NGRlZDI2NGZhNDM1ZGZhYTEwZWQzNA==
4
+ OTNlZTU3NjY4YTQ5ZWMxYmFjOTM5YjlkZDhjYWM3ZmNkODA1MTM5Yw==
5
5
  data.tar.gz: !binary |-
6
- MDVlYWM1NWE4YTE2MTY4YTVkODNkZjBhZmFiMGIxOGNhZWI0YjU3MA==
6
+ ZDBjMDA2MmEyODBjNzA4OWIwODdmMmJhNzNlMDc5ZTNkM2MwOWI0NQ==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- MzU2ODQ0OTcwZjQwZTE5YTljNmE2N2JiM2M4NDc5MGQxODljMzMxMmI2Yjdk
10
- MWE1ZDkxYWY5ZjE2NWU4OWMzYjJkYWZhNTI5MTVlNDYzYjkyMjc1NTViNmZk
11
- NjZjNGEwZmZjMjc2ZWFjMWY3OWVlNjczNDk4ZjMxNTc2OWQ5YWY=
9
+ Y2ViN2EwY2ZkMTU1MGE1ZTI1NmI0NGQ1ZmZhZDkyMTcyNTY0OTJlOGEwMGQ3
10
+ NzVlMGE1Zjk1OTBhNzVkYjkxYzkxNjBlOWQ5MjAzYjFjYTBlMjAxMmQ2NzM4
11
+ NzNhZDhhYThiMzc2MzY0MzllNDhjZTAzMWRkMDVlOGNlNGVhOTE=
12
12
  data.tar.gz: !binary |-
13
- MDI1MmQyY2E5ZjJhNGRiYTM1Zjk4ZmM4MzE0ODI3Zjg4YzI0Mjg1OWUxM2Ew
14
- NGEwMzkxN2EzZWI2OWZhNTBkNzZhOTE2YjIyZWZhNzNiYTkyZTA1NzQwZDVi
15
- NThjYjE0OGE1ZDk4NzFiMjRhYmY1NDlmNWM2MTRlZWJlNzA5YWY=
13
+ NTIwNGVjYThkZDdiODljYmZmMjQxMTI2ZmNkMDYxZmVkMzZkYzIzZmE0ZGYz
14
+ Y2U1NjEwMmZmYjYzMDkwMjZlZTFjMGQ3ZGQxNjYzZTdiYWEzYzJmMDU2YjEz
15
+ YWI4NTBhMTRlYzU3ODgzY2RiMDBhYmYyYzU5ZmM0ZWY3MmZhZGE=
@@ -1,2 +1,3 @@
1
1
 
2
- * Axel Friedrich: axel dod friedrich_smail ad gmx dod de
2
+ * Axel Friedrich: axel dod friedrich_smail ad gmx dod de
3
+ * Abinoam P. Marques Jr.
@@ -1,3 +1,13 @@
1
+ === 0.1.2 / 2013-01-05
2
+
3
+ * Made it work on Ubuntu (Many thanks to Abinoam P. Marques Jr.)
4
+ * Fixed a bug in handling configSection. (Can be used now.)
5
+ * Updated documentation and readme.
6
+
7
+ === 0.1.1 / 2014-01-02
8
+
9
+ * Translated remaining German text to English
10
+
1
11
  === 0.1.0 / 2014-01-01
2
12
 
3
13
  * 1 major enhancement
@@ -3,7 +3,7 @@ CONTRIBUTORS
3
3
  History.txt
4
4
  LICENSE
5
5
  Manifest.txt
6
- README.txt
6
+ README.rdoc
7
7
  Rakefile
8
8
  ext/readme.txt
9
9
  ext/tkballoonhelp.rb
@@ -1,6 +1,6 @@
1
1
  = TKXXS
2
2
 
3
- * https://github.com/Axel2
3
+ * https://github.com/Axel2/tkxxs
4
4
 
5
5
  == References
6
6
 
@@ -12,7 +12,7 @@ TKXXS_CLASSES is intended for developers only.
12
12
 
13
13
  == Description
14
14
 
15
- TKXXS provides a very simple and very easy to use GUI (graphical user interface) for Ruby; It gives you a persistent output window and popping up (modal) dialogs for input; For a screenshot, see: images/screenshot.png; Tested on Windows, only.
15
+ TKXXS provides a very simple and very easy to use GUI (graphical user interface) for Ruby; It gives you a persistent output window and popping up (modal) dialogs for input; For a screenshot, see: <tt>https://github.com/Axel2/tkxxs/blob/master/images/screenshot.png</tt>; I tested it on Windows, only; Got user report, that it works on Ubuntu, too.
16
16
 
17
17
  TKXXS shall:
18
18
 
@@ -25,7 +25,7 @@ TKXXS shall:
25
25
 
26
26
 
27
27
  Drawbacks:
28
- * I'v tested it only on Windows. Other operating system probably will need modifications, which I would like to merge in.
28
+ * I'v tested it only on Windows, but got user report, that it works on Ubuntu, too.l
29
29
  * For sure some more drawbacks which I'm not aware of now.
30
30
 
31
31
 
@@ -90,11 +90,43 @@ You close the application simply by clicking the close-icon on top of the output
90
90
  See samples/big_example.rb
91
91
 
92
92
 
93
+ == configSection
94
+
95
+ Normally, you need not care about it.
96
+
97
+ The hash-argument of the dialog methods take as key <tt>:configSection</tt>. The value of this key sets the section name of the configuration file, where configuration setting of this dialog are stored and read from. Configuration settings are, for example: Window size and position, and recent dirs/files and favorite dirs/files.
98
+
99
+ Key may be String, Integer, Float or nil, but not Symbol. nil is the default section.
100
+ * Setting section: Conf#section=
101
+ * Reading the actual section: Conf#section
102
+ * Configuration file path is: Conf#filename (It's YAML)
103
+
104
+ The config section remains unchanged, unless it is set to a new value by either using:
105
+ Conf#section = ...
106
+ or by setting the <tt>:configSection</tt> of the hash-argument of the dialog methods.
107
+
108
+ You can use <tt>:configSection</tt> for example, if you want to have different favorite dirs for two different choose_dir-dialogs. Example code:
109
+
110
+ CONF = Conf.new # This is set inside TKXXS
111
+ ...
112
+ old_section = CONF.section
113
+
114
+ left_dir = choose_dir(
115
+ :configSection=>'left'
116
+ )
117
+
118
+ right_dir = choose_dir(
119
+ :configSection=>'right',
120
+ )
121
+
122
+ CONF.section = old_section
123
+ ...
124
+
93
125
  == Installation
94
126
 
95
127
  === Prerequisites
96
128
 
97
- * Tested only on Windows
129
+ * Tested only on Windows (but user reported that it works on Ubuntu, too.)
98
130
  * Ruby 1.8.7 or 1.9.x with TK (e.g. RubyInstaller)
99
131
  * gem Platform (starting with capital letter "P"!)
100
132
 
@@ -1,332 +1,332 @@
1
- #
2
- # tkballoonhelp.rb : simple balloon help widget
3
- # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp)
4
- #
5
- # Add a balloon help to a widget.
6
- # This widget has only poor featureas. If you need more useful features,
7
- # please try to use the Tix extension of Tcl/Tk under Ruby/Tk.
8
- #
9
- # The interval time to display a balloon help is defined 'interval' option
10
- # (default is 750ms).
11
- #
12
- # Modifications by Axel Friedrich:
13
- # * 2010-03-01:
14
- # * 2010-01-31: Shifting position of balloon if it is out of screen
15
- # * TODO: wraplength
16
- require 'tk'
17
-
18
- module Tk
19
- module RbWidget
20
- class BalloonHelp<TkLabel
21
- end
22
- end
23
- end
24
- class Tk::RbWidget::BalloonHelp<TkLabel
25
- DEFAULT_FOREGROUND = 'black'
26
- DEFAULT_BACKGROUND = 'white'
27
- DEFAULT_INTERVAL = 750
28
-
29
- def _balloon_binding(interval)
30
- @timer = TkAfter.new(interval, 1, proc{show})
31
- def @timer.interval(val)
32
- @sleep_time = val
33
- end
34
- @bindtag = TkBindTag.new
35
- @bindtag.bind('Enter', proc{@timer.start})
36
- @bindtag.bind('Motion', proc{@timer.restart; erase})
37
- @bindtag.bind('Any-ButtonPress', proc{@timer.restart; erase})
38
- @bindtag.bind('Leave', proc{@timer.stop; erase})
39
- tags = @parent.bindtags
40
- idx = tags.index(@parent)
41
- unless idx
42
- ppath = TkComm.window(@parent.path)
43
- idx = tags.index(ppath) || 0
44
- end
45
- tags[idx,0] = @bindtag
46
- @parent.bindtags(tags)
47
- end
48
- private :_balloon_binding
49
-
50
- def initialize(parent=nil, keys={})
51
- @parent = parent || Tk.root
52
-
53
- @frame = TkToplevel.new(@parent)
54
- if defined?($tkxxs_) && $tkxxs_[:userscreenx]
55
- $balloonhlp_ = Hash.new
56
- $balloonhlp_[:userscreenx] = $tkxxs_[:userscreenx]
57
- $balloonhlp_[:userscreeny] = $tkxxs_[:userscreeny]
58
- $balloonhlp_[:userscreenwidth] = $tkxxs_[:userscreenwidth]
59
- $balloonhlp_[:userscreenheight] = $tkxxs_[:userscreenheight]
60
- elsif !defined?($balloonhlp_) || !$balloonhlp_[:userscreenx]
61
- userscreen(@frame)
62
- end
63
- @frame.withdraw
64
- @frame.overrideredirect(true)
65
- @frame.transient(TkWinfo.toplevel(@parent))
66
- @epath = @frame.path
67
-
68
- if keys
69
- keys = _symbolkey2str(keys)
70
- else
71
- keys = {}
72
- end
73
-
74
- @command = keys.delete('command')
75
-
76
- @interval = keys.delete('interval'){DEFAULT_INTERVAL}
77
- _balloon_binding(@interval)
78
-
79
- # @label = TkLabel.new(@frame, 'background'=>'bisque').pack
80
- @label = TkLabel.new(@frame,
81
- ## :wraplength => '2i', # Axel
82
- 'foreground'=>DEFAULT_FOREGROUND,
83
- ## 'background'=>DEFAULT_BACKGROUND).pack # -Axel
84
- 'background'=>DEFAULT_BACKGROUND).pack(:expand=>1, :fill=>:both)
85
- @label.configure(_symbolkey2str(keys)) unless keys.empty?
86
- @path = @label
87
- end
88
-
89
- def userscreen( root )
90
- # TODO: Screen "pops"; other way?
91
- root.state('zoomed')
92
- root.update
93
-
94
- if RUBY_PLATFORM[/mingw|mswin|bccwin/ix] # Windows
95
- root.state('zoomed') # OK on Windows, bad on Linux
96
- else
97
- # Linux: works
98
- # Other: not tested
99
- root.height = root.winfo_screenheight
100
- root.width = root.winfo_screenwidth
101
- end
102
-
103
- root.winfo_geometry =~ /(\d+)x(\d+)\+([+-]?\d+)\+([+-]?\d+)/
104
- xwg = $3.to_i
105
- ywg = $4.to_i
106
- root.geometry =~ /(\d+)x(\d+)\+([+-]?\d+)\+([+-]?\d+)/
107
- gw = $1.to_i
108
- gh = $2.to_i
109
-
110
- ## sw = root.winfo_screenwidth
111
- ## sh = root.winfo_screenheight
112
-
113
- rx = root.winfo_rootx
114
- ry = root.winfo_rooty # maybe, taskbar height
115
-
116
- border = -[xwg,ywg].min
117
- userscreenx = xwg + border
118
- userscreeny= ywg + border
119
- userscreenwidth = gw
120
- userscreenheight = gh + ry - ywg - border
121
-
122
- $balloonhlp_ ||= Hash.new
123
- $balloonhlp_[:userscreenx ] = userscreenx
124
- $balloonhlp_[:userscreeny ] = userscreeny
125
- $balloonhlp_[:userscreenwidth ] = userscreenwidth
126
- $balloonhlp_[:userscreenheight] = userscreenheight
127
-
128
- root.state('normal')
129
- nil
130
- end # userscreen
131
-
132
- def epath
133
- @epath
134
- end
135
-
136
- def interval(val)
137
- if val
138
- @timer.interval(val)
139
- else
140
- @interval
141
- end
142
- end
143
-
144
- def command(cmd = Proc.new)
145
- @command = cmd
146
- self
147
- end
148
-
149
- def show
150
- x = TkWinfo.pointerx(@parent)
151
- y = TkWinfo.pointery(@parent)
152
- ## @frame.geometry("+#{x+1}+#{y+1}")
153
-
154
- if @command
155
- case @command.arity
156
- when 0
157
- @command.call
158
- when 2
159
- @command.call(x - TkWinfo.rootx(@parent), y - TkWinfo.rooty(@parent))
160
- when 3
161
- @command.call(x - TkWinfo.rootx(@parent), y - TkWinfo.rooty(@parent),
162
- self)
163
- else
164
- @command.call(x - TkWinfo.rootx(@parent), y - TkWinfo.rooty(@parent),
165
- self, @parent)
166
- end
167
- end
168
-
169
- @frame.geometry("+#{x+1}+#{y+1}")
170
- @frame.update
171
-
172
- rw = TkWinfo.reqwidth(@frame)
173
- rh = TkWinfo.reqheight(@frame)
174
- geom1 = geom(x,y,rw,rh)
175
- @frame.geometry(geom1)
176
-
177
- @frame.deiconify
178
- @frame.raise
179
-
180
- ## @org_cursor = @parent['cursor'] # -patch Nagai
181
- ## @parent.cursor('crosshair') # -patch Nagai
182
- begin # +patch Nagai
183
- @org_cursor = @parent.cget('cursor') # +patch Nagai
184
- rescue # +patch Nagai
185
- @org_cursor = @parent['cursor'] # +patch Nagai
186
- end # +patch Nagai
187
- begin # +patch Nagai
188
- @parent.configure('cursor', 'crosshair') # +patch Nagai
189
- rescue # +patch Nagai
190
- @parent.cursor('crosshair') # +patch Nagai
191
- end # +patch Nagai
192
-
193
- @frame.update
194
- end
195
-
196
- def geom( x,y,rw,rh, gapx=1, gapy=10 ) # gap: pixels; may not be 0!
197
- xcorrected = false
198
- ## rw = TkWinfo.reqwidth(@frame)
199
- ## rh = TkWinfo.reqheight(@frame)
200
- xmin = $balloonhlp_[:userscreenx]
201
- ymin = $balloonhlp_[:userscreeny]
202
- xmax= xmin + $balloonhlp_[:userscreenwidth]
203
- ymax= ymin + $balloonhlp_[:userscreenheight]
204
-
205
- origx = x
206
- x += gapx
207
- y += gapy
208
-
209
- if x + rw > xmax
210
- x = [(xmax-rw), xmin].max # Shift left
211
- xcorrected = true
212
- end
213
-
214
- y = y - gapy - rh if y + rh > ymax # Shift up
215
-
216
- if y < ymin # height will overlap pointer
217
- y = ymin
218
- x = origx - rw - gapx if xcorrected # Shift left
219
- end
220
-
221
- if x < xmin # to big
222
- x = xmin
223
- wrap_help
224
- end
225
- geom = "+#{ x }+#{ y }" # balloon may not overlap cursor - why?
226
-
227
- geom
228
- end # geom
229
-
230
-
231
- def wrap_help( )
232
- #TODO: Introduce "wraplength"
233
- puts 'Cannot show balloon help: to big.'
234
- end # wrap_help
235
-
236
-
237
- def erase
238
- ## @parent.cursor(@org_cursor) # -patch Nagai
239
- begin # +patch Nagai
240
- @parent.configure('cursor', @org_cursor) # +patch Nagai
241
- rescue # +patch Nagai
242
- @parent.cursor(@org_cursor) # +patch Nagai
243
- end # +patch Nagai
244
- @frame.withdraw
245
- end
246
-
247
- def destroy
248
- @frame.destroy
249
- end
250
- end
251
-
252
- ################################################
253
- # test
254
- ################################################
255
- if __FILE__ == $0
256
- TkButton.new('text'=>'This button has a balloon help') {|b|
257
- pack('fill'=>'x')
258
- Tk::RbWidget::BalloonHelp.new(b, 'text'=>' Message ')
259
- }
260
- TkButton.new('text'=>'This button has another balloon help') {|b|
261
- pack('fill'=>'x')
262
- Tk::RbWidget::BalloonHelp.new(b,
263
- 'text'=>"CONFIGURED MESSAGE\nchange colors, and so on",
264
- 'interval'=>200, 'font'=>'courier',
265
- 'background'=>'gray', 'foreground'=>'red')
266
- }
267
-
268
- sb = TkScrollbox.new.pack(:fill=>:x)
269
- sb.insert(:end, *%w(aaa bbb ccc ddd eee fff ggg hhh iii jjj kkk lll mmm))
270
- =begin
271
- # CASE1 : command takes no arguemnt
272
- bh = Tk::RbWidget::BalloonHelp.new(sb, :interval=>500,
273
- :relief=>:ridge, :background=>'white',
274
- :command=>proc{
275
- y = TkWinfo.pointery(sb) - TkWinfo.rooty(sb)
276
- bh.text "current index == #{sb.nearest(y)}"
277
- })
278
- =end
279
- =begin
280
- # CASE2 : command takes 2 arguemnts
281
- bh = Tk::RbWidget::BalloonHelp.new(sb, :interval=>500,
282
- :relief=>:ridge, :background=>'white',
283
- :command=>proc{|x, y|
284
- bh.text "current index == #{sb.nearest(y)}"
285
- })
286
- =end
287
- =begin
288
- # CASE3 : command takes 3 arguemnts
289
- Tk::RbWidget::BalloonHelp.new(sb, :interval=>500,
290
- :relief=>:ridge, :background=>'white',
291
- :command=>proc{|x, y, bhelp|
292
- bhelp.text "current index == #{sb.nearest(y)}"
293
- })
294
- =end
295
- =begin
296
- # CASE4a : command is a Proc object and takes 4 arguemnts
297
- cmd = proc{|x, y, bhelp, parent|
298
- bhelp.text "current index == #{parent.nearest(y)}"
299
- }
300
-
301
- Tk::RbWidget::BalloonHelp.new(sb, :interval=>500,
302
- :relief=>:ridge, :background=>'white',
303
- :command=>cmd)
304
-
305
- sb2 = TkScrollbox.new.pack(:fill=>:x)
306
- sb2.insert(:end, *%w(AAA BBB CCC DDD EEE FFF GGG HHH III JJJ KKK LLL MMM))
307
- Tk::RbWidget::BalloonHelp.new(sb2, :interval=>500,
308
- :padx=>5, :relief=>:raised,
309
- :background=>'gray25', :foreground=>'white',
310
- :command=>cmd)
311
- =end
312
- #=begin
313
- # CASE4b : command is a Method object and takes 4 arguemnts
314
- def set_msg(x, y, bhelp, parent)
315
- bhelp.text "current index == #{parent.nearest(y)}"
316
- end
317
- cmd = self.method(:set_msg)
318
-
319
- Tk::RbWidget::BalloonHelp.new(sb, :interval=>500,
320
- :relief=>:ridge, :background=>'white',
321
- :command=>cmd)
322
-
323
- sb2 = TkScrollbox.new.pack(:fill=>:x)
324
- sb2.insert(:end, *%w(AAA BBB CCC DDD EEE FFF GGG HHH III JJJ KKK LLL MMM))
325
- Tk::RbWidget::BalloonHelp.new(sb2, :interval=>500,
326
- :padx=>5, :relief=>:raised,
327
- :background=>'gray25', :foreground=>'white',
328
- :command=>cmd)
329
- #=end
330
-
331
- Tk.mainloop
332
- end
1
+ #
2
+ # tkballoonhelp.rb : simple balloon help widget
3
+ # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp)
4
+ #
5
+ # Add a balloon help to a widget.
6
+ # This widget has only poor featureas. If you need more useful features,
7
+ # please try to use the Tix extension of Tcl/Tk under Ruby/Tk.
8
+ #
9
+ # The interval time to display a balloon help is defined 'interval' option
10
+ # (default is 750ms).
11
+ #
12
+ # Modifications by Axel Friedrich:
13
+ # * 2010-03-01:
14
+ # * 2010-01-31: Shifting position of balloon if it is out of screen
15
+ # * TODO: wraplength
16
+ require 'tk'
17
+
18
+ module Tk
19
+ module RbWidget
20
+ class BalloonHelp<TkLabel
21
+ end
22
+ end
23
+ end
24
+ class Tk::RbWidget::BalloonHelp<TkLabel
25
+ DEFAULT_FOREGROUND = 'black'
26
+ DEFAULT_BACKGROUND = 'white'
27
+ DEFAULT_INTERVAL = 750
28
+
29
+ def _balloon_binding(interval)
30
+ @timer = TkAfter.new(interval, 1, proc{show})
31
+ def @timer.interval(val)
32
+ @sleep_time = val
33
+ end
34
+ @bindtag = TkBindTag.new
35
+ @bindtag.bind('Enter', proc{@timer.start})
36
+ @bindtag.bind('Motion', proc{@timer.restart; erase})
37
+ @bindtag.bind('Any-ButtonPress', proc{@timer.restart; erase})
38
+ @bindtag.bind('Leave', proc{@timer.stop; erase})
39
+ tags = @parent.bindtags
40
+ idx = tags.index(@parent)
41
+ unless idx
42
+ ppath = TkComm.window(@parent.path)
43
+ idx = tags.index(ppath) || 0
44
+ end
45
+ tags[idx,0] = @bindtag
46
+ @parent.bindtags(tags)
47
+ end
48
+ private :_balloon_binding
49
+
50
+ def initialize(parent=nil, keys={})
51
+ @parent = parent || Tk.root
52
+
53
+ @frame = TkToplevel.new(@parent)
54
+ if defined?($tkxxs_) && $tkxxs_[:userscreenx]
55
+ $balloonhlp_ = Hash.new
56
+ $balloonhlp_[:userscreenx] = $tkxxs_[:userscreenx]
57
+ $balloonhlp_[:userscreeny] = $tkxxs_[:userscreeny]
58
+ $balloonhlp_[:userscreenwidth] = $tkxxs_[:userscreenwidth]
59
+ $balloonhlp_[:userscreenheight] = $tkxxs_[:userscreenheight]
60
+ elsif !defined?($balloonhlp_) || !$balloonhlp_[:userscreenx]
61
+ userscreen(@frame)
62
+ end
63
+ @frame.withdraw
64
+ @frame.overrideredirect(true)
65
+ @frame.transient(TkWinfo.toplevel(@parent))
66
+ @epath = @frame.path
67
+
68
+ if keys
69
+ keys = _symbolkey2str(keys)
70
+ else
71
+ keys = {}
72
+ end
73
+
74
+ @command = keys.delete('command')
75
+
76
+ @interval = keys.delete('interval'){DEFAULT_INTERVAL}
77
+ _balloon_binding(@interval)
78
+
79
+ # @label = TkLabel.new(@frame, 'background'=>'bisque').pack
80
+ @label = TkLabel.new(@frame,
81
+ ## :wraplength => '2i', # Axel
82
+ 'foreground'=>DEFAULT_FOREGROUND,
83
+ ## 'background'=>DEFAULT_BACKGROUND).pack # -Axel
84
+ 'background'=>DEFAULT_BACKGROUND).pack(:expand=>1, :fill=>:both)
85
+ @label.configure(_symbolkey2str(keys)) unless keys.empty?
86
+ @path = @label
87
+ end
88
+
89
+ def userscreen( root )
90
+ # TODO: Screen "pops"; other way?
91
+ root.state('zoomed')
92
+ root.update
93
+
94
+ if RUBY_PLATFORM[/mingw|mswin|bccwin/ix] # Windows
95
+ root.state('zoomed') # OK on Windows, bad on Linux
96
+ else
97
+ # Linux: works
98
+ # Other: not tested
99
+ root.height = root.winfo_screenheight
100
+ root.width = root.winfo_screenwidth
101
+ end
102
+
103
+ root.winfo_geometry =~ /(\d+)x(\d+)\+([+-]?\d+)\+([+-]?\d+)/
104
+ xwg = $3.to_i
105
+ ywg = $4.to_i
106
+ root.geometry =~ /(\d+)x(\d+)\+([+-]?\d+)\+([+-]?\d+)/
107
+ gw = $1.to_i
108
+ gh = $2.to_i
109
+
110
+ ## sw = root.winfo_screenwidth
111
+ ## sh = root.winfo_screenheight
112
+
113
+ rx = root.winfo_rootx
114
+ ry = root.winfo_rooty # maybe, taskbar height
115
+
116
+ border = -[xwg,ywg].min
117
+ userscreenx = xwg + border
118
+ userscreeny= ywg + border
119
+ userscreenwidth = gw
120
+ userscreenheight = gh + ry - ywg - border
121
+
122
+ $balloonhlp_ ||= Hash.new
123
+ $balloonhlp_[:userscreenx ] = userscreenx
124
+ $balloonhlp_[:userscreeny ] = userscreeny
125
+ $balloonhlp_[:userscreenwidth ] = userscreenwidth
126
+ $balloonhlp_[:userscreenheight] = userscreenheight
127
+
128
+ root.state('normal')
129
+ nil
130
+ end # userscreen
131
+
132
+ def epath
133
+ @epath
134
+ end
135
+
136
+ def interval(val)
137
+ if val
138
+ @timer.interval(val)
139
+ else
140
+ @interval
141
+ end
142
+ end
143
+
144
+ def command(cmd = Proc.new)
145
+ @command = cmd
146
+ self
147
+ end
148
+
149
+ def show
150
+ x = TkWinfo.pointerx(@parent)
151
+ y = TkWinfo.pointery(@parent)
152
+ ## @frame.geometry("+#{x+1}+#{y+1}")
153
+
154
+ if @command
155
+ case @command.arity
156
+ when 0
157
+ @command.call
158
+ when 2
159
+ @command.call(x - TkWinfo.rootx(@parent), y - TkWinfo.rooty(@parent))
160
+ when 3
161
+ @command.call(x - TkWinfo.rootx(@parent), y - TkWinfo.rooty(@parent),
162
+ self)
163
+ else
164
+ @command.call(x - TkWinfo.rootx(@parent), y - TkWinfo.rooty(@parent),
165
+ self, @parent)
166
+ end
167
+ end
168
+
169
+ @frame.geometry("+#{x+1}+#{y+1}")
170
+ @frame.update
171
+
172
+ rw = TkWinfo.reqwidth(@frame)
173
+ rh = TkWinfo.reqheight(@frame)
174
+ geom1 = geom(x,y,rw,rh)
175
+ @frame.geometry(geom1)
176
+
177
+ @frame.deiconify
178
+ @frame.raise
179
+
180
+ ## @org_cursor = @parent['cursor'] # -patch Nagai
181
+ ## @parent.cursor('crosshair') # -patch Nagai
182
+ begin # +patch Nagai
183
+ @org_cursor = @parent.cget('cursor') # +patch Nagai
184
+ rescue # +patch Nagai
185
+ @org_cursor = @parent['cursor'] # +patch Nagai
186
+ end # +patch Nagai
187
+ begin # +patch Nagai
188
+ @parent.configure('cursor', 'crosshair') # +patch Nagai
189
+ rescue # +patch Nagai
190
+ @parent.cursor('crosshair') # +patch Nagai
191
+ end # +patch Nagai
192
+
193
+ @frame.update
194
+ end
195
+
196
+ def geom( x,y,rw,rh, gapx=1, gapy=10 ) # gap: pixels; may not be 0!
197
+ xcorrected = false
198
+ ## rw = TkWinfo.reqwidth(@frame)
199
+ ## rh = TkWinfo.reqheight(@frame)
200
+ xmin = $balloonhlp_[:userscreenx]
201
+ ymin = $balloonhlp_[:userscreeny]
202
+ xmax= xmin + $balloonhlp_[:userscreenwidth]
203
+ ymax= ymin + $balloonhlp_[:userscreenheight]
204
+
205
+ origx = x
206
+ x += gapx
207
+ y += gapy
208
+
209
+ if x + rw > xmax
210
+ x = [(xmax-rw), xmin].max # Shift left
211
+ xcorrected = true
212
+ end
213
+
214
+ y = y - gapy - rh if y + rh > ymax # Shift up
215
+
216
+ if y < ymin # height will overlap pointer
217
+ y = ymin
218
+ x = origx - rw - gapx if xcorrected # Shift left
219
+ end
220
+
221
+ if x < xmin # to big
222
+ x = xmin
223
+ wrap_help
224
+ end
225
+ geom = "+#{ x }+#{ y }" # balloon may not overlap cursor - why?
226
+
227
+ geom
228
+ end # geom
229
+
230
+
231
+ def wrap_help( )
232
+ #TODO: Introduce "wraplength"
233
+ puts 'Cannot show balloon help: to big.'
234
+ end # wrap_help
235
+
236
+
237
+ def erase
238
+ ## @parent.cursor(@org_cursor) # -patch Nagai
239
+ begin # +patch Nagai
240
+ @parent.configure('cursor', @org_cursor) # +patch Nagai
241
+ rescue # +patch Nagai
242
+ @parent.cursor(@org_cursor) # +patch Nagai
243
+ end # +patch Nagai
244
+ @frame.withdraw
245
+ end
246
+
247
+ def destroy
248
+ @frame.destroy
249
+ end
250
+ end
251
+
252
+ ################################################
253
+ # test
254
+ ################################################
255
+ if __FILE__ == $0
256
+ TkButton.new('text'=>'This button has a balloon help') {|b|
257
+ pack('fill'=>'x')
258
+ Tk::RbWidget::BalloonHelp.new(b, 'text'=>' Message ')
259
+ }
260
+ TkButton.new('text'=>'This button has another balloon help') {|b|
261
+ pack('fill'=>'x')
262
+ Tk::RbWidget::BalloonHelp.new(b,
263
+ 'text'=>"CONFIGURED MESSAGE\nchange colors, and so on",
264
+ 'interval'=>200, 'font'=>'courier',
265
+ 'background'=>'gray', 'foreground'=>'red')
266
+ }
267
+
268
+ sb = TkScrollbox.new.pack(:fill=>:x)
269
+ sb.insert(:end, *%w(aaa bbb ccc ddd eee fff ggg hhh iii jjj kkk lll mmm))
270
+ =begin
271
+ # CASE1 : command takes no arguemnt
272
+ bh = Tk::RbWidget::BalloonHelp.new(sb, :interval=>500,
273
+ :relief=>:ridge, :background=>'white',
274
+ :command=>proc{
275
+ y = TkWinfo.pointery(sb) - TkWinfo.rooty(sb)
276
+ bh.text "current index == #{sb.nearest(y)}"
277
+ })
278
+ =end
279
+ =begin
280
+ # CASE2 : command takes 2 arguemnts
281
+ bh = Tk::RbWidget::BalloonHelp.new(sb, :interval=>500,
282
+ :relief=>:ridge, :background=>'white',
283
+ :command=>proc{|x, y|
284
+ bh.text "current index == #{sb.nearest(y)}"
285
+ })
286
+ =end
287
+ =begin
288
+ # CASE3 : command takes 3 arguemnts
289
+ Tk::RbWidget::BalloonHelp.new(sb, :interval=>500,
290
+ :relief=>:ridge, :background=>'white',
291
+ :command=>proc{|x, y, bhelp|
292
+ bhelp.text "current index == #{sb.nearest(y)}"
293
+ })
294
+ =end
295
+ =begin
296
+ # CASE4a : command is a Proc object and takes 4 arguemnts
297
+ cmd = proc{|x, y, bhelp, parent|
298
+ bhelp.text "current index == #{parent.nearest(y)}"
299
+ }
300
+
301
+ Tk::RbWidget::BalloonHelp.new(sb, :interval=>500,
302
+ :relief=>:ridge, :background=>'white',
303
+ :command=>cmd)
304
+
305
+ sb2 = TkScrollbox.new.pack(:fill=>:x)
306
+ sb2.insert(:end, *%w(AAA BBB CCC DDD EEE FFF GGG HHH III JJJ KKK LLL MMM))
307
+ Tk::RbWidget::BalloonHelp.new(sb2, :interval=>500,
308
+ :padx=>5, :relief=>:raised,
309
+ :background=>'gray25', :foreground=>'white',
310
+ :command=>cmd)
311
+ =end
312
+ #=begin
313
+ # CASE4b : command is a Method object and takes 4 arguemnts
314
+ def set_msg(x, y, bhelp, parent)
315
+ bhelp.text "current index == #{parent.nearest(y)}"
316
+ end
317
+ cmd = self.method(:set_msg)
318
+
319
+ Tk::RbWidget::BalloonHelp.new(sb, :interval=>500,
320
+ :relief=>:ridge, :background=>'white',
321
+ :command=>cmd)
322
+
323
+ sb2 = TkScrollbox.new.pack(:fill=>:x)
324
+ sb2.insert(:end, *%w(AAA BBB CCC DDD EEE FFF GGG HHH III JJJ KKK LLL MMM))
325
+ Tk::RbWidget::BalloonHelp.new(sb2, :interval=>500,
326
+ :padx=>5, :relief=>:raised,
327
+ :background=>'gray25', :foreground=>'white',
328
+ :command=>cmd)
329
+ #=end
330
+
331
+ Tk.mainloop
332
+ end