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