8 char *WMSplitViewDidResizeSubviewsNotification
9 = "WMSplitViewDidResizeSubviewsNotification";
10 char *WMSplitViewWillResizeSubviewsNotification
11 = "WMSplitViewWillResizeSubviewsNotification";
14 typedef struct _T_SplitViewSubview
{
23 typedef struct W_SplitView
{
29 WMSplitViewConstrainProc
*constrainProc
;
32 unsigned int vertical
:1;
33 unsigned int adjustOnPaint
:1;
34 unsigned int subviewsWereManuallyMoved
:1;
37 /* WMSplitViewResizeSubviewsProc *resizeSubviewsProc; */
42 #define DIVIDER_THICKNESS 8
43 #define MIN_SUBVIEW_SIZE 4
44 #define MAX_SUBVIEW_SIZE -1
47 #define _GetSubviewsCount() WMGetBagItemCount(sPtr->subviewsBag)
49 #define _AddPSubviewStruct(P) \
50 (WMPutInBag(sPtr->subviewsBag,((void*)P)))
52 #define _GetPSubviewStructAt(i) \
53 ((T_SplitViewSubview*)WMGetFromBag(sPtr->subviewsBag,(i)))
55 #define _GetSubviewAt(i) \
56 (((T_SplitViewSubview*)WMGetFromBag(sPtr->subviewsBag,(i)))->view)
58 #define _GetMinSizeAt(i) \
59 (((T_SplitViewSubview*)WMGetFromBag(sPtr->subviewsBag,(i)))->minSize)
61 #define _GetMaxSizeAt(i) \
62 (((T_SplitViewSubview*)WMGetFromBag(sPtr->subviewsBag,(i)))->maxSize)
64 #define _GetSizeAt(i) \
65 (((T_SplitViewSubview*)WMGetFromBag(sPtr->subviewsBag,(i)))->size)
67 #define _GetPosAt(i) \
68 (((T_SplitViewSubview*)WMGetFromBag(sPtr->subviewsBag,(i)))->pos)
70 #define _GetSplitViewSize() \
71 ((sPtr->flags.vertical) ? sPtr->view->size.width : sPtr->view->size.height)
73 static void destroySplitView(SplitView
*sPtr
);
74 static void paintSplitView(SplitView
*sPtr
);
76 static void handleEvents(XEvent
*event
, void *data
);
77 static void handleActionEvents(XEvent
*event
, void *data
);
81 getConstraints(SplitView
*sPtr
, int index
, int *minSize
, int *maxSize
)
83 *minSize
= MIN_SUBVIEW_SIZE
;
84 *maxSize
= MAX_SUBVIEW_SIZE
;
86 if (sPtr
->constrainProc
)
87 (*sPtr
->constrainProc
)(sPtr
, index
, minSize
, maxSize
);
89 if (*minSize
< MIN_SUBVIEW_SIZE
)
90 *minSize
= MIN_SUBVIEW_SIZE
;
92 if (*maxSize
< MIN_SUBVIEW_SIZE
)
93 *maxSize
= MAX_SUBVIEW_SIZE
;
94 else if (*maxSize
< *minSize
)
100 updateConstraints(SplitView
*sPtr
)
102 T_SplitViewSubview
*p
;
105 count
= _GetSubviewsCount();
106 for (i
= 0; i
< count
; i
++) {
107 p
= _GetPSubviewStructAt(i
);
108 getConstraints(sPtr
, i
, &(p
->minSize
), &(p
->maxSize
));
114 resizeView(SplitView
*sPtr
, WMView
*view
, int size
)
118 if (sPtr
->flags
.vertical
) {
120 height
= sPtr
->view
->size
.height
;
122 width
= sPtr
->view
->size
.width
;
127 WMResizeWidget(view
->self
, width
, height
);
129 W_ResizeView(view
, width
, height
);
134 reparentView(SplitView
*sPtr
, WMView
*view
, int pos
)
138 if (sPtr
->flags
.vertical
) {
146 W_ReparentView(view
, sPtr
->view
, x
, y
);
151 moveView(SplitView
*sPtr
, WMView
*view
, int pos
)
155 if (sPtr
->flags
.vertical
) {
164 WMMoveWidget(view
->self
, x
, y
);
166 W_MoveView(view
, x
, y
);
171 checkSizes(SplitView
*sPtr
)
173 int i
, count
, offset
;
174 T_SplitViewSubview
*p
;
176 count
= _GetSubviewsCount();
178 for (i
= 0; i
< count
; i
++) {
179 p
= _GetPSubviewStructAt(i
);
180 if (p
->size
< p
->minSize
) {
181 offset
+= p
->minSize
- p
->size
;
182 p
->size
= p
->minSize
;
183 } else if (p
->maxSize
!= MAX_SUBVIEW_SIZE
&& p
->size
> p
->maxSize
) {
184 offset
+= p
->maxSize
- p
->size
;
185 p
->size
= p
->maxSize
;
194 checkPositions(SplitView
*sPtr
)
197 T_SplitViewSubview
*p
;
199 count
= _GetSubviewsCount();
201 for (i
= 0; i
< count
; i
++) {
202 p
= _GetPSubviewStructAt(i
);
204 pos
+= p
->size
+ DIVIDER_THICKNESS
;
210 updateSubviewsGeom(SplitView
*sPtr
)
213 T_SplitViewSubview
*p
;
215 count
= _GetSubviewsCount();
216 for (i
= 0; i
< count
; i
++) {
217 p
= _GetPSubviewStructAt(i
);
218 resizeView(sPtr
, p
->view
, p
->size
);
219 moveView(sPtr
, p
->view
, p
->pos
);
225 getTotalSize(SplitView
*sPtr
)
227 int i
, count
, totSize
;
229 count
= _GetSubviewsCount();
234 for (i
= 0; i
< count
; i
++)
235 totSize
+= _GetSizeAt(i
) + DIVIDER_THICKNESS
;
237 return (totSize
- DIVIDER_THICKNESS
);
242 distributeOffsetEqually(SplitView
*sPtr
, int offset
)
244 T_SplitViewSubview
*p
;
245 int i
, count
, sizeChanged
, forced
;
247 if ((count
= _GetSubviewsCount()) < 1)
251 while (offset
!= 0) {
253 for (i
= 0; i
< count
&& offset
!= 0; i
++) {
254 p
= _GetPSubviewStructAt(i
);
256 if (p
->size
> p
->minSize
) {
261 } else if (p
->maxSize
== MAX_SUBVIEW_SIZE
|| p
->size
< p
->maxSize
) {
267 if (offset
!= 0 && !sizeChanged
) {
268 p
= _GetPSubviewStructAt(count
-1);
271 p
->maxSize
= MAX_SUBVIEW_SIZE
;
283 distributeOffsetFormEnd(SplitView
*sPtr
, int offset
)
285 T_SplitViewSubview
*p
;
286 int i
, count
, sizeTmp
;
288 if ((count
= _GetSubviewsCount()) < 1)
291 for (i
= count
-1; i
>= 0 && offset
!= 0; i
--) {
292 p
= _GetPSubviewStructAt(i
);
295 if (p
->maxSize
== MAX_SUBVIEW_SIZE
|| p
->size
+ offset
< p
->maxSize
)
298 p
->size
= p
->maxSize
;
300 if (p
->size
+ offset
>= p
->minSize
)
303 p
->size
= p
->minSize
;
305 offset
-= p
->size
- sizeTmp
;
308 return (offset
== 0);
313 adjustSplitViewSubviews(WMSplitView
*sPtr
)
315 T_SplitViewSubview
*p
;
316 int i
, count
, adjSize
, adjPad
;
318 CHECK_CLASS(sPtr
, WC_SplitView
);
321 printf("---- (adjustSplitViewSubviews - 1) ----\n");
325 if ((count
= _GetSubviewsCount()) < 1)
328 adjSize
= (_GetSplitViewSize() - ((count
-1) * DIVIDER_THICKNESS
)) / count
;
329 adjPad
= (_GetSplitViewSize() - ((count
-1) * DIVIDER_THICKNESS
)) % count
;
330 for (i
= 0; i
< count
; i
++) {
331 p
= _GetPSubviewStructAt(i
);
335 distributeOffsetEqually(sPtr
, adjPad
- checkSizes(sPtr
));
337 checkPositions(sPtr
);
338 updateSubviewsGeom(sPtr
);
340 sPtr
->flags
.subviewsWereManuallyMoved
= 0;
343 printf("---- (adjustSplitViewSubviews - 2) ----\n");
350 handleSubviewResized(void *self
, WMNotification
*notif
)
352 SplitView
*sPtr
= (SplitView
*)self
;
354 CHECK_CLASS(sPtr
, WC_SplitView
);
356 if (WMGetNotificationName(notif
) == WMViewSizeDidChangeNotification
) {
357 T_SplitViewSubview
*p
;
359 WMView
*view
= WMGetNotificationObject(notif
);
361 count
= _GetSubviewsCount();
363 for (i
= 0; i
< count
; i
++) {
364 p
= _GetPSubviewStructAt(i
);
365 if (p
->view
== view
) {
373 resizeView(sPtr
, p
->view
, p
->size
);
374 moveView(sPtr
, p
->view
, p
->pos
);
381 handleViewResized(void *self
, WMNotification
*notification
)
383 SplitView
*sPtr
= (SplitView
*)self
;
386 printf("---- (handleViewResized - 1) ----\n");
390 updateConstraints(sPtr
);
393 if (sPtr
->constrainProc
|| sPtr
->flags
.subviewsWereManuallyMoved
) {
394 distributeOffsetFormEnd(sPtr
, _GetSplitViewSize() - getTotalSize(sPtr
));
395 checkPositions(sPtr
);
396 updateSubviewsGeom(sPtr
);
398 adjustSplitViewSubviews(sPtr
);
400 assert(checkSizes(sPtr
) == 0);
403 printf("---- (handleViewResized - 2) ----\n");
410 paintSplitView(SplitView
*sPtr
)
412 T_SplitViewSubview
*p
;
413 W_Screen
*scr
= sPtr
->view
->screen
;
415 WMPixmap
*dimple
= scr
->scrollerDimple
;
418 printf("---- (paintSplitView - 1) ----\n");
422 if (!sPtr
->view
->flags
.mapped
|| !sPtr
->view
->flags
.realized
)
425 XClearWindow(scr
->display
, sPtr
->view
->window
);
427 count
= _GetSubviewsCount();
431 if (sPtr
->flags
.adjustOnPaint
) {
432 handleViewResized(sPtr
, NULL
);
433 sPtr
->flags
.adjustOnPaint
= 0;
436 XSetClipMask(scr
->display
, scr
->clipGC
, dimple
->mask
);
438 if (sPtr
->flags
.vertical
) {
439 x
= ((DIVIDER_THICKNESS
- dimple
->width
) / 2);
440 y
= (sPtr
->view
->size
.height
- dimple
->height
)/2;
442 x
= (sPtr
->view
->size
.width
- dimple
->width
)/2;
443 y
= ((DIVIDER_THICKNESS
- dimple
->height
) / 2);
446 for (i
= 0; i
< count
-1; i
++) {
447 p
= _GetPSubviewStructAt(i
);
449 if (sPtr
->flags
.vertical
)
454 XSetClipOrigin(scr
->display
, scr
->clipGC
, x
, y
);
455 XCopyArea(scr
->display
, dimple
->pixmap
, sPtr
->view
->window
,
456 scr
->clipGC
, 0, 0, dimple
->width
, dimple
->height
, x
, y
);
458 if (sPtr
->flags
.vertical
)
459 x
+= DIVIDER_THICKNESS
;
461 y
+= DIVIDER_THICKNESS
;
465 printf("---- (paintSplitView - 2) ----\n");
472 drawDragingRectangle(SplitView
*sPtr
, int pos
)
476 if (sPtr
->flags
.vertical
) {
479 w
= DIVIDER_THICKNESS
;
480 h
= sPtr
->view
->size
.height
;
484 w
= sPtr
->view
->size
.width
;
485 h
= DIVIDER_THICKNESS
;
488 XFillRectangle(sPtr
->view
->screen
->display
, sPtr
->view
->window
,
489 sPtr
->view
->screen
->ixorGC
, x
, y
, w
, h
);
494 getMinMaxDividerCoord(SplitView
*sPtr
, int divider
, int *minC
, int *maxC
)
496 int relMinC
, relMaxC
;
497 int totSize
= _GetSizeAt(divider
) + _GetSizeAt(divider
+1);
499 relMinC
= _GetMinSizeAt(divider
);
500 if (_GetMaxSizeAt(divider
+1) != MAX_SUBVIEW_SIZE
501 && relMinC
< totSize
- _GetMaxSizeAt(divider
+1))
502 relMinC
= totSize
- _GetMaxSizeAt(divider
+1);
504 relMaxC
= totSize
- _GetMinSizeAt(divider
+1);
505 if (_GetMaxSizeAt(divider
) != MAX_SUBVIEW_SIZE
506 && relMaxC
> _GetMaxSizeAt(divider
))
507 relMaxC
= _GetMaxSizeAt(divider
);
509 *minC
= _GetPosAt(divider
) + relMinC
;
510 *maxC
= _GetPosAt(divider
) + relMaxC
;
515 dragDivider(SplitView
*sPtr
, int clickX
, int clickY
)
517 int divider
, pos
, ofs
, done
, dragging
;
521 int minCoord
, maxCoord
, coord
;
523 if (sPtr
->constrainProc
) {
524 updateConstraints(sPtr
);
526 distributeOffsetFormEnd(sPtr
, _GetSplitViewSize() - getTotalSize(sPtr
));
527 checkPositions(sPtr
);
528 updateSubviewsGeom(sPtr
);
531 scr
= sPtr
->view
->screen
;
532 divider
= ofs
= pos
= done
= 0;
533 coord
= (sPtr
->flags
.vertical
) ? clickX
: clickY
;
534 count
= _GetSubviewsCount();
538 for (i
= 0; i
< count
-1; i
++) {
539 pos
+= _GetSizeAt(i
) + DIVIDER_THICKNESS
;
541 ofs
= coord
- pos
+ DIVIDER_THICKNESS
;
551 getMinMaxDividerCoord(sPtr
, divider
, &minCoord
, &maxCoord
);
556 WMMaskEvent(scr
->display
, ButtonMotionMask
|ButtonReleaseMask
559 coord
= (sPtr
->flags
.vertical
) ? ev
.xmotion
.x
: ev
.xmotion
.y
;
565 drawDragingRectangle(sPtr
, pos
);
570 drawDragingRectangle(sPtr
, pos
);
571 if (coord
- ofs
< minCoord
)
573 else if (coord
- ofs
> maxCoord
)
577 drawDragingRectangle(sPtr
, pos
);
588 T_SplitViewSubview
*p1
, *p2
;
591 p1
= _GetPSubviewStructAt(divider
);
592 p2
= _GetPSubviewStructAt(divider
+1);
594 totSize
= p1
->size
+ DIVIDER_THICKNESS
+ p2
->size
;
596 p1
->size
= pos
- p1
->pos
;
597 p2
->size
= totSize
- p1
->size
- DIVIDER_THICKNESS
;
598 p2
->pos
= p1
->pos
+ p1
->size
+ DIVIDER_THICKNESS
;
600 resizeView(sPtr
, p1
->view
, p1
->size
);
601 moveView(sPtr
, p2
->view
, p2
->pos
);
602 resizeView(sPtr
, p2
->view
, p2
->size
);
603 sPtr
->flags
.subviewsWereManuallyMoved
= 1;
609 handleEvents(XEvent
*event
, void *data
)
611 SplitView
*sPtr
= (SplitView
*)data
;
613 CHECK_CLASS(data
, WC_SplitView
);
616 switch (event
->type
) {
618 if (event
->xexpose
.count
!=0)
620 paintSplitView(sPtr
);
624 destroySplitView(sPtr
);
631 handleActionEvents(XEvent
*event
, void *data
)
634 CHECK_CLASS(data
, WC_SplitView
);
636 switch (event
->type
) {
638 if (event
->xbutton
.button
== Button1
)
639 dragDivider(data
, event
->xbutton
.x
, event
->xbutton
.y
);
647 destroySplitView(SplitView
*sPtr
)
651 count
= _GetSubviewsCount();
652 for (i
= 0; i
< count
; i
++)
653 wfree(WMGetFromBag(sPtr
->subviewsBag
, i
));
654 WMFreeBag(sPtr
->subviewsBag
);
656 WMRemoveNotificationObserver(sPtr
);
662 WMCreateSplitView(WMWidget
*parent
)
666 sPtr
= wmalloc(sizeof(SplitView
));
667 memset(sPtr
, 0, sizeof(SplitView
));
669 sPtr
->widgetClass
= WC_SplitView
;
671 sPtr
->view
= W_CreateView(W_VIEW(parent
));
676 sPtr
->view
->self
= sPtr
;
678 WMSetViewNotifySizeChanges(sPtr
->view
, True
);
680 WMCreateEventHandler(sPtr
->view
, ExposureMask
|StructureNotifyMask
681 |ClientMessageMask
, handleEvents
, sPtr
);
684 WMCreateEventHandler(sPtr
->view
, ButtonPressMask
|ButtonReleaseMask
685 |EnterWindowMask
|LeaveWindowMask
,
686 handleActionEvents
, sPtr
);
689 WMAddNotificationObserver(handleViewResized
, sPtr
,
690 WMViewSizeDidChangeNotification
, sPtr
->view
);
692 sPtr
->subviewsBag
= WMCreateBag(8);
699 WMAdjustSplitViewSubviews(WMSplitView
*sPtr
)
701 CHECK_CLASS(sPtr
, WC_SplitView
);
705 adjustSplitViewSubviews(sPtr
);
707 assert(checkSizes(sPtr
) == 0);
712 WMAddSplitViewSubview(WMSplitView
*sPtr
, WMView
*subview
)
714 int wasMapped
, count
;
715 T_SplitViewSubview
*p
;
717 CHECK_CLASS(sPtr
, WC_SplitView
);
719 if (!(p
= (T_SplitViewSubview
*)wmalloc(sizeof(T_SplitViewSubview
))))
722 wasMapped
= subview
->flags
.mapped
;
724 W_UnmapView(subview
);
726 count
= _GetSubviewsCount();
728 getConstraints(sPtr
, count
, &(p
->minSize
), &(p
->maxSize
));
729 if (sPtr
->flags
.vertical
)
730 p
->size
= subview
->size
.width
;
732 p
->size
= subview
->size
.height
;
734 WMPutInBag(sPtr
->subviewsBag
,(void*)p
);
735 reparentView(sPtr
, subview
, 0);
738 We should have something like that...
740 WMSetViewNotifySizeChanges(subview, True);
741 WMAddNotificationObserver(handleSubviewResized, sPtr,
742 WMViewSizeDidChangeNotification,
744 WMSetViewNotifyMoveChanges(subview, True);
745 WMAddNotificationObserver(handleSubviewResized, sPtr,
746 WMViewMoveDidChangeNotification,
752 sPtr
->flags
.adjustOnPaint
= 1;
753 paintSplitView(sPtr
);
758 WMGetSplitViewSubviewAt(WMSplitView
*sPtr
, int index
)
760 CHECK_CLASS(sPtr
, WC_SplitView
);
762 if (index
> 0 && index
< _GetSubviewsCount())
763 return (_GetSubviewAt(index
));
770 WMRemoveSplitViewSubview(WMSplitView
*sPtr
, WMView
*view
)
772 T_SplitViewSubview
*p
;
775 CHECK_CLASS(sPtr
, WC_SplitView
);
777 count
= _GetSubviewsCount();
778 for (i
= 0; i
< count
; i
++) {
779 p
= _GetPSubviewStructAt(i
);
780 if (p
->view
== view
) {
782 WMDeleteFromBag(sPtr
->subviewsBag
, i
);
783 sPtr
->flags
.adjustOnPaint
= 1;
784 paintSplitView(sPtr
);
792 WMRemoveSplitViewSubviewAt(WMSplitView
*sPtr
, int index
)
794 T_SplitViewSubview
*p
;
796 CHECK_CLASS(sPtr
, WC_SplitView
);
798 if (index
> 0 && index
< _GetSubviewsCount()) {
799 p
= _GetPSubviewStructAt(index
);
801 WMDeleteFromBag(sPtr
->subviewsBag
, index
);
802 sPtr
->flags
.adjustOnPaint
= 1;
803 paintSplitView(sPtr
);
809 WMSetSplitViewConstrainProc(WMSplitView
*sPtr
, WMSplitViewConstrainProc
*proc
)
811 CHECK_CLASS(sPtr
, WC_SplitView
);
813 sPtr
->constrainProc
= proc
;
818 WMGetSplitViewSubviewsCount(WMSplitView
*sPtr
)
820 CHECK_CLASS(sPtr
, WC_SplitView
);
822 return (_GetSubviewsCount());
827 WMGetSplitViewVertical(WMSplitView
*sPtr
)
829 CHECK_CLASS(sPtr
, WC_SplitView
);
831 return (sPtr
->flags
.vertical
== 1);
835 WMSetSplitViewVertical(WMSplitView
*sPtr
, Bool flag
)
839 CHECK_CLASS(sPtr
, WC_SplitView
);
841 vertical
= (flag
) ? 1 : 0;
842 if (sPtr
->flags
.vertical
== vertical
)
845 sPtr
->flags
.vertical
= vertical
;
847 if (sPtr
->view
->flags
.mapped
&& sPtr
->view
->flags
.realized
)
848 handleViewResized(sPtr
, NULL
);
850 sPtr
->flags
.adjustOnPaint
= 1;
855 WMGetSplitViewDividerThickness(WMSplitView
*sPtr
)
857 CHECK_CLASS(sPtr
, WC_SplitView
);
859 return (DIVIDER_THICKNESS
);
864 WMSetSplitViewResizeSubviewsProc(WMSplitView
*sPtr
,
865 WMSplitViewResizeSubviewsProc
*proc
)
867 CHECK_CLASS(sPtr
, WC_SplitView
);
869 sPtr
->resizeSubviewsProc
= proc
;