bug fixes.
[wmaker-crm.git] / WINGs / wtabview.c
blob787c1b971afff9f795c1eca9bb259bdcec739956
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 struct W_ViewProcedureTable _TabViewViewProcedures = {
38 NULL,
39 NULL,
40 NULL
44 #define DEFAULT_WIDTH 40
45 #define DEFAULT_HEIGHT 40
48 static void destroyTabView(TabView *tPtr);
49 static void paintTabView(TabView *tPtr);
52 static void W_SetTabViewItemParent(WMTabViewItem *item, WMTabView *parent);
54 static void W_DrawLabel(WMTabViewItem *item, Drawable d, WMRect rect);
56 static void W_UnmapTabViewItem(WMTabViewItem *item);
58 static void W_MapTabViewItem(WMTabViewItem *item);
60 static WMView *W_TabViewItemView(WMTabViewItem *item);
62 static void recalcTabWidth(TabView *tPtr);
65 static void
66 handleEvents(XEvent *event, void *data)
68 TabView *tPtr = (TabView*)data;
70 CHECK_CLASS(data, WC_TabView);
72 switch (event->type) {
73 case Expose:
74 if (event->xexpose.count!=0)
75 break;
76 paintTabView(tPtr);
77 break;
79 case ButtonPress:
81 WMTabViewItem *item = WMTabViewItemAtPoint(tPtr,
82 event->xbutton.x,
83 event->xbutton.y);
84 if (item) {
85 WMSelectTabViewItem(tPtr, item);
88 break;
90 case DestroyNotify:
91 destroyTabView(tPtr);
92 break;
98 WMTabView*
99 WMCreateTabView(WMWidget *parent)
101 TabView *tPtr;
102 WMScreen *scr = WMWidgetScreen(parent);
104 tPtr = wmalloc(sizeof(TabView));
105 memset(tPtr, 0, sizeof(TabView));
107 tPtr->widgetClass = WC_TabView;
109 tPtr->view = W_CreateView(W_VIEW(parent));
110 if (!tPtr->view) {
111 free(tPtr);
112 return NULL;
114 tPtr->view->self = tPtr;
116 tPtr->lightGray = WMCreateRGBColor(scr, 0xd9d9, 0xd9d9, 0xd9d9, False);
117 tPtr->tabColor = WMCreateRGBColor(scr, 0x8420, 0x8420, 0x8420, False);
119 tPtr->font = WMRetainFont(scr->normalFont);
121 WMCreateEventHandler(tPtr->view, ExposureMask|StructureNotifyMask
122 |ButtonPressMask, handleEvents, tPtr);
124 WMResizeWidget(tPtr, DEFAULT_WIDTH, DEFAULT_HEIGHT);
126 tPtr->tabHeight = WMFontHeight(tPtr->font) + 3;
128 return tPtr;
132 void
133 WMSetTabViewDelegate(WMTabView *tPtr, WMTabViewDelegate *delegate)
135 tPtr->delegate = delegate;
139 void
140 WMAddItemInTabView(WMTabView *tPtr, WMTabViewItem *item)
142 WMInsertItemInTabView(tPtr, tPtr->itemCount, item);
146 void
147 WMInsertItemInTabView(WMTabView *tPtr, int index, WMTabViewItem *item)
149 wassertr(W_TabViewItemView(item) != NULL);
151 if (tPtr->maxItems == tPtr->itemCount) {
152 WMTabViewItem **items;
154 items = wrealloc(tPtr->items,
155 sizeof(WMTabViewItem*) * (tPtr->maxItems + 10));
156 if (!items) {
157 wwarning("out of memory allocating memory for tabview");
158 return;
160 memset(&items[tPtr->maxItems], 0, sizeof(WMTabViewItem*) * 10);
161 tPtr->items = items;
162 tPtr->maxItems += 10;
165 if (index > tPtr->itemCount)
166 index = tPtr->itemCount;
168 if (index == 0 && tPtr->items[0]) {
169 W_UnmapTabViewItem(tPtr->items[0]);
172 if (index < tPtr->itemCount) {
173 memmove(&tPtr->items[index + 1], &tPtr->items[index],
174 tPtr->itemCount - index);
177 tPtr->items[index] = item;
179 tPtr->itemCount++;
181 recalcTabWidth(tPtr);
183 W_SetTabViewItemParent(item, tPtr);
185 W_UnmapTabViewItem(item);
187 W_ReparentView(W_TabViewItemView(item), tPtr->view, 1,
188 tPtr->tabHeight + 1);
190 W_ResizeView(W_TabViewItemView(item), tPtr->view->size.width - 3,
191 tPtr->view->size.height - tPtr->tabHeight - 3);
193 if (index == 0) {
194 W_MapTabViewItem(item);
196 if (tPtr->delegate && tPtr->delegate->didChangeNumberOfItems)
197 (*tPtr->delegate->didChangeNumberOfItems)(tPtr->delegate, tPtr);
201 void
202 WMRemoveTabViewItem(WMTabView *tPtr, WMTabViewItem *item)
204 int i;
206 for (i = 0; i < tPtr->itemCount; i++) {
207 if (tPtr->items[i] == item) {
208 if (i < tPtr->itemCount - 1)
209 memmove(&tPtr->items[i], &tPtr->items[i + 1],
210 tPtr->itemCount - i - 1);
211 else
212 tPtr->items[i] = NULL;
214 W_SetTabViewItemParent(item, NULL);
216 tPtr->itemCount--;
217 break;
220 if (tPtr->delegate && tPtr->delegate->didChangeNumberOfItems)
221 (*tPtr->delegate->didChangeNumberOfItems)(tPtr->delegate, tPtr);
226 static Bool
227 isInside(int x, int y, int width, int height, int px, int py)
229 if (py >= y + height - 3 && py <= y + height
230 && px >= x + py - (y + height - 3)
231 && px <= x + width - (py - (y + height - 3))) {
233 return True;
235 if (py >= y + 3 && py < y + height - 3
236 && px >= x + 3 + ((y + 3) - py)*3/7
237 && px <= x + width - 3 - ((y + 3) - py)*3/7) {
239 return True;
241 if (py >= y && py < y + 3
242 && px >= x + 7 + py - y
243 && px <= x + width - 7 - (py - y)) {
245 return True;
247 return False;
251 WMTabViewItem*
252 WMTabViewItemAtPoint(WMTabView *tPtr, int x, int y)
254 int i;
256 i = tPtr->selectedItem;
257 if (isInside(8 + (tPtr->tabWidth-10)*i, 0, tPtr->tabWidth,
258 tPtr->tabHeight, x, y)) {
259 return tPtr->items[i];
262 for (i = 0; i < tPtr->itemCount; i++) {
263 if (isInside(8 + (tPtr->tabWidth-10)*i, 0, tPtr->tabWidth,
264 tPtr->tabHeight, x, y)) {
265 return tPtr->items[i];
268 return NULL;
272 void
273 WMSelectFirstTabViewItem(WMTabView *tPtr)
275 WMSelectTabViewItemAtIndex(tPtr, 0);
279 void
280 WMSelectLastTabViewItem(WMTabView *tPtr)
282 WMSelectTabViewItemAtIndex(tPtr, tPtr->itemCount);
286 void
287 WMSelectNextTabViewItem(WMTabView *tPtr)
289 WMSelectTabViewItemAtIndex(tPtr, tPtr->selectedItem + 1);
293 void
294 WMSelectPreviousTabViewItem(WMTabView *tPtr)
296 WMSelectTabViewItemAtIndex(tPtr, tPtr->selectedItem - 1);
300 WMTabViewItem*
301 WMGetSelectedTabViewItem(WMTabView *tPtr)
303 return tPtr->items[tPtr->selectedItem];
307 void
308 WMSelectTabViewItem(WMTabView *tPtr, WMTabViewItem *item)
310 int i;
312 for (i = 0; i < tPtr->itemCount; i++) {
313 if (tPtr->items[i] == item) {
314 WMSelectTabViewItemAtIndex(tPtr, i);
315 break;
321 void
322 WMSelectTabViewItemAtIndex(WMTabView *tPtr, int index)
324 WMTabViewItem *item;
326 if (index == tPtr->selectedItem)
327 return;
329 if (index < 0)
330 index = 0;
331 else if (index >= tPtr->itemCount)
332 index = tPtr->itemCount - 1;
334 item = tPtr->items[tPtr->selectedItem];
336 if (tPtr->delegate && tPtr->delegate->shouldSelectItem)
337 if (!(*tPtr->delegate->shouldSelectItem)(tPtr->delegate, tPtr,
338 tPtr->items[index]))
339 return;
341 if (tPtr->delegate && tPtr->delegate->willSelectItem)
342 (*tPtr->delegate->willSelectItem)(tPtr->delegate, tPtr,
343 tPtr->items[index]);
345 W_UnmapTabViewItem(item);
348 item = tPtr->items[index];
350 W_MapTabViewItem(item);
352 tPtr->selectedItem = index;
354 if (tPtr->delegate && tPtr->delegate->didSelectItem)
355 (*tPtr->delegate->didSelectItem)(tPtr->delegate, tPtr,
356 tPtr->items[index]);
360 static void
361 recalcTabWidth(TabView *tPtr)
363 int i;
364 int twidth = W_VIEW(tPtr)->size.width;
365 int width;
367 tPtr->tabWidth = 0;
368 for (i = 0; i < tPtr->itemCount; i++) {
369 char *str = WMGetTabViewItemLabel(tPtr->items[i]);
371 if (str) {
372 width = WMWidthOfString(tPtr->font, str, strlen(str));
373 if (width > tPtr->tabWidth)
374 tPtr->tabWidth = width;
377 tPtr->tabWidth += 30;
378 if (tPtr->tabWidth > twidth - 10 * tPtr->itemCount
379 && tPtr->tabWidth < twidth - 16)
380 tPtr->tabWidth = (twidth - 16) / tPtr->itemCount;
384 static void
385 drawRelief(W_Screen *scr, Drawable d, int x, int y, unsigned int width,
386 unsigned int height)
388 Display *dpy = scr->display;
389 GC bgc = WMColorGC(scr->black);
390 GC wgc = WMColorGC(scr->white);
391 GC dgc = WMColorGC(scr->darkGray);
393 XDrawLine(dpy, d, wgc, x, y, x, y+height-1);
395 XDrawLine(dpy, d, bgc, x, y+height-1, x+width-1, y+height-1);
396 XDrawLine(dpy, d, dgc, x+1, y+height-2, x+width-2, y+height-2);
398 XDrawLine(dpy, d, bgc, x+width-1, y, x+width-1, y+height-1);
399 XDrawLine(dpy, d, dgc, x+width-2, y+1, x+width-2, y+height-2);
403 static void
404 drawTab(TabView *tPtr, Drawable d, int x, int y,
405 unsigned width, unsigned height, Bool selected)
407 WMScreen *scr = W_VIEW(tPtr)->screen;
408 Display *dpy = scr->display;
409 GC white = WMColorGC(selected ? scr->white : tPtr->lightGray);
410 GC black = WMColorGC(scr->black);
411 GC dark = WMColorGC(scr->darkGray);
412 GC light = WMColorGC(scr->gray);
413 XPoint trap[8];
415 trap[0].x = x + (selected ? 0 : 1);
416 trap[0].y = y + height - (selected ? 0 : 1);
418 trap[1].x = x + 3;
419 trap[1].y = y + height - 3;
421 trap[2].x = x + 10 - 3;
422 trap[2].y = y + 3;
424 trap[3].x = x + 10;
425 trap[3].y = y;
427 trap[4].x = x + width - 10;
428 trap[4].y = y;
430 trap[5].x = x + width - 10 + 3;
431 trap[5].y = y + 3;
433 trap[6].x = x + width - 3;
434 trap[6].y = y + height - 3;
436 trap[7].x = x + width - (selected ? 0 : 1);
437 trap[7].y = y + height - (selected ? 0 : 1);
439 XFillPolygon(dpy, d, selected ? light : WMColorGC(tPtr->tabColor), trap, 8,
440 Convex, CoordModeOrigin);
442 XDrawLine(dpy, d, white, trap[0].x, trap[0].y, trap[1].x, trap[1].y);
443 XDrawLine(dpy, d, white, trap[1].x, trap[1].y, trap[2].x, trap[2].y);
444 XDrawLine(dpy, d, white, trap[2].x, trap[2].y, trap[3].x, trap[3].y);
445 XDrawLine(dpy, d, white, trap[3].x, trap[3].y, trap[4].x, trap[4].y);
446 XDrawLine(dpy, d, dark, trap[4].x, trap[4].y, trap[5].x, trap[5].y);
447 XDrawLine(dpy, d, black, trap[5].x, trap[5].y, trap[6].x, trap[6].y);
448 XDrawLine(dpy, d, black, trap[6].x, trap[6].y, trap[7].x, trap[7].y);
450 XDrawLine(dpy, d, selected ? light : WMColorGC(scr->white),
451 trap[0].x, trap[0].y, trap[7].x, trap[7].y);
455 static void
456 paintTabView(TabView *tPtr)
458 Pixmap buffer;
459 WMScreen *scr = W_VIEW(tPtr)->screen;
460 Display *dpy = scr->display;
461 GC white = WMColorGC(scr->white);
462 int i;
463 WMRect rect;
465 if (tPtr->flags.type == WTTopTabsBevelBorder) {
466 buffer = XCreatePixmap(dpy, W_VIEW(tPtr)->window,
467 W_VIEW(tPtr)->size.width, tPtr->tabHeight,
468 W_VIEW(tPtr)->screen->depth);
470 XFillRectangle(dpy, buffer, WMColorGC(W_VIEW(tPtr)->backColor),
471 0, 0, W_VIEW(tPtr)->size.width, tPtr->tabHeight);
473 rect.pos.x = 8 + 15;
474 rect.pos.y = 2;
475 rect.size.width = tPtr->tabWidth;
476 rect.size.height = tPtr->tabHeight;
478 for (i = tPtr->itemCount - 1; i >= 0; i--) {
479 if (i != tPtr->selectedItem) {
480 drawTab(tPtr, buffer, 8 + (rect.size.width-10)*i, 0,
481 rect.size.width, rect.size.height, False);
484 drawTab(tPtr, buffer, 8 + (rect.size.width-10) * tPtr->selectedItem,
485 0, rect.size.width, rect.size.height, True);
487 XDrawLine(dpy, buffer, white, 0, tPtr->tabHeight - 1,
488 8, tPtr->tabHeight - 1);
490 XDrawLine(dpy, buffer, white,
491 8 + 10 + (rect.size.width-10) * tPtr->itemCount,
492 tPtr->tabHeight - 1, W_VIEW(tPtr)->size.width - 1,
493 tPtr->tabHeight - 1);
496 for (i = 0; i < tPtr->itemCount; i++) {
497 W_DrawLabel(tPtr->items[i], buffer, rect);
499 rect.pos.x += rect.size.width - 10;
502 XCopyArea(dpy, buffer, W_VIEW(tPtr)->window, scr->copyGC, 0, 0,
503 W_VIEW(tPtr)->size.width, tPtr->tabHeight, 0, 0);
505 XFreePixmap(dpy, buffer);
507 switch (tPtr->flags.type) {
508 case WTTopTabsBevelBorder:
509 drawRelief(scr, W_VIEW(tPtr)->window, 0, tPtr->tabHeight - 1,
510 W_VIEW(tPtr)->size.width,
511 W_VIEW(tPtr)->size.height - tPtr->tabHeight + 1);
512 break;
514 case WTNoTabsBevelBorder:
515 W_DrawRelief(scr, W_VIEW(tPtr)->window, 0, 0, W_VIEW(tPtr)->size.width,
516 W_VIEW(tPtr)->size.height, WRRaised);
517 break;
519 case WTNoTabsLineBorder:
520 W_DrawRelief(scr, W_VIEW(tPtr)->window, 0, 0, W_VIEW(tPtr)->size.width,
521 W_VIEW(tPtr)->size.height, WRSimple);
522 break;
524 case WTNoTabsNoBorder:
525 break;
530 static void
531 destroyTabView(TabView *tPtr)
533 int i;
535 for (i = 0; i < tPtr->itemCount; i++) {
536 WMSetTabViewItemView(tPtr->items[i], NULL);
537 WMDestroyTabViewItem(tPtr->items[i]);
539 free(tPtr->items);
541 WMReleaseColor(tPtr->lightGray);
542 WMReleaseColor(tPtr->tabColor);
543 WMReleaseFont(tPtr->font);
545 free(tPtr);
548 /******************************************************************/
551 typedef struct W_TabViewItem {
552 WMTabView *tabView;
554 W_View *view;
556 char *label;
558 int identifier;
560 struct {
561 unsigned visible:1;
562 } flags;
563 } TabViewItem;
566 static void
567 W_SetTabViewItemParent(WMTabViewItem *item, WMTabView *parent)
569 item->tabView = parent;
573 static void
574 W_DrawLabel(WMTabViewItem *item, Drawable d, WMRect rect)
576 WMScreen *scr = W_VIEW(item->tabView)->screen;
578 if (!item->label)
579 return;
581 WMDrawString(scr, d, WMColorGC(scr->black), item->tabView->font,
582 rect.pos.x, rect.pos.y, item->label, strlen(item->label));
586 static void
587 W_UnmapTabViewItem(WMTabViewItem *item)
589 wassertr(item->view);
591 W_UnmapView(item->view);
593 item->flags.visible = 0;
597 static void
598 W_MapTabViewItem(WMTabViewItem *item)
600 wassertr(item->view);
602 W_MapView(item->view);
604 item->flags.visible = 1;
608 static WMView*
609 W_TabViewItemView(WMTabViewItem *item)
611 return item->view;
615 WMTabViewItem*
616 WMCreateTabViewItemWithIdentifier(int identifier)
618 WMTabViewItem *item;
620 item = wmalloc(sizeof(WMTabViewItem));
621 memset(item, 0, sizeof(WMTabViewItem));
623 item->identifier = identifier;
625 return item;
630 WMGetTabViewItemIdentifier(WMTabViewItem *item)
632 return item->identifier;
636 void
637 WMSetTabViewFont(WMTabView *tPtr, WMFont *font)
639 if (tPtr->font)
640 WMReleaseFont(tPtr->font);
642 tPtr->font = WMRetainFont(font);
643 tPtr->tabHeight = WMFontHeight(tPtr->font) + 3;
644 recalcTabWidth(tPtr);
648 void
649 WMSetTabViewItemLabel(WMTabViewItem *item, char *label)
651 if (item->label)
652 free(item->label);
654 item->label = wstrdup(label);
656 if (item->tabView)
657 recalcTabWidth(item->tabView);
661 char*
662 WMGetTabViewItemLabel(WMTabViewItem *item)
664 return item->label;
668 void
669 WMSetTabViewItemView(WMTabViewItem *item, WMView *view)
671 item->view = view;
675 WMView*
676 WMGetTabViewItemView(WMTabViewItem *item)
678 return item->view;
682 void
683 WMDestroyTabViewItem(WMTabViewItem *item)
685 if (item->label)
686 free(item->label);
688 if (item->view)
689 W_DestroyView(item->view);
691 free(item);