//----------------------------------------------------------------------------
// ObjectWindows
// Copyright (c) 1993, 1996 by Borland International, All Rights Reserved
//
/// \file
/// Implementation of TSlider, slider UI widget abstract base class.
//----------------------------------------------------------------------------
#include <owl/pch.h>
#include <owl/slider.h>
#include <owl/dc.h>
#include <owl/commctrl.h>
namespace owl {
OWL_DIAGINFO;
DEFINE_RESPONSE_TABLE1(TSlider, TScrollBar)
EV_WM_HSCROLL,
EV_WM_VSCROLL,
END_RESPONSE_TABLE;
//
/// Constructs a slider object setting Pos and ThumbRgn to 0, TicGap to Range
/// divided by 10, SlotThick to 17, Snap to true, and Sliding to false. Sets Attr.W
/// and Attr.H to the values in X and Y. ThumbResId is set to thumbResId.
//
TSlider::TSlider(TWindow* parent, int id, int x, int y, int w, int h, TResId thumbResId, TModule* module)
:
TScrollBar(parent, id, x, y, w, h, true, module),
ThumbResId(thumbResId),
ThumbRect(0, 0, 0, 0) // This will get setup when bitmap is loaded.
{
InitializeCommonControls(ICC_BAR_CLASSES);
SetRange(0, 100);
Pos = 0;
ThumbRgn = 0;
TicGap = Range/10; // Setup 10 evenly spaced tics by default, no array
Tics = 0;
TicCount = 0;
SlotThick = 4; // Default for all sliders
Snap = false;
SelStart = SelEnd = 0;
Sliding = false;
}
//
/// Constructor for a TSlider object created from resource
//
TSlider::TSlider(TWindow* parent, int resId, TResId thumbResId, TModule* module)
:
TScrollBar(parent, resId, module),
ThumbResId(thumbResId),
ThumbRect(0, 0, 0, 0) // This will get setup when bitmap is loaded.
{
InitializeCommonControls(ICC_BAR_CLASSES);
SetRange(0, 100);
Pos = 0;
ThumbRgn = 0;
TicGap = Range/10; // Setup 10 evenly spaced tics by default, no array.
Tics = 0;
TicCount = 0;
SlotThick = 4; // Default for all sliders
Snap = false;
SelStart = SelEnd = 0;
Sliding = false;
}
//
/// Constructs a slider object to encapsulate (alias) an existing control.
//
TSlider::TSlider(THandle hWnd, TModule* module)
:
TScrollBar(hWnd, module),
ThumbResId(0),
ThumbRect(0, 0, 0, 0) // This will get setup when bitmap is loaded.
{
InitializeCommonControls(ICC_BAR_CLASSES);
int rMin = static_cast<int>(SendMessage(TBM_GETRANGEMIN));
int rMax = static_cast<int>(SendMessage(TBM_GETRANGEMAX));
SetRange(rMin, rMax);
Pos = static_cast<int>(SendMessage(TBM_GETPOS));
GetWindowClassName();
ThumbRgn = 0;
TicGap = Range/10; // Setup 10 evenly spaced tics by default, no array.
Tics = 0;
TicCount = 0;
SlotThick = 4; // Default for all sliders
Snap = TicGap > 0;
SelStart = SelEnd = 0;
Sliding = false;
}
//
/// Destructs a TSlider object and deletes ThumbRgn.
//
TSlider::~TSlider()
{
delete[] Tics;
delete ThumbRgn;
}
//
/// Checks and sets the slider range.
/// Sets the slider to the range between minValue and maxValue. Overloads TScrollBar's virtual
/// function.
//
void
TSlider::SetRange(int minValue, int maxValue, bool redraw)
{
Min = minValue;
Max = maxValue;
if (Max > Min)
Range = Max - Min;
else if (Min > Max)
Range = Min - Max;
else
Range = 1;
if (GetHandle()) {
// TParam2 p2 = (Attr.Style & TBS_VERT) ? MkParam2(maxValue, minValue) : MkParam2(minValue, maxValue);
TParam2 p2 = MkParam2(minValue, maxValue);
SendMessage(TBM_SETRANGE, redraw, p2); // Swapped for vertical
}
}
//
/// Sets the position of the thumb and always redraws.
/// Moves the thumb to the position specified in thumbPos. If thumbPos is outside
/// the present range of the slider, the thumb is moved to the closest position
/// within the specified range. Overloads TScrollBar's virtual function.
///
/// Always redraws.
//
void
TSlider::SetPosition(int pos)
{
SetPosition(pos, true);
}
//
/// Sets the position of the thumb and always redraws.
/// Moves the thumb to the position specified in thumbPos. If thumbPos is outside
/// the present range of the slider, the thumb is moved to the closest position
/// within the specified range. Overloads TScrollBar's virtual function.
///
/// Redraw is optional.
//
void
TSlider::SetPosition(int pos, bool redraw)
{
// Constrain pos to be in the range "Min .. Max" & snap to tics if enabled
//
pos = SnapPos(pos);
// Slide thumb to new position, converting pos to pixels
//
if (GetHandle()) {
SendMessage(TBM_SETPOS, redraw, pos);
}
Pos = pos;
}
//
/// Sets the slider's ruler. Each slider has a built-in ruler that is drawn with the
/// slider. The ruler, which can be blank or have tick marks on it, can be created
/// so that it forces the thumb to snap to the tick positions automatically.
/// \note Snapping is not supported in native currently
//
void
TSlider::SetRuler(int ticGap, bool snap)
{
TicGap = ticGap;
Snap = snap;
delete[] Tics;
Tics = 0;
if (GetHandle()) {
SendMessage(TBM_SETTICFREQ, ticGap, 0);
}
}
//
/// Sets the ruler's custom tics and snap. Snapping is not currently supported in
/// native.
//\ todo need to add multple tics support
//
void
TSlider::SetRuler(int tics[], int ticCount, bool snap)
{
PRECONDITION(tics || ticCount == 0); // A 0 tics array is only OK if no tics
// Alloc the array if the size is different, or we dont have one. Then copy
// the tic positions
//
if (ticCount > TicCount || !Tics) {
delete[] Tics;
Tics = ticCount ? new int[ticCount] : 0;
}
for (int i = 0; i < ticCount; i++)
if (tics[i] >= Min && tics[i] <= Max) // Ignore out of range tics
Tics[i] = tics[i];
TicCount = ticCount;
Snap = snap;
if (GetHandle()) {
SendMessage(TBM_CLEARTICS, false);
for (int i = 0; i < TicCount; i++)
SendMessage(TBM_SETTIC, i, tics[i]);
}
}
//
/// Set a selection range for the slider. Requires that TBS_ENABLESELRANGE style
/// attribute be set.
//
void
TSlider::SetSel(int start, int end, bool redraw)
{
// Save selection state
//
SelStart = start;
SelEnd = end;
if (GetHandle()) {
SendMessage(TBM_SETSEL, redraw, MkUint32(uint16(start), uint16(end)));
}
}
//
// Get the selection range from the slider.
// Requires that TBS_ENABLESELRANGE style attribute be set.
//
void
TSlider::GetSel(int& start, int& end)
{
if (GetHandle()) {
start = (int)SendMessage(TBM_GETSELSTART);
end = (int)SendMessage(TBM_GETSELEND);
}
// Resync selection state
//
SelStart = start;
SelEnd = end;
}
//----------------------------------------------------------------------------
// Protected implementation
//
/// Returns the windows system class name that this slider is basing itself on.
//
auto TSlider::GetWindowClassName() -> TWindowClassName
{
return TWindowClassName{TRACKBAR_CLASS};
}
//
/// Calls TScrollBar::SetupWindow and SetupThumbRgn to set up the slider window.
//
void
TSlider::SetupWindow()
{
TScrollBar::SetupWindow();
SetRange(Min, Max);
if (Tics)
SetRuler(Tics, TicCount, Snap);
else
SetRuler(TicGap, Snap);
SetSel(SelStart, SelEnd, false);
SetPosition(Pos, true);
}
//
/// Constrains pos so it is in the range from Min to Max and (if snapping is
/// enabled) performs snapping by rounding pos to the nearest TicGap.
//
int
TSlider::SnapPos(int pos)
{
if (pos > Max)
pos = Max;
else if (pos < Min)
pos = Min;
return Snap && TicGap > 0 ? (((pos-Min)+TicGap/2)/TicGap)*TicGap + Min : pos;
}
//
/// Overrides the handling in TScrollBar.
/// In particular, TSlider does not support the code in TScrollBar to retrieve 32-bit positions,
/// so we here simply resort to the 16-bit position value passed with the TB_THUMBPOSITION and
/// TB_THUMBTRACK notifications.
//
// TODO: For Windows Vista and later, handle the TRBN_THUMBPOSCHANGING notification instead.
// This new notification carries 32-bit data in the accompanying structure NMTRBTHUMBPOSCHANGING.
//
void
TSlider::EvHScroll(uint scrollCode, uint thumbPos, THandle hCtl)
{
PRECONDITION(hCtl == GetHandle()); // Only handle messages for ourselves.
switch (scrollCode)
{
case TB_THUMBPOSITION:
SBThumbPosition(thumbPos);
break;
case TB_THUMBTRACK:
SBThumbTrack(thumbPos);
break;
default:
TScrollBar::EvHScroll(scrollCode, thumbPos, hCtl);
}
}
//
/// Overrides the handling in TScrollBar.
/// See EvHScroll for details.
//
void
TSlider::EvVScroll(uint scrollCode, uint thumbPos, THandle hCtl)
{
// Simply forward to EvHScroll, since the code is identical.
//
EvHScroll(scrollCode, thumbPos, hCtl);
}
IMPLEMENT_ABSTRACT_STREAMABLE1(TSlider, TScrollBar);
#if OWL_PERSISTENT_STREAMS
//
//
//
void*
TSlider::Streamer::Read(ipstream& is, uint32 version) const
{
TSlider* o = GetObject();
ReadBaseObject((TScrollBar*)o, is);
is >> o->Min
>> o->Max
>> o->Pos
>> o->ThumbResId
>> o->ThumbRect;
if (version == 1) {
TRect tmpRect;
is >> tmpRect; // dummy CaretRect for compatibilty with stream v1
}
is >> o->TicGap
>> o->Snap;
// In stream version 2 and above, a tic array with count is written, as well
// as a selection range
//
if (version >= 2) {
is >> o->TicCount;
o->Tics = o->TicCount ? new int[o->TicCount] : 0;
for (int i = 0; i < o->TicCount; i++)
is >> o->Tics[i];
is >> o->SelStart
>> o->SelEnd;
}
o->SetRange(o->Min, o->Max); // let it calculate Range
return o;
}
//
//
//
void
TSlider::Streamer::Write(opstream& os) const
{
TSlider* o = GetObject();
WriteBaseObject((TScrollBar*)o, os);
os << o->Min
<< o->Max
<< o->Pos
<< o->ThumbResId
<< o->ThumbRect
<< o->TicGap
<< o->Snap
<< o->TicCount;
// In stream version 2 and above, a tic array with count is written, as well
// as a selection range
//
os << o->TicCount;
for (int i = 0; i < o->TicCount; i++)
os << o->Tics[i];
int d1,d2;
o->GetSel(d1,d2); // Force retrieval of current selection before writing
os << o->SelStart
<< o->SelEnd;
}
#endif
} // OWL namespace
/* ========================================================================== */
↑ V522 There might be dereferencing of a potential null pointer 'Tics'.
↑ V601 The 'false' value is implicitly cast to the integer type. Inspect the second argument.