//---------------------------------------------------------------------------- // ObjectWindows // (C) Copyright 1991, 1994 by Borland International, All Rights Reserved // // Implementation of class TScroller. //---------------------------------------------------------------------------- #pragma hdrignore SECTION #include #include #include #include #include #define max(a,b) (((a) > (b)) ? (a) : (b)) #define min(a,b) (((a) < (b)) ? (a) : (b)) #define abs(a) ((a) >= 0 ? (a) : -(a)) #if !defined(SECTION) || SECTION == 1 // // constructs a TScroller object // TScroller::TScroller(TWindow* window, int xUnit, int yUnit, long xRange, long yRange) { Window = window; XPos = YPos = 0; XUnit = xUnit; YUnit = yUnit; XRange = xRange; YRange = yRange; XLine = 1; YLine = 1; XPage = 1; YPage = 1; AutoMode = true; TrackMode = true; AutoOrg = true; HasHScrollBar = ToBool(Window && (Window->Attr.Style&WS_HSCROLL)); HasVScrollBar = ToBool(Window && (Window->Attr.Style&WS_VSCROLL)); } // // destructs a TScroller object // // sets owning Window's Scroller member to 0 // TScroller::~TScroller() { if (Window) Window->Scroller = 0; } // // sets the number of units per page (amount by which to scroll on a page // scroll request) according to the current size of the Window's client area // void TScroller::SetPageSize() { if (Window) { TRect clientRect; Window->GetClientRect(clientRect); int width = clientRect.Width(); int height = clientRect.Height(); if (width && XUnit > 0) XPage = max(1, (width+1) / XUnit - 1); if (height && YUnit > 0) YPage = max(1, (height+1) / YUnit - 1); } } // // sets the range of the TScroller and also sets the range of its // Window's scrollbars // void TScroller::SetRange(long xRange, long yRange) { XRange = xRange; YRange = yRange; SetSBarRange(); ScrollTo(XPos, YPos); } // // resets the X and Y scroll unit size (in device units) to the passed // parameters // // calls SetPageSize to update the X and Y page size, which are specified // in scroll units // void TScroller::SetUnits(int xUnit, int yUnit) { XUnit = xUnit; YUnit = yUnit; SetPageSize(); } // // sets the range of the Window's scrollbars & repaints as necessary // void TScroller::SetSBarRange() { if (Window) { if (HasHScrollBar) { int curMin, curMax; Window->GetScrollRange(SB_HORZ, curMin, curMax); int newMax = max(0, (int)min(XRange, SHRT_MAX)); if (newMax != curMax || curMin != 0) Window->SetScrollRange(SB_HORZ, 0, newMax, true); } if (HasVScrollBar) { int curMin, curMax; Window->GetScrollRange(SB_VERT, curMin, curMax); int newMax = max(0, (int)min(YRange, SHRT_MAX)); if (newMax != curMax || curMin != 0) Window->SetScrollRange(SB_VERT, 0, newMax, true); } } } // // sets the origin for the paint display context according to XPos, YPos // void TScroller::BeginView(TDC& dc, TRect& rect) { long xOrg = XPos * XUnit; long yOrg = YPos * YUnit; if (AutoOrg && xOrg <= SHRT_MAX && yOrg <= SHRT_MAX) { TPoint offset(int(-xOrg), int(-yOrg)); dc.SetViewportOrg(offset); rect -= offset; } } // // updates the position of the Window's scrollbar(s) // void TScroller::EndView() { if (Window) { if (HasHScrollBar) { int newPos = XRange > SHRT_MAX ? XScrollValue(XPos) : (int)XPos; if (newPos != Window->GetScrollPos(SB_HORZ)) Window->SetScrollPos(SB_HORZ, newPos, true); } if (HasVScrollBar) { int newPos = YRange > SHRT_MAX ? YScrollValue(YPos) : (int)YPos; if (newPos != Window->GetScrollPos(SB_VERT)) Window->SetScrollPos(SB_VERT, newPos, true); } } } // // scrolls vertically according to scroll action and thumb position // void TScroller::VScroll(uint scrollEvent, int thumbPos) { switch (scrollEvent) { case SB_LINEDOWN: ScrollBy(0, YLine); break; case SB_LINEUP: ScrollBy(0, -YLine); break; case SB_PAGEDOWN: ScrollBy(0, YPage); break; case SB_PAGEUP: ScrollBy(0, -YPage); break; case SB_TOP: ScrollTo(XPos, 0); break; case SB_BOTTOM: ScrollTo(XPos, YRange); break; case SB_THUMBPOSITION: if (YRange > SHRT_MAX) ScrollTo(XPos, YRangeValue(thumbPos)); else ScrollTo(XPos, thumbPos); break; case SB_THUMBTRACK: if (TrackMode) if (YRange > SHRT_MAX) ScrollTo(XPos, YRangeValue(thumbPos)); else ScrollTo(XPos, thumbPos); if (Window && HasVScrollBar) Window->SetScrollPos(SB_VERT, thumbPos, true); break; } } // // scrolls horizontally according to scroll action and thumb position // void TScroller::HScroll(uint scrollEvent, int thumbPos) { switch (scrollEvent) { case SB_LINEDOWN: ScrollBy(XLine, 0); break; case SB_LINEUP: ScrollBy(-XLine, 0); break; case SB_PAGEDOWN: ScrollBy(XPage, 0); break; case SB_PAGEUP: ScrollBy(-XPage, 0); break; case SB_TOP: ScrollTo(0, YPos); break; case SB_BOTTOM: ScrollTo(XRange, YPos); break; case SB_THUMBPOSITION: if (XRange > SHRT_MAX) ScrollTo(XRangeValue(thumbPos), YPos); else ScrollTo(thumbPos, YPos); break; case SB_THUMBTRACK: if (TrackMode) if (XRange > SHRT_MAX) ScrollTo(XRangeValue(thumbPos), YPos); else ScrollTo(thumbPos, YPos); if (Window && HasHScrollBar) Window->SetScrollPos(SB_HORZ, thumbPos, true); break; } } // // scrolls to an (x,y) position, after checking boundary conditions // causes a WM_PAINT message to be sent // // first scrolls the contents of the client area, if a portion of the client // area will remain visible // void TScroller::ScrollTo(long x, long y) { if (Window) { long newXPos = max(0, min(x, XRange)); long newYPos = max(0, min(y, YRange)); if (newXPos != XPos || newYPos != YPos) { // // scaling isn't needed here. if condition is met, ScrollWindow() // will succeed since XPage and YPage are ints // // if condition isn't met, ScrollWindow() is called in EndScroll() // as a result of calling UpdateWindow() // // EndScroll() performs the necessary scaling // if (AutoOrg || abs(YPos-newYPos) < YPage && abs(XPos-newXPos) < XPage) Window->ScrollWindow((int)(XPos - newXPos) * XUnit, (int)(YPos - newYPos) * YUnit, 0, 0); else Window->Invalidate(); XPos = newXPos; YPos = newYPos; Window->UpdateWindow(); } } } // // // bool TScroller::IsAutoMode() { return AutoMode; } // // performs "auto-scrolling" (dragging the mouse from within the client // client area of the Window to without results in auto-scrolling when // the AutoMode data member of the Scroller is true) // void TScroller::AutoScroll() { if (AutoMode && Window) { TRect clientRect; TPoint cursorPos; long dx = 0, dy = 0; GetCursorPos(&cursorPos); Window->ScreenToClient(cursorPos); Window->GetClientRect(clientRect); if (cursorPos.y < 0) dy = min(-YLine, max(-YPage, cursorPos.y / 10 * YLine)); else if (cursorPos.y > clientRect.bottom) dy = max(YLine, min(YPage, (cursorPos.y-clientRect.bottom)/10 * YLine)); if (cursorPos.x < 0) dx = min(-XLine, max(-XPage, cursorPos.x / 10 * XLine)); else if (cursorPos.x > clientRect.right) dx = max(XLine, min(XPage, (cursorPos.x-clientRect.right)/10 * XLine)); ScrollBy(dx, dy); } } #endif #if !defined(SECTION) || SECTION == 2 IMPLEMENT_STREAMABLE(TScroller); // // reads an instance of TScroller from the passed ipstream // void* TScroller::Streamer::Read(ipstream& is, uint32 /*version*/) const { TScroller* o = GetObject(); is >> o->XPos >> o->YPos >> o->XUnit >> o->YUnit >> o->XRange >> o->YRange >> o->XLine >> o->YLine >> o->XPage >> o->YPage >> o->AutoMode >> o->TrackMode >> o->AutoOrg >> o->HasHScrollBar >> o->HasVScrollBar; o->Window = 0; return o; } // // writes the TScroller to the passed opstream // void TScroller::Streamer::Write(opstream& os) const { TScroller* o = GetObject(); os << o->XPos << o->YPos << o->XUnit << o->YUnit << o->XRange << o->YRange << o->XLine << o->YLine << o->XPage << o->YPage << o->AutoMode << o->TrackMode << o->AutoOrg << o->HasHScrollBar << o->HasVScrollBar; } #endif