vruby 2004.08.07

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,1326 @@
1
+ ###################################
2
+ #
3
+ # vrcontrol.rb
4
+ # Programmed by nyasu <nyasu@osk.3web.ne.jp>
5
+ # Copyright 1999-2001 Nishikawa,Yasuhiro
6
+ #
7
+ # More information at http://www.threeweb.ad.jp/~nyasu/software/vrproject.html
8
+ # (in Japanese)
9
+ #
10
+ ###################################
11
+
12
+ VR_DIR="vr/" unless defined?(::VR_DIR)
13
+ require VR_DIR+'vruby'
14
+ require VR_DIR+'sysmod'
15
+ =begin
16
+ = VisualuRuby(tmp) Standard Controls
17
+ This file prepares classes of standard controls, panels and menu modules.
18
+
19
+ <<< handlers.rd
20
+
21
+ === Control Container
22
+ * ((<VRStdControlContainer>))
23
+
24
+ === Standard Controls
25
+ * ((<VRButton>))
26
+ * ((<VRGroupbox>))
27
+ * ((<VRCheckbox>))
28
+ * ((<VRRadiobutton>))
29
+ * ((<VRStatic>))
30
+ * ((<VREdit>))
31
+ * ((<VRText>))
32
+ * ((<VRListbox>))
33
+ * ((<VRCombobox>))
34
+
35
+ === Menu
36
+ * ((<VRMenu>))
37
+ * ((<VRMenuItem>))
38
+ * ((<VRMenuUseable>))
39
+
40
+ === Panels
41
+ * ((<VRPanel>))
42
+ * ((<VRBitmapPanel>))
43
+ * ((<VRCanvasPanel>))
44
+ =end
45
+
46
+ ###########################################
47
+ # Messages and Styles
48
+ #
49
+
50
+ module WMsg
51
+ BN_CLICKED = 0
52
+ BN_DBLCLICKED = 5
53
+ BM_GETCHECK = 0xf0
54
+ BM_SETCHECK = 0xf1
55
+
56
+ STN_CLICKED = 0
57
+ STN_DBLCLICKED = 1
58
+
59
+ LB_ADDSTRING = 0x0180
60
+ LB_INSERTSTRING = 0x0181
61
+ LB_DELETESTRING = 0x0182
62
+ LB_SETSEL = 0x0185
63
+ LB_SETCURSEL = 0x0186
64
+ LB_GETSEL = 0x0187
65
+ LB_GETCURSEL = 0x188
66
+ LB_GETTEXT = 0x189
67
+ LB_GETTEXTLEN = 0x18a
68
+ LB_GETCOUNT = 0x18b
69
+ LB_SELECTSTRING = 0x18c
70
+ LB_DIR = 0x18d
71
+ LB_FINDSTRING = 0x18f
72
+ LB_GETSELCOUNT = 0x190
73
+ LB_GETSELITEMS = 0x191
74
+ LB_GETITEMDATA = 0x199
75
+ LB_SETITEMDATA = 0x19a
76
+ LBN_SELCHANGE=1
77
+ LBN_DBLCLK=2
78
+
79
+ CB_ADDSTRING = 0x143
80
+ CB_DELETESTRING = 0x144
81
+ CB_DIR = 0x145
82
+ CB_GETCOUNT = 0x146
83
+ CB_GETCURSEL = 0x147
84
+ CB_GETLBTEXT = 0x148
85
+ CB_GETLBTEXTLEN = 0x149
86
+ CB_INSERTSTRING = 0x14a
87
+ CB_FINDSTRING = 0x14c
88
+ CB_SELECTSTRING = 0x14d
89
+ CB_SETCURSEL = 0x14e
90
+ CB_GETITEMDATA = 0x150
91
+ CB_SETITEMDATA = 0x151
92
+ CB_SETEXTENDEDUI =0x155
93
+ CBN_SELCHANGE = 1
94
+ end
95
+
96
+ module WStyle
97
+ BS_PUSHBUTTON = 0
98
+ BS_CHECKBOX = 2
99
+ BS_AUTOCHECKBOX = 3
100
+ BS_RADIOBUTTON = 4
101
+ BS_3STATE = 5
102
+ BS_GROUPBOX = 7
103
+ BS_USERBUTTON = 8
104
+ BS_AUTORADIOBUTTON= 9
105
+
106
+ ES_MULTILINE = 4
107
+ ES_PASSWORD = 0x20
108
+ ES_AUTOVSCROLL = 0x40
109
+ ES_AUTOHSCROLL = 0x80
110
+ ES_READONLY = 0x800
111
+ ES_WANTRETURN = 0x1000
112
+ LBS_STANDARD = 0x00a00000 | 1
113
+ LBS_MULTIPLESEL = 8
114
+
115
+ CBS_STANDARD = 0x00a00200 | 3
116
+ CBS_AUTOSCROLL = 0x40
117
+ end
118
+
119
+ ###############################################
120
+ # Standard Control
121
+ #
122
+
123
+ class VRStdControl < VRControl
124
+ def _vr_cmdhandlers
125
+ unless defined?(@_vr_cmdhandlers)
126
+ @_vr_cmdhandlers={}
127
+ else
128
+ @_vr_cmdhandlers
129
+ end
130
+ end
131
+
132
+ def addCommandHandler(msg,handlername,handlertype,argparsestr)
133
+ @_vr_cmdhandlers={} unless defined?(@_vr_cmdhandlers)
134
+ @_vr_cmdhandlers[msg]=[] unless _vr_cmdhandlers[msg]
135
+ @_vr_cmdhandlers[msg].push [handlername,handlertype,argparsestr]
136
+ end
137
+
138
+ def deleteCommandHandler(msg,handlername)
139
+ return false unless @_vr_cmdhandlers[msg]
140
+ @_vr_cmdhandlers.delete_if do |shandler|
141
+ shandler[0] != (PREHANDLERSTR+handlername).intern
142
+ end
143
+ end
144
+ end
145
+
146
+
147
+ ################################################
148
+ # Standard Control Container
149
+ #
150
+ module VRStdControlContainer
151
+ =begin
152
+ == VRStdControlContainer
153
+ This module provides a message handler for WM_COMMAND, which calls
154
+ the defined methods in a parent window.
155
+ VRForm includes this module automatically loading "vrcontrol.rb".
156
+ =end
157
+
158
+ include VRMessageHandler
159
+
160
+ def stdcontrolcontainerinit
161
+ addHandler(WMsg::WM_COMMAND,"wmcommand",MSGTYPE::ARGPASS,nil)
162
+ addEvent WMsg::WM_COMMAND
163
+ end
164
+
165
+ def vrinit
166
+ super
167
+ stdcontrolcontainerinit
168
+ addNoRelayMessages [WMsg::WM_COMMAND]
169
+ end
170
+
171
+ def self_wmcommand(msg)
172
+ id=LOWORD(msg.wParam)
173
+ ct=@controls[id] # Activated Control
174
+ if !ct then
175
+ if !@_vr_menu then return end
176
+ ct=@_vr_menus[id]
177
+ if !ct then
178
+ return # no handler
179
+ end
180
+ end
181
+
182
+ messageid=HIWORD(msg.wParam)
183
+ return unless ct._vr_cmdhandlers and ct._vr_cmdhandlers[messageid]
184
+
185
+ ct._vr_cmdhandlers[messageid].each do |shandler|
186
+ args=msgarg2handlerarg(shandler[1],msg,shandler[2])
187
+ ct.__send__(shandler[0],*args) if ct.respond_to?(shandler[0])
188
+ msg.retval = controlmsg_dispatching(ct,shandler[0],*args)
189
+ end
190
+ end
191
+
192
+ end
193
+
194
+ # add
195
+ module VRContainersSet
196
+ include VRStdControlContainer
197
+ INITIALIZERS.push :stdcontrolcontainerinit
198
+ end
199
+
200
+
201
+
202
+ ##########################################
203
+ # Standard Controls
204
+ #
205
+ #
206
+ # Minimum definition for a Standard Control is
207
+ #
208
+ #> class VRSampleControl <VRStdControl
209
+ #> WINCLASSINFO = ["ControlClass",additionalStyle,exStyle]
210
+ #> def vrinit()
211
+ #> super
212
+ #> addCommandHandler(message,eventname,type,argparsestr])
213
+ #> end
214
+ #> end
215
+ #
216
+ # @_vr_cmdhandlers such as {
217
+ ## message -> [eventname, argtype, unpackstr]
218
+ # WMsg::BN_CLICKED=>["clicked",MSGTYPE::ARGNONE,nil],
219
+ # WMsg::LBN_SELCHANGE=>["selchange",MSGTYPE::ARGNONE,nil]
220
+ #}
221
+ # ############################################################
222
+
223
+ class VRButton < VRStdControl
224
+ =begin
225
+ == VRButton
226
+ Button.
227
+ Button's caption can be set/got by caption/caption= method of SWin::Window.
228
+
229
+ === Event handlers
230
+ Buttons invoke the following method of parent window.
231
+ --- ????_clicked
232
+ This parent's method is fired when button is pushed.
233
+ --- ????_dblclicked
234
+ This parent's method is fired when button is double clicked.
235
+ =end
236
+
237
+ WINCLASSINFO = ["BUTTON",WStyle::BS_PUSHBUTTON]
238
+
239
+ def vrinit
240
+ super
241
+ addCommandHandler(WMsg::BN_CLICKED, "clicked", MSGTYPE::ARGNONE,nil)
242
+ addCommandHandler(WMsg::BN_DBLCLICKED, "dblclicked",MSGTYPE::ARGNONE,nil)
243
+ end
244
+ end
245
+
246
+ class VRGroupbox < VRStdControl
247
+ =begin
248
+ == VRGroupbox
249
+ Groupbox.
250
+
251
+ This control can be a container of other window.
252
+ You need to extend this class by Container modules, VRStdControlContainer for Standard Controls and VRCommonControlContainer for Common Controls.
253
+ =end
254
+
255
+ include VRParent
256
+ WINCLASSINFO = ["BUTTON",WStyle::BS_GROUPBOX]
257
+ end
258
+
259
+ class VRCheckbox < VRButton
260
+ =begin
261
+ == VRCheckbox
262
+ Check box.
263
+ Parent class is ((<VRButton>))
264
+
265
+ === Methods
266
+ Checkbox has the following methods.
267
+ --- checked?
268
+ Return boolean value whether checkbox is checked or not.
269
+ --- check(v)
270
+ Check checkbox as v(=true/false).
271
+ =end
272
+ WINCLASSINFO = ["BUTTON",WStyle::BS_AUTOCHECKBOX]
273
+
274
+ def checked?
275
+ c=sendMessage(WMsg::BM_GETCHECK,0,0) #getcheck
276
+ return c!=0
277
+ end
278
+ def check(v)
279
+ sendMessage WMsg::BM_SETCHECK, ( (v)? 1 : 0 ),0
280
+ end
281
+ end
282
+
283
+ class VRRadiobutton < VRCheckbox
284
+ =begin
285
+ == VRRadiobutton
286
+ Radio Button.
287
+
288
+ Parent class is ((<VRCheckbox>))
289
+ =end
290
+ WINCLASSINFO = ["BUTTON",WStyle::BS_AUTORADIOBUTTON]
291
+ end
292
+
293
+
294
+ class VRStatic < VRStdControl
295
+ =begin
296
+ == VRStatic
297
+ Static Control(text).
298
+
299
+ Text can be access as caption.
300
+ =end
301
+ WINCLASSINFO = ["STATIC",0]
302
+ def vrinit
303
+ addCommandHandler(WMsg::STN_CLICKED, "clicked",0,nil)
304
+ end
305
+ end
306
+
307
+ class VREdit < VRStdControl
308
+ =begin
309
+ == VREdit
310
+ Edit Control.
311
+
312
+ === Methods
313
+ --- text
314
+ Gets Text in the control. Line break(\r\n) is translated by this method.
315
+ --- text=(str)
316
+ Sets Text in the control. Line break is translated by this method.
317
+ --- getSel
318
+ Returns [start_pos,end_pos] of the selected area.
319
+ --- setSel(st,en,noscroll=0)
320
+ Sets the selected area specified by ((|st|)) as start point and ((|en|))
321
+ as end point and Scrolls to show the area. When ((|noscroll|)) is 1,
322
+ it doesn't scroll.
323
+ --- setCaret(r)
324
+ Sets cursor point at ((|r|))
325
+ --- replaceSel(newstr)
326
+ Replaces text in the selected area with ((|newstr|)).
327
+ --- readonly=(b)
328
+ Sets readonly flag as boolean ((|b|))
329
+ --- limit
330
+ Gets the length limit of this Editbox.
331
+ --- limit=(lmt)
332
+ Sets the length limit of this Editbox.
333
+ --- modified
334
+ Returns true if the editbox text is modified by user.
335
+ --- modified=(f)
336
+ Sets modified flag of the editbox.
337
+ --- cut
338
+ Cuts the selected area into clipboard.
339
+ --- copy
340
+ Copies the selected area into clipboard.
341
+ --- paste
342
+ Paste the clipboard text into the editbox.
343
+ --- clear
344
+ Clears selected area text.
345
+ Use ((<cut>)) method to set the text into clipboard.
346
+ --- undo
347
+ Undo the previous cut/copy/paste/clear action.
348
+
349
+ === Event handlers
350
+ Editboxes invoke the following method of parent window.
351
+ --- ????_changed
352
+ This parent's method is fired when editbox text is modified.
353
+ =end
354
+
355
+ WINCLASSINFO = ["EDIT",WStyle::ES_AUTOHSCROLL,WExStyle::WS_EX_CLIENTEDGE]
356
+
357
+ def vrinit
358
+ super
359
+ addCommandHandler(0x300,"changed",MSGTYPE::ARGNONE,nil)
360
+ end
361
+
362
+ def getSel
363
+ r=sendMessage(0xb0,0,0)
364
+ return LOWORD(r),HIWORD(r)
365
+ end
366
+
367
+ def setCaret(r)
368
+ setSel(r,r)
369
+ end
370
+
371
+ def setSel(st,en,noscroll=0)
372
+ sendMessage(0xb1,st,en)
373
+ end
374
+
375
+ def replaceSel(newstr)
376
+ sendMessage(0xc2,0,newstr.to_s)
377
+ end
378
+
379
+ def readonly=(b)
380
+ f= (b)? 1 : 0
381
+ sendMessage 0xcf,f,0
382
+ end
383
+
384
+ def limit=(lmt)
385
+ sendMessage 0xc5,lmt.to_i,0
386
+ end
387
+ def limit
388
+ sendMessage 0xd5,0,0
389
+ end
390
+
391
+ def modified
392
+ r=sendMessage 0xb8,0,0 #GETMODIFY
393
+ if r==0 then false else true end
394
+ end
395
+ alias modified? :modified
396
+ def modified=(f)
397
+ r= if f then 1 else 0 end
398
+ sendMessage 0xb9,r,0
399
+ end
400
+
401
+ # change linebreak code
402
+ # caption,caption= methods is raw methods
403
+
404
+ VR_REGEXPNEWLINE="\r\n"
405
+ def text() self.caption.gsub(/#{VR_REGEXPNEWLINE}/,$/); end
406
+ def text=(str)
407
+ self.caption = str.gsub(/([^\r])\n/,'\1'+VR_REGEXPNEWLINE)
408
+ end
409
+
410
+
411
+ # for clipboard and so on..
412
+ def cut
413
+ sendMessage 0x300,0,0 #CUT
414
+ end
415
+ def copy
416
+ sendMessage 0x301,0,0 #COPY
417
+ end
418
+ def paste
419
+ sendMessage 0x302,0,0 #PASTE
420
+ end
421
+ def clear
422
+ sendMessage 0x303,0,0 #CLEAR
423
+ end
424
+ def undo
425
+ sendMessage 0x304,0,0 #UNDO
426
+ end
427
+
428
+ end
429
+
430
+ class VRText < VREdit
431
+ =begin
432
+ == VRText
433
+ Mutiline Editbox.
434
+ Parent class is ((<VREdit>))
435
+
436
+ === Methods
437
+ --- scrollTo(line.col)
438
+ Scrolls ((|line|)) lines vertically and ((|col|)) columns horizontally.
439
+ --- visibleStartLine
440
+ Returns line number of the first visible line in the editbox.
441
+ --- countLines
442
+ Returns max line number.
443
+ --- getLineLengthOf(ln)
444
+ Returns length of the ((|ln|))-th line.
445
+ --- getLineTextOf(ln,maxlen)
446
+ Returns text of ((|ln|))-th line. If maxlen is specified, returned text is
447
+ limited in its length.
448
+ --- scrollup
449
+ Scrolls line up in the editbox.
450
+ --- scrolldown
451
+ Scrolls line down in the editbox.
452
+ --- scrollupPage
453
+ Scrolls page up in the editbox.
454
+ --- scrolldownPage
455
+ Scrolls page down in the editbox.
456
+ --- scrolltocaret
457
+ Scrolls the caret into view in the editbox.
458
+ --- char2line(ptr)
459
+ Returns the index of the line that contains the specified character index.
460
+ --- line2char(ln)
461
+ Returns the character index of a line.
462
+ --- getCurrentLine
463
+ Returns the current line index.
464
+ =end
465
+
466
+ WINCLASSINFO = ["EDIT",
467
+ WStyle::ES_MULTILINE|WStyle::ES_AUTOVSCROLL,WExStyle::WS_EX_CLIENTEDGE
468
+ ]
469
+
470
+ private
471
+ def c_scroll(r)
472
+ sendMessage 0xb5,r.to_i,0
473
+ end
474
+
475
+ public
476
+
477
+ def countLines
478
+ sendMessage 0x00BA,0,0
479
+ end
480
+
481
+ def scrollTo(line,col)
482
+ sendMessage 0x00B6,0,MAKELPARAM(line,col) #LINESCROLL
483
+ end
484
+ def visibleStartLine()
485
+ sendMessage 0x00CE,0,0 #GETFIRSTVISIBLELINE
486
+ end
487
+
488
+ def getLineLengthOf(l)
489
+ sendMessage 0xc1,l.to_i,0 #GETLINELENGTH
490
+ end
491
+ def getLineTextOf(l,textsize=getLineLengthOf(l))
492
+ r=pack("Ia",textsize," "*textsize)
493
+ len=sendMessage 0xc4,l.to_i,r
494
+ r[0,len]
495
+ end
496
+
497
+ def scrollup() c_scroll 0; end
498
+ def scrolldown() c_scroll 1; end
499
+ def scrollupPage() c_scroll 2; end
500
+ def scrolldownPage() c_scroll 3; end
501
+
502
+ def scrolltocaret
503
+ sendMessage 0xb7,0,0 #SCROLLCARET
504
+ end
505
+
506
+ def char2line(ptr)
507
+ sendMessage 0xc9,ptr.to_i,0 #LINEFROMCHAR
508
+ end
509
+ def line2char(l)
510
+ sendMessage 0xbb,l.to_i,0 #LINEINDEX
511
+ end
512
+ def getCurrentLine
513
+ char2line(-1)
514
+ end
515
+ end
516
+
517
+
518
+ class VRListbox < VRStdControl
519
+ =begin
520
+ == VRListbox
521
+ Listbox.
522
+ Listbox has multi strings to select.
523
+
524
+ === Methods
525
+ --- addString(idx,str)
526
+ Adds ((|str|)) String at the ((|idx|)).
527
+ When ((|idx|)) is omitted, ((|str|)) is added at the bottom.
528
+ --- deleteString(idx)
529
+ Deletes string at ((|idx|))
530
+ --- countStrings
531
+ Returns the count of its strings.
532
+ --- clearStrings
533
+ Deletes all strings.
534
+ --- eachString
535
+ Yields each string.
536
+ --- setListStrings(strarray)
537
+ Sets array of string ( ((|strarray|)) ) as the listbox strings.
538
+ --- selectedString
539
+ Returns the selected index.
540
+ --- select(idx)
541
+ Selects ((|idx|))-th string.
542
+ --- getTextOf(idx)
543
+ Retrieves the text of ((|idx|))-th string.
544
+ --- setDir(fname,opt=0)
545
+ Sets the filenames specified by ((|fname|)) to the listbox.
546
+ ((|opt|)) specifies the attributes of the files to be added.
547
+ --- findString(findstr,start=0)
548
+ Finds ((|findstr|)) in the listbox strings and returns the its index.
549
+ ((|start|)) specifies the index to start finding.
550
+ --- getDataOf(idx)
551
+ Retrieves the 32bit value associated with the ((|idx|))-th string.
552
+ --- setDataOf(idx,data)
553
+ Associates the 32bit value with the ((|idx|))-th string.
554
+ === Event handlers
555
+ --- ????_selchanged
556
+ Fired when the selected string is changed.
557
+ =end
558
+
559
+ WINCLASSINFO = ["LISTBOX",WStyle::LBS_STANDARD,WExStyle::WS_EX_CLIENTEDGE]
560
+
561
+ def vrinit
562
+ super
563
+ addCommandHandler(WMsg::LBN_SELCHANGE, "selchange",MSGTYPE::ARGNONE,nil)
564
+ set_liststrings
565
+ end
566
+
567
+ private
568
+ def set_liststrings
569
+ clearStrings
570
+
571
+ return unless defined? @_vr_init_items
572
+ 0.upto(@_vr_init_items.size-1) do |idx|
573
+ addString idx,@_vr_init_items[idx]
574
+ end if @_vr_init_items
575
+ end
576
+
577
+ public
578
+ def addString(*arg)
579
+ if arg[0].is_a?(Integer) then
580
+ sendMessage WMsg::LB_INSERTSTRING,arg[0],arg[1].to_s
581
+ else
582
+ sendMessage WMsg::LB_ADDSTRING,0,arg[0].to_s
583
+ end
584
+ end
585
+
586
+ def deleteString(idx)
587
+ sendMessage WMsg::LB_DELETESTRING,idx.to_i,0
588
+ end
589
+ def countStrings
590
+ sendMessage WMsg::LB_GETCOUNT,0,0
591
+ end
592
+
593
+ def clearStrings
594
+ c=getCount
595
+ (1..c).each do |i|
596
+ deleteString 0 #delete #0 c-times
597
+ end
598
+ end
599
+
600
+ def eachString
601
+ c=getCount
602
+ 0.upto(c-1) do |i|
603
+ yield getString(i)
604
+ end
605
+ end
606
+
607
+ def setListStrings(sarray)
608
+ @_vr_init_items=sarray
609
+ if hWnd>0 then set_liststrings end
610
+ end
611
+
612
+ def selectedString
613
+ sendMessage(WMsg::LB_GETCURSEL,0,0)
614
+ end
615
+
616
+ def getTextOf(idx)
617
+ len = sendMessage(WMsg::LB_GETTEXTLEN,idx.to_i,0) #LB_gettextlen
618
+ raise "No such index(#{idx}) in the Listbox"if len<0
619
+ str=" " * len
620
+ sendMessage(WMsg::LB_GETTEXT,idx.to_i,str) #LB_getText
621
+ str
622
+ end
623
+
624
+ def select(idx)
625
+ sendMessage(WMsg::LB_SETCURSEL,idx.to_i,0)
626
+ end
627
+
628
+ def setDir(fname,opt=0)
629
+ sendMessage(WMsg::LB_DIR,opt.to_i,fname.to_s)
630
+ end
631
+
632
+ def findString(findstr,start=0)
633
+ sendMessage(WMsg::LB_FINDSTRING,start.to_i,findstr.to_s)
634
+ end
635
+
636
+ def getDataOf(idx)
637
+ sendMessage(WMsg::LB_GETITEMDATA,idx.to_i,0)
638
+ end
639
+ def setDataOf(idx,data)
640
+ sendMessage(WMsg::LB_SETITEMDATA,idx.to_i,data.to_i)
641
+ end
642
+
643
+ def eachSelected
644
+ count = sendMessage(WMsg::LB_GETSELCOUNT,0,0)
645
+
646
+ if count<1 then
647
+ yield selectedString
648
+ return
649
+ end
650
+
651
+ buffer = '\0\0\0\0' * count
652
+ sendMessage(WMsg::LB_GETSELITEMS,count,buffer)
653
+
654
+ buffer.unpack("I*")[0,count].each do |i|
655
+ yield i
656
+ end
657
+ end
658
+
659
+ end
660
+
661
+ class VRCombobox < VRStdControl
662
+ =begin
663
+ == VRCombobox
664
+ Combobox is like Listbox, but Only one string is selected.
665
+
666
+ === Methods
667
+ --- addString(idx,str)
668
+ Adds ((|str|)) String at the ((|idx|)).
669
+ When ((|idx|)) is omitted, ((|str|)) is added at the bottom.
670
+ --- deleteString(idx)
671
+ Deletes string at ((|idx|))
672
+ --- countStrings
673
+ Returns the count of its strings.
674
+ --- clearStrings
675
+ Deletes all strings.
676
+ --- eachString
677
+ Yields each string.
678
+ --- setListStrings(strarray)
679
+ Sets array of string ( ((|strarray|)) ) as the combobox strings.
680
+ --- selectedString
681
+ Returns the selected index.
682
+ --- select(idx)
683
+ Selects ((|idx|))-th string.
684
+ --- getTextOf(idx)
685
+ Retrieves the text of ((|idx|))-th string.
686
+ --- setDir(fname,opt=0)
687
+ Sets the filenames specified by ((|fname|)) to the combobox.
688
+ ((|opt|)) specifies the attributes of the files to be added.
689
+ --- findString(findstr,start=0)
690
+ Finds ((|findstr|)) in the combobox strings and returns the its index.
691
+ ((|start|)) specifies the index to start finding.
692
+ --- getDataOf(idx)
693
+ Retrieves the 32bit value associated with the ((|idx|))-th string.
694
+ --- setDataOf(idx,data)
695
+ Associates the 32bit value with the ((|idx|))-th string.
696
+ === Event handlers
697
+ --- ????_selchanged
698
+ Fired when the selected string is changed.
699
+ =end
700
+
701
+ WINCLASSINFO = ["COMBOBOX",WStyle::CBS_STANDARD]
702
+
703
+ def vrinit
704
+ super
705
+ set_liststrings
706
+ addCommandHandler(WMsg::CBN_SELCHANGE, "selchange",MSGTYPE::ARGNONE,nil)
707
+ end
708
+
709
+ private
710
+ def set_liststrings
711
+ clearStrings
712
+ return unless defined? @_vr_init_items
713
+ 0.upto(@_vr_init_items.size-1) do |idx|
714
+ addString idx,@_vr_init_items[idx]
715
+ end if @_vr_init_items
716
+ end
717
+
718
+ public
719
+ def addString(*arg)
720
+ if arg[0].is_a?(Integer) then
721
+ sendMessage WMsg::CB_INSERTSTRING,arg[0],arg[1].to_s
722
+ else
723
+ sendMessage WMsg::CB_ADDSTRING,0,arg[0].to_s
724
+ end
725
+ end
726
+
727
+
728
+ def deleteString(idx)
729
+ sendMessage WMsg::CB_DELETESTRING,idx,0
730
+ end
731
+ def countStrings
732
+ sendMessage WMsg::CB_GETCOUNT,0,0
733
+ end
734
+
735
+ def clearStrings
736
+ c=getCount
737
+ (1..c).each do |i|
738
+ deleteString 0 #delete #0 c-times
739
+ end
740
+ end
741
+
742
+ def eachString
743
+ c=getCount
744
+ 0.upto(c-1) do |i|
745
+ yield getString(i)
746
+ end
747
+ end
748
+
749
+ def setListStrings(sarray)
750
+ @_vr_init_items=sarray
751
+ if hWnd>0 then set_liststrings end
752
+ end
753
+
754
+ def selectedString
755
+ sendMessage(WMsg::CB_GETCURSEL,0,0)
756
+ end
757
+
758
+ def getTextOf(idx)
759
+ len = sendMessage(WMsg::CB_GETLBTEXTLEN,idx,0) #CB_gettextlen
760
+ raise "No such index(#{idx}) in the Combobox"if len<0
761
+ str=" " * len
762
+ sendMessage(WMsg::CB_GETLBTEXT,idx,str) #CB_getText
763
+ str
764
+ end
765
+
766
+ def select(idx)
767
+ sendMessage(WMsg::CB_SETCURSEL,idx,0)
768
+ end
769
+
770
+ def setDir(fname,opt=0)
771
+ sendMessage(WMsg::CB_DIR,opt.to_i,fname.to_s)
772
+ end
773
+
774
+ def findString(findstr,start=0)
775
+ sendMessage(WMsg::CB_FINDSTRING,start.to_i,findstr.to_s)
776
+ end
777
+
778
+ def getDataOf(idx)
779
+ sendMessage(WMsg::CB_GETITEMDATA,idx.to_i,0)
780
+ end
781
+ def setDataOf(idx,data)
782
+ sendMessage(WMsg::CB_SETITEMDATA,idx.to_i,data.to_i)
783
+ end
784
+ end
785
+
786
+ #####################################
787
+ # Editable Combobox
788
+ # programmed by USHIWATARI-san
789
+ module WMsg
790
+ CBN_EDITCHANGE = 5
791
+ end
792
+ module WStyle
793
+ CBS_DROPDOWN = 0x00a00200 | 2
794
+ end
795
+
796
+ class VREditCombobox < VRCombobox
797
+ =begin
798
+ == VREditCombobox
799
+ Editable Combobox.
800
+ This is a kind of Combobox where you can edit the text.
801
+
802
+ === Methods
803
+ This has also VRCombobox's methods.
804
+ --- text
805
+ Returns the current text.
806
+
807
+ === Event handlers
808
+ --- changed
809
+ Fired when the text is changed.
810
+ =end
811
+
812
+
813
+ WINCLASSINFO = ["COMBOBOX",WStyle::CBS_DROPDOWN | WStyle::CBS_AUTOSCROLL ]
814
+ def vrinit
815
+ super
816
+ addCommandHandler(WMsg::CBN_EDITCHANGE, "changed",MSGTYPE::ARGNONE,nil)
817
+ end
818
+
819
+ def text
820
+ self.caption
821
+ end
822
+ def text=(str)
823
+ self.caption = str.gsub(/([^\r])\n/,'\1'+VREdit::VR_REGEXPNEWLINE)
824
+ end
825
+
826
+ end
827
+
828
+
829
+
830
+ #####################################
831
+ # Menu
832
+ #
833
+ class VRMenu
834
+ =begin
835
+ == VRMenu
836
+ Menu.
837
+
838
+ === Methods
839
+ --- append(caption,state)
840
+ Adds a new menu item at the last with the caption of ((|caption|)) and
841
+ the state of ((|state|)). See ((<state=>)) about ((|state|)).
842
+ --- insert(ptr,caption,name,state)
843
+ Inserts new item at ((|ptr|)).
844
+ --- delete(id)
845
+ Deletes menu. ((|id|)) can be a instance of VRMenuItem or a menu-id integer.
846
+ --- count
847
+ Counts the menu items.
848
+ --- set(sarr)
849
+ Sets the menu according to the ((|sarr|)) which is a structured array
850
+ of strings such like
851
+ (({ [ ["&File", [["&Open","open"],["E&xit","exit"]], }))
852
+ (({ ["&Edit",["&Copy","copy]] }))
853
+ (({ ] ] }))
854
+ Caption : TEXT
855
+ Name : TEXT
856
+ Menu : [Caption, Name|Menu]
857
+
858
+ When a menu is clicked, ((|Name|))_clicked method is fired.
859
+
860
+ =end
861
+
862
+ attr :menu
863
+ attr :parent
864
+
865
+ SEPARATOR=["sep","_vrmenusep",0x800]
866
+
867
+ def initialize(menu,parent)
868
+ @menu=menu
869
+ @parent=parent
870
+ end
871
+
872
+ def append (*arg)
873
+ m=VRMenuItem.new(@menu)
874
+ id=@parent.newControlID
875
+ if arg[2] then
876
+ @menu.append arg[0],id,arg[2]
877
+ else
878
+ @menu.append arg[0],id
879
+ end
880
+ @parent.registerMenu(m,arg[1],id,arg[0])
881
+ m
882
+ end
883
+ def insert (ptr,*arg)
884
+ m=VRMenuItem.new(@menu)
885
+ id=@parent.newControlID
886
+ if arg.size>2 then
887
+ @menu.insert arg[0],id,ptr,arg[2]
888
+ else
889
+ @menu.insert arg[0],id,ptr
890
+ end
891
+ @parent.registerMenu(m,arg[1],id,arg[0])
892
+ m
893
+ end
894
+ def delete (id)
895
+ if id.is_a?(VRMenuItem) then
896
+ @menu.delete id.etc
897
+ else
898
+ @menu.delete id
899
+ end
900
+ end
901
+ def count (*arg)
902
+ @menu.count(*arg)
903
+ end
904
+
905
+ def set(sarr)
906
+ sarr.each do |item|
907
+ if item[1].is_a?(Array) then
908
+ m=@parent.newMenu(true)
909
+ m.set(item[1])
910
+ @menu.append item[0],m.menu,item[2]
911
+ elsif item[1].is_a?(VRMenu) then
912
+ @menu.append item[0],item[1].menu,item[2]
913
+ else
914
+ append(*item)
915
+ end
916
+ end
917
+ self
918
+ end
919
+ end
920
+
921
+ VRMenuTemplate = Struct.new("VRMenuTemplate",:caption,:item,:state)
922
+ =begin
923
+ == VRMenuTemplate
924
+ If you don't like using Array for VRMenu#set, this will help you.
925
+
926
+ === Methods
927
+ --- caption
928
+ --- caption=
929
+ Represents the caption of the menu.
930
+ --- item
931
+ --- item=
932
+ When ((|item|)) is String, ((|item|)) means the name of menu item.
933
+ This name is used for the event handler name like ((|item|))_clicked.
934
+ ((|item|)) can be also an instance of VRMenuTemplate. In this case ((|item|))
935
+ represents its submenu.
936
+ === example
937
+ a=VRMenuTemplate.new
938
+ a.caption,a.item = "Test1","test1"
939
+
940
+ b=VRMenuTemplate.new("Test2","test2")
941
+ c=VRMenuTemplate.new("Test3","test3",VRMenuItem::GRAYED)
942
+
943
+ d1=VRMenuTemplate.new("Test4-1","test41")
944
+ d2=VRMenuTemplate.new("Test4-2","test42")
945
+ d3=VRMenuTemplate.new("Test4-3","test43")
946
+
947
+ d = VRMenuTemplate.new
948
+ d.caption , d.item = "Test4" , [d1,d2,d3]
949
+ =end
950
+
951
+ class VRMenuItem
952
+ =begin
953
+ == VRMenuItem
954
+ This is a wrapper of SWin::Menu
955
+ === Methods
956
+ --- new(menu)
957
+ ((|menu|)) must be the instance of SWin::Menu.
958
+ --- state
959
+ Returns the state of the menu item.
960
+ --- state=
961
+ Sets the state of the menu item.
962
+ state means
963
+ * 0 MF_ENABLED
964
+ * 1 MF_GRAYED
965
+ * 2 MF_DISABLED
966
+ * 8 MF_CHECKED
967
+ --- checked?
968
+ Returns true if the menu item is checked.
969
+ --- checked=
970
+ Sets true/false whether the menu item is checked or not.
971
+ --- modify(text)
972
+ Modifies the text of the menu item.
973
+ =end
974
+ attr :name,1
975
+ attr :etc,1
976
+
977
+ GRAYED=1
978
+ DISABLED=2
979
+ CHECKED=8
980
+
981
+ def initialize(menu)
982
+ @menu=menu
983
+ end
984
+ def _vr_cmdhandlers
985
+ {0=>[["clicked",MSGTYPE::ARGNONE,nil]], # for menu
986
+ 1=>[["clicked",MSGTYPE::ARGNONE,nil]]} # for key accelerator
987
+ end
988
+
989
+ def state= (st)
990
+ @menu.setState(@etc,st)
991
+ end
992
+ def state
993
+ @menu.getState(@etc)
994
+ end
995
+ def checked=(f)
996
+ @menu.setChecked(@etc,f)
997
+ end
998
+ def checked?
999
+ (self.state&8)==8
1000
+ end
1001
+ def modify(text)
1002
+ @menu.modify @etc,text
1003
+ end
1004
+ end
1005
+
1006
+ module VRKeyAcceleratorUseable # Thanks to Yukimisake-san.
1007
+ def menuTransTable(hsh)
1008
+ tVirt = {"Ctrl" => 0x08,"Shift" => 0x04,"Alt" => 0x10}
1009
+ tVkey = {"F1"=>0x70,"F2"=>0x71,"F3"=>0x72,"F4"=>0x73,
1010
+ "F5"=>0x74,"F6"=>0x75,"F7"=>0x76,"F8"=>0x77,
1011
+ "F9"=>0x78,"F10"=>0x79,"F11"=>0x7a,"F12"=>0x7b,
1012
+ "Insert"=>0x2d,"Delete"=>0x2e,"PageUp"=>0x21,"PageDown"=>0x22,
1013
+ "End"=>0x23,"Home"=>0x24
1014
+ }
1015
+ r = []
1016
+ hsh.each{|k,v|
1017
+ fVirt = 1
1018
+ key = nil
1019
+ if txt = v[/\t.*/] then
1020
+ a = txt.strip!.split(/\+/)
1021
+ a[0,a.size-1].each{|ii|
1022
+ raise "Iregal Key" unless n = tVirt[ii]
1023
+ fVirt += n } if a.size > 1
1024
+ if (s = a[a.size-1]).size > 1 then
1025
+ unless key = tVkey[s] then raise "Iregal Key" end
1026
+ else
1027
+ key = (s.upcase)[0]
1028
+ end
1029
+ end
1030
+ if key then
1031
+ r << fVirt
1032
+ r << key
1033
+ r << k
1034
+ end
1035
+ }
1036
+ r
1037
+ end
1038
+ end
1039
+
1040
+ module VRMenuUseable
1041
+ =begin
1042
+ == VRMenuUseable
1043
+ Include this module to use menus.
1044
+
1045
+ === Methods
1046
+ --- newMenu(popup=false)
1047
+ Creates a new ((<VRMenu>)). If popup is true, the created menu is popup menu.
1048
+ --- newPopupMenu
1049
+ Same as newMenu(true)
1050
+ --- setMenu(menu)
1051
+ Sets the menu ((<VRMenu>)) to the window.
1052
+ --- showPopup(popupmenu)
1053
+ Shows ((|popupmenu|)) at the cursor position
1054
+ =end
1055
+
1056
+ include VRKeyAcceleratorUseable
1057
+
1058
+ SetForegroundWindow = Win32API.new("user32","SetForegroundWindow","I","I")
1059
+
1060
+ def registerMenu(m,name,id,mcaption="")
1061
+ m.etc= id
1062
+ instance_eval("@"+name+"=m")
1063
+ @_vr_menus= {} unless defined?(@_vr_menus)
1064
+ @_vr_menucaptions= {} unless defined?(@_vr_menucaptions)
1065
+ @_vr_menus[id]= m
1066
+ @_vr_menucaptions[id] = mcaption
1067
+ m.name = name
1068
+ m
1069
+ end
1070
+
1071
+ def newMenu(popup=false)
1072
+ if popup then
1073
+ menu=@screen.factory.newpopup
1074
+ else
1075
+ menu=@screen.factory.newmenu
1076
+ end
1077
+ VRMenu.new(menu,self)
1078
+ end
1079
+
1080
+ def newPopupMenu # contributed by Yuya-san
1081
+ return self.newMenu(true)
1082
+ end
1083
+
1084
+ def setMenu(menu,keyacc=false)
1085
+ SetForegroundWindow.call(self.hWnd)
1086
+ if menu.is_a?(SWin::Menu) then
1087
+ super menu
1088
+ return
1089
+ end
1090
+
1091
+ @_vr_menu=menu
1092
+ @menu=menu
1093
+ super menu.menu
1094
+ if keyacc then
1095
+ tb = menuTransTable(@_vr_menucaptions)
1096
+ SWin::Application.setAccel(self,tb)
1097
+ end
1098
+ end
1099
+
1100
+ def showPopup(menu)
1101
+ SetForegroundWindow.call(self.hWnd)
1102
+ if menu.is_a?(SWin::Menu) then
1103
+ m=menu
1104
+ else # asumes it is VRMenu
1105
+ m=menu.menu
1106
+ @_vr_menu = menu
1107
+ end
1108
+ popupMenu m,*Cursor.get_screenposition
1109
+ end
1110
+
1111
+ def setMenuByArray(arr)
1112
+ self.setMenu newMenu(arr)
1113
+ end
1114
+
1115
+ end
1116
+
1117
+
1118
+ ##############################
1119
+ # Other Controls
1120
+ #
1121
+
1122
+ module WStruct
1123
+ SCROLLINFO="llllll"
1124
+ end
1125
+
1126
+ class VRScrollbar < VRControl
1127
+ WINCLASSINFO = ["SCROLLBAR",0]
1128
+ attr :smallstep,1
1129
+ attr :longstep,1
1130
+
1131
+ def vrinit
1132
+ setRange(0,100)
1133
+ self.pagesize=10
1134
+ self.position=50
1135
+ @smallstep, @longstep = 1,10
1136
+ end
1137
+
1138
+ def setRange(min,max)
1139
+ sendMessage 0xe6,min.to_i,max.to_i
1140
+ end
1141
+
1142
+ def position=(val)
1143
+ sendMessage 0xe0,val.to_i,1
1144
+ end
1145
+ def position
1146
+ sendMessage 0xe1,0,0
1147
+ end
1148
+
1149
+ def pagesize=(p)
1150
+ si=[4*7,2,0,0,p.to_i,0,0].pack WStruct::SCROLLINFO
1151
+ sendMessage 0xe9,1,si # SBM_SETSCROLLINFO
1152
+ end
1153
+ def pagesize
1154
+ si=[4*7,2,0,0,0,0,0].pack WStruct::SCROLLINFO
1155
+ sendMessage 0xea,1,si # SBM_GETSCROLLINFO
1156
+ si.unpack(WStruct::SCROLLINFO)[4]
1157
+ end
1158
+ end
1159
+
1160
+ class VRHScrollbar < VRScrollbar
1161
+ WINCLASSINFO = ["SCROLLBAR",0]
1162
+ end
1163
+ class VRVScrollbar < VRScrollbar
1164
+ WINCLASSINFO = ["SCROLLBAR",1]
1165
+ end
1166
+
1167
+ module WMsg
1168
+ WM_HSCROLL=276
1169
+ WM_VSCROLL=277
1170
+ end
1171
+
1172
+ module VRScrollbarContainer
1173
+ def scrollbarcontainerinit
1174
+ addHandler WMsg::WM_HSCROLL,"vrscroll",MSGTYPE::ARGINTINT,nil
1175
+ addHandler WMsg::WM_VSCROLL,"vrscroll",MSGTYPE::ARGINTINT,nil
1176
+ acceptEvents [ WMsg::WM_HSCROLL,WMsg::WM_VSCROLL]
1177
+ @_vr_scrollbars={}
1178
+ end
1179
+ def vrinit
1180
+ super
1181
+ scrollbarcontainerinit
1182
+ end
1183
+
1184
+ def searchscrollbar(hwnd)
1185
+ @_vr_scrollbars=Hash.new unless defined? @_vr_scrollbars
1186
+ srl = @_vr_scrollbars[hwnd] # false : to be ignored window, 0: form
1187
+ if srl==nil then
1188
+ @controls.each_value do |v|
1189
+ if v.is_a?(SWin::Window) and v.hWnd==hwnd then
1190
+ if v.is_a?(VRScrollbar) then
1191
+ @_vr_scrollbars[hwnd] = srl = v
1192
+ elsif defined?(VRTrackbar) and v.is_a?(VRTrackbar) then
1193
+ @_vr_scrollbars[hwnd] = srl = false
1194
+ elsif defined?(VRUpdown) and v.is_a?(VRUpdown) then
1195
+ @_vr_scrollbars[hwnd] = srl = false
1196
+ else
1197
+ @_vr_scrollbars[hwnd] = srl = 0
1198
+ end
1199
+ break
1200
+ end
1201
+ end # @controls.each_value
1202
+ end
1203
+
1204
+ case srl
1205
+ when 0
1206
+ self
1207
+ when false
1208
+ nil
1209
+ when nil
1210
+ nil
1211
+ else
1212
+ srl
1213
+ end
1214
+ end
1215
+
1216
+ def self_vrscroll(wparam,hwnd)
1217
+ srl = searchscrollbar(hwnd)
1218
+ return unless srl
1219
+
1220
+ code=LOWORD(wparam)
1221
+ if code==4 then
1222
+ pos=HIWORD(wparam)
1223
+ else
1224
+ pos = srl.position
1225
+ end
1226
+ case code
1227
+ when 0
1228
+ srl.sendMessage 224,pos-srl.smallstep,1
1229
+ when 1
1230
+ srl.sendMessage 224,pos+srl.smallstep,1
1231
+ when 2
1232
+ srl.sendMessage 224,pos-srl.longstep,1
1233
+ when 3
1234
+ srl.sendMessage 224,pos+srl.longstep,1
1235
+ when 4
1236
+ srl.sendMessage 224,pos,1
1237
+ end
1238
+ controlmsg_dispatching(srl,"changed")
1239
+ end
1240
+ end
1241
+
1242
+ # add
1243
+ module VRContainersSet
1244
+ include VRScrollbarContainer
1245
+ INITIALIZERS.push :scrollbarcontainerinit
1246
+ end
1247
+
1248
+
1249
+ ########################
1250
+ #
1251
+ # Control using VRPanel
1252
+ #
1253
+ class VRBitmapPanel < VRPanel
1254
+ =begin
1255
+ == VRBitmapPanel
1256
+ Bitmap panel that can display static bitmap.
1257
+
1258
+ === Methods
1259
+ --- loadFile(filename)
1260
+ Loads ((|filename|)) as bitmap file.
1261
+ --- createBitmap(info,bmp)
1262
+ Creates an bitmap from ((|info|)) and ((|bmp|)).
1263
+ --- bmp
1264
+ The instance of displaying SWin::Bitmap.
1265
+ =end
1266
+ attr :bmp,1
1267
+
1268
+ include VRDrawable
1269
+ def vrinit
1270
+ super
1271
+ @bmp=nil
1272
+ end
1273
+
1274
+ def loadFile(fname)
1275
+ @bmp=SWin::Bitmap.loadFile fname
1276
+ self.refresh
1277
+ end
1278
+
1279
+ def createBitmap(info,bmp)
1280
+ @bmp=SWin::Bitmap.createBitmap info,bmp
1281
+ self.refresh
1282
+ end
1283
+
1284
+ def self_paint
1285
+ drawBitmap @bmp if @bmp.is_a?(SWin::Bitmap)
1286
+ end
1287
+ end
1288
+
1289
+
1290
+ class VRCanvasPanel < VRPanel
1291
+ =begin
1292
+ == VRCanvasPanel
1293
+ Bitmap Canvas panel that can display drawable bitmap.
1294
+ === Methods
1295
+ --- createCanvas(w,h,color=0xffffff)
1296
+ Creates a new canvas dimensioned ( ((|w|)),((|h||)) ) and
1297
+ colored ((|color|)) on the background.
1298
+ --- canvas
1299
+ Returns the instance of SWin::Canvas to draw it.
1300
+ =end
1301
+
1302
+ attr :canvas
1303
+
1304
+ include VRDrawable
1305
+
1306
+ def createCanvas(w,h,color=0xffffff)
1307
+ @canvas=@screen.factory.newcanvas(w,h)
1308
+ @canvas.setBrush(color)
1309
+ @canvas.setPen(color)
1310
+ @canvas.fillRect(0,0,w,h)
1311
+ @canvas.setPen(0x0)
1312
+ end
1313
+
1314
+ def vrinit
1315
+ super
1316
+ @canvas=nil
1317
+ end
1318
+
1319
+ def self_paint
1320
+ bitblt @canvas if @canvas
1321
+ end
1322
+ end
1323
+
1324
+ if VR_COMPATIBILITY_LEVEL then
1325
+ require VR_DIR + 'compat/vrcontrol.rb'
1326
+ end