Added WMSetTabViewFont().
[wmaker-crm.git] / WINGs / wtabview.c
blob8c382b5f79f6044f306e3245de3de484e6195f7f
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 short tabWidth;
21 short tabHeight;
23 struct {
24 WMReliefType relief:4;
25 WMTitlePosition titlePosition:4;
26 WMTabViewTypes type:2;
28 unsigned tabbed:1;
29 unsigned allowsTruncatedLabels:1;
30 } flags;
31 } TabView;
35 struct W_ViewProcedureTable _TabViewViewProcedures = {
36 NULL,
37 NULL,
38 NULL
42 #define DEFAULT_WIDTH 40
43 #define DEFAULT_HEIGHT 40
46 static void destroyTabView(TabView *tPtr);
47 static void paintTabView(TabView *tPtr);
50 static void W_SetTabViewItemParent(WMTabViewItem *item, WMTabView *parent);
52 static void W_DrawLabel(WMTabViewItem *item, Drawable d, WMRect rect);
54 static void W_UnmapTabViewItem(WMTabViewItem *item);
56 static void W_MapTabViewItem(WMTabViewItem *item);
58 static WMView *W_TabViewItemView(WMTabViewItem *item);
60 static void recalcTabWidth(TabView *tPtr);
63 static void
64 handleEvents(XEvent *event, void *data)
66 TabView *tPtr = (TabView*)data;
68 CHECK_CLASS(data, WC_TabView);
70 switch (event->type) {
71 case Expose:
72 if (event->xexpose.count!=0)
73 break;
74 paintTabView(tPtr);
75 break;
77 case ButtonPress:
79 WMTabViewItem *item = WMTabViewItemAtPoint(tPtr,
80 event->xbutton.x,
81 event->xbutton.y);
82 if (item) {
83 WMSelectTabViewItem(tPtr, item);
86 break;
88 case DestroyNotify:
89 destroyTabView(tPtr);
90 break;
96 WMTabView*
97 WMCreateTabView(WMWidget *parent)
99 TabView *tPtr;
100 WMScreen *scr = WMWidgetScreen(parent);
102 tPtr = wmalloc(sizeof(TabView));
103 memset(tPtr, 0, sizeof(TabView));
105 tPtr->widgetClass = WC_TabView;
107 tPtr->view = W_CreateView(W_VIEW(parent));
108 if (!tPtr->view) {
109 free(tPtr);
110 return NULL;
112 tPtr->view->self = tPtr;
114 tPtr->lightGray = WMCreateRGBColor(scr, 0xd9d9, 0xd9d9, 0xd9d9, False);
115 tPtr->tabColor = WMCreateRGBColor(scr, 0x8420, 0x8420, 0x8420, False);
117 tPtr->font = WMRetainFont(scr->normalFont);
119 WMCreateEventHandler(tPtr->view, ExposureMask|StructureNotifyMask
120 |ButtonPressMask, handleEvents, tPtr);
122 WMResizeWidget(tPtr, DEFAULT_WIDTH, DEFAULT_HEIGHT);
124 tPtr->tabHeight = WMFontHeight(tPtr->font) + 3;
126 return tPtr;
130 void
131 WMAddItemInTabView(WMTabView *tPtr, WMTabViewItem *item)
133 WMInsertItemInTabView(tPtr, tPtr->itemCount, item);
137 void
138 WMInsertItemInTabView(WMTabView *tPtr, int index, WMTabViewItem *item)
140 wassertr(W_TabViewItemView(item) != NULL);
142 if (tPtr->maxItems == tPtr->itemCount) {
143 WMTabViewItem **items;
145 items = wrealloc(tPtr->items,
146 sizeof(WMTabViewItem*) * (tPtr->maxItems + 10));
147 if (!items) {
148 wwarning("out of memory allocating memory for tabview");
149 return;
151 memset(&items[tPtr->maxItems], 0, sizeof(WMTabViewItem*) * 10);
152 tPtr->items = items;
153 tPtr->maxItems += 10;
156 if (index > tPtr->itemCount)
157 index = tPtr->itemCount;
159 if (index == 0 && tPtr->items[0]) {
160 W_UnmapTabViewItem(tPtr->items[0]);
163 if (index < tPtr->itemCount) {
164 memmove(&tPtr->items[index + 1], &tPtr->items[index],
165 tPtr->itemCount - index);
168 tPtr->items[index] = item;
170 tPtr->itemCount++;
172 recalcTabWidth(tPtr);
174 W_SetTabViewItemParent(item, tPtr);
176 W_UnmapTabViewItem(item);
178 W_ReparentView(W_TabViewItemView(item), tPtr->view, 1,
179 tPtr->tabHeight + 1);
181 W_ResizeView(W_TabViewItemView(item), tPtr->view->size.width - 3,
182 tPtr->view->size.height - tPtr->tabHeight - 3);
184 if (index == 0) {
185 W_MapTabViewItem(item);
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;
213 static Bool
214 isInside(int x, int y, int width, int height, int px, int py)
216 if (py >= y + height - 3 && py <= y + height
217 && px >= x + py - (y + height - 3)
218 && px <= x + width - (py - (y + height - 3))) {
220 return True;
222 if (py >= y + 3 && py < y + height - 3
223 && px >= x + 3 + ((y + 3) - py)*3/7
224 && px <= x + width - 3 - ((y + 3) - py)*3/7) {
226 return True;
228 if (py >= y && py < y + 3
229 && px >= x + 7 + py - y
230 && px <= x + width - 7 - (py - y)) {
232 return True;
234 return False;
238 WMTabViewItem*
239 WMTabViewItemAtPoint(WMTabView *tPtr, int x, int y)
241 int i;
243 i = tPtr->selectedItem;
244 if (isInside(8 + (tPtr->tabWidth-10)*i, 0, tPtr->tabWidth,
245 tPtr->tabHeight, x, y)) {
246 return tPtr->items[i];
249 for (i = 0; i < tPtr->itemCount; i++) {
250 if (isInside(8 + (tPtr->tabWidth-10)*i, 0, tPtr->tabWidth,
251 tPtr->tabHeight, x, y)) {
252 return tPtr->items[i];
255 return NULL;
259 void
260 WMSelectFirstTabViewItem(WMTabView *tPtr)
262 WMSelectTabViewItemAtIndex(tPtr, 0);
266 void
267 WMSelectLastTabViewItem(WMTabView *tPtr)
269 WMSelectTabViewItemAtIndex(tPtr, tPtr->itemCount);
273 void
274 WMSelectNextTabViewItem(WMTabView *tPtr)
276 WMSelectTabViewItemAtIndex(tPtr, tPtr->selectedItem + 1);
280 void
281 WMSelectPreviousTabViewItem(WMTabView *tPtr)
283 WMSelectTabViewItemAtIndex(tPtr, tPtr->selectedItem - 1);
287 WMTabViewItem*
288 WMGetSelectedTabViewItem(WMTabView *tPtr)
290 return tPtr->items[tPtr->selectedItem];
294 void
295 WMSelectTabViewItem(WMTabView *tPtr, WMTabViewItem *item)
297 int i;
299 for (i = 0; i < tPtr->itemCount; i++) {
300 if (tPtr->items[i] == item) {
301 WMSelectTabViewItemAtIndex(tPtr, i);
302 break;
308 void
309 WMSelectTabViewItemAtIndex(WMTabView *tPtr, int index)
311 WMTabViewItem *item;
313 if (index == tPtr->selectedItem)
314 return;
316 if (index < 0)
317 index = 0;
318 else if (index >= tPtr->itemCount)
319 index = tPtr->itemCount - 1;
322 item = tPtr->items[tPtr->selectedItem];
324 W_UnmapTabViewItem(item);
327 item = tPtr->items[index];
329 W_MapTabViewItem(item);
331 tPtr->selectedItem = index;
335 static void
336 recalcTabWidth(TabView *tPtr)
338 int i;
339 int twidth = W_VIEW(tPtr)->size.width;
340 int width;
342 tPtr->tabWidth = 0;
343 for (i = 0; i < tPtr->itemCount; i++) {
344 char *str = WMGetTabViewItemLabel(tPtr->items[i]);
346 if (str) {
347 width = WMWidthOfString(tPtr->font, str, strlen(str));
348 if (width > tPtr->tabWidth)
349 tPtr->tabWidth = width;
352 tPtr->tabWidth += 30;
353 if (tPtr->tabWidth > twidth - 10 * tPtr->itemCount
354 && tPtr->tabWidth < twidth - 16)
355 tPtr->tabWidth = (twidth - 16) / tPtr->itemCount;
359 static void
360 drawRelief(W_Screen *scr, Drawable d, int x, int y, unsigned int width,
361 unsigned int height)
363 Display *dpy = scr->display;
364 GC bgc = WMColorGC(scr->black);
365 GC wgc = WMColorGC(scr->white);
366 GC dgc = WMColorGC(scr->darkGray);
368 XDrawLine(dpy, d, wgc, x, y, x, y+height-1);
370 XDrawLine(dpy, d, bgc, x, y+height-1, x+width-1, y+height-1);
371 XDrawLine(dpy, d, dgc, x+1, y+height-2, x+width-2, y+height-2);
373 XDrawLine(dpy, d, bgc, x+width-1, y, x+width-1, y+height-1);
374 XDrawLine(dpy, d, dgc, x+width-2, y+1, x+width-2, y+height-2);
378 static void
379 drawTab(TabView *tPtr, Drawable d, int x, int y,
380 unsigned width, unsigned height, Bool selected)
382 WMScreen *scr = W_VIEW(tPtr)->screen;
383 Display *dpy = scr->display;
384 GC white = WMColorGC(selected ? scr->white : tPtr->lightGray);
385 GC black = WMColorGC(scr->black);
386 GC dark = WMColorGC(scr->darkGray);
387 GC light = WMColorGC(scr->gray);
388 XPoint trap[8];
390 trap[0].x = x + (selected ? 0 : 1);
391 trap[0].y = y + height - (selected ? 0 : 1);
393 trap[1].x = x + 3;
394 trap[1].y = y + height - 3;
396 trap[2].x = x + 10 - 3;
397 trap[2].y = y + 3;
399 trap[3].x = x + 10;
400 trap[3].y = y;
402 trap[4].x = x + width - 10;
403 trap[4].y = y;
405 trap[5].x = x + width - 10 + 3;
406 trap[5].y = y + 3;
408 trap[6].x = x + width - 3;
409 trap[6].y = y + height - 3;
411 trap[7].x = x + width - (selected ? 0 : 1);
412 trap[7].y = y + height - (selected ? 0 : 1);
414 XFillPolygon(dpy, d, selected ? light : WMColorGC(tPtr->tabColor), trap, 8,
415 Convex, CoordModeOrigin);
417 XDrawLine(dpy, d, white, trap[0].x, trap[0].y, trap[1].x, trap[1].y);
418 XDrawLine(dpy, d, white, trap[1].x, trap[1].y, trap[2].x, trap[2].y);
419 XDrawLine(dpy, d, white, trap[2].x, trap[2].y, trap[3].x, trap[3].y);
420 XDrawLine(dpy, d, white, trap[3].x, trap[3].y, trap[4].x, trap[4].y);
421 XDrawLine(dpy, d, dark, trap[4].x, trap[4].y, trap[5].x, trap[5].y);
422 XDrawLine(dpy, d, black, trap[5].x, trap[5].y, trap[6].x, trap[6].y);
423 XDrawLine(dpy, d, black, trap[6].x, trap[6].y, trap[7].x, trap[7].y);
425 XDrawLine(dpy, d, selected ? light : WMColorGC(scr->white),
426 trap[0].x, trap[0].y, trap[7].x, trap[7].y);
430 static void
431 paintTabView(TabView *tPtr)
433 Pixmap buffer;
434 WMScreen *scr = W_VIEW(tPtr)->screen;
435 Display *dpy = scr->display;
436 GC white = WMColorGC(scr->white);
437 int i;
438 WMRect rect;
440 if (tPtr->flags.type == WTTopTabsBevelBorder) {
441 buffer = XCreatePixmap(dpy, W_VIEW(tPtr)->window,
442 W_VIEW(tPtr)->size.width, tPtr->tabHeight,
443 W_VIEW(tPtr)->screen->depth);
445 XFillRectangle(dpy, buffer, WMColorGC(W_VIEW(tPtr)->backColor),
446 0, 0, W_VIEW(tPtr)->size.width, tPtr->tabHeight);
448 rect.pos.x = 8 + 15;
449 rect.pos.y = 2;
450 rect.size.width = tPtr->tabWidth;
451 rect.size.height = tPtr->tabHeight;
453 for (i = tPtr->itemCount - 1; i >= 0; i--) {
454 if (i != tPtr->selectedItem) {
455 drawTab(tPtr, buffer, 8 + (rect.size.width-10)*i, 0,
456 rect.size.width, rect.size.height, False);
459 drawTab(tPtr, buffer, 8 + (rect.size.width-10) * tPtr->selectedItem,
460 0, rect.size.width, rect.size.height, True);
462 XDrawLine(dpy, buffer, white, 0, tPtr->tabHeight - 1,
463 8, tPtr->tabHeight - 1);
465 XDrawLine(dpy, buffer, white,
466 8 + 10 + (rect.size.width-10) * tPtr->itemCount,
467 tPtr->tabHeight - 1, W_VIEW(tPtr)->size.width - 1,
468 tPtr->tabHeight - 1);
471 for (i = 0; i < tPtr->itemCount; i++) {
472 W_DrawLabel(tPtr->items[i], buffer, rect);
474 rect.pos.x += rect.size.width - 10;
477 XCopyArea(dpy, buffer, W_VIEW(tPtr)->window, scr->copyGC, 0, 0,
478 W_VIEW(tPtr)->size.width, tPtr->tabHeight, 0, 0);
480 XFreePixmap(dpy, buffer);
482 switch (tPtr->flags.type) {
483 case WTTopTabsBevelBorder:
484 drawRelief(scr, W_VIEW(tPtr)->window, 0, tPtr->tabHeight - 1,
485 W_VIEW(tPtr)->size.width,
486 W_VIEW(tPtr)->size.height - tPtr->tabHeight + 1);
487 break;
489 case WTNoTabsBevelBorder:
490 W_DrawRelief(scr, W_VIEW(tPtr)->window, 0, 0, W_VIEW(tPtr)->size.width,
491 W_VIEW(tPtr)->size.height, WRRaised);
492 break;
494 case WTNoTabsLineBorder:
495 W_DrawRelief(scr, W_VIEW(tPtr)->window, 0, 0, W_VIEW(tPtr)->size.width,
496 W_VIEW(tPtr)->size.height, WRSimple);
497 break;
499 case WTNoTabsNoBorder:
500 break;
505 static void
506 destroyTabView(TabView *tPtr)
508 int i;
510 for (i = 0; i < tPtr->itemCount; i++) {
511 WMSetTabViewItemView(tPtr->items[i], NULL);
512 WMDestroyTabViewItem(tPtr->items[i]);
514 free(tPtr->items);
516 WMReleaseColor(tPtr->lightGray);
517 WMReleaseColor(tPtr->tabColor);
518 WMReleaseFont(tPtr->font);
520 free(tPtr);
523 /******************************************************************/
526 typedef struct W_TabViewItem {
527 WMTabView *tabView;
529 W_View *view;
531 char *label;
533 int identifier;
535 struct {
536 unsigned visible:1;
537 } flags;
538 } TabViewItem;
541 static void
542 W_SetTabViewItemParent(WMTabViewItem *item, WMTabView *parent)
544 item->tabView = parent;
548 static void
549 W_DrawLabel(WMTabViewItem *item, Drawable d, WMRect rect)
551 WMScreen *scr = W_VIEW(item->tabView)->screen;
553 if (!item->label)
554 return;
556 WMDrawString(scr, d, WMColorGC(scr->black), item->tabView->font,
557 rect.pos.x, rect.pos.y, item->label, strlen(item->label));
561 static void
562 W_UnmapTabViewItem(WMTabViewItem *item)
564 wassertr(item->view);
566 W_UnmapView(item->view);
568 item->flags.visible = 0;
572 static void
573 W_MapTabViewItem(WMTabViewItem *item)
575 wassertr(item->view);
577 W_MapView(item->view);
579 item->flags.visible = 1;
583 static WMView*
584 W_TabViewItemView(WMTabViewItem *item)
586 return item->view;
590 WMTabViewItem*
591 WMCreateTabViewItemWithIdentifier(int identifier)
593 WMTabViewItem *item;
595 item = wmalloc(sizeof(WMTabViewItem));
596 memset(item, 0, sizeof(WMTabViewItem));
598 item->identifier = identifier;
600 return item;
604 void
605 WMSetTabViewFont(WMTabView *tPtr, WMFont *font)
607 if (tPtr->font)
608 WMReleaseFont(tPtr->font);
610 tPtr->font = WMRetainFont(font);
614 void
615 WMSetTabViewItemLabel(WMTabViewItem *item, char *label)
617 if (item->label)
618 free(item->label);
620 item->label = wstrdup(label);
622 if (item->tabView)
623 recalcTabWidth(item->tabView);
627 char*
628 WMGetTabViewItemLabel(WMTabViewItem *item)
630 return item->label;
634 void
635 WMSetTabViewItemView(WMTabViewItem *item, WMView *view)
637 item->view = view;
641 WMView*
642 WMGetTabViewItemView(WMTabViewItem *item)
644 return item->view;
648 void
649 WMDestroyTabViewItem(WMTabViewItem *item)
651 if (item->label)
652 free(item->label);
654 if (item->view)
655 W_DestroyView(item->view);
657 free(item);