5 typedef struct W_TabView
{
9 struct W_TabViewItem
**items
;
11 int maxItems
; /* size of items array, can be increased */
23 WMTabViewDelegate
*delegate
;
29 WMReliefType relief
:4;
30 WMTitlePosition titlePosition
:4;
34 unsigned dontFitAll
:1;
43 #define DEFAULT_WIDTH 40
44 #define DEFAULT_HEIGHT 40
46 #define NORMAL_SIDE_OFFSET 8
47 #define BUTTONED_SIDE_OFFSET 20
50 static void destroyTabView(TabView
*tPtr
);
51 static void paintTabView(TabView
*tPtr
);
54 static void W_SetTabViewItemParent(WMTabViewItem
*item
, WMTabView
*parent
);
56 static void W_DrawLabel(WMTabViewItem
*item
, Drawable d
, WMRect rect
);
58 static void W_UnmapTabViewItem(WMTabViewItem
*item
);
60 static void W_MapTabViewItem(WMTabViewItem
*item
);
62 static WMView
*W_TabViewItemView(WMTabViewItem
*item
);
64 static void recalcTabWidth(TabView
*tPtr
);
67 static void didResize(struct W_ViewDelegate
*, WMView
*);
69 static W_ViewDelegate delegate
= {
81 handleEvents(XEvent
*event
, void *data
)
83 TabView
*tPtr
= (TabView
*)data
;
85 CHECK_CLASS(data
, WC_TabView
);
87 switch (event
->type
) {
89 if (event
->xexpose
.count
!=0)
96 WMTabViewItem
*item
= WMTabViewItemAtPoint(tPtr
,
100 WMSelectTabViewItem(tPtr
, item
);
101 } else if (tPtr
->flags
.dontFitAll
) {
103 if (event
->xbutton
.x
< BUTTONED_SIDE_OFFSET
) {
104 if (tPtr
->firstVisible
> 0) {
106 tPtr
->firstVisible
--;
108 } else if (event
->xbutton
.x
- BUTTONED_SIDE_OFFSET
109 > tPtr
->visibleTabs
*(tPtr
->tabWidth
-10)) {
111 if (tPtr
->firstVisible
+ tPtr
->visibleTabs
114 tPtr
->firstVisible
++;
126 destroyTabView(tPtr
);
134 WMCreateTabView(WMWidget
*parent
)
137 WMScreen
*scr
= WMWidgetScreen(parent
);
139 tPtr
= wmalloc(sizeof(TabView
));
140 memset(tPtr
, 0, sizeof(TabView
));
142 tPtr
->widgetClass
= WC_TabView
;
144 tPtr
->view
= W_CreateView(W_VIEW(parent
));
149 tPtr
->view
->self
= tPtr
;
150 tPtr
->view
->delegate
= &delegate
;
152 tPtr
->lightGray
= WMCreateRGBColor(scr
, 0xd9d9, 0xd9d9, 0xd9d9, False
);
153 tPtr
->tabColor
= WMCreateRGBColor(scr
, 0x8420, 0x8420, 0x8420, False
);
155 tPtr
->font
= WMRetainFont(scr
->normalFont
);
157 WMCreateEventHandler(tPtr
->view
, ExposureMask
|StructureNotifyMask
158 |ButtonPressMask
, handleEvents
, tPtr
);
160 WMResizeWidget(tPtr
, DEFAULT_WIDTH
, DEFAULT_HEIGHT
);
162 tPtr
->tabHeight
= WMFontHeight(tPtr
->font
) + 3;
169 WMSetTabViewDelegate(WMTabView
*tPtr
, WMTabViewDelegate
*delegate
)
171 tPtr
->delegate
= delegate
;
176 WMAddTabViewItemWithView(WMTabView
*tPtr
, WMView
*view
, int identifier
,
181 item
= WMCreateTabViewItemWithIdentifier(identifier
);
182 WMSetTabViewItemView(item
, view
);
183 WMAddItemInTabView(tPtr
, item
);
184 WMSetTabViewItemLabel(item
, label
);
191 WMAddItemInTabView(WMTabView
*tPtr
, WMTabViewItem
*item
)
193 WMInsertItemInTabView(tPtr
, tPtr
->itemCount
, item
);
198 WMInsertItemInTabView(WMTabView
*tPtr
, int index
, WMTabViewItem
*item
)
200 wassertr(W_TabViewItemView(item
) != NULL
);
202 if (tPtr
->maxItems
== tPtr
->itemCount
) {
203 WMTabViewItem
**items
;
205 items
= wrealloc(tPtr
->items
,
206 sizeof(WMTabViewItem
*) * (tPtr
->maxItems
+ 10));
207 memset(&items
[tPtr
->maxItems
], 0, sizeof(WMTabViewItem
*) * 10);
209 tPtr
->maxItems
+= 10;
212 if (index
> tPtr
->itemCount
)
213 index
= tPtr
->itemCount
;
215 if (index
== 0 && tPtr
->items
[0]) {
216 W_UnmapTabViewItem(tPtr
->items
[0]);
219 if (index
< tPtr
->itemCount
) {
220 memmove(&tPtr
->items
[index
+ 1], &tPtr
->items
[index
],
221 tPtr
->itemCount
- index
);
224 tPtr
->items
[index
] = item
;
228 recalcTabWidth(tPtr
);
230 W_SetTabViewItemParent(item
, tPtr
);
232 W_UnmapTabViewItem(item
);
234 W_ReparentView(W_TabViewItemView(item
), tPtr
->view
, 1,
235 tPtr
->tabHeight
+ 1);
237 W_ResizeView(W_TabViewItemView(item
), tPtr
->view
->size
.width
- 3,
238 tPtr
->view
->size
.height
- tPtr
->tabHeight
- 3);
241 W_MapTabViewItem(item
);
243 if (tPtr
->delegate
&& tPtr
->delegate
->didChangeNumberOfItems
)
244 (*tPtr
->delegate
->didChangeNumberOfItems
)(tPtr
->delegate
, tPtr
);
249 WMRemoveTabViewItem(WMTabView
*tPtr
, WMTabViewItem
*item
)
253 for (i
= 0; i
< tPtr
->itemCount
; i
++) {
254 if (tPtr
->items
[i
] == item
) {
255 if (i
< tPtr
->itemCount
- 1)
256 memmove(&tPtr
->items
[i
], &tPtr
->items
[i
+ 1],
257 tPtr
->itemCount
- i
- 1);
259 tPtr
->items
[i
] = NULL
;
261 W_SetTabViewItemParent(item
, NULL
);
267 if (tPtr
->delegate
&& tPtr
->delegate
->didChangeNumberOfItems
)
268 (*tPtr
->delegate
->didChangeNumberOfItems
)(tPtr
->delegate
, tPtr
);
274 isInside(int x
, int y
, int width
, int height
, int px
, int py
)
276 if (py
>= y
+ height
- 3 && py
<= y
+ height
277 && px
>= x
+ py
- (y
+ height
- 3)
278 && px
<= x
+ width
- (py
- (y
+ height
- 3))) {
282 if (py
>= y
+ 3 && py
< y
+ height
- 3
283 && px
>= x
+ 3 + ((y
+ 3) - py
)*3/7
284 && px
<= x
+ width
- 3 - ((y
+ 3) - py
)*3/7) {
288 if (py
>= y
&& py
< y
+ 3
289 && px
>= x
+ 7 + py
- y
290 && px
<= x
+ width
- 7 - (py
- y
)) {
299 WMTabViewItemAtPoint(WMTabView
*tPtr
, int x
, int y
)
303 int count
= tPtr
->visibleTabs
;
304 int first
= tPtr
->firstVisible
;
306 if (tPtr
->flags
.dontFitAll
) {
307 offset
= BUTTONED_SIDE_OFFSET
;
309 i
= tPtr
->selectedItem
- tPtr
->firstVisible
;
310 if (i
>= 0 && i
< tPtr
->visibleTabs
311 && isInside(offset
+ (tPtr
->tabWidth
-10)*i
, 0, tPtr
->tabWidth
,
312 tPtr
->tabHeight
, x
, y
)) {
313 return tPtr
->items
[tPtr
->selectedItem
];
316 offset
= NORMAL_SIDE_OFFSET
;
318 i
= tPtr
->selectedItem
;
319 if (isInside(offset
+ (tPtr
->tabWidth
-10)*i
, 0, tPtr
->tabWidth
,
320 tPtr
->tabHeight
, x
, y
)) {
321 return tPtr
->items
[i
];
325 for (i
= 0; i
< count
; i
++) {
326 if (isInside(offset
+ (tPtr
->tabWidth
-10)*i
, 0, tPtr
->tabWidth
,
327 tPtr
->tabHeight
, x
, y
)) {
328 return tPtr
->items
[i
+first
];
336 WMSetTabViewType(WMTabView
*tPtr
, WMTabViewType type
)
338 tPtr
->flags
.type
= type
;
342 WMSelectFirstTabViewItem(WMTabView
*tPtr
)
344 WMSelectTabViewItemAtIndex(tPtr
, 0);
349 WMSelectLastTabViewItem(WMTabView
*tPtr
)
351 WMSelectTabViewItemAtIndex(tPtr
, tPtr
->itemCount
);
356 WMSelectNextTabViewItem(WMTabView
*tPtr
)
358 WMSelectTabViewItemAtIndex(tPtr
, tPtr
->selectedItem
+ 1);
363 WMSelectPreviousTabViewItem(WMTabView
*tPtr
)
365 WMSelectTabViewItemAtIndex(tPtr
, tPtr
->selectedItem
- 1);
370 WMGetSelectedTabViewItem(WMTabView
*tPtr
)
372 return tPtr
->items
[tPtr
->selectedItem
];
377 WMSelectTabViewItem(WMTabView
*tPtr
, WMTabViewItem
*item
)
381 for (i
= 0; i
< tPtr
->itemCount
; i
++) {
382 if (tPtr
->items
[i
] == item
) {
383 WMSelectTabViewItemAtIndex(tPtr
, i
);
391 WMSelectTabViewItemAtIndex(WMTabView
*tPtr
, int index
)
395 if (index
== tPtr
->selectedItem
) {
401 else if (index
>= tPtr
->itemCount
)
402 index
= tPtr
->itemCount
- 1;
404 item
= tPtr
->items
[tPtr
->selectedItem
];
406 if (tPtr
->delegate
&& tPtr
->delegate
->shouldSelectItem
)
407 if (!(*tPtr
->delegate
->shouldSelectItem
)(tPtr
->delegate
, tPtr
,
411 if (tPtr
->delegate
&& tPtr
->delegate
->willSelectItem
)
412 (*tPtr
->delegate
->willSelectItem
)(tPtr
->delegate
, tPtr
,
415 W_UnmapTabViewItem(item
);
418 item
= tPtr
->items
[index
];
420 W_MapTabViewItem(item
);
422 tPtr
->selectedItem
= index
;
424 if (tPtr
->delegate
&& tPtr
->delegate
->didSelectItem
)
425 (*tPtr
->delegate
->didSelectItem
)(tPtr
->delegate
, tPtr
,
433 recalcTabWidth(TabView
*tPtr
)
436 int twidth
= W_VIEW(tPtr
)->size
.width
;
440 for (i
= 0; i
< tPtr
->itemCount
; i
++) {
441 char *str
= WMGetTabViewItemLabel(tPtr
->items
[i
]);
444 width
= WMWidthOfString(tPtr
->font
, str
, strlen(str
));
445 if (width
> tPtr
->tabWidth
)
446 tPtr
->tabWidth
= width
;
449 tPtr
->tabWidth
+= 30;
450 if ((tPtr
->tabWidth
+ 2) * tPtr
->itemCount
> twidth
- 2*NORMAL_SIDE_OFFSET
) {
451 tPtr
->flags
.dontFitAll
= 1;
452 tPtr
->firstVisible
= 0;
453 tPtr
->visibleTabs
= (twidth
- 2*BUTTONED_SIDE_OFFSET
) / (tPtr
->tabWidth
-10);
455 tPtr
->flags
.dontFitAll
= 0;
456 tPtr
->firstVisible
= 0;
457 tPtr
->visibleTabs
= tPtr
->itemCount
;
463 drawRelief(W_Screen
*scr
, Drawable d
, int x
, int y
, unsigned int width
,
466 Display
*dpy
= scr
->display
;
467 GC bgc
= WMColorGC(scr
->black
);
468 GC wgc
= WMColorGC(scr
->white
);
469 GC dgc
= WMColorGC(scr
->darkGray
);
471 XDrawLine(dpy
, d
, wgc
, x
, y
, x
, y
+height
-1);
473 XDrawLine(dpy
, d
, bgc
, x
, y
+height
-1, x
+width
-1, y
+height
-1);
474 XDrawLine(dpy
, d
, dgc
, x
+1, y
+height
-2, x
+width
-2, y
+height
-2);
476 XDrawLine(dpy
, d
, bgc
, x
+width
-1, y
, x
+width
-1, y
+height
-1);
477 XDrawLine(dpy
, d
, dgc
, x
+width
-2, y
+1, x
+width
-2, y
+height
-2);
482 drawTab(TabView
*tPtr
, Drawable d
, int x
, int y
,
483 unsigned width
, unsigned height
, Bool selected
)
485 WMScreen
*scr
= W_VIEW(tPtr
)->screen
;
486 Display
*dpy
= scr
->display
;
487 GC white
= WMColorGC(selected
? scr
->white
: tPtr
->lightGray
);
488 GC black
= WMColorGC(scr
->black
);
489 GC dark
= WMColorGC(scr
->darkGray
);
490 GC light
= WMColorGC(scr
->gray
);
493 trap
[0].x
= x
+ (selected
? 0 : 1);
494 trap
[0].y
= y
+ height
- (selected
? 0 : 1);
497 trap
[1].y
= y
+ height
- 3;
499 trap
[2].x
= x
+ 10 - 3;
505 trap
[4].x
= x
+ width
- 10;
508 trap
[5].x
= x
+ width
- 10 + 3;
511 trap
[6].x
= x
+ width
- 3;
512 trap
[6].y
= y
+ height
- 3;
514 trap
[7].x
= x
+ width
- (selected
? 0 : 1);
515 trap
[7].y
= y
+ height
- (selected
? 0 : 1);
517 XFillPolygon(dpy
, d
, selected
? light
: WMColorGC(tPtr
->tabColor
), trap
, 8,
518 Convex
, CoordModeOrigin
);
520 XDrawLine(dpy
, d
, white
, trap
[0].x
, trap
[0].y
, trap
[1].x
, trap
[1].y
);
521 XDrawLine(dpy
, d
, white
, trap
[1].x
, trap
[1].y
, trap
[2].x
, trap
[2].y
);
522 XDrawLine(dpy
, d
, white
, trap
[2].x
, trap
[2].y
, trap
[3].x
, trap
[3].y
);
523 XDrawLine(dpy
, d
, white
, trap
[3].x
, trap
[3].y
, trap
[4].x
, trap
[4].y
);
524 XDrawLine(dpy
, d
, dark
, trap
[4].x
, trap
[4].y
, trap
[5].x
, trap
[5].y
);
525 XDrawLine(dpy
, d
, black
, trap
[5].x
, trap
[5].y
, trap
[6].x
, trap
[6].y
);
526 XDrawLine(dpy
, d
, black
, trap
[6].x
, trap
[6].y
, trap
[7].x
, trap
[7].y
);
528 XDrawLine(dpy
, d
, selected
? light
: WMColorGC(scr
->white
),
529 trap
[0].x
, trap
[0].y
, trap
[7].x
, trap
[7].y
);
534 paintDot(TabView
*tPtr
, Drawable d
, int x
, int y
)
536 WMScreen
*scr
= W_VIEW(tPtr
)->screen
;
537 Display
*dpy
= scr
->display
;
538 GC white
= WMColorGC(scr
->white
);
539 GC black
= WMColorGC(scr
->black
);
541 XFillRectangle(dpy
, d
, black
, x
, y
, 2, 2);
542 XDrawPoint(dpy
, d
, white
, x
, y
);
548 paintTabView(TabView
*tPtr
)
551 WMScreen
*scr
= W_VIEW(tPtr
)->screen
;
552 Display
*dpy
= scr
->display
;
553 GC white
= WMColorGC(scr
->white
);
557 if (tPtr
->flags
.type
== WTTopTabsBevelBorder
) {
558 int count
= tPtr
->visibleTabs
;
559 int first
= tPtr
->firstVisible
;
563 int selectedIsVisible
;
565 buffer
= XCreatePixmap(dpy
, W_VIEW(tPtr
)->window
,
566 W_VIEW(tPtr
)->size
.width
, tPtr
->tabHeight
,
567 W_VIEW(tPtr
)->screen
->depth
);
569 XFillRectangle(dpy
, buffer
, WMColorGC(W_VIEW(tPtr
)->backColor
),
570 0, 0, W_VIEW(tPtr
)->size
.width
, tPtr
->tabHeight
);
573 if (tPtr
->flags
.dontFitAll
) {
574 rect
.pos
.x
= 15 + BUTTONED_SIDE_OFFSET
;
575 offs
= BUTTONED_SIDE_OFFSET
;
576 moreAtLeft
= first
> 0;
577 moreAtRight
= (first
+ count
) < tPtr
->itemCount
;
578 if (tPtr
->selectedItem
>= first
579 && tPtr
->selectedItem
< first
+ count
)
580 selectedIsVisible
= 1;
582 selectedIsVisible
= 0;
584 rect
.pos
.x
= 15 + NORMAL_SIDE_OFFSET
;
585 offs
= NORMAL_SIDE_OFFSET
;
588 selectedIsVisible
= 1;
590 rect
.size
.width
= tPtr
->tabWidth
;
591 rect
.size
.height
= tPtr
->tabHeight
;
593 for (i
= count
- (moreAtRight
? 0 : 1);
594 i
>= (moreAtLeft
? -1 : 0); i
--) {
595 if (!selectedIsVisible
|| i
!= (tPtr
->selectedItem
-first
)) {
596 drawTab(tPtr
, buffer
, offs
+ (rect
.size
.width
-10)*i
, 0,
597 rect
.size
.width
, rect
.size
.height
, False
);
601 if (selectedIsVisible
) {
602 drawTab(tPtr
, buffer
,
603 offs
+ (rect
.size
.width
-10) * (tPtr
->selectedItem
- first
),
604 0, rect
.size
.width
, rect
.size
.height
, True
);
606 XDrawLine(dpy
, buffer
, white
, 0, tPtr
->tabHeight
- 1,
607 offs
, tPtr
->tabHeight
- 1);
609 XDrawLine(dpy
, buffer
, white
,
610 offs
+ 10 + (rect
.size
.width
-10) * count
,
611 tPtr
->tabHeight
- 1, W_VIEW(tPtr
)->size
.width
- 1,
612 tPtr
->tabHeight
- 1);
614 XDrawLine(dpy
, buffer
, white
, 0, tPtr
->tabHeight
- 1,
615 W_VIEW(tPtr
)->size
.width
, tPtr
->tabHeight
- 1);
618 for (i
= 0; i
< count
; i
++) {
619 W_DrawLabel(tPtr
->items
[first
+i
], buffer
, rect
);
621 rect
.pos
.x
+= rect
.size
.width
- 10;
625 paintDot(tPtr
, buffer
, 4, 10);
626 paintDot(tPtr
, buffer
, 7, 10);
627 paintDot(tPtr
, buffer
, 10, 10);
632 x
= BUTTONED_SIDE_OFFSET
- 5 + tPtr
->visibleTabs
* (tPtr
->tabWidth
- 10);
634 x
= x
+ (W_VIEW(tPtr
)->size
.width
- x
)/2;
636 paintDot(tPtr
, buffer
, x
+ 5, 10);
637 paintDot(tPtr
, buffer
, x
+ 8, 10);
638 paintDot(tPtr
, buffer
, x
+ 11, 10);
641 XCopyArea(dpy
, buffer
, W_VIEW(tPtr
)->window
, scr
->copyGC
, 0, 0,
642 W_VIEW(tPtr
)->size
.width
, tPtr
->tabHeight
, 0, 0);
644 XFreePixmap(dpy
, buffer
);
646 switch (tPtr
->flags
.type
) {
647 case WTTopTabsBevelBorder
:
648 drawRelief(scr
, W_VIEW(tPtr
)->window
, 0, tPtr
->tabHeight
- 1,
649 W_VIEW(tPtr
)->size
.width
,
650 W_VIEW(tPtr
)->size
.height
- tPtr
->tabHeight
+ 1);
653 case WTNoTabsBevelBorder
:
654 W_DrawRelief(scr
, W_VIEW(tPtr
)->window
, 0, 0, W_VIEW(tPtr
)->size
.width
,
655 W_VIEW(tPtr
)->size
.height
, WRRaised
);
658 case WTNoTabsLineBorder
:
659 W_DrawRelief(scr
, W_VIEW(tPtr
)->window
, 0, 0, W_VIEW(tPtr
)->size
.width
,
660 W_VIEW(tPtr
)->size
.height
, WRSimple
);
663 case WTNoTabsNoBorder
:
670 rearrange(TabView
*tPtr
)
675 recalcTabWidth(tPtr
);
677 width
= tPtr
->view
->size
.width
- 3;
678 height
= tPtr
->view
->size
.height
- tPtr
->tabHeight
- 3;
680 for (i
= 0; i
< tPtr
->itemCount
; i
++) {
681 W_ResizeView(W_TabViewItemView(tPtr
->items
[i
]), width
, height
);
683 if (W_VIEW_MAPPED(tPtr
->view
) && W_VIEW_REALIZED(tPtr
->view
))
689 didResize(struct W_ViewDelegate
*deleg
, WMView
*view
)
691 rearrange(view
->self
);
696 destroyTabView(TabView
*tPtr
)
700 for (i
= 0; i
< tPtr
->itemCount
; i
++) {
701 WMSetTabViewItemView(tPtr
->items
[i
], NULL
);
702 WMDestroyTabViewItem(tPtr
->items
[i
]);
706 WMReleaseColor(tPtr
->lightGray
);
707 WMReleaseColor(tPtr
->tabColor
);
708 WMReleaseFont(tPtr
->font
);
713 /******************************************************************/
716 typedef struct W_TabViewItem
{
732 W_SetTabViewItemParent(WMTabViewItem
*item
, WMTabView
*parent
)
734 item
->tabView
= parent
;
739 W_DrawLabel(WMTabViewItem
*item
, Drawable d
, WMRect rect
)
741 WMScreen
*scr
= W_VIEW(item
->tabView
)->screen
;
746 WMDrawString(scr
, d
, WMColorGC(scr
->black
), item
->tabView
->font
,
747 rect
.pos
.x
, rect
.pos
.y
, item
->label
, strlen(item
->label
));
752 W_UnmapTabViewItem(WMTabViewItem
*item
)
754 wassertr(item
->view
);
756 W_UnmapView(item
->view
);
758 item
->flags
.visible
= 0;
763 W_MapTabViewItem(WMTabViewItem
*item
)
765 wassertr(item
->view
);
767 W_MapView(item
->view
);
768 W_RaiseView(item
->view
);
770 item
->flags
.visible
= 1;
775 W_TabViewItemView(WMTabViewItem
*item
)
782 WMCreateTabViewItemWithIdentifier(int identifier
)
786 item
= wmalloc(sizeof(WMTabViewItem
));
787 memset(item
, 0, sizeof(WMTabViewItem
));
789 item
->identifier
= identifier
;
796 WMCreateTabViewItem(int identifier
, char *label
)
800 item
= wmalloc(sizeof(WMTabViewItem
));
801 memset(item
, 0, sizeof(WMTabViewItem
));
803 item
->identifier
= identifier
;
804 WMSetTabViewItemLabel(item
, label
);
812 WMGetTabViewItemIdentifier(WMTabViewItem
*item
)
814 return item
->identifier
;
819 WMSetTabViewFont(WMTabView
*tPtr
, WMFont
*font
)
822 WMReleaseFont(tPtr
->font
);
824 tPtr
->font
= WMRetainFont(font
);
825 tPtr
->tabHeight
= WMFontHeight(tPtr
->font
) + 3;
826 recalcTabWidth(tPtr
);
831 WMSetTabViewItemLabel(WMTabViewItem
*item
, char *label
)
836 item
->label
= wstrdup(label
);
839 recalcTabWidth(item
->tabView
);
844 WMGetTabViewItemLabel(WMTabViewItem
*item
)
851 WMSetTabViewItemView(WMTabViewItem
*item
, WMView
*view
)
858 WMGetTabViewItemView(WMTabViewItem
*item
)
865 WMDestroyTabViewItem(WMTabViewItem
*item
)
871 W_DestroyView(item
->view
);