purple_shoes 0.0.126 → 0.5.149

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,222 @@
1
+ # syntax highlighting
2
+
3
+ require_relative 'common'
4
+
5
+ module HH::Markup
6
+
7
+ TOKENIZER = HH::Syntax.load "ruby"
8
+ COLORS = {
9
+ :comment => {:stroke => "#887"},
10
+ :keyword => {:stroke => "#111"},
11
+ :method => {:stroke => "#C09", :weight => "bold"},
12
+ # :class => {:stroke => "#0c4", :weight => "bold"},
13
+ # :module => {:stroke => "#050"},
14
+ # :punct => {:stroke => "#668", :weight => "bold"},
15
+ :symbol => {:stroke => "#C30"},
16
+ :string => {:stroke => "#C90"},
17
+ :number => {:stroke => "#396" },
18
+ :regex => {:stroke => "#000", :fill => "#FFC" },
19
+ # :char => {:stroke => "#f07"},
20
+ :attribute => {:stroke => "#369" },
21
+ # :global => {:stroke => "#7FB" },
22
+ :expr => {:stroke => "#722" },
23
+ # :escape => {:stroke => "#277" }
24
+ :ident => {:stroke => "#994c99"},
25
+ :constant => {:stroke => "#630", :weight => "bold"},
26
+ :class => {:stroke => "#630", :weight => "bold"},
27
+ :matching => {:stroke => "#ff0", :weight => "bold"},
28
+ }
29
+
30
+
31
+ def highlight str, pos=nil, colors=COLORS
32
+ tokens = []
33
+ TOKENIZER.tokenize(str) do |t|
34
+ if t.group == :punct
35
+ # split punctuation into single characters tokens
36
+ # TODO: to it in the parser
37
+ tokens += t.split('').map{|s| HH::Syntax::Token.new(s, :punct)}
38
+ else
39
+ # add token as is
40
+ tokens << t
41
+ end
42
+ end
43
+
44
+ res = []
45
+ tokens.each do |token|
46
+ res <<
47
+ if colors[token.group]
48
+ #span(token, colors[token.group])
49
+ tmp = fg(token, tr_color(colors[token.group][:stroke]))
50
+ colors[token.group][:fill] ? bg(tmp, tr_color(colors[token.group][:fill])) : tmp
51
+ elsif colors[:any]
52
+ #span(token, colors[:any])
53
+ tmp = fg(token, tr_color(colors[:any][:stroke]))
54
+ colors[:any][:fill] ? bg(tmp, tr_color(colors[:any][:fill])) : tmp
55
+ else
56
+ token
57
+ end
58
+ end
59
+
60
+ if pos.nil? or pos < 0
61
+ return res
62
+ end
63
+
64
+ token_index, matching_index = matching_token(tokens, pos)
65
+
66
+ if token_index
67
+ #res[token_index] = span(tokens[token_index], colors[:matching])
68
+ tmp = fg(tokens[token_index], tr_color(colors[:matching][:stroke]))
69
+ res[token_index] = colors[:matching][:fill] ? bg(tmp, tr_color(colors[:matching][:fill])) : tmp
70
+ if matching_index
71
+ #res[matching_index] = span(tokens[matching_index], colors[:matching])
72
+ tmp = fg(tokens[matching_index], tr_color(colors[:matching][:stroke]))
73
+ res[matching_index] = colors[:matching][:fill] ? bg(tmp, tr_color(colors[:matching][:fill])) : tmp
74
+ end
75
+ end
76
+
77
+ res
78
+ end
79
+
80
+ private
81
+ def matching_token(tokens, pos)
82
+ curr_pos = 0
83
+ token_index = nil
84
+ tokens.each_with_index do |t, i|
85
+ curr_pos += t.size
86
+ if token_index.nil? and curr_pos >= pos
87
+ token_index = i
88
+ break
89
+ end
90
+ end
91
+ if token_index.nil? then return nil end
92
+
93
+ match = matching_token_at_index(tokens, token_index);
94
+ if match.nil? and curr_pos == pos and token_index < tokens.size-1
95
+ # try the token before the cursor, instead of the one after
96
+ token_index += 1
97
+ match = matching_token_at_index(tokens, token_index)
98
+ end
99
+
100
+ if match
101
+ [token_index, match]
102
+ else
103
+ nil
104
+ end
105
+ end
106
+
107
+
108
+ def matching_token_at_index(tokens, index)
109
+ starts, ends, direction = matching_tokens(tokens, index)
110
+ if starts.nil?
111
+ return nil
112
+ end
113
+
114
+ stack_level = 1
115
+ index += direction
116
+ while index >= 0 and index < tokens.size
117
+ # TODO separate space in the tokenizer
118
+ t = tokens[index].gsub(/\s/, '')
119
+ if ends.include?(t) and not as_modifier?(tokens, index)
120
+ stack_level -= 1
121
+ return index if stack_level == 0
122
+ elsif starts.include?(t) and not as_modifier?(tokens, index)
123
+ stack_level += 1
124
+ end
125
+ index += direction
126
+ end
127
+ # no matching token found
128
+ return nil
129
+ end
130
+
131
+ # returns an array of tokens matching and the direction
132
+ def matching_tokens(tokens, index)
133
+ # TODO separate space in the tokenizer
134
+ token = tokens[index].gsub(/\s/, '')
135
+ starts = [token]
136
+ if OPEN_BRACKETS[token]
137
+ direction = 1
138
+ ends = [OPEN_BRACKETS[token]]
139
+ elsif CLOSE_BRACKETS[token]
140
+ direction = -1
141
+ ends = [CLOSE_BRACKETS[token]]
142
+ elsif OPEN_BLOCK.include?(token)
143
+ if as_modifier?(tokens, index)
144
+ return nil
145
+ end
146
+ direction = 1
147
+ ends = ['end']
148
+ starts = OPEN_BLOCK
149
+ elsif token == 'end'
150
+ direction = -1
151
+ ends = OPEN_BLOCK
152
+ else
153
+ return nil
154
+ end
155
+
156
+ [starts, ends, direction]
157
+ end
158
+
159
+ def as_modifier?(tokens, index)
160
+
161
+ if not MODIFIERS.include? tokens[index].gsub(/\s/, '')
162
+ return false
163
+ end
164
+
165
+ index -= 1
166
+ # find last index before the token that is no space
167
+ index -= 1 while index >= 0 and tokens[index] =~ /\A[ \t]*\z/
168
+
169
+ if index < 0
170
+ # first character of the string
171
+ false
172
+ elsif tokens[index] =~ /\n[ \t]*\Z/
173
+ # first token of the line
174
+ false
175
+ elsif tokens[index].group == :punct
176
+ # preceded by a punctuation token on the same line
177
+ i = tokens[index].rindex(/\S/)
178
+ punc = tokens[index][i, 1]
179
+ # true if the preceeding statement was terminating
180
+ not NON_TERMINATING.include?(punc)
181
+ else
182
+ # preceded by a non punctuation token on the same line
183
+ true
184
+ end
185
+ end
186
+
187
+
188
+ OPEN_BRACKETS = {
189
+ '{' => '}',
190
+ '(' => ')',
191
+ '[' => ']',
192
+ }
193
+
194
+ #close_bracket = {}
195
+ #OPEN_BRACKETS.each{|open, close| opens_bracket[close] = open}
196
+ #CLOSE_BRACKETS = opens_bracket
197
+ # the following is more readable :)
198
+ CLOSE_BRACKETS = {
199
+ '}' => '{',
200
+ ')' => '(',
201
+ ']' => '[',
202
+ }
203
+
204
+ BRACKETS = CLOSE_BRACKETS.keys + OPEN_BRACKETS.keys
205
+
206
+ OPEN_BLOCK = [
207
+ 'def',
208
+ 'class',
209
+ 'module',
210
+ 'do',
211
+ 'if',
212
+ 'unless',
213
+ 'while',
214
+ 'until',
215
+ 'begin',
216
+ 'for'
217
+ ]
218
+
219
+ MODIFIERS = %w[if unless while until]
220
+
221
+ NON_TERMINATING = %w{+ - * / , . = ~ < > ( [}
222
+ end
@@ -0,0 +1,2 @@
1
+ module ::HH end
2
+ require_relative 'highlighter/markup'
data/lib/purple_shoes.rb CHANGED
@@ -22,6 +22,7 @@ module Shoes
22
22
  PAGE_UP PAGE_DOWN HOME END INSERT
23
23
  F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15].each{|k| KEY_NAMES[eval("Swt::SWT::#{k}")] = k}
24
24
  KEY_NAMES[Swt::SWT::CR] = "\n"
25
+ LINECAP = {curve: Swt::SWT::CAP_ROUND, rect: Swt::SWT::CAP_FLAT, project: Swt::SWT::CAP_SQUARE}
25
26
  COLORS = {}
26
27
  end
27
28
 
@@ -31,6 +32,9 @@ module Swt
31
32
  include_package 'org.eclipse.swt.widgets'
32
33
  include_package 'org.eclipse.swt.graphics'
33
34
  include_package 'org.eclipse.swt.events'
35
+ include_package 'org.eclipse.swt.dnd'
36
+ import java.awt.datatransfer.StringSelection
37
+ import java.awt.Toolkit
34
38
  end
35
39
 
36
40
  class Object
@@ -53,3 +57,5 @@ require_relative 'shoes/download'
53
57
  require_relative 'shoes/manual'
54
58
 
55
59
  require_relative 'plugins/video'
60
+
61
+ autoload :HH, File.join(Shoes::DIR, 'ext/highlighter')
data/lib/shoes/app.rb CHANGED
@@ -6,6 +6,15 @@ class Shoes
6
6
  args.each do |k, v|
7
7
  instance_variable_set "@#{k}", v
8
8
  end
9
+
10
+ win_title = @owner.instance_variable_get('@title')
11
+ class << @owner; self end.
12
+ class_eval do
13
+ define_method :inspect do
14
+ win_title or 'purple shoes'
15
+ end
16
+ end if @owner
17
+
9
18
  App.class_eval do
10
19
  attr_accessor *(args.keys - [:width, :height, :title])
11
20
  end
@@ -14,9 +23,9 @@ class Shoes
14
23
  Shoes.APPS << self
15
24
  end
16
25
 
17
- attr_accessor :cslot, :top_slot, :contents, :mmcs, :mscs, :order, :mouse_pos, :hided
26
+ attr_accessor :cslot, :top_slot, :contents, :mmcs, :mhcs, :mscs, :order, :mouse_pos, :hided
18
27
  attr_writer :mouse_button
19
- attr_reader :location
28
+ attr_reader :owner, :location
20
29
 
21
30
  def visit url
22
31
  if url =~ /^(http|https):\/\//
@@ -124,11 +133,25 @@ class Shoes
124
133
  def image name, args={}, &blk
125
134
  args = basic_attributes args
126
135
  args[:rotate] ||= rotate
136
+ if name =~ /^(http|https):\/\//
137
+ tmpname = File.join(Dir.tmpdir, "__purple_shoes_#{Time.now.to_f}.png")
138
+ url, name = name, File.join(DIR, '../static/downloading.png')
139
+ end
127
140
  img = Swt::Image.new Shoes.display, name
128
141
  args[:full_width], args[:full_height] = img.getImageData.width, img.getImageData.height
129
142
  args[:real], args[:app] = img, self
130
143
 
131
144
  Image.new(args).tap do |s|
145
+ download url, save: tmpname do
146
+ tmp = Swt::Image.new Shoes.display, tmpname
147
+ s.real = tmp
148
+ s.full_width, s.full_height = tmp.getImageData.width, tmp.getImageData.height
149
+ if s.initials[:width].zero? and s.initials[:height].zero?
150
+ s.width, s.height = s.full_width, s.full_height
151
+ end
152
+ File.delete tmpname
153
+ end if url
154
+
132
155
  pl = Swt::PaintListener.new
133
156
  s.pl = pl
134
157
  class << pl; self end.
@@ -139,11 +162,11 @@ class Shoes
139
162
  unless s.hided
140
163
  Shoes.set_rotate e.gc, *s.rotate do
141
164
  if s.initials[:width].zero? and s.initials[:height].zero?
142
- gc.drawImage img, s.left, s.top
165
+ gc.drawImage s.real, s.left, s.top
143
166
  else
144
167
  s.width = s.full_width if s.width.zero?
145
168
  s.height = s.full_height if s.height.zero?
146
- gc.drawImage img, 0, 0, s.full_width, s.full_height, s.left, s.top, s.width, s.height
169
+ gc.drawImage s.real, 0, 0, s.full_width, s.full_height, s.left, s.top, s.width, s.height
147
170
  end
148
171
  end
149
172
  end
@@ -161,6 +184,8 @@ class Shoes
161
184
  elsif klass == Radio then Swt::SWT::RADIO
162
185
  elsif klass == Check then Swt::SWT::CHECK end
163
186
  b = Swt::Button.new @cs, opt
187
+ b.setVisible false if args[:hidden]
188
+ args.delete :hidden
164
189
  b.setText name if klass == Button
165
190
  b.setLocation args[:left], args[:top]
166
191
  if args[:width] > 0 and args[:height] > 0
@@ -197,6 +222,8 @@ class Shoes
197
222
  args[:height] = h if args[:height].zero?
198
223
 
199
224
  el = Swt::Text.new @cs, Swt::SWT::BORDER | style
225
+ el.setVisible false if args[:hidden]
226
+ args.delete :hidden
200
227
  el.setText txt || args[:text].to_s
201
228
  el.setSize args[:width], args[:height]
202
229
  args[:real], args[:app] = el, self
@@ -219,6 +246,8 @@ class Shoes
219
246
  args[:height] = 20 if args[:height].zero?
220
247
  args[:items] ||= []
221
248
  cb = Swt::Combo.new @cs, Swt::SWT::DROP_DOWN
249
+ cb.setVisible false if args[:hidden]
250
+ args.delete :hidden
222
251
  cb.setSize args[:width], args[:height]
223
252
  cb.setItems args[:items].map(&:to_s)
224
253
  cb.setText args[:choose].to_s
@@ -273,6 +302,7 @@ class Shoes
273
302
  args[:stroke] ||= stroke
274
303
  args[:fill] ||= fill
275
304
  args[:rotate] ||= rotate
305
+ args[:cap] = (LINECAP[args[:cap]] or cap)
276
306
  args[:real], args[:app], args[:block] = :shape, self, blk
277
307
  Shape.new(args).tap do |s|
278
308
  pl = Swt::PaintListener.new
@@ -286,6 +316,7 @@ class Shoes
286
316
  gc = e.gc
287
317
  Shoes.dps_reset s.dps, gc
288
318
  gc.setAntialias Swt::SWT::ON
319
+ gc.setLineCap s.cap
289
320
  sw, pat1, pat2 = s.strokewidth, s.stroke, s.fill
290
321
  Shoes.set_rotate gc, *s.rotate do
291
322
  if pat2
@@ -320,13 +351,19 @@ class Shoes
320
351
  args = basic_attributes args
321
352
  args[:width].zero? ? (args[:width] = args[:radius] * 2) : (args[:radius] = args[:width]/2.0)
322
353
  args[:height] = args[:width] if args[:height].zero?
354
+ if args[:center]
355
+ args[:left] -= args[:width] / 2
356
+ args[:top] -= args[:height] / 2
357
+ end
323
358
  args[:strokewidth] = ( args[:strokewidth] or strokewidth or 1 )
324
359
  args[:nocontrol] = args[:noorder] = true
325
360
 
326
361
  args[:stroke] ||= stroke
327
362
  args[:fill] ||= fill
328
363
  args[:rotate] ||= rotate
364
+ args[:cap] = (LINECAP[args[:cap]] or cap)
329
365
  args[:real], args[:app] = :shape, self
366
+ args[:angle1] = false unless args[:angle1]
330
367
  Oval.new(args).tap do |s|
331
368
  pl = Swt::PaintListener.new
332
369
  s.pl = pl
@@ -337,17 +374,20 @@ class Shoes
337
374
  gc = e.gc
338
375
  Shoes.dps_reset s.dps, gc
339
376
  gc.setAntialias Swt::SWT::ON
377
+ gc.setLineCap s.cap
340
378
  sw, pat1, pat2 = s.strokewidth, s.stroke, s.fill
341
379
  Shoes.set_rotate gc, *s.rotate do
342
380
  if pat2
343
381
  Shoes.set_pattern s, gc, pat2
344
- gc.fillOval s.left+sw, s.top+sw, s.width-sw*2, s.height-sw*2
382
+ s.angle1 ? gc.fillArc(s.left+sw, s.top+sw, s.width-sw*2, s.height-sw*2, s.angle1, s.angle2) :
383
+ gc.fillOval(s.left+sw, s.top+sw, s.width-sw*2, s.height-sw*2)
345
384
  end
346
385
  if pat1
347
386
  Shoes.set_pattern s, gc, pat1, :Foreground
348
387
  if sw > 0
349
388
  gc.setLineWidth sw
350
- gc.drawOval s.left+sw/2, s.top+sw/2, s.width-sw, s.height-sw
389
+ s.angle1 ? gc.drawArc(s.left+sw/2, s.top+sw/2, s.width-sw, s.height-sw, s.angle1, s.angle2) :
390
+ gc.drawOval(s.left+sw/2, s.top+sw/2, s.width-sw, s.height-sw)
351
391
  end
352
392
  end
353
393
  end
@@ -358,6 +398,13 @@ class Shoes
358
398
  clickable s, &blk
359
399
  end
360
400
  end
401
+
402
+ def arc l, t, w, h, a1, a2, args={}
403
+ a1 = a1 * 180 / Math::PI
404
+ a2 = -a2 * 180 / Math::PI
405
+ args.merge!({angle1: a1, angle2: a2})
406
+ oval l, t, w, h, args
407
+ end
361
408
 
362
409
  def rect *attrs, &blk
363
410
  args = attrs.last.class == Hash ? attrs.pop : {}
@@ -368,6 +415,10 @@ class Shoes
368
415
  else args[:left], args[:top], args[:width], args[:height] = attrs
369
416
  end
370
417
  args[:height] = args[:width] unless args[:height]
418
+ if args[:center]
419
+ args[:left] -= args[:width] / 2
420
+ args[:top] -= args[:height] / 2
421
+ end
371
422
  args[:strokewidth] = ( args[:strokewidth] or strokewidth or 1 )
372
423
  args[:curve] ||= 0
373
424
  args[:nocontrol] = args[:noorder] = true
@@ -376,6 +427,7 @@ class Shoes
376
427
  args[:stroke] ||= stroke
377
428
  args[:fill] ||= fill
378
429
  args[:rotate] ||= rotate
430
+ args[:cap] = (LINECAP[args[:cap]] or cap)
379
431
  args[:real], args[:app] = :shape, self
380
432
  Rect.new(args).tap do |s|
381
433
  pl = Swt::PaintListener.new
@@ -387,6 +439,7 @@ class Shoes
387
439
  gc = e.gc
388
440
  Shoes.dps_reset s.dps, gc
389
441
  gc.setAntialias Swt::SWT::ON
442
+ gc.setLineCap s.cap
390
443
  sw, pat1, pat2 = s.strokewidth, s.stroke, s.fill
391
444
  Shoes.set_rotate gc, *s.rotate do
392
445
  if pat2
@@ -444,6 +497,7 @@ class Shoes
444
497
 
445
498
  args[:stroke] ||= stroke
446
499
  args[:rotate] ||= rotate
500
+ args[:cap] = (LINECAP[args[:cap]] or cap)
447
501
  args[:real], args[:app] = :shape, self
448
502
  Line.new(args).tap do |s|
449
503
  pl = Swt::PaintListener.new
@@ -455,6 +509,7 @@ class Shoes
455
509
  gc = e.gc
456
510
  Shoes.dps_reset s.dps, gc
457
511
  gc.setAntialias Swt::SWT::ON
512
+ gc.setLineCap s.cap
458
513
  sw, pat = s.strokewidth, s.stroke
459
514
  Shoes.set_rotate gc, *s.rotate do
460
515
  if pat
@@ -487,6 +542,7 @@ class Shoes
487
542
  args[:stroke] ||= stroke
488
543
  args[:fill] ||= fill
489
544
  args[:rotate] ||= rotate
545
+ args[:cap] = (LINECAP[args[:cap]] or cap)
490
546
  args[:real], args[:app] = :shape, self
491
547
  Star.new(args).tap do |s|
492
548
  pl = Swt::PaintListener.new
@@ -498,6 +554,7 @@ class Shoes
498
554
  gc = e.gc
499
555
  Shoes.dps_reset s.dps, gc
500
556
  gc.setAntialias Swt::SWT::ON
557
+ gc.setLineCap s.cap
501
558
  sw, pat1, pat2 = s.strokewidth, s.stroke, s.fill
502
559
  outer, inner, points, left, top = s.outer, s.inner, s.points, s.left, s.top
503
560
  polygon = []
@@ -653,6 +710,8 @@ class Shoes
653
710
  args[:width] ||= 150
654
711
  args[:height] ||= 16
655
712
  args = basic_attributes args
713
+ pb.setVisible false if args[:hidden]
714
+ args.delete :hidden
656
715
  pb.setSize args[:width], args[:height]
657
716
  pb.setLocation args[:left], args[:top]
658
717
  args[:real], args[:app] = pb, self
@@ -660,7 +719,7 @@ class Shoes
660
719
  end
661
720
 
662
721
  def download name, args={}, &blk
663
- Download.new name, args, &blk
722
+ Download.new self, name, args, &blk
664
723
  end
665
724
 
666
725
  def scroll_top
@@ -680,11 +739,24 @@ class Shoes
680
739
  shell.getVerticalBar.getMaximum - 10
681
740
  end
682
741
 
742
+ def clipboard
743
+ Swt::Clipboard.new(Shoes.display).getContents Swt::TextTransfer.getInstance
744
+ end
745
+
746
+ def clipboard=(str)
747
+ Swt::Toolkit.getDefaultToolkit.getSystemClipboard.setContents Swt::StringSelection.new(str), Shoes
748
+ end
749
+
683
750
  def close
684
751
  @shell.close
685
752
  Shoes.APPS.delete self
686
753
  end
687
754
 
755
+ def window args={}, &blk
756
+ args.merge! owner: self
757
+ Shoes.app args, &blk
758
+ end
759
+
688
760
  def flush
689
761
  unless @cs.isDisposed
690
762
  Shoes.call_back_procs self
@@ -711,5 +783,14 @@ class Shoes
711
783
  g, a = attrs
712
784
  g ? rgb(g*255, g*255, g*255, a) : rgb(128, 128, 128)[0..2]
713
785
  end
786
+
787
+ def cap *line_cap
788
+ @line_cap = case line_cap.first
789
+ when :curve, :rect, :project
790
+ LINECAP[line_cap.first]
791
+ else
792
+ @line_cap ||= LINECAP[:rect]
793
+ end
794
+ end
714
795
  end
715
796
  end
data/lib/shoes/basic.rb CHANGED
@@ -3,6 +3,8 @@ class Shoes
3
3
  include Mod
4
4
  def initialize args
5
5
  @initials = args
6
+ @hided = true if args[:hidden]
7
+ args.delete :hidden
6
8
  args.each do |k, v|
7
9
  instance_variable_set "@#{k}", v
8
10
  end
@@ -39,10 +41,6 @@ class Shoes
39
41
  attr_reader :args, :initials
40
42
  attr_accessor :parent, :pl, :ln, :dps
41
43
 
42
- def hided
43
- @app.hided or @hided
44
- end
45
-
46
44
  def move x, y
47
45
  @app.cslot.contents -= [self]
48
46
  move3 x, y
@@ -61,6 +59,10 @@ class Shoes
61
59
  @left, @top = x, y
62
60
  end
63
61
 
62
+ def center_at x, y
63
+ [x - (@width / 2), y - (@height / 2)]
64
+ end
65
+
64
66
  def positioning x, y, max
65
67
  if parent.is_a?(Flow) and x + @width <= parent.left + parent.width
66
68
  move3 x + parent.margin_left, max.top + parent.margin_top
@@ -82,6 +84,7 @@ class Shoes
82
84
  @dps.clear
83
85
  @parent.contents -= [self]
84
86
  @app.mscs -= [self]
87
+ @app.mhcs -= [self]
85
88
  hide
86
89
  end
87
90
  end
@@ -154,8 +157,18 @@ class Shoes
154
157
  class Border < Pattern; end
155
158
 
156
159
  class ShapeBase < Basic; end
157
- class Rect < ShapeBase; end
158
- class Oval < ShapeBase; end
160
+ class Rect < ShapeBase
161
+ def move3 x, y
162
+ x, y = center_at(x, y) if @center
163
+ super
164
+ end
165
+ end
166
+ class Oval < ShapeBase
167
+ def move3 x, y
168
+ x, y = center_at(x, y) if @center
169
+ super
170
+ end
171
+ end
159
172
  class Line < ShapeBase; end
160
173
  class Star < ShapeBase
161
174
  def move3 x, y
@@ -247,7 +260,13 @@ class Shoes
247
260
  end
248
261
  end
249
262
 
250
- class Button < Native; end
263
+ class Button < Native
264
+ def click &blk
265
+ @real.addSelectionListener do |e|
266
+ self.class == Button ? blk[self] : (blk[self] if @real.getSelection)
267
+ end
268
+ end
269
+ end
251
270
  class ToggleButton < Button
252
271
  def checked?
253
272
  real.getSelection
@@ -260,9 +279,21 @@ class Shoes
260
279
  class Radio < ToggleButton; end
261
280
  class Check < ToggleButton; end
262
281
 
263
- class EditLine < Native; end
264
- class EditBox < Native; end
265
- class ListBox < Native; end
282
+ class EditLine < Native
283
+ def change &blk
284
+ @real.addModifyListener{|e| blk[self]}
285
+ end
286
+ end
287
+ class EditBox < Native
288
+ def change &blk
289
+ @real.addModifyListener{|e| blk[self]}
290
+ end
291
+ end
292
+ class ListBox < Native
293
+ def change &blk
294
+ @real.addSelectionListener{|e| blk[self]}
295
+ end
296
+ end
266
297
  class Progress < Native
267
298
  def fraction
268
299
  @real.isDisposed ? 0 : real.getSelection / 100.0
@@ -1,16 +1,18 @@
1
1
  class Shoes
2
2
  class Download
3
- def initialize name, args, &blk
3
+ def initialize app, name, args, &blk
4
4
  require 'open-uri'
5
5
  Thread.new do
6
6
  open name,
7
7
  content_length_proc: lambda{|len| @content_length, @started = len, true},
8
8
  progress_proc: lambda{|size| @progress = size} do |sio|
9
9
  open(args[:save], 'wb'){|fw| fw.print sio.read} if args[:save]
10
- #blk[sio] if blk
11
- @finished = true
10
+ @finished, @sio = true, sio
12
11
  end
13
12
  end
13
+ a = app.animate do
14
+ (a.stop; blk[@sio]) if @finished
15
+ end if blk
14
16
  end
15
17
 
16
18
  attr_reader :progress, :content_length
data/lib/shoes/help.rb CHANGED
@@ -4,10 +4,9 @@ require 'nkf'
4
4
  class Manual < Shoes
5
5
  url '/', :index
6
6
  url '/manual/(\d+)', :index
7
- #url '/mk_search_page', :mk_search_page
8
7
 
9
8
  include Hpricot
10
- #include HH::Markup
9
+ include HH::Markup
11
10
 
12
11
  def index pnum = 0
13
12
  font LANG == 'ja' ? 'MS UI Gothic' : 'Arial'
@@ -90,7 +89,7 @@ class Manual < Shoes
90
89
  end
91
90
  end
92
91
  para NL
93
- show_page mk_paras(d.gsub('&', '\u0026')), false, term
92
+ show_page mk_paras(d), false, term
94
93
  end
95
94
  end
96
95
 
@@ -107,8 +106,7 @@ class Manual < Shoes
107
106
  if _code.include? 'te-su-to'
108
107
  para fg(code(' ' + _code), maroon), NL, margin: [-10, 10, 0, 20]
109
108
  else
110
- #para code(highlight(' ' + _code, nil)), NL, margin: [-10, 10, 0, 20]
111
- para fg(code(' ' + _code), blueviolet), NL, margin: [-10, 10, 0, 20]
109
+ para *highlight(' ' + _code, nil).map{|e| code e}, NL, margin: [-10, 10, 0, 20]
112
110
  end
113
111
  end
114
112
  para NL
@@ -171,7 +169,7 @@ class Manual < Shoes
171
169
  COLORS.each do |color, v|
172
170
  r, g, b = v
173
171
  c = v.dark? ? white : black
174
- flow width: 0.33 do
172
+ flow width: 0.33, height: 55, margin_top: 5 do
175
173
  background send(color)
176
174
  para fg(strong(color), c), align: 'center'
177
175
  para fg("rgb(#{r}, #{g}, #{b})", c), align: 'center'
@@ -203,6 +201,7 @@ class Manual < Shoes
203
201
  end
204
202
 
205
203
  def find_pnum page
204
+ return 999 if page == 'Search'
206
205
  TOC_LIST.each_with_index do |e, i|
207
206
  title, section = e
208
207
  return i if title == page