//	Zinc Application Framework - I_SCRLL.CPP
//	COPYRIGHT (C) 1990-1999.  All Rights Reserved.
//	Zinc Software Incorporated.  Pleasant Grove, Utah  USA

#include <time.h>
#include "i_scrll.hpp"
#include <z_app.hpp>
#include <z_mouse2.hpp>	// For DM_BOTTOM_RIGHT_CORNER.
#include <z_string.hpp>
#include <z_timer.hpp>
#include <z_utils.hpp>

// Put scrollbar width here to avoid scattered #ifdefs.
#if defined(ZAF_TEXT_MODE)
const int ZAF_SCROLLBAR_WIDTH = 0;
#else
const int ZAF_SCROLLBAR_WIDTH = 16;
#endif

#define ZafUseLazyScrollMethod

// ----- ZafScrollBar ---------------------------------------------------------

ZafEventType ZafScrollBar::DispatchMouseEvent(const ZafEventStruct &event)
{
	if (modifyMode)
		return (Modify(event));

	// LogicalEvent() must be called first to map the logical events (L_*) and
	// to convert the event to the context of this object.
	ZafEventType ccode = LogicalEvent(event);

	if (windowManager->MouseEventRoute() == this)
		return (Event(event));

	if (lButton && lButton->zafRegion.Overlap(event.position))
		ccode = lButton->DispatchMouseEvent(event);
	else if (rButton && rButton->zafRegion.Overlap(event.position))
		ccode = rButton->DispatchMouseEvent(event);
	else
		ccode = ZafWindowObject::DispatchMouseEvent(event);

	return (ccode);
}

ZafWindowObject *ZafScrollBar::FindMouseObject(const ZafEventStruct &event)
{
	return (ZafWindowObject::FindMouseObject(event));
}

#if defined(ZAF_DEFAULT_DRAW)
ZafEventType ZafScrollBar::Draw(const ZafEventStruct &event, ZafEventType ccode)
{
	// Compute the actual draw region.
	ZafPaletteState state = PaletteState();
	ZafRegionStruct drawRegion = BeginDraw();

	display->SetClipRegion(event.region);

	if (Bordered())
		DrawBorder(drawRegion, ccode);

	ZafPaletteStruct palette = LogicalPalette(ZAF_PM_BACKGROUND, state);
	if (scrollType == ZAF_CORNER_SCROLL || scrollType == ZAF_SIZEGRIP_SCROLL ||
		scrollType == ZAF_VERTICAL_SLIDER || scrollType == ZAF_HORIZONTAL_SLIDER)
		palette.fillPattern = ZAF_PTN_SOLID_FILL;

	display->SetPalette(palette);
 
	ZafRegionStruct region = drawRegion;

	if (scrollType == ZAF_HORIZONTAL_SLIDER || scrollType == ZAF_VERTICAL_SLIDER)
	{
		display->SetForeground(palette.colorBackground);
		display->SetMonoForeground(palette.monoBackground);

		display->Rectangle(region.left, region.top, region.right, region.top + 4, 0, true);
		display->Rectangle(region.left, region.top + 4, region.left + 4, region.bottom - 4, 0, true);
		display->Rectangle(region.right - 4, region.top + 4, region.right, region.bottom - 4, 0, true);
		display->Rectangle(region.left, region.bottom - 4, region.right, region.bottom, 0, true);
		region-=4;
		if (scrollType == ZAF_HORIZONTAL_SLIDER)
		{
			int regionOffset = (region.Height() - 4) / 2;
			ZafRegionStruct backgroundRegion = region;
			region.top += regionOffset;
			region.bottom -= regionOffset;
			if (region.Height() % 2)
				region.top++;
			// Fill in background above track bar.
			display->Rectangle(backgroundRegion.left, backgroundRegion.top,
				backgroundRegion.right, region.top - 1, 1, true);
			// Fill in background below track bar.
			display->Rectangle(backgroundRegion.left, region.bottom  + 1,
				backgroundRegion.right, backgroundRegion.bottom, 1, true);
		}
		else
		{
			int regionOffset = (region.Width() - 4) / 2;
			ZafRegionStruct backgroundRegion = region;
			region.left += regionOffset;
			region.right -= regionOffset;
			if (region.Width() % 2)
				region.left++;
			// Fill in background to the left of the track bar.
			display->Rectangle(backgroundRegion.left, backgroundRegion.top,
				region.left - 1, backgroundRegion.bottom, 1, true);
			// Fill in background to the right of the track bar.
			display->Rectangle(region.right + 1, backgroundRegion.top,
				backgroundRegion.right, backgroundRegion.bottom, 1, true);
		}
		DrawBorder(region, ccode);
		if (Focus())
			mButton->DrawFocus(drawRegion, ccode);
		EndDraw();
		return (false);
	}
	else if (scrollType == ZAF_SIZEGRIP_SCROLL)
	{
		ZafPaletteStruct lightShadow = LogicalPalette(ZAF_PM_LIGHT_SHADOW, ZAF_PM_ANY_STATE);
		ZafPaletteStruct darkShadow = LogicalPalette(ZAF_PM_DARK_SHADOW, ZAF_PM_ANY_STATE);
		ZafPaletteStruct whiteShadow = lightShadow;

		// Copy the background colors to the foreground since display->Line() uses 
		// the foreground color.  The "shadow" palettes have different colors in 
		// the foreground and background entries so they can generate two shades
		// of shadow.
		whiteShadow.colorForeground = whiteShadow.colorBackground;

		display->Rectangle(drawRegion, 0, true);
		--drawRegion.right;
		--drawRegion.bottom;

		display->SetPalette(darkShadow);
		display->Line(drawRegion.right - 1, drawRegion.bottom, drawRegion.right, drawRegion.bottom - 1);
		display->Line(drawRegion.right - 2, drawRegion.bottom, drawRegion.right, drawRegion.bottom - 2);
		display->Line(drawRegion.right - 5, drawRegion.bottom, drawRegion.right, drawRegion.bottom - 5);
		display->Line(drawRegion.right - 6, drawRegion.bottom, drawRegion.right, drawRegion.bottom - 6);
		display->Line(drawRegion.right - 9, drawRegion.bottom, drawRegion.right, drawRegion.bottom - 9);
		display->Line(drawRegion.right - 10, drawRegion.bottom, drawRegion.right, drawRegion.bottom - 10);

		display->SetPalette(whiteShadow);
		display->Line(drawRegion.right - 3, drawRegion.bottom, drawRegion.right, drawRegion.bottom - 3);
		display->Line(drawRegion.right - 7, drawRegion.bottom, drawRegion.right, drawRegion.bottom - 7);
		display->Line(drawRegion.right - 11, drawRegion.bottom, drawRegion.right, drawRegion.bottom - 11);

		display->SetPalette(lightShadow);
		display->Line(drawRegion.right - 4, drawRegion.bottom, drawRegion.right, drawRegion.bottom - 4);
		display->Line(drawRegion.right - 8, drawRegion.bottom, drawRegion.right, drawRegion.bottom - 8);
		display->Line(drawRegion.right - 12, drawRegion.bottom, drawRegion.right, drawRegion.bottom - 12);
	}
	else
		display->Rectangle(0, 0, zafRegion.Width() - 1, zafRegion.Height() - 1, 0, true);

	EndDraw();

	return (ccode);
}
#endif

ZafEventType ZafScrollBar::Event(const ZafEventStruct &event)
{
	ZafEventType ccode = LogicalEvent(event);

	if (modifyMode && event.InputType() == E_MOUSE)
		return (Modify(event));

	// Calculate the updateRegion.
	ZafRegionStruct updateRegion;
	if (event.InputType() == E_MOUSE && ccode != L_VIEW)
	{
		if (scrollType == ZAF_VERTICAL_SCROLL)
		{
			updateRegion.left = 0;
			updateRegion.top = lButton->zafRegion.bottom + 1;
			updateRegion.right = zafRegion.Width() - 1;
			updateRegion.bottom = rButton->zafRegion.top - 1;
		}
		else if (scrollType == ZAF_HORIZONTAL_SCROLL)
		{
			updateRegion.left = lButton->zafRegion.right + 1;
			updateRegion.top = 0;
			updateRegion.right = rButton->zafRegion.left - 1;
			updateRegion.bottom = zafRegion.Height() - 1;
		}
		else
		{
			updateRegion.left = updateRegion.top = 0;
			updateRegion.right = zafRegion.Width() - 1;
			updateRegion.bottom = zafRegion.Height() - 1;
		}
		updateRegion.coordinateType = zafRegion.coordinateType;
	}

	long scrollCurrent = scrollData->Current();
	long minimum = scrollData->Minimum();
	long maximum = scrollData->Maximum();
	long showing = scrollData->Showing();
	static ZafEventType direction = L_NONE;

	ZafRegionStruct newRegion;
	ZafWindow *parentWindow = DynamicPtrCast(parent, ZafWindow);

	// Check for zinc events.
	switch (ccode)
	{
	// ----- Create messages -----
	case S_INITIALIZE:
		// Create scroll bar buttons.
		Destroy();
		lButton = mButton = rButton = ZAF_NULLP(ZafScrollButton);

		if (ScrollType() == ZAF_VERTICAL_SCROLL)
		{
			lButton = new ZafScrollButton(ZAF_VTOP_BUTTON);
			lButton->SetNoncurrent(true);
			Add(lButton);
			rButton = new ZafScrollButton(ZAF_VBOTTOM_BUTTON);
			rButton->SetNoncurrent(true);
			Add(rButton);
			mButton = new ZafScrollButton(ZAF_VMIDDLE_BUTTON);
			if (supportObject)
				mButton->SetNoncurrent(true);
			Add(mButton);
		}
		else if (ScrollType() == ZAF_HORIZONTAL_SCROLL)
		{
			lButton = new ZafScrollButton(ZAF_HLEFT_BUTTON);
			lButton->SetNoncurrent(true);
			Add(lButton);
			rButton = new ZafScrollButton(ZAF_HRIGHT_BUTTON);
			rButton->SetNoncurrent(true);
			Add(rButton);
			mButton = new ZafScrollButton(ZAF_HMIDDLE_BUTTON);
			if (supportObject)
				mButton->SetNoncurrent(true);
			Add(mButton);
		}
		else if (ScrollType() == ZAF_VERTICAL_SLIDER)
		{
			mButton = new ZafScrollButton(ZAF_VMIDDLE_BUTTON);
			Add(mButton);
		}
		else if (ScrollType() == ZAF_HORIZONTAL_SLIDER)
		{
			mButton = new ZafScrollButton(ZAF_HMIDDLE_BUTTON);
			Add(mButton);
		}

		// Set drag selection to true to cause scrolling to happen as the thumb
		// button is dragged.
/* START BLOCK COMMENT
**			if (!SupportObject() || (parent && (parent->IsA(ID_ZAF_TEXT) ||
**				parent->IsA(ID_ZAF_VT_LIST) || parent->IsA(ID_ZAF_HZ_LIST)) ))
**				SetExtendedSelection(true);
END BLOCK COMMENT */
		if (SupportObject())
			SetBordered(false);
		ZafWindow::Event(event);
		break;

	case S_COMPUTE_SIZE:
		{
			// Get the appropriate available region from the parent.
			if (RegionType() == ZAF_AVAILABLE_REGION)
			{
				ZafVtJustify vLocation = ZAF_VT_TOP;
				if (ScrollType() == ZAF_HORIZONTAL_SCROLL)
					vLocation = ZAF_VT_BOTTOM;
				zafRegion = parent->MaxRegion(this, vLocation, ZAF_HZ_LEFT);
			}

			if (scrollType == ZAF_VERTICAL_SCROLL || scrollType == ZAF_CORNER_SCROLL ||
				scrollType == ZAF_VERTICAL_SLIDER || scrollType == ZAF_SIZEGRIP_SCROLL)
				if (RegionType() == ZAF_AVAILABLE_REGION)
					zafRegion.left = zafRegion.right - ZAF_SCROLLBAR_WIDTH;
//				else
				else if (autoSize)
					zafRegion.right = zafRegion.left + ZAF_SCROLLBAR_WIDTH;
			if (scrollType == ZAF_HORIZONTAL_SCROLL || scrollType == ZAF_CORNER_SCROLL ||
				scrollType == ZAF_HORIZONTAL_SLIDER || scrollType == ZAF_SIZEGRIP_SCROLL)
				if (RegionType() == ZAF_AVAILABLE_REGION)
					zafRegion.top = zafRegion.bottom - ZAF_SCROLLBAR_WIDTH;
//				else
				else if (autoSize)
					zafRegion.bottom = zafRegion.top + ZAF_SCROLLBAR_WIDTH;
		}
		break;

	case N_SIZE:
		{
			ZafWindowObject *object;

			// Adjust the non-support object sizes.
			for (object = First(); object; object = object->Next())
				object->Event(S_COMPUTE_SIZE);

			// Reset the scroll bar or slider after setting its
			// new dimensions (S_COMPUTE_SIZE) but before causing it to redraw
			// (OSSize()).
			if (scrollType == ZAF_VERTICAL_SCROLL || scrollType == ZAF_VERTICAL_SLIDER)
			{
				ZafScrollStruct scroll = { scrollData->Current(), scrollData->Minimum(),
					scrollData->Maximum(), scrollData->Showing(), scrollData->Delta() };
				Event(ZafEventStruct(S_VSCROLL_SET, 0, scroll));
			}
			else if (scrollType == ZAF_HORIZONTAL_SCROLL || scrollType == ZAF_HORIZONTAL_SLIDER)
			{
				ZafScrollStruct scroll = { scrollData->Current(), scrollData->Minimum(),
					scrollData->Maximum(), scrollData->Showing(), scrollData->Delta() };
				Event(ZafEventStruct(S_HSCROLL_SET, 0, scroll));
			}

			// Finalize the sizing operation.
			for (object = First(); object; object = object->Next())
				object->OSSize();
		}
		break;

	case N_MOUSE_ENTER:
		ZafWindowObject::Event(event);
		if (!editMode && scrollType == ZAF_SIZEGRIP_SCROLL && parentWindow->Sizeable() &&
			!parentWindow->Maximized())
			eventManager->SetDeviceState(E_MOUSE, DM_BOTTOM_RIGHT_CORNER);
		break;

	case L_DOUBLE_CLICK:
	case L_BEGIN_SELECT:
		{
			if (Disabled())
				break;

			// Clicking on a corner scroll does nothing.
			if (scrollType == ZAF_CORNER_SCROLL)
				return (ZafWindowObject::Event(event));

			// Clicking on a size grip will size the window if the window
			// can be sized.
			if (scrollType == ZAF_SIZEGRIP_SCROLL)
			{
				if (parentWindow->Sizeable() && !parentWindow->Maximized())
				{
					ZafRawCode sizeFlags = ZAF_SIZE_RIGHT | ZAF_SIZE_BOTTOM;
					parent->Event(ZafEventStruct(S_SIZE_MODE, sizeFlags, event.position));
				}
				break;
			}

			ZafEventStruct sEvent;
			selected = ZAF_NULLP(ZafScrollButton);

			if (mButton && mButton->zafRegion.Overlap(event.position))
			{
				selected = mButton;

				// Track the button regions to check that it stays within
				// range.
				ZafRegionStruct startRegion = mButton->zafRegion;
				newRegion = startRegion;
#ifdef ZafUseLazyScrollMethod
				startPosition = currentPosition = event.position;

				// Draw the button to indicate it's being dragged.
				BeginDraw();
				display->RectangleXORDiff(ZAF_NULLP(ZafRegionStruct), &newRegion);
				EndDraw();
#else
				currentPosition.column = newRegion.left;
				currentPosition.line = newRegion.top;
				startPosition = event.position;
#endif

				windowManager->CaptureMouse(this);
			}
			else if (scrollType == ZAF_VERTICAL_SLIDER || scrollType == ZAF_HORIZONTAL_SLIDER)
			{
				// If the L_BEGIN_SELECT was not on the middle button and the
				// scroll bar is a slider, then move the middle button to where
				// the mouse click ocurred.
				long pos, region, range = maximum - minimum;
				sEvent.scroll = *scrollData;
 				if (scrollType == ZAF_VERTICAL_SLIDER)
				{
					pos = (updateRegion.bottom - event.position.line);
					region = updateRegion.Height()/*  - mButton->zafRegion.Height() */;
					sEvent.type = N_VSCROLL;
				}
				else
				{
					pos = (event.position.column - updateRegion.left);
					region = updateRegion.Width()/*  - mButton->zafRegion.Width() */;
					sEvent.type = N_HSCROLL;
				}
				sEvent.scroll.delta = region ? ((pos * range + region/2) / region) -
					(scrollCurrent - minimum) : 0;

				// Send the event to cause the update to occur.
				Event(sEvent);
			}
			else
			{
				// The mouse click was in the page up/page down area of the 
				// scroll bar.
				ZafEventStruct sEvent;
				sEvent.type = (scrollType == ZAF_VERTICAL_SCROLL) ? N_VSCROLL : N_HSCROLL;
				sEvent.scroll = *scrollData;
				if (scrollType == ZAF_VERTICAL_SCROLL)
				{
					// Selection of vertical page (previous/next).
					if (event.position.line < mButton->zafRegion.top)
						direction = L_PGUP;
					else
						direction = L_PGDN;
				}
				else if (scrollType == ZAF_HORIZONTAL_SCROLL)
				{
					// Selection of horizontal page (previous/next).
					if (event.position.column < mButton->zafRegion.left)
						direction = L_PGUP;
					else
						direction = L_PGDN;
				}

				if (direction == L_PGUP)
				{
					if (scrollCurrent - showing < minimum)
						sEvent.scroll.delta = minimum - scrollCurrent;
					else
						sEvent.scroll.delta = -showing;
				}
				else
				{
					if (scrollCurrent + showing > maximum)
						sEvent.scroll.delta = maximum - scrollCurrent;
					else
						sEvent.scroll.delta = showing;
				}

/* START BLOCK COMMENT
**	  				Event(sEvent);
**					if (SupportObject())
**						parent->Event(sEvent);
END BLOCK COMMENT */

				ZafTimer *repeatTimer = new ZafTimer(D_ON, InitialDelay());
				repeatTimer->Add(this, N_INITIAL_DELAY);
				repeatTimer->SetStringID(ZAF_ITEXT("ZafScrollRepeat"));
				eventManager->Add(repeatTimer);
				windowManager->CaptureMouse(this);
				currentPosition = event.position;

  				Event(sEvent);
				if (SupportObject())
					parent->Event(sEvent);
			}
		}
		break;

//	case L_CONTINUE_COPY_DRAG:
	case L_CONTINUE_SELECT:
		{
			if (windowManager->dragObject)
				ZafWindowObject::Event(event);

			if (selected)
			{
#ifdef ZafUseLazyScrollMethod
				long deltaX = event.position.column - currentPosition.column;
				long deltaY = event.position.line - currentPosition.line;

				newRegion = selected->zafRegion;
				if (scrollType == ZAF_VERTICAL_SLIDER || scrollType == ZAF_VERTICAL_SCROLL)
					newRegion.VtShift(currentPosition.line - startPosition.line);
				if (scrollType == ZAF_HORIZONTAL_SLIDER || scrollType == ZAF_HORIZONTAL_SCROLL)
					newRegion.HzShift(currentPosition.column - startPosition.column);

				if (scrollType == ZAF_VERTICAL_SLIDER || scrollType == ZAF_VERTICAL_SCROLL)
					deltaX = 0;
				else if (newRegion.left + deltaX < updateRegion.left)
					deltaX = updateRegion.left - newRegion.left;
				else if (newRegion.right + deltaX > updateRegion.right)
					deltaX = updateRegion.right - newRegion.right;
				if (scrollType == ZAF_HORIZONTAL_SLIDER || scrollType == ZAF_HORIZONTAL_SCROLL)
					deltaY = 0;
				else if (newRegion.top + deltaY < updateRegion.top)
					deltaY = updateRegion.top - newRegion.top;
				else if (newRegion.bottom + deltaY > updateRegion.bottom)
					deltaY = updateRegion.bottom - newRegion.bottom;

				if (deltaX || deltaY)
				{
					// Update the newRegion.
					ZafRegionStruct oldRegion = newRegion;
					newRegion.HzShift((int)deltaX);
					newRegion.VtShift((int)deltaY);
					currentPosition.column += (int)deltaX;
					currentPosition.line += (int)deltaY;
					{
						BeginDraw();
						display->RectangleXORDiff(&oldRegion, &newRegion);
						EndDraw();
					}
				}
#else
				long deltaX = event.position.column - startPosition.column;
				long deltaY = event.position.line - startPosition.line;

				newRegion = selected->zafRegion;
				newRegion.VtShift(currentPosition.line - newRegion.top);
				newRegion.HzShift(currentPosition.column - newRegion.left);
				if (scrollType == ZAF_VERTICAL_SLIDER || scrollType == ZAF_VERTICAL_SCROLL)
					deltaX = 0;
				else if (newRegion.left + deltaX < updateRegion.left)
					deltaX = updateRegion.left - newRegion.left;
				else if (newRegion.right + deltaX > updateRegion.right)
					deltaX = updateRegion.right - newRegion.right;
				if (scrollType == ZAF_HORIZONTAL_SLIDER || scrollType == ZAF_HORIZONTAL_SCROLL)
					deltaY = 0;
				else if (newRegion.top + deltaY < updateRegion.top)
					deltaY = updateRegion.top - newRegion.top;
				else if (newRegion.bottom + deltaY > updateRegion.bottom)
					deltaY = updateRegion.bottom - newRegion.bottom;

				if (deltaX || deltaY)
				{
					// Update the newRegion.
					newRegion.HzShift((int)deltaX);
					newRegion.VtShift((int)deltaY);
				}

				ZafEventStruct sEvent;
				long pos;
				long range = maximum - minimum;
				long region;
				if (scrollType == ZAF_VERTICAL_SLIDER || scrollType == ZAF_VERTICAL_SCROLL)
				{
					if (scrollType == ZAF_VERTICAL_SLIDER)
						pos = updateRegion.bottom - newRegion.bottom;
					else
						pos = newRegion.top - updateRegion.top;
					region = updateRegion.Height() - mButton->zafRegion.Height();
					sEvent.type = N_VSCROLL;
				}
				else if (scrollType == ZAF_HORIZONTAL_SLIDER || scrollType == ZAF_HORIZONTAL_SCROLL)
				{
					pos = newRegion.left - updateRegion.left;
					region = updateRegion.Width() - mButton->zafRegion.Width();
					sEvent.type = N_HSCROLL;
				}
				sEvent.scroll = *scrollData;
				sEvent.scroll.delta = region ? ((pos * range + region - 1) /
					region) - (scrollCurrent - minimum) : 0;
				// Reset the scroll region.
				sEvent.rawCode = (ZafRawCode)L_CONTINUE_SELECT;
				Event(sEvent);
				if (sEvent.scroll.delta && SupportObject())
					parent->Event(sEvent);
#endif
			}
			else
			{
				// Page event.  Keep track of mouse position so can determine
				// if scrolling needs to happen when get a timer message.
				currentPosition = event.position;
			}
		}
		break;

	case S_CURRENT:
	case S_NON_CURRENT:
//		if (scrollType != ZAF_HORIZONTAL_SLIDER && scrollType != ZAF_VERTICAL_SLIDER &&
//			mButton)
		if (mButton)
			mButton->Event(event);
		ZafWindow::Event(event);
		Redisplay();
		break;

//	case L_END_COPY_DRAG:
	case L_END_SELECT:
		if (windowManager->MouseEventRoute() == this)
			windowManager->CaptureMouse(ZAF_NULLP(ZafWindowObject));
		if (selected)
		{
			newRegion = selected->zafRegion;
			selected = ZAF_NULLP(ZafScrollButton);
#ifdef ZafUseLazyScrollMethod
			if (scrollType == ZAF_VERTICAL_SLIDER || scrollType == ZAF_VERTICAL_SCROLL)
				newRegion.VtShift(currentPosition.line - startPosition.line);
			if (scrollType == ZAF_HORIZONTAL_SLIDER || scrollType == ZAF_HORIZONTAL_SCROLL)
				newRegion.HzShift(currentPosition.column - startPosition.column);
			BeginDraw();
			display->RectangleXORDiff(&newRegion, ZAF_NULLP(ZafRegionStruct));
			EndDraw();
			ZafPositionStruct sMousePosition = event.position;
			sMousePosition.line += zafRegion.top;
			sMousePosition.column += zafRegion.left;
//			if (!zafRegion.Overlap(sMousePosition))
//				break;
			// Update scroll information.
			ZafEventStruct sEvent;
			long pos = 0;
			long range = maximum - minimum;
			long region = 0;
			if (scrollType == ZAF_VERTICAL_SLIDER || scrollType == ZAF_VERTICAL_SCROLL)
			{
				if (scrollType == ZAF_VERTICAL_SLIDER)
					pos = updateRegion.bottom - newRegion.bottom;
				else
					pos = newRegion.top - updateRegion.top;
				region = updateRegion.Height() - mButton->zafRegion.Height();
				sEvent.type = N_VSCROLL;
			}
			else if (scrollType == ZAF_HORIZONTAL_SLIDER || scrollType == ZAF_HORIZONTAL_SCROLL)
			{
				pos = newRegion.left - updateRegion.left;
				region = updateRegion.Width() - mButton->zafRegion.Width();
				sEvent.type = N_HSCROLL;
			}
			sEvent.scroll = *scrollData;
			sEvent.scroll.delta = region ? ((pos * range + region - 1) /
				region) - (scrollCurrent - minimum) : 0;
			// Reset the scroll region.
			sEvent.rawCode = (ZafRawCode)L_END_SELECT;
			Event(sEvent);
			if (sEvent.scroll.delta && SupportObject())
				parent->Event(sEvent);
#endif
		}
		else
		{
			// Page event.
			ZafDevice *repeatTimer = eventManager->GetObject(ZAF_ITEXT("ZafScrollRepeat"));
			if (repeatTimer)
			{
				eventManager->Subtract(repeatTimer);
				delete repeatTimer;
			}
		}
		if (windowManager->dragObject)
			ZafWindowObject::Event(event);
		break;

	case N_INITIAL_DELAY:
	case N_REPEAT_DELAY:
		{
			ZafPositionStruct mousePosition = currentPosition;
			mousePosition.line += zafRegion.top;
			mousePosition.column += zafRegion.left;

			// If the last mouse position was in the zafRegion, we _might_
			// need to update depending on whether the mouse was in the paging
			// area it was down clicked in.
			if (zafRegion.Overlap(mousePosition))
			{
				if ((scrollType == ZAF_VERTICAL_SCROLL &&
					((direction == L_PGUP && currentPosition.line < mButton->zafRegion.top) ||
					(direction == L_PGDN && currentPosition.line > mButton->zafRegion.bottom))) ||
					(scrollType == ZAF_HORIZONTAL_SCROLL &&
					((direction == L_PGUP && currentPosition.column < mButton->zafRegion.left) ||
					(direction == L_PGDN && currentPosition.column > mButton->zafRegion.right))))
				{
					ZafEventStruct sEvent;
					sEvent.type = scrollType == ZAF_VERTICAL_SCROLL ? N_VSCROLL : N_HSCROLL;
					sEvent.scroll = *scrollData;
					if (direction == L_PGUP)
					{
						if (scrollCurrent - showing < minimum)
							sEvent.scroll.delta = minimum - scrollCurrent;
						else
							sEvent.scroll.delta = -showing;
					}
					else
					{
						if (scrollCurrent + showing > maximum)
							sEvent.scroll.delta = maximum - scrollCurrent;
						else
							sEvent.scroll.delta = showing;
					}

					if (sEvent.scroll.delta)
					{
						Event(sEvent);
						if (SupportObject())
							parent->Event(sEvent);
					}
				}
			}
			if (ccode == N_INITIAL_DELAY)
			{
				ZafTimer *repeatTimer = DynamicPtrCast(eventManager->GetObject(ZAF_ITEXT("ZafScrollRepeat")),
					ZafTimer);
				if (repeatTimer)
				{
					repeatTimer->SetNotifyMessage(N_REPEAT_DELAY);
					repeatTimer->SetInterval(RepeatDelay());
				}
			}
		}
		break;

	case L_UP:
	case L_DOWN:
	case L_LEFT:
	case L_RIGHT:
	case L_PGUP:
	case L_PGDN:
	case L_FIRST:
	case L_LAST:
		{
			ZafEventStruct sEvent;
			sEvent.scroll = *scrollData;
			if (scrollType == ZAF_VERTICAL_SLIDER)
			{
				sEvent.type = N_VSCROLL;
				if (ccode == L_DOWN || ccode == L_RIGHT)
					sEvent.scroll.delta = -scrollData->Delta();
				else if (ccode == L_PGUP)
					sEvent.scroll.delta = scrollData->Showing();
				else if (ccode == L_PGDN)
					sEvent.scroll.delta = -scrollData->Showing();
				else if (ccode == L_FIRST)
					sEvent.scroll.delta = scrollData->Maximum() - scrollData->Minimum();
				else if (ccode == L_LAST)
					sEvent.scroll.delta = -(scrollData->Maximum() - scrollData->Minimum());
			}
			else if (scrollType == ZAF_VERTICAL_SCROLL)
			{
				sEvent.type = N_VSCROLL;
				if (ccode == L_UP || ccode == L_LEFT)
					sEvent.scroll.delta = -scrollData->Delta();
				else if (ccode == L_PGUP)
					sEvent.scroll.delta = -scrollData->Showing();
				else if (ccode == L_PGDN)
					sEvent.scroll.delta = scrollData->Showing();
				else if (ccode == L_FIRST)
					sEvent.scroll.delta = -(scrollData->Maximum() - scrollData->Minimum());
				else if (ccode == L_LAST)
					sEvent.scroll.delta = (scrollData->Maximum() - scrollData->Minimum());
			}
			else
			{
				sEvent.type = N_HSCROLL;
				if (ccode == L_UP || ccode == L_LEFT)
					sEvent.scroll.delta = -scrollData->Delta();
				else if (ccode == L_PGUP)
					sEvent.scroll.delta = -scrollData->Showing();
				else if (ccode == L_PGDN)
					sEvent.scroll.delta = scrollData->Showing();
				else if (ccode == L_FIRST)
					sEvent.scroll.delta = -(scrollData->Maximum() - scrollData->Minimum());
				else if (ccode == L_LAST)
					sEvent.scroll.delta = scrollData->Maximum() - scrollData->Minimum();
			}

			// Prevent scrolling past the min or max.
			if (sEvent.scroll.delta < 0 && sEvent.scroll.current + sEvent.scroll.delta < sEvent.scroll.minimum)
				sEvent.scroll.delta = sEvent.scroll.minimum - sEvent.scroll.current;
			else if (sEvent.scroll.delta > 0 && sEvent.scroll.current + sEvent.scroll.delta > sEvent.scroll.maximum)
				sEvent.scroll.delta = sEvent.scroll.maximum - sEvent.scroll.current;

			// If somehow a delta of 0 was achieved, might as well not scroll.
			if (sEvent.scroll.delta)
			{
				Event(sEvent);
				if (SupportObject())
					parent->Event(sEvent);
			}
		}
		break;

	case L_NEXT:
	case L_PREVIOUS:
		ccode = S_UNKNOWN;
		break;

	// ----- Base class messages -----
	default:
		ccode = ZafWindow::Event(event);
		break;
	}

	// Return the control code.
	return (ccode);
}

ZafEventType ZafScrollBar::ScrollEvent(const ZafEventStruct &event)
{
	// Process the scrolling request.
	ZafEventType ccode = event.type;
	switch (ccode)
	{
	case S_VSCROLL_SET:
	case S_HSCROLL_SET:
		scrollData->SetScroll(event.scroll);
		OSSetScroll();
		break;

	case N_VSCROLL:
	case N_HSCROLL:
	case S_VSCROLL:
	case S_HSCROLL:
		{
			if (!screenID)
				return (ccode);

			long delta = event.scroll.delta;
			long scrollCurrent = scrollData->Current();
			long minimum = scrollData->Minimum();
			long maximum = scrollData->Maximum();

			long tScroll = scrollCurrent + delta;
			if (tScroll < minimum)
			{
				delta = scrollCurrent - minimum;
				tScroll = minimum;
			}
			else if (tScroll > maximum)
			{
				delta = maximum - scrollCurrent;
				tScroll = maximum;
			}

			scrollData->current = tScroll;
			scrollCurrent = tScroll;
			int size = scrollType == ZAF_VERTICAL_SCROLL ||
				scrollType == ZAF_VERTICAL_SLIDER ? mButton->zafRegion.bottom - mButton->zafRegion.top :
				mButton->zafRegion.right - mButton->zafRegion.left;

			// Determine region available for the thumb button.
			ZafRegionStruct region;
			if (scrollType == ZAF_VERTICAL_SCROLL)
			{
				region.left = 0;
				region.top = lButton->zafRegion.bottom + 1;
				region.right = zafRegion.Width() - 1;
				region.bottom = zafRegion.Height() - rButton->zafRegion.Height() - 1;
			}
			else if (scrollType == ZAF_HORIZONTAL_SCROLL)
			{
				region.left = lButton->zafRegion.right + 1;
				region.top = 0;
				region.right = zafRegion.Width() - rButton->zafRegion.Width() - 1;
				region.bottom = zafRegion.Height() - 1;
			}
			else
			{
				region.left = region.top = 0;
				region.right = clientRegion.Width() - 1;
				region.bottom = clientRegion.Height() - 1;
			}
			region.coordinateType = zafRegion.coordinateType;

			ZafRegionStruct update = mButton->zafRegion;
			if (scrollType == ZAF_VERTICAL_SCROLL || scrollType == ZAF_VERTICAL_SLIDER)
			{
				long value = region.bottom - region.top - size;
				value *= (scrollCurrent - minimum);
				if (maximum > minimum)
					value /= (maximum - minimum);
				if (scrollType == ZAF_VERTICAL_SLIDER)
				{
					mButton->zafRegion.bottom = region.bottom - (int)value;
					mButton->zafRegion.top = mButton->zafRegion.bottom - size;
				}
				else
				{
					mButton->zafRegion.top = region.top + (int)value;
					mButton->zafRegion.bottom = mButton->zafRegion.top + size;
				}
			}
			else if (scrollType == ZAF_HORIZONTAL_SCROLL || scrollType == ZAF_HORIZONTAL_SLIDER)
			{
				long value = region.right - region.left - size;
				value *= (scrollCurrent - minimum);
				if (maximum > minimum)
					value /= (maximum - minimum);
				mButton->zafRegion.left = region.left + (int)value;
				mButton->zafRegion.right = mButton->zafRegion.left + size;
			}
			if (screenID)
			{
				if ((ccode == S_VSCROLL || ccode == N_VSCROLL) &&
					((event.scroll.delta > 0  && scrollType != ZAF_VERTICAL_SLIDER && scrollType != ZAF_HORIZONTAL_SLIDER) ||
					(event.scroll.delta < 0 && (scrollType == ZAF_VERTICAL_SLIDER || scrollType == ZAF_HORIZONTAL_SLIDER))))
					update.bottom = mButton->zafRegion.top;
				else if (ccode == S_VSCROLL || ccode == N_VSCROLL)
					update.top = mButton->zafRegion.bottom;
				else if ((ccode == S_HSCROLL || ccode == N_HSCROLL) && event.scroll.delta > 0)
					update.right = mButton->zafRegion.left;
				else if (ccode == S_HSCROLL || ccode == N_HSCROLL)
					update.left = mButton->zafRegion.right;

				update.left += clientRegion.left;
				update.top += clientRegion.top;
				update.right += clientRegion.left;
				update.bottom += clientRegion.top;
				OSInvalidateRegion(&update);
//  				Event(ZafEventStruct(S_REDISPLAY_REGION, 0, update));

				ZafRegionStruct drawRegion;
				drawRegion.left = drawRegion.top = 0;
				drawRegion.right = mButton->zafRegion.Width() - 1;
				drawRegion.bottom = mButton->zafRegion.Height() - 1;
				drawRegion.coordinateType = mButton->zafRegion.coordinateType;
				windowManager->OSValidateObject(mButton);
				mButton->OSInvalidateRegion(&drawRegion);
//  				mButton->Event(ZafEventStruct(S_REDISPLAY_REGION, 0, drawRegion));
			}

			if (!SupportObject() && userFunction && (delta || event.rawCode == L_END_SELECT))
			{
				ZafEventStruct uEvent;
				uEvent.type = event.rawCode;
				uEvent.scroll = *scrollData;
				(*userFunction)(this, uEvent, L_SELECT);
			}
		}
		break;

	default:
		ccode = ZafWindow::ScrollEvent(event);
		break;
	}

	// Return the control code.
	return (ccode);
}

// ----- Attributes ---------------------------------------------------------

bool ZafScrollBar::SetFocus(bool setFocus)
{
	// Defer to the base class.
	return (ZafWindow::SetFocus(setFocus));
}

bool ZafScrollBar::SetVisible(bool visible)
{
	return ZafWindow::SetVisible(visible);
}

// ----- OS Specific Functions ----------------------------------------------

ZafEventType ZafScrollBar::OSEvent(const ZafEventStruct &)
{
	return (S_ERROR);
}

ZafError ZafScrollBar::OSGetScroll(void)
{
	return (ZAF_ERROR_NONE);
}

void ZafScrollBar::OSMapPalette(ZafPaletteStruct &palette, ZafPaletteType type, ZafPaletteState state)
{
	// Defer to the base class.
	ZafWindowObject::OSMapPalette(palette, type, state);
}

ZafError ZafScrollBar::OSSetScroll(void)
{
	// Reset the Scrollbar values if currently visible.
	if (screenID && scrollData && mButton)
	{
//		long delta = scrollData->Delta();
		long scrollCurrent = scrollData->Current();
		long minimum = scrollData->Minimum();
		long maximum = scrollData->Maximum();
		long showing = scrollData->Showing();

		long tScroll = scrollCurrent;
		if (tScroll < minimum)
		{
//			delta = scrollCurrent - minimum;
			tScroll = minimum;
		}
		else if (tScroll > maximum)
		{
//			delta = maximum - scrollCurrent;
			tScroll = maximum;
		}

		scrollData->current = tScroll;
		scrollCurrent = tScroll;
		int size = scrollType == ZAF_VERTICAL_SCROLL ||
			scrollType == ZAF_VERTICAL_SLIDER ? mButton->zafRegion.bottom - mButton->zafRegion.top :
			mButton->zafRegion.right - mButton->zafRegion.left;

		// Determine region available for the thumb button.
		ZafRegionStruct region;
		if (scrollType == ZAF_VERTICAL_SCROLL)
		{
			region.left = 0;
			region.top = lButton->zafRegion.bottom + 1;
			region.right = zafRegion.Width() - 1;
			region.bottom = zafRegion.Height() - rButton->zafRegion.Height() - 1;
		}
		else if (scrollType == ZAF_HORIZONTAL_SCROLL)
		{
			region.left = lButton->zafRegion.right + 1;
			region.top = 0;
			region.right = zafRegion.Width() - rButton->zafRegion.Width() - 1;
			region.bottom = zafRegion.Height() - 1;
		}
		else
		{
			region.left = region.top = 0;
			region.right = clientRegion.Width() - 1;
			region.bottom = clientRegion.Height() - 1;
		}
		region.coordinateType = zafRegion.coordinateType;

		ZafRegionStruct update = mButton->zafRegion;
		if (scrollType != ZAF_VERTICAL_SLIDER &&
			scrollType != ZAF_HORIZONTAL_SLIDER && SupportObject())
		{
			// Calculate thumb size.
			mButton->zafRegion = region;
			long sizeValue = ((long)showing * 100) / ZafMax(1, (int)(maximum - minimum + showing));
			size = ZafMin(region.Height(), region.Width());

			// If size == -1, thumb button will disappear.
			if (scrollType == ZAF_VERTICAL_SCROLL)
				size = (showing > 0 && maximum > minimum ?
					ZafMax((int)(region.Width() / 3), (int)(region.Height() * sizeValue / 100)) : -1);
			else if (scrollType == ZAF_HORIZONTAL_SCROLL)
				size = (showing > 0 && maximum > minimum ?
					ZafMax((int)(region.Height() / 3), (int)(region.Width() * sizeValue / 100)) : -1);
		}
		if (scrollType == ZAF_VERTICAL_SCROLL || scrollType == ZAF_VERTICAL_SLIDER)
		{
			long value = region.bottom - region.top - size;
			value *= (scrollCurrent - minimum);
			if (maximum > minimum)
				value /= (maximum - minimum);
			if (scrollType == ZAF_VERTICAL_SLIDER)
			{
				mButton->zafRegion.bottom = region.bottom - (int)value;
				mButton->zafRegion.top = mButton->zafRegion.bottom - size;
			}
			else
			{
				mButton->zafRegion.top = region.top + (int)value;
#if defined(ZAF_TEXT_MODE)
				mButton->zafRegion.bottom = ZafMin(mButton->zafRegion.top, mButton->zafRegion.top + size);
#else
				mButton->zafRegion.bottom = mButton->zafRegion.top + size;
#endif
			}
		}
		else if (scrollType == ZAF_HORIZONTAL_SCROLL || scrollType == ZAF_HORIZONTAL_SLIDER)
		{
			long value = region.right - region.left - size;
			value *= (scrollCurrent - minimum);
			if (maximum > minimum)
				value /= (maximum - minimum);
			mButton->zafRegion.left = region.left + (int)value;
#if defined(ZAF_TEXT_MODE)
			mButton->zafRegion.right = ZafMin(mButton->zafRegion.left, mButton->zafRegion.left + size);
#else
			mButton->zafRegion.right = mButton->zafRegion.left + size;
#endif

		}
/* START BLOCK COMMENT
**			if (bordered)
**			{
**				region.VtShift(clientRegion.top);
**				region.HzShift(clientRegion.left);
**			}
**			Event(ZafEventStruct(S_REDISPLAY_REGION, 0, region));
END BLOCK COMMENT */
		if (lButton && rButton)
		{
			lButton->SetDisabled(size < 0 ? true : false);
			rButton->SetDisabled(size < 0 ? true : false);
		}

		// Need to update mButton position?
		if (update != mButton->zafRegion && Visible() && AutomaticUpdate())
		{
			if (bordered)
			{
				update.VtShift(clientRegion.top);
				update.HzShift(clientRegion.left);
			}

			// Invalidate the exposed portions of the background and the middle
			// button.
//			OSInvalidateRegion(&update, false, false);
			mButton->OSSize();
//			windowManager->OSValidateObject(mButton);
//			mButton->Redisplay();
			OSInvalidateRegion(&clientRegion, false, false);
			OSInvalidateRegion(&mButton->zafRegion, false, false);
		}
	}
	return (ZAF_ERROR_NONE);
}

void ZafScrollBar::OSRegisterObject(void)
{
	ZafWindow::OSRegisterObject();
}

OSWindowID ZafScrollBar::OSScreenID(ZafScreenIDType) const
{
	return (screenID);
}

void ZafScrollBar::OSSize(void)
{
//	bool saveUpdate = automaticUpdate;
//	SetAutomaticUpdate(false);
	ZafWindow::OSSize();
//	SetAutomaticUpdate(saveUpdate);
}

// ----- ZafScrollButton ------------------------------------------------
ZafPaletteMap ZAF_FARDATA ZafScrollButton::defaultPaletteMap[] =
{
	{ ZAF_PM_DARK_SHADOW, ZAF_PM_DISABLED, { ZAF_LINE_SOLID, ZAF_PTN_SOLID_FILL, ZAF_CLR_LIGHTGRAY, ZAF_CLR_DARKGRAY, ZAF_MONO_BLACK, ZAF_MONO_WHITE, ZAF_FNT_DIALOG } },
	{ ZAF_PM_NONE, 0, { 0, 0, 0, 0, 0, 0, 0, 0 } }
};

#define ZAF_SCROLL_BUTTON_INFO
#include "img_def.cpp"

char ZAF_FARDATA ZafScrollButton::scrollUpArrowName[] = "scrollUpArrow";
char ZAF_FARDATA ZafScrollButton::scrollDownArrowName[] = "scrollDownArrow";
char ZAF_FARDATA ZafScrollButton::scrollLeftArrowName[] = "scrollLeftArrow";
char ZAF_FARDATA ZafScrollButton::scrollRightArrowName[] = "scrollRightArrow";

ZafBitmapData *ZafScrollButton::scrollUpArrowBitmap = ZAF_NULLP(ZafBitmapData);
ZafBitmapData *ZafScrollButton::scrollDownArrowBitmap = ZAF_NULLP(ZafBitmapData);
ZafBitmapData *ZafScrollButton::scrollLeftArrowBitmap = ZAF_NULLP(ZafBitmapData);
ZafBitmapData *ZafScrollButton::scrollRightArrowBitmap = ZAF_NULLP(ZafBitmapData);

ZafScrollButton::ZafScrollButton(ZafScrollButtonType tButtonType):
	ZafButton(0, 0, 0, 0, ZAF_NULLP(ZafIChar)),
	scrollButtonType(tButtonType)
{
	SetBordered(false);
	SetHzJustify(ZAF_HZ_CENTER);
	SetVtJustify(ZAF_VT_CENTER);
	SetRegionType(ZAF_AVAILABLE_REGION);
	SetAllowToggling(false);
	SetAutoRepeatSelection(true);

	// Initialize the scroll button information.
#if defined(ZAF_TEXT_MODE)
	SetDepth(0);
#else
	SetDepth(1);
#endif

	// Check the image information.
	ImageAllocate();

	if (scrollButtonType == ZAF_VTOP_BUTTON)
	{
		bitmapData = scrollUpArrowBitmap;
		value = L_UP;
	}
	else if (scrollButtonType == ZAF_VBOTTOM_BUTTON)
	{
		bitmapData = scrollDownArrowBitmap;
		value = L_DOWN;
	}
	else if (scrollButtonType == ZAF_HLEFT_BUTTON)
	{
		bitmapData = scrollLeftArrowBitmap;
		value = L_UP;
	}
	else if (scrollButtonType == ZAF_HRIGHT_BUTTON)
	{
		bitmapData = scrollRightArrowBitmap;
		value = L_DOWN;
	}

	memberUserFunction = (MemberUserFunction)&ZafScrollButton::Callback;
}

ZafScrollButton::~ZafScrollButton(void)
{
	// Check the image information.
	ImageFree();
}

ZafEventType ZafScrollButton::Callback(const ZafEventStruct &, ZafEventType ccode)
{
	if (ccode == L_SELECT)
		parent->Event(Value());

	return (0);
}

#if defined(ZAF_DEFAULT_DRAW)
ZafEventType ZafScrollButton::Draw(const ZafEventStruct &event,
	ZafEventType ccode)
{
	// Let ZafButton draw buttons other than slider buttons.
	ZafScrollBar *parentScroll = DynamicPtrCast(parent, ZafScrollBar);
	ZafScrollBarType scrollType = parentScroll->ScrollType();
	if (scrollType != ZAF_VERTICAL_SLIDER && scrollType != ZAF_HORIZONTAL_SLIDER)
		return(ZafButton::Draw(event, ccode));

	// Compute the actual draw region.
	ZafRegionStruct drawRegion = BeginDraw();

	display->SetClipRegion(event.region);

	ZafPaletteState state = PaletteState();

	ZafPaletteStruct lightShadow = LogicalPalette(ZAF_PM_LIGHT_SHADOW, ZAF_PM_ANY_STATE);
//	ZafPaletteStruct darkShadow = LogicalPalette(ZAF_PM_DARK_SHADOW, ZAF_PM_ANY_STATE);
	ZafPaletteStruct darkShadow = LogicalPalette(ZAF_PM_DARK_SHADOW, state);
	ZafPaletteStruct whiteShadow = lightShadow;
	ZafPaletteStruct blackShadow = darkShadow;

	// Copy the background colors to the foreground since display->Line() uses 
	// the foreground color.  The "shadow" palettes have different colors in 
	// the foreground and background entries so they can generate two shades
	// of shadow.
	whiteShadow.colorForeground = whiteShadow.colorBackground;
	blackShadow.colorForeground = blackShadow.colorBackground;

	ZafPaletteStruct polygonPalette = LogicalPalette(ZAF_PM_BACKGROUND, ZAF_PM_ANY_STATE);
	polygonPalette.colorForeground = polygonPalette.colorBackground;
	polygonPalette.monoForeground = polygonPalette.monoBackground;

	if (scrollType == ZAF_HORIZONTAL_SLIDER)
	{
		int midPoint = drawRegion.left + drawRegion.Width() / 2;
		int anglePoint = drawRegion.bottom - drawRegion.Width() / 2;

		ZafCoordinate polygon[12];
		polygon[0] = polygon[2] = polygon[10] = drawRegion.left + 1;
		polygon[1] = polygon[11] = polygon[9] = drawRegion.top + 1;
		polygon[3] = polygon[7] = anglePoint;
		polygon[4] = midPoint;
		polygon[5] = drawRegion.bottom - 2;
		polygon[6] = polygon[8] = drawRegion.right - 2;

		display->SetPalette(polygonPalette);
		display->Polygon(6, polygon, 0, true);

		// Draw the shadow pattern.
		display->SetPalette(whiteShadow);
		display->Line(drawRegion.left, drawRegion.top, drawRegion.right - 1, drawRegion.top);
		display->Line(drawRegion.left, drawRegion.top, drawRegion.left, anglePoint);
		display->Line(drawRegion.left, anglePoint, midPoint, drawRegion.bottom);

		display->SetPalette(blackShadow);
		display->Line(drawRegion.right, drawRegion.top, drawRegion.right, anglePoint);
		display->Line(drawRegion.right, anglePoint, midPoint, drawRegion.bottom);

		display->SetPalette(darkShadow);
		display->Line(drawRegion.right - 1, drawRegion.top + 1, drawRegion.right - 1, anglePoint);
		display->Line(drawRegion.right - 1, anglePoint, midPoint, drawRegion.bottom - 1);
	}
	else
	{
		int midPoint = drawRegion.top + drawRegion.Height() / 2;
		int anglePoint = drawRegion.right - drawRegion.Height() / 2;

		ZafCoordinate polygon[12];
		polygon[0] = polygon[2] = polygon[10] = drawRegion.left + 1;
		polygon[1] = polygon[11] = polygon[9] = drawRegion.top + 1;
		polygon[3] = polygon[5] = drawRegion.bottom - 1;
		polygon[4] = polygon[8] = anglePoint;
		polygon[6] = drawRegion.right - 2;
		polygon[7] = midPoint;

		display->SetPalette(polygonPalette);
		display->Polygon(6, polygon, 0, true);

		// Draw the shadow pattern.
		display->SetPalette(whiteShadow);
		display->Line(drawRegion.left, drawRegion.top, anglePoint, drawRegion.top);
		display->Line(drawRegion.left, drawRegion.top, drawRegion.left, drawRegion.bottom - 1);
		display->Line(anglePoint, drawRegion.top, drawRegion.right, midPoint);

		display->SetPalette(blackShadow);
		display->Line(drawRegion.right, midPoint, anglePoint, drawRegion.bottom);
		display->Line(drawRegion.left, drawRegion.bottom, anglePoint, drawRegion.bottom);

		display->SetPalette(darkShadow);
		display->Line(anglePoint,	drawRegion.bottom - 1, drawRegion.right - 1, midPoint);
		display->Line(drawRegion.left + 1, drawRegion.bottom - 1, anglePoint, drawRegion.bottom - 1);
	}

	EndDraw();

	return (ccode);
}

ZafEventType ZafScrollButton::DrawShadow(ZafRegionStruct &region,
	int depth, ZafEventType ccode)
{
	// Let ZafButton draw depressed shadow for non-thumb buttons.
	// Thumb buttons don't draw depressed and all scroll buttons draw
	// shadowing slightly differently than normal buttons.
	if (depth < 0 && scrollButtonType != ZAF_VMIDDLE_BUTTON && scrollButtonType != ZAF_HMIDDLE_BUTTON)
		return ZafWindowObject::DrawShadow(region, depth, ccode);

	ZafPaletteState state = PaletteState();

	ZafPaletteStruct lightShadow = LogicalPalette(ZAF_PM_LIGHT_SHADOW, ZAF_PM_ANY_STATE);
//	ZafPaletteStruct darkShadow = LogicalPalette(ZAF_PM_DARK_SHADOW, ZAF_PM_ANY_STATE);
	ZafPaletteStruct darkShadow = LogicalPalette(ZAF_PM_DARK_SHADOW, state);
	ZafPaletteStruct whiteShadow = lightShadow;
	ZafPaletteStruct blackShadow = darkShadow;

	// Copy the background colors to the foreground since display->Line() uses 
	// the foreground color.  The "shadow" palettes have different colors in 
	// the foreground and background entries so they can generate two shades
	// of shadow.
	whiteShadow.colorForeground = whiteShadow.colorBackground;
	blackShadow.colorForeground = blackShadow.colorBackground;

	// Draw the shadow pattern.
	display->SetPalette(lightShadow);
	display->Line(region.left, region.top, region.right - 1, region.top);
	display->Line(region.left, region.top, region.left, region.bottom - 1);

	display->SetPalette(whiteShadow);
	display->Line(region.left + 1, region.top + 1, region.right - 1, region.top + 1);
	display->Line(region.left + 1, region.top + 1, region.left + 1, region.bottom - 1);

	display->SetPalette(blackShadow);
	display->Line(region.left, region.bottom, region.right, region.bottom);
	display->Line(region.right, region.top, region.right, region.bottom);

	display->SetPalette(darkShadow);
	display->Line(region.left + 1, region.bottom - 1, region.right - 1, region.bottom - 1);
	display->Line(region.right - 1, region.top + 1, region.right - 1, region.bottom - 1);

	region -= ZAF_BORDER_SIZE;

	return (ccode);
}
#endif

ZafEventType ZafScrollButton::Event(const ZafEventStruct &event)
{
	ZafEventType ccode = LogicalEvent(event);

	// Check for zinc events.
	switch (ccode)
	{
	// ----- Create messages -----
	case S_COMPUTE_SIZE:
		{
			ZafScrollBar *parentScroll = DynamicPtrCast(parent, ZafScrollBar);
			ZafScrollBarType scrollType = parentScroll->ScrollType();

#if defined(ZAF_TEXT_MODE)
			ZafWindowObject::Event(event);

			if (scrollButtonType == ZAF_VTOP_BUTTON)
				zafRegion.bottom = zafRegion.top;
			else if (scrollButtonType == ZAF_VBOTTOM_BUTTON)
				zafRegion.top = zafRegion.bottom;
			else if (scrollButtonType == ZAF_HLEFT_BUTTON)
				zafRegion.right = zafRegion.left;
			else if (scrollButtonType == ZAF_HRIGHT_BUTTON)
				zafRegion.left = zafRegion.right;
			else if (scrollButtonType == ZAF_VMIDDLE_BUTTON)
				zafRegion.bottom = zafRegion.top;
			else if (scrollButtonType == ZAF_HMIDDLE_BUTTON)
				zafRegion.right = zafRegion.left;
#else
			int width, height, clipWidth, clipHeight;

			clipWidth = parent->zafRegion.right - parent->zafRegion.left;
			clipHeight = parent->zafRegion.bottom - parent->zafRegion.top;


			if (scrollType == ZAF_VERTICAL_SCROLL || scrollType == ZAF_VERTICAL_SLIDER)
			{
				width = clipWidth;
				if (scrollButtonType == ZAF_VMIDDLE_BUTTON &&
					scrollType == ZAF_VERTICAL_SCROLL && parent->SupportObject())
					height = zafRegion.Height();
				else
					height = clipWidth;
			}
			else
			{
				height = clipHeight;
				if (scrollButtonType == ZAF_HMIDDLE_BUTTON &&
					scrollType == ZAF_HORIZONTAL_SCROLL && parent->SupportObject())
					width = zafRegion.Width();
				else
					width = clipHeight;
			}

			ZafWindowObject::Event(event);

			// Resize if the region doesn't fit all the scroll buttons.
			if (scrollButtonType == ZAF_VTOP_BUTTON)
			{
				if (clipHeight / 3 < height)
					height = clipHeight / 3;
				zafRegion.bottom = zafRegion.top + height;
			}
			else if (scrollButtonType == ZAF_VBOTTOM_BUTTON)
			{
				if (clipHeight / 2 < height)
					height = clipHeight / 2;
				zafRegion.top = zafRegion.bottom - height;
			}
			else if (scrollButtonType == ZAF_HLEFT_BUTTON)
			{
				if (clipWidth / 3 < width)
					width = clipWidth / 3;
				zafRegion.right = zafRegion.left + width;
			}
			else if (scrollButtonType == ZAF_HRIGHT_BUTTON)
			{
				if (clipWidth / 2 < width)
					width = clipWidth / 2;
				zafRegion.left = zafRegion.right - width;
			}
			else if (scrollButtonType == ZAF_VMIDDLE_BUTTON)
			{
				zafRegion.bottom = zafRegion.top + height;
				if (scrollType == ZAF_VERTICAL_SLIDER)
					zafRegion.bottom -= 8;
			}
			else if (scrollButtonType == ZAF_HMIDDLE_BUTTON)
			{
				zafRegion.right = zafRegion.left + width;
				if (scrollType == ZAF_HORIZONTAL_SLIDER)
					zafRegion.right -= 8;
			}
#endif
		}

		break;

	default:
		ccode = ZafButton::Event(event);
		break;
	}

	return (ccode);
}

void ZafScrollButton::ImageAllocate(void)
{
#if !defined(ZAF_TEXT_MODE)
	// scrollUpArrowBitmap
	if (!scrollUpArrowBitmap)
	{
		ZafI18nData::AddStaticModule(ImageFree);
		scrollUpArrowBitmap = new ZafBitmapData(_scrollUpArrow_ZafBitmap);
		scrollUpArrowBitmap->staticHandle = true;
		scrollUpArrowBitmap->SetDestroyable(false);

		scrollDownArrowBitmap = new ZafBitmapData(_scrollDownArrow_ZafBitmap);
		scrollDownArrowBitmap->staticHandle = true;
		scrollDownArrowBitmap->SetDestroyable(false);

		scrollLeftArrowBitmap = new ZafBitmapData(_scrollLeftArrow_ZafBitmap);
		scrollLeftArrowBitmap->staticHandle = true;
		scrollLeftArrowBitmap->SetDestroyable(false);

		scrollRightArrowBitmap = new ZafBitmapData(_scrollRightArrow_ZafBitmap);
		scrollRightArrowBitmap->staticHandle = true;
		scrollRightArrowBitmap->SetDestroyable(false);
	}
#endif
}

void ZafScrollButton::ImageFree(bool globalRequest)
{
#if !defined(ZAF_TEXT_MODE)
	// Destroy the static images.
	if (globalRequest && scrollUpArrowBitmap)
	{
		scrollUpArrowBitmap->staticHandle = false;
		delete scrollUpArrowBitmap;
		scrollUpArrowBitmap = ZAF_NULLP(ZafBitmapData);
		scrollDownArrowBitmap->staticHandle = false;
		delete scrollDownArrowBitmap;
		scrollDownArrowBitmap = ZAF_NULLP(ZafBitmapData);
		scrollRightArrowBitmap->staticHandle = false;
		delete scrollRightArrowBitmap;
		scrollRightArrowBitmap = ZAF_NULLP(ZafBitmapData);
		scrollLeftArrowBitmap->staticHandle = false;
		delete scrollLeftArrowBitmap;
		scrollLeftArrowBitmap = ZAF_NULLP(ZafBitmapData);
	}
#endif
}

const ZafPaletteStruct *ZafScrollButton::MapClassPalette(ZafPaletteType type, ZafPaletteState state)
{
	const ZafPaletteStruct *palette = MapPalette(defaultPaletteMap, type, state);
	return (palette ? palette : ZafButton::MapClassPalette(type, state));
}

ZafScrollButtonType ZafScrollButton::SetScrollButtonType(ZafScrollButtonType tButtonType)
{
	scrollButtonType = tButtonType;
	return (scrollButtonType);
}


