You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
606 lines
16 KiB
606 lines
16 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
//=============================================================================// |
|
|
|
#define PROTECTED_THINGS_DISABLE |
|
|
|
#include <vgui/IBorder.h> |
|
#include <vgui/IInput.h> |
|
#include <vgui/ISystem.h> |
|
#include <vgui/IScheme.h> |
|
#include <vgui/ISurface.h> |
|
#include <vgui/MouseCode.h> |
|
#include <KeyValues.h> |
|
|
|
#include <vgui_controls/ScrollBarSlider.h> |
|
#include <vgui_controls/Controls.h> |
|
|
|
#include <math.h> |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include <tier0/memdbgon.h> |
|
|
|
using namespace vgui; |
|
|
|
//----------------------------------------------------------------------------- |
|
// The ScrollBarSlider is the scroll bar nob that moves up and down in through a range. |
|
//----------------------------------------------------------------------------- |
|
ScrollBarSlider::ScrollBarSlider(Panel *parent, const char *panelName, bool vertical) : Panel(parent, panelName) |
|
{ |
|
_vertical=vertical; |
|
_dragging=false; |
|
_value=0; |
|
_range[0]=0; |
|
_range[1]=0; |
|
_rangeWindow=0; |
|
_buttonOffset=0; |
|
_ScrollBarSliderBorder=NULL; |
|
RecomputeNobPosFromValue(); |
|
SetBlockDragChaining( true ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Set the size of the ScrollBarSlider nob |
|
//----------------------------------------------------------------------------- |
|
void ScrollBarSlider::SetSize(int wide,int tall) |
|
{ |
|
BaseClass::SetSize(wide,tall); |
|
RecomputeNobPosFromValue(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Whether the scroll bar is vertical (true) or not (false) |
|
//----------------------------------------------------------------------------- |
|
bool ScrollBarSlider::IsVertical() |
|
{ |
|
return _vertical; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Set the ScrollBarSlider value of the nob. |
|
//----------------------------------------------------------------------------- |
|
void ScrollBarSlider::SetValue(int value) |
|
{ |
|
int oldValue = _value; |
|
|
|
if (value > _range[1] - _rangeWindow) |
|
{ |
|
// note our scrolling range must take into acount _rangeWindow |
|
value = _range[1] - _rangeWindow; |
|
} |
|
|
|
if (value < _range[0]) |
|
{ |
|
value = _range[0]; |
|
} |
|
|
|
_value = value; |
|
RecomputeNobPosFromValue(); |
|
|
|
if (_value != oldValue) |
|
{ |
|
SendScrollBarSliderMovedMessage(); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Get the ScrollBarSlider value of the nob. |
|
//----------------------------------------------------------------------------- |
|
int ScrollBarSlider::GetValue() |
|
{ |
|
return _value; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void ScrollBarSlider::PerformLayout() |
|
{ |
|
RecomputeNobPosFromValue(); |
|
BaseClass::PerformLayout(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Given the value of the ScrollBarSlider, adjust the ends of the nob. |
|
//----------------------------------------------------------------------------- |
|
void ScrollBarSlider::RecomputeNobPosFromValue() |
|
{ |
|
int wide, tall; |
|
GetPaintSize(wide, tall); |
|
|
|
float fwide = (float)( wide - 1 ); |
|
float ftall = (float)( tall - 1 ); |
|
float frange = (float)(_range[1] -_range[0]); |
|
float fvalue = (float)(_value - _range[0]); |
|
float frangewindow = (float)(_rangeWindow); |
|
float fper = ( frange != frangewindow ) ? fvalue / ( frange-frangewindow ) : 0; |
|
|
|
// Msg( "fwide: %f ftall: %f frange: %f fvalue: %f frangewindow: %f fper: %f\n", |
|
// fwide, ftall, frange, fvalue, frangewindow, fper ); |
|
|
|
if ( frangewindow > 0 ) |
|
{ |
|
if ( frange <= 0.0 ) |
|
{ |
|
frange = 1.0; |
|
} |
|
|
|
float width, length; |
|
if (_vertical) |
|
{ |
|
width = fwide; |
|
length = ftall; |
|
} |
|
else |
|
{ |
|
width = ftall; |
|
length = fwide; |
|
} |
|
|
|
// our size is proportional to frangewindow/frange |
|
// the scroll bar nob's length reflects the amount of stuff on the screen |
|
// vs the total amount of stuff we could scroll through in window |
|
// so if a window showed half its contents and the other half is hidden the |
|
// scroll bar's length is half the window. |
|
// if everything is on the screen no nob is displayed |
|
// frange is how many 'lines' of stuff we can display |
|
// frangewindow is how many 'lines' are in the display window |
|
|
|
// proportion of whole window that is on screen |
|
float proportion = frangewindow / frange; |
|
float fnobsize = length * proportion; |
|
if ( fnobsize < width ) fnobsize = (float)width; |
|
|
|
float freepixels = length - fnobsize; |
|
|
|
float firstpixel = freepixels * fper; |
|
|
|
_nobPos[0] = (int)( firstpixel ); |
|
_nobPos[1] = (int)( firstpixel + fnobsize ); |
|
|
|
if ( _nobPos[1] > length ) |
|
{ |
|
_nobPos[0] = (int)( length - fnobsize ); |
|
_nobPos[1] = (int)length; |
|
} |
|
|
|
} |
|
|
|
Repaint(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Get the ScrollBarSlider value using the location of the nob ends. |
|
//----------------------------------------------------------------------------- |
|
void ScrollBarSlider::RecomputeValueFromNobPos() |
|
{ |
|
int wide, tall; |
|
GetPaintSize(wide, tall); |
|
|
|
float fwide = (float)( wide - 1 ); |
|
float ftall = (float)( tall - 1 ); |
|
float frange = (float)( _range[1] - _range[0] ); |
|
float fvalue = (float)( _value - _range[0] ); |
|
float fnob = (float)_nobPos[0]; |
|
float frangewindow = (float)(_rangeWindow); |
|
|
|
if ( frangewindow > 0 ) |
|
{ |
|
if ( frange <= 0.0 ) |
|
{ |
|
frange = 1.0; |
|
} |
|
|
|
// set local width and length |
|
float width, length; |
|
if ( _vertical ) |
|
{ |
|
width = fwide; |
|
length = ftall; |
|
} |
|
else |
|
{ |
|
width = ftall; |
|
length = fwide; |
|
} |
|
|
|
// calculate the size of the nob |
|
float proportion = frangewindow / frange; |
|
float fnobsize = length * proportion; |
|
|
|
if ( fnobsize < width ) |
|
{ |
|
fnobsize = width; |
|
} |
|
|
|
// Our scroll bar actually doesnt scroll through all frange lines in the truerange, we |
|
// actually only scroll through frange-frangewindow number of lines so we must take that |
|
// into account when we calculate the value |
|
// convert to our local size system |
|
|
|
// Make sure we don't divide by zero |
|
if ( length - fnobsize == 0 ) |
|
{ |
|
fvalue = 0.0f; |
|
} |
|
else |
|
{ |
|
fvalue = (frange - frangewindow) * ( fnob / ( length - fnobsize ) ); |
|
} |
|
} |
|
|
|
// check to see if we should just snap to the bottom |
|
if (fabs(fvalue + _rangeWindow - _range[1]) < (0.01f * frange)) |
|
{ |
|
// snap to the end |
|
_value = _range[1] - _rangeWindow; |
|
} |
|
else |
|
{ |
|
// Take care of rounding issues. |
|
_value = (int)( fvalue + _range[0] + 0.5); |
|
} |
|
|
|
// Clamp final result |
|
_value = ( _value < (_range[1] - _rangeWindow) ) ? _value : (_range[1] - _rangeWindow); |
|
|
|
if (_value < _range[0]) |
|
{ |
|
_value = _range[0]; |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Check if the ScrollBarSlider can move through one or more pixels per |
|
// unit of its range. |
|
//----------------------------------------------------------------------------- |
|
bool ScrollBarSlider::HasFullRange() |
|
{ |
|
int wide, tall; |
|
GetPaintSize(wide, tall); |
|
|
|
float frangewindow = (float)(_rangeWindow); |
|
|
|
float checkAgainst = 0; |
|
if(_vertical) |
|
{ |
|
checkAgainst = (float)tall; |
|
} |
|
else |
|
{ |
|
checkAgainst = (float)wide; |
|
} |
|
|
|
if ( frangewindow > 0 ) |
|
{ |
|
if( frangewindow <= ( checkAgainst + _buttonOffset ) ) |
|
{ |
|
return true; |
|
} |
|
} |
|
|
|
return false; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Inform other watchers that the ScrollBarSlider was moved |
|
//----------------------------------------------------------------------------- |
|
void ScrollBarSlider::SendScrollBarSliderMovedMessage() |
|
{ |
|
// send a changed message |
|
PostActionSignal(new KeyValues("ScrollBarSliderMoved", "position", _value)); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Return true if this slider is actually drawing itself |
|
//----------------------------------------------------------------------------- |
|
bool ScrollBarSlider::IsSliderVisible( void ) |
|
{ |
|
int itemRange = _range[1] - _range[0]; |
|
|
|
// Don't draw nob, no items in list |
|
if ( itemRange <= 0 ) |
|
return false ; |
|
|
|
// Not enough range |
|
if ( itemRange <= _rangeWindow ) |
|
return false; |
|
|
|
return true; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void ScrollBarSlider::ApplySchemeSettings(IScheme *pScheme) |
|
{ |
|
BaseClass::ApplySchemeSettings(pScheme); |
|
|
|
SetFgColor(GetSchemeColor("ScrollBarSlider.FgColor", pScheme)); |
|
SetBgColor(GetSchemeColor("ScrollBarSlider.BgColor", pScheme)); |
|
|
|
IBorder *newBorder = pScheme->GetBorder("ScrollBarSliderBorder"); |
|
|
|
if ( newBorder ) |
|
{ |
|
_ScrollBarSliderBorder = newBorder; |
|
} |
|
else |
|
{ |
|
_ScrollBarSliderBorder = pScheme->GetBorder("ButtonBorder"); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void ScrollBarSlider::ApplySettings( KeyValues *pInResourceData ) |
|
{ |
|
BaseClass::ApplySettings( pInResourceData ); |
|
|
|
const char *pButtonBorderName = pInResourceData->GetString( "ButtonBorder", NULL ); |
|
if ( pButtonBorderName ) |
|
{ |
|
_ScrollBarSliderBorder = vgui::scheme()->GetIScheme( GetScheme() )->GetBorder( pButtonBorderName ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void ScrollBarSlider::Paint() |
|
{ |
|
int wide,tall; |
|
GetPaintSize(wide,tall); |
|
|
|
if ( !IsSliderVisible() ) |
|
return; |
|
|
|
Color col = GetFgColor(); |
|
surface()->DrawSetColor(col); |
|
|
|
if (_vertical) |
|
{ |
|
if ( GetPaintBackgroundType() == 2 ) |
|
{ |
|
DrawBox( 1, _nobPos[0], wide - 2, _nobPos[1] - _nobPos[0], col, 1.0f ); |
|
} |
|
else |
|
{ |
|
// Nob |
|
surface()->DrawFilledRect(1, _nobPos[0], wide - 2, _nobPos[1]); |
|
} |
|
|
|
// border |
|
if (_ScrollBarSliderBorder) |
|
{ |
|
_ScrollBarSliderBorder->Paint(0, _nobPos[0], wide, _nobPos[1]); |
|
} |
|
} |
|
else |
|
{ |
|
// horizontal nob |
|
surface()->DrawFilledRect(_nobPos[0], 1, _nobPos[1], tall - 2 ); |
|
|
|
// border |
|
if (_ScrollBarSliderBorder) |
|
{ |
|
_ScrollBarSliderBorder->Paint(_nobPos[0] - 1, 1, _nobPos[1], tall ); |
|
} |
|
} |
|
|
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void ScrollBarSlider::PaintBackground() |
|
{ |
|
// BaseClass::PaintBackground(); |
|
|
|
int wide,tall; |
|
GetPaintSize(wide,tall); |
|
surface()->DrawSetColor(GetBgColor()); |
|
surface()->DrawFilledRect(0, 0, wide-1, tall-1); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Set the range of the ScrollBarSlider |
|
//----------------------------------------------------------------------------- |
|
void ScrollBarSlider::SetRange(int min,int max) |
|
{ |
|
if(max<min) |
|
{ |
|
max=min; |
|
} |
|
|
|
if(min>max) |
|
{ |
|
min=max; |
|
} |
|
|
|
_range[0]=min; |
|
_range[1]=max; |
|
|
|
// update the value (forces it within the range) |
|
SetValue( _value ); |
|
InvalidateLayout(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Get the range values of the ScrollBarSlider |
|
//----------------------------------------------------------------------------- |
|
void ScrollBarSlider::GetRange(int& min,int& max) |
|
{ |
|
min=_range[0]; |
|
max=_range[1]; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Respond to cursor movements, we only care about clicking and dragging |
|
//----------------------------------------------------------------------------- |
|
void ScrollBarSlider::OnCursorMoved(int x,int y) |
|
{ |
|
if (!_dragging) |
|
{ |
|
return; |
|
} |
|
|
|
// input()->GetCursorPos(x, y); |
|
// ScreenToLocal(x, y); |
|
|
|
int wide, tall; |
|
GetPaintSize(wide, tall); |
|
|
|
if (_vertical) |
|
{ |
|
_nobPos[0] = _nobDragStartPos[0] + (y - _dragStartPos[1]); |
|
_nobPos[1] = _nobDragStartPos[1] + (y - _dragStartPos[1]); |
|
|
|
if (_nobPos[1] > tall) |
|
{ |
|
_nobPos[0] = tall - (_nobPos[1] - _nobPos[0]); |
|
_nobPos[1] = tall; |
|
SetValue( _range[1] - _rangeWindow ); |
|
} |
|
} |
|
else |
|
{ |
|
_nobPos[0] = _nobDragStartPos[0] + (x - _dragStartPos[0]); |
|
_nobPos[1] = _nobDragStartPos[1] + (x - _dragStartPos[0]); |
|
|
|
if (_nobPos[1] > wide) |
|
{ |
|
_nobPos[0] = wide - (_nobPos[1] - _nobPos[0]); |
|
_nobPos[1] = wide; |
|
} |
|
|
|
} |
|
if (_nobPos[0] < 0) |
|
{ |
|
_nobPos[1] = _nobPos[1] - _nobPos[0]; |
|
_nobPos[0] = 0; |
|
SetValue(0); |
|
} |
|
|
|
InvalidateLayout(); // not invalidatelayout - because it won't draw while we're scrolling the slider |
|
RecomputeValueFromNobPos(); |
|
// Repaint(); |
|
SendScrollBarSliderMovedMessage(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Respond to mouse clicks on the ScrollBarSlider |
|
//----------------------------------------------------------------------------- |
|
void ScrollBarSlider::OnMousePressed(MouseCode code) |
|
{ |
|
int x,y; |
|
input()->GetCursorPos(x,y); |
|
ScreenToLocal(x,y); |
|
|
|
if (_vertical) |
|
{ |
|
if ((y >= _nobPos[0]) && (y < _nobPos[1])) |
|
{ |
|
_dragging = true; |
|
input()->SetMouseCapture(GetVPanel()); |
|
_nobDragStartPos[0] = _nobPos[0]; |
|
_nobDragStartPos[1] = _nobPos[1]; |
|
_dragStartPos[0] = x; |
|
_dragStartPos[1] = y; |
|
} |
|
else if (y < _nobPos[0]) |
|
{ |
|
// jump the bar up by the range window |
|
int val = GetValue(); |
|
val -= _rangeWindow; |
|
SetValue(val); |
|
} |
|
else if (y >= _nobPos[1]) |
|
{ |
|
// jump the bar down by the range window |
|
int val = GetValue(); |
|
val += _rangeWindow; |
|
SetValue(val); |
|
} |
|
} |
|
else |
|
{ |
|
if((x >= _nobPos[0]) && (x < _nobPos[1])) |
|
{ |
|
_dragging = true; |
|
input()->SetMouseCapture(GetVPanel()); |
|
_nobDragStartPos[0] = _nobPos[0]; |
|
_nobDragStartPos[1] = _nobPos[1]; |
|
_dragStartPos[0] = x; |
|
_dragStartPos[1] = y; |
|
} |
|
else if (x < _nobPos[0]) |
|
{ |
|
// jump the bar up by the range window |
|
int val = GetValue(); |
|
val -= _rangeWindow; |
|
SetValue(val); |
|
} |
|
else if (x >= _nobPos[1]) |
|
{ |
|
// jump the bar down by the range window |
|
int val = GetValue(); |
|
val += _rangeWindow; |
|
SetValue(val); |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Treat double clicks as single clicks |
|
//----------------------------------------------------------------------------- |
|
void ScrollBarSlider::OnMouseDoublePressed(MouseCode code) |
|
{ |
|
OnMousePressed(code); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Stop looking for mouse events when mouse is up. |
|
//----------------------------------------------------------------------------- |
|
void ScrollBarSlider::OnMouseReleased(MouseCode code) |
|
{ |
|
_dragging = false; |
|
input()->SetMouseCapture(null); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Get the position of the ends of the ScrollBarSlider. |
|
//----------------------------------------------------------------------------- |
|
void ScrollBarSlider::GetNobPos(int& min, int& max) |
|
{ |
|
min=_nobPos[0]; |
|
max=_nobPos[1]; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Set the number of lines visible in the window the ScrollBarSlider is attached to |
|
//----------------------------------------------------------------------------- |
|
void ScrollBarSlider::SetRangeWindow(int rangeWindow) |
|
{ |
|
_rangeWindow = rangeWindow; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Get the number of lines visible in the window the ScrollBarSlider is attached to |
|
//----------------------------------------------------------------------------- |
|
int ScrollBarSlider::GetRangeWindow() |
|
{ |
|
return _rangeWindow; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void ScrollBarSlider::SetButtonOffset(int buttonOffset) |
|
{ |
|
_buttonOffset = buttonOffset; |
|
} |