8 char *WMSplitViewDidResizeSubviewsNotification
9 = "WMSplitViewDidResizeSubviewsNotification";
10 char *WMSplitViewWillResizeSubviewsNotification
11 = "WMSplitViewWillResizeSubviewsNotification";
14 typedef struct W_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 /* TODO: rewrite --Dan */
48 #define _GetSubviewsCount() WMGetArrayItemCount(sPtr->subviews)
50 #define _AddPSubviewStruct(P) \
51 (WMAddToArray(sPtr->subviews,((void*)P)))
53 #define _GetPSubviewStructAt(i) \
54 ((W_SplitViewSubview*)WMGetFromArray(sPtr->subviews,(i)))
56 #define _GetSubviewAt(i) \
57 (((W_SplitViewSubview*)WMGetFromArray(sPtr->subviews,(i)))->view)
59 #define _GetMinSizeAt(i) \
60 (((W_SplitViewSubview*)WMGetFromArray(sPtr->subviews,(i)))->minSize)
62 #define _GetMaxSizeAt(i) \
63 (((W_SplitViewSubview*)WMGetFromArray(sPtr->subviews,(i)))->maxSize)
65 #define _GetSizeAt(i) \
66 (((W_SplitViewSubview*)WMGetFromArray(sPtr->subviews,(i)))->size)
68 #define _GetPosAt(i) \
69 (((W_SplitViewSubview*)WMGetFromArray(sPtr->subviews,(i)))->pos)
71 #define _GetSplitViewSize() \
72 ((sPtr->flags.vertical) ? sPtr->view->size.width : sPtr->view->size.height)
74 static void destroySplitView(WMSplitView
*sPtr
);
75 static void paintSplitView(WMSplitView
*sPtr
);
77 static void handleEvents(XEvent
*event
, void *data
);
78 static void handleActionEvents(XEvent
*event
, void *data
);
82 getConstraints(WMSplitView
*sPtr
, int index
, int *minSize
, int *maxSize
)
84 *minSize
= MIN_SUBVIEW_SIZE
;
85 *maxSize
= MAX_SUBVIEW_SIZE
;
87 if (sPtr
->constrainProc
)
88 (*sPtr
->constrainProc
)(sPtr
, index
, minSize
, maxSize
);
90 if (*minSize
< MIN_SUBVIEW_SIZE
)
91 *minSize
= MIN_SUBVIEW_SIZE
;
93 if (*maxSize
< MIN_SUBVIEW_SIZE
)
94 *maxSize
= MAX_SUBVIEW_SIZE
;
95 else if (*maxSize
< *minSize
)
101 updateConstraints(WMSplitView
*sPtr
)
103 W_SplitViewSubview
*p
;
106 count
= _GetSubviewsCount();
107 for (i
= 0; i
< count
; i
++) {
108 p
= _GetPSubviewStructAt(i
);
109 getConstraints(sPtr
, i
, &(p
->minSize
), &(p
->maxSize
));
115 resizeView(WMSplitView
*sPtr
, WMView
*view
, int size
)
119 if (sPtr
->flags
.vertical
) {
121 height
= sPtr
->view
->size
.height
;
123 width
= sPtr
->view
->size
.width
;
128 WMResizeWidget(view
->self
, width
, height
);
130 W_ResizeView(view
, width
, height
);
135 reparentView(WMSplitView
*sPtr
, WMView
*view
, int pos
)
139 if (sPtr
->flags
.vertical
) {
147 W_ReparentView(view
, sPtr
->view
, x
, y
);
152 moveView(WMSplitView
*sPtr
, WMView
*view
, int pos
)
156 if (sPtr
->flags
.vertical
) {
165 WMMoveWidget(view
->self
, x
, y
);
167 W_MoveView(view
, x
, y
);
172 checkSizes(WMSplitView
*sPtr
)
174 int i
, count
, offset
;
175 W_SplitViewSubview
*p
;
177 count
= _GetSubviewsCount();
179 for (i
= 0; i
< count
; i
++) {
180 p
= _GetPSubviewStructAt(i
);
181 if (p
->size
< p
->minSize
) {
182 offset
+= p
->minSize
- p
->size
;
183 p
->size
= p
->minSize
;
184 } else if (p
->maxSize
!= MAX_SUBVIEW_SIZE
&& p
->size
> p
->maxSize
) {
185 offset
+= p
->maxSize
- p
->size
;
186 p
->size
= p
->maxSize
;
195 checkPositions(WMSplitView
*sPtr
)
198 W_SplitViewSubview
*p
;
200 count
= _GetSubviewsCount();
202 for (i
= 0; i
< count
; i
++) {
203 p
= _GetPSubviewStructAt(i
);
205 pos
+= p
->size
+ DIVIDER_THICKNESS
;
211 updateSubviewsGeom(WMSplitView
*sPtr
)
214 W_SplitViewSubview
*p
;
216 count
= _GetSubviewsCount();
217 for (i
= 0; i
< count
; i
++) {
218 p
= _GetPSubviewStructAt(i
);
219 resizeView(sPtr
, p
->view
, p
->size
);
220 moveView(sPtr
, p
->view
, p
->pos
);
226 getTotalSize(WMSplitView
*sPtr
)
228 int i
, count
, totSize
;
230 count
= _GetSubviewsCount();
235 for (i
= 0; i
< count
; i
++)
236 totSize
+= _GetSizeAt(i
) + DIVIDER_THICKNESS
;
238 return (totSize
- DIVIDER_THICKNESS
);
243 distributeOffsetEqually(WMSplitView
*sPtr
, int offset
)
245 W_SplitViewSubview
*p
;
246 int i
, count
, sizeChanged
, forced
;
248 if ((count
= _GetSubviewsCount()) < 1)
252 while (offset
!= 0) {
254 for (i
= 0; i
< count
&& offset
!= 0; i
++) {
255 p
= _GetPSubviewStructAt(i
);
257 if (p
->size
> p
->minSize
) {
262 } else if (p
->maxSize
== MAX_SUBVIEW_SIZE
|| p
->size
< p
->maxSize
) {
268 if (offset
!= 0 && !sizeChanged
) {
269 p
= _GetPSubviewStructAt(count
-1);
272 p
->maxSize
= MAX_SUBVIEW_SIZE
;
284 distributeOffsetFormEnd(WMSplitView
*sPtr
, int offset
)
286 W_SplitViewSubview
*p
;
287 int i
, count
, sizeTmp
;
289 if ((count
= _GetSubviewsCount()) < 1)
292 for (i
= count
-1; i
>= 0 && offset
!= 0; i
--) {
293 p
= _GetPSubviewStructAt(i
);
296 if (p
->maxSize
== MAX_SUBVIEW_SIZE
|| p
->size
+ offset
< p
->maxSize
)
299 p
->size
= p
->maxSize
;
301 if (p
->size
+ offset
>= p
->minSize
)
304 p
->size
= p
->minSize
;
306 offset
-= p
->size
- sizeTmp
;
309 return (offset
== 0);
314 adjustSplitViewSubviews(WMSplitView
*sPtr
)
316 W_SplitViewSubview
*p
;
317 int i
, count
, adjSize
, adjPad
;
319 CHECK_CLASS(sPtr
, WC_SplitView
);
322 printf("---- (adjustSplitViewSubviews - 1) ----\n");
326 if ((count
= _GetSubviewsCount()) < 1)
329 adjSize
= (_GetSplitViewSize() - ((count
-1) * DIVIDER_THICKNESS
)) / count
;
330 adjPad
= (_GetSplitViewSize() - ((count
-1) * DIVIDER_THICKNESS
)) % count
;
331 for (i
= 0; i
< count
; i
++) {
332 p
= _GetPSubviewStructAt(i
);
336 distributeOffsetEqually(sPtr
, adjPad
- checkSizes(sPtr
));
338 checkPositions(sPtr
);
339 updateSubviewsGeom(sPtr
);
341 sPtr
->flags
.subviewsWereManuallyMoved
= 0;
344 printf("---- (adjustSplitViewSubviews - 2) ----\n");
351 handleSubviewResized(void *self
, WMNotification
*notif
)
353 WMSplitView
*sPtr
= (WMSplitView
*)self
;
355 CHECK_CLASS(sPtr
, WC_SplitView
);
357 if (WMGetNotificationName(notif
) == WMViewSizeDidChangeNotification
) {
358 W_SplitViewSubview
*p
;
360 WMView
*view
= WMGetNotificationObject(notif
);
362 count
= _GetSubviewsCount();
364 for (i
= 0; i
< count
; i
++) {
365 p
= _GetPSubviewStructAt(i
);
366 if (p
->view
== view
) {
374 resizeView(sPtr
, p
->view
, p
->size
);
375 moveView(sPtr
, p
->view
, p
->pos
);
382 handleViewResized(void *self
, WMNotification
*notification
)
384 WMSplitView
*sPtr
= (WMSplitView
*)self
;
387 printf("---- (handleViewResized - 1) ----\n");
391 updateConstraints(sPtr
);
394 if (sPtr
->constrainProc
|| sPtr
->flags
.subviewsWereManuallyMoved
) {
395 distributeOffsetFormEnd(sPtr
, _GetSplitViewSize() - getTotalSize(sPtr
));
396 checkPositions(sPtr
);
397 updateSubviewsGeom(sPtr
);
399 adjustSplitViewSubviews(sPtr
);
401 assert(checkSizes(sPtr
) == 0);
404 printf("---- (handleViewResized - 2) ----\n");
411 paintSplitView(WMSplitView
*sPtr
)
413 W_SplitViewSubview
*p
;
414 W_Screen
*scr
= sPtr
->view
->screen
;
416 WMPixmap
*dimple
= scr
->scrollerDimple
;
419 printf("---- (paintSplitView - 1) ----\n");
423 if (!sPtr
->view
->flags
.mapped
|| !sPtr
->view
->flags
.realized
)
426 XClearWindow(scr
->display
, sPtr
->view
->window
);
428 count
= _GetSubviewsCount();
432 if (sPtr
->flags
.adjustOnPaint
) {
433 handleViewResized(sPtr
, NULL
);
434 sPtr
->flags
.adjustOnPaint
= 0;
437 XSetClipMask(scr
->display
, scr
->clipGC
, dimple
->mask
);
439 if (sPtr
->flags
.vertical
) {
440 x
= ((DIVIDER_THICKNESS
- dimple
->width
) / 2);
441 y
= (sPtr
->view
->size
.height
- dimple
->height
)/2;
443 x
= (sPtr
->view
->size
.width
- dimple
->width
)/2;
444 y
= ((DIVIDER_THICKNESS
- dimple
->height
) / 2);
447 for (i
= 0; i
< count
-1; i
++) {
448 p
= _GetPSubviewStructAt(i
);
450 if (sPtr
->flags
.vertical
)
455 XSetClipOrigin(scr
->display
, scr
->clipGC
, x
, y
);
456 XCopyArea(scr
->display
, dimple
->pixmap
, sPtr
->view
->window
,
457 scr
->clipGC
, 0, 0, dimple
->width
, dimple
->height
, x
, y
);
459 if (sPtr
->flags
.vertical
)
460 x
+= DIVIDER_THICKNESS
;
462 y
+= DIVIDER_THICKNESS
;
466 printf("---- (paintSplitView - 2) ----\n");
473 drawDragingRectangle(WMSplitView
*sPtr
, int pos
)
477 if (sPtr
->flags
.vertical
) {
480 w
= DIVIDER_THICKNESS
;
481 h
= sPtr
->view
->size
.height
;
485 w
= sPtr
->view
->size
.width
;
486 h
= DIVIDER_THICKNESS
;
489 XFillRectangle(sPtr
->view
->screen
->display
, sPtr
->view
->window
,
490 sPtr
->view
->screen
->ixorGC
, x
, y
, w
, h
);
495 getMinMaxDividerCoord(WMSplitView
*sPtr
, int divider
, int *minC
, int *maxC
)
497 int relMinC
, relMaxC
;
498 int totSize
= _GetSizeAt(divider
) + _GetSizeAt(divider
+1);
500 relMinC
= _GetMinSizeAt(divider
);
501 if (_GetMaxSizeAt(divider
+1) != MAX_SUBVIEW_SIZE
502 && relMinC
< totSize
- _GetMaxSizeAt(divider
+1))
503 relMinC
= totSize
- _GetMaxSizeAt(divider
+1);
505 relMaxC
= totSize
- _GetMinSizeAt(divider
+1);
506 if (_GetMaxSizeAt(divider
) != MAX_SUBVIEW_SIZE
507 && relMaxC
> _GetMaxSizeAt(divider
))
508 relMaxC
= _GetMaxSizeAt(divider
);
510 *minC
= _GetPosAt(divider
) + relMinC
;
511 *maxC
= _GetPosAt(divider
) + relMaxC
;
516 dragDivider(WMSplitView
*sPtr
, int clickX
, int clickY
)
518 int divider
, pos
, ofs
, done
, dragging
;
522 int minCoord
, maxCoord
, coord
;
524 if (sPtr
->constrainProc
) {
525 updateConstraints(sPtr
);
527 distributeOffsetFormEnd(sPtr
, _GetSplitViewSize() - getTotalSize(sPtr
));
528 checkPositions(sPtr
);
529 updateSubviewsGeom(sPtr
);
532 scr
= sPtr
->view
->screen
;
533 divider
= ofs
= pos
= done
= 0;
534 coord
= (sPtr
->flags
.vertical
) ? clickX
: clickY
;
535 count
= _GetSubviewsCount();
539 for (i
= 0; i
< count
-1; i
++) {
540 pos
+= _GetSizeAt(i
) + DIVIDER_THICKNESS
;
542 ofs
= coord
- pos
+ DIVIDER_THICKNESS
;
552 getMinMaxDividerCoord(sPtr
, divider
, &minCoord
, &maxCoord
);
557 WMMaskEvent(scr
->display
, ButtonMotionMask
|ButtonReleaseMask
560 coord
= (sPtr
->flags
.vertical
) ? ev
.xmotion
.x
: ev
.xmotion
.y
;
566 drawDragingRectangle(sPtr
, pos
);
571 drawDragingRectangle(sPtr
, pos
);
572 if (coord
- ofs
< minCoord
)
574 else if (coord
- ofs
> maxCoord
)
578 drawDragingRectangle(sPtr
, pos
);
589 W_SplitViewSubview
*p1
, *p2
;
592 p1
= _GetPSubviewStructAt(divider
);
593 p2
= _GetPSubviewStructAt(divider
+1);
595 totSize
= p1
->size
+ DIVIDER_THICKNESS
+ p2
->size
;
597 p1
->size
= pos
- p1
->pos
;
598 p2
->size
= totSize
- p1
->size
- DIVIDER_THICKNESS
;
599 p2
->pos
= p1
->pos
+ p1
->size
+ DIVIDER_THICKNESS
;
601 resizeView(sPtr
, p1
->view
, p1
->size
);
602 moveView(sPtr
, p2
->view
, p2
->pos
);
603 resizeView(sPtr
, p2
->view
, p2
->size
);
604 sPtr
->flags
.subviewsWereManuallyMoved
= 1;
610 handleEvents(XEvent
*event
, void *data
)
612 WMSplitView
*sPtr
= (WMSplitView
*)data
;
614 CHECK_CLASS(data
, WC_SplitView
);
617 switch (event
->type
) {
619 if (event
->xexpose
.count
!=0)
621 paintSplitView(sPtr
);
625 destroySplitView(sPtr
);
632 handleActionEvents(XEvent
*event
, void *data
)
635 CHECK_CLASS(data
, WC_SplitView
);
637 switch (event
->type
) {
639 if (event
->xbutton
.button
== Button1
)
640 dragDivider(data
, event
->xbutton
.x
, event
->xbutton
.y
);
648 destroySplitView(WMSplitView
*sPtr
)
650 WMFreeArray(sPtr
->subviews
);
652 WMRemoveNotificationObserver(sPtr
);
658 WMCreateSplitView(WMWidget
*parent
)
662 sPtr
= wmalloc(sizeof(WMSplitView
));
663 memset(sPtr
, 0, sizeof(WMSplitView
));
665 sPtr
->widgetClass
= WC_SplitView
;
667 sPtr
->view
= W_CreateView(W_VIEW(parent
));
672 sPtr
->view
->self
= sPtr
;
674 WMSetViewNotifySizeChanges(sPtr
->view
, True
);
676 WMCreateEventHandler(sPtr
->view
, ExposureMask
|StructureNotifyMask
677 |ClientMessageMask
, handleEvents
, sPtr
);
680 WMCreateEventHandler(sPtr
->view
, ButtonPressMask
|ButtonReleaseMask
681 |EnterWindowMask
|LeaveWindowMask
,
682 handleActionEvents
, sPtr
);
685 WMAddNotificationObserver(handleViewResized
, sPtr
,
686 WMViewSizeDidChangeNotification
, sPtr
->view
);
688 sPtr
->subviews
= WMCreateArrayWithDestructor(8, wfree
);
695 WMAdjustSplitViewSubviews(WMSplitView
*sPtr
)
697 CHECK_CLASS(sPtr
, WC_SplitView
);
701 adjustSplitViewSubviews(sPtr
);
703 assert(checkSizes(sPtr
) == 0);
708 WMAddSplitViewSubview(WMSplitView
*sPtr
, WMView
*subview
)
710 int wasMapped
, count
;
711 W_SplitViewSubview
*p
;
713 CHECK_CLASS(sPtr
, WC_SplitView
);
715 if (!(p
= (W_SplitViewSubview
*)wmalloc(sizeof(W_SplitViewSubview
))))
718 wasMapped
= subview
->flags
.mapped
;
720 W_UnmapView(subview
);
722 count
= _GetSubviewsCount();
724 getConstraints(sPtr
, count
, &(p
->minSize
), &(p
->maxSize
));
725 if (sPtr
->flags
.vertical
)
726 p
->size
= subview
->size
.width
;
728 p
->size
= subview
->size
.height
;
730 WMAddToArray(sPtr
->subviews
, p
);
731 reparentView(sPtr
, subview
, 0);
734 We should have something like that...
736 WMSetViewNotifySizeChanges(subview, True);
737 WMAddNotificationObserver(handleSubviewResized, sPtr,
738 WMViewSizeDidChangeNotification,
740 WMSetViewNotifyMoveChanges(subview, True);
741 WMAddNotificationObserver(handleSubviewResized, sPtr,
742 WMViewMoveDidChangeNotification,
748 sPtr
->flags
.adjustOnPaint
= 1;
749 paintSplitView(sPtr
);
751 handleViewResized(sPtr
, NULL
);
757 WMGetSplitViewSubviewAt(WMSplitView
*sPtr
, int index
)
759 CHECK_CLASS(sPtr
, WC_SplitView
);
761 if (index
>= 0 && index
< _GetSubviewsCount())
762 return (_GetSubviewAt(index
));
769 WMRemoveSplitViewSubview(WMSplitView
*sPtr
, WMView
*view
)
771 W_SplitViewSubview
*p
;
774 CHECK_CLASS(sPtr
, WC_SplitView
);
776 /* TODO: rewrite this. This code with macros is getting more complex than it worths */
777 count
= _GetSubviewsCount();
778 for (i
= 0; i
< count
; i
++) {
779 p
= _GetPSubviewStructAt(i
);
780 if (p
->view
== view
) {
781 WMDeleteFromArray(sPtr
->subviews
, i
);
782 sPtr
->flags
.adjustOnPaint
= 1;
783 paintSplitView(sPtr
);
791 WMRemoveSplitViewSubviewAt(WMSplitView
*sPtr
, int index
)
793 W_SplitViewSubview
*p
;
795 CHECK_CLASS(sPtr
, WC_SplitView
);
797 /* TODO: same about rewrite */
798 if (index
>= 0 && index
< _GetSubviewsCount()) {
799 p
= _GetPSubviewStructAt(index
);
800 WMDeleteFromArray(sPtr
->subviews
, index
);
801 sPtr
->flags
.adjustOnPaint
= 1;
802 paintSplitView(sPtr
);
808 WMSetSplitViewConstrainProc(WMSplitView
*sPtr
, WMSplitViewConstrainProc
*proc
)
810 CHECK_CLASS(sPtr
, WC_SplitView
);
812 sPtr
->constrainProc
= proc
;
817 WMGetSplitViewSubviewsCount(WMSplitView
*sPtr
)
819 CHECK_CLASS(sPtr
, WC_SplitView
);
821 return (_GetSubviewsCount());
826 WMGetSplitViewVertical(WMSplitView
*sPtr
)
828 CHECK_CLASS(sPtr
, WC_SplitView
);
830 return (sPtr
->flags
.vertical
== 1);
834 WMSetSplitViewVertical(WMSplitView
*sPtr
, Bool flag
)
838 CHECK_CLASS(sPtr
, WC_SplitView
);
840 vertical
= (flag
) ? 1 : 0;
841 if (sPtr
->flags
.vertical
== vertical
)
844 sPtr
->flags
.vertical
= vertical
;
846 /* if (sPtr->view->flags.mapped && sPtr->view->flags.realized)*/
847 handleViewResized(sPtr
, NULL
);
849 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
;