Change to the linux kernel coding style
[wmaker-crm.git] / WINGs / wtabview.c
1
2 #include "WINGsP.h"
3
4 typedef struct W_TabView {
5         W_Class widgetClass;
6         W_View *view;
7
8         struct W_TabViewItem **items;
9         int itemCount;
10         int maxItems;           /* size of items array, can be increased */
11
12         int selectedItem;
13         int firstVisible;
14
15         int visibleTabs;
16
17         WMFont *font;
18
19         WMColor *lightGray;
20         WMColor *tabColor;
21
22         WMTabViewDelegate *delegate;
23
24         short tabHeight;
25
26         struct {
27                 WMReliefType relief:4;
28                 WMTitlePosition titlePosition:4;
29                 WMTabViewType type:2;
30
31                 unsigned enabled:1;
32                 unsigned tabbed:1;
33                 unsigned dontFitAll:1;
34                 unsigned bordered:1;
35                 unsigned uniformTabs:1;
36         } flags;
37 } TabView;
38
39 typedef struct W_TabViewItem {
40         WMTabView *tabView;
41
42         W_View *view;
43
44         char *label;
45
46         short tabWidth;
47         int identifier;
48
49         struct {
50                 unsigned visible:1;
51                 unsigned enabled:1;
52         } flags;
53 } W_TabViewItem;
54
55 #define DEFAULT_WIDTH   40
56 #define DEFAULT_HEIGHT  40
57
58 #define NORMAL_SIDE_OFFSET 8
59 #define BUTTONED_SIDE_OFFSET 15
60
61 static void destroyTabView(TabView * tPtr);
62 static void paintTabView(TabView * tPtr);
63
64 static void W_SetTabViewItemParent(WMTabViewItem * item, WMTabView * parent);
65
66 static void W_DrawLabel(WMTabViewItem * item, Drawable d, WMRect rect, Bool enabled);
67
68 static void W_UnmapTabViewItem(WMTabViewItem * item);
69
70 static void W_MapTabViewItem(WMTabViewItem * item);
71
72 static WMView *W_TabViewItemView(WMTabViewItem * item);
73
74 static int W_TabViewItemTabWidth(WMTabViewItem * item);
75
76 static void W_SetTabViewItemTabWidth(WMTabViewItem * item, int width);
77
78 static void recalcTabWidth(TabView * tPtr);
79 static void rearrange(TabView * tPtr);
80
81 static void didResize(struct W_ViewDelegate *, WMView *);
82
83 static W_ViewDelegate delegate = {
84         NULL,
85         NULL,
86         didResize,
87         NULL,
88         NULL
89 };
90
91 static int positionOfTab(WMTabView * tabView, int tab)
92 {
93         int i;
94         int offs;
95
96         if (tab < tabView->firstVisible)
97                 return -1;
98
99         if (tab > tabView->firstVisible + tabView->visibleTabs)
100                 return -1;
101
102         if (tabView->flags.dontFitAll)
103                 offs = BUTTONED_SIDE_OFFSET;
104         else
105                 offs = NORMAL_SIDE_OFFSET;
106
107         for (i = tabView->firstVisible; i < tab; i++)
108                 offs += W_TabViewItemTabWidth(tabView->items[i]) - 10;
109
110         return offs;
111 }
112
113 static int countVisibleTabs(TabView * tPtr, int first)
114 {
115         int i;
116         int width;
117
118         if (first < 0) {
119                 width = W_VIEW_WIDTH(tPtr->view) - 2 * NORMAL_SIDE_OFFSET;
120                 first = 0;
121         } else {
122                 width = W_VIEW_WIDTH(tPtr->view) - 2 * BUTTONED_SIDE_OFFSET;
123         }
124
125         for (i = first; i < tPtr->itemCount; i++) {
126                 width -= W_TabViewItemTabWidth(tPtr->items[i]) - 10;
127                 if (width <= 0) {
128                         return i - first;
129                 }
130         }
131         return i - first;
132 }
133
134 static void handleEvents(XEvent * event, void *data)
135 {
136         TabView *tPtr = (TabView *) data;
137
138         CHECK_CLASS(data, WC_TabView);
139
140         switch (event->type) {
141         case Expose:
142                 if (event->xexpose.count != 0)
143                         break;
144                 paintTabView(tPtr);
145                 break;
146
147         case ButtonPress:
148                 if (tPtr->flags.enabled) {
149                         WMTabViewItem *item = WMTabViewItemAtPoint(tPtr,
150                                                                    event->xbutton.x,
151                                                                    event->xbutton.y);
152                         /*if (item && !item->flags.enabled)
153                            break; */
154
155                         if (item && item->flags.enabled) {
156                                 WMSelectTabViewItem(tPtr, item);
157                         } else if (tPtr->flags.dontFitAll) {
158                                 int redraw = 0;
159                                 int lastVisible = tPtr->firstVisible + tPtr->visibleTabs - 1;
160
161                                 if (event->xbutton.x < BUTTONED_SIDE_OFFSET) {
162                                         if (tPtr->firstVisible > 0) {
163                                                 redraw = 1;
164                                                 tPtr->firstVisible--;
165                                         }
166                                 } else if (event->xbutton.x > positionOfTab(tPtr, lastVisible)) {
167
168                                         if (lastVisible < tPtr->itemCount - 1) {
169                                                 redraw = 1;
170                                                 tPtr->firstVisible++;
171                                         }
172                                 }
173                                 tPtr->visibleTabs = countVisibleTabs(tPtr, tPtr->firstVisible);
174                                 if (redraw) {
175                                         paintTabView(tPtr);
176                                 }
177                         }
178                 }
179                 break;
180
181         case DestroyNotify:
182                 destroyTabView(tPtr);
183                 break;
184         }
185 }
186
187 WMTabView *WMCreateTabView(WMWidget * parent)
188 {
189         TabView *tPtr;
190         WMScreen *scr = WMWidgetScreen(parent);
191
192         tPtr = wmalloc(sizeof(TabView));
193         memset(tPtr, 0, sizeof(TabView));
194
195         tPtr->widgetClass = WC_TabView;
196
197         tPtr->view = W_CreateView(W_VIEW(parent));
198         if (!tPtr->view) {
199                 wfree(tPtr);
200                 return NULL;
201         }
202         tPtr->view->self = tPtr;
203         tPtr->view->delegate = &delegate;
204
205         tPtr->lightGray = WMCreateRGBColor(scr, 0xd9d9, 0xd9d9, 0xd9d9, False);
206         tPtr->tabColor = WMCreateRGBColor(scr, 0x8420, 0x8420, 0x8420, False);
207
208         tPtr->font = WMRetainFont(scr->normalFont);
209
210         tPtr->flags.type = WTTopTabsBevelBorder;
211         tPtr->flags.bordered = 1;
212         tPtr->flags.uniformTabs = 0;
213         tPtr->flags.enabled = 1;
214
215         WMCreateEventHandler(tPtr->view, ExposureMask | StructureNotifyMask | ButtonPressMask, handleEvents, tPtr);
216
217         WMResizeWidget(tPtr, DEFAULT_WIDTH, DEFAULT_HEIGHT);
218
219         tPtr->tabHeight = WMFontHeight(tPtr->font) + 3;
220
221         return tPtr;
222 }
223
224 void WMSetTabViewDelegate(WMTabView * tPtr, WMTabViewDelegate * delegate)
225 {
226         tPtr->delegate = delegate;
227 }
228
229 WMTabViewItem *WMAddTabViewItemWithView(WMTabView * tPtr, WMView * view, int identifier, char *label)
230 {
231         WMTabViewItem *item;
232
233         item = WMCreateTabViewItemWithIdentifier(identifier);
234         WMSetTabViewItemView(item, view);
235         WMAddItemInTabView(tPtr, item);
236         WMSetTabViewItemLabel(item, label);
237
238         return item;
239 }
240
241 void WMAddItemInTabView(WMTabView * tPtr, WMTabViewItem * item)
242 {
243         WMInsertItemInTabView(tPtr, tPtr->itemCount, item);
244 }
245
246 void WMSetTabViewEnabled(WMTabView * tPtr, Bool flag)
247 {
248         tPtr->flags.enabled = ((flag == 0) ? 0 : 1);
249         if (W_VIEW_REALIZED(tPtr->view))
250                 paintTabView(tPtr);
251 }
252
253 void WMInsertItemInTabView(WMTabView * tPtr, int index, WMTabViewItem * item)
254 {
255         wassertr(W_TabViewItemView(item) != NULL);
256
257         if (tPtr->maxItems == tPtr->itemCount) {
258                 WMTabViewItem **items;
259
260                 items = wrealloc(tPtr->items, sizeof(WMTabViewItem *) * (tPtr->maxItems + 10));
261                 memset(&items[tPtr->maxItems], 0, sizeof(WMTabViewItem *) * 10);
262                 tPtr->items = items;
263                 tPtr->maxItems += 10;
264         }
265
266         if (index > tPtr->itemCount)
267                 index = tPtr->itemCount;
268
269         if (index == 0 && tPtr->items[0]) {
270                 W_UnmapTabViewItem(tPtr->items[0]);
271         }
272
273         if (index < tPtr->itemCount) {
274                 memmove(tPtr->items + index + 1, tPtr->items + index,
275                         (tPtr->itemCount - index) * sizeof(WMTabViewItem *));
276         }
277
278         tPtr->items[index] = item;
279
280         tPtr->itemCount++;
281
282         recalcTabWidth(tPtr);
283
284         W_SetTabViewItemParent(item, tPtr);
285
286         W_UnmapTabViewItem(item);
287
288         if (tPtr->flags.bordered) {
289                 W_ReparentView(W_TabViewItemView(item), tPtr->view, 1, tPtr->tabHeight + 1);
290
291                 W_ResizeView(W_TabViewItemView(item), tPtr->view->size.width - 3,
292                              tPtr->view->size.height - tPtr->tabHeight - 3);
293         } else {
294                 W_ReparentView(W_TabViewItemView(item), tPtr->view, 0, tPtr->tabHeight);
295
296                 W_ResizeView(W_TabViewItemView(item), tPtr->view->size.width,
297                              tPtr->view->size.height - tPtr->tabHeight);
298         }
299
300         if (index == 0) {
301                 W_MapTabViewItem(item);
302         }
303         if (tPtr->delegate && tPtr->delegate->didChangeNumberOfItems)
304                 (*tPtr->delegate->didChangeNumberOfItems) (tPtr->delegate, tPtr);
305
306         if (W_VIEW_REALIZED(tPtr->view))
307                 paintTabView(tPtr);
308 }
309
310 void WMRemoveTabViewItem(WMTabView * tPtr, WMTabViewItem * item)
311 {
312         int i;
313
314         for (i = 0; i < tPtr->itemCount; i++) {
315                 if (tPtr->items[i] == item) {
316                         if (i < tPtr->itemCount - 1)
317                                 memmove(&tPtr->items[i], &tPtr->items[i + 1], tPtr->itemCount - i - 1);
318                         else
319                                 tPtr->items[i] = NULL;
320
321                         W_SetTabViewItemParent(item, NULL);
322
323                         tPtr->itemCount--;
324                         break;
325                 }
326         }
327         if (tPtr->delegate && tPtr->delegate->didChangeNumberOfItems)
328                 (*tPtr->delegate->didChangeNumberOfItems) (tPtr->delegate, tPtr);
329 }
330
331 static Bool isInside(int x, int y, int width, int height, int px, int py)
332 {
333         if (py >= y + height - 3 && py <= y + height && px >= x + py - (y + height - 3)
334             && px <= x + width - (py - (y + height - 3))) {
335
336                 return True;
337         }
338         if (py >= y + 3 && py < y + height - 3
339             && px >= x + 3 + ((y + 3) - py) * 3 / 7 && px <= x + width - 3 - ((y + 3) - py) * 3 / 7) {
340
341                 return True;
342         }
343         if (py >= y && py < y + 3 && px >= x + 7 + py - y && px <= x + width - 7 - (py - y)) {
344
345                 return True;
346         }
347         return False;
348 }
349
350 WMTabViewItem *WMTabViewItemAtPoint(WMTabView * tPtr, int x, int y)
351 {
352         int i;
353         int count = tPtr->visibleTabs;
354         int first = tPtr->firstVisible;
355
356         if (tPtr->flags.dontFitAll) {
357                 i = tPtr->selectedItem - tPtr->firstVisible;
358                 if (i >= 0 && i < tPtr->visibleTabs
359                     && isInside(positionOfTab(tPtr, tPtr->selectedItem), 0,
360                                 W_TabViewItemTabWidth(tPtr->items[tPtr->selectedItem]), tPtr->tabHeight, x, y)) {
361                         return tPtr->items[tPtr->selectedItem];
362                 }
363         } else {
364                 i = tPtr->selectedItem;
365                 if (isInside(positionOfTab(tPtr, i), 0,
366                              W_TabViewItemTabWidth(tPtr->items[i]), tPtr->tabHeight, x, y)) {
367                         return tPtr->items[i];
368                 }
369         }
370
371         for (i = first; i < first + count; i++) {
372                 int pos;
373
374                 pos = positionOfTab(tPtr, i);
375                 if (isInside(pos, 0, W_TabViewItemTabWidth(tPtr->items[i]), tPtr->tabHeight, x, y)) {
376                         return tPtr->items[i];
377                 }
378         }
379         return NULL;
380 }
381
382 void WMSetTabViewType(WMTabView * tPtr, WMTabViewType type)
383 {
384         tPtr->flags.type = type;
385
386         if (type != WTTopTabsBevelBorder)
387                 tPtr->tabHeight = 0;
388         else
389                 tPtr->tabHeight = WMFontHeight(tPtr->font) + 3;
390
391         if (type == WTNoTabsNoBorder)
392                 tPtr->flags.bordered = 0;
393         else
394                 tPtr->flags.bordered = 1;
395
396         rearrange(tPtr);
397 }
398
399 void WMSelectFirstTabViewItem(WMTabView * tPtr)
400 {
401         WMSelectTabViewItemAtIndex(tPtr, 0);
402 }
403
404 void WMSelectLastTabViewItem(WMTabView * tPtr)
405 {
406         WMSelectTabViewItemAtIndex(tPtr, tPtr->itemCount);
407 }
408
409 void WMSelectNextTabViewItem(WMTabView * tPtr)
410 {
411         WMSelectTabViewItemAtIndex(tPtr, tPtr->selectedItem + 1);
412 }
413
414 void WMSelectPreviousTabViewItem(WMTabView * tPtr)
415 {
416         WMSelectTabViewItemAtIndex(tPtr, tPtr->selectedItem - 1);
417 }
418
419 WMTabViewItem *WMGetSelectedTabViewItem(WMTabView * tPtr)
420 {
421         return tPtr->items[tPtr->selectedItem];
422 }
423
424 void WMSelectTabViewItem(WMTabView * tPtr, WMTabViewItem * item)
425 {
426         int i;
427
428         for (i = 0; i < tPtr->itemCount; i++) {
429                 if (tPtr->items[i] == item) {
430                         WMSelectTabViewItemAtIndex(tPtr, i);
431                         break;
432                 }
433         }
434 }
435
436 void WMSelectTabViewItemAtIndex(WMTabView * tPtr, int index)
437 {
438         WMTabViewItem *item;
439
440         if (index == tPtr->selectedItem) {
441                 return;
442         }
443
444         if (index < 0)
445                 index = 0;
446         else if (index >= tPtr->itemCount)
447                 index = tPtr->itemCount - 1;
448
449         item = tPtr->items[tPtr->selectedItem];
450
451         if (tPtr->delegate && tPtr->delegate->shouldSelectItem)
452                 if (!(*tPtr->delegate->shouldSelectItem) (tPtr->delegate, tPtr, tPtr->items[index]))
453                         return;
454
455         if (tPtr->delegate && tPtr->delegate->willSelectItem)
456                 (*tPtr->delegate->willSelectItem) (tPtr->delegate, tPtr, tPtr->items[index]);
457
458         W_UnmapTabViewItem(item);
459
460         item = tPtr->items[index];
461
462         W_MapTabViewItem(item);
463
464         tPtr->selectedItem = index;
465
466         if (tPtr->delegate && tPtr->delegate->didSelectItem)
467                 (*tPtr->delegate->didSelectItem) (tPtr->delegate, tPtr, tPtr->items[index]);
468
469         paintTabView(tPtr);
470 }
471
472 static void recalcTabWidth(TabView * tPtr)
473 {
474         int i;
475         /*int twidth = W_VIEW(tPtr)->size.width; */
476         int width;
477
478         if (tPtr->flags.uniformTabs) {
479                 int tabWidth;
480
481                 tabWidth = 0;
482
483                 for (i = 0; i < tPtr->itemCount; i++) {
484                         char *str = WMGetTabViewItemLabel(tPtr->items[i]);
485
486                         if (str) {
487                                 width = WMWidthOfString(tPtr->font, str, strlen(str));
488                                 if (width > tabWidth)
489                                         tabWidth = width;
490                         }
491                 }
492
493                 tabWidth = tabWidth + 30;
494
495                 for (i = 0; i < tPtr->itemCount; i++)
496                         W_SetTabViewItemTabWidth(tPtr->items[i], tabWidth);
497
498                 tPtr->firstVisible = 0;
499                 tPtr->visibleTabs = countVisibleTabs(tPtr, -1);
500                 if (tPtr->visibleTabs < tPtr->itemCount)
501                         tPtr->flags.dontFitAll = 1;
502                 else
503                         tPtr->flags.dontFitAll = 0;
504         } else {
505                 for (i = 0; i < tPtr->itemCount; i++) {
506                         char *str = WMGetTabViewItemLabel(tPtr->items[i]);
507                         if (!str)
508                                 continue;
509
510                         width = WMWidthOfString(tPtr->font, str, strlen(str)) + 30;
511
512                         W_SetTabViewItemTabWidth(tPtr->items[i], width);
513                 }
514
515                 if (countVisibleTabs(tPtr, -1) < tPtr->itemCount) {
516                         tPtr->flags.dontFitAll = 1;
517                         tPtr->firstVisible = 0;
518                         tPtr->visibleTabs = countVisibleTabs(tPtr, tPtr->firstVisible);
519                 } else {
520                         tPtr->flags.dontFitAll = 0;
521                         tPtr->firstVisible = 0;
522                         tPtr->visibleTabs = tPtr->itemCount;
523                 }
524         }
525 }
526
527 static void drawRelief(W_Screen * scr, Drawable d, int x, int y, unsigned int width, unsigned int height)
528 {
529         Display *dpy = scr->display;
530         GC bgc = WMColorGC(scr->black);
531         GC wgc = WMColorGC(scr->white);
532         GC dgc = WMColorGC(scr->darkGray);
533
534         XDrawLine(dpy, d, wgc, x, y, x, y + height - 1);
535
536         XDrawLine(dpy, d, bgc, x, y + height - 1, x + width - 1, y + height - 1);
537         XDrawLine(dpy, d, dgc, x + 1, y + height - 2, x + width - 2, y + height - 2);
538
539         XDrawLine(dpy, d, bgc, x + width - 1, y, x + width - 1, y + height - 1);
540         XDrawLine(dpy, d, dgc, x + width - 2, y + 1, x + width - 2, y + height - 2);
541 }
542
543 static void drawTab(TabView * tPtr, Drawable d, int x, int y, unsigned width, unsigned height, Bool selected)
544 {
545         WMScreen *scr = W_VIEW(tPtr)->screen;
546         Display *dpy = scr->display;
547         GC white = WMColorGC(selected ? scr->white : tPtr->lightGray);
548         GC black = WMColorGC(scr->black);
549         GC dark = WMColorGC(scr->darkGray);
550         GC light = WMColorGC(scr->gray);
551         XPoint trap[8];
552
553         trap[0].x = x + (selected ? 0 : 1);
554         trap[0].y = y + height - (selected ? 0 : 1);
555
556         trap[1].x = x + 3;
557         trap[1].y = y + height - 3;
558
559         trap[2].x = x + 10 - 3;
560         trap[2].y = y + 3;
561
562         trap[3].x = x + 10;
563         trap[3].y = y;
564
565         trap[4].x = x + width - 10;
566         trap[4].y = y;
567
568         trap[5].x = x + width - 10 + 3;
569         trap[5].y = y + 3;
570
571         trap[6].x = x + width - 3;
572         trap[6].y = y + height - 3;
573
574         trap[7].x = x + width - (selected ? 0 : 1);
575         trap[7].y = y + height - (selected ? 0 : 1);
576
577         XFillPolygon(dpy, d, selected ? light : WMColorGC(tPtr->tabColor), trap, 8, Convex, CoordModeOrigin);
578
579         XDrawLine(dpy, d, white, trap[0].x, trap[0].y, trap[1].x, trap[1].y);
580         XDrawLine(dpy, d, white, trap[1].x, trap[1].y, trap[2].x, trap[2].y);
581         XDrawLine(dpy, d, white, trap[2].x, trap[2].y, trap[3].x, trap[3].y);
582         XDrawLine(dpy, d, white, trap[3].x, trap[3].y, trap[4].x, trap[4].y);
583         XDrawLine(dpy, d, dark, trap[4].x, trap[4].y, trap[5].x, trap[5].y);
584         XDrawLine(dpy, d, black, trap[5].x, trap[5].y, trap[6].x, trap[6].y);
585         XDrawLine(dpy, d, black, trap[6].x, trap[6].y, trap[7].x, trap[7].y);
586
587         XDrawLine(dpy, d, selected ? light : WMColorGC(scr->white), trap[0].x, trap[0].y, trap[7].x, trap[7].y);
588 }
589
590 static void paintDot(TabView * tPtr, Drawable d, int x, int y)
591 {
592         WMScreen *scr = W_VIEW(tPtr)->screen;
593         Display *dpy = scr->display;
594         GC white = WMColorGC(scr->white);
595         GC black = WMColorGC(scr->black);
596
597         XFillRectangle(dpy, d, black, x, y, 2, 2);
598         XDrawPoint(dpy, d, white, x, y);
599 }
600
601 static void paintTabView(TabView * tPtr)
602 {
603         Pixmap buffer;
604         WMScreen *scr = W_VIEW(tPtr)->screen;
605         Display *dpy = scr->display;
606         GC white = WMColorGC(scr->white);
607         int i;
608
609         if (tPtr->flags.type == WTTopTabsBevelBorder) {
610                 int count = tPtr->visibleTabs;
611                 int first = tPtr->firstVisible;
612                 int moreAtLeft;
613                 int moreAtRight;
614                 int selectedIsVisible;
615                 int ty;
616                 int twidth, theight;
617
618                 ty = 2;
619                 theight = tPtr->tabHeight;
620
621                 buffer = XCreatePixmap(dpy, W_VIEW(tPtr)->window,
622                                        W_VIEW(tPtr)->size.width, theight, W_VIEW(tPtr)->screen->depth);
623
624                 XFillRectangle(dpy, buffer, WMColorGC(W_VIEW(tPtr)->backColor),
625                                0, 0, W_VIEW(tPtr)->size.width, tPtr->tabHeight);
626
627                 if (tPtr->flags.dontFitAll) {
628                         moreAtLeft = first > 0;
629                         moreAtRight = (first + count) < tPtr->itemCount;
630                         if (tPtr->selectedItem >= first && tPtr->selectedItem < first + count)
631                                 selectedIsVisible = 1;
632                         else
633                                 selectedIsVisible = 0;
634                 } else {
635                         moreAtLeft = 0;
636                         moreAtRight = 0;
637                         selectedIsVisible = 1;
638                 }
639
640                 if (moreAtRight) {
641                         drawTab(tPtr, buffer, positionOfTab(tPtr, first + count), 0,
642                                 W_VIEW_WIDTH(tPtr->view), theight, False);
643                 }
644                 for (i = first + count - 1; i >= first; i--) {
645                         if (!selectedIsVisible || i != tPtr->selectedItem) {
646                                 twidth = W_TabViewItemTabWidth(tPtr->items[i]);
647
648                                 drawTab(tPtr, buffer, positionOfTab(tPtr, i), 0, twidth, theight, False);
649                         }
650                 }
651                 if (moreAtLeft) {
652                         drawTab(tPtr, buffer, positionOfTab(tPtr, 0) - 2 * BUTTONED_SIDE_OFFSET,
653                                 0, BUTTONED_SIDE_OFFSET * 4, theight, False);
654                 }
655
656                 if (selectedIsVisible) {
657                         int idx = tPtr->selectedItem;
658
659                         drawTab(tPtr, buffer, positionOfTab(tPtr, idx),
660                                 0, W_TabViewItemTabWidth(tPtr->items[idx]), theight, True);
661
662                         XDrawLine(dpy, buffer, white, 0, theight - 1, positionOfTab(tPtr, idx), theight - 1);
663
664                         XDrawLine(dpy, buffer, white,
665                                   positionOfTab(tPtr, idx) + W_TabViewItemTabWidth(tPtr->items[idx]),
666                                   tPtr->tabHeight - 1, W_VIEW_WIDTH(tPtr->view) - 1, tPtr->tabHeight - 1);
667                 } else {
668                         XDrawLine(dpy, buffer, white, 0, theight - 1, W_VIEW_WIDTH(tPtr->view), theight - 1);
669                 }
670
671                 for (i = 0; i < count; i++) {
672                         WMRect rect;
673
674                         rect.pos.x = 15 + positionOfTab(tPtr, first + i);
675                         rect.pos.y = ty;
676                         rect.size.width = W_TabViewItemTabWidth(tPtr->items[first + i]);
677                         rect.size.height = theight;
678                         W_DrawLabel(tPtr->items[first + i], buffer, rect,
679                                     tPtr->flags.enabled && tPtr->items[first + i]->flags.enabled);
680                 }
681
682                 if (moreAtLeft) {
683                         paintDot(tPtr, buffer, 4, 10);
684                         paintDot(tPtr, buffer, 7, 10);
685                         paintDot(tPtr, buffer, 10, 10);
686                 }
687                 if (moreAtRight) {
688                         int x;
689
690                         x = positionOfTab(tPtr, tPtr->firstVisible + tPtr->visibleTabs);
691
692                         x = x + (W_VIEW_WIDTH(tPtr->view) - x) / 2;
693                         paintDot(tPtr, buffer, x + 5, 10);
694                         paintDot(tPtr, buffer, x + 8, 10);
695                         paintDot(tPtr, buffer, x + 11, 10);
696                 }
697
698                 XCopyArea(dpy, buffer, W_VIEW(tPtr)->window, scr->copyGC, 0, 0,
699                           W_VIEW_WIDTH(tPtr->view), theight, 0, 0);
700
701                 XFreePixmap(dpy, buffer);
702         }
703         switch (tPtr->flags.type) {
704         case WTTopTabsBevelBorder:
705                 drawRelief(scr, W_VIEW(tPtr)->window, 0, tPtr->tabHeight - 1,
706                            W_VIEW(tPtr)->size.width, W_VIEW(tPtr)->size.height - tPtr->tabHeight + 1);
707                 break;
708
709         case WTNoTabsBevelBorder:
710                 W_DrawRelief(scr, W_VIEW(tPtr)->window, 0, 0, W_VIEW(tPtr)->size.width,
711                              W_VIEW(tPtr)->size.height, WRRaised);
712                 break;
713
714         case WTNoTabsLineBorder:
715                 W_DrawRelief(scr, W_VIEW(tPtr)->window, 0, 0, W_VIEW(tPtr)->size.width,
716                              W_VIEW(tPtr)->size.height, WRSimple);
717                 break;
718
719         case WTNoTabsNoBorder:
720                 break;
721         }
722 }
723
724 static void rearrange(TabView * tPtr)
725 {
726         int i;
727         int width, height;
728         int bordered = tPtr->flags.bordered;
729
730         recalcTabWidth(tPtr);
731
732         width = tPtr->view->size.width - (bordered ? 3 : 0);
733         height = tPtr->view->size.height - tPtr->tabHeight - (bordered ? 3 : 0);
734
735         for (i = 0; i < tPtr->itemCount; i++) {
736                 W_MoveView(W_TabViewItemView(tPtr->items[i]), 1 * bordered, tPtr->tabHeight + 1 * bordered);
737                 W_ResizeView(W_TabViewItemView(tPtr->items[i]), width, height);
738         }
739         if (W_VIEW_MAPPED(tPtr->view) && W_VIEW_REALIZED(tPtr->view))
740                 paintTabView(tPtr);
741 }
742
743 static void didResize(struct W_ViewDelegate *deleg, WMView * view)
744 {
745         rearrange(view->self);
746 }
747
748 static void destroyTabView(TabView * tPtr)
749 {
750         int i;
751
752         for (i = 0; i < tPtr->itemCount; i++) {
753                 WMSetTabViewItemView(tPtr->items[i], NULL);
754                 WMDestroyTabViewItem(tPtr->items[i]);
755         }
756         wfree(tPtr->items);
757
758         WMReleaseColor(tPtr->lightGray);
759         WMReleaseColor(tPtr->tabColor);
760         WMReleaseFont(tPtr->font);
761
762         wfree(tPtr);
763 }
764
765 /******************************************************************/
766
767 static void W_SetTabViewItemParent(WMTabViewItem * item, WMTabView * parent)
768 {
769         item->tabView = parent;
770 }
771
772 static void W_DrawLabel(WMTabViewItem * item, Drawable d, WMRect rect, Bool enabled)
773 {
774         WMScreen *scr = W_VIEW(item->tabView)->screen;
775
776         if (!item->label)
777                 return;
778
779         WMDrawString(scr, d, enabled ? scr->black : scr->darkGray,
780                      item->tabView->font, rect.pos.x, rect.pos.y, item->label, strlen(item->label));
781 }
782
783 static void W_UnmapTabViewItem(WMTabViewItem * item)
784 {
785         wassertr(item->view);
786
787         W_UnmapView(item->view);
788
789         item->flags.visible = 0;
790 }
791
792 static void W_MapTabViewItem(WMTabViewItem * item)
793 {
794         wassertr(item->view);
795
796         W_MapView(item->view);
797         W_RaiseView(item->view);
798
799         item->flags.visible = 1;
800 }
801
802 static WMView *W_TabViewItemView(WMTabViewItem * item)
803 {
804         return item->view;
805 }
806
807 static int W_TabViewItemTabWidth(WMTabViewItem * item)
808 {
809         return item->tabWidth;
810 }
811
812 static void W_SetTabViewItemTabWidth(WMTabViewItem * item, int width)
813 {
814         item->tabWidth = width;
815 }
816
817 WMTabViewItem *WMCreateTabViewItemWithIdentifier(int identifier)
818 {
819         WMTabViewItem *item;
820
821         item = wmalloc(sizeof(WMTabViewItem));
822         memset(item, 0, sizeof(WMTabViewItem));
823
824         item->identifier = identifier;
825
826         item->flags.enabled = 1;
827
828         return item;
829 }
830
831 WMTabViewItem *WMCreateTabViewItem(int identifier, char *label)
832 {
833         WMTabViewItem *item;
834
835         item = wmalloc(sizeof(WMTabViewItem));
836         memset(item, 0, sizeof(WMTabViewItem));
837
838         item->identifier = identifier;
839
840         item->flags.enabled = 1;
841
842         WMSetTabViewItemLabel(item, label);
843
844         return item;
845 }
846
847 void WMSetTabViewItemEnabled(WMTabViewItem * tPtr, Bool flag)
848 {
849         tPtr->flags.enabled = ((flag == 0) ? 0 : 1);
850         if (tPtr->tabView && W_VIEW_REALIZED(tPtr->tabView->view))
851                 paintTabView(tPtr->tabView);
852 }
853
854 int WMGetTabViewItemIdentifier(WMTabViewItem * item)
855 {
856         return item->identifier;
857 }
858
859 void WMSetTabViewFont(WMTabView * tPtr, WMFont * font)
860 {
861         if (tPtr->font)
862                 WMReleaseFont(tPtr->font);
863
864         tPtr->font = WMRetainFont(font);
865         tPtr->tabHeight = WMFontHeight(tPtr->font) + 3;
866         recalcTabWidth(tPtr);
867 }
868
869 void WMSetTabViewItemLabel(WMTabViewItem * item, char *label)
870 {
871         if (item->label)
872                 wfree(item->label);
873
874         if (label)
875                 item->label = wstrdup(label);
876         else
877                 item->label = NULL;
878
879         if (item->tabView)
880                 recalcTabWidth(item->tabView);
881 }
882
883 char *WMGetTabViewItemLabel(WMTabViewItem * item)
884 {
885         return item->label;
886 }
887
888 void WMSetTabViewItemView(WMTabViewItem * item, WMView * view)
889 {
890         item->view = view;
891 }
892
893 WMView *WMGetTabViewItemView(WMTabViewItem * item)
894 {
895         return item->view;
896 }
897
898 void WMDestroyTabViewItem(WMTabViewItem * item)
899 {
900         if (item->label)
901                 wfree(item->label);
902
903         if (item->view)
904                 W_DestroyView(item->view);
905
906         wfree(item);
907 }