5 char *WMSplitViewDidResizeSubviewsNotification
6 = "WMSplitViewDidResizeSubviewsNotification";
7 char *WMSplitViewWillResizeSubviewsNotification
8 = "WMSplitViewWillResizeSubviewsNotification";
11 typedef struct W_SplitViewSubview
{
19 typedef struct W_SplitView
{
25 WMSplitViewConstrainProc
*constrainProc
;
28 unsigned int vertical
:1;
29 unsigned int adjustOnPaint
:1;
30 unsigned int subviewsWereManuallyMoved
:1;
33 /* WMSplitViewResizeSubviewsProc *resizeSubviewsProc; */
37 #define DIVIDER_THICKNESS 8
38 #define MIN_SUBVIEW_SIZE 4
39 #define MAX_SUBVIEW_SIZE -1
41 /* TODO: rewrite --Dan */
42 #define _GetSubviewsCount() WMGetArrayItemCount(sPtr->subviews)
44 #define _AddPSubviewStruct(P) \
45 (WMAddToArray(sPtr->subviews,((void*)P)))
47 #define _GetPSubviewStructAt(i) \
48 ((W_SplitViewSubview*)WMGetFromArray(sPtr->subviews,(i)))
50 #define _GetSubviewAt(i) \
51 (((W_SplitViewSubview*)WMGetFromArray(sPtr->subviews,(i)))->view)
53 #define _GetMinSizeAt(i) \
54 (((W_SplitViewSubview*)WMGetFromArray(sPtr->subviews,(i)))->minSize)
56 #define _GetMaxSizeAt(i) \
57 (((W_SplitViewSubview*)WMGetFromArray(sPtr->subviews,(i)))->maxSize)
59 #define _GetSizeAt(i) \
60 (((W_SplitViewSubview*)WMGetFromArray(sPtr->subviews,(i)))->size)
62 #define _GetPosAt(i) \
63 (((W_SplitViewSubview*)WMGetFromArray(sPtr->subviews,(i)))->pos)
65 #define _GetSplitViewSize() \
66 ((sPtr->flags.vertical) ? sPtr->view->size.width : sPtr->view->size.height)
68 static void destroySplitView(WMSplitView
* sPtr
);
69 static void paintSplitView(WMSplitView
* sPtr
);
71 static void handleEvents(XEvent
* event
, void *data
);
72 static void handleActionEvents(XEvent
* event
, void *data
);
74 static void getConstraints(WMSplitView
* sPtr
, int index
, int *minSize
, int *maxSize
)
76 *minSize
= MIN_SUBVIEW_SIZE
;
77 *maxSize
= MAX_SUBVIEW_SIZE
;
79 if (sPtr
->constrainProc
)
80 (*sPtr
->constrainProc
) (sPtr
, index
, minSize
, maxSize
);
82 if (*minSize
< MIN_SUBVIEW_SIZE
)
83 *minSize
= MIN_SUBVIEW_SIZE
;
85 if (*maxSize
< MIN_SUBVIEW_SIZE
)
86 *maxSize
= MAX_SUBVIEW_SIZE
;
87 else if (*maxSize
< *minSize
)
91 static void updateConstraints(WMSplitView
* sPtr
)
93 W_SplitViewSubview
*p
;
96 count
= _GetSubviewsCount();
97 for (i
= 0; i
< count
; i
++) {
98 p
= _GetPSubviewStructAt(i
);
99 getConstraints(sPtr
, i
, &(p
->minSize
), &(p
->maxSize
));
103 static void resizeView(WMSplitView
* sPtr
, WMView
* view
, int size
)
107 if (sPtr
->flags
.vertical
) {
109 height
= sPtr
->view
->size
.height
;
111 width
= sPtr
->view
->size
.width
;
116 WMResizeWidget(view
->self
, width
, height
);
118 W_ResizeView(view
, width
, height
);
121 static void reparentView(WMSplitView
* sPtr
, WMView
* view
, int pos
)
125 if (sPtr
->flags
.vertical
) {
133 W_ReparentView(view
, sPtr
->view
, x
, y
);
136 static void moveView(WMSplitView
* sPtr
, WMView
* view
, int pos
)
140 if (sPtr
->flags
.vertical
) {
149 WMMoveWidget(view
->self
, x
, y
);
151 W_MoveView(view
, x
, y
);
154 static int checkSizes(WMSplitView
* sPtr
)
156 int i
, count
, offset
;
157 W_SplitViewSubview
*p
;
159 count
= _GetSubviewsCount();
161 for (i
= 0; i
< count
; i
++) {
162 p
= _GetPSubviewStructAt(i
);
163 if (p
->size
< p
->minSize
) {
164 offset
+= p
->minSize
- p
->size
;
165 p
->size
= p
->minSize
;
166 } else if (p
->maxSize
!= MAX_SUBVIEW_SIZE
&& p
->size
> p
->maxSize
) {
167 offset
+= p
->maxSize
- p
->size
;
168 p
->size
= p
->maxSize
;
175 static void checkPositions(WMSplitView
* sPtr
)
178 W_SplitViewSubview
*p
;
180 count
= _GetSubviewsCount();
182 for (i
= 0; i
< count
; i
++) {
183 p
= _GetPSubviewStructAt(i
);
185 pos
+= p
->size
+ DIVIDER_THICKNESS
;
189 static void updateSubviewsGeom(WMSplitView
* sPtr
)
192 W_SplitViewSubview
*p
;
194 count
= _GetSubviewsCount();
195 for (i
= 0; i
< count
; i
++) {
196 p
= _GetPSubviewStructAt(i
);
197 resizeView(sPtr
, p
->view
, p
->size
);
198 moveView(sPtr
, p
->view
, p
->pos
);
202 static int getTotalSize(WMSplitView
* sPtr
)
204 int i
, count
, totSize
;
206 count
= _GetSubviewsCount();
211 for (i
= 0; i
< count
; i
++)
212 totSize
+= _GetSizeAt(i
) + DIVIDER_THICKNESS
;
214 return (totSize
- DIVIDER_THICKNESS
);
217 static Bool
distributeOffsetEqually(WMSplitView
* sPtr
, int offset
)
219 W_SplitViewSubview
*p
;
220 int i
, count
, sizeChanged
, forced
;
222 if ((count
= _GetSubviewsCount()) < 1)
226 while (offset
!= 0) {
228 for (i
= 0; i
< count
&& offset
!= 0; i
++) {
229 p
= _GetPSubviewStructAt(i
);
231 if (p
->size
> p
->minSize
) {
236 } else if (p
->maxSize
== MAX_SUBVIEW_SIZE
|| p
->size
< p
->maxSize
) {
242 if (offset
!= 0 && !sizeChanged
) {
243 p
= _GetPSubviewStructAt(count
- 1);
246 p
->maxSize
= MAX_SUBVIEW_SIZE
;
256 static Bool
distributeOffsetFormEnd(WMSplitView
* sPtr
, int offset
)
258 W_SplitViewSubview
*p
;
259 int i
, count
, sizeTmp
;
261 if ((count
= _GetSubviewsCount()) < 1)
264 for (i
= count
- 1; i
>= 0 && offset
!= 0; i
--) {
265 p
= _GetPSubviewStructAt(i
);
268 if (p
->maxSize
== MAX_SUBVIEW_SIZE
|| p
->size
+ offset
< p
->maxSize
)
271 p
->size
= p
->maxSize
;
273 if (p
->size
+ offset
>= p
->minSize
)
276 p
->size
= p
->minSize
;
278 offset
-= p
->size
- sizeTmp
;
281 return (offset
== 0);
284 static void adjustSplitViewSubviews(WMSplitView
* sPtr
)
286 W_SplitViewSubview
*p
;
287 int i
, count
, adjSize
, adjPad
;
289 CHECK_CLASS(sPtr
, WC_SplitView
);
292 printf("---- (adjustSplitViewSubviews - 1) ----\n");
296 if ((count
= _GetSubviewsCount()) < 1)
299 adjSize
= (_GetSplitViewSize() - ((count
- 1) * DIVIDER_THICKNESS
)) / count
;
300 adjPad
= (_GetSplitViewSize() - ((count
- 1) * DIVIDER_THICKNESS
)) % count
;
301 for (i
= 0; i
< count
; i
++) {
302 p
= _GetPSubviewStructAt(i
);
306 distributeOffsetEqually(sPtr
, adjPad
- checkSizes(sPtr
));
308 checkPositions(sPtr
);
309 updateSubviewsGeom(sPtr
);
311 sPtr
->flags
.subviewsWereManuallyMoved
= 0;
314 printf("---- (adjustSplitViewSubviews - 2) ----\n");
320 static void handleSubviewResized(void *self
, WMNotification
* notif
)
322 WMSplitView
*sPtr
= (WMSplitView
*) self
;
324 CHECK_CLASS(sPtr
, WC_SplitView
);
326 if (WMGetNotificationName(notif
) == WMViewSizeDidChangeNotification
) {
327 W_SplitViewSubview
*p
;
329 WMView
*view
= WMGetNotificationObject(notif
);
331 count
= _GetSubviewsCount();
333 for (i
= 0; i
< count
; i
++) {
334 p
= _GetPSubviewStructAt(i
);
335 if (p
->view
== view
) {
343 resizeView(sPtr
, p
->view
, p
->size
);
344 moveView(sPtr
, p
->view
, p
->pos
);
350 static void handleViewResized(void *self
, WMNotification
* notification
)
352 WMSplitView
*sPtr
= (WMSplitView
*) self
;
355 printf("---- (handleViewResized - 1) ----\n");
359 updateConstraints(sPtr
);
362 if (sPtr
->constrainProc
|| sPtr
->flags
.subviewsWereManuallyMoved
) {
363 distributeOffsetFormEnd(sPtr
, _GetSplitViewSize() - getTotalSize(sPtr
));
364 checkPositions(sPtr
);
365 updateSubviewsGeom(sPtr
);
367 adjustSplitViewSubviews(sPtr
);
369 assert(checkSizes(sPtr
) == 0);
372 printf("---- (handleViewResized - 2) ----\n");
377 static void paintSplitView(WMSplitView
* sPtr
)
379 W_SplitViewSubview
*p
;
380 W_Screen
*scr
= sPtr
->view
->screen
;
382 WMPixmap
*dimple
= scr
->scrollerDimple
;
385 printf("---- (paintSplitView - 1) ----\n");
389 if (!sPtr
->view
->flags
.mapped
|| !sPtr
->view
->flags
.realized
)
392 XClearWindow(scr
->display
, sPtr
->view
->window
);
394 count
= _GetSubviewsCount();
398 if (sPtr
->flags
.adjustOnPaint
) {
399 handleViewResized(sPtr
, NULL
);
400 sPtr
->flags
.adjustOnPaint
= 0;
403 XSetClipMask(scr
->display
, scr
->clipGC
, dimple
->mask
);
405 if (sPtr
->flags
.vertical
) {
406 x
= ((DIVIDER_THICKNESS
- dimple
->width
) / 2);
407 y
= (sPtr
->view
->size
.height
- dimple
->height
) / 2;
409 x
= (sPtr
->view
->size
.width
- dimple
->width
) / 2;
410 y
= ((DIVIDER_THICKNESS
- dimple
->height
) / 2);
413 for (i
= 0; i
< count
- 1; i
++) {
414 p
= _GetPSubviewStructAt(i
);
416 if (sPtr
->flags
.vertical
)
421 XSetClipOrigin(scr
->display
, scr
->clipGC
, x
, y
);
422 XCopyArea(scr
->display
, dimple
->pixmap
, sPtr
->view
->window
,
423 scr
->clipGC
, 0, 0, dimple
->width
, dimple
->height
, x
, y
);
425 if (sPtr
->flags
.vertical
)
426 x
+= DIVIDER_THICKNESS
;
428 y
+= DIVIDER_THICKNESS
;
432 printf("---- (paintSplitView - 2) ----\n");
437 static void drawDragingRectangle(WMSplitView
* sPtr
, int pos
)
441 if (sPtr
->flags
.vertical
) {
444 w
= DIVIDER_THICKNESS
;
445 h
= sPtr
->view
->size
.height
;
449 w
= sPtr
->view
->size
.width
;
450 h
= DIVIDER_THICKNESS
;
453 XFillRectangle(sPtr
->view
->screen
->display
, sPtr
->view
->window
, sPtr
->view
->screen
->ixorGC
, x
, y
, w
, h
);
456 static void getMinMaxDividerCoord(WMSplitView
* sPtr
, int divider
, int *minC
, int *maxC
)
458 int relMinC
, relMaxC
;
459 int totSize
= _GetSizeAt(divider
) + _GetSizeAt(divider
+ 1);
461 relMinC
= _GetMinSizeAt(divider
);
462 if (_GetMaxSizeAt(divider
+ 1) != MAX_SUBVIEW_SIZE
&& relMinC
< totSize
- _GetMaxSizeAt(divider
+ 1))
463 relMinC
= totSize
- _GetMaxSizeAt(divider
+ 1);
465 relMaxC
= totSize
- _GetMinSizeAt(divider
+ 1);
466 if (_GetMaxSizeAt(divider
) != MAX_SUBVIEW_SIZE
&& relMaxC
> _GetMaxSizeAt(divider
))
467 relMaxC
= _GetMaxSizeAt(divider
);
469 *minC
= _GetPosAt(divider
) + relMinC
;
470 *maxC
= _GetPosAt(divider
) + relMaxC
;
473 static void dragDivider(WMSplitView
* sPtr
, int clickX
, int clickY
)
475 int divider
, pos
, ofs
, done
, dragging
;
479 int minCoord
, maxCoord
, coord
;
481 if (sPtr
->constrainProc
) {
482 updateConstraints(sPtr
);
484 distributeOffsetFormEnd(sPtr
, _GetSplitViewSize() - getTotalSize(sPtr
));
485 checkPositions(sPtr
);
486 updateSubviewsGeom(sPtr
);
489 scr
= sPtr
->view
->screen
;
490 divider
= ofs
= pos
= done
= 0;
491 coord
= (sPtr
->flags
.vertical
) ? clickX
: clickY
;
492 count
= _GetSubviewsCount();
496 for (i
= 0; i
< count
- 1; i
++) {
497 pos
+= _GetSizeAt(i
) + DIVIDER_THICKNESS
;
499 ofs
= coord
- pos
+ DIVIDER_THICKNESS
;
509 getMinMaxDividerCoord(sPtr
, divider
, &minCoord
, &maxCoord
);
514 WMMaskEvent(scr
->display
, ButtonMotionMask
| ButtonReleaseMask
| ExposureMask
, &ev
);
516 coord
= (sPtr
->flags
.vertical
) ? ev
.xmotion
.x
: ev
.xmotion
.y
;
522 drawDragingRectangle(sPtr
, pos
);
527 drawDragingRectangle(sPtr
, pos
);
528 if (coord
- ofs
< minCoord
)
530 else if (coord
- ofs
> maxCoord
)
534 drawDragingRectangle(sPtr
, pos
);
545 W_SplitViewSubview
*p1
, *p2
;
548 p1
= _GetPSubviewStructAt(divider
);
549 p2
= _GetPSubviewStructAt(divider
+ 1);
551 totSize
= p1
->size
+ DIVIDER_THICKNESS
+ p2
->size
;
553 p1
->size
= pos
- p1
->pos
;
554 p2
->size
= totSize
- p1
->size
- DIVIDER_THICKNESS
;
555 p2
->pos
= p1
->pos
+ p1
->size
+ DIVIDER_THICKNESS
;
557 resizeView(sPtr
, p1
->view
, p1
->size
);
558 moveView(sPtr
, p2
->view
, p2
->pos
);
559 resizeView(sPtr
, p2
->view
, p2
->size
);
560 sPtr
->flags
.subviewsWereManuallyMoved
= 1;
564 static void handleEvents(XEvent
* event
, void *data
)
566 WMSplitView
*sPtr
= (WMSplitView
*) data
;
568 CHECK_CLASS(data
, WC_SplitView
);
570 switch (event
->type
) {
572 if (event
->xexpose
.count
!= 0)
574 paintSplitView(sPtr
);
578 destroySplitView(sPtr
);
583 static void handleActionEvents(XEvent
* event
, void *data
)
586 CHECK_CLASS(data
, WC_SplitView
);
588 switch (event
->type
) {
590 if (event
->xbutton
.button
== Button1
)
591 dragDivider(data
, event
->xbutton
.x
, event
->xbutton
.y
);
596 static void destroySplitView(WMSplitView
* sPtr
)
598 WMFreeArray(sPtr
->subviews
);
600 WMRemoveNotificationObserver(sPtr
);
605 WMSplitView
*WMCreateSplitView(WMWidget
* parent
)
609 sPtr
= wmalloc(sizeof(WMSplitView
));
610 sPtr
->widgetClass
= WC_SplitView
;
612 sPtr
->view
= W_CreateView(W_VIEW(parent
));
617 sPtr
->view
->self
= sPtr
;
619 WMSetViewNotifySizeChanges(sPtr
->view
, True
);
621 WMCreateEventHandler(sPtr
->view
, ExposureMask
| StructureNotifyMask
622 | ClientMessageMask
, handleEvents
, sPtr
);
624 WMCreateEventHandler(sPtr
->view
, ButtonPressMask
| ButtonReleaseMask
625 | EnterWindowMask
| LeaveWindowMask
, handleActionEvents
, sPtr
);
627 WMAddNotificationObserver(handleViewResized
, sPtr
, WMViewSizeDidChangeNotification
, sPtr
->view
);
629 sPtr
->subviews
= WMCreateArrayWithDestructor(8, wfree
);
634 void WMAdjustSplitViewSubviews(WMSplitView
* sPtr
)
636 CHECK_CLASS(sPtr
, WC_SplitView
);
640 adjustSplitViewSubviews(sPtr
);
642 assert(checkSizes(sPtr
) == 0);
645 void WMAddSplitViewSubview(WMSplitView
* sPtr
, WMView
* subview
)
647 int wasMapped
, count
;
648 W_SplitViewSubview
*p
;
650 CHECK_CLASS(sPtr
, WC_SplitView
);
652 p
= (W_SplitViewSubview
*) wmalloc(sizeof(W_SplitViewSubview
));
656 wasMapped
= subview
->flags
.mapped
;
658 W_UnmapView(subview
);
660 count
= _GetSubviewsCount();
662 getConstraints(sPtr
, count
, &(p
->minSize
), &(p
->maxSize
));
663 if (sPtr
->flags
.vertical
)
664 p
->size
= subview
->size
.width
;
666 p
->size
= subview
->size
.height
;
668 WMAddToArray(sPtr
->subviews
, p
);
669 reparentView(sPtr
, subview
, 0);
672 We should have something like that...
674 WMSetViewNotifySizeChanges(subview, True);
675 WMAddNotificationObserver(handleSubviewResized, sPtr,
676 WMViewSizeDidChangeNotification,
678 WMSetViewNotifyMoveChanges(subview, True);
679 WMAddNotificationObserver(handleSubviewResized, sPtr,
680 WMViewMoveDidChangeNotification,
686 sPtr
->flags
.adjustOnPaint
= 1;
687 paintSplitView(sPtr
);
689 handleViewResized(sPtr
, NULL
);
693 WMView
*WMGetSplitViewSubviewAt(WMSplitView
* sPtr
, int index
)
695 CHECK_CLASS(sPtr
, WC_SplitView
);
697 if (index
>= 0 && index
< _GetSubviewsCount())
698 return (_GetSubviewAt(index
));
703 void WMRemoveSplitViewSubview(WMSplitView
* sPtr
, WMView
* view
)
705 W_SplitViewSubview
*p
;
708 CHECK_CLASS(sPtr
, WC_SplitView
);
710 /* TODO: rewrite this. This code with macros is getting more complex than it worths */
711 count
= _GetSubviewsCount();
712 for (i
= 0; i
< count
; i
++) {
713 p
= _GetPSubviewStructAt(i
);
714 if (p
->view
== view
) {
715 WMDeleteFromArray(sPtr
->subviews
, i
);
716 sPtr
->flags
.adjustOnPaint
= 1;
717 paintSplitView(sPtr
);
723 void WMRemoveSplitViewSubviewAt(WMSplitView
* sPtr
, int index
)
725 CHECK_CLASS(sPtr
, WC_SplitView
);
727 /* TODO: same about rewrite */
728 if (index
>= 0 && index
< _GetSubviewsCount()) {
729 WMDeleteFromArray(sPtr
->subviews
, index
);
730 sPtr
->flags
.adjustOnPaint
= 1;
731 paintSplitView(sPtr
);
735 void WMSetSplitViewConstrainProc(WMSplitView
* sPtr
, WMSplitViewConstrainProc
* proc
)
737 CHECK_CLASS(sPtr
, WC_SplitView
);
739 sPtr
->constrainProc
= proc
;
742 int WMGetSplitViewSubviewsCount(WMSplitView
* sPtr
)
744 CHECK_CLASS(sPtr
, WC_SplitView
);
746 return (_GetSubviewsCount());
749 Bool
WMGetSplitViewVertical(WMSplitView
* sPtr
)
751 CHECK_CLASS(sPtr
, WC_SplitView
);
753 return (sPtr
->flags
.vertical
== 1);
756 void WMSetSplitViewVertical(WMSplitView
* sPtr
, Bool flag
)
760 CHECK_CLASS(sPtr
, WC_SplitView
);
762 vertical
= ((flag
== 0) ? 0 : 1);
763 if (sPtr
->flags
.vertical
== vertical
)
766 sPtr
->flags
.vertical
= vertical
;
768 /* if (sPtr->view->flags.mapped && sPtr->view->flags.realized) */
769 handleViewResized(sPtr
, NULL
);
771 sPtr->flags.adjustOnPaint = 1;
775 int WMGetSplitViewDividerThickness(WMSplitView
* sPtr
)
777 CHECK_CLASS(sPtr
, WC_SplitView
);
779 return (DIVIDER_THICKNESS
);
783 void WMSetSplitViewResizeSubviewsProc(WMSplitView
* sPtr
, WMSplitViewResizeSubviewsProc
* proc
)
785 CHECK_CLASS(sPtr
, WC_SplitView
);
787 sPtr
->resizeSubviewsProc
= proc
;