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;
40 #define DEFAULT_WIDTH 40
41 #define DEFAULT_HEIGHT 40
43 #define NORMAL_SIDE_OFFSET 8
44 #define BUTTONED_SIDE_OFFSET 20
47 static void destroyTabView(TabView
*tPtr
);
48 static void paintTabView(TabView
*tPtr
);
51 static void W_SetTabViewItemParent(WMTabViewItem
*item
, WMTabView
*parent
);
53 static void W_DrawLabel(WMTabViewItem
*item
, Drawable d
, WMRect rect
);
55 static void W_UnmapTabViewItem(WMTabViewItem
*item
);
57 static void W_MapTabViewItem(WMTabViewItem
*item
);
59 static WMView
*W_TabViewItemView(WMTabViewItem
*item
);
61 static void recalcTabWidth(TabView
*tPtr
);
65 handleEvents(XEvent
*event
, void *data
)
67 TabView
*tPtr
= (TabView
*)data
;
69 CHECK_CLASS(data
, WC_TabView
);
71 switch (event
->type
) {
73 if (event
->xexpose
.count
!=0)
80 WMTabViewItem
*item
= WMTabViewItemAtPoint(tPtr
,
84 WMSelectTabViewItem(tPtr
, item
);
85 } else if (tPtr
->flags
.dontFitAll
) {
87 if (event
->xbutton
.x
< BUTTONED_SIDE_OFFSET
) {
88 if (tPtr
->firstVisible
> 0) {
92 } else if (event
->xbutton
.x
- BUTTONED_SIDE_OFFSET
93 > tPtr
->visibleTabs
*(tPtr
->tabWidth
-10)) {
95 if (tPtr
->firstVisible
+ tPtr
->visibleTabs
110 destroyTabView(tPtr
);
118 WMCreateTabView(WMWidget
*parent
)
121 WMScreen
*scr
= WMWidgetScreen(parent
);
123 tPtr
= wmalloc(sizeof(TabView
));
124 memset(tPtr
, 0, sizeof(TabView
));
126 tPtr
->widgetClass
= WC_TabView
;
128 tPtr
->view
= W_CreateView(W_VIEW(parent
));
133 tPtr
->view
->self
= tPtr
;
135 tPtr
->lightGray
= WMCreateRGBColor(scr
, 0xd9d9, 0xd9d9, 0xd9d9, False
);
136 tPtr
->tabColor
= WMCreateRGBColor(scr
, 0x8420, 0x8420, 0x8420, False
);
138 tPtr
->font
= WMRetainFont(scr
->normalFont
);
140 WMCreateEventHandler(tPtr
->view
, ExposureMask
|StructureNotifyMask
141 |ButtonPressMask
, handleEvents
, tPtr
);
143 WMResizeWidget(tPtr
, DEFAULT_WIDTH
, DEFAULT_HEIGHT
);
145 tPtr
->tabHeight
= WMFontHeight(tPtr
->font
) + 3;
152 WMSetTabViewDelegate(WMTabView
*tPtr
, WMTabViewDelegate
*delegate
)
154 tPtr
->delegate
= delegate
;
159 WMAddTabViewItemWithView(WMTabView
*tPtr
, WMView
*view
, int identifier
,
164 item
= WMCreateTabViewItemWithIdentifier(identifier
);
165 WMSetTabViewItemView(item
, view
);
166 WMAddItemInTabView(tPtr
, item
);
167 WMSetTabViewItemLabel(item
, label
);
174 WMAddItemInTabView(WMTabView
*tPtr
, WMTabViewItem
*item
)
176 WMInsertItemInTabView(tPtr
, tPtr
->itemCount
, item
);
181 WMInsertItemInTabView(WMTabView
*tPtr
, int index
, WMTabViewItem
*item
)
183 wassertr(W_TabViewItemView(item
) != NULL
);
185 if (tPtr
->maxItems
== tPtr
->itemCount
) {
186 WMTabViewItem
**items
;
188 items
= wrealloc(tPtr
->items
,
189 sizeof(WMTabViewItem
*) * (tPtr
->maxItems
+ 10));
190 memset(&items
[tPtr
->maxItems
], 0, sizeof(WMTabViewItem
*) * 10);
192 tPtr
->maxItems
+= 10;
195 if (index
> tPtr
->itemCount
)
196 index
= tPtr
->itemCount
;
198 if (index
== 0 && tPtr
->items
[0]) {
199 W_UnmapTabViewItem(tPtr
->items
[0]);
202 if (index
< tPtr
->itemCount
) {
203 memmove(&tPtr
->items
[index
+ 1], &tPtr
->items
[index
],
204 tPtr
->itemCount
- index
);
207 tPtr
->items
[index
] = item
;
211 recalcTabWidth(tPtr
);
213 W_SetTabViewItemParent(item
, tPtr
);
215 W_UnmapTabViewItem(item
);
217 W_ReparentView(W_TabViewItemView(item
), tPtr
->view
, 1,
218 tPtr
->tabHeight
+ 1);
220 W_ResizeView(W_TabViewItemView(item
), tPtr
->view
->size
.width
- 3,
221 tPtr
->view
->size
.height
- tPtr
->tabHeight
- 3);
224 W_MapTabViewItem(item
);
226 if (tPtr
->delegate
&& tPtr
->delegate
->didChangeNumberOfItems
)
227 (*tPtr
->delegate
->didChangeNumberOfItems
)(tPtr
->delegate
, tPtr
);
232 WMRemoveTabViewItem(WMTabView
*tPtr
, WMTabViewItem
*item
)
236 for (i
= 0; i
< tPtr
->itemCount
; i
++) {
237 if (tPtr
->items
[i
] == item
) {
238 if (i
< tPtr
->itemCount
- 1)
239 memmove(&tPtr
->items
[i
], &tPtr
->items
[i
+ 1],
240 tPtr
->itemCount
- i
- 1);
242 tPtr
->items
[i
] = NULL
;
244 W_SetTabViewItemParent(item
, NULL
);
250 if (tPtr
->delegate
&& tPtr
->delegate
->didChangeNumberOfItems
)
251 (*tPtr
->delegate
->didChangeNumberOfItems
)(tPtr
->delegate
, tPtr
);
257 isInside(int x
, int y
, int width
, int height
, int px
, int py
)
259 if (py
>= y
+ height
- 3 && py
<= y
+ height
260 && px
>= x
+ py
- (y
+ height
- 3)
261 && px
<= x
+ width
- (py
- (y
+ height
- 3))) {
265 if (py
>= y
+ 3 && py
< y
+ height
- 3
266 && px
>= x
+ 3 + ((y
+ 3) - py
)*3/7
267 && px
<= x
+ width
- 3 - ((y
+ 3) - py
)*3/7) {
271 if (py
>= y
&& py
< y
+ 3
272 && px
>= x
+ 7 + py
- y
273 && px
<= x
+ width
- 7 - (py
- y
)) {
282 WMTabViewItemAtPoint(WMTabView
*tPtr
, int x
, int y
)
286 int count
= tPtr
->visibleTabs
;
287 int first
= tPtr
->firstVisible
;
289 if (tPtr
->flags
.dontFitAll
) {
290 offset
= BUTTONED_SIDE_OFFSET
;
292 i
= tPtr
->selectedItem
- tPtr
->firstVisible
;
293 if (i
>= 0 && i
< tPtr
->visibleTabs
294 && isInside(offset
+ (tPtr
->tabWidth
-10)*i
, 0, tPtr
->tabWidth
,
295 tPtr
->tabHeight
, x
, y
)) {
296 return tPtr
->items
[tPtr
->selectedItem
];
299 offset
= NORMAL_SIDE_OFFSET
;
301 i
= tPtr
->selectedItem
;
302 if (isInside(offset
+ (tPtr
->tabWidth
-10)*i
, 0, tPtr
->tabWidth
,
303 tPtr
->tabHeight
, x
, y
)) {
304 return tPtr
->items
[i
];
308 for (i
= 0; i
< count
; i
++) {
309 if (isInside(offset
+ (tPtr
->tabWidth
-10)*i
, 0, tPtr
->tabWidth
,
310 tPtr
->tabHeight
, x
, y
)) {
311 return tPtr
->items
[i
+first
];
319 WMSelectFirstTabViewItem(WMTabView
*tPtr
)
321 WMSelectTabViewItemAtIndex(tPtr
, 0);
326 WMSelectLastTabViewItem(WMTabView
*tPtr
)
328 WMSelectTabViewItemAtIndex(tPtr
, tPtr
->itemCount
);
333 WMSelectNextTabViewItem(WMTabView
*tPtr
)
335 WMSelectTabViewItemAtIndex(tPtr
, tPtr
->selectedItem
+ 1);
340 WMSelectPreviousTabViewItem(WMTabView
*tPtr
)
342 WMSelectTabViewItemAtIndex(tPtr
, tPtr
->selectedItem
- 1);
347 WMGetSelectedTabViewItem(WMTabView
*tPtr
)
349 return tPtr
->items
[tPtr
->selectedItem
];
354 WMSelectTabViewItem(WMTabView
*tPtr
, WMTabViewItem
*item
)
358 for (i
= 0; i
< tPtr
->itemCount
; i
++) {
359 if (tPtr
->items
[i
] == item
) {
360 WMSelectTabViewItemAtIndex(tPtr
, i
);
368 WMSelectTabViewItemAtIndex(WMTabView
*tPtr
, int index
)
372 if (index
== tPtr
->selectedItem
)
377 else if (index
>= tPtr
->itemCount
)
378 index
= tPtr
->itemCount
- 1;
380 item
= tPtr
->items
[tPtr
->selectedItem
];
382 if (tPtr
->delegate
&& tPtr
->delegate
->shouldSelectItem
)
383 if (!(*tPtr
->delegate
->shouldSelectItem
)(tPtr
->delegate
, tPtr
,
387 if (tPtr
->delegate
&& tPtr
->delegate
->willSelectItem
)
388 (*tPtr
->delegate
->willSelectItem
)(tPtr
->delegate
, tPtr
,
391 W_UnmapTabViewItem(item
);
394 item
= tPtr
->items
[index
];
396 W_MapTabViewItem(item
);
398 tPtr
->selectedItem
= index
;
400 if (tPtr
->delegate
&& tPtr
->delegate
->didSelectItem
)
401 (*tPtr
->delegate
->didSelectItem
)(tPtr
->delegate
, tPtr
,
407 recalcTabWidth(TabView
*tPtr
)
410 int twidth
= W_VIEW(tPtr
)->size
.width
;
414 for (i
= 0; i
< tPtr
->itemCount
; i
++) {
415 char *str
= WMGetTabViewItemLabel(tPtr
->items
[i
]);
418 width
= WMWidthOfString(tPtr
->font
, str
, strlen(str
));
419 if (width
> tPtr
->tabWidth
)
420 tPtr
->tabWidth
= width
;
423 tPtr
->tabWidth
+= 30;
424 if ((tPtr
->tabWidth
+ 2) * tPtr
->itemCount
> twidth
- 2*NORMAL_SIDE_OFFSET
) {
425 tPtr
->flags
.dontFitAll
= 1;
426 tPtr
->firstVisible
= 0;
427 tPtr
->visibleTabs
= (twidth
- 2*BUTTONED_SIDE_OFFSET
) / (tPtr
->tabWidth
-10);
429 tPtr
->flags
.dontFitAll
= 0;
430 tPtr
->firstVisible
= 0;
431 tPtr
->visibleTabs
= tPtr
->itemCount
;
437 drawRelief(W_Screen
*scr
, Drawable d
, int x
, int y
, unsigned int width
,
440 Display
*dpy
= scr
->display
;
441 GC bgc
= WMColorGC(scr
->black
);
442 GC wgc
= WMColorGC(scr
->white
);
443 GC dgc
= WMColorGC(scr
->darkGray
);
445 XDrawLine(dpy
, d
, wgc
, x
, y
, x
, y
+height
-1);
447 XDrawLine(dpy
, d
, bgc
, x
, y
+height
-1, x
+width
-1, y
+height
-1);
448 XDrawLine(dpy
, d
, dgc
, x
+1, y
+height
-2, x
+width
-2, y
+height
-2);
450 XDrawLine(dpy
, d
, bgc
, x
+width
-1, y
, x
+width
-1, y
+height
-1);
451 XDrawLine(dpy
, d
, dgc
, x
+width
-2, y
+1, x
+width
-2, y
+height
-2);
456 drawTab(TabView
*tPtr
, Drawable d
, int x
, int y
,
457 unsigned width
, unsigned height
, Bool selected
)
459 WMScreen
*scr
= W_VIEW(tPtr
)->screen
;
460 Display
*dpy
= scr
->display
;
461 GC white
= WMColorGC(selected
? scr
->white
: tPtr
->lightGray
);
462 GC black
= WMColorGC(scr
->black
);
463 GC dark
= WMColorGC(scr
->darkGray
);
464 GC light
= WMColorGC(scr
->gray
);
467 trap
[0].x
= x
+ (selected
? 0 : 1);
468 trap
[0].y
= y
+ height
- (selected
? 0 : 1);
471 trap
[1].y
= y
+ height
- 3;
473 trap
[2].x
= x
+ 10 - 3;
479 trap
[4].x
= x
+ width
- 10;
482 trap
[5].x
= x
+ width
- 10 + 3;
485 trap
[6].x
= x
+ width
- 3;
486 trap
[6].y
= y
+ height
- 3;
488 trap
[7].x
= x
+ width
- (selected
? 0 : 1);
489 trap
[7].y
= y
+ height
- (selected
? 0 : 1);
491 XFillPolygon(dpy
, d
, selected
? light
: WMColorGC(tPtr
->tabColor
), trap
, 8,
492 Convex
, CoordModeOrigin
);
494 XDrawLine(dpy
, d
, white
, trap
[0].x
, trap
[0].y
, trap
[1].x
, trap
[1].y
);
495 XDrawLine(dpy
, d
, white
, trap
[1].x
, trap
[1].y
, trap
[2].x
, trap
[2].y
);
496 XDrawLine(dpy
, d
, white
, trap
[2].x
, trap
[2].y
, trap
[3].x
, trap
[3].y
);
497 XDrawLine(dpy
, d
, white
, trap
[3].x
, trap
[3].y
, trap
[4].x
, trap
[4].y
);
498 XDrawLine(dpy
, d
, dark
, trap
[4].x
, trap
[4].y
, trap
[5].x
, trap
[5].y
);
499 XDrawLine(dpy
, d
, black
, trap
[5].x
, trap
[5].y
, trap
[6].x
, trap
[6].y
);
500 XDrawLine(dpy
, d
, black
, trap
[6].x
, trap
[6].y
, trap
[7].x
, trap
[7].y
);
502 XDrawLine(dpy
, d
, selected
? light
: WMColorGC(scr
->white
),
503 trap
[0].x
, trap
[0].y
, trap
[7].x
, trap
[7].y
);
508 paintDot(TabView
*tPtr
, Drawable d
, int x
, int y
)
510 WMScreen
*scr
= W_VIEW(tPtr
)->screen
;
511 Display
*dpy
= scr
->display
;
512 GC white
= WMColorGC(scr
->white
);
513 GC black
= WMColorGC(scr
->black
);
515 XFillRectangle(dpy
, d
, black
, x
, y
, 2, 2);
516 XDrawPoint(dpy
, d
, white
, x
, y
);
522 paintTabView(TabView
*tPtr
)
525 WMScreen
*scr
= W_VIEW(tPtr
)->screen
;
526 Display
*dpy
= scr
->display
;
527 GC white
= WMColorGC(scr
->white
);
531 if (tPtr
->flags
.type
== WTTopTabsBevelBorder
) {
532 int count
= tPtr
->visibleTabs
;
533 int first
= tPtr
->firstVisible
;
537 int selectedIsVisible
;
539 buffer
= XCreatePixmap(dpy
, W_VIEW(tPtr
)->window
,
540 W_VIEW(tPtr
)->size
.width
, tPtr
->tabHeight
,
541 W_VIEW(tPtr
)->screen
->depth
);
543 XFillRectangle(dpy
, buffer
, WMColorGC(W_VIEW(tPtr
)->backColor
),
544 0, 0, W_VIEW(tPtr
)->size
.width
, tPtr
->tabHeight
);
547 if (tPtr
->flags
.dontFitAll
) {
548 rect
.pos
.x
= 15 + BUTTONED_SIDE_OFFSET
;
549 offs
= BUTTONED_SIDE_OFFSET
;
550 moreAtLeft
= first
> 0;
551 moreAtRight
= (first
+ count
) < tPtr
->itemCount
;
552 if (tPtr
->selectedItem
>= first
553 && tPtr
->selectedItem
< first
+ count
)
554 selectedIsVisible
= 1;
556 selectedIsVisible
= 0;
558 rect
.pos
.x
= 15 + NORMAL_SIDE_OFFSET
;
559 offs
= NORMAL_SIDE_OFFSET
;
562 selectedIsVisible
= 1;
564 rect
.size
.width
= tPtr
->tabWidth
;
565 rect
.size
.height
= tPtr
->tabHeight
;
567 for (i
= count
- (moreAtRight
? 0 : 1);
568 i
>= (moreAtLeft
? -1 : 0); i
--) {
569 if (!selectedIsVisible
|| i
!= (tPtr
->selectedItem
-first
)) {
570 drawTab(tPtr
, buffer
, offs
+ (rect
.size
.width
-10)*i
, 0,
571 rect
.size
.width
, rect
.size
.height
, False
);
575 if (selectedIsVisible
) {
576 drawTab(tPtr
, buffer
,
577 offs
+ (rect
.size
.width
-10) * (tPtr
->selectedItem
- first
),
578 0, rect
.size
.width
, rect
.size
.height
, True
);
580 XDrawLine(dpy
, buffer
, white
, 0, tPtr
->tabHeight
- 1,
581 offs
, tPtr
->tabHeight
- 1);
583 XDrawLine(dpy
, buffer
, white
,
584 offs
+ 10 + (rect
.size
.width
-10) * count
,
585 tPtr
->tabHeight
- 1, W_VIEW(tPtr
)->size
.width
- 1,
586 tPtr
->tabHeight
- 1);
588 XDrawLine(dpy
, buffer
, white
, 0, tPtr
->tabHeight
- 1,
589 W_VIEW(tPtr
)->size
.width
, tPtr
->tabHeight
- 1);
592 for (i
= 0; i
< count
; i
++) {
593 W_DrawLabel(tPtr
->items
[first
+i
], buffer
, rect
);
595 rect
.pos
.x
+= rect
.size
.width
- 10;
599 paintDot(tPtr
, buffer
, 4, 10);
600 paintDot(tPtr
, buffer
, 7, 10);
601 paintDot(tPtr
, buffer
, 10, 10);
606 x
= BUTTONED_SIDE_OFFSET
- 5 + tPtr
->visibleTabs
* (tPtr
->tabWidth
- 10);
608 x
= x
+ (W_VIEW(tPtr
)->size
.width
- x
)/2;
610 paintDot(tPtr
, buffer
, x
+ 5, 10);
611 paintDot(tPtr
, buffer
, x
+ 8, 10);
612 paintDot(tPtr
, buffer
, x
+ 11, 10);
615 XCopyArea(dpy
, buffer
, W_VIEW(tPtr
)->window
, scr
->copyGC
, 0, 0,
616 W_VIEW(tPtr
)->size
.width
, tPtr
->tabHeight
, 0, 0);
618 XFreePixmap(dpy
, buffer
);
620 switch (tPtr
->flags
.type
) {
621 case WTTopTabsBevelBorder
:
622 drawRelief(scr
, W_VIEW(tPtr
)->window
, 0, tPtr
->tabHeight
- 1,
623 W_VIEW(tPtr
)->size
.width
,
624 W_VIEW(tPtr
)->size
.height
- tPtr
->tabHeight
+ 1);
627 case WTNoTabsBevelBorder
:
628 W_DrawRelief(scr
, W_VIEW(tPtr
)->window
, 0, 0, W_VIEW(tPtr
)->size
.width
,
629 W_VIEW(tPtr
)->size
.height
, WRRaised
);
632 case WTNoTabsLineBorder
:
633 W_DrawRelief(scr
, W_VIEW(tPtr
)->window
, 0, 0, W_VIEW(tPtr
)->size
.width
,
634 W_VIEW(tPtr
)->size
.height
, WRSimple
);
637 case WTNoTabsNoBorder
:
644 destroyTabView(TabView
*tPtr
)
648 for (i
= 0; i
< tPtr
->itemCount
; i
++) {
649 WMSetTabViewItemView(tPtr
->items
[i
], NULL
);
650 WMDestroyTabViewItem(tPtr
->items
[i
]);
654 WMReleaseColor(tPtr
->lightGray
);
655 WMReleaseColor(tPtr
->tabColor
);
656 WMReleaseFont(tPtr
->font
);
661 /******************************************************************/
664 typedef struct W_TabViewItem
{
680 W_SetTabViewItemParent(WMTabViewItem
*item
, WMTabView
*parent
)
682 item
->tabView
= parent
;
687 W_DrawLabel(WMTabViewItem
*item
, Drawable d
, WMRect rect
)
689 WMScreen
*scr
= W_VIEW(item
->tabView
)->screen
;
694 WMDrawString(scr
, d
, WMColorGC(scr
->black
), item
->tabView
->font
,
695 rect
.pos
.x
, rect
.pos
.y
, item
->label
, strlen(item
->label
));
700 W_UnmapTabViewItem(WMTabViewItem
*item
)
702 wassertr(item
->view
);
704 W_UnmapView(item
->view
);
706 item
->flags
.visible
= 0;
711 W_MapTabViewItem(WMTabViewItem
*item
)
713 wassertr(item
->view
);
715 W_MapView(item
->view
);
717 item
->flags
.visible
= 1;
722 W_TabViewItemView(WMTabViewItem
*item
)
729 WMCreateTabViewItemWithIdentifier(int identifier
)
733 item
= wmalloc(sizeof(WMTabViewItem
));
734 memset(item
, 0, sizeof(WMTabViewItem
));
736 item
->identifier
= identifier
;
743 WMCreateTabViewItem(int identifier
, char *label
)
747 item
= wmalloc(sizeof(WMTabViewItem
));
748 memset(item
, 0, sizeof(WMTabViewItem
));
750 item
->identifier
= identifier
;
751 WMSetTabViewItemLabel(item
, label
);
759 WMGetTabViewItemIdentifier(WMTabViewItem
*item
)
761 return item
->identifier
;
766 WMSetTabViewFont(WMTabView
*tPtr
, WMFont
*font
)
769 WMReleaseFont(tPtr
->font
);
771 tPtr
->font
= WMRetainFont(font
);
772 tPtr
->tabHeight
= WMFontHeight(tPtr
->font
) + 3;
773 recalcTabWidth(tPtr
);
778 WMSetTabViewItemLabel(WMTabViewItem
*item
, char *label
)
783 item
->label
= wstrdup(label
);
786 recalcTabWidth(item
->tabView
);
791 WMGetTabViewItemLabel(WMTabViewItem
*item
)
798 WMSetTabViewItemView(WMTabViewItem
*item
, WMView
*view
)
805 WMGetTabViewItemView(WMTabViewItem
*item
)
812 WMDestroyTabViewItem(WMTabViewItem
*item
)
818 W_DestroyView(item
->view
);