Various bug fixes.
[wmaker-crm.git] / WINGs / wtabview.c
blobd52b315c9e3cbf55e48e5ed1d80241058d33a046
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 */
13 int selectedItem;
15 WMFont *font;
17 WMColor *lightGray;
18 WMColor *tabColor;
20 WMTabViewDelegate *delegate;
22 short tabWidth;
23 short tabHeight;
25 struct {
26 WMReliefType relief:4;
27 WMTitlePosition titlePosition:4;
28 WMTabViewTypes type:2;
30 unsigned tabbed:1;
31 unsigned allowsTruncatedLabels:1;
32 } flags;
33 } TabView;
37 #define DEFAULT_WIDTH 40
38 #define DEFAULT_HEIGHT 40
41 static void destroyTabView(TabView *tPtr);
42 static void paintTabView(TabView *tPtr);
45 static void W_SetTabViewItemParent(WMTabViewItem *item, WMTabView *parent);
47 static void W_DrawLabel(WMTabViewItem *item, Drawable d, WMRect rect);
49 static void W_UnmapTabViewItem(WMTabViewItem *item);
51 static void W_MapTabViewItem(WMTabViewItem *item);
53 static WMView *W_TabViewItemView(WMTabViewItem *item);
55 static void recalcTabWidth(TabView *tPtr);
58 static void
59 handleEvents(XEvent *event, void *data)
61 TabView *tPtr = (TabView*)data;
63 CHECK_CLASS(data, WC_TabView);
65 switch (event->type) {
66 case Expose:
67 if (event->xexpose.count!=0)
68 break;
69 paintTabView(tPtr);
70 break;
72 case ButtonPress:
74 WMTabViewItem *item = WMTabViewItemAtPoint(tPtr,
75 event->xbutton.x,
76 event->xbutton.y);
77 if (item) {
78 WMSelectTabViewItem(tPtr, item);
81 break;
83 case DestroyNotify:
84 destroyTabView(tPtr);
85 break;
91 WMTabView*
92 WMCreateTabView(WMWidget *parent)
94 TabView *tPtr;
95 WMScreen *scr = WMWidgetScreen(parent);
97 tPtr = wmalloc(sizeof(TabView));
98 memset(tPtr, 0, sizeof(TabView));
100 tPtr->widgetClass = WC_TabView;
102 tPtr->view = W_CreateView(W_VIEW(parent));
103 if (!tPtr->view) {
104 free(tPtr);
105 return NULL;
107 tPtr->view->self = tPtr;
109 tPtr->lightGray = WMCreateRGBColor(scr, 0xd9d9, 0xd9d9, 0xd9d9, False);
110 tPtr->tabColor = WMCreateRGBColor(scr, 0x8420, 0x8420, 0x8420, False);
112 tPtr->font = WMRetainFont(scr->normalFont);
114 WMCreateEventHandler(tPtr->view, ExposureMask|StructureNotifyMask
115 |ButtonPressMask, handleEvents, tPtr);
117 WMResizeWidget(tPtr, DEFAULT_WIDTH, DEFAULT_HEIGHT);
119 tPtr->tabHeight = WMFontHeight(tPtr->font) + 3;
121 return tPtr;
125 void
126 WMSetTabViewDelegate(WMTabView *tPtr, WMTabViewDelegate *delegate)
128 tPtr->delegate = delegate;
132 void
133 WMAddItemInTabView(WMTabView *tPtr, WMTabViewItem *item)
135 WMInsertItemInTabView(tPtr, tPtr->itemCount, item);
139 void
140 WMInsertItemInTabView(WMTabView *tPtr, int index, WMTabViewItem *item)
142 wassertr(W_TabViewItemView(item) != NULL);
144 if (tPtr->maxItems == tPtr->itemCount) {
145 WMTabViewItem **items;
147 items = wrealloc(tPtr->items,
148 sizeof(WMTabViewItem*) * (tPtr->maxItems + 10));
149 if (!items) {
150 wwarning("out of memory allocating memory for tabview");
151 return;
153 memset(&items[tPtr->maxItems], 0, sizeof(WMTabViewItem*) * 10);
154 tPtr->items = items;
155 tPtr->maxItems += 10;
158 if (index > tPtr->itemCount)
159 index = tPtr->itemCount;
161 if (index == 0 && tPtr->items[0]) {
162 W_UnmapTabViewItem(tPtr->items[0]);
165 if (index < tPtr->itemCount) {
166 memmove(&tPtr->items[index + 1], &tPtr->items[index],
167 tPtr->itemCount - index);
170 tPtr->items[index] = item;
172 tPtr->itemCount++;
174 recalcTabWidth(tPtr);
176 W_SetTabViewItemParent(item, tPtr);
178 W_UnmapTabViewItem(item);
180 W_ReparentView(W_TabViewItemView(item), tPtr->view, 1,
181 tPtr->tabHeight + 1);
183 W_ResizeView(W_TabViewItemView(item), tPtr->view->size.width - 3,
184 tPtr->view->size.height - tPtr->tabHeight - 3);
186 if (index == 0) {
187 W_MapTabViewItem(item);
189 if (tPtr->delegate && tPtr->delegate->didChangeNumberOfItems)
190 (*tPtr->delegate->didChangeNumberOfItems)(tPtr->delegate, tPtr);
194 void
195 WMRemoveTabViewItem(WMTabView *tPtr, WMTabViewItem *item)
197 int i;
199 for (i = 0; i < tPtr->itemCount; i++) {
200 if (tPtr->items[i] == item) {
201 if (i < tPtr->itemCount - 1)
202 memmove(&tPtr->items[i], &tPtr->items[i + 1],
203 tPtr->itemCount - i - 1);
204 else
205 tPtr->items[i] = NULL;
207 W_SetTabViewItemParent(item, NULL);
209 tPtr->itemCount--;
210 break;
213 if (tPtr->delegate && tPtr->delegate->didChangeNumberOfItems)
214 (*tPtr->delegate->didChangeNumberOfItems)(tPtr->delegate, tPtr);
219 static Bool
220 isInside(int x, int y, int width, int height, int px, int py)
222 if (py >= y + height - 3 && py <= y + height
223 && px >= x + py - (y + height - 3)
224 && px <= x + width - (py - (y + height - 3))) {
226 return True;
228 if (py >= y + 3 && py < y + height - 3
229 && px >= x + 3 + ((y + 3) - py)*3/7
230 && px <= x + width - 3 - ((y + 3) - py)*3/7) {
232 return True;
234 if (py >= y && py < y + 3
235 && px >= x + 7 + py - y
236 && px <= x + width - 7 - (py - y)) {
238 return True;
240 return False;
244 WMTabViewItem*
245 WMTabViewItemAtPoint(WMTabView *tPtr, int x, int y)
247 int i;
249 i = tPtr->selectedItem;
250 if (isInside(8 + (tPtr->tabWidth-10)*i, 0, tPtr->tabWidth,
251 tPtr->tabHeight, x, y)) {
252 return tPtr->items[i];
255 for (i = 0; i < tPtr->itemCount; i++) {
256 if (isInside(8 + (tPtr->tabWidth-10)*i, 0, tPtr->tabWidth,
257 tPtr->tabHeight, x, y)) {
258 return tPtr->items[i];
261 return NULL;
265 void
266 WMSelectFirstTabViewItem(WMTabView *tPtr)
268 WMSelectTabViewItemAtIndex(tPtr, 0);
272 void
273 WMSelectLastTabViewItem(WMTabView *tPtr)
275 WMSelectTabViewItemAtIndex(tPtr, tPtr->itemCount);
279 void
280 WMSelectNextTabViewItem(WMTabView *tPtr)
282 WMSelectTabViewItemAtIndex(tPtr, tPtr->selectedItem + 1);
286 void
287 WMSelectPreviousTabViewItem(WMTabView *tPtr)
289 WMSelectTabViewItemAtIndex(tPtr, tPtr->selectedItem - 1);
293 WMTabViewItem*
294 WMGetSelectedTabViewItem(WMTabView *tPtr)
296 return tPtr->items[tPtr->selectedItem];
300 void
301 WMSelectTabViewItem(WMTabView *tPtr, WMTabViewItem *item)
303 int i;
305 for (i = 0; i < tPtr->itemCount; i++) {
306 if (tPtr->items[i] == item) {
307 WMSelectTabViewItemAtIndex(tPtr, i);
308 break;
314 void
315 WMSelectTabViewItemAtIndex(WMTabView *tPtr, int index)
317 WMTabViewItem *item;
319 if (index == tPtr->selectedItem)
320 return;
322 if (index < 0)
323 index = 0;
324 else if (index >= tPtr->itemCount)
325 index = tPtr->itemCount - 1;
327 item = tPtr->items[tPtr->selectedItem];
329 if (tPtr->delegate && tPtr->delegate->shouldSelectItem)
330 if (!(*tPtr->delegate->shouldSelectItem)(tPtr->delegate, tPtr,
331 tPtr->items[index]))
332 return;
334 if (tPtr->delegate && tPtr->delegate->willSelectItem)
335 (*tPtr->delegate->willSelectItem)(tPtr->delegate, tPtr,
336 tPtr->items[index]);
338 W_UnmapTabViewItem(item);
341 item = tPtr->items[index];
343 W_MapTabViewItem(item);
345 tPtr->selectedItem = index;
347 if (tPtr->delegate && tPtr->delegate->didSelectItem)
348 (*tPtr->delegate->didSelectItem)(tPtr->delegate, tPtr,
349 tPtr->items[index]);
353 static void
354 recalcTabWidth(TabView *tPtr)
356 int i;
357 int twidth = W_VIEW(tPtr)->size.width;
358 int width;
360 tPtr->tabWidth = 0;
361 for (i = 0; i < tPtr->itemCount; i++) {
362 char *str = WMGetTabViewItemLabel(tPtr->items[i]);
364 if (str) {
365 width = WMWidthOfString(tPtr->font, str, strlen(str));
366 if (width > tPtr->tabWidth)
367 tPtr->tabWidth = width;
370 tPtr->tabWidth += 30;
371 if (tPtr->tabWidth > twidth - 10 * tPtr->itemCount
372 && tPtr->tabWidth < twidth - 16)
373 tPtr->tabWidth = (twidth - 16) / tPtr->itemCount;
377 static void
378 drawRelief(W_Screen *scr, Drawable d, int x, int y, unsigned int width,
379 unsigned int height)
381 Display *dpy = scr->display;
382 GC bgc = WMColorGC(scr->black);
383 GC wgc = WMColorGC(scr->white);
384 GC dgc = WMColorGC(scr->darkGray);
386 XDrawLine(dpy, d, wgc, x, y, x, y+height-1);
388 XDrawLine(dpy, d, bgc, x, y+height-1, x+width-1, y+height-1);
389 XDrawLine(dpy, d, dgc, x+1, y+height-2, x+width-2, y+height-2);
391 XDrawLine(dpy, d, bgc, x+width-1, y, x+width-1, y+height-1);
392 XDrawLine(dpy, d, dgc, x+width-2, y+1, x+width-2, y+height-2);
396 static void
397 drawTab(TabView *tPtr, Drawable d, int x, int y,
398 unsigned width, unsigned height, Bool selected)
400 WMScreen *scr = W_VIEW(tPtr)->screen;
401 Display *dpy = scr->display;
402 GC white = WMColorGC(selected ? scr->white : tPtr->lightGray);
403 GC black = WMColorGC(scr->black);
404 GC dark = WMColorGC(scr->darkGray);
405 GC light = WMColorGC(scr->gray);
406 XPoint trap[8];
408 trap[0].x = x + (selected ? 0 : 1);
409 trap[0].y = y + height - (selected ? 0 : 1);
411 trap[1].x = x + 3;
412 trap[1].y = y + height - 3;
414 trap[2].x = x + 10 - 3;
415 trap[2].y = y + 3;
417 trap[3].x = x + 10;
418 trap[3].y = y;
420 trap[4].x = x + width - 10;
421 trap[4].y = y;
423 trap[5].x = x + width - 10 + 3;
424 trap[5].y = y + 3;
426 trap[6].x = x + width - 3;
427 trap[6].y = y + height - 3;
429 trap[7].x = x + width - (selected ? 0 : 1);
430 trap[7].y = y + height - (selected ? 0 : 1);
432 XFillPolygon(dpy, d, selected ? light : WMColorGC(tPtr->tabColor), trap, 8,
433 Convex, CoordModeOrigin);
435 XDrawLine(dpy, d, white, trap[0].x, trap[0].y, trap[1].x, trap[1].y);
436 XDrawLine(dpy, d, white, trap[1].x, trap[1].y, trap[2].x, trap[2].y);
437 XDrawLine(dpy, d, white, trap[2].x, trap[2].y, trap[3].x, trap[3].y);
438 XDrawLine(dpy, d, white, trap[3].x, trap[3].y, trap[4].x, trap[4].y);
439 XDrawLine(dpy, d, dark, trap[4].x, trap[4].y, trap[5].x, trap[5].y);
440 XDrawLine(dpy, d, black, trap[5].x, trap[5].y, trap[6].x, trap[6].y);
441 XDrawLine(dpy, d, black, trap[6].x, trap[6].y, trap[7].x, trap[7].y);
443 XDrawLine(dpy, d, selected ? light : WMColorGC(scr->white),
444 trap[0].x, trap[0].y, trap[7].x, trap[7].y);
448 static void
449 paintTabView(TabView *tPtr)
451 Pixmap buffer;
452 WMScreen *scr = W_VIEW(tPtr)->screen;
453 Display *dpy = scr->display;
454 GC white = WMColorGC(scr->white);
455 int i;
456 WMRect rect;
458 if (tPtr->flags.type == WTTopTabsBevelBorder) {
459 buffer = XCreatePixmap(dpy, W_VIEW(tPtr)->window,
460 W_VIEW(tPtr)->size.width, tPtr->tabHeight,
461 W_VIEW(tPtr)->screen->depth);
463 XFillRectangle(dpy, buffer, WMColorGC(W_VIEW(tPtr)->backColor),
464 0, 0, W_VIEW(tPtr)->size.width, tPtr->tabHeight);
466 rect.pos.x = 8 + 15;
467 rect.pos.y = 2;
468 rect.size.width = tPtr->tabWidth;
469 rect.size.height = tPtr->tabHeight;
471 for (i = tPtr->itemCount - 1; i >= 0; i--) {
472 if (i != tPtr->selectedItem) {
473 drawTab(tPtr, buffer, 8 + (rect.size.width-10)*i, 0,
474 rect.size.width, rect.size.height, False);
477 drawTab(tPtr, buffer, 8 + (rect.size.width-10) * tPtr->selectedItem,
478 0, rect.size.width, rect.size.height, True);
480 XDrawLine(dpy, buffer, white, 0, tPtr->tabHeight - 1,
481 8, tPtr->tabHeight - 1);
483 XDrawLine(dpy, buffer, white,
484 8 + 10 + (rect.size.width-10) * tPtr->itemCount,
485 tPtr->tabHeight - 1, W_VIEW(tPtr)->size.width - 1,
486 tPtr->tabHeight - 1);
489 for (i = 0; i < tPtr->itemCount; i++) {
490 W_DrawLabel(tPtr->items[i], buffer, rect);
492 rect.pos.x += rect.size.width - 10;
495 XCopyArea(dpy, buffer, W_VIEW(tPtr)->window, scr->copyGC, 0, 0,
496 W_VIEW(tPtr)->size.width, tPtr->tabHeight, 0, 0);
498 XFreePixmap(dpy, buffer);
500 switch (tPtr->flags.type) {
501 case WTTopTabsBevelBorder:
502 drawRelief(scr, W_VIEW(tPtr)->window, 0, tPtr->tabHeight - 1,
503 W_VIEW(tPtr)->size.width,
504 W_VIEW(tPtr)->size.height - tPtr->tabHeight + 1);
505 break;
507 case WTNoTabsBevelBorder:
508 W_DrawRelief(scr, W_VIEW(tPtr)->window, 0, 0, W_VIEW(tPtr)->size.width,
509 W_VIEW(tPtr)->size.height, WRRaised);
510 break;
512 case WTNoTabsLineBorder:
513 W_DrawRelief(scr, W_VIEW(tPtr)->window, 0, 0, W_VIEW(tPtr)->size.width,
514 W_VIEW(tPtr)->size.height, WRSimple);
515 break;
517 case WTNoTabsNoBorder:
518 break;
523 static void
524 destroyTabView(TabView *tPtr)
526 int i;
528 for (i = 0; i < tPtr->itemCount; i++) {
529 WMSetTabViewItemView(tPtr->items[i], NULL);
530 WMDestroyTabViewItem(tPtr->items[i]);
532 free(tPtr->items);
534 WMReleaseColor(tPtr->lightGray);
535 WMReleaseColor(tPtr->tabColor);
536 WMReleaseFont(tPtr->font);
538 free(tPtr);
541 /******************************************************************/
544 typedef struct W_TabViewItem {
545 WMTabView *tabView;
547 W_View *view;
549 char *label;
551 int identifier;
553 struct {
554 unsigned visible:1;
555 } flags;
556 } TabViewItem;
559 static void
560 W_SetTabViewItemParent(WMTabViewItem *item, WMTabView *parent)
562 item->tabView = parent;
566 static void
567 W_DrawLabel(WMTabViewItem *item, Drawable d, WMRect rect)
569 WMScreen *scr = W_VIEW(item->tabView)->screen;
571 if (!item->label)
572 return;
574 WMDrawString(scr, d, WMColorGC(scr->black), item->tabView->font,
575 rect.pos.x, rect.pos.y, item->label, strlen(item->label));
579 static void
580 W_UnmapTabViewItem(WMTabViewItem *item)
582 wassertr(item->view);
584 W_UnmapView(item->view);
586 item->flags.visible = 0;
590 static void
591 W_MapTabViewItem(WMTabViewItem *item)
593 wassertr(item->view);
595 W_MapView(item->view);
597 item->flags.visible = 1;
601 static WMView*
602 W_TabViewItemView(WMTabViewItem *item)
604 return item->view;
608 WMTabViewItem*
609 WMCreateTabViewItemWithIdentifier(int identifier)
611 WMTabViewItem *item;
613 item = wmalloc(sizeof(WMTabViewItem));
614 memset(item, 0, sizeof(WMTabViewItem));
616 item->identifier = identifier;
618 return item;
623 WMGetTabViewItemIdentifier(WMTabViewItem *item)
625 return item->identifier;
629 void
630 WMSetTabViewFont(WMTabView *tPtr, WMFont *font)
632 if (tPtr->font)
633 WMReleaseFont(tPtr->font);
635 tPtr->font = WMRetainFont(font);
636 tPtr->tabHeight = WMFontHeight(tPtr->font) + 3;
637 recalcTabWidth(tPtr);
641 void
642 WMSetTabViewItemLabel(WMTabViewItem *item, char *label)
644 if (item->label)
645 free(item->label);
647 item->label = wstrdup(label);
649 if (item->tabView)
650 recalcTabWidth(item->tabView);
654 char*
655 WMGetTabViewItemLabel(WMTabViewItem *item)
657 return item->label;
661 void
662 WMSetTabViewItemView(WMTabViewItem *item, WMView *view)
664 item->view = view;
668 WMView*
669 WMGetTabViewItemView(WMTabViewItem *item)
671 return item->view;
675 void
676 WMDestroyTabViewItem(WMTabViewItem *item)
678 if (item->label)
679 free(item->label);
681 if (item->view)
682 W_DestroyView(item->view);
684 free(item);