/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Netscape Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/NPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): */ #include "nsScrollbar.h" #include "nsToolkit.h" #include "nsGUIEvent.h" #include #include "nsUnitConversion.h" NS_IMPL_ADDREF(nsScrollbar) NS_IMPL_RELEASE(nsScrollbar) //------------------------------------------------------------------------- // // nsScrollbar constructor // //------------------------------------------------------------------------- nsScrollbar::nsScrollbar(PRBool aIsVertical) : nsWindow(), nsIScrollbar() { NS_INIT_REFCNT(); mPositionFlag = (aIsVertical) ? SBS_VERT : SBS_HORZ; mScaleFactor = 1.0f; mLineIncrement = 0; mBackground = ::GetSysColor(COLOR_SCROLLBAR); //prevent resource leaks.. if (mBrush) ::DeleteObject(mBrush); mBrush = ::CreateSolidBrush(NSRGB_2_COLOREF(mBackground)); } //------------------------------------------------------------------------- // // nsScrollbar destructor // //------------------------------------------------------------------------- nsScrollbar::~nsScrollbar() { } //------------------------------------------------------------------------- // // Query interface implementation // //------------------------------------------------------------------------- nsresult nsScrollbar::QueryInterface(const nsIID& aIID, void** aInstancePtr) { nsresult result = nsWindow::QueryInterface(aIID, aInstancePtr); static NS_DEFINE_IID(kInsScrollbarIID, NS_ISCROLLBAR_IID); if (result == NS_NOINTERFACE && aIID.Equals(kInsScrollbarIID)) { *aInstancePtr = (void*) ((nsIScrollbar*)this); NS_ADDREF_THIS(); result = NS_OK; } return result; } //------------------------------------------------------------------------- // // Define the range settings // //------------------------------------------------------------------------- NS_METHOD nsScrollbar::SetMaxRange(PRUint32 aEndRange) { if (aEndRange > 32767) mScaleFactor = aEndRange / 32767.0f; if (mWnd) { VERIFY(::SetScrollRange(mWnd, SB_CTL, 0, NSToIntRound(aEndRange / mScaleFactor), TRUE)); } return NS_OK; } //------------------------------------------------------------------------- // // Return the range settings // //------------------------------------------------------------------------- PRUint32 nsScrollbar::GetMaxRange(PRUint32& aRange) { int startRange, endRange; if (mWnd) { VERIFY(::GetScrollRange(mWnd, SB_CTL, &startRange, &endRange)); } aRange = (PRUint32)NSToIntRound(endRange * mScaleFactor); return NS_OK; } //------------------------------------------------------------------------- // // Set the thumb position // //------------------------------------------------------------------------- NS_METHOD nsScrollbar::SetPosition(PRUint32 aPos) { ::SetScrollPos(mWnd, SB_CTL, NSToIntRound(aPos / mScaleFactor), TRUE); return NS_OK; } //------------------------------------------------------------------------- // // Get the current thumb position. // //------------------------------------------------------------------------- PRUint32 nsScrollbar::GetPosition(PRUint32& aPosition) { aPosition = (PRUint32)NSToIntRound(::GetScrollPos(mWnd, SB_CTL) * mScaleFactor); return NS_OK; } //------------------------------------------------------------------------- // // Set the thumb size // //------------------------------------------------------------------------- NS_METHOD nsScrollbar::SetThumbSize(PRUint32 aSize) { if (mWnd) { SCROLLINFO si; si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_PAGE; si.nPage = NSToIntRound(aSize / mScaleFactor); ::SetScrollInfo(mWnd, SB_CTL, &si, TRUE); } return NS_OK; } //------------------------------------------------------------------------- // // Get the thumb size // //------------------------------------------------------------------------- NS_METHOD nsScrollbar::GetThumbSize(PRUint32& aSize) { if (mWnd) { SCROLLINFO si; si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_PAGE; VERIFY(::GetScrollInfo(mWnd, SB_CTL, &si)); aSize = (PRUint32)NSToIntRound(si.nPage * mScaleFactor); } else { aSize = 0; } return NS_OK; } //------------------------------------------------------------------------- // // Set the line increment for this scrollbar // //------------------------------------------------------------------------- NS_METHOD nsScrollbar::SetLineIncrement(PRUint32 aSize) { mLineIncrement = NSToIntRound(aSize / mScaleFactor); return NS_OK; } //------------------------------------------------------------------------- // // Get the line increment for this scrollbar // //------------------------------------------------------------------------- NS_METHOD nsScrollbar::GetLineIncrement(PRUint32& aSize) { aSize = (PRUint32)NSToIntRound(mLineIncrement * mScaleFactor); return NS_OK; } //------------------------------------------------------------------------- // // Set all scrolling parameters // //------------------------------------------------------------------------- NS_METHOD nsScrollbar::SetParameters(PRUint32 aMaxRange, PRUint32 aThumbSize, PRUint32 aPosition, PRUint32 aLineIncrement) { if (aMaxRange > 32767) mScaleFactor = aMaxRange / 32767.0f; if (mWnd) { SCROLLINFO si; si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE; si.nPage = NSToIntRound(aThumbSize / mScaleFactor); si.nPos = NSToIntRound(aPosition / mScaleFactor); si.nMin = 0; si.nMax = NSToIntRound(aMaxRange / mScaleFactor); ::SetScrollInfo(mWnd, SB_CTL, &si, TRUE); } mLineIncrement = NSToIntRound(aLineIncrement / mScaleFactor); return NS_OK; } //------------------------------------------------------------------------- // // paint message. Don't send the paint out // //------------------------------------------------------------------------- PRBool nsScrollbar::OnPaint() { return PR_FALSE; } PRBool nsScrollbar::OnResize(nsRect &aWindowRect) { return PR_FALSE; } //------------------------------------------------------------------------- // // Deal with scrollbar messages (actually implemented only in nsScrollbar) // //------------------------------------------------------------------------- PRBool nsScrollbar::OnScroll(UINT scrollCode, int cPos) { PRBool result = PR_TRUE; int newPosition; switch (scrollCode) { // scroll one line right or down // SB_LINERIGHT and SB_LINEDOWN are actually the same value //case SB_LINERIGHT: case SB_LINEDOWN: { newPosition = ::GetScrollPos(mWnd, SB_CTL) + mLineIncrement; PRUint32 range; PRUint32 size; GetMaxRange(range); GetThumbSize(size); PRUint32 max = range - size; if (newPosition > (int)max) newPosition = (int)max; // if an event callback is registered, give it the chance // to change the increment if (mEventCallback) { nsScrollbarEvent event; event.message = NS_SCROLLBAR_LINE_NEXT; event.widget = (nsWindow*)this; DWORD pos = ::GetMessagePos(); POINT cpos; cpos.x = LOWORD(pos); cpos.y = HIWORD(pos); ::ScreenToClient(mWnd, &cpos); event.point.x = cpos.x; event.point.y = cpos.y; event.time = ::GetMessageTime(); event.position = (PRUint32)NSToIntRound(newPosition * mScaleFactor); result = ConvertStatus((*mEventCallback)(&event)); newPosition = NSToIntRound(event.position / mScaleFactor); } ::SetScrollPos(mWnd, SB_CTL, newPosition, TRUE); break; } // scroll one line left or up //case SB_LINELEFT: case SB_LINEUP: { newPosition = ::GetScrollPos(mWnd, SB_CTL) - mLineIncrement; if (newPosition < 0) newPosition = 0; // if an event callback is registered, give it the chance // to change the decrement if (mEventCallback) { nsScrollbarEvent event; event.message = NS_SCROLLBAR_LINE_PREV; event.widget = (nsWindow*)this; DWORD pos = ::GetMessagePos(); POINT cpos; cpos.x = LOWORD(pos); cpos.y = HIWORD(pos); ::ScreenToClient(mWnd, &cpos); event.point.x = cpos.x; event.point.y = cpos.y; event.time = ::GetMessageTime(); event.position = (PRUint32)NSToIntRound(newPosition * mScaleFactor); result = ConvertStatus((*mEventCallback)(&event)); newPosition = NSToIntRound(event.position / mScaleFactor); } ::SetScrollPos(mWnd, SB_CTL, newPosition, TRUE); break; } // Scrolls one page right or down // case SB_PAGERIGHT: case SB_PAGEDOWN: { SCROLLINFO si; si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_PAGE; VERIFY(::GetScrollInfo(mWnd, SB_CTL, &si)); newPosition = ::GetScrollPos(mWnd, SB_CTL) + si.nPage; PRUint32 range; PRUint32 size; GetMaxRange(range); GetThumbSize(size); PRUint32 max = range - size; if (newPosition > (int)max) newPosition = (int)max; // if an event callback is registered, give it the chance // to change the increment if (mEventCallback) { nsScrollbarEvent event; event.message = NS_SCROLLBAR_PAGE_NEXT; event.widget = (nsWindow*)this; DWORD pos = ::GetMessagePos(); POINT cpos; cpos.x = LOWORD(pos); cpos.y = HIWORD(pos); ::ScreenToClient(mWnd, &cpos); event.point.x = cpos.x; event.point.y = cpos.y; event.time = ::GetMessageTime(); event.position = (PRUint32)NSToIntRound(newPosition * mScaleFactor);; result = ConvertStatus((*mEventCallback)(&event)); newPosition = NSToIntRound(event.position / mScaleFactor); } ::SetScrollPos(mWnd, SB_CTL, newPosition, TRUE); break; } // Scrolls one page left or up. //case SB_PAGELEFT: case SB_PAGEUP: { SCROLLINFO si; si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_PAGE; VERIFY(::GetScrollInfo(mWnd, SB_CTL, &si)); newPosition = ::GetScrollPos(mWnd, SB_CTL) - si.nPage; if (newPosition < 0) newPosition = 0; // if an event callback is registered, give it the chance // to change the increment if (mEventCallback) { nsScrollbarEvent event; event.message = NS_SCROLLBAR_PAGE_PREV; event.widget = (nsWindow*)this; DWORD pos = ::GetMessagePos(); POINT cpos; cpos.x = LOWORD(pos); cpos.y = HIWORD(pos); ::ScreenToClient(mWnd, &cpos); event.point.x = cpos.x; event.point.y = cpos.y; event.time = ::GetMessageTime(); event.position = (PRUint32)NSToIntRound(newPosition * mScaleFactor); result = ConvertStatus((*mEventCallback)(&event)); newPosition = NSToIntRound(event.position / mScaleFactor); } ::SetScrollPos(mWnd, SB_CTL, newPosition - 10, TRUE); break; } // Scrolls to the absolute position. The current position is specified by // the cPos parameter. case SB_THUMBPOSITION: case SB_THUMBTRACK: { newPosition = cPos; // if an event callback is registered, give it the chance // to change the increment if (mEventCallback) { nsScrollbarEvent event; event.message = NS_SCROLLBAR_POS; event.widget = (nsWindow*)this; DWORD pos = ::GetMessagePos(); POINT cpos; cpos.x = LOWORD(pos); cpos.y = HIWORD(pos); ::ScreenToClient(mWnd, &cpos); event.point.x = cpos.x; event.point.y = cpos.y; event.time = ::GetMessageTime(); event.position = (PRUint32)NSToIntRound(newPosition * mScaleFactor); result = ConvertStatus((*mEventCallback)(&event)); newPosition = NSToIntRound(event.position / mScaleFactor); } ::SetScrollPos(mWnd, SB_CTL, newPosition, TRUE); break; } } return result; } //------------------------------------------------------------------------- // // return the window class name and initialize the class if needed // //------------------------------------------------------------------------- LPCTSTR nsScrollbar::WindowClass() { return "SCROLLBAR"; } //------------------------------------------------------------------------- // // return window styles // //------------------------------------------------------------------------- DWORD nsScrollbar::WindowStyle() { return mPositionFlag | WS_CHILD | WS_CLIPSIBLINGS; } //------------------------------------------------------------------------- // // return window extended styles // //------------------------------------------------------------------------- DWORD nsScrollbar::WindowExStyle() { return 0; } //------------------------------------------------------------------------- // // get position/dimensions // //------------------------------------------------------------------------- NS_METHOD nsScrollbar::GetBounds(nsRect &aRect) { return nsWindow::GetBounds(aRect); }