1 /******************************************************************************
2 *
3 * Copyright (C) 2004-2007, The Gentee Group. All rights reserved.
4 * This file is part of the Gentee open source project - http://www.gentee.com.
5 *
6 * THIS FILE IS PROVIDED UNDER THE TERMS OF THE GENTEE LICENSE ("AGREEMENT").
7 * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS FILE CONSTITUTES RECIPIENTS
8 * ACCEPTANCE OF THE AGREEMENT.
9 *
10 * ID: vis.menu 18.07.07 0.0.A.
11 *
12 * Author: Alexander Krivonogov ( gentee )
13 *
14 ******************************************************************************/
15
16 define {
17 SHORTKEY_MAX = 0x7C
18 }
19
20 type shortkey
21 {
22 uint mstate
23 uint key
24 uint next
25 str pcaption
26 }
27
28 global {
29 hash hshortkey of uint
30 }
31 func shortkey_init <entry>
32 {
33 uint i
34 collection names = %{ "Shift", "Ctrl", "Alt", "BkSp", "Enter", "Esc", "Space", "PgUp", "PgDn", "End", "Home", "Left", "Up", "Right", "Down", "Ins", "Del"}
35 collection keys = %{ 0x10 , 0x11, 0x12, 0x08 , 0x0D , 0x1B , 0x20 , 0x21 , 0x22 , 0x23 , 0x24 , 0x25 , 0x26, 0x27 , 0x28 , 0x2D , 0x2E }
36 hshortkey.ignorecase()
37 fornum i = 0, *names
38 {
39 hshortkey[names[i]->str] = keys[i]
40 }
41 fornum i = 1, 11
42 {
43 hshortkey[ "F\(i)" ] = 0x6F + i
44
45 }
46 fornum i = 0, 10
47 {
48 hshortkey[ "\(i)" ] = 0x30 + i
49 }
50 fornum i = 'A', 'Z' + 1
51 {
52 hshortkey[ "".appendch( i ) ] = i
53 }
54
55 }
56
57 property ustr shortkey.caption<result>()
58 {
59 result = .pcaption
60 }
61
62 property shortkey.caption( str value )
63 {
64 subfunc add( str sadd )
65 {
66 if *.pcaption : .pcaption@"+"
67 .pcaption@sadd
68 }
69
70 uint i, key, mstate
71 arrstr s
72 value.split( s, '+', $SPLIT_NOSYS )
73 if *s
74 {
75 fornum i = 0, *s - 1
76 {
77 //print( s[i] )
78 switch hshortkey[s[i]]
79 {
80 case 0x10: mstate |= $mstShift
81 case 0x11: mstate |= $mstCtrl
82 case 0x12: mstate |= $mstAlt
83 }
84 }
85 switch key = hshortkey[s[i]]
86 {
87 case 0x10, 0x11, 0x12: key = 0
88 }
89 if key
90 {
91 .pcaption.clear()
92 .key = key
93 .mstate = mstate
94 if .mstate & $mstShift : add( "Shift" )
95 if .mstate & $mstCtrl : add( "Ctrl" )
96 if .mstate & $mstAlt : add( "Alt" )
97 foreach name, hshortkey.keys
98 {
99 if hshortkey[name] == .key
100 {
101 add( name )
102 break;
103 }
104 }
105 }
106 }
107 else
108 {
109 .key = 0
110 .mstate = 0
111 .pcaption.clear()
112 }
113 }
114
115 /* Компонента vCustomMenu, порождена от vComp, является заготовкой для
116 vMenu, vMenuItem, vPopupMenu
117 */
118
119 type vCustomMenu <index=vComp inherit = vComp> {
120 //Hidden Fields
121 uint phMenu //Хэндл меню
122 uint pFake
123 }
124
125 /* Компонента vCustomMainMenu, порождена от vCustomMenu, может содержать vMenuItem
126 */
127 type vCustomMainMenu <inherit = vCustomMenu> {
128 reserved tblkey[ $SHORTKEY_MAX * 8]
129 }
130
131 extern {
132 method vCustomMenu.mInsert <alias=vCustomMenu_mInsert>( vComp comp )
133 method vCustomMainMenu vCustomMenu.iMainMenu()
134 /* method vCustomMainMenu.FreeShortKey( vCustomMenu item )
135 method vCustomMainMenu.SetShortKey( vCustomMenu item )*/
136 }
137
138
139 /* Компонента vMenu, порождена от vCustomMainMenu, может содержать vMenuItem
140 */
141 type vMenu <inherit = vCustomMainMenu> {
142 }
143
144 include {
145 "menuitem.g"
146 }
147
148 method vCustomMainMenu.FreeShortKey( vMenuItem item )
149 {
150 uint key
151 if ( key = item.pShortKey.key ) && key < $SHORTKEY_MAX
152 {
153 uint addr
154 uint previtem as
155 ( addr = &.tblkey + ( key << 3 ) )->vMenuItem
156
157 if &previtem == &item
158 {
159 addr->uint = item.pShortKey.next
160 }
161 else
162 {
163 while &previtem
164 {
165 if &previtem.pShortKey.next == &item
166 {
167 previtem.pShortKey.next = item.pShortKey.next
168 break
169 }
170 previtem as previtem.pShortKey.next->vMenuItem
171 }
172 }
173 }
174 }
175
176 method vCustomMainMenu.SetShortKey( vMenuItem item )
177 {
178 uint key
179 if ( key = item.pShortKey.key ) && key < $SHORTKEY_MAX
180 {
181 uint addr
182 uint nextitem as
183 ( (addr = &.tblkey + ( key << 3 ))->uint )->vMenuItem
184 addr->uint = &item
185 item.pShortKey.next = &nextitem
186 }
187 }
188
189 method uint vCustomMainMenu.CheckShortKey( uint mstate, key )
190 {
191 if key && key < $SHORTKEY_MAX
192 {
193 uint nextitem as
194 ( &.tblkey + (key << 3 ) )->uint->vMenuItem
195 while &nextitem
196 {
197 if nextitem.Enabled && nextitem.pShortKey.mstate == mstate
198 {
199 nextitem.OnClick.Run( nextitem )
200 return 1
201 }
202 nextitem as nextitem.pShortKey.next
203 }
204 }
205 return 0
206 }
207
208 /*Метод vMenuItem.iMainMenu()
209 Получить основное меню
210 */
211 method vCustomMainMenu vCustomMenu.iMainMenu()
212 {
213 uint mainmenu as this
214 while mainmenu.Owner.TypeIs( vCustomMenu )
215 {
216 mainmenu as mainmenu.Owner
217 }
218 return mainmenu as vCustomMainMenu
219 }
220
221
222 /*------------------------------------------------------------------------------
223 Properties
224 */
225 /*Количество элементов uint *vMenu
226 Возвращает количество закладок
227 */
228 operator uint *( vCustomMenu menu )
229 {
230 return *menu.Comps
231 }
232
233 /*Индекс vMenuItem vMenu[index]
234 Возвращает закладку с текущим номером
235 */
236 method vMenuItem vCustomMenu.index( uint index )
237 {
238 if index != -1 && index < *.Comps
239 {
240 return .Comps[ index ]->vMenuItem
241 }
242 return 0->vMenuItem
243 }
244
245 /*------------------------------------------------------------------------------
246 Virtual methods
247 */
248 method vCustomMenu.mInsert /*<alias = vCustomMenu_mInsert> */( vComp comp )
249 {
250 if comp.TypeIs( vMenuItem )
251 {
252 this->vComp.mInsert( comp )
253 MENUITEMINFO mi
254 mi.cbSize = sizeof( MENUITEMINFO )
255 mi.fMask = $MIIM_ID
256 mi.wID = &comp
257 InsertMenuItem( .phMenu, 1, 0, mi )
258 comp->vMenuItem.iUpdate()
259 this.iMainMenu().SetShortKey( comp->vMenuItem )
260 }
261 if !this.TypeIs( vMenu )
262 {
263 if .pFake
264 {
265 RemoveMenu( .phMenu, .pFake, 0 )
266 }
267 else
268 {
269 .pFake = &App.CreateComp( vFakeMenuItem )
270 }
271
272 MENUITEMINFO mi
273 mi.cbSize = sizeof( MENUITEMINFO )
274 mi.fMask = $MIIM_ID | $MIIM_TYPE
275 mi.fType = $MFT_SEPARATOR | $MFT_OWNERDRAW
276 mi.wID = .pFake
277 .pFake->vFakeMenuItem.pMenu = &this
278 InsertMenuItem( .phMenu, .pFake, GetMenuItemCount( .phMenu ) - 1, mi )
279 }
280
281 }
282
283 method vCustomMenu.mRemove <alias = vCustomMenu_mRemove> ( vComp comp )
284 {
285 if comp.TypeIs( vMenuItem )
286 {
287 RemoveMenu( .phMenu, &comp, 0 )
288 }
289 this->vComp.mRemove( comp )
290 }
291
292 /*method vMenu.Activate( vComp owner)
293 {
294 if &owner && owner.TypeIs( vForm )
295 {
296 // print( "z12 \(.Name)\n" )
297 SetMenu( owner->vForm.hwnd, .phMenu )
298 DrawMenuBar( owner->vForm.hwnd )
299 }
300 //}
301 }*/
302
303 /*method vMenu.mSetOwner <alias = vMenu_mSetOwner>( vComp newowner )
304 {
305 if this.pOwner
306 {
307 SetMenu( .Owner->vForm.hwnd, 0 )
308 DrawMenuBar( .Owner->vForm.hwnd )
309 }
310 this->vComp.mSetOwner( newowner )
311 //.Activate( .Owner )
312 if &.Owner && .Owner.TypeIs( vForm )
313 {
314 SetMenu( .Owner->vForm.hwnd, .phMenu )
315 DrawMenuBar( .Owner->vForm.hwnd )
316 }
317 }*/
318
319 /*------------------------------------------------------------------------------
320 Registration
321 */
322 method vCustomMenu vCustomMenu.init( )
323 {
324 this.pTypeId = vCustomMenu
325 return this
326 }
327
328 method vCustomMenu vCustomMainMenu.init( )
329 {
330 this.pTypeId = vCustomMainMenu
331 return this
332 }
333
334
335 method vMenu vMenu.init( )
336 {
337 this.pTypeId = vMenu
338 this.phMenu = CreateMenu()
339 return this
340 }
341
342 method vCustomMenu.delete( )
343 {
344 if this.phMenu
345 {
346 DestroyMenu( this.phMenu )
347 }
348 }
349
350
351 func init_vMenu <entry>()
352 {
353 regcomp( vCustomMenu, "vCustomMenu", vComp, $vComp_last,
354 %{ %{$mInsert, vCustomMenu_mInsert },
355 %{$mRemove, vCustomMenu_mRemove }
356 },
357 0->collection )
358
359 regcomp( vMenu, "vMenu", vCustomMenu, $vComp_last,
360 /*%{ %{$mSetOwner, vMenu_mSetOwner }
361 },*/
362 0->collection,
363 0->collection )
364
365 regcomp( vMenuItem, "vMenuItem", vCustomMenu, $vCtrl_last,
366 %{ %{$mInsert, vMenuItem_mInsert },/*
367 %{$mSetOwner, vMenuItem_mSetOwner },*/
368 %{$mMenuClick, vMenuItem_mMenuClick },
369 %{$mLangChanged, vMenuItem_mLangChanged }/*,
370 %{$mWinDrawItem, vMenuItem_mWinDrawItem },
371 %{$mWinMeasureItem, vMenuItem_mWinMeasureItem }*/
372 },
373 0->collection )
374
375 regcomp( vFakeMenuItem, "vFakeMenuItem", vComp, $vCtrl_last,
376 %{
377 %{$mWinDrawItem, vFakeMenuItem_mWinDrawItem },
378 %{$mWinMeasureItem, vFakeMenuItem_mWinMeasureItem }
379 },
380 0->collection )
381
382 ifdef $DESIGNING {
383 cm.AddComp( vMenu, 1, "Windows", "menu" )
384
385 cm.AddComp( vMenuItem )
386 cm.AddProps( vMenuItem, %{
387 "Caption", ustr, 0,
388 "Visible", uint, 0,
389 "Enabled", uint, 0,
390 "Separator", uint, 0,
391 "Checked", uint, 0,
392 "RadioCheck", uint, 0,
393 "AutoCheck", uint, 0,
394 "ShortKey", ustr, 0,
395 "Image", ustr, 0,
396 "Ellipsis", uint, 0
397 })
398
399 cm.AddEvents( vMenuItem, %{
400 "OnClick" , "evparEvent"
401 })
402
403
404 }
405
406 }
407
408
409