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

#include <w_app.hpp>
#include <z_scrll2.hpp>

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

#if defined(ZAF_DEFAULT_DRAW)
ZafEventType ZafScrollBar::Draw(const ZafEventStruct &, ZafEventType ccode)
{
	return (ccode);
}
#endif

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

	if (ccode == E_OSEVENT)
		return ZafScrollBar::OSEvent(event);

	// Process ZAF events.
	switch (ccode)
	{
	case S_REGISTER_OBJECT:
		ccode = ZafWindowObject::Event(event);
		if (SupportObject())
		{
			// Initialize the scroll bar settings.
			if (ScrollType() != ZAF_CORNER_SCROLL)
				OSSetScroll();
		}
		break;

	case S_COMPUTE_SIZE:
		ZafWindowObject::Event(event);
		if (autoSize)
		{
#if defined(ZAF_WIN32)
			if (scrollType == ZAF_VERTICAL_SLIDER)
				zafRegion.right = zafRegion.left + 22;
			else if (scrollType == ZAF_VERTICAL_SCROLL)
				zafRegion.right = zafRegion.left + GetSystemMetrics(SM_CXVSCROLL) - 1;
			else if (scrollType == ZAF_HORIZONTAL_SLIDER)
				zafRegion.bottom = zafRegion.top + 22;
			else if (scrollType == ZAF_HORIZONTAL_SCROLL)
				zafRegion.bottom = zafRegion.top + GetSystemMetrics(SM_CYHSCROLL) - 1;
#else
			if (scrollType == ZAF_VERTICAL_SCROLL || scrollType == ZAF_VERTICAL_SLIDER)
		  		zafRegion.right = zafRegion.left + GetSystemMetrics(SM_CXVSCROLL) - 1;
			else if (scrollType == ZAF_HORIZONTAL_SCROLL || scrollType == ZAF_HORIZONTAL_SLIDER)
		  		zafRegion.bottom = zafRegion.top + GetSystemMetrics(SM_CYHSCROLL) - 1;
#endif
		}
		break;

	case S_HSCROLL:
	case S_VSCROLL:
		scrollData->SetCurrent(scrollData->current + event.scroll.delta);
		OSSetScroll();
		break;

	case S_HSCROLL_SET:
	case S_VSCROLL_SET:
		*scrollData = event.scroll;
		OSSetScroll();
		break;

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

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

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

ZafEventType ZafScrollBar::OSEvent(const ZafEventStruct &event)
{
	if (editMode && event.InputType() == E_MOUSE)
		return (ZafWindowObject::Event(event));

	ZafEventType ccode = event.type;

	switch (event.osEvent.message)
	{
	case WM_HSCROLL:
	case WM_VSCROLL:
		{
#if defined (ZAF_WIN32)
		int scrollCode = (int)LOWORD(event.osEvent.wParam);
		short nPos = (short)HIWORD(event.osEvent.wParam);
#else
		int scrollCode = (int)event.osEvent.wParam;
		short nPos = (short)LOWORD(event.osEvent.lParam);
#endif

		bool invert = ScrollType() == ZAF_VERTICAL_SLIDER;
		long scrollPos = scrollData->Current();
		ZafEventStruct scrollEvent;

		switch (scrollCode)
		{
		case SB_BOTTOM:
			if (invert)
				scrollPos = scrollData->Minimum();
			else
				scrollPos = scrollData->Maximum();
			scrollEvent.type = L_LAST;
			break;

		case SB_TOP:
			if (invert)
				scrollPos = scrollData->Maximum();
			else
				scrollPos = scrollData->Minimum();
			scrollEvent.type = L_FIRST;
			break;

		case SB_LINEDOWN:
			if (invert)
				scrollPos -= scrollData->Delta();
			else
				scrollPos += scrollData->Delta();
			scrollEvent.type = L_DOWN;
			break;

		case SB_LINEUP:
			if (invert)
				scrollPos += scrollData->Delta();
			else
				scrollPos -= scrollData->Delta();
			scrollEvent.type = L_UP;
			break;

		case SB_PAGEDOWN:
			if (invert)
				scrollPos -= scrollData->Showing();
			else
				scrollPos += scrollData->Showing();
			scrollEvent.type = L_PGDN;
			break;

		case SB_PAGEUP:
			if (invert)
				scrollPos += scrollData->Showing();
			else
				scrollPos -= scrollData->Showing();
			scrollEvent.type = L_PGUP;
			break;

		case SB_THUMBPOSITION:
		case SB_THUMBTRACK:
			if (invert)
				scrollPos = scrollData->Maximum() - (nPos + 32767) * scrollFactor;
			else
				scrollPos = scrollData->Minimum() + (nPos + 32767) * scrollFactor;
			scrollEvent.type = (scrollCode == SB_THUMBTRACK) ? L_CONTINUE_SELECT : L_END_SELECT;
			break;
		}

		if (scrollPos < scrollData->Minimum())
			scrollPos = scrollData->Minimum();
		else if (scrollPos > scrollData->Maximum())
			scrollPos = scrollData->Maximum();
		if (scrollPos != scrollData->Current())
		{
			long delta = scrollPos - scrollData->current;
			scrollData->current = scrollPos;
			OSSetScroll();
			scrollEvent.scroll = *scrollData;
			scrollEvent.scroll.delta = delta;
			if (SupportObject())
			{
				ZafEventStruct sEvent;
				if (ScrollType() == ZAF_VERTICAL_SCROLL)
					sEvent.type = N_VSCROLL;
				else
					sEvent.type = N_HSCROLL;
				sEvent.scroll.delta = delta;
				parent->Event(sEvent);
			}
			else
				(this->*memberUserFunction)(scrollEvent, L_SELECT);
		}

		ccode = 0;
		}
		break;

#if defined(ZAF_WIN32)
	case WM_CTLCOLORSTATIC:
		if (ScrollType() == ZAF_VERTICAL_SLIDER || ScrollType() == ZAF_HORIZONTAL_SLIDER)
		{
			// Get the palette.
			ZafPaletteStruct palette = parent->LogicalPalette(ZAF_PM_BACKGROUND, PaletteState());

			// Get the OS colors from the text palette.
			COLORREF colorForeground = (palette.colorForeground == ZAF_CLR_DEFAULT) ?
				palette.osPalette.colorForeground :
				((ZafScreenDisplay *)display)->colorTable[palette.colorForeground];
			COLORREF colorBackground = (palette.colorBackground == ZAF_CLR_DEFAULT) ?
				palette.osPalette.colorBackground :
				((ZafScreenDisplay *)display)->colorTable[palette.colorBackground];

			// Set the OS colors.
			SelectPalette((HDC)event.osEvent.wParam, ((ZafScreenDisplay *)display)->logicalPalette, FALSE);
			::SetTextColor((HDC)event.osEvent.wParam, colorForeground);
			SetBkColor((HDC)event.osEvent.wParam, colorBackground);

			// Get a background brush.
			HBRUSH backgroundBrush = ((ZafScreenDisplay *)display)->GetGdiCacheBrush(palette);
			((ZafScreenDisplay *)display)->ReleaseGdiCacheObject(backgroundBrush);
			ccode = (ZafEventType)backgroundBrush;
		}
		break;
#endif

	case WM_PAINT:
		if (OSDraw())
			ccode = DefaultCallback(event);
		else
			ccode = ZafWindowObject::Event(event);
		break;

	case WM_KEYDOWN:
	case WM_KEYUP:
	case WM_SYSKEYDOWN:
	case WM_SYSKEYUP:
		if (event.osEvent.wParam == VK_TAB)
			ccode = S_UNKNOWN;
		else if (event.osEvent.wParam == VK_UP ||
		 event.osEvent.wParam == VK_DOWN ||
		 event.osEvent.wParam == VK_RIGHT ||
		 event.osEvent.wParam == VK_LEFT)
			ccode = DefaultCallback(event);
		else
			ccode = ZafWindowObject::OSEvent(event);
		break;

	default:
		ccode = ZafWindowObject::OSEvent(event);
		break;
	}

	return (ccode);
}

ZafError ZafScrollBar::OSGetScroll(void)
{
	if (screenID && parent->SystemObject())
	{
		if (ScrollType() == ZAF_HORIZONTAL_SLIDER || ScrollType() == ZAF_VERTICAL_SLIDER)
		{
#if defined(ZAF_WIN32)
			int scrollPos = (int)SendMessage(screenID, TBM_GETPOS, (WPARAM)0, (LPARAM)0);
#else
			int scrollPos = GetScrollPos(screenID, SB_CTL);
#endif
			if (ScrollType() == ZAF_VERTICAL_SLIDER)
				scrollData->current = scrollData->maximum - (scrollPos + 32767) * scrollFactor * scrollData->delta;
			else
				scrollData->current = scrollData->minimum + (scrollPos + 32767) * scrollFactor * scrollData->delta;
		}
		else
		{
			int scrollPos = GetScrollPos(screenID, SupportObject() ? (ScrollType() == ZAF_VERTICAL_SCROLL ? SB_VERT : SB_HORZ) : SB_CTL);
			scrollData->current = scrollData->minimum + (scrollPos + 32767) * scrollFactor * scrollData->delta;
		}
	}

	return (ZAF_ERROR_NONE);
}

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

void ZafScrollBar::OSRegisterObject(void)
{
	if (ScrollType() == ZAF_HORIZONTAL_SCROLL || ScrollType() == ZAF_VERTICAL_SCROLL)
	{
		// Set the Windows style flags.
		DWORD dwStyle = WS_CHILD;
		if (visible)
			dwStyle |= WS_VISIBLE;
		if (ScrollType() == ZAF_HORIZONTAL_SCROLL)
			dwStyle |= SBS_HORZ;
		else
			dwStyle |= SBS_VERT;
	 	if (Disabled() && !editMode)
			dwStyle |= WS_DISABLED;

		// Create the scroll bar.
		screenID = ZafMSWindowsApp::CreateSubclassedWindow(this, ZAF_ITEXT("SCROLLBAR"), dwStyle);

		// Initialize the scroll bar settings.
		OSSetScroll();
	}
	else if (ScrollType() == ZAF_HORIZONTAL_SLIDER || ScrollType() == ZAF_VERTICAL_SLIDER)
	{
#if defined(ZAF_WIN32)
		// Set the Windows style flags.
		DWORD dwStyle = WS_CHILD | TBS_NOTICKS;
		if (visible)
			dwStyle |= WS_VISIBLE;
		if (ScrollType() == ZAF_HORIZONTAL_SLIDER)
			dwStyle |= TBS_HORZ;
		else
			dwStyle |= TBS_VERT;
	 	if (Disabled() && !editMode)
			dwStyle |= WS_DISABLED;

		// Create the slider.
		InitCommonControls();
		screenID = ZafMSWindowsApp::CreateSubclassedWindow(this, TRACKBAR_CLASS, dwStyle);
#else
		// Set the Windows style flags.
		DWORD dwStyle = WS_CHILD;
		if (visible)
			dwStyle |= WS_VISIBLE;
		if (ScrollType() == ZAF_HORIZONTAL_SLIDER)
			dwStyle |= SBS_HORZ;
		else
			dwStyle |= SBS_VERT;
	 	if (Disabled() && !editMode)
			dwStyle |= WS_DISABLED;

		// Create a scroll bar.
		screenID = ZafMSWindowsApp::CreateSubclassedWindow(this, ZAF_ITEXT("SCROLLBAR"), dwStyle);
#endif

		// Initialize the slider settings.
		OSSetScroll();
	}
}

ZafError ZafScrollBar::OSSetScroll(void)
{
	if (screenID && parent->SystemObject())
	{
		// Compute scroll values.
		// (Scroll values are adjusted for 16-bit range.)
		long scrollPositions = (scrollData->Maximum() - scrollData->Minimum() + 1);
		scrollFactor = (int)(scrollPositions / 65535U + 1);
		scrollPositions /= scrollFactor;
		short nMin = -32767; // Lowest value possible in Windows.
		short nMax = (short)(nMin + scrollPositions - 1);
		short nPos = (short)(nMin + (scrollData->Current() - scrollData->Minimum()) / scrollFactor);
#if defined(ZAF_WIN32)
		short nPage = (short)(scrollData->Showing() / scrollFactor);
#endif

		if (ScrollType() == ZAF_HORIZONTAL_SLIDER || ScrollType() == ZAF_VERTICAL_SLIDER)
		{
#if defined(ZAF_WIN32)
			SendMessage(screenID, TBM_SETRANGE, TRUE, MAKELONG(nMin, nMax));
			if (ScrollType() == ZAF_VERTICAL_SLIDER)
				SendMessage(screenID, TBM_SETPOS, TRUE, nMax - (nPos - nMin));
			else
				SendMessage(screenID, TBM_SETPOS, TRUE, nPos);
#else
			SetScrollRange(screenID, SB_CTL, nMin, nMax, FALSE);
			if (ScrollType() == ZAF_VERTICAL_SLIDER)
				SetScrollPos(screenID, SB_CTL, nMax - (nPos - nMin), TRUE);
			else
				SetScrollPos(screenID, SB_CTL, nPos, TRUE);
#endif
		}
		else
		{
			int scrollID = SupportObject() ? ((ScrollType() == ZAF_VERTICAL_SCROLL) ? SB_VERT : SB_HORZ) : SB_CTL;
#if defined(ZAF_WIN32)
			SCROLLINFO scrollInfo;
			scrollInfo.cbSize = sizeof(scrollInfo);
			scrollInfo.fMask = SIF_ALL;
			scrollInfo.nMin = nMin;
			scrollInfo.nMax = nMax + nPage - 1;
			scrollInfo.nPage = nPage;
			scrollInfo.nPos = nPos;
			SetScrollInfo(screenID, scrollID, &scrollInfo, TRUE);
#else
			SetScrollRange(screenID, scrollID, nMin, nMax, FALSE);
			SetScrollPos(screenID, scrollID, nPos, TRUE);
#endif
		}
	}

	return (ZAF_ERROR_NONE);
}

// ----- Stubs --------------------------------------------------------------

bool ZafScrollBar::SetFocus(bool setFocus)
{
	return ZafWindowObject::SetFocus(setFocus);
}

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

ZafEventType ZafScrollBar::ScrollEvent(const ZafEventStruct &event)
{
	return (event.type);
}

void ZafScrollBar::OSSize(void)
{
	ZafWindowObject::OSSize();
}

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