- fixed uncompilable tree.
[wmaker-crm.git] / WINGs / wtabview.c
blobd690421f6d56e4e37dcd72e3c1c2aa2c032a1929
2 #include "WINGsP.h"
5 typedef struct W_TabView {
6 W_Class widgetClass;
7 W_View *view;
9 struct W_TabViewItem **items;
10 int itemCount;
11 int maxItems; /* size of items array, can be increased */
13 int selectedItem;
14 int firstVisible;
16 int visibleTabs;
18 WMFont *font;
20 WMColor *lightGray;
21 WMColor *tabColor;
23 WMTabViewDelegate *delegate;
25 short tabWidth;
26 short tabHeight;
28 struct {
29 WMReliefType relief:4;
30 WMTitlePosition titlePosition:4;
31 WMTabViewType type:2;
33 unsigned tabbed:1;
34 unsigned dontFitAll:1;
35 } flags;
36 } TabView;
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);
64 static void
65 handleEvents(XEvent *event, void *data)
67 TabView *tPtr = (TabView*)data;
69 CHECK_CLASS(data, WC_TabView);
71 switch (event->type) {
72 case Expose:
73 if (event->xexpose.count!=0)
74 break;
75 paintTabView(tPtr);
76 break;
78 case ButtonPress:
80 WMTabViewItem *item = WMTabViewItemAtPoint(tPtr,
81 event->xbutton.x,
82 event->xbutton.y);
83 if (item) {
84 WMSelectTabViewItem(tPtr, item);
85 } else if (tPtr->flags.dontFitAll) {
86 int redraw;
87 if (event->xbutton.x < BUTTONED_SIDE_OFFSET) {
88 if (tPtr->firstVisible > 0) {
89 redraw = 1;
90 tPtr->firstVisible--;
92 } else if (event->xbutton.x - BUTTONED_SIDE_OFFSET
93 > tPtr->visibleTabs*(tPtr->tabWidth-10)) {
95 if (tPtr->firstVisible + tPtr->visibleTabs
96 < tPtr->itemCount) {
97 redraw = 1;
98 tPtr->firstVisible++;
102 if (redraw) {
103 paintTabView(tPtr);
107 break;
109 case DestroyNotify:
110 destroyTabView(tPtr);
111 break;
117 WMTabView*
118 WMCreateTabView(WMWidget *parent)
120 TabView *tPtr;
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));
129 if (!tPtr->view) {
130 wfree(tPtr);
131 return NULL;
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;
147 return tPtr;
151 void
152 WMSetTabViewDelegate(WMTabView *tPtr, WMTabViewDelegate *delegate)
154 tPtr->delegate = delegate;
158 WMTabViewItem*
159 WMAddTabViewItemWithView(WMTabView *tPtr, WMView *view, int identifier,
160 char *label)
162 WMTabViewItem *item;
164 item = WMCreateTabViewItemWithIdentifier(identifier);
165 WMSetTabViewItemView(item, view);
166 WMAddItemInTabView(tPtr, item);
167 WMSetTabViewItemLabel(item, label);
169 return item;
173 void
174 WMAddItemInTabView(WMTabView *tPtr, WMTabViewItem *item)
176 WMInsertItemInTabView(tPtr, tPtr->itemCount, item);
180 void
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);
191 tPtr->items = items;
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;
209 tPtr->itemCount++;
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);
223 if (index == 0) {
224 W_MapTabViewItem(item);
226 if (tPtr->delegate && tPtr->delegate->didChangeNumberOfItems)
227 (*tPtr->delegate->didChangeNumberOfItems)(tPtr->delegate, tPtr);
231 void
232 WMRemoveTabViewItem(WMTabView *tPtr, WMTabViewItem *item)
234 int i;
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);
241 else
242 tPtr->items[i] = NULL;
244 W_SetTabViewItemParent(item, NULL);
246 tPtr->itemCount--;
247 break;
250 if (tPtr->delegate && tPtr->delegate->didChangeNumberOfItems)
251 (*tPtr->delegate->didChangeNumberOfItems)(tPtr->delegate, tPtr);
256 static Bool
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))) {
263 return True;
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) {
269 return True;
271 if (py >= y && py < y + 3
272 && px >= x + 7 + py - y
273 && px <= x + width - 7 - (py - y)) {
275 return True;
277 return False;
281 WMTabViewItem*
282 WMTabViewItemAtPoint(WMTabView *tPtr, int x, int y)
284 int i;
285 int offset;
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];
298 } else {
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];
314 return NULL;
318 void
319 WMSelectFirstTabViewItem(WMTabView *tPtr)
321 WMSelectTabViewItemAtIndex(tPtr, 0);
325 void
326 WMSelectLastTabViewItem(WMTabView *tPtr)
328 WMSelectTabViewItemAtIndex(tPtr, tPtr->itemCount);
332 void
333 WMSelectNextTabViewItem(WMTabView *tPtr)
335 WMSelectTabViewItemAtIndex(tPtr, tPtr->selectedItem + 1);
339 void
340 WMSelectPreviousTabViewItem(WMTabView *tPtr)
342 WMSelectTabViewItemAtIndex(tPtr, tPtr->selectedItem - 1);
346 WMTabViewItem*
347 WMGetSelectedTabViewItem(WMTabView *tPtr)
349 return tPtr->items[tPtr->selectedItem];
353 void
354 WMSelectTabViewItem(WMTabView *tPtr, WMTabViewItem *item)
356 int i;
358 for (i = 0; i < tPtr->itemCount; i++) {
359 if (tPtr->items[i] == item) {
360 WMSelectTabViewItemAtIndex(tPtr, i);
361 break;
367 void
368 WMSelectTabViewItemAtIndex(WMTabView *tPtr, int index)
370 WMTabViewItem *item;
372 if (index == tPtr->selectedItem)
373 return;
375 if (index < 0)
376 index = 0;
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,
384 tPtr->items[index]))
385 return;
387 if (tPtr->delegate && tPtr->delegate->willSelectItem)
388 (*tPtr->delegate->willSelectItem)(tPtr->delegate, tPtr,
389 tPtr->items[index]);
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,
402 tPtr->items[index]);
406 static void
407 recalcTabWidth(TabView *tPtr)
409 int i;
410 int twidth = W_VIEW(tPtr)->size.width;
411 int width;
413 tPtr->tabWidth = 0;
414 for (i = 0; i < tPtr->itemCount; i++) {
415 char *str = WMGetTabViewItemLabel(tPtr->items[i]);
417 if (str) {
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);
428 } else {
429 tPtr->flags.dontFitAll = 0;
430 tPtr->firstVisible = 0;
431 tPtr->visibleTabs = tPtr->itemCount;
436 static void
437 drawRelief(W_Screen *scr, Drawable d, int x, int y, unsigned int width,
438 unsigned int height)
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);
455 static void
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);
465 XPoint trap[8];
467 trap[0].x = x + (selected ? 0 : 1);
468 trap[0].y = y + height - (selected ? 0 : 1);
470 trap[1].x = x + 3;
471 trap[1].y = y + height - 3;
473 trap[2].x = x + 10 - 3;
474 trap[2].y = y + 3;
476 trap[3].x = x + 10;
477 trap[3].y = y;
479 trap[4].x = x + width - 10;
480 trap[4].y = y;
482 trap[5].x = x + width - 10 + 3;
483 trap[5].y = y + 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);
507 static void
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);
521 static void
522 paintTabView(TabView *tPtr)
524 Pixmap buffer;
525 WMScreen *scr = W_VIEW(tPtr)->screen;
526 Display *dpy = scr->display;
527 GC white = WMColorGC(scr->white);
528 int i;
529 WMRect rect;
531 if (tPtr->flags.type == WTTopTabsBevelBorder) {
532 int count = tPtr->visibleTabs;
533 int first = tPtr->firstVisible;
534 int offs;
535 int moreAtLeft;
536 int moreAtRight;
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);
546 rect.pos.y = 2;
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;
555 else
556 selectedIsVisible = 0;
557 } else {
558 rect.pos.x = 15 + NORMAL_SIDE_OFFSET;
559 offs = NORMAL_SIDE_OFFSET;
560 moreAtLeft = 0;
561 moreAtRight = 0;
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);
587 } else {
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;
598 if (moreAtLeft) {
599 paintDot(tPtr, buffer, 4, 10);
600 paintDot(tPtr, buffer, 7, 10);
601 paintDot(tPtr, buffer, 10, 10);
603 if (moreAtRight) {
604 int x;
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);
625 break;
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);
630 break;
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);
635 break;
637 case WTNoTabsNoBorder:
638 break;
643 static void
644 destroyTabView(TabView *tPtr)
646 int i;
648 for (i = 0; i < tPtr->itemCount; i++) {
649 WMSetTabViewItemView(tPtr->items[i], NULL);
650 WMDestroyTabViewItem(tPtr->items[i]);
652 wfree(tPtr->items);
654 WMReleaseColor(tPtr->lightGray);
655 WMReleaseColor(tPtr->tabColor);
656 WMReleaseFont(tPtr->font);
658 wfree(tPtr);
661 /******************************************************************/
664 typedef struct W_TabViewItem {
665 WMTabView *tabView;
667 W_View *view;
669 char *label;
671 int identifier;
673 struct {
674 unsigned visible:1;
675 } flags;
676 } TabViewItem;
679 static void
680 W_SetTabViewItemParent(WMTabViewItem *item, WMTabView *parent)
682 item->tabView = parent;
686 static void
687 W_DrawLabel(WMTabViewItem *item, Drawable d, WMRect rect)
689 WMScreen *scr = W_VIEW(item->tabView)->screen;
691 if (!item->label)
692 return;
694 WMDrawString(scr, d, WMColorGC(scr->black), item->tabView->font,
695 rect.pos.x, rect.pos.y, item->label, strlen(item->label));
699 static void
700 W_UnmapTabViewItem(WMTabViewItem *item)
702 wassertr(item->view);
704 W_UnmapView(item->view);
706 item->flags.visible = 0;
710 static void
711 W_MapTabViewItem(WMTabViewItem *item)
713 wassertr(item->view);
715 W_MapView(item->view);
717 item->flags.visible = 1;
721 static WMView*
722 W_TabViewItemView(WMTabViewItem *item)
724 return item->view;
728 WMTabViewItem*
729 WMCreateTabViewItemWithIdentifier(int identifier)
731 WMTabViewItem *item;
733 item = wmalloc(sizeof(WMTabViewItem));
734 memset(item, 0, sizeof(WMTabViewItem));
736 item->identifier = identifier;
738 return item;
742 WMTabViewItem*
743 WMCreateTabViewItem(int identifier, char *label)
745 WMTabViewItem *item;
747 item = wmalloc(sizeof(WMTabViewItem));
748 memset(item, 0, sizeof(WMTabViewItem));
750 item->identifier = identifier;
751 WMSetTabViewItemLabel(item, label);
753 return item;
759 WMGetTabViewItemIdentifier(WMTabViewItem *item)
761 return item->identifier;
765 void
766 WMSetTabViewFont(WMTabView *tPtr, WMFont *font)
768 if (tPtr->font)
769 WMReleaseFont(tPtr->font);
771 tPtr->font = WMRetainFont(font);
772 tPtr->tabHeight = WMFontHeight(tPtr->font) + 3;
773 recalcTabWidth(tPtr);
777 void
778 WMSetTabViewItemLabel(WMTabViewItem *item, char *label)
780 if (item->label)
781 wfree(item->label);
783 item->label = wstrdup(label);
785 if (item->tabView)
786 recalcTabWidth(item->tabView);
790 char*
791 WMGetTabViewItemLabel(WMTabViewItem *item)
793 return item->label;
797 void
798 WMSetTabViewItemView(WMTabViewItem *item, WMView *view)
800 item->view = view;
804 WMView*
805 WMGetTabViewItemView(WMTabViewItem *item)
807 return item->view;
811 void
812 WMDestroyTabViewItem(WMTabViewItem *item)
814 if (item->label)
815 wfree(item->label);
817 if (item->view)
818 W_DestroyView(item->view);
820 wfree(item);