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
5 years ago
|
//========= 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;
|
||
|
}
|