#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);
}



syntax highlighted by Code2HTML, v. 0.9.1