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 _GetPSubviewStructAt(i) \
45 ((W_SplitViewSubview*)WMGetFromArray(sPtr->subviews,(i)))
47 #define _GetSubviewAt(i) \
48 (((W_SplitViewSubview*)WMGetFromArray(sPtr->subviews,(i)))->view)
50 #define _GetMinSizeAt(i) \
51 (((W_SplitViewSubview*)WMGetFromArray(sPtr->subviews,(i)))->minSize)
53 #define _GetMaxSizeAt(i) \
54 (((W_SplitViewSubview*)WMGetFromArray(sPtr->subviews,(i)))->maxSize)
56 #define _GetSizeAt(i) \
57 (((W_SplitViewSubview*)WMGetFromArray(sPtr->subviews,(i)))->size)
59 #define _GetPosAt(i) \
60 (((W_SplitViewSubview*)WMGetFromArray(sPtr->subviews,(i)))->pos)
62 #define _GetSplitViewSize() \
63 ((sPtr->flags.vertical) ? sPtr->view->size.width : sPtr->view->size.height)
65 static void destroySplitView(WMSplitView
* sPtr
);
66 static void paintSplitView(WMSplitView
* sPtr
);
68 static void handleEvents(XEvent
* event
, void *data
);
69 static void handleActionEvents(XEvent
* event
, void *data
);
71 static void getConstraints(WMSplitView
* sPtr
, int index
, int *minSize
, int *maxSize
)
73 *minSize
= MIN_SUBVIEW_SIZE
;
74 *maxSize
= MAX_SUBVIEW_SIZE
;
76 if (sPtr
->constrainProc
)
77 (*sPtr
->constrainProc
) (sPtr
, index
, minSize
, maxSize
);
79 if (*minSize
< MIN_SUBVIEW_SIZE
)
80 *minSize
= MIN_SUBVIEW_SIZE
;
82 if (*maxSize
< MIN_SUBVIEW_SIZE
)
83 *maxSize
= MAX_SUBVIEW_SIZE
;
84 else if (*maxSize
< *minSize
)
88 static void updateConstraints(WMSplitView
* sPtr
)
90 W_SplitViewSubview
*p
;
93 count
= _GetSubviewsCount();
94 for (i
= 0; i
< count
; i
++) {
95 p
= _GetPSubviewStructAt(i
);
96 getConstraints(sPtr
, i
, &(p
->minSize
), &(p
->maxSize
));
100 static void resizeView(WMSplitView
* sPtr
, WMView
* view
, int size
)
104 if (sPtr
->flags
.vertical
) {
106 height
= sPtr
->view
->size
.height
;
108 width
= sPtr
->view
->size
.width
;
113 WMResizeWidget(view
->self
, width
, height
);
115 W_ResizeView(view
, width
, height
);
118 static void reparentView(WMSplitView
* sPtr
, WMView
* view
, int pos
)
122 if (sPtr
->flags
.vertical
) {
130 W_ReparentView(view
, sPtr
->view
, x
, y
);
133 static void moveView(WMSplitView
* sPtr
, WMView
* view
, int pos
)
137 if (sPtr
->flags
.vertical
) {
146 WMMoveWidget(view
->self
, x
, y
);
148 W_MoveView(view
, x
, y
);
151 static int checkSizes(WMSplitView
* sPtr
)
153 int i
, count
, offset
;
154 W_SplitViewSubview
*p
;
156 count
= _GetSubviewsCount();
158 for (i
= 0; i
< count
; i
++) {
159 p
= _GetPSubviewStructAt(i
);
160 if (p
->size
< p
->minSize
) {
161 offset
+= p
->minSize
- p
->size
;
162 p
->size
= p
->minSize
;
163 } else if (p
->maxSize
!= MAX_SUBVIEW_SIZE
&& p
->size
> p
->maxSize
) {
164 offset
+= p
->maxSize
- p
->size
;
165 p
->size
= p
->maxSize
;
172 static void checkPositions(WMSplitView
* sPtr
)
175 W_SplitViewSubview
*p
;
177 count
= _GetSubviewsCount();
179 for (i
= 0; i
< count
; i
++) {
180 p
= _GetPSubviewStructAt(i
);
182 pos
+= p
->size
+ DIVIDER_THICKNESS
;
186 static void updateSubviewsGeom(WMSplitView
* sPtr
)
189 W_SplitViewSubview
*p
;
191 count
= _GetSubviewsCount();
192 for (i
= 0; i
< count
; i
++) {
193 p
= _GetPSubviewStructAt(i
);
194 resizeView(sPtr
, p
->view
, p
->size
);
195 moveView(sPtr
, p
->view
, p
->pos
);
199 static int getTotalSize(WMSplitView
* sPtr
)
201 int i
, count
, totSize
;
203 count
= _GetSubviewsCount();
208 for (i
= 0; i
< count
; i
++)
209 totSize
+= _GetSizeAt(i
) + DIVIDER_THICKNESS
;
211 return (totSize
- DIVIDER_THICKNESS
);
214 static Bool
distributeOffsetEqually(WMSplitView
* sPtr
, int offset
)
216 W_SplitViewSubview
*p
;
217 int i
, count
, sizeChanged
, forced
;
219 if ((count
= _GetSubviewsCount()) < 1)
223 while (offset
!= 0) {
225 for (i
= 0; i
< count
&& offset
!= 0; i
++) {
226 p
= _GetPSubviewStructAt(i
);
228 if (p
->size
> p
->minSize
) {
233 } else if (p
->maxSize
== MAX_SUBVIEW_SIZE
|| p
->size
< p
->maxSize
) {
239 if (offset
!= 0 && !sizeChanged
) {
240 p
= _GetPSubviewStructAt(count
- 1);
243 p
->maxSize
= MAX_SUBVIEW_SIZE
;
253 static Bool
distributeOffsetFormEnd(WMSplitView
* sPtr
, int offset
)
255 W_SplitViewSubview
*p
;
256 int i
, count
, sizeTmp
;
258 if ((count
= _GetSubviewsCount()) < 1)
261 for (i
= count
- 1; i
>= 0 && offset
!= 0; i
--) {
262 p
= _GetPSubviewStructAt(i
);
265 if (p
->maxSize
== MAX_SUBVIEW_SIZE
|| p
->size
+ offset
< p
->maxSize
)
268 p
->size
= p
->maxSize
;
270 if (p
->size
+ offset
>= p
->minSize
)
273 p
->size
= p
->minSize
;
275 offset
-= p
->size
- sizeTmp
;
278 return (offset
== 0);
281 static void adjustSplitViewSubviews(WMSplitView
* sPtr
)
283 W_SplitViewSubview
*p
;
284 int i
, count
, adjSize
, adjPad
;
286 CHECK_CLASS(sPtr
, WC_SplitView
);
289 printf("---- (adjustSplitViewSubviews - 1) ----\n");
293 if ((count
= _GetSubviewsCount()) < 1)
296 adjSize
= (_GetSplitViewSize() - ((count
- 1) * DIVIDER_THICKNESS
)) / count
;
297 adjPad
= (_GetSplitViewSize() - ((count
- 1) * DIVIDER_THICKNESS
)) % count
;
298 for (i
= 0; i
< count
; i
++) {
299 p
= _GetPSubviewStructAt(i
);
303 distributeOffsetEqually(sPtr
, adjPad
- checkSizes(sPtr
));
305 checkPositions(sPtr
);
306 updateSubviewsGeom(sPtr
);
308 sPtr
->flags
.subviewsWereManuallyMoved
= 0;
311 printf("---- (adjustSplitViewSubviews - 2) ----\n");
317 static void handleSubviewResized(void *self
, WMNotification
* notif
)
319 WMSplitView
*sPtr
= (WMSplitView
*) self
;
321 CHECK_CLASS(sPtr
, WC_SplitView
);
323 if (WMGetNotificationName(notif
) == WMViewSizeDidChangeNotification
) {
324 W_SplitViewSubview
*p
;
326 WMView
*view
= WMGetNotificationObject(notif
);
328 count
= _GetSubviewsCount();
330 for (i
= 0; i
< count
; i
++) {
331 p
= _GetPSubviewStructAt(i
);
332 if (p
->view
== view
) {
340 resizeView(sPtr
, p
->view
, p
->size
);
341 moveView(sPtr
, p
->view
, p
->pos
);
347 static void handleViewResized(void *self
, WMNotification
* notification
)
349 WMSplitView
*sPtr
= (WMSplitView
*) self
;
351 /* Parameter not used, but tell the compiler that it is ok */
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
);
781 return (DIVIDER_THICKNESS
);
785 void WMSetSplitViewResizeSubviewsProc(WMSplitView
* sPtr
, WMSplitViewResizeSubviewsProc
* proc
)
787 CHECK_CLASS(sPtr
, WC_SplitView
);
789 sPtr
->resizeSubviewsProc
= proc
;