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
;
354 /* Parameter not used, but tell the compiler that it is ok */
358 printf("---- (handleViewResized - 1) ----\n");
362 updateConstraints(sPtr
);
365 if (sPtr
->constrainProc
|| sPtr
->flags
.subviewsWereManuallyMoved
) {
366 distributeOffsetFormEnd(sPtr
, _GetSplitViewSize() - getTotalSize(sPtr
));
367 checkPositions(sPtr
);
368 updateSubviewsGeom(sPtr
);
370 adjustSplitViewSubviews(sPtr
);
372 assert(checkSizes(sPtr
) == 0);
375 printf("---- (handleViewResized - 2) ----\n");
380 static void paintSplitView(WMSplitView
* sPtr
)
382 W_SplitViewSubview
*p
;
383 W_Screen
*scr
= sPtr
->view
->screen
;
385 WMPixmap
*dimple
= scr
->scrollerDimple
;
388 printf("---- (paintSplitView - 1) ----\n");
392 if (!sPtr
->view
->flags
.mapped
|| !sPtr
->view
->flags
.realized
)
395 XClearWindow(scr
->display
, sPtr
->view
->window
);
397 count
= _GetSubviewsCount();
401 if (sPtr
->flags
.adjustOnPaint
) {
402 handleViewResized(sPtr
, NULL
);
403 sPtr
->flags
.adjustOnPaint
= 0;
406 XSetClipMask(scr
->display
, scr
->clipGC
, dimple
->mask
);
408 if (sPtr
->flags
.vertical
) {
409 x
= ((DIVIDER_THICKNESS
- dimple
->width
) / 2);
410 y
= (sPtr
->view
->size
.height
- dimple
->height
) / 2;
412 x
= (sPtr
->view
->size
.width
- dimple
->width
) / 2;
413 y
= ((DIVIDER_THICKNESS
- dimple
->height
) / 2);
416 for (i
= 0; i
< count
- 1; i
++) {
417 p
= _GetPSubviewStructAt(i
);
419 if (sPtr
->flags
.vertical
)
424 XSetClipOrigin(scr
->display
, scr
->clipGC
, x
, y
);
425 XCopyArea(scr
->display
, dimple
->pixmap
, sPtr
->view
->window
,
426 scr
->clipGC
, 0, 0, dimple
->width
, dimple
->height
, x
, y
);
428 if (sPtr
->flags
.vertical
)
429 x
+= DIVIDER_THICKNESS
;
431 y
+= DIVIDER_THICKNESS
;
435 printf("---- (paintSplitView - 2) ----\n");
440 static void drawDragingRectangle(WMSplitView
* sPtr
, int pos
)
444 if (sPtr
->flags
.vertical
) {
447 w
= DIVIDER_THICKNESS
;
448 h
= sPtr
->view
->size
.height
;
452 w
= sPtr
->view
->size
.width
;
453 h
= DIVIDER_THICKNESS
;
456 XFillRectangle(sPtr
->view
->screen
->display
, sPtr
->view
->window
, sPtr
->view
->screen
->ixorGC
, x
, y
, w
, h
);
459 static void getMinMaxDividerCoord(WMSplitView
* sPtr
, int divider
, int *minC
, int *maxC
)
461 int relMinC
, relMaxC
;
462 int totSize
= _GetSizeAt(divider
) + _GetSizeAt(divider
+ 1);
464 relMinC
= _GetMinSizeAt(divider
);
465 if (_GetMaxSizeAt(divider
+ 1) != MAX_SUBVIEW_SIZE
&& relMinC
< totSize
- _GetMaxSizeAt(divider
+ 1))
466 relMinC
= totSize
- _GetMaxSizeAt(divider
+ 1);
468 relMaxC
= totSize
- _GetMinSizeAt(divider
+ 1);
469 if (_GetMaxSizeAt(divider
) != MAX_SUBVIEW_SIZE
&& relMaxC
> _GetMaxSizeAt(divider
))
470 relMaxC
= _GetMaxSizeAt(divider
);
472 *minC
= _GetPosAt(divider
) + relMinC
;
473 *maxC
= _GetPosAt(divider
) + relMaxC
;
476 static void dragDivider(WMSplitView
* sPtr
, int clickX
, int clickY
)
478 int divider
, pos
, ofs
, done
, dragging
;
482 int minCoord
, maxCoord
, coord
;
484 if (sPtr
->constrainProc
) {
485 updateConstraints(sPtr
);
487 distributeOffsetFormEnd(sPtr
, _GetSplitViewSize() - getTotalSize(sPtr
));
488 checkPositions(sPtr
);
489 updateSubviewsGeom(sPtr
);
492 scr
= sPtr
->view
->screen
;
493 divider
= ofs
= pos
= done
= 0;
494 coord
= (sPtr
->flags
.vertical
) ? clickX
: clickY
;
495 count
= _GetSubviewsCount();
499 for (i
= 0; i
< count
- 1; i
++) {
500 pos
+= _GetSizeAt(i
) + DIVIDER_THICKNESS
;
502 ofs
= coord
- pos
+ DIVIDER_THICKNESS
;
512 getMinMaxDividerCoord(sPtr
, divider
, &minCoord
, &maxCoord
);
517 WMMaskEvent(scr
->display
, ButtonMotionMask
| ButtonReleaseMask
| ExposureMask
, &ev
);
519 coord
= (sPtr
->flags
.vertical
) ? ev
.xmotion
.x
: ev
.xmotion
.y
;
525 drawDragingRectangle(sPtr
, pos
);
530 drawDragingRectangle(sPtr
, pos
);
531 if (coord
- ofs
< minCoord
)
533 else if (coord
- ofs
> maxCoord
)
537 drawDragingRectangle(sPtr
, pos
);
548 W_SplitViewSubview
*p1
, *p2
;
551 p1
= _GetPSubviewStructAt(divider
);
552 p2
= _GetPSubviewStructAt(divider
+ 1);
554 totSize
= p1
->size
+ DIVIDER_THICKNESS
+ p2
->size
;
556 p1
->size
= pos
- p1
->pos
;
557 p2
->size
= totSize
- p1
->size
- DIVIDER_THICKNESS
;
558 p2
->pos
= p1
->pos
+ p1
->size
+ DIVIDER_THICKNESS
;
560 resizeView(sPtr
, p1
->view
, p1
->size
);
561 moveView(sPtr
, p2
->view
, p2
->pos
);
562 resizeView(sPtr
, p2
->view
, p2
->size
);
563 sPtr
->flags
.subviewsWereManuallyMoved
= 1;
567 static void handleEvents(XEvent
* event
, void *data
)
569 WMSplitView
*sPtr
= (WMSplitView
*) data
;
571 CHECK_CLASS(data
, WC_SplitView
);
573 switch (event
->type
) {
575 if (event
->xexpose
.count
!= 0)
577 paintSplitView(sPtr
);
581 destroySplitView(sPtr
);
586 static void handleActionEvents(XEvent
* event
, void *data
)
589 CHECK_CLASS(data
, WC_SplitView
);
591 switch (event
->type
) {
593 if (event
->xbutton
.button
== Button1
)
594 dragDivider(data
, event
->xbutton
.x
, event
->xbutton
.y
);
599 static void destroySplitView(WMSplitView
* sPtr
)
601 WMFreeArray(sPtr
->subviews
);
603 WMRemoveNotificationObserver(sPtr
);
608 WMSplitView
*WMCreateSplitView(WMWidget
* parent
)
612 sPtr
= wmalloc(sizeof(WMSplitView
));
613 sPtr
->widgetClass
= WC_SplitView
;
615 sPtr
->view
= W_CreateView(W_VIEW(parent
));
620 sPtr
->view
->self
= sPtr
;
622 WMSetViewNotifySizeChanges(sPtr
->view
, True
);
624 WMCreateEventHandler(sPtr
->view
, ExposureMask
| StructureNotifyMask
625 | ClientMessageMask
, handleEvents
, sPtr
);
627 WMCreateEventHandler(sPtr
->view
, ButtonPressMask
| ButtonReleaseMask
628 | EnterWindowMask
| LeaveWindowMask
, handleActionEvents
, sPtr
);
630 WMAddNotificationObserver(handleViewResized
, sPtr
, WMViewSizeDidChangeNotification
, sPtr
->view
);
632 sPtr
->subviews
= WMCreateArrayWithDestructor(8, wfree
);
637 void WMAdjustSplitViewSubviews(WMSplitView
* sPtr
)
639 CHECK_CLASS(sPtr
, WC_SplitView
);
643 adjustSplitViewSubviews(sPtr
);
645 assert(checkSizes(sPtr
) == 0);
648 void WMAddSplitViewSubview(WMSplitView
* sPtr
, WMView
* subview
)
650 int wasMapped
, count
;
651 W_SplitViewSubview
*p
;
653 CHECK_CLASS(sPtr
, WC_SplitView
);
655 p
= (W_SplitViewSubview
*) wmalloc(sizeof(W_SplitViewSubview
));
659 wasMapped
= subview
->flags
.mapped
;
661 W_UnmapView(subview
);
663 count
= _GetSubviewsCount();
665 getConstraints(sPtr
, count
, &(p
->minSize
), &(p
->maxSize
));
666 if (sPtr
->flags
.vertical
)
667 p
->size
= subview
->size
.width
;
669 p
->size
= subview
->size
.height
;
671 WMAddToArray(sPtr
->subviews
, p
);
672 reparentView(sPtr
, subview
, 0);
675 We should have something like that...
677 WMSetViewNotifySizeChanges(subview, True);
678 WMAddNotificationObserver(handleSubviewResized, sPtr,
679 WMViewSizeDidChangeNotification,
681 WMSetViewNotifyMoveChanges(subview, True);
682 WMAddNotificationObserver(handleSubviewResized, sPtr,
683 WMViewMoveDidChangeNotification,
689 sPtr
->flags
.adjustOnPaint
= 1;
690 paintSplitView(sPtr
);
692 handleViewResized(sPtr
, NULL
);
696 WMView
*WMGetSplitViewSubviewAt(WMSplitView
* sPtr
, int index
)
698 CHECK_CLASS(sPtr
, WC_SplitView
);
700 if (index
>= 0 && index
< _GetSubviewsCount())
701 return (_GetSubviewAt(index
));
706 void WMRemoveSplitViewSubview(WMSplitView
* sPtr
, WMView
* view
)
708 W_SplitViewSubview
*p
;
711 CHECK_CLASS(sPtr
, WC_SplitView
);
713 /* TODO: rewrite this. This code with macros is getting more complex than it worths */
714 count
= _GetSubviewsCount();
715 for (i
= 0; i
< count
; i
++) {
716 p
= _GetPSubviewStructAt(i
);
717 if (p
->view
== view
) {
718 WMDeleteFromArray(sPtr
->subviews
, i
);
719 sPtr
->flags
.adjustOnPaint
= 1;
720 paintSplitView(sPtr
);
726 void WMRemoveSplitViewSubviewAt(WMSplitView
* sPtr
, int index
)
728 CHECK_CLASS(sPtr
, WC_SplitView
);
730 /* TODO: same about rewrite */
731 if (index
>= 0 && index
< _GetSubviewsCount()) {
732 WMDeleteFromArray(sPtr
->subviews
, index
);
733 sPtr
->flags
.adjustOnPaint
= 1;
734 paintSplitView(sPtr
);
738 void WMSetSplitViewConstrainProc(WMSplitView
* sPtr
, WMSplitViewConstrainProc
* proc
)
740 CHECK_CLASS(sPtr
, WC_SplitView
);
742 sPtr
->constrainProc
= proc
;
745 int WMGetSplitViewSubviewsCount(WMSplitView
* sPtr
)
747 CHECK_CLASS(sPtr
, WC_SplitView
);
749 return (_GetSubviewsCount());
752 Bool
WMGetSplitViewVertical(WMSplitView
* sPtr
)
754 CHECK_CLASS(sPtr
, WC_SplitView
);
756 return (sPtr
->flags
.vertical
== 1);
759 void WMSetSplitViewVertical(WMSplitView
* sPtr
, Bool flag
)
763 CHECK_CLASS(sPtr
, WC_SplitView
);
765 vertical
= ((flag
== 0) ? 0 : 1);
766 if (sPtr
->flags
.vertical
== vertical
)
769 sPtr
->flags
.vertical
= vertical
;
771 /* if (sPtr->view->flags.mapped && sPtr->view->flags.realized) */
772 handleViewResized(sPtr
, NULL
);
774 sPtr->flags.adjustOnPaint = 1;
778 int WMGetSplitViewDividerThickness(WMSplitView
*sPtr
)
780 CHECK_CLASS(sPtr
, WC_SplitView
);
784 return (DIVIDER_THICKNESS
);
788 void WMSetSplitViewResizeSubviewsProc(WMSplitView
* sPtr
, WMSplitViewResizeSubviewsProc
* proc
)
790 CHECK_CLASS(sPtr
, WC_SplitView
);
792 sPtr
->resizeSubviewsProc
= proc
;