Fixed wrealloc() to be consistent with the wmalloc() behaviour when it cannot
[wmaker-crm.git] / WINGs / wtabview.c
blob1cb520f2b3550a8da12ef75f2a60f30fdee0a97f
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 wfree(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 memset(&items[tPtr->maxItems], 0, sizeof(WMTabViewItem*) * 10);
150 tPtr->items = items;
151 tPtr->maxItems += 10;
154 if (index > tPtr->itemCount)
155 index = tPtr->itemCount;
157 if (index == 0 && tPtr->items[0]) {
158 W_UnmapTabViewItem(tPtr->items[0]);
161 if (index < tPtr->itemCount) {
162 memmove(&tPtr->items[index + 1], &tPtr->items[index],
163 tPtr->itemCount - index);
166 tPtr->items[index] = item;
168 tPtr->itemCount++;
170 recalcTabWidth(tPtr);
172 W_SetTabViewItemParent(item, tPtr);
174 W_UnmapTabViewItem(item);
176 W_ReparentView(W_TabViewItemView(item), tPtr->view, 1,
177 tPtr->tabHeight + 1);
179 W_ResizeView(W_TabViewItemView(item), tPtr->view->size.width - 3,
180 tPtr->view->size.height - tPtr->tabHeight - 3);
182 if (index == 0) {
183 W_MapTabViewItem(item);
185 if (tPtr->delegate && tPtr->delegate->didChangeNumberOfItems)
186 (*tPtr->delegate->didChangeNumberOfItems)(tPtr->delegate, tPtr);
190 void
191 WMRemoveTabViewItem(WMTabView *tPtr, WMTabViewItem *item)
193 int i;
195 for (i = 0; i < tPtr->itemCount; i++) {
196 if (tPtr->items[i] == item) {
197 if (i < tPtr->itemCount - 1)
198 memmove(&tPtr->items[i], &tPtr->items[i + 1],
199 tPtr->itemCount - i - 1);
200 else
201 tPtr->items[i] = NULL;
203 W_SetTabViewItemParent(item, NULL);
205 tPtr->itemCount--;
206 break;
209 if (tPtr->delegate && tPtr->delegate->didChangeNumberOfItems)
210 (*tPtr->delegate->didChangeNumberOfItems)(tPtr->delegate, tPtr);
215 static Bool
216 isInside(int x, int y, int width, int height, int px, int py)
218 if (py >= y + height - 3 && py <= y + height
219 && px >= x + py - (y + height - 3)
220 && px <= x + width - (py - (y + height - 3))) {
222 return True;
224 if (py >= y + 3 && py < y + height - 3
225 && px >= x + 3 + ((y + 3) - py)*3/7
226 && px <= x + width - 3 - ((y + 3) - py)*3/7) {
228 return True;
230 if (py >= y && py < y + 3
231 && px >= x + 7 + py - y
232 && px <= x + width - 7 - (py - y)) {
234 return True;
236 return False;
240 WMTabViewItem*
241 WMTabViewItemAtPoint(WMTabView *tPtr, int x, int y)
243 int i;
245 i = tPtr->selectedItem;
246 if (isInside(8 + (tPtr->tabWidth-10)*i, 0, tPtr->tabWidth,
247 tPtr->tabHeight, x, y)) {
248 return tPtr->items[i];
251 for (i = 0; i < tPtr->itemCount; i++) {
252 if (isInside(8 + (tPtr->tabWidth-10)*i, 0, tPtr->tabWidth,
253 tPtr->tabHeight, x, y)) {
254 return tPtr->items[i];
257 return NULL;
261 void
262 WMSelectFirstTabViewItem(WMTabView *tPtr)
264 WMSelectTabViewItemAtIndex(tPtr, 0);
268 void
269 WMSelectLastTabViewItem(WMTabView *tPtr)
271 WMSelectTabViewItemAtIndex(tPtr, tPtr->itemCount);
275 void
276 WMSelectNextTabViewItem(WMTabView *tPtr)
278 WMSelectTabViewItemAtIndex(tPtr, tPtr->selectedItem + 1);
282 void
283 WMSelectPreviousTabViewItem(WMTabView *tPtr)
285 WMSelectTabViewItemAtIndex(tPtr, tPtr->selectedItem - 1);
289 WMTabViewItem*
290 WMGetSelectedTabViewItem(WMTabView *tPtr)
292 return tPtr->items[tPtr->selectedItem];
296 void
297 WMSelectTabViewItem(WMTabView *tPtr, WMTabViewItem *item)
299 int i;
301 for (i = 0; i < tPtr->itemCount; i++) {
302 if (tPtr->items[i] == item) {
303 WMSelectTabViewItemAtIndex(tPtr, i);
304 break;
310 void
311 WMSelectTabViewItemAtIndex(WMTabView *tPtr, int index)
313 WMTabViewItem *item;
315 if (index == tPtr->selectedItem)
316 return;
318 if (index < 0)
319 index = 0;
320 else if (index >= tPtr->itemCount)
321 index = tPtr->itemCount - 1;
323 item = tPtr->items[tPtr->selectedItem];
325 if (tPtr->delegate && tPtr->delegate->shouldSelectItem)
326 if (!(*tPtr->delegate->shouldSelectItem)(tPtr->delegate, tPtr,
327 tPtr->items[index]))
328 return;
330 if (tPtr->delegate && tPtr->delegate->willSelectItem)
331 (*tPtr->delegate->willSelectItem)(tPtr->delegate, tPtr,
332 tPtr->items[index]);
334 W_UnmapTabViewItem(item);
337 item = tPtr->items[index];
339 W_MapTabViewItem(item);
341 tPtr->selectedItem = index;
343 if (tPtr->delegate && tPtr->delegate->didSelectItem)
344 (*tPtr->delegate->didSelectItem)(tPtr->delegate, tPtr,
345 tPtr->items[index]);
349 static void
350 recalcTabWidth(TabView *tPtr)
352 int i;
353 int twidth = W_VIEW(tPtr)->size.width;
354 int width;
356 tPtr->tabWidth = 0;
357 for (i = 0; i < tPtr->itemCount; i++) {
358 char *str = WMGetTabViewItemLabel(tPtr->items[i]);
360 if (str) {
361 width = WMWidthOfString(tPtr->font, str, strlen(str));
362 if (width > tPtr->tabWidth)
363 tPtr->tabWidth = width;
366 tPtr->tabWidth += 30;
367 if (tPtr->tabWidth > twidth - 10 * tPtr->itemCount
368 && tPtr->tabWidth < twidth - 16)
369 tPtr->tabWidth = (twidth - 16) / tPtr->itemCount;
373 static void
374 drawRelief(W_Screen *scr, Drawable d, int x, int y, unsigned int width,
375 unsigned int height)
377 Display *dpy = scr->display;
378 GC bgc = WMColorGC(scr->black);
379 GC wgc = WMColorGC(scr->white);
380 GC dgc = WMColorGC(scr->darkGray);
382 XDrawLine(dpy, d, wgc, x, y, x, y+height-1);
384 XDrawLine(dpy, d, bgc, x, y+height-1, x+width-1, y+height-1);
385 XDrawLine(dpy, d, dgc, x+1, y+height-2, x+width-2, y+height-2);
387 XDrawLine(dpy, d, bgc, x+width-1, y, x+width-1, y+height-1);
388 XDrawLine(dpy, d, dgc, x+width-2, y+1, x+width-2, y+height-2);
392 static void
393 drawTab(TabView *tPtr, Drawable d, int x, int y,
394 unsigned width, unsigned height, Bool selected)
396 WMScreen *scr = W_VIEW(tPtr)->screen;
397 Display *dpy = scr->display;
398 GC white = WMColorGC(selected ? scr->white : tPtr->lightGray);
399 GC black = WMColorGC(scr->black);
400 GC dark = WMColorGC(scr->darkGray);
401 GC light = WMColorGC(scr->gray);
402 XPoint trap[8];
404 trap[0].x = x + (selected ? 0 : 1);
405 trap[0].y = y + height - (selected ? 0 : 1);
407 trap[1].x = x + 3;
408 trap[1].y = y + height - 3;
410 trap[2].x = x + 10 - 3;
411 trap[2].y = y + 3;
413 trap[3].x = x + 10;
414 trap[3].y = y;
416 trap[4].x = x + width - 10;
417 trap[4].y = y;
419 trap[5].x = x + width - 10 + 3;
420 trap[5].y = y + 3;
422 trap[6].x = x + width - 3;
423 trap[6].y = y + height - 3;
425 trap[7].x = x + width - (selected ? 0 : 1);
426 trap[7].y = y + height - (selected ? 0 : 1);
428 XFillPolygon(dpy, d, selected ? light : WMColorGC(tPtr->tabColor), trap, 8,
429 Convex, CoordModeOrigin);
431 XDrawLine(dpy, d, white, trap[0].x, trap[0].y, trap[1].x, trap[1].y);
432 XDrawLine(dpy, d, white, trap[1].x, trap[1].y, trap[2].x, trap[2].y);
433 XDrawLine(dpy, d, white, trap[2].x, trap[2].y, trap[3].x, trap[3].y);
434 XDrawLine(dpy, d, white, trap[3].x, trap[3].y, trap[4].x, trap[4].y);
435 XDrawLine(dpy, d, dark, trap[4].x, trap[4].y, trap[5].x, trap[5].y);
436 XDrawLine(dpy, d, black, trap[5].x, trap[5].y, trap[6].x, trap[6].y);
437 XDrawLine(dpy, d, black, trap[6].x, trap[6].y, trap[7].x, trap[7].y);
439 XDrawLine(dpy, d, selected ? light : WMColorGC(scr->white),
440 trap[0].x, trap[0].y, trap[7].x, trap[7].y);
444 static void
445 paintTabView(TabView *tPtr)
447 Pixmap buffer;
448 WMScreen *scr = W_VIEW(tPtr)->screen;
449 Display *dpy = scr->display;
450 GC white = WMColorGC(scr->white);
451 int i;
452 WMRect rect;
454 if (tPtr->flags.type == WTTopTabsBevelBorder) {
455 buffer = XCreatePixmap(dpy, W_VIEW(tPtr)->window,
456 W_VIEW(tPtr)->size.width, tPtr->tabHeight,
457 W_VIEW(tPtr)->screen->depth);
459 XFillRectangle(dpy, buffer, WMColorGC(W_VIEW(tPtr)->backColor),
460 0, 0, W_VIEW(tPtr)->size.width, tPtr->tabHeight);
462 rect.pos.x = 8 + 15;
463 rect.pos.y = 2;
464 rect.size.width = tPtr->tabWidth;
465 rect.size.height = tPtr->tabHeight;
467 for (i = tPtr->itemCount - 1; i >= 0; i--) {
468 if (i != tPtr->selectedItem) {
469 drawTab(tPtr, buffer, 8 + (rect.size.width-10)*i, 0,
470 rect.size.width, rect.size.height, False);
473 drawTab(tPtr, buffer, 8 + (rect.size.width-10) * tPtr->selectedItem,
474 0, rect.size.width, rect.size.height, True);
476 XDrawLine(dpy, buffer, white, 0, tPtr->tabHeight - 1,
477 8, tPtr->tabHeight - 1);
479 XDrawLine(dpy, buffer, white,
480 8 + 10 + (rect.size.width-10) * tPtr->itemCount,
481 tPtr->tabHeight - 1, W_VIEW(tPtr)->size.width - 1,
482 tPtr->tabHeight - 1);
485 for (i = 0; i < tPtr->itemCount; i++) {
486 W_DrawLabel(tPtr->items[i], buffer, rect);
488 rect.pos.x += rect.size.width - 10;
491 XCopyArea(dpy, buffer, W_VIEW(tPtr)->window, scr->copyGC, 0, 0,
492 W_VIEW(tPtr)->size.width, tPtr->tabHeight, 0, 0);
494 XFreePixmap(dpy, buffer);
496 switch (tPtr->flags.type) {
497 case WTTopTabsBevelBorder:
498 drawRelief(scr, W_VIEW(tPtr)->window, 0, tPtr->tabHeight - 1,
499 W_VIEW(tPtr)->size.width,
500 W_VIEW(tPtr)->size.height - tPtr->tabHeight + 1);
501 break;
503 case WTNoTabsBevelBorder:
504 W_DrawRelief(scr, W_VIEW(tPtr)->window, 0, 0, W_VIEW(tPtr)->size.width,
505 W_VIEW(tPtr)->size.height, WRRaised);
506 break;
508 case WTNoTabsLineBorder:
509 W_DrawRelief(scr, W_VIEW(tPtr)->window, 0, 0, W_VIEW(tPtr)->size.width,
510 W_VIEW(tPtr)->size.height, WRSimple);
511 break;
513 case WTNoTabsNoBorder:
514 break;
519 static void
520 destroyTabView(TabView *tPtr)
522 int i;
524 for (i = 0; i < tPtr->itemCount; i++) {
525 WMSetTabViewItemView(tPtr->items[i], NULL);
526 WMDestroyTabViewItem(tPtr->items[i]);
528 wfree(tPtr->items);
530 WMReleaseColor(tPtr->lightGray);
531 WMReleaseColor(tPtr->tabColor);
532 WMReleaseFont(tPtr->font);
534 wfree(tPtr);
537 /******************************************************************/
540 typedef struct W_TabViewItem {
541 WMTabView *tabView;
543 W_View *view;
545 char *label;
547 int identifier;
549 struct {
550 unsigned visible:1;
551 } flags;
552 } TabViewItem;
555 static void
556 W_SetTabViewItemParent(WMTabViewItem *item, WMTabView *parent)
558 item->tabView = parent;
562 static void
563 W_DrawLabel(WMTabViewItem *item, Drawable d, WMRect rect)
565 WMScreen *scr = W_VIEW(item->tabView)->screen;
567 if (!item->label)
568 return;
570 WMDrawString(scr, d, WMColorGC(scr->black), item->tabView->font,
571 rect.pos.x, rect.pos.y, item->label, strlen(item->label));
575 static void
576 W_UnmapTabViewItem(WMTabViewItem *item)
578 wassertr(item->view);
580 W_UnmapView(item->view);
582 item->flags.visible = 0;
586 static void
587 W_MapTabViewItem(WMTabViewItem *item)
589 wassertr(item->view);
591 W_MapView(item->view);
593 item->flags.visible = 1;
597 static WMView*
598 W_TabViewItemView(WMTabViewItem *item)
600 return item->view;
604 WMTabViewItem*
605 WMCreateTabViewItemWithIdentifier(int identifier)
607 WMTabViewItem *item;
609 item = wmalloc(sizeof(WMTabViewItem));
610 memset(item, 0, sizeof(WMTabViewItem));
612 item->identifier = identifier;
614 return item;
619 WMGetTabViewItemIdentifier(WMTabViewItem *item)
621 return item->identifier;
625 void
626 WMSetTabViewFont(WMTabView *tPtr, WMFont *font)
628 if (tPtr->font)
629 WMReleaseFont(tPtr->font);
631 tPtr->font = WMRetainFont(font);
632 tPtr->tabHeight = WMFontHeight(tPtr->font) + 3;
633 recalcTabWidth(tPtr);
637 void
638 WMSetTabViewItemLabel(WMTabViewItem *item, char *label)
640 if (item->label)
641 wfree(item->label);
643 item->label = wstrdup(label);
645 if (item->tabView)
646 recalcTabWidth(item->tabView);
650 char*
651 WMGetTabViewItemLabel(WMTabViewItem *item)
653 return item->label;
657 void
658 WMSetTabViewItemView(WMTabViewItem *item, WMView *view)
660 item->view = view;
664 WMView*
665 WMGetTabViewItemView(WMTabViewItem *item)
667 return item->view;
671 void
672 WMDestroyTabViewItem(WMTabViewItem *item)
674 if (item->label)
675 wfree(item->label);
677 if (item->view)
678 W_DestroyView(item->view);
680 wfree(item);