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