stella/src/gui/ScrollBarWidget.cxx

290 lines
8.0 KiB
C++

//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2013 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id$
//============================================================================
#include "OSystem.hxx"
#include "Dialog.hxx"
#include "FrameBuffer.hxx"
#include "ScrollBarWidget.hxx"
#include "bspf.hxx"
/*
* TODO:
* - Allow for a horizontal scrollbar, too?
* - If there are less items than fit on one pages, no scrolling can be done
* and we thus should not highlight the arrows/slider.
*/
#define UP_DOWN_BOX_HEIGHT 18
// Up arrow
static unsigned int up_arrow[8] = {
0x00011000,
0x00011000,
0x00111100,
0x00111100,
0x01111110,
0x01111110,
0x11111111,
0x11111111
};
// Down arrow
static unsigned int down_arrow[8] = {
0x11111111,
0x11111111,
0x01111110,
0x01111110,
0x00111100,
0x00111100,
0x00011000,
0x00011000
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ScrollBarWidget::ScrollBarWidget(GuiObject* boss, const GUI::Font& font,
int x, int y, int w, int h)
: Widget(boss, font, x, y, w, h), CommandSender(boss),
_numEntries(0),
_entriesPerPage(0),
_currentPos(0),
_wheel_lines(0),
_part(kNoPart),
_draggingPart(kNoPart),
_sliderHeight(0),
_sliderPos(0),
_sliderDeltaMouseDownPos(0)
{
_flags = WIDGET_ENABLED | WIDGET_TRACK_MOUSE | WIDGET_CLEARBG;
_bgcolor = kWidColor;
_bgcolorhi = kWidColor;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void ScrollBarWidget::handleMouseDown(int x, int y, int button,
int clickCount)
{
// Ignore subsequent mouse clicks when the slider is being moved
if(_draggingPart == kSliderPart)
return;
int old_pos = _currentPos;
// Do nothing if there are less items than fit on one page
if(_numEntries <= _entriesPerPage)
return;
if (y <= UP_DOWN_BOX_HEIGHT)
{
// Up arrow
_currentPos--;
_draggingPart = kUpArrowPart;
}
else if(y >= _h - UP_DOWN_BOX_HEIGHT)
{
// Down arrow
_currentPos++;
_draggingPart = kDownArrowPart;
}
else if(y < _sliderPos)
{
_currentPos -= _entriesPerPage;
}
else if(y >= _sliderPos + _sliderHeight)
{
_currentPos += _entriesPerPage;
}
else
{
_draggingPart = kSliderPart;
_sliderDeltaMouseDownPos = y - _sliderPos;
}
// Make sure that _currentPos is still inside the bounds
checkBounds(old_pos);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void ScrollBarWidget::handleMouseUp(int x, int y, int button,
int clickCount)
{
_draggingPart = kNoPart;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void ScrollBarWidget::handleMouseWheel(int x, int y, int direction)
{
int old_pos = _currentPos;
if(_numEntries < _entriesPerPage)
return;
if(direction < 0)
_currentPos -= _wheel_lines ? _wheel_lines : _WHEEL_LINES;
else
_currentPos += _wheel_lines ? _wheel_lines : _WHEEL_LINES;
// Make sure that _currentPos is still inside the bounds
checkBounds(old_pos);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void ScrollBarWidget::handleMouseMoved(int x, int y, int button)
{
// Do nothing if there are less items than fit on one page
if(_numEntries <= _entriesPerPage)
return;
if(_draggingPart == kSliderPart)
{
int old_pos = _currentPos;
_sliderPos = y - _sliderDeltaMouseDownPos;
if(_sliderPos < UP_DOWN_BOX_HEIGHT)
_sliderPos = UP_DOWN_BOX_HEIGHT;
if(_sliderPos > _h - UP_DOWN_BOX_HEIGHT - _sliderHeight)
_sliderPos = _h - UP_DOWN_BOX_HEIGHT - _sliderHeight;
_currentPos = (_sliderPos - UP_DOWN_BOX_HEIGHT) * (_numEntries - _entriesPerPage) /
(_h - 2 * UP_DOWN_BOX_HEIGHT - _sliderHeight);
checkBounds(old_pos);
}
else
{
int old_part = _part;
if(y <= UP_DOWN_BOX_HEIGHT) // Up arrow
_part = kUpArrowPart;
else if(y >= _h - UP_DOWN_BOX_HEIGHT) // Down arrow
_part = kDownArrowPart;
else if(y < _sliderPos)
_part = kPageUpPart;
else if(y >= _sliderPos + _sliderHeight)
_part = kPageDownPart;
else
_part = kSliderPart;
if (old_part != _part)
{
setDirty(); draw();
}
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool ScrollBarWidget::handleMouseClicks(int x, int y, int button)
{
// Let continuous mouse clicks come through, as the scroll buttons need them
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void ScrollBarWidget::checkBounds(int old_pos)
{
if(_numEntries <= _entriesPerPage || _currentPos < 0)
_currentPos = 0;
else if(_currentPos > _numEntries - _entriesPerPage)
_currentPos = _numEntries - _entriesPerPage;
if (old_pos != _currentPos)
{
recalc(); // This takes care of the required refresh
setDirty(); draw();
sendCommand(kSetPositionCmd, _currentPos, _id);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void ScrollBarWidget::handleMouseEntered(int button)
{
setFlags(WIDGET_HILITED);
setDirty(); draw();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void ScrollBarWidget::handleMouseLeft(int button)
{
_part = kNoPart;
clearFlags(WIDGET_HILITED);
setDirty(); draw();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void ScrollBarWidget::recalc()
{
//cerr << "ScrollBarWidget::recalc()\n";
if(_numEntries > _entriesPerPage)
{
_sliderHeight = (_h - 2 * UP_DOWN_BOX_HEIGHT) * _entriesPerPage / _numEntries;
if(_sliderHeight < UP_DOWN_BOX_HEIGHT)
_sliderHeight = UP_DOWN_BOX_HEIGHT;
_sliderPos = UP_DOWN_BOX_HEIGHT + (_h - 2 * UP_DOWN_BOX_HEIGHT - _sliderHeight) *
_currentPos / (_numEntries - _entriesPerPage);
if(_sliderPos < 0)
_sliderPos = 0;
}
else
{
_sliderHeight = _h - 2 * UP_DOWN_BOX_HEIGHT;
_sliderPos = UP_DOWN_BOX_HEIGHT;
}
setDirty(); draw();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void ScrollBarWidget::drawWidget(bool hilite)
{
//cerr << "ScrollBarWidget::drawWidget\n";
FBSurface& s = _boss->dialog().surface();
int bottomY = _y + _h;
bool isSinglePage = (_numEntries <= _entriesPerPage);
s.frameRect(_x, _y, _w, _h, kShadowColor);
if(_draggingPart != kNoPart)
_part = _draggingPart;
// Up arrow
s.frameRect(_x, _y, _w, UP_DOWN_BOX_HEIGHT, kColor);
s.drawBitmap(up_arrow, _x+3, _y+5, isSinglePage ? kColor :
(hilite && _part == kUpArrowPart) ? kScrollColorHi : kScrollColor, 8);
// Down arrow
s.frameRect(_x, bottomY - UP_DOWN_BOX_HEIGHT, _w, UP_DOWN_BOX_HEIGHT, kColor);
s.drawBitmap(down_arrow, _x+3, bottomY - UP_DOWN_BOX_HEIGHT + 5, isSinglePage ? kColor :
(hilite && _part == kDownArrowPart) ? kScrollColorHi : kScrollColor, 8);
// Slider
if(!isSinglePage)
{
s.fillRect(_x, _y + _sliderPos, _w, _sliderHeight,
(hilite && _part == kSliderPart) ? kScrollColorHi : kScrollColor);
s.frameRect(_x, _y + _sliderPos, _w, _sliderHeight, kColor);
int y = _y + _sliderPos + _sliderHeight / 2;
s.hLine(_x + 2, y - 2, _x + _w - 3, kWidColor);
s.hLine(_x + 2, y, _x + _w - 3, kWidColor);
s.hLine(_x + 2, y + 2, _x + _w - 3, kWidColor);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int ScrollBarWidget::_WHEEL_LINES = 4;