X-Git-Url: https://repo.or.cz/w/wmaker-crm.git/blobdiff_plain/59fc927dc9f183802621138534fa6eaafe5593ba..688a56e8ab67b56550e2874d9d7423f0d435bfd9:/WINGs/wtabview.c diff --git a/WINGs/wtabview.c b/WINGs/wtabview.c dissimilarity index 96% index 00e2727f..3ae47283 100644 --- a/WINGs/wtabview.c +++ b/WINGs/wtabview.c @@ -1,1045 +1,907 @@ - -#include "WINGsP.h" - - -typedef struct W_TabView { - W_Class widgetClass; - W_View *view; - - struct W_TabViewItem **items; - int itemCount; - int maxItems; /* size of items array, can be increased */ - - int selectedItem; - int firstVisible; - - int visibleTabs; - - WMFont *font; - - WMColor *lightGray; - WMColor *tabColor; - - WMTabViewDelegate *delegate; - - short tabHeight; - - struct { - WMReliefType relief:4; - WMTitlePosition titlePosition:4; - WMTabViewType type:2; - - unsigned enabled:1; - unsigned tabbed:1; - unsigned dontFitAll:1; - unsigned bordered:1; - unsigned uniformTabs:1; - } flags; -} TabView; - - -typedef struct W_TabViewItem { - WMTabView *tabView; - - W_View *view; - - char *label; - - short tabWidth; - int identifier; - - struct { - unsigned visible:1; - unsigned enabled:1; - } flags; -} W_TabViewItem; - - - - - - -#define DEFAULT_WIDTH 40 -#define DEFAULT_HEIGHT 40 - -#define NORMAL_SIDE_OFFSET 8 -#define BUTTONED_SIDE_OFFSET 15 - - -static void destroyTabView(TabView *tPtr); -static void paintTabView(TabView *tPtr); - - -static void W_SetTabViewItemParent(WMTabViewItem *item, WMTabView *parent); - -static void W_DrawLabel(WMTabViewItem *item, Drawable d, WMRect rect, - Bool enabled); - -static void W_UnmapTabViewItem(WMTabViewItem *item); - -static void W_MapTabViewItem(WMTabViewItem *item); - -static WMView *W_TabViewItemView(WMTabViewItem *item); - -static int W_TabViewItemTabWidth(WMTabViewItem *item); - -static void W_SetTabViewItemTabWidth(WMTabViewItem *item, int width); - - -static void recalcTabWidth(TabView *tPtr); -static void rearrange(TabView *tPtr); - -static void didResize(struct W_ViewDelegate*, WMView*); - -static W_ViewDelegate delegate = { - NULL, - NULL, - didResize, - NULL, - NULL -}; - - -static int -positionOfTab(WMTabView *tabView, int tab) -{ - int i; - int offs; - - if (tab < tabView->firstVisible) - return -1; - - if (tab > tabView->firstVisible + tabView->visibleTabs) - return -1; - - if (tabView->flags.dontFitAll) - offs = BUTTONED_SIDE_OFFSET; - else - offs = NORMAL_SIDE_OFFSET; - - for (i = tabView->firstVisible; i < tab; i++) - offs += W_TabViewItemTabWidth(tabView->items[i]) - 10; - - return offs; -} - - -static int -countVisibleTabs(TabView *tPtr, int first) -{ - int i; - int width; - - if (first < 0) { - width = W_VIEW_WIDTH(tPtr->view) - 2 * NORMAL_SIDE_OFFSET; - first = 0; - } else { - width = W_VIEW_WIDTH(tPtr->view) - 2 * BUTTONED_SIDE_OFFSET; - } - - for (i = first; i < tPtr->itemCount; i++) { - width -= W_TabViewItemTabWidth(tPtr->items[i]) - 10; - if (width <= 0) { - return i - first; - } - } - return i - first; -} - - - -static void -handleEvents(XEvent *event, void *data) -{ - TabView *tPtr = (TabView*)data; - - CHECK_CLASS(data, WC_TabView); - - switch (event->type) { - case Expose: - if (event->xexpose.count!=0) - break; - paintTabView(tPtr); - break; - - case ButtonPress: - if (tPtr->flags.enabled) { - WMTabViewItem *item = WMTabViewItemAtPoint(tPtr, - event->xbutton.x, - event->xbutton.y); - /*if (item && !item->flags.enabled) - break;*/ - - if (item && item->flags.enabled) { - WMSelectTabViewItem(tPtr, item); - } else if (tPtr->flags.dontFitAll) { - int redraw = 0; - int lastVisible = tPtr->firstVisible+tPtr->visibleTabs-1; - - if (event->xbutton.x < BUTTONED_SIDE_OFFSET) { - if (tPtr->firstVisible > 0) { - redraw = 1; - tPtr->firstVisible--; - } - } else if (event->xbutton.x > positionOfTab(tPtr,lastVisible)){ - - if (lastVisible < tPtr->itemCount-1) { - redraw = 1; - tPtr->firstVisible++; - } - } - tPtr->visibleTabs = countVisibleTabs(tPtr, tPtr->firstVisible); - if (redraw) { - paintTabView(tPtr); - } - } - } - break; - - case DestroyNotify: - destroyTabView(tPtr); - break; - } -} - - - -WMTabView* -WMCreateTabView(WMWidget *parent) -{ - TabView *tPtr; - WMScreen *scr = WMWidgetScreen(parent); - - tPtr = wmalloc(sizeof(TabView)); - memset(tPtr, 0, sizeof(TabView)); - - tPtr->widgetClass = WC_TabView; - - tPtr->view = W_CreateView(W_VIEW(parent)); - if (!tPtr->view) { - wfree(tPtr); - return NULL; - } - tPtr->view->self = tPtr; - tPtr->view->delegate = &delegate; - - tPtr->lightGray = WMCreateRGBColor(scr, 0xd9d9, 0xd9d9, 0xd9d9, False); - tPtr->tabColor = WMCreateRGBColor(scr, 0x8420, 0x8420, 0x8420, False); - - tPtr->font = WMRetainFont(scr->normalFont); - - tPtr->flags.type = WTTopTabsBevelBorder; - tPtr->flags.bordered = 1; - tPtr->flags.uniformTabs = 0; - tPtr->flags.enabled = 1; - - WMCreateEventHandler(tPtr->view, ExposureMask|StructureNotifyMask - |ButtonPressMask, handleEvents, tPtr); - - WMResizeWidget(tPtr, DEFAULT_WIDTH, DEFAULT_HEIGHT); - - tPtr->tabHeight = WMFontHeight(tPtr->font) + 3; - - return tPtr; -} - - -void -WMSetTabViewDelegate(WMTabView *tPtr, WMTabViewDelegate *delegate) -{ - tPtr->delegate = delegate; -} - - -WMTabViewItem* -WMAddTabViewItemWithView(WMTabView *tPtr, WMView *view, int identifier, - char *label) -{ - WMTabViewItem *item; - - item = WMCreateTabViewItemWithIdentifier(identifier); - WMSetTabViewItemView(item, view); - WMAddItemInTabView(tPtr, item); - WMSetTabViewItemLabel(item, label); - - return item; -} - - -void -WMAddItemInTabView(WMTabView *tPtr, WMTabViewItem *item) -{ - WMInsertItemInTabView(tPtr, tPtr->itemCount, item); -} - - -void -WMSetTabViewEnabled(WMTabView *tPtr, Bool flag) -{ - tPtr->flags.enabled = ((flag==0) ? 0 : 1); - if (W_VIEW_REALIZED(tPtr->view)) - paintTabView(tPtr); -} - - -void -WMInsertItemInTabView(WMTabView *tPtr, int index, WMTabViewItem *item) -{ - wassertr(W_TabViewItemView(item) != NULL); - - if (tPtr->maxItems == tPtr->itemCount) { - WMTabViewItem **items; - - items = wrealloc(tPtr->items, - sizeof(WMTabViewItem*) * (tPtr->maxItems + 10)); - memset(&items[tPtr->maxItems], 0, sizeof(WMTabViewItem*) * 10); - tPtr->items = items; - tPtr->maxItems += 10; - } - - if (index > tPtr->itemCount) - index = tPtr->itemCount; - - if (index == 0 && tPtr->items[0]) { - W_UnmapTabViewItem(tPtr->items[0]); - } - - if (index < tPtr->itemCount) { - memmove(tPtr->items + index + 1, tPtr->items + index, - (tPtr->itemCount - index) * sizeof(WMTabViewItem*)); - } - - tPtr->items[index] = item; - - tPtr->itemCount++; - - recalcTabWidth(tPtr); - - W_SetTabViewItemParent(item, tPtr); - - W_UnmapTabViewItem(item); - - if (tPtr->flags.bordered) { - W_ReparentView(W_TabViewItemView(item), tPtr->view, 1, - tPtr->tabHeight + 1); - - W_ResizeView(W_TabViewItemView(item), tPtr->view->size.width - 3, - tPtr->view->size.height - tPtr->tabHeight - 3); - } else { - W_ReparentView(W_TabViewItemView(item), tPtr->view, 0, - tPtr->tabHeight); - - W_ResizeView(W_TabViewItemView(item), tPtr->view->size.width, - tPtr->view->size.height - tPtr->tabHeight); - } - - if (index == 0) { - W_MapTabViewItem(item); - } - if (tPtr->delegate && tPtr->delegate->didChangeNumberOfItems) - (*tPtr->delegate->didChangeNumberOfItems)(tPtr->delegate, tPtr); - - if (W_VIEW_REALIZED(tPtr->view)) - paintTabView(tPtr); -} - - -void -WMRemoveTabViewItem(WMTabView *tPtr, WMTabViewItem *item) -{ - int i; - - for (i = 0; i < tPtr->itemCount; i++) { - if (tPtr->items[i] == item) { - if (i < tPtr->itemCount - 1) - memmove(&tPtr->items[i], &tPtr->items[i + 1], - tPtr->itemCount - i - 1); - else - tPtr->items[i] = NULL; - - W_SetTabViewItemParent(item, NULL); - - tPtr->itemCount--; - break; - } - } - if (tPtr->delegate && tPtr->delegate->didChangeNumberOfItems) - (*tPtr->delegate->didChangeNumberOfItems)(tPtr->delegate, tPtr); -} - - - -static Bool -isInside(int x, int y, int width, int height, int px, int py) -{ - if (py >= y + height - 3 && py <= y + height - && px >= x + py - (y + height - 3) - && px <= x + width - (py - (y + height - 3))) { - - return True; - } - if (py >= y + 3 && py < y + height - 3 - && px >= x + 3 + ((y + 3) - py)*3/7 - && px <= x + width - 3 - ((y + 3) - py)*3/7) { - - return True; - } - if (py >= y && py < y + 3 - && px >= x + 7 + py - y - && px <= x + width - 7 - (py - y)) { - - return True; - } - return False; -} - - -WMTabViewItem* -WMTabViewItemAtPoint(WMTabView *tPtr, int x, int y) -{ - int i; - int count = tPtr->visibleTabs; - int first = tPtr->firstVisible; - - if (tPtr->flags.dontFitAll) { - i = tPtr->selectedItem - tPtr->firstVisible; - if (i >= 0 && i < tPtr->visibleTabs - && isInside(positionOfTab(tPtr, tPtr->selectedItem), 0, - W_TabViewItemTabWidth(tPtr->items[tPtr->selectedItem]), - tPtr->tabHeight, x, y)) { - return tPtr->items[tPtr->selectedItem]; - } - } else { - i = tPtr->selectedItem; - if (isInside(positionOfTab(tPtr, i), 0, - W_TabViewItemTabWidth(tPtr->items[i]), - tPtr->tabHeight, x, y)) { - return tPtr->items[i]; - } - } - - for (i = first; i < first + count; i++) { - int pos; - - pos = positionOfTab(tPtr, i); - if (isInside(pos, 0, W_TabViewItemTabWidth(tPtr->items[i]), - tPtr->tabHeight, x, y)) { - return tPtr->items[i]; - } - } - return NULL; -} - - -void -WMSetTabViewType(WMTabView *tPtr, WMTabViewType type) -{ - tPtr->flags.type = type; - - if (type != WTTopTabsBevelBorder) - tPtr->tabHeight = 0; - else - tPtr->tabHeight = WMFontHeight(tPtr->font) + 3; - - if (type == WTNoTabsNoBorder) - tPtr->flags.bordered = 0; - else - tPtr->flags.bordered = 1; - - rearrange(tPtr); -} - -void -WMSelectFirstTabViewItem(WMTabView *tPtr) -{ - WMSelectTabViewItemAtIndex(tPtr, 0); -} - - -void -WMSelectLastTabViewItem(WMTabView *tPtr) -{ - WMSelectTabViewItemAtIndex(tPtr, tPtr->itemCount); -} - - -void -WMSelectNextTabViewItem(WMTabView *tPtr) -{ - WMSelectTabViewItemAtIndex(tPtr, tPtr->selectedItem + 1); -} - - -void -WMSelectPreviousTabViewItem(WMTabView *tPtr) -{ - WMSelectTabViewItemAtIndex(tPtr, tPtr->selectedItem - 1); -} - - -WMTabViewItem* -WMGetSelectedTabViewItem(WMTabView *tPtr) -{ - return tPtr->items[tPtr->selectedItem]; -} - - -void -WMSelectTabViewItem(WMTabView *tPtr, WMTabViewItem *item) -{ - int i; - - for (i = 0; i < tPtr->itemCount; i++) { - if (tPtr->items[i] == item) { - WMSelectTabViewItemAtIndex(tPtr, i); - break; - } - } -} - - -void -WMSelectTabViewItemAtIndex(WMTabView *tPtr, int index) -{ - WMTabViewItem *item; - - if (index == tPtr->selectedItem) { - return; - } - - if (index < 0) - index = 0; - else if (index >= tPtr->itemCount) - index = tPtr->itemCount - 1; - - item = tPtr->items[tPtr->selectedItem]; - - if (tPtr->delegate && tPtr->delegate->shouldSelectItem) - if (!(*tPtr->delegate->shouldSelectItem)(tPtr->delegate, tPtr, - tPtr->items[index])) - return; - - if (tPtr->delegate && tPtr->delegate->willSelectItem) - (*tPtr->delegate->willSelectItem)(tPtr->delegate, tPtr, - tPtr->items[index]); - - W_UnmapTabViewItem(item); - - - item = tPtr->items[index]; - - W_MapTabViewItem(item); - - tPtr->selectedItem = index; - - if (tPtr->delegate && tPtr->delegate->didSelectItem) - (*tPtr->delegate->didSelectItem)(tPtr->delegate, tPtr, - tPtr->items[index]); - - paintTabView(tPtr); -} - - - -static void -recalcTabWidth(TabView *tPtr) -{ - int i; - /*int twidth = W_VIEW(tPtr)->size.width;*/ - int width; - - if (tPtr->flags.uniformTabs) { - int tabWidth; - - tabWidth = 0; - - for (i = 0; i < tPtr->itemCount; i++) { - char *str = WMGetTabViewItemLabel(tPtr->items[i]); - - if (str) { - width = WMWidthOfString(tPtr->font, str, strlen(str)); - if (width > tabWidth) - tabWidth = width; - } - } - - tabWidth = tabWidth + 30; - - for (i = 0; i < tPtr->itemCount; i++) - W_SetTabViewItemTabWidth(tPtr->items[i], tabWidth); - - tPtr->firstVisible = 0; - tPtr->visibleTabs = countVisibleTabs(tPtr, -1); - if (tPtr->visibleTabs < tPtr->itemCount) - tPtr->flags.dontFitAll = 1; - else - tPtr->flags.dontFitAll = 0; - } else { - for (i = 0; i < tPtr->itemCount; i++) { - char *str = WMGetTabViewItemLabel(tPtr->items[i]); - if (!str) - continue; - - width = WMWidthOfString(tPtr->font, str, strlen(str)) + 30; - - W_SetTabViewItemTabWidth(tPtr->items[i], width); - } - - if (countVisibleTabs(tPtr, -1) < tPtr->itemCount) { - tPtr->flags.dontFitAll = 1; - tPtr->firstVisible = 0; - tPtr->visibleTabs = countVisibleTabs(tPtr, tPtr->firstVisible); - } else { - tPtr->flags.dontFitAll = 0; - tPtr->firstVisible = 0; - tPtr->visibleTabs = tPtr->itemCount; - } - } -} - - -static void -drawRelief(W_Screen *scr, Drawable d, int x, int y, unsigned int width, - unsigned int height) -{ - Display *dpy = scr->display; - GC bgc = WMColorGC(scr->black); - GC wgc = WMColorGC(scr->white); - GC dgc = WMColorGC(scr->darkGray); - - XDrawLine(dpy, d, wgc, x, y, x, y+height-1); - - XDrawLine(dpy, d, bgc, x, y+height-1, x+width-1, y+height-1); - XDrawLine(dpy, d, dgc, x+1, y+height-2, x+width-2, y+height-2); - - XDrawLine(dpy, d, bgc, x+width-1, y, x+width-1, y+height-1); - XDrawLine(dpy, d, dgc, x+width-2, y+1, x+width-2, y+height-2); -} - - -static void -drawTab(TabView *tPtr, Drawable d, int x, int y, - unsigned width, unsigned height, Bool selected) -{ - WMScreen *scr = W_VIEW(tPtr)->screen; - Display *dpy = scr->display; - GC white = WMColorGC(selected ? scr->white : tPtr->lightGray); - GC black = WMColorGC(scr->black); - GC dark = WMColorGC(scr->darkGray); - GC light = WMColorGC(scr->gray); - XPoint trap[8]; - - trap[0].x = x + (selected ? 0 : 1); - trap[0].y = y + height - (selected ? 0 : 1); - - trap[1].x = x + 3; - trap[1].y = y + height - 3; - - trap[2].x = x + 10 - 3; - trap[2].y = y + 3; - - trap[3].x = x + 10; - trap[3].y = y; - - trap[4].x = x + width - 10; - trap[4].y = y; - - trap[5].x = x + width - 10 + 3; - trap[5].y = y + 3; - - trap[6].x = x + width - 3; - trap[6].y = y + height - 3; - - trap[7].x = x + width - (selected ? 0 : 1); - trap[7].y = y + height - (selected ? 0 : 1); - - XFillPolygon(dpy, d, selected ? light : WMColorGC(tPtr->tabColor), trap, 8, - Convex, CoordModeOrigin); - - XDrawLine(dpy, d, white, trap[0].x, trap[0].y, trap[1].x, trap[1].y); - XDrawLine(dpy, d, white, trap[1].x, trap[1].y, trap[2].x, trap[2].y); - XDrawLine(dpy, d, white, trap[2].x, trap[2].y, trap[3].x, trap[3].y); - XDrawLine(dpy, d, white, trap[3].x, trap[3].y, trap[4].x, trap[4].y); - XDrawLine(dpy, d, dark, trap[4].x, trap[4].y, trap[5].x, trap[5].y); - XDrawLine(dpy, d, black, trap[5].x, trap[5].y, trap[6].x, trap[6].y); - XDrawLine(dpy, d, black, trap[6].x, trap[6].y, trap[7].x, trap[7].y); - - XDrawLine(dpy, d, selected ? light : WMColorGC(scr->white), - trap[0].x, trap[0].y, trap[7].x, trap[7].y); -} - - -static void -paintDot(TabView *tPtr, Drawable d, int x, int y) -{ - WMScreen *scr = W_VIEW(tPtr)->screen; - Display *dpy = scr->display; - GC white = WMColorGC(scr->white); - GC black = WMColorGC(scr->black); - - XFillRectangle(dpy, d, black, x, y, 2, 2); - XDrawPoint(dpy, d, white, x, y); -} - - - -static void -paintTabView(TabView *tPtr) -{ - Pixmap buffer; - WMScreen *scr = W_VIEW(tPtr)->screen; - Display *dpy = scr->display; - GC white = WMColorGC(scr->white); - int i; - - if (tPtr->flags.type == WTTopTabsBevelBorder) { - int count = tPtr->visibleTabs; - int first = tPtr->firstVisible; - int moreAtLeft; - int moreAtRight; - int selectedIsVisible; - int ty; - int twidth, theight; - - ty = 2; - theight = tPtr->tabHeight; - - buffer = XCreatePixmap(dpy, W_VIEW(tPtr)->window, - W_VIEW(tPtr)->size.width, theight, - W_VIEW(tPtr)->screen->depth); - - XFillRectangle(dpy, buffer, WMColorGC(W_VIEW(tPtr)->backColor), - 0, 0, W_VIEW(tPtr)->size.width, tPtr->tabHeight); - - if (tPtr->flags.dontFitAll) { - moreAtLeft = first > 0; - moreAtRight = (first + count) < tPtr->itemCount; - if (tPtr->selectedItem >= first - && tPtr->selectedItem < first + count) - selectedIsVisible = 1; - else - selectedIsVisible = 0; - } else { - moreAtLeft = 0; - moreAtRight = 0; - selectedIsVisible = 1; - } - - if (moreAtRight) { - drawTab(tPtr, buffer, positionOfTab(tPtr, first+count), 0, - W_VIEW_WIDTH(tPtr->view), theight, False); - } - for (i = first + count-1; i >= first; i--) { - if (!selectedIsVisible || i != tPtr->selectedItem) { - twidth = W_TabViewItemTabWidth(tPtr->items[i]); - - drawTab(tPtr, buffer, positionOfTab(tPtr, i), 0, - twidth, theight, False); - } - } - if (moreAtLeft) { - drawTab(tPtr, buffer, positionOfTab(tPtr, 0)-2*BUTTONED_SIDE_OFFSET, - 0, BUTTONED_SIDE_OFFSET*4, theight, False); - } - - if (selectedIsVisible) { - int idx = tPtr->selectedItem; - - drawTab(tPtr, buffer, positionOfTab(tPtr, idx), - 0, W_TabViewItemTabWidth(tPtr->items[idx]), - theight, True); - - XDrawLine(dpy, buffer, white, 0, theight - 1, - positionOfTab(tPtr, idx), theight - 1); - - XDrawLine(dpy, buffer, white, - positionOfTab(tPtr, idx) + W_TabViewItemTabWidth(tPtr->items[idx]), - tPtr->tabHeight - 1, W_VIEW_WIDTH(tPtr->view) - 1, - tPtr->tabHeight - 1); - } else { - XDrawLine(dpy, buffer, white, 0, theight - 1, - W_VIEW_WIDTH(tPtr->view), theight - 1); - } - - for (i = 0; i < count; i++) { - WMRect rect; - - rect.pos.x = 15 + positionOfTab(tPtr, first+i); - rect.pos.y = ty; - rect.size.width = W_TabViewItemTabWidth(tPtr->items[first+i]); - rect.size.height = theight; - W_DrawLabel(tPtr->items[first+i], buffer, rect, - tPtr->flags.enabled && - tPtr->items[first+i]->flags.enabled); - } - - if (moreAtLeft) { - paintDot(tPtr, buffer, 4, 10); - paintDot(tPtr, buffer, 7, 10); - paintDot(tPtr, buffer, 10, 10); - } - if (moreAtRight) { - int x; - - x = positionOfTab(tPtr, tPtr->firstVisible + tPtr->visibleTabs); - - x = x + (W_VIEW_WIDTH(tPtr->view) - x)/2; - paintDot(tPtr, buffer, x + 5, 10); - paintDot(tPtr, buffer, x + 8, 10); - paintDot(tPtr, buffer, x + 11, 10); - } - - XCopyArea(dpy, buffer, W_VIEW(tPtr)->window, scr->copyGC, 0, 0, - W_VIEW_WIDTH(tPtr->view), theight, 0, 0); - - XFreePixmap(dpy, buffer); - } - switch (tPtr->flags.type) { - case WTTopTabsBevelBorder: - drawRelief(scr, W_VIEW(tPtr)->window, 0, tPtr->tabHeight - 1, - W_VIEW(tPtr)->size.width, - W_VIEW(tPtr)->size.height - tPtr->tabHeight + 1); - break; - - case WTNoTabsBevelBorder: - W_DrawRelief(scr, W_VIEW(tPtr)->window, 0, 0, W_VIEW(tPtr)->size.width, - W_VIEW(tPtr)->size.height, WRRaised); - break; - - case WTNoTabsLineBorder: - W_DrawRelief(scr, W_VIEW(tPtr)->window, 0, 0, W_VIEW(tPtr)->size.width, - W_VIEW(tPtr)->size.height, WRSimple); - break; - - case WTNoTabsNoBorder: - break; - } -} - - -static void -rearrange(TabView *tPtr) -{ - int i; - int width, height; - int bordered = tPtr->flags.bordered; - - recalcTabWidth(tPtr); - - width = tPtr->view->size.width - (bordered ? 3 : 0); - height = tPtr->view->size.height - tPtr->tabHeight - (bordered ? 3 : 0); - - for (i = 0; i < tPtr->itemCount; i++) { - W_MoveView(W_TabViewItemView(tPtr->items[i]), - 1*bordered, tPtr->tabHeight + 1*bordered); - W_ResizeView(W_TabViewItemView(tPtr->items[i]), width, height); - } - if (W_VIEW_MAPPED(tPtr->view) && W_VIEW_REALIZED(tPtr->view)) - paintTabView(tPtr); -} - - -static void -didResize(struct W_ViewDelegate *deleg, WMView *view) -{ - rearrange(view->self); -} - - -static void -destroyTabView(TabView *tPtr) -{ - int i; - - for (i = 0; i < tPtr->itemCount; i++) { - WMSetTabViewItemView(tPtr->items[i], NULL); - WMDestroyTabViewItem(tPtr->items[i]); - } - wfree(tPtr->items); - - WMReleaseColor(tPtr->lightGray); - WMReleaseColor(tPtr->tabColor); - WMReleaseFont(tPtr->font); - - wfree(tPtr); -} - -/******************************************************************/ - - -static void -W_SetTabViewItemParent(WMTabViewItem *item, WMTabView *parent) -{ - item->tabView = parent; -} - - -static void -W_DrawLabel(WMTabViewItem *item, Drawable d, WMRect rect, Bool enabled) -{ - WMScreen *scr = W_VIEW(item->tabView)->screen; - - if (!item->label) - return; - - WMDrawString(scr, d, enabled ? scr->black : scr->darkGray, - item->tabView->font, rect.pos.x, rect.pos.y, - item->label, strlen(item->label)); -} - - -static void -W_UnmapTabViewItem(WMTabViewItem *item) -{ - wassertr(item->view); - - W_UnmapView(item->view); - - item->flags.visible = 0; -} - - -static void -W_MapTabViewItem(WMTabViewItem *item) -{ - wassertr(item->view); - - W_MapView(item->view); - W_RaiseView(item->view); - - item->flags.visible = 1; -} - - -static WMView* -W_TabViewItemView(WMTabViewItem *item) -{ - return item->view; -} - - -static int -W_TabViewItemTabWidth(WMTabViewItem *item) -{ - return item->tabWidth; -} - - -static void -W_SetTabViewItemTabWidth(WMTabViewItem *item, int width) -{ - item->tabWidth = width; -} - - -WMTabViewItem* -WMCreateTabViewItemWithIdentifier(int identifier) -{ - WMTabViewItem *item; - - item = wmalloc(sizeof(WMTabViewItem)); - memset(item, 0, sizeof(WMTabViewItem)); - - item->identifier = identifier; - - item->flags.enabled = 1; - - return item; -} - - -WMTabViewItem* -WMCreateTabViewItem(int identifier, char *label) -{ - WMTabViewItem *item; - - item = wmalloc(sizeof(WMTabViewItem)); - memset(item, 0, sizeof(WMTabViewItem)); - - item->identifier = identifier; - - item->flags.enabled = 1; - - WMSetTabViewItemLabel(item, label); - - return item; -} - - -void -WMSetTabViewItemEnabled(WMTabViewItem *tPtr, Bool flag) -{ - tPtr->flags.enabled = ((flag==0) ? 0 : 1); - if (tPtr->tabView && W_VIEW_REALIZED(tPtr->tabView->view)) - paintTabView(tPtr->tabView); -} - - -int -WMGetTabViewItemIdentifier(WMTabViewItem *item) -{ - return item->identifier; -} - - -void -WMSetTabViewFont(WMTabView *tPtr, WMFont *font) -{ - if (tPtr->font) - WMReleaseFont(tPtr->font); - - tPtr->font = WMRetainFont(font); - tPtr->tabHeight = WMFontHeight(tPtr->font) + 3; - recalcTabWidth(tPtr); -} - - -void -WMSetTabViewItemLabel(WMTabViewItem *item, char *label) -{ - if (item->label) - wfree(item->label); - - if (label) - item->label = wstrdup(label); - else - item->label = NULL; - - if (item->tabView) - recalcTabWidth(item->tabView); -} - - -char* -WMGetTabViewItemLabel(WMTabViewItem *item) -{ - return item->label; -} - - -void -WMSetTabViewItemView(WMTabViewItem *item, WMView *view) -{ - item->view = view; -} - - -WMView* -WMGetTabViewItemView(WMTabViewItem *item) -{ - return item->view; -} - - -void -WMDestroyTabViewItem(WMTabViewItem *item) -{ - if (item->label) - wfree(item->label); - - if (item->view) - W_DestroyView(item->view); - - wfree(item); -} - + +#include "WINGsP.h" + +typedef struct W_TabView { + W_Class widgetClass; + W_View *view; + + struct W_TabViewItem **items; + int itemCount; + int maxItems; /* size of items array, can be increased */ + + int selectedItem; + int firstVisible; + + int visibleTabs; + + WMFont *font; + + WMColor *lightGray; + WMColor *tabColor; + + WMTabViewDelegate *delegate; + + short tabHeight; + + struct { + WMReliefType relief:4; + WMTitlePosition titlePosition:4; + WMTabViewType type:2; + + unsigned enabled:1; + unsigned tabbed:1; + unsigned dontFitAll:1; + unsigned bordered:1; + unsigned uniformTabs:1; + } flags; +} TabView; + +typedef struct W_TabViewItem { + WMTabView *tabView; + + W_View *view; + + char *label; + + short tabWidth; + int identifier; + + struct { + unsigned visible:1; + unsigned enabled:1; + } flags; +} W_TabViewItem; + +#define DEFAULT_WIDTH 40 +#define DEFAULT_HEIGHT 40 + +#define NORMAL_SIDE_OFFSET 8 +#define BUTTONED_SIDE_OFFSET 15 + +static void destroyTabView(TabView * tPtr); +static void paintTabView(TabView * tPtr); + +static void W_SetTabViewItemParent(WMTabViewItem * item, WMTabView * parent); + +static void W_DrawLabel(WMTabViewItem * item, Drawable d, WMRect rect, Bool enabled); + +static void W_UnmapTabViewItem(WMTabViewItem * item); + +static void W_MapTabViewItem(WMTabViewItem * item); + +static WMView *W_TabViewItemView(WMTabViewItem * item); + +static int W_TabViewItemTabWidth(WMTabViewItem * item); + +static void W_SetTabViewItemTabWidth(WMTabViewItem * item, int width); + +static void recalcTabWidth(TabView * tPtr); +static void rearrange(TabView * tPtr); + +static void didResize(struct W_ViewDelegate *, WMView *); + +static W_ViewDelegate delegate = { + NULL, + NULL, + didResize, + NULL, + NULL +}; + +static int positionOfTab(WMTabView * tabView, int tab) +{ + int i; + int offs; + + if (tab < tabView->firstVisible) + return -1; + + if (tab > tabView->firstVisible + tabView->visibleTabs) + return -1; + + if (tabView->flags.dontFitAll) + offs = BUTTONED_SIDE_OFFSET; + else + offs = NORMAL_SIDE_OFFSET; + + for (i = tabView->firstVisible; i < tab; i++) + offs += W_TabViewItemTabWidth(tabView->items[i]) - 10; + + return offs; +} + +static int countVisibleTabs(TabView * tPtr, int first) +{ + int i; + int width; + + if (first < 0) { + width = W_VIEW_WIDTH(tPtr->view) - 2 * NORMAL_SIDE_OFFSET; + first = 0; + } else { + width = W_VIEW_WIDTH(tPtr->view) - 2 * BUTTONED_SIDE_OFFSET; + } + + for (i = first; i < tPtr->itemCount; i++) { + width -= W_TabViewItemTabWidth(tPtr->items[i]) - 10; + if (width <= 0) { + return i - first; + } + } + return i - first; +} + +static void handleEvents(XEvent * event, void *data) +{ + TabView *tPtr = (TabView *) data; + + CHECK_CLASS(data, WC_TabView); + + switch (event->type) { + case Expose: + if (event->xexpose.count != 0) + break; + paintTabView(tPtr); + break; + + case ButtonPress: + if (tPtr->flags.enabled) { + WMTabViewItem *item = WMTabViewItemAtPoint(tPtr, + event->xbutton.x, + event->xbutton.y); + /*if (item && !item->flags.enabled) + break; */ + + if (item && item->flags.enabled) { + WMSelectTabViewItem(tPtr, item); + } else if (tPtr->flags.dontFitAll) { + int redraw = 0; + int lastVisible = tPtr->firstVisible + tPtr->visibleTabs - 1; + + if (event->xbutton.x < BUTTONED_SIDE_OFFSET) { + if (tPtr->firstVisible > 0) { + redraw = 1; + tPtr->firstVisible--; + } + } else if (event->xbutton.x > positionOfTab(tPtr, lastVisible)) { + + if (lastVisible < tPtr->itemCount - 1) { + redraw = 1; + tPtr->firstVisible++; + } + } + tPtr->visibleTabs = countVisibleTabs(tPtr, tPtr->firstVisible); + if (redraw) { + paintTabView(tPtr); + } + } + } + break; + + case DestroyNotify: + destroyTabView(tPtr); + break; + } +} + +WMTabView *WMCreateTabView(WMWidget * parent) +{ + TabView *tPtr; + WMScreen *scr = WMWidgetScreen(parent); + + tPtr = wmalloc(sizeof(TabView)); + memset(tPtr, 0, sizeof(TabView)); + + tPtr->widgetClass = WC_TabView; + + tPtr->view = W_CreateView(W_VIEW(parent)); + if (!tPtr->view) { + wfree(tPtr); + return NULL; + } + tPtr->view->self = tPtr; + tPtr->view->delegate = &delegate; + + tPtr->lightGray = WMCreateRGBColor(scr, 0xd9d9, 0xd9d9, 0xd9d9, False); + tPtr->tabColor = WMCreateRGBColor(scr, 0x8420, 0x8420, 0x8420, False); + + tPtr->font = WMRetainFont(scr->normalFont); + + tPtr->flags.type = WTTopTabsBevelBorder; + tPtr->flags.bordered = 1; + tPtr->flags.uniformTabs = 0; + tPtr->flags.enabled = 1; + + WMCreateEventHandler(tPtr->view, ExposureMask | StructureNotifyMask | ButtonPressMask, handleEvents, tPtr); + + WMResizeWidget(tPtr, DEFAULT_WIDTH, DEFAULT_HEIGHT); + + tPtr->tabHeight = WMFontHeight(tPtr->font) + 3; + + return tPtr; +} + +void WMSetTabViewDelegate(WMTabView * tPtr, WMTabViewDelegate * delegate) +{ + tPtr->delegate = delegate; +} + +WMTabViewItem *WMAddTabViewItemWithView(WMTabView * tPtr, WMView * view, int identifier, char *label) +{ + WMTabViewItem *item; + + item = WMCreateTabViewItemWithIdentifier(identifier); + WMSetTabViewItemView(item, view); + WMAddItemInTabView(tPtr, item); + WMSetTabViewItemLabel(item, label); + + return item; +} + +void WMAddItemInTabView(WMTabView * tPtr, WMTabViewItem * item) +{ + WMInsertItemInTabView(tPtr, tPtr->itemCount, item); +} + +void WMSetTabViewEnabled(WMTabView * tPtr, Bool flag) +{ + tPtr->flags.enabled = ((flag == 0) ? 0 : 1); + if (W_VIEW_REALIZED(tPtr->view)) + paintTabView(tPtr); +} + +void WMInsertItemInTabView(WMTabView * tPtr, int index, WMTabViewItem * item) +{ + wassertr(W_TabViewItemView(item) != NULL); + + if (tPtr->maxItems == tPtr->itemCount) { + WMTabViewItem **items; + + items = wrealloc(tPtr->items, sizeof(WMTabViewItem *) * (tPtr->maxItems + 10)); + memset(&items[tPtr->maxItems], 0, sizeof(WMTabViewItem *) * 10); + tPtr->items = items; + tPtr->maxItems += 10; + } + + if (index > tPtr->itemCount) + index = tPtr->itemCount; + + if (index == 0 && tPtr->items[0]) { + W_UnmapTabViewItem(tPtr->items[0]); + } + + if (index < tPtr->itemCount) { + memmove(tPtr->items + index + 1, tPtr->items + index, + (tPtr->itemCount - index) * sizeof(WMTabViewItem *)); + } + + tPtr->items[index] = item; + + tPtr->itemCount++; + + recalcTabWidth(tPtr); + + W_SetTabViewItemParent(item, tPtr); + + W_UnmapTabViewItem(item); + + if (tPtr->flags.bordered) { + W_ReparentView(W_TabViewItemView(item), tPtr->view, 1, tPtr->tabHeight + 1); + + W_ResizeView(W_TabViewItemView(item), tPtr->view->size.width - 3, + tPtr->view->size.height - tPtr->tabHeight - 3); + } else { + W_ReparentView(W_TabViewItemView(item), tPtr->view, 0, tPtr->tabHeight); + + W_ResizeView(W_TabViewItemView(item), tPtr->view->size.width, + tPtr->view->size.height - tPtr->tabHeight); + } + + if (index == 0) { + W_MapTabViewItem(item); + } + if (tPtr->delegate && tPtr->delegate->didChangeNumberOfItems) + (*tPtr->delegate->didChangeNumberOfItems) (tPtr->delegate, tPtr); + + if (W_VIEW_REALIZED(tPtr->view)) + paintTabView(tPtr); +} + +void WMRemoveTabViewItem(WMTabView * tPtr, WMTabViewItem * item) +{ + int i; + + for (i = 0; i < tPtr->itemCount; i++) { + if (tPtr->items[i] == item) { + if (i < tPtr->itemCount - 1) + memmove(&tPtr->items[i], &tPtr->items[i + 1], tPtr->itemCount - i - 1); + else + tPtr->items[i] = NULL; + + W_SetTabViewItemParent(item, NULL); + + tPtr->itemCount--; + break; + } + } + if (tPtr->delegate && tPtr->delegate->didChangeNumberOfItems) + (*tPtr->delegate->didChangeNumberOfItems) (tPtr->delegate, tPtr); +} + +static Bool isInside(int x, int y, int width, int height, int px, int py) +{ + if (py >= y + height - 3 && py <= y + height && px >= x + py - (y + height - 3) + && px <= x + width - (py - (y + height - 3))) { + + return True; + } + if (py >= y + 3 && py < y + height - 3 + && px >= x + 3 + ((y + 3) - py) * 3 / 7 && px <= x + width - 3 - ((y + 3) - py) * 3 / 7) { + + return True; + } + if (py >= y && py < y + 3 && px >= x + 7 + py - y && px <= x + width - 7 - (py - y)) { + + return True; + } + return False; +} + +WMTabViewItem *WMTabViewItemAtPoint(WMTabView * tPtr, int x, int y) +{ + int i; + int count = tPtr->visibleTabs; + int first = tPtr->firstVisible; + + if (tPtr->flags.dontFitAll) { + i = tPtr->selectedItem - tPtr->firstVisible; + if (i >= 0 && i < tPtr->visibleTabs + && isInside(positionOfTab(tPtr, tPtr->selectedItem), 0, + W_TabViewItemTabWidth(tPtr->items[tPtr->selectedItem]), tPtr->tabHeight, x, y)) { + return tPtr->items[tPtr->selectedItem]; + } + } else { + i = tPtr->selectedItem; + if (isInside(positionOfTab(tPtr, i), 0, + W_TabViewItemTabWidth(tPtr->items[i]), tPtr->tabHeight, x, y)) { + return tPtr->items[i]; + } + } + + for (i = first; i < first + count; i++) { + int pos; + + pos = positionOfTab(tPtr, i); + if (isInside(pos, 0, W_TabViewItemTabWidth(tPtr->items[i]), tPtr->tabHeight, x, y)) { + return tPtr->items[i]; + } + } + return NULL; +} + +void WMSetTabViewType(WMTabView * tPtr, WMTabViewType type) +{ + tPtr->flags.type = type; + + if (type != WTTopTabsBevelBorder) + tPtr->tabHeight = 0; + else + tPtr->tabHeight = WMFontHeight(tPtr->font) + 3; + + if (type == WTNoTabsNoBorder) + tPtr->flags.bordered = 0; + else + tPtr->flags.bordered = 1; + + rearrange(tPtr); +} + +void WMSelectFirstTabViewItem(WMTabView * tPtr) +{ + WMSelectTabViewItemAtIndex(tPtr, 0); +} + +void WMSelectLastTabViewItem(WMTabView * tPtr) +{ + WMSelectTabViewItemAtIndex(tPtr, tPtr->itemCount); +} + +void WMSelectNextTabViewItem(WMTabView * tPtr) +{ + WMSelectTabViewItemAtIndex(tPtr, tPtr->selectedItem + 1); +} + +void WMSelectPreviousTabViewItem(WMTabView * tPtr) +{ + WMSelectTabViewItemAtIndex(tPtr, tPtr->selectedItem - 1); +} + +WMTabViewItem *WMGetSelectedTabViewItem(WMTabView * tPtr) +{ + return tPtr->items[tPtr->selectedItem]; +} + +void WMSelectTabViewItem(WMTabView * tPtr, WMTabViewItem * item) +{ + int i; + + for (i = 0; i < tPtr->itemCount; i++) { + if (tPtr->items[i] == item) { + WMSelectTabViewItemAtIndex(tPtr, i); + break; + } + } +} + +void WMSelectTabViewItemAtIndex(WMTabView * tPtr, int index) +{ + WMTabViewItem *item; + + if (index == tPtr->selectedItem) { + return; + } + + if (index < 0) + index = 0; + else if (index >= tPtr->itemCount) + index = tPtr->itemCount - 1; + + item = tPtr->items[tPtr->selectedItem]; + + if (tPtr->delegate && tPtr->delegate->shouldSelectItem) + if (!(*tPtr->delegate->shouldSelectItem) (tPtr->delegate, tPtr, tPtr->items[index])) + return; + + if (tPtr->delegate && tPtr->delegate->willSelectItem) + (*tPtr->delegate->willSelectItem) (tPtr->delegate, tPtr, tPtr->items[index]); + + W_UnmapTabViewItem(item); + + item = tPtr->items[index]; + + W_MapTabViewItem(item); + + tPtr->selectedItem = index; + + if (tPtr->delegate && tPtr->delegate->didSelectItem) + (*tPtr->delegate->didSelectItem) (tPtr->delegate, tPtr, tPtr->items[index]); + + paintTabView(tPtr); +} + +static void recalcTabWidth(TabView * tPtr) +{ + int i; + /*int twidth = W_VIEW(tPtr)->size.width; */ + int width; + + if (tPtr->flags.uniformTabs) { + int tabWidth; + + tabWidth = 0; + + for (i = 0; i < tPtr->itemCount; i++) { + char *str = WMGetTabViewItemLabel(tPtr->items[i]); + + if (str) { + width = WMWidthOfString(tPtr->font, str, strlen(str)); + if (width > tabWidth) + tabWidth = width; + } + } + + tabWidth = tabWidth + 30; + + for (i = 0; i < tPtr->itemCount; i++) + W_SetTabViewItemTabWidth(tPtr->items[i], tabWidth); + + tPtr->firstVisible = 0; + tPtr->visibleTabs = countVisibleTabs(tPtr, -1); + if (tPtr->visibleTabs < tPtr->itemCount) + tPtr->flags.dontFitAll = 1; + else + tPtr->flags.dontFitAll = 0; + } else { + for (i = 0; i < tPtr->itemCount; i++) { + char *str = WMGetTabViewItemLabel(tPtr->items[i]); + if (!str) + continue; + + width = WMWidthOfString(tPtr->font, str, strlen(str)) + 30; + + W_SetTabViewItemTabWidth(tPtr->items[i], width); + } + + if (countVisibleTabs(tPtr, -1) < tPtr->itemCount) { + tPtr->flags.dontFitAll = 1; + tPtr->firstVisible = 0; + tPtr->visibleTabs = countVisibleTabs(tPtr, tPtr->firstVisible); + } else { + tPtr->flags.dontFitAll = 0; + tPtr->firstVisible = 0; + tPtr->visibleTabs = tPtr->itemCount; + } + } +} + +static void drawRelief(W_Screen * scr, Drawable d, int x, int y, unsigned int width, unsigned int height) +{ + Display *dpy = scr->display; + GC bgc = WMColorGC(scr->black); + GC wgc = WMColorGC(scr->white); + GC dgc = WMColorGC(scr->darkGray); + + XDrawLine(dpy, d, wgc, x, y, x, y + height - 1); + + XDrawLine(dpy, d, bgc, x, y + height - 1, x + width - 1, y + height - 1); + XDrawLine(dpy, d, dgc, x + 1, y + height - 2, x + width - 2, y + height - 2); + + XDrawLine(dpy, d, bgc, x + width - 1, y, x + width - 1, y + height - 1); + XDrawLine(dpy, d, dgc, x + width - 2, y + 1, x + width - 2, y + height - 2); +} + +static void drawTab(TabView * tPtr, Drawable d, int x, int y, unsigned width, unsigned height, Bool selected) +{ + WMScreen *scr = W_VIEW(tPtr)->screen; + Display *dpy = scr->display; + GC white = WMColorGC(selected ? scr->white : tPtr->lightGray); + GC black = WMColorGC(scr->black); + GC dark = WMColorGC(scr->darkGray); + GC light = WMColorGC(scr->gray); + XPoint trap[8]; + + trap[0].x = x + (selected ? 0 : 1); + trap[0].y = y + height - (selected ? 0 : 1); + + trap[1].x = x + 3; + trap[1].y = y + height - 3; + + trap[2].x = x + 10 - 3; + trap[2].y = y + 3; + + trap[3].x = x + 10; + trap[3].y = y; + + trap[4].x = x + width - 10; + trap[4].y = y; + + trap[5].x = x + width - 10 + 3; + trap[5].y = y + 3; + + trap[6].x = x + width - 3; + trap[6].y = y + height - 3; + + trap[7].x = x + width - (selected ? 0 : 1); + trap[7].y = y + height - (selected ? 0 : 1); + + XFillPolygon(dpy, d, selected ? light : WMColorGC(tPtr->tabColor), trap, 8, Convex, CoordModeOrigin); + + XDrawLine(dpy, d, white, trap[0].x, trap[0].y, trap[1].x, trap[1].y); + XDrawLine(dpy, d, white, trap[1].x, trap[1].y, trap[2].x, trap[2].y); + XDrawLine(dpy, d, white, trap[2].x, trap[2].y, trap[3].x, trap[3].y); + XDrawLine(dpy, d, white, trap[3].x, trap[3].y, trap[4].x, trap[4].y); + XDrawLine(dpy, d, dark, trap[4].x, trap[4].y, trap[5].x, trap[5].y); + XDrawLine(dpy, d, black, trap[5].x, trap[5].y, trap[6].x, trap[6].y); + XDrawLine(dpy, d, black, trap[6].x, trap[6].y, trap[7].x, trap[7].y); + + XDrawLine(dpy, d, selected ? light : WMColorGC(scr->white), trap[0].x, trap[0].y, trap[7].x, trap[7].y); +} + +static void paintDot(TabView * tPtr, Drawable d, int x, int y) +{ + WMScreen *scr = W_VIEW(tPtr)->screen; + Display *dpy = scr->display; + GC white = WMColorGC(scr->white); + GC black = WMColorGC(scr->black); + + XFillRectangle(dpy, d, black, x, y, 2, 2); + XDrawPoint(dpy, d, white, x, y); +} + +static void paintTabView(TabView * tPtr) +{ + Pixmap buffer; + WMScreen *scr = W_VIEW(tPtr)->screen; + Display *dpy = scr->display; + GC white = WMColorGC(scr->white); + int i; + + if (tPtr->flags.type == WTTopTabsBevelBorder) { + int count = tPtr->visibleTabs; + int first = tPtr->firstVisible; + int moreAtLeft; + int moreAtRight; + int selectedIsVisible; + int ty; + int twidth, theight; + + ty = 2; + theight = tPtr->tabHeight; + + buffer = XCreatePixmap(dpy, W_VIEW(tPtr)->window, + W_VIEW(tPtr)->size.width, theight, W_VIEW(tPtr)->screen->depth); + + XFillRectangle(dpy, buffer, WMColorGC(W_VIEW(tPtr)->backColor), + 0, 0, W_VIEW(tPtr)->size.width, tPtr->tabHeight); + + if (tPtr->flags.dontFitAll) { + moreAtLeft = first > 0; + moreAtRight = (first + count) < tPtr->itemCount; + if (tPtr->selectedItem >= first && tPtr->selectedItem < first + count) + selectedIsVisible = 1; + else + selectedIsVisible = 0; + } else { + moreAtLeft = 0; + moreAtRight = 0; + selectedIsVisible = 1; + } + + if (moreAtRight) { + drawTab(tPtr, buffer, positionOfTab(tPtr, first + count), 0, + W_VIEW_WIDTH(tPtr->view), theight, False); + } + for (i = first + count - 1; i >= first; i--) { + if (!selectedIsVisible || i != tPtr->selectedItem) { + twidth = W_TabViewItemTabWidth(tPtr->items[i]); + + drawTab(tPtr, buffer, positionOfTab(tPtr, i), 0, twidth, theight, False); + } + } + if (moreAtLeft) { + drawTab(tPtr, buffer, positionOfTab(tPtr, 0) - 2 * BUTTONED_SIDE_OFFSET, + 0, BUTTONED_SIDE_OFFSET * 4, theight, False); + } + + if (selectedIsVisible) { + int idx = tPtr->selectedItem; + + drawTab(tPtr, buffer, positionOfTab(tPtr, idx), + 0, W_TabViewItemTabWidth(tPtr->items[idx]), theight, True); + + XDrawLine(dpy, buffer, white, 0, theight - 1, positionOfTab(tPtr, idx), theight - 1); + + XDrawLine(dpy, buffer, white, + positionOfTab(tPtr, idx) + W_TabViewItemTabWidth(tPtr->items[idx]), + tPtr->tabHeight - 1, W_VIEW_WIDTH(tPtr->view) - 1, tPtr->tabHeight - 1); + } else { + XDrawLine(dpy, buffer, white, 0, theight - 1, W_VIEW_WIDTH(tPtr->view), theight - 1); + } + + for (i = 0; i < count; i++) { + WMRect rect; + + rect.pos.x = 15 + positionOfTab(tPtr, first + i); + rect.pos.y = ty; + rect.size.width = W_TabViewItemTabWidth(tPtr->items[first + i]); + rect.size.height = theight; + W_DrawLabel(tPtr->items[first + i], buffer, rect, + tPtr->flags.enabled && tPtr->items[first + i]->flags.enabled); + } + + if (moreAtLeft) { + paintDot(tPtr, buffer, 4, 10); + paintDot(tPtr, buffer, 7, 10); + paintDot(tPtr, buffer, 10, 10); + } + if (moreAtRight) { + int x; + + x = positionOfTab(tPtr, tPtr->firstVisible + tPtr->visibleTabs); + + x = x + (W_VIEW_WIDTH(tPtr->view) - x) / 2; + paintDot(tPtr, buffer, x + 5, 10); + paintDot(tPtr, buffer, x + 8, 10); + paintDot(tPtr, buffer, x + 11, 10); + } + + XCopyArea(dpy, buffer, W_VIEW(tPtr)->window, scr->copyGC, 0, 0, + W_VIEW_WIDTH(tPtr->view), theight, 0, 0); + + XFreePixmap(dpy, buffer); + } + switch (tPtr->flags.type) { + case WTTopTabsBevelBorder: + drawRelief(scr, W_VIEW(tPtr)->window, 0, tPtr->tabHeight - 1, + W_VIEW(tPtr)->size.width, W_VIEW(tPtr)->size.height - tPtr->tabHeight + 1); + break; + + case WTNoTabsBevelBorder: + W_DrawRelief(scr, W_VIEW(tPtr)->window, 0, 0, W_VIEW(tPtr)->size.width, + W_VIEW(tPtr)->size.height, WRRaised); + break; + + case WTNoTabsLineBorder: + W_DrawRelief(scr, W_VIEW(tPtr)->window, 0, 0, W_VIEW(tPtr)->size.width, + W_VIEW(tPtr)->size.height, WRSimple); + break; + + case WTNoTabsNoBorder: + break; + } +} + +static void rearrange(TabView * tPtr) +{ + int i; + int width, height; + int bordered = tPtr->flags.bordered; + + recalcTabWidth(tPtr); + + width = tPtr->view->size.width - (bordered ? 3 : 0); + height = tPtr->view->size.height - tPtr->tabHeight - (bordered ? 3 : 0); + + for (i = 0; i < tPtr->itemCount; i++) { + W_MoveView(W_TabViewItemView(tPtr->items[i]), 1 * bordered, tPtr->tabHeight + 1 * bordered); + W_ResizeView(W_TabViewItemView(tPtr->items[i]), width, height); + } + if (W_VIEW_MAPPED(tPtr->view) && W_VIEW_REALIZED(tPtr->view)) + paintTabView(tPtr); +} + +static void didResize(struct W_ViewDelegate *deleg, WMView * view) +{ + rearrange(view->self); +} + +static void destroyTabView(TabView * tPtr) +{ + int i; + + for (i = 0; i < tPtr->itemCount; i++) { + WMSetTabViewItemView(tPtr->items[i], NULL); + WMDestroyTabViewItem(tPtr->items[i]); + } + wfree(tPtr->items); + + WMReleaseColor(tPtr->lightGray); + WMReleaseColor(tPtr->tabColor); + WMReleaseFont(tPtr->font); + + wfree(tPtr); +} + +/******************************************************************/ + +static void W_SetTabViewItemParent(WMTabViewItem * item, WMTabView * parent) +{ + item->tabView = parent; +} + +static void W_DrawLabel(WMTabViewItem * item, Drawable d, WMRect rect, Bool enabled) +{ + WMScreen *scr = W_VIEW(item->tabView)->screen; + + if (!item->label) + return; + + WMDrawString(scr, d, enabled ? scr->black : scr->darkGray, + item->tabView->font, rect.pos.x, rect.pos.y, item->label, strlen(item->label)); +} + +static void W_UnmapTabViewItem(WMTabViewItem * item) +{ + wassertr(item->view); + + W_UnmapView(item->view); + + item->flags.visible = 0; +} + +static void W_MapTabViewItem(WMTabViewItem * item) +{ + wassertr(item->view); + + W_MapView(item->view); + W_RaiseView(item->view); + + item->flags.visible = 1; +} + +static WMView *W_TabViewItemView(WMTabViewItem * item) +{ + return item->view; +} + +static int W_TabViewItemTabWidth(WMTabViewItem * item) +{ + return item->tabWidth; +} + +static void W_SetTabViewItemTabWidth(WMTabViewItem * item, int width) +{ + item->tabWidth = width; +} + +WMTabViewItem *WMCreateTabViewItemWithIdentifier(int identifier) +{ + WMTabViewItem *item; + + item = wmalloc(sizeof(WMTabViewItem)); + memset(item, 0, sizeof(WMTabViewItem)); + + item->identifier = identifier; + + item->flags.enabled = 1; + + return item; +} + +WMTabViewItem *WMCreateTabViewItem(int identifier, char *label) +{ + WMTabViewItem *item; + + item = wmalloc(sizeof(WMTabViewItem)); + memset(item, 0, sizeof(WMTabViewItem)); + + item->identifier = identifier; + + item->flags.enabled = 1; + + WMSetTabViewItemLabel(item, label); + + return item; +} + +void WMSetTabViewItemEnabled(WMTabViewItem * tPtr, Bool flag) +{ + tPtr->flags.enabled = ((flag == 0) ? 0 : 1); + if (tPtr->tabView && W_VIEW_REALIZED(tPtr->tabView->view)) + paintTabView(tPtr->tabView); +} + +int WMGetTabViewItemIdentifier(WMTabViewItem * item) +{ + return item->identifier; +} + +void WMSetTabViewFont(WMTabView * tPtr, WMFont * font) +{ + if (tPtr->font) + WMReleaseFont(tPtr->font); + + tPtr->font = WMRetainFont(font); + tPtr->tabHeight = WMFontHeight(tPtr->font) + 3; + recalcTabWidth(tPtr); +} + +void WMSetTabViewItemLabel(WMTabViewItem * item, char *label) +{ + if (item->label) + wfree(item->label); + + if (label) + item->label = wstrdup(label); + else + item->label = NULL; + + if (item->tabView) + recalcTabWidth(item->tabView); +} + +char *WMGetTabViewItemLabel(WMTabViewItem * item) +{ + return item->label; +} + +void WMSetTabViewItemView(WMTabViewItem * item, WMView * view) +{ + item->view = view; +} + +WMView *WMGetTabViewItemView(WMTabViewItem * item) +{ + return item->view; +} + +void WMDestroyTabViewItem(WMTabViewItem * item) +{ + if (item->label) + wfree(item->label); + + if (item->view) + W_DestroyView(item->view); + + wfree(item); +}