//----------------------------------------------------------------------------
// ObjectWindows
// Copyright (c) 1991, 1996 by Borland International, All Rights Reserved
//
/// \file
/// Implementation of class TScroller.
/// Including bug fixes by Rich Goldstein
//----------------------------------------------------------------------------
#include <owl/pch.h>
#include <owl/scroller.h>
#include <owl/window.h>
#include <owl/dc.h>
#include <stdlib.h>
#include <algorithm>
namespace owl {
OWL_DIAGINFO;
//
/// Constructs a TScroller object with window as the owner window, and xUnit, yUnit,
/// xRange, and yRange as xUnit, yUnit, xRange and yRange, respectively. Initializes
/// data members to default values. HasHScrollBar and HasVScrollBar are set
/// according to the scroll bar attributes of the owner window.
//
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;
XTotalUnits = 0;
YTotalUnits = 0;
XLine = 1; YLine = 1;
XPage = 1; YPage = 1;
AutoMode = true;
TrackMode = true;
AutoOrg = true;
HasHScrollBar = ToBool(Window && (Window->GetWindowAttr().Style&WS_HSCROLL));
HasVScrollBar = ToBool(Window && (Window->GetWindowAttr().Style&WS_VSCROLL));
}
//
/// Destructs a TScroller object. Sets owning window's Scroller number variable to 0.
//
TScroller::~TScroller()
{
if (Window && Window->GetScroller() == this)
Window->SetScroller(0);
}
//
/// Sets the XPage and YPage data members (amount by which to scroll on a page
/// scroll request) to the width and height (in XUnits and
/// YUnits) of the owner window's client area.
//
void
TScroller::SetPageSize()
{
PRECONDITION(Window);
PRECONDITION(Window->GetHandle());
if (Window && Window->GetHandle()) {
TRect clientRect;
Window->GetClientRect(clientRect);
int width = clientRect.Width();
int height = clientRect.Height();
if (width && XUnit > 0) {
XPage = std::max(1, (width+1) / XUnit - 1);
if (XTotalUnits && XTotalUnits > width) {
SetScrollPage(SB_HORZ, (width * XRange) / XTotalUnits, true);
}
else
SetScrollPage(SB_HORZ, XPage, false);
}
if (height && YUnit > 0) {
YPage = std::max(1, (height+1) / YUnit - 1);
if (YTotalUnits && YTotalUnits > height) {
SetScrollPage(SB_VERT, (height * YRange) / YTotalUnits, true);
}
else
SetScrollPage(SB_VERT, YPage, false);
}
}
}
//
/// Sets the xRange and yRange of the TScroller to the parameters specified. Then
/// calls SetSBarRange to synchronize the range of the owner window's scroll bars.
//
void
TScroller::SetRange(long xRange, long yRange)
{
XRange = xRange;
YRange = yRange;
SetSBarRange();
ScrollTo(XPos, YPos);
}
//
// Sets the total units of the window
//
void
TScroller::SetTotalRangeOfUnits(long xTotalUnits, long yTotalUnits)
{
XTotalUnits = xTotalUnits;
YTotalUnits = yTotalUnits;
SetSBarRange();
ScrollTo(XPos, YPos);
}
//
/// Sets the XUnit and YUnit data members to TheXUnit and TheYUnit, respectively.
/// Updates XPage and YPage by calling SetPageSize.
//
void
TScroller::SetUnits(int xUnit, int yUnit)
{
XUnit = xUnit;
YUnit = yUnit;
SetPageSize();
}
//
/// Sets the range of the owner window's scroll bars to match the range of the
/// TScroller and repaints as necessary
//
void
TScroller::SetSBarRange()
{
PRECONDITION(Window);
PRECONDITION(Window->GetHandle());
if (Window && Window->GetHandle()) {
if (HasHScrollBar) {
int curMin, curMax;
GetScrollRange(SB_HORZ, curMin, curMax);
int newMax = std::max(0, std::min(int(XRange - 1), (int)INT_MAX));
if (newMax != curMax || curMin != 0)
SetScrollRange(SB_HORZ, 0, newMax, true);
}
if (HasVScrollBar) {
int curMin, curMax;
GetScrollRange(SB_VERT, curMin, curMax);
int newMax = std::max(0, std::min(int(YRange - 1), (int)INT_MAX));
if (newMax != curMax || curMin != 0)
SetScrollRange(SB_VERT, 0, newMax, true);
}
}
}
//
/// If TScroller_AutoOrg is true (default condition), BeginView automatically
/// offsets the origin of the logical coordinates of the client area by XPos, YPos
/// during a paint operation. If AutoOrg is false (for example, when the scroller is
/// larger than 32,767 units), you must set the offset manually.
//
void
TScroller::BeginView(TDC& dc, TRect& rect)
{
long xOrg = XPos * XUnit;
long yOrg = YPos * YUnit;
if (AutoOrg && xOrg <= INT_MAX && yOrg <= INT_MAX) {
TPoint offset(int(-xOrg), int(-yOrg));
dc.SetViewportOrg(offset);
rect -= offset;
}
}
//
/// Updates the position of the owner window's scroll bars to be coordinated with
/// the position of the TScroller.
//
void
TScroller::EndView()
{
if (Window) {
if (HasHScrollBar) {
int newPos = XPos;
if (newPos != GetScrollPos(SB_HORZ))
SetScrollPos(SB_HORZ, newPos, true);
}
if (HasVScrollBar) {
int newPos = YPos;
if (newPos != GetScrollPos(SB_VERT))
SetScrollPos(SB_VERT, newPos, true);
}
}
}
//
/// Responds to the specified vertical scrollEvent by calling ScrollBy or ScrollTo.
/// The type of scroll event is identified by the corresponding SB_ constants.
/// The 16-bit thumbPos argument is ignored. The function retrieves the 32-bit value
/// directly from the scroll bar instead.
//
void
TScroller::VScroll(uint scrollEvent, int)
{
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:
ScrollTo(XPos, GetScrollTrackPos(SB_VERT));
break;
case SB_THUMBTRACK:
{
int thumbPos32 = GetScrollTrackPos(SB_VERT);
if (TrackMode)
ScrollTo(XPos, thumbPos32);
if (Window && HasVScrollBar)
SetScrollPos(SB_VERT, thumbPos32, true);
break;
}
}
}
//
/// Responds to the specified horizontal scrollEvent by calling ScrollBy or ScrollTo.
/// The type of scroll event is identified by the corresponding SB_ constants.
/// The 16-bit thumbPos argument is ignored. The function retrieves the 32-bit value
/// directly from the scroll bar instead.
//
void
TScroller::HScroll(uint scrollEvent, int)
{
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:
ScrollTo(GetScrollTrackPos(SB_HORZ), YPos);
break;
case SB_THUMBTRACK:
{
int thumbPos32 = GetScrollTrackPos(SB_HORZ);
if (TrackMode)
ScrollTo(thumbPos32, YPos);
if (Window && HasHScrollBar)
SetScrollPos(SB_HORZ, thumbPos32, true);
break;
}
}
}
//
/// Scrolls the rectangle to the position specified in x and y 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)
{
PRECONDITION(Window);
PRECONDITION(Window->GetHandle());
if (Window && Window->GetHandle()) {
long newXPos = std::max(0L, std::min(x, long(XRange - XPage)));
long newYPos = std::max(0L, std::min(y, long(YRange - YPage)));
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();
}
}
}
//
/// IsAutoMode is true if automatic scrolling is activated.
//
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)
///
/// Scrolls the owner window's display in response to the mouse being dragged from
/// inside to outside the window. The direction and the amount by which the display
/// is scrolled depend on the current position of the mouse.
//
void
TScroller::AutoScroll()
{
PRECONDITION(Window);
PRECONDITION(Window->GetHandle());
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 = std::min((long)-YLine, std::max((long)-YPage, long(cursorPos.y / 10 * YLine)));
else if (cursorPos.y > clientRect.bottom)
dy = std::max((long)YLine, std::min((long)YPage, long((cursorPos.y-clientRect.bottom)/10 * YLine)));
if (cursorPos.x < 0)
dx = std::min((long)-XLine, std::max((long)-XPage, long(cursorPos.x / 10 * XLine)));
else if (cursorPos.x > clientRect.right)
dx = std::max((long)XLine, std::min((long)XPage, (cursorPos.x-clientRect.right)/10 * XLine));
ScrollBy(dx, dy);
}
}
IMPLEMENT_STREAMABLE(TScroller);
#if OWL_PERSISTENT_STREAMS
//
// 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
} // OWL namespace
/* ========================================================================== */
↑ V595 The 'Window' pointer was utilized before it was verified against nullptr. Check lines: 68, 70.
↑ V595 The 'Window' pointer was utilized before it was verified against nullptr. Check lines: 141, 143.
↑ V595 The 'Window' pointer was utilized before it was verified against nullptr. Check lines: 314, 316.
↑ V595 The 'Window' pointer was utilized before it was verified against nullptr. Check lines: 366, 368.
↑ V560 A part of conditional expression is always true: xOrg <= 2147483647.
↑ V560 A part of conditional expression is always true: yOrg <= 2147483647.