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