First pass at fixing ContextMenu when list of items is larger

than the enclosing screen.  Selecting images with the mouse
is working, but the up and down 'buttons' are currently just
drawn text/placeholders.

Still TODO is get the keyboard actions (cursor up/down, etc)
working.


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@1949 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2010-02-15 19:54:15 +00:00
parent f096fa1eb7
commit 965787050a
4 changed files with 116 additions and 81 deletions

View File

@ -108,7 +108,7 @@ void AboutDialog::updateStrings(int page, int lines, string& title)
case 1: case 1:
title = string("Stella ") + STELLA_VERSION; title = string("Stella ") + STELLA_VERSION;
ADD_ATEXT("\\CA multi-platform Atari 2600 VCS emulator"); ADD_ATEXT("\\CA multi-platform Atari 2600 VCS emulator");
ADD_ATEXT(string("\\C\\c2") + instance().features()); ADD_ATEXT(string("\\C\\c2Features: ") + instance().features());
ADD_ATEXT(string("\\C\\c2") + instance().buildInfo()); ADD_ATEXT(string("\\C\\c2") + instance().buildInfo());
ADD_ALINE; ADD_ALINE;
ADD_ATEXT("\\CCopyright (C) 1995-2010 The Stella Team"); ADD_ATEXT("\\CCopyright (C) 1995-2010 The Stella Team");

View File

@ -33,7 +33,9 @@ ContextMenu::ContextMenu(GuiObject* boss, const GUI::Font& font,
_currentItem(-1), _currentItem(-1),
_selectedItem(-1), _selectedItem(-1),
_rowHeight(font.getLineHeight()), _rowHeight(font.getLineHeight()),
_twoColumns(false), _firstEntry(0),
_numEntries(0),
_showScroll(false),
_font(&font), _font(&font),
_cmd(cmd), _cmd(cmd),
_xorig(0), _xorig(0),
@ -54,21 +56,6 @@ void ContextMenu::addItems(const StringMap& items)
_entries.clear(); _entries.clear();
_entries = items; _entries = items;
// Create two columns of entries if there are more than 10 items
if(_entries.size() > 10)
{
_twoColumns = true;
_entriesPerColumn = _entries.size() / 2;
if(_entries.size() & 1)
_entriesPerColumn++;
}
else
{
_twoColumns = false;
_entriesPerColumn = _entries.size();
}
// Resize to largest string // Resize to largest string
int maxwidth = 0; int maxwidth = 0;
for(unsigned int i = 0; i < _entries.size(); ++i) for(unsigned int i = 0; i < _entries.size(); ++i)
@ -79,8 +66,8 @@ void ContextMenu::addItems(const StringMap& items)
} }
_x = _y = 0; _x = _y = 0;
_w = maxwidth * (_twoColumns ? 2 : 1) + 10; _w = maxwidth + 10;
_h = _entriesPerColumn * _rowHeight + 4; _h = 1; // recalculate this in ::recalc()
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -88,6 +75,8 @@ void ContextMenu::show(uInt32 x, uInt32 y, int item)
{ {
_xorig = x; _xorig = x;
_yorig = y; _yorig = y;
recalc(instance().frameBuffer().imageRect());
parent().addDialog(this); parent().addDialog(this);
setSelected(item); setSelected(item);
} }
@ -98,6 +87,7 @@ void ContextMenu::center()
// Make sure the menu is exactly where it should be, in case the image // Make sure the menu is exactly where it should be, in case the image
// offset has changed // offset has changed
const GUI::Rect& image = instance().frameBuffer().imageRect(); const GUI::Rect& image = instance().frameBuffer().imageRect();
recalc(image);
uInt32 x = image.x() + _xorig; uInt32 x = image.x() + _xorig;
uInt32 y = image.y() + _yorig; uInt32 y = image.y() + _yorig;
uInt32 tx = image.x() + image.width(); uInt32 tx = image.x() + image.width();
@ -108,6 +98,27 @@ void ContextMenu::center()
surface().setPos(x, y); surface().setPos(x, y);
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void ContextMenu::recalc(const GUI::Rect& image)
{
// Now is the time to adjust the height
// If it's higher than the screen, we need to scroll through
int maxentries = (image.height() - 4) / _rowHeight;
if((int)_entries.size() > maxentries)
{
// We show two less than the max, so we have room for two scroll buttons
_numEntries = maxentries - 2;
_h = maxentries * _rowHeight + 4;
_showScroll = true;
}
else
{
_numEntries = _entries.size();
_h = _entries.size() * _rowHeight + 4;
_showScroll = false;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void ContextMenu::setSelected(int item) void ContextMenu::setSelected(int item)
{ {
@ -184,15 +195,6 @@ void ContextMenu::handleMouseDown(int x, int y, int button, int clickCount)
} }
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void ContextMenu::handleMouseWheel(int x, int y, int direction)
{
if(direction < 0)
moveUp();
else if(direction > 0)
moveDown();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void ContextMenu::handleMouseMoved(int x, int y, int button) void ContextMenu::handleMouseMoved(int x, int y, int button)
{ {
@ -265,21 +267,8 @@ void ContextMenu::handleEvent(Event::Type e)
int ContextMenu::findItem(int x, int y) const int ContextMenu::findItem(int x, int y) const
{ {
if(x >= 0 && x < _w && y >= 0 && y < _h) if(x >= 0 && x < _w && y >= 0 && y < _h)
{
if(_twoColumns)
{
unsigned int entry = (y - 4) / _rowHeight;
if(x > _w / 2)
{
entry += _entriesPerColumn;
if(entry >= _entries.size())
return -1;
}
return entry;
}
return (y - 4) / _rowHeight; return (y - 4) / _rowHeight;
}
return -1; return -1;
} }
@ -297,6 +286,19 @@ void ContextMenu::drawCurrentSelection(int item)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void ContextMenu::sendSelection() void ContextMenu::sendSelection()
{ {
// Select the correct item when scrolling; we have to take into account
// that the viewable items are no longer 1-to-1 with the entries
int item = _currentItem;
if(_showScroll)
{
if(item == 0) // scroll up
return scrollUp();
else if(item == _numEntries+1) // scroll down
return scrollDown();
else
item = item + _firstEntry - 1;
}
// We remove the dialog when the user has selected an item // We remove the dialog when the user has selected an item
// Make sure the dialog is removed before sending any commands, // Make sure the dialog is removed before sending any commands,
// since one consequence of sending a command may be to add another // since one consequence of sending a command may be to add another
@ -304,7 +306,7 @@ void ContextMenu::sendSelection()
close(); close();
// Send any command associated with the selection // Send any command associated with the selection
_selectedItem = _currentItem; _selectedItem = item;
sendCommand(_cmd ? _cmd : kCMenuItemSelectedCmd, _selectedItem, -1); sendCommand(_cmd ? _cmd : kCMenuItemSelectedCmd, _selectedItem, -1);
} }
@ -312,6 +314,14 @@ void ContextMenu::sendSelection()
void ContextMenu::moveUp() void ContextMenu::moveUp()
{ {
int item = _currentItem; int item = _currentItem;
if(_showScroll)
{
if(item > 0) // scroll up
{
if(_firstEntry > item)
_firstEntry--;
}
}
if(item > 0) if(item > 0)
drawCurrentSelection(--item); drawCurrentSelection(--item);
} }
@ -320,10 +330,39 @@ void ContextMenu::moveUp()
void ContextMenu::moveDown() void ContextMenu::moveDown()
{ {
int item = _currentItem; int item = _currentItem;
if(_showScroll)
{
if(item == _numEntries+1) // scroll down
{
if(_firstEntry + _numEntries < (int)_entries.size())
_firstEntry++;
}
setDirty();
}
if(item < (int)_entries.size() - 1) if(item < (int)_entries.size() - 1)
drawCurrentSelection(++item); drawCurrentSelection(++item);
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void ContextMenu::scrollUp()
{
if(_firstEntry > _currentItem)
{
_firstEntry--;
setDirty();
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void ContextMenu::scrollDown()
{
if(_firstEntry + _numEntries < (int)_entries.size())
{
_firstEntry++;
setDirty();
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void ContextMenu::drawDialog() void ContextMenu::drawDialog()
{ {
@ -338,42 +377,34 @@ void ContextMenu::drawDialog()
s.fillRect(_x+1, _y+1, _w-2, _h-2, kWidColor); s.fillRect(_x+1, _y+1, _w-2, _h-2, kWidColor);
s.box(_x, _y, _w, _h, kColor, kShadowColor); s.box(_x, _y, _w, _h, kColor, kShadowColor);
// If necessary, draw dividing line // Draw the entries, taking scroll buttons into account
if(_twoColumns) int x = _x + 2, y = _y + 2, w = _w - 4;
s.vLine(_x + _w / 2, _y, _y + _h - 2, kColor); cerr << "_firstEntry = " << _firstEntry << ", _numEntries = " << _numEntries << endl;
// Draw the entries // Show top scroll area
int x, y, w; int offset = _firstEntry;
int count = _entries.size(); if(_showScroll)
for(int i = 0; i < count; i++)
{ {
bool hilite = i == _currentItem; s.drawString(_font, " ^^^^^", x + 1, y + 2, w, kTextColor);
if(_twoColumns) y += _rowHeight;
{ offset--;
int n = _entries.size() / 2;
if(_entries.size() & 1) n++;
if(i >= n)
{
x = _x + 1 + _w / 2;
y = _y + 2 + _rowHeight * (i - n);
}
else
{
x = _x + 2;
y = _y + 2 + _rowHeight * i;
}
w = _w / 2 - 3;
}
else
{
x = _x + 2;
y = _y + 2 + i * _rowHeight;
w = _w - 4;
}
if(hilite) s.fillRect(x, y, w, _rowHeight, kTextColorHi);
s.drawString(_font, _entries[i].first, x + 1, y + 2, w - 2,
hilite ? kWidColor : kTextColor);
} }
for(int i = _firstEntry; i < _firstEntry + _numEntries; ++i)
{
bool hilite = (i-offset) == _currentItem;
if(hilite) s.fillRect(x, y, w, _rowHeight, kTextColorHi);
s.drawString(_font, _entries[i].first, x + 1, y + 2, w,
hilite ? kWidColor : kTextColor);
y += _rowHeight;
}
// Show bottom scroll area
if(_showScroll)
{
s.drawString(_font, " vvvvv", x + 1, y + 2, w, kTextColor);
}
s.addDirtyRect(_x, _y, _w, _h); s.addDirtyRect(_x, _y, _w, _h);
_dirty = false; _dirty = false;
} }

View File

@ -44,7 +44,7 @@ class ContextMenu : public Dialog, public CommandSender
public: public:
ContextMenu(GuiObject* boss, const GUI::Font& font, ContextMenu(GuiObject* boss, const GUI::Font& font,
const StringMap& items, int cmd = 0); const StringMap& items, int cmd = 0);
virtual ~ContextMenu(); virtual ~ContextMenu();
/** Add the given items to the widget. */ /** Add the given items to the widget. */
void addItems(const StringMap& items); void addItems(const StringMap& items);
@ -74,7 +74,6 @@ class ContextMenu : public Dialog, public CommandSender
protected: protected:
void handleMouseDown(int x, int y, int button, int clickCount); void handleMouseDown(int x, int y, int button, int clickCount);
void handleMouseWheel(int x, int y, int direction);
void handleMouseMoved(int x, int y, int button); void handleMouseMoved(int x, int y, int button);
void handleKeyDown(int ascii, int keycode, int modifiers); // Scroll through entries with arrow keys etc void handleKeyDown(int ascii, int keycode, int modifiers); // Scroll through entries with arrow keys etc
void handleJoyDown(int stick, int button); void handleJoyDown(int stick, int button);
@ -85,6 +84,7 @@ class ContextMenu : public Dialog, public CommandSender
void drawDialog(); void drawDialog();
private: private:
void recalc(const GUI::Rect& image);
void drawMenuEntry(int entry, bool hilite); void drawMenuEntry(int entry, bool hilite);
int findItem(int x, int y) const; int findItem(int x, int y) const;
@ -92,6 +92,8 @@ class ContextMenu : public Dialog, public CommandSender
void moveUp(); void moveUp();
void moveDown(); void moveDown();
void scrollUp();
void scrollDown();
void sendSelection(); void sendSelection();
@ -101,9 +103,8 @@ class ContextMenu : public Dialog, public CommandSender
int _currentItem; int _currentItem;
int _selectedItem; int _selectedItem;
int _rowHeight; int _rowHeight;
int _firstEntry, _numEntries;
bool _twoColumns; bool _showScroll;
int _entriesPerColumn;
const GUI::Font* _font; const GUI::Font* _font;
int _cmd; int _cmd;

View File

@ -107,6 +107,9 @@ void DialogContainer::draw(bool full)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void DialogContainer::addDialog(Dialog* d) void DialogContainer::addDialog(Dialog* d)
{ {
const GUI::Rect& image = myOSystem->frameBuffer().imageRect();
assert(d->getWidth() <= image.width() && d->getHeight() <= image.height());
myDialogStack.push(d); myDialogStack.push(d);
d->open(); d->open();