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 WMAddItemInTabView(WMTabView
*tPtr
, WMTabViewItem
*item
)
161 WMInsertItemInTabView(tPtr
, tPtr
->itemCount
, item
);
166 WMInsertItemInTabView(WMTabView
*tPtr
, int index
, WMTabViewItem
*item
)
168 wassertr(W_TabViewItemView(item
) != NULL
);
170 if (tPtr
->maxItems
== tPtr
->itemCount
) {
171 WMTabViewItem
**items
;
173 items
= wrealloc(tPtr
->items
,
174 sizeof(WMTabViewItem
*) * (tPtr
->maxItems
+ 10));
175 memset(&items
[tPtr
->maxItems
], 0, sizeof(WMTabViewItem
*) * 10);
177 tPtr
->maxItems
+= 10;
180 if (index
> tPtr
->itemCount
)
181 index
= tPtr
->itemCount
;
183 if (index
== 0 && tPtr
->items
[0]) {
184 W_UnmapTabViewItem(tPtr
->items
[0]);
187 if (index
< tPtr
->itemCount
) {
188 memmove(&tPtr
->items
[index
+ 1], &tPtr
->items
[index
],
189 tPtr
->itemCount
- index
);
192 tPtr
->items
[index
] = item
;
196 recalcTabWidth(tPtr
);
198 W_SetTabViewItemParent(item
, tPtr
);
200 W_UnmapTabViewItem(item
);
202 W_ReparentView(W_TabViewItemView(item
), tPtr
->view
, 1,
203 tPtr
->tabHeight
+ 1);
205 W_ResizeView(W_TabViewItemView(item
), tPtr
->view
->size
.width
- 3,
206 tPtr
->view
->size
.height
- tPtr
->tabHeight
- 3);
209 W_MapTabViewItem(item
);
211 if (tPtr
->delegate
&& tPtr
->delegate
->didChangeNumberOfItems
)
212 (*tPtr
->delegate
->didChangeNumberOfItems
)(tPtr
->delegate
, tPtr
);
217 WMRemoveTabViewItem(WMTabView
*tPtr
, WMTabViewItem
*item
)
221 for (i
= 0; i
< tPtr
->itemCount
; i
++) {
222 if (tPtr
->items
[i
] == item
) {
223 if (i
< tPtr
->itemCount
- 1)
224 memmove(&tPtr
->items
[i
], &tPtr
->items
[i
+ 1],
225 tPtr
->itemCount
- i
- 1);
227 tPtr
->items
[i
] = NULL
;
229 W_SetTabViewItemParent(item
, NULL
);
235 if (tPtr
->delegate
&& tPtr
->delegate
->didChangeNumberOfItems
)
236 (*tPtr
->delegate
->didChangeNumberOfItems
)(tPtr
->delegate
, tPtr
);
242 isInside(int x
, int y
, int width
, int height
, int px
, int py
)
244 if (py
>= y
+ height
- 3 && py
<= y
+ height
245 && px
>= x
+ py
- (y
+ height
- 3)
246 && px
<= x
+ width
- (py
- (y
+ height
- 3))) {
250 if (py
>= y
+ 3 && py
< y
+ height
- 3
251 && px
>= x
+ 3 + ((y
+ 3) - py
)*3/7
252 && px
<= x
+ width
- 3 - ((y
+ 3) - py
)*3/7) {
256 if (py
>= y
&& py
< y
+ 3
257 && px
>= x
+ 7 + py
- y
258 && px
<= x
+ width
- 7 - (py
- y
)) {
267 WMTabViewItemAtPoint(WMTabView
*tPtr
, int x
, int y
)
271 int count
= tPtr
->visibleTabs
;
272 int first
= tPtr
->firstVisible
;
274 if (tPtr
->flags
.dontFitAll
) {
275 offset
= BUTTONED_SIDE_OFFSET
;
277 i
= tPtr
->selectedItem
- tPtr
->firstVisible
;
278 if (i
>= 0 && i
< tPtr
->visibleTabs
279 && isInside(offset
+ (tPtr
->tabWidth
-10)*i
, 0, tPtr
->tabWidth
,
280 tPtr
->tabHeight
, x
, y
)) {
281 return tPtr
->items
[tPtr
->selectedItem
];
284 offset
= NORMAL_SIDE_OFFSET
;
286 i
= tPtr
->selectedItem
;
287 if (isInside(offset
+ (tPtr
->tabWidth
-10)*i
, 0, tPtr
->tabWidth
,
288 tPtr
->tabHeight
, x
, y
)) {
289 return tPtr
->items
[i
];
293 for (i
= 0; i
< count
; i
++) {
294 if (isInside(offset
+ (tPtr
->tabWidth
-10)*i
, 0, tPtr
->tabWidth
,
295 tPtr
->tabHeight
, x
, y
)) {
296 return tPtr
->items
[i
+first
];
304 WMSelectFirstTabViewItem(WMTabView
*tPtr
)
306 WMSelectTabViewItemAtIndex(tPtr
, 0);
311 WMSelectLastTabViewItem(WMTabView
*tPtr
)
313 WMSelectTabViewItemAtIndex(tPtr
, tPtr
->itemCount
);
318 WMSelectNextTabViewItem(WMTabView
*tPtr
)
320 WMSelectTabViewItemAtIndex(tPtr
, tPtr
->selectedItem
+ 1);
325 WMSelectPreviousTabViewItem(WMTabView
*tPtr
)
327 WMSelectTabViewItemAtIndex(tPtr
, tPtr
->selectedItem
- 1);
332 WMGetSelectedTabViewItem(WMTabView
*tPtr
)
334 return tPtr
->items
[tPtr
->selectedItem
];
339 WMSelectTabViewItem(WMTabView
*tPtr
, WMTabViewItem
*item
)
343 for (i
= 0; i
< tPtr
->itemCount
; i
++) {
344 if (tPtr
->items
[i
] == item
) {
345 WMSelectTabViewItemAtIndex(tPtr
, i
);
353 WMSelectTabViewItemAtIndex(WMTabView
*tPtr
, int index
)
357 if (index
== tPtr
->selectedItem
)
362 else if (index
>= tPtr
->itemCount
)
363 index
= tPtr
->itemCount
- 1;
365 item
= tPtr
->items
[tPtr
->selectedItem
];
367 if (tPtr
->delegate
&& tPtr
->delegate
->shouldSelectItem
)
368 if (!(*tPtr
->delegate
->shouldSelectItem
)(tPtr
->delegate
, tPtr
,
372 if (tPtr
->delegate
&& tPtr
->delegate
->willSelectItem
)
373 (*tPtr
->delegate
->willSelectItem
)(tPtr
->delegate
, tPtr
,
376 W_UnmapTabViewItem(item
);
379 item
= tPtr
->items
[index
];
381 W_MapTabViewItem(item
);
383 tPtr
->selectedItem
= index
;
385 if (tPtr
->delegate
&& tPtr
->delegate
->didSelectItem
)
386 (*tPtr
->delegate
->didSelectItem
)(tPtr
->delegate
, tPtr
,
392 recalcTabWidth(TabView
*tPtr
)
395 int twidth
= W_VIEW(tPtr
)->size
.width
;
399 for (i
= 0; i
< tPtr
->itemCount
; i
++) {
400 char *str
= WMGetTabViewItemLabel(tPtr
->items
[i
]);
403 width
= WMWidthOfString(tPtr
->font
, str
, strlen(str
));
404 if (width
> tPtr
->tabWidth
)
405 tPtr
->tabWidth
= width
;
408 tPtr
->tabWidth
+= 30;
409 if ((tPtr
->tabWidth
+ 2) * tPtr
->itemCount
> twidth
- 2*NORMAL_SIDE_OFFSET
) {
410 tPtr
->flags
.dontFitAll
= 1;
411 tPtr
->firstVisible
= 0;
412 tPtr
->visibleTabs
= (twidth
- 2*BUTTONED_SIDE_OFFSET
) / (tPtr
->tabWidth
-10);
414 tPtr
->flags
.dontFitAll
= 0;
415 tPtr
->firstVisible
= 0;
416 tPtr
->visibleTabs
= tPtr
->itemCount
;
422 drawRelief(W_Screen
*scr
, Drawable d
, int x
, int y
, unsigned int width
,
425 Display
*dpy
= scr
->display
;
426 GC bgc
= WMColorGC(scr
->black
);
427 GC wgc
= WMColorGC(scr
->white
);
428 GC dgc
= WMColorGC(scr
->darkGray
);
430 XDrawLine(dpy
, d
, wgc
, x
, y
, x
, y
+height
-1);
432 XDrawLine(dpy
, d
, bgc
, x
, y
+height
-1, x
+width
-1, y
+height
-1);
433 XDrawLine(dpy
, d
, dgc
, x
+1, y
+height
-2, x
+width
-2, y
+height
-2);
435 XDrawLine(dpy
, d
, bgc
, x
+width
-1, y
, x
+width
-1, y
+height
-1);
436 XDrawLine(dpy
, d
, dgc
, x
+width
-2, y
+1, x
+width
-2, y
+height
-2);
441 drawTab(TabView
*tPtr
, Drawable d
, int x
, int y
,
442 unsigned width
, unsigned height
, Bool selected
)
444 WMScreen
*scr
= W_VIEW(tPtr
)->screen
;
445 Display
*dpy
= scr
->display
;
446 GC white
= WMColorGC(selected
? scr
->white
: tPtr
->lightGray
);
447 GC black
= WMColorGC(scr
->black
);
448 GC dark
= WMColorGC(scr
->darkGray
);
449 GC light
= WMColorGC(scr
->gray
);
452 trap
[0].x
= x
+ (selected
? 0 : 1);
453 trap
[0].y
= y
+ height
- (selected
? 0 : 1);
456 trap
[1].y
= y
+ height
- 3;
458 trap
[2].x
= x
+ 10 - 3;
464 trap
[4].x
= x
+ width
- 10;
467 trap
[5].x
= x
+ width
- 10 + 3;
470 trap
[6].x
= x
+ width
- 3;
471 trap
[6].y
= y
+ height
- 3;
473 trap
[7].x
= x
+ width
- (selected
? 0 : 1);
474 trap
[7].y
= y
+ height
- (selected
? 0 : 1);
476 XFillPolygon(dpy
, d
, selected
? light
: WMColorGC(tPtr
->tabColor
), trap
, 8,
477 Convex
, CoordModeOrigin
);
479 XDrawLine(dpy
, d
, white
, trap
[0].x
, trap
[0].y
, trap
[1].x
, trap
[1].y
);
480 XDrawLine(dpy
, d
, white
, trap
[1].x
, trap
[1].y
, trap
[2].x
, trap
[2].y
);
481 XDrawLine(dpy
, d
, white
, trap
[2].x
, trap
[2].y
, trap
[3].x
, trap
[3].y
);
482 XDrawLine(dpy
, d
, white
, trap
[3].x
, trap
[3].y
, trap
[4].x
, trap
[4].y
);
483 XDrawLine(dpy
, d
, dark
, trap
[4].x
, trap
[4].y
, trap
[5].x
, trap
[5].y
);
484 XDrawLine(dpy
, d
, black
, trap
[5].x
, trap
[5].y
, trap
[6].x
, trap
[6].y
);
485 XDrawLine(dpy
, d
, black
, trap
[6].x
, trap
[6].y
, trap
[7].x
, trap
[7].y
);
487 XDrawLine(dpy
, d
, selected
? light
: WMColorGC(scr
->white
),
488 trap
[0].x
, trap
[0].y
, trap
[7].x
, trap
[7].y
);
493 paintDot(TabView
*tPtr
, Drawable d
, int x
, int y
)
495 WMScreen
*scr
= W_VIEW(tPtr
)->screen
;
496 Display
*dpy
= scr
->display
;
497 GC white
= WMColorGC(scr
->white
);
498 GC black
= WMColorGC(scr
->black
);
500 XFillRectangle(dpy
, d
, black
, x
, y
, 2, 2);
501 XDrawPoint(dpy
, d
, white
, x
, y
);
507 paintTabView(TabView
*tPtr
)
510 WMScreen
*scr
= W_VIEW(tPtr
)->screen
;
511 Display
*dpy
= scr
->display
;
512 GC white
= WMColorGC(scr
->white
);
516 if (tPtr
->flags
.type
== WTTopTabsBevelBorder
) {
517 int count
= tPtr
->visibleTabs
;
518 int first
= tPtr
->firstVisible
;
522 int selectedIsVisible
;
524 buffer
= XCreatePixmap(dpy
, W_VIEW(tPtr
)->window
,
525 W_VIEW(tPtr
)->size
.width
, tPtr
->tabHeight
,
526 W_VIEW(tPtr
)->screen
->depth
);
528 XFillRectangle(dpy
, buffer
, WMColorGC(W_VIEW(tPtr
)->backColor
),
529 0, 0, W_VIEW(tPtr
)->size
.width
, tPtr
->tabHeight
);
532 if (tPtr
->flags
.dontFitAll
) {
533 rect
.pos
.x
= 15 + BUTTONED_SIDE_OFFSET
;
534 offs
= BUTTONED_SIDE_OFFSET
;
535 moreAtLeft
= first
> 0;
536 moreAtRight
= (first
+ count
) < tPtr
->itemCount
;
537 if (tPtr
->selectedItem
>= first
538 && tPtr
->selectedItem
< first
+ count
)
539 selectedIsVisible
= 1;
541 selectedIsVisible
= 0;
543 rect
.pos
.x
= 15 + NORMAL_SIDE_OFFSET
;
544 offs
= NORMAL_SIDE_OFFSET
;
547 selectedIsVisible
= 1;
549 rect
.size
.width
= tPtr
->tabWidth
;
550 rect
.size
.height
= tPtr
->tabHeight
;
552 for (i
= count
- (moreAtRight
? 0 : 1);
553 i
>= (moreAtLeft
? -1 : 0); i
--) {
554 if (!selectedIsVisible
|| i
!= (tPtr
->selectedItem
-first
)) {
555 drawTab(tPtr
, buffer
, offs
+ (rect
.size
.width
-10)*i
, 0,
556 rect
.size
.width
, rect
.size
.height
, False
);
560 if (selectedIsVisible
) {
561 drawTab(tPtr
, buffer
,
562 offs
+ (rect
.size
.width
-10) * (tPtr
->selectedItem
- first
),
563 0, rect
.size
.width
, rect
.size
.height
, True
);
565 XDrawLine(dpy
, buffer
, white
, 0, tPtr
->tabHeight
- 1,
566 offs
, tPtr
->tabHeight
- 1);
568 XDrawLine(dpy
, buffer
, white
,
569 offs
+ 10 + (rect
.size
.width
-10) * count
,
570 tPtr
->tabHeight
- 1, W_VIEW(tPtr
)->size
.width
- 1,
571 tPtr
->tabHeight
- 1);
573 XDrawLine(dpy
, buffer
, white
, 0, tPtr
->tabHeight
- 1,
574 W_VIEW(tPtr
)->size
.width
, tPtr
->tabHeight
- 1);
577 for (i
= 0; i
< count
; i
++) {
578 W_DrawLabel(tPtr
->items
[first
+i
], buffer
, rect
);
580 rect
.pos
.x
+= rect
.size
.width
- 10;
584 paintDot(tPtr
, buffer
, 4, 10);
585 paintDot(tPtr
, buffer
, 7, 10);
586 paintDot(tPtr
, buffer
, 10, 10);
591 x
= BUTTONED_SIDE_OFFSET
- 5 + tPtr
->visibleTabs
* (tPtr
->tabWidth
- 10);
593 x
= x
+ (W_VIEW(tPtr
)->size
.width
- x
)/2;
595 paintDot(tPtr
, buffer
, x
+ 5, 10);
596 paintDot(tPtr
, buffer
, x
+ 8, 10);
597 paintDot(tPtr
, buffer
, x
+ 11, 10);
600 XCopyArea(dpy
, buffer
, W_VIEW(tPtr
)->window
, scr
->copyGC
, 0, 0,
601 W_VIEW(tPtr
)->size
.width
, tPtr
->tabHeight
, 0, 0);
603 XFreePixmap(dpy
, buffer
);
605 switch (tPtr
->flags
.type
) {
606 case WTTopTabsBevelBorder
:
607 drawRelief(scr
, W_VIEW(tPtr
)->window
, 0, tPtr
->tabHeight
- 1,
608 W_VIEW(tPtr
)->size
.width
,
609 W_VIEW(tPtr
)->size
.height
- tPtr
->tabHeight
+ 1);
612 case WTNoTabsBevelBorder
:
613 W_DrawRelief(scr
, W_VIEW(tPtr
)->window
, 0, 0, W_VIEW(tPtr
)->size
.width
,
614 W_VIEW(tPtr
)->size
.height
, WRRaised
);
617 case WTNoTabsLineBorder
:
618 W_DrawRelief(scr
, W_VIEW(tPtr
)->window
, 0, 0, W_VIEW(tPtr
)->size
.width
,
619 W_VIEW(tPtr
)->size
.height
, WRSimple
);
622 case WTNoTabsNoBorder
:
629 destroyTabView(TabView
*tPtr
)
633 for (i
= 0; i
< tPtr
->itemCount
; i
++) {
634 WMSetTabViewItemView(tPtr
->items
[i
], NULL
);
635 WMDestroyTabViewItem(tPtr
->items
[i
]);
639 WMReleaseColor(tPtr
->lightGray
);
640 WMReleaseColor(tPtr
->tabColor
);
641 WMReleaseFont(tPtr
->font
);
646 /******************************************************************/
649 typedef struct W_TabViewItem
{
665 W_SetTabViewItemParent(WMTabViewItem
*item
, WMTabView
*parent
)
667 item
->tabView
= parent
;
672 W_DrawLabel(WMTabViewItem
*item
, Drawable d
, WMRect rect
)
674 WMScreen
*scr
= W_VIEW(item
->tabView
)->screen
;
679 WMDrawString(scr
, d
, WMColorGC(scr
->black
), item
->tabView
->font
,
680 rect
.pos
.x
, rect
.pos
.y
, item
->label
, strlen(item
->label
));
685 W_UnmapTabViewItem(WMTabViewItem
*item
)
687 wassertr(item
->view
);
689 W_UnmapView(item
->view
);
691 item
->flags
.visible
= 0;
696 W_MapTabViewItem(WMTabViewItem
*item
)
698 wassertr(item
->view
);
700 W_MapView(item
->view
);
702 item
->flags
.visible
= 1;
707 W_TabViewItemView(WMTabViewItem
*item
)
714 WMCreateTabViewItemWithIdentifier(int identifier
)
718 item
= wmalloc(sizeof(WMTabViewItem
));
719 memset(item
, 0, sizeof(WMTabViewItem
));
721 item
->identifier
= identifier
;
728 WMCreateTabViewItem(int identifier
, char *label
)
732 item
= wmalloc(sizeof(WMTabViewItem
));
733 memset(item
, 0, sizeof(WMTabViewItem
));
735 item
->identifier
= identifier
;
736 WMSetTabViewItemLabel(item
, label
);
744 WMGetTabViewItemIdentifier(WMTabViewItem
*item
)
746 return item
->identifier
;
751 WMSetTabViewFont(WMTabView
*tPtr
, WMFont
*font
)
754 WMReleaseFont(tPtr
->font
);
756 tPtr
->font
= WMRetainFont(font
);
757 tPtr
->tabHeight
= WMFontHeight(tPtr
->font
) + 3;
758 recalcTabWidth(tPtr
);
763 WMSetTabViewItemLabel(WMTabViewItem
*item
, char *label
)
768 item
->label
= wstrdup(label
);
771 recalcTabWidth(item
->tabView
);
776 WMGetTabViewItemLabel(WMTabViewItem
*item
)
783 WMSetTabViewItemView(WMTabViewItem
*item
, WMView
*view
)
790 WMGetTabViewItemView(WMTabViewItem
*item
)
797 WMDestroyTabViewItem(WMTabViewItem
*item
)
803 W_DestroyView(item
->view
);