33const TCHAR SyncPropertyName[] =
_T(
"OWL_TScroller_SyncScrollBars");
35auto IsSyncing(
const TWindow& w) ->
bool
37 return ::GetProp(w.GetHandle(), SyncPropertyName) !=
nullptr;
43 explicit TSyncGuard(
const TWindow& w)
44 : Window(w.GetHandle()), Entered(!::GetProp(Window, SyncPropertyName))
46 if (Entered) ::SetProp(Window, SyncPropertyName,
reinterpret_cast<HANDLE
>(1));
51 if (Entered) ::RemoveProp(Window, SyncPropertyName);
54 auto IsReentry() const ->
bool {
return !Entered; }
60 TSyncGuard(
const TSyncGuard&);
61 TSyncGuard& operator =(
const TSyncGuard&);
76 auto IsScrollable() const ->
bool {
return ScrollMax > 0 && ScrollPage <= ScrollMax; }
87auto CalculateBarMetrics(
int extent,
int unit,
long range,
long totalUnits,
int scrollMax,
int page,
int scrollPage) -> TBarMetrics
89 if (extent > 0 && unit > 0)
91 page = std::max(1, extent / unit);
92 scrollPage = (totalUnits && totalUnits > extent) ?
93 static_cast<int>(
static_cast<long long>(extent) * range / totalUnits) :
96 const TBarMetrics m = {page, scrollPage, scrollMax};
100auto CalculateScrollMax(
long range) ->
int
102 return static_cast<int>(std::max(0L, std::min(range - 1,
static_cast<long>(INT_MAX))));
161 if (IsSyncing(*
Window))
return;
234 const TSyncGuard guard(*
Window);
235 if (guard.IsReentry())
return;
238 const auto apply = [&](
int bar,
const TBarMetrics& m)
242 if (!m.IsScrollable())
246 if (curMin != 0 || curMax != 0)
255 const auto rangeChanged = curMin != 0 || curMax != m.ScrollMax;
256 const auto pageChanged = curPage != m.ScrollPage;
257 const auto rangeFirst = curPage <= m.ScrollMax;
258 if (rangeChanged && rangeFirst)
262 if (rangeChanged && !rangeFirst)
268 const auto maxPassCount = 3;
270 for (; pass != maxPassCount; ++pass)
275 const auto barHeight = ::GetSystemMetrics(SM_CYHSCROLL);
276 const auto barWidth = ::GetSystemMetrics(SM_CXVSCROLL);
277 const auto full =
TSize(client.cx + (vShown ? barWidth : 0), client.cy + (hShown ? barHeight : 0));
279 const auto calculate = [&](
bool needH,
bool needV)
283 const auto unchanged = needH == hShown && needV == vShown;
284 const auto width = unchanged ? client.cx : full.cx - (needV ? barWidth : 0);
285 const auto height = unchanged ? client.cy : full.cy - (needH ? barHeight : 0);
296 calculate(needH, needV);
299 const auto nh = needH || (
HasHScrollBar && h.IsScrollable());
300 const auto nv = needV || (
HasVScrollBar && v.IsScrollable());
301 if (nh == needH && nv == needV)
break;
304 calculate(needH, needV);
314 WARN(pass == maxPassCount,
_T(
"TScroller::SetSBarRange: Scroll bar layout did not settle."));
329 if (
AutoOrg && xOrg <= INT_MAX && yOrg <= INT_MAX) {
330 TPoint offset(
int(-xOrg),
int(-yOrg));
367 switch (scrollEvent) {
392 case SB_THUMBPOSITION:
417 switch (scrollEvent) {
442 case SB_THUMBPOSITION:
472 long newXPos = std::max(0L, std::min(x,
long(
XRange -
XPage)));
473 long newYPos = std::max(0L, std::min(y,
long(
YRange -
YPage)));
475 if (newXPos !=
XPos || newYPos !=
YPos) {
487 static_cast<int>(
YPos - newYPos) *
YUnit,
nullptr,
nullptr);
528 GetCursorPos(&cursorPos);
533 dy = std::min(
static_cast<long>(-
YLine), std::max(
static_cast<long>(-
YPage),
long(cursorPos.y / 10 *
YLine)));
535 else if (cursorPos.y > clientRect.bottom)
536 dy = std::max(
static_cast<long>(
YLine), std::min(
static_cast<long>(
YPage),
long((cursorPos.y-clientRect.bottom)/10 *
YLine)));
539 dx = std::min(
static_cast<long>(-
XLine), std::max(
static_cast<long>(-
XPage),
long(cursorPos.x / 10 *
XLine)));
541 else if (cursorPos.x > clientRect.right)
542 dx = std::max(
static_cast<long>(
XLine), std::min(
static_cast<long>(
XPage), (cursorPos.x-clientRect.right)/10 *
XLine));
551#if OWL_PERSISTENT_STREAMS
577TScroller::Streamer::Write(opstream& os)
const
579 TScroller* o = GetObject();
580 os << o->XPos << o->YPos <<
581 o->XUnit << o->YUnit <<
582 o->XRange << o->YRange <<
583 o->XLine << o->YLine <<
584 o->XPage << o->YPage <<
585 o->AutoMode << o->TrackMode <<
587 o->HasHScrollBar << o->HasVScrollBar;
#define WARN(condition, message)
#define PRECONDITION(condition)
TDC is the root class for GDI DC wrappers.
virtual bool SetViewportOrg(const TPoint &origin, TPoint *oldOrg=nullptr)
Sets this DC's viewport origin to the given origin value, and saves the previous origin in oldOrg.
TPoint is a support class, derived from tagPOINT.
TRect is a mathematical class derived from tagRect.
TSize()
Default constructor that does nothing.
TWindow, derived from TEventHandler and TStreamableBase, provides window-specific behavior and encaps...
TWindowAttr & GetWindowAttr()
Returns the TWindowAttr structure, which contains the window's creation attributes.
void SetScroller(TScroller *scroller)
Sets the scroller object for this window.
uint32 GetStyle() const
Gets the style bits of the underlying window or the 'Style' member of the attribute structure associa...
void ScrollWindow(int dx, int dy, const TRect *scroll=nullptr, const TRect *clip=nullptr)
Scrolls a window in the vertical (dx) and horizontal (dy) directions.
void UpdateWindow()
Updates the client area of the specified window by immediately sending a WM_PAINT message.
void ScreenToClient(TPoint &point) const
Uses the screen coordinates specified in point to calculate the client window's coordinates and then ...
void GetClientRect(TRect &rect) const
Gets the coordinates of the window's client area and then copies them into the object referred to by ...
virtual void Invalidate(bool erase=true)
Invalidates (mark for painting) the entire client area of a window.
HWND GetHandle() const
Returns the handle of the window.
TScroller * GetScroller()
Returns the associated scroller object for this window.
ipstream, a specialized input stream derivative of pstream, is the base class for reading (extracting...
Definition of GDI DC encapsulation classes: TDC, TWindowDC, TScreenDC, TDesktopDC,...
Object Windows Library (OWLNext Core).
IMPLEMENT_STREAMABLE(TDocManager)
uint32 Style
Contains the values that define the style, shape, and size of your window.
Base window class TWindow definition, including HWND encapsulation.