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.splitter 31.03.08 0.0.A.
11 *
12 * Author: Alexander Krivonogov ( gentee )
13 *
14 ******************************************************************************/
15
16 /* Компонента vSplitter, порождена от vCtrl
17 Может иметь только два объекта, для того чтобы поменять объекты местами изменить
18 TabOrder
19 */
20 /*! В перспективе: свертывание одного из объектов, свертывание по двойному нажатию
21 мышки, отображение полоски сплиттера
22 */
23 type vSplitter <inherit = vCtrl>
24 {
25 //Hidden Fields
26 uint pAutoSize
27 uint pDistance
28 uint pRealDistance
29 uint pSplitterWidth
30 uint pOrientation
31 uint pFixedPart
32 uint pLeftMinSize
33 uint pRightMinSize
34
35 double pProportion //Пропорция для изменения размеров левой и правой части
36 uint fDrag //Флаг режима перетаскивания
37 uint fUpdatingSize //Флаг обновления размеров
38 //Events
39 evEvent OnMoved
40 }
41
42 define <export>{
43 //Orientation values:
44 soVertical = 0 //Объекты слева и справа
45 soHorizontal = 1 //Объекты сверху и снизу
46
47 //FixedPart values: При изменении размеров самого сплитера
48 sfpLeft = 0 //Левый объект не будет изменяться
49 sfpRight = 1 //Правый объект не будет изменяться
50 sfpNone = 2 //Объекты будут изменяться пропорционально
51 }
52
53 extern {
54 property uint vSplitter.Distance()
55 property vSplitter.Distance( uint val)
56 }
57
58 /*------------------------------------------------------------------------------
59 Internal Methods
60 */
61 /*Метод vSplitter.iUpdateSize()
62 Пересчитать размеры левого и правого объекта
63 */
64 method vSplitter.iUpdateSize()
65 {
66 if !.hwnd : return
67 uint distance
68 .fUpdatingSize = 1
69 uint width = ?( .pOrientation == $soVertical, this.Width, this.Height ) -
70 .pSplitterWidth
71
72 if int( width ) > 0 && !.pAutoSize
73 {
74 switch .pFixedPart
75 {
76 case $sfpLeft
77 {
78 .pDistance = max( int( .pDistance ), int( .pLeftMinSize ) )
79 distance = width - max( int( width - .pDistance ), int( .pRightMinSize ) )
80 distance = max( int( distance ), int( .pLeftMinSize ) )
81 distance = min( width, int( distance ))
82 }
83 case $sfpRight
84 {
85 distance = width - max( int( width - .pDistance ), int( .pRightMinSize ) )
86 distance = max( int( distance ), 0 ) //int( .pLeftMinSize ) )
87 distance = min( width, int( distance ))
88 }
89 default
90 {
91 distance = width - max( int( width - .pDistance ), int( .pRightMinSize ) )
92 distance = max( int( distance ), int( .pLeftMinSize ) )
93 distance = min( width, int( distance ))
94 }
95 }
96 }
97 else : distance = .pDistance
98
99 if .pRealDistance != distance
100 {
101 .OnMoved.Run( this )
102 }
103 .pRealDistance = distance
104 ifdef !$DESIGNING {
105 if *.Comps
106 {
107 if !.Comps[0]->vCtrl.Visible : distance = 0
108 elif *.Comps > 1 && !.Comps[1]->vCtrl.Visible : distance = width
109 }
110 }
111 if *.Comps && .Comps[0]->vCtrl.Visible
112 {
113 uint left as .Comps[0]->vCtrl
114 left.HorzAlign = $alhLeft
115 left.VertAlign = $alvTop
116 left.flgNoPosChanging = 0
117 left.Left = 0
118 left.Top = 0
119
120 if .pOrientation == $soVertical
121 {
122 left.Height = this.Height
123 left.Width = distance
124 }
125 else
126 {
127 left.Height = distance
128 left.Width = .Width
129 }
130 if !( ( .pAutoSize || .p_designing ) && .pFixedPart == $sfpLeft ) : left.flgNoPosChanging = 1
131 }
132 if *.Comps > 1 && .Comps[1]->vCtrl.Visible
133 {
134 uint right as .Comps[1]->vCtrl
135 right.HorzAlign = $alhLeft
136 right.VertAlign = $alvTop
137 right.flgNoPosChanging = 0
138
139 if .pOrientation == $soVertical
140 {
141 right.Top = 0
142 right.Height = this.Height
143 right.Left = distance + .pSplitterWidth
144 right.Width = .Width - distance - .pSplitterWidth
145 }
146 else
147 {
148 right.Top = distance + .pSplitterWidth
149 right.Left = 0
150 right.Width = this.Width
151 right.Height = .Height - distance - .pSplitterWidth
152 }
153 if !( ( .pAutoSize || .p_designing ) && .pFixedPart == $sfpRight ) : right.flgNoPosChanging = 1
154 }
155 .fUpdatingSize = 0
156 }
157
158 /*------------------------------------------------------------------------------
159 Properties
160 */
161 /* Свойство uint vSplitter.AutoSize - Get Set
162 Режим работы сплиттера, когда недоступно ручное изменение размеров, но при
163 изменении размеров одного объекта, меняются размеры другого
164 */
165 property uint vSplitter.AutoSize()
166 {
167 return this.pAutoSize
168 }
169
170 property vSplitter.AutoSize( uint val)
171 {
172 if this.pAutoSize != val
173 {
174 this.pAutoSize = val
175 .iUpdateSize()
176 }
177 }
178
179 /* Свойство uint vSplitter.Distance - Get Set
180 Положение сплиттера (расстояние от левого или верхнего края
181 */
182 property uint vSplitter.Distance()
183 {
184 return this.pDistance
185 }
186
187 property vSplitter.Distance( uint val)
188 {
189 if this.pDistance != val
190 {
191 this.pDistance = val
192 .iUpdateSize()
193 .pProportion = double( .pDistance ) / double( .Width )
194 }
195 }
196
197 /* Свойство uint vSplitter.SplitterWidth - Get Set
198 Ширина полоски сплиттера
199 */
200 property uint vSplitter.SplitterWidth()
201 {
202 return this.pSplitterWidth
203 }
204
205 property vSplitter.SplitterWidth( uint val)
206 {
207 val = min( max( int( val ), int( 0 ) ), 50 )
208 if this.pSplitterWidth != val
209 {
210 this.pSplitterWidth = val
211 .iUpdateSize()
212 }
213 }
214
215 /* Свойство uint vSplitter.Orientation - Get Set
216 Ориентация сплиттера (возможные значения - so* )
217 */
218 property uint vSplitter.Orientation()
219 {
220 return this.pOrientation
221 }
222
223 property vSplitter.Orientation( uint val)
224 {
225 if this.pOrientation != val
226 {
227 this.pOrientation = val
228 .iUpdateSize()
229 }
230 }
231
232 /* Свойство uint vSplitter.FixedPart - Get Set
233 Постоянная часть сплиттера (не изменяет размеры при изменении размеров самого
234 объетка
235 */
236 property uint vSplitter.FixedPart()
237 {
238 return this.pFixedPart
239 }
240
241 property vSplitter.FixedPart( uint val)
242 {
243 if this.pFixedPart != val
244 {
245 this.pFixedPart = val
246 .iUpdateSize()
247 }
248 }
249
250 /* Свойство uint vSplitter.LeftMinSize - Get Set
251 Минимальная ширина левой/верхней части
252 */
253 property uint vSplitter.LeftMinSize()
254 {
255 return this.pLeftMinSize
256 }
257
258 property vSplitter.LeftMinSize( uint val)
259 {
260 if this.pLeftMinSize != val
261 {
262 this.pLeftMinSize = val
263 }
264 }
265
266 /* Свойство uint vSplitter.RightMinSize - Get Set
267 Минимальная ширина правой/нижней части
268 */
269 property uint vSplitter.RightMinSize()
270 {
271 return this.pRightMinSize
272 }
273
274 property vSplitter.RightMinSize( uint val)
275 {
276 if this.pRightMinSize != val
277 {
278 this.pRightMinSize = val
279 }
280 }
281
282 /*------------------------------------------------------------------------------
283 Virtual Methods
284 */
285 /*Виртуальный метод vSplitter vSplitter.mCreateWin
286 Создание окна
287 */
288 method vSplitter vSplitter.mCreateWin <alias=vSplitter_mCreateWin>()
289 {
290 uint distance = .pDistance
291 uint style = $SS_NOTIFY | $WS_CHILD | $WS_CLIPCHILDREN |
292 $WS_CLIPSIBLINGS | $WS_OVERLAPPED
293 ifdef $DESIGNING {
294 if .p_designing : style |= $WS_BORDER
295 }
296 .CreateWin( "STATIC".ustr(), 0, style )
297 this->vCtrl.mCreateWin()
298 if !.pAutoSize : .Distance = distance
299
300 return this
301 }
302
303 /*Виртуальный метод vSplitter.mInsert
304 Вставка дочерних элементов
305 */
306 method vSplitter.mInsert <alias=vSplitter_mInsert>( vComp newcomp )
307 {
308 if newcomp.TypeIs( vCtrl ) && *.Comps < 2
309 {
310 this->vCtrl.mInsert( newcomp )
311 .iUpdateSize()
312 }
313 }
314
315 /*Виртуальный метод vSplitter.mPosChanging
316 Изменение размеров
317 */
318 method vSplitter.mPosChanging <alias=vSplitter_mPosChanging>( eventpos evp )
319 {
320 uint old = ?( .pOrientation == $soVertical, .Width, .Height )
321 this->vCtrl.mPosChanging( evp )
322 switch .pFixedPart
323 {
324 case $sfpRight
325 {
326 /*.pDistance += ?( .pOrientation == $soVertical,
327 .Width - old, .Height-old )*/
328 if *.Comps > 1 && .Comps[1]->vCtrl.Visible
329 {
330 .pDistance = ?( .pOrientation == $soVertical,
331 .Width - .Comps[1]->vCtrl.Width,
332 .Height - .Comps[1]->vCtrl.Height ) - .pSplitterWidth
333 }
334 }
335 case $sfpNone
336 {
337 .pDistance = uint( .pProportion * double( ?( .pOrientation == $soVertical, evp.loc.width, evp.loc.height ) ) )
338 }
339 }
340 .iUpdateSize()
341 }
342
343 /*Виртуальный метод vSplitter.mMouse
344 Сообщения от мышки
345 */
346 method uint vSplitter.mMouse <alias=vSplitter_mMouse> ( evparMouse ev )
347 {
348 if !.pAutoSize
349 {
350 switch ev.evmtype
351 {
352 case $evmMove
353 {
354 if .fDrag
355 {
356 .Distance = ?( .pOrientation == $soVertical, ev.x, ev.y )
357 }
358 }
359 case $evmLDown
360 {
361 if !.fDrag
362 {
363 .fDrag = 1
364 SetCapture( .hwnd )
365 }
366 }
367 case $evmLUp
368 {
369 if .fDrag : ReleaseCapture()
370 }
371 }
372
373 if .pOrientation == $soVertical
374 {
375 if ev.x > .pRealDistance && ev.x <= .pRealDistance + .pSplitterWidth
376 {
377 SetCursor( App.cursorSizeWE )
378 }
379 }
380 else
381 {
382 if ev.y > .pRealDistance && ev.y <= .pRealDistance + .pSplitterWidth
383 {
384
385 SetCursor( App.cursorSizeNS )
386 }
387 }
388 }
389 return this->vCtrl.mMouse( ev )
390 }
391
392 /*Виртуальный метод vSplitter.mSetName
393 Установка заголовка в режиме проектирования
394 */
395 ifdef $DESIGNING {
396 method uint vSplitter.mSetName <alias=vSplitter_mSetName>( str newname )
397 {
398 SetWindowText( this.hwnd, newname.ustr().ptr() )
399 return 1
400 }
401 }
402
403 /*Виртуальный метод vSplitter.mChildPosChanged
404 Изменение размеров дочерних элементов
405 */
406 method vSplitter.mChildPosChanged <alias=vSplitter_mChildPosChanged>( vComp curcomp )
407 {
408 if !.fUpdatingSize
409 {
410 if ( .pAutoSize || .p_designing )
411 {
412 switch .pFixedPart
413 {
414 case $sfpLeft
415 {
416 if *.Comps > 0 && &curcomp==.Comps[0]
417 {
418 .pDistance = ?( .pOrientation == $soVertical,
419 .Comps[0]->vCtrl.Width, .Comps[0]->vCtrl.Height )
420 }
421 .iUpdateSize()
422 }
423 case $sfpRight
424 {
425 if *.Comps > 1 && &curcomp==.Comps[1]
426 {
427 if .Comps[1]->vCtrl.Visible
428 {
429 ifdef $DESIGNING {
430 .pDistance = ?( .pOrientation == $soVertical,
431 .Comps[1]->vCtrl.Left,
432 .Comps[1]->vCtrl.Top ) - .pSplitterWidth
433 }
434 else
435 {
436 .pDistance = ?( .pOrientation == $soVertical,
437 .Width - .Comps[1]->vCtrl.Width,
438 .Height - .Comps[1]->vCtrl.Height ) - .pSplitterWidth
439 }
440 }
441 }
442 .iUpdateSize()
443 }
444 }
445 }
446 else
447 {
448 .iUpdateSize()
449 }
450 }
451 //this->vCtrl.mChildPosChanged( evp )
452 }
453
454 /*------------------------------------------------------------------------------
455 Windows messages
456 */
457 /*Метод обработки сообщения uint vSplitter.wmcapturechange
458 Сообщения о захвате и освобождении мышки
459 */
460 method uint vSplitter.wmcapturechange
461 <alias=vSplitter_wmcapturechanged>( winmsg wmsg )
462 {
463 if wmsg.lpar != .hwnd && .fDrag
464 {
465 .fDrag = 0
466 }
467 return 0
468 }
469
470 /*------------------------------------------------------------------------------
471 Registration
472 */
473 /*Системный метод vSplitter vSplitter.init
474 Инициализация объекта
475 */
476 method vSplitter vSplitter.init( )
477 {
478 this.pTypeId = vSplitter
479 this.pCanContain = 1
480 this.loc.width = 200
481 this.loc.height = 100
482 this.pDistance = 50
483 this.pSplitterWidth = 5
484 this.flgXPStyle = 1
485 return this
486 }
487
488 //Функция регистрации
489 func init_vSplitter <entry>()
490 {
491 regcomp( vSplitter, "vSplitter", vCtrl, $vCtrl_last,
492 %{ %{$mCreateWin, vSplitter_mCreateWin},
493 %{$mInsert, vSplitter_mInsert},
494 %{$mPosChanging,vSplitter_mPosChanging},
495 %{$mMouse, vSplitter_mMouse},
496 %{$mChildPosChanged, vSplitter_mChildPosChanged}
497 ifdef $DESIGNING {,
498 %{$mSetName, vSplitter_mSetName}
499 }
500 },
501 //0->collection )
502 %{ %{$WM_CAPTURECHANGED, vSplitter_wmcapturechanged }
503 })
504
505 ifdef $DESIGNING {
506 cm.AddComp( vSplitter, 1, "Windows", "splitter" )
507
508 cm.AddProps( vSplitter, %{
509 "Distance", uint, $PROP_LOADAFTERCHILD,
510 "SplitterWidth", uint, 0,
511 "Orientation", uint, 0,
512 "FixedPart", uint, 0,
513 "LeftMinSize", uint, 0,
514 "RightMinSize", uint, 0,
515 "AutoSize", uint, 0
516 })
517
518 cm.AddPropVals( vSplitter, "Orientation", %{
519 "soVertical", $soVertical,
520 "soHorizontal", $soHorizontal
521 })
522
523 cm.AddPropVals( vSplitter, "FixedPart", %{
524 "sfpLeft", $sfpLeft,
525 "sfpRight", $sfpRight,
526 "sfpNone", $sfpNone
527 })
528
529 cm.AddEvents( vSplitter, %{
530 "OnMoved" , "evparEvent"
531 })
532 }
533
534 }
535