added mouse support to editable widgets

added missing hotkeys to launcher context menu
updated docs
This commit is contained in:
thrust26 2020-12-20 15:13:03 +01:00
parent e837e1f94c
commit c081481825
11 changed files with 245 additions and 90 deletions

View File

@ -16,9 +16,11 @@
* Added high scores saving.
* Enhanced cut/copy/paste for text editing. (TODO: PromptWidget)
* Enhanced cut/copy/paste for text editing (except PromptWidget).
* Added undo and redo to text editing. (TODO: PromptWidget)
* Added undo and redo to text editing (except PromptWidget).
* Added mouse support for text editing (except PromptWidget).
* Added wildcard support to launcher dialog filter.

View File

@ -1987,23 +1987,18 @@
<th>Key (macOS)</th>
</tr>
<tr>
<td>Load <i>previous</i> game in ROM (multicart ROM, TIA mode)</td>
<td>Load <i>previous</i> game in ROM (multicart ROM)</td>
<td>Shift-Control + r</td>
<td>Shift-Control + r</td>
</tr>
<tr>
<td>Reload current ROM (singlecart ROM, TIA mode)<br>
Load <i>next</i> game in ROM (multicart ROM, TIA mode)</td>
<td>Reload current ROM (singlecart ROM)<br>
Load <i>next</i> game in ROM (multicart ROM)</td>
<td>Control + r</td>
<td>Control + r</td>
</tr>
<tr>
<td>Reload ROM listing (ROM launcher mode)</td>
<td>Control + r</td>
<td>Control + r</td>
</tr>
<tr>
<td>Emulate 'frying' effect (TIA mode)</td>
<td>Emulate 'frying' effect</td>
<td>Backspace</td>
<td>Backspace</td>
</tr>
@ -4007,7 +4002,7 @@
<h3><b><a name="ROMLauncherContextMenu">ROM Launcher Context Menu</a></b></h3>
<p>The ROM launcher also contains a context menu, selected by clicking the
right mouse button anywhere in the current window. This context menu
right mouse button in the ROM list. This context menu
contains the following items:</p>
<p><ol>
@ -4018,31 +4013,32 @@
its functionality, and use ROM properties as defined by the ROM itself. The dialog is as
follows (see <b>Advanced Configuration - <a href="#Properties">Game Properties</a></b>
for more information concerning ROM properties):</p>
<table border="5" cellpadding="2" frame="box" rules="none">
<tr>
<td><img src="graphics/launcher_override.png"></td>
<td>&nbsp;&nbsp;&nbsp;&nbsp;</td>
<td valign="top">
<table border="1" cellpadding="4">
<tr><th>Item</th><th>For more information,<br>see <a href="#CommandLine">Commandline</a></th></tr>
<tr><td>Bankswitch type</td><td>-bs</td></tr>
<tr><td>TV type</td><td>-tv</td></tr>
<tr><td>Left difficulty</td><td>-ld</td></tr>
<tr><td>Right difficulty</td><td>-rd</td></tr>
<tr><td>Startup mode</td><td>-debug</td></tr>
<tr><td>Left joy items</td><td>-holdjoy0</td></tr>
<tr><td>Right joy items</td><td>-holdjoy1</td></tr>
<tr><td>Console: Select</td><td>-holdselect</td></tr>
<tr><td>Console: Reset</td><td>-holdreset</td></tr>
</table>
<p></p>
</td>
</tr>
</table>
<table border="5" cellpadding="2" frame="box" rules="none">
<tr>
<td><img src="graphics/launcher_override.png"></td>
<td>&nbsp;&nbsp;&nbsp;&nbsp;</td>
<td valign="top">
<table border="1" cellpadding="4">
<tr><th>Item</th><th>For more information,<br>see <a href="#CommandLine">Commandline</a></th></tr>
<tr><td>Bankswitch type</td><td>-bs</td></tr>
<tr><td>TV type</td><td>-tv</td></tr>
<tr><td>Left difficulty</td><td>-ld</td></tr>
<tr><td>Right difficulty</td><td>-rd</td></tr>
<tr><td>Startup mode</td><td>-debug</td></tr>
<tr><td>Left joy items</td><td>-holdjoy0</td></tr>
<tr><td>Right joy items</td><td>-holdjoy1</td></tr>
<tr><td>Console: Select</td><td>-holdselect</td></tr>
<tr><td>Console: Reset</td><td>-holdreset</td></tr>
</table>
<p></p>
</td>
</tr>
</table>
<p>This dialog can also be opened by pressing 'Control + p'.</p>
</li>
<br><li><b>High scores</b>: This option displays the <a href="#HighScores">
<li><b>High scores</b>: This option displays the <a href="#HighScores">
High Scores</a> dialog for the selected ROM. Only available if high score
properties have been setup for the ROM.</li>
properties have been setup for the ROM. Also available via 'Control + h' keys combo.</li>
</li>
<br><li><b>Reload listing</b>: Selecting this performs a reload of the
current listing. It is an alternative to pressing the 'Control + r'
@ -4355,7 +4351,7 @@
<p><ul>
<li>Developer key-combo shortcuts, used to change TIA state dynamically
(ie, while the emulation is still running). See <b>Keyboard Layout -
<a href="#DeveloperKeys">Developer Keys in TIA mode</a></b> for more information.</li>
<a href="#DeveloperKeys">Developer Keys</a></b> for more information.</li>
<li>Commandline options influencing emulation state. See <b>Using the Command Line -
<a href="#DeveloperCommandLine">Developer Commands</a></b> for more information.</li>

View File

@ -34,6 +34,8 @@ class RomListSettings : public Dialog, public CommandSender
RomListSettings(GuiObject* boss, const GUI::Font& font);
~RomListSettings() override = default;
bool isShading() const override { return false; }
/** Show dialog onscreen at the specified coordinates
('data' will be the currently selected line number in RomListWidget) */
void show(uInt32 x, uInt32 y, const Common::Rect& bossRect, int data = -1);

View File

@ -35,8 +35,8 @@ ContextMenu::ContextMenu(GuiObject* boss, const GUI::Font& font,
_cmd(cmd),
_maxWidth(width)
{
addItems(items);
setArrows();
addItems(items);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -48,10 +48,10 @@ void ContextMenu::addItems(const VariantList& items)
// Resize to largest string
int maxwidth = _maxWidth;
for(const auto& e: _entries)
maxwidth = std::max(maxwidth, _font.getStringWidth(e.first));
maxwidth = std::max(maxwidth, _font.getStringWidth(e.first) + _textOfs * 2 + 2);
_x = _y = 0;
_w = maxwidth + PopUpWidget::dropDownWidth(_font); // 23;
_w = maxwidth;
_h = 1; // recalculate this in ::recalc()
_scrollUpColor = _firstEntry > 0 ? kScrollColor : kColor;

View File

@ -27,7 +27,8 @@ EditTextWidget::EditTextWidget(GuiObject* boss, const GUI::Font& font,
int x, int y, int w, int h, const string& text)
: EditableWidget(boss, font, x, y, w, h + 2, text)
{
_flags = Widget::FLAG_ENABLED | Widget::FLAG_CLEARBG | Widget::FLAG_RETAIN_FOCUS;
_flags = Widget::FLAG_ENABLED | Widget::FLAG_CLEARBG
| Widget::FLAG_RETAIN_FOCUS | Widget::FLAG_TRACK_MOUSE;
EditableWidget::startEditMode(); // We're always in edit mode
@ -56,24 +57,16 @@ void EditTextWidget::setText(const string& str, bool changed)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EditTextWidget::handleMouseDown(int x, int y, MouseButton b, int clickCount)
{
if(!isEditable())
return;
resetSelection();
x += _editScrollOffset;
int width = 0;
uInt32 i;
for (i = 0; i < editString().size(); ++i)
if(b == MouseButton::LEFT)
{
width += _font.getCharWidth(editString()[i]);
if (width >= x)
break;
}
if(!isEditable())
return;
if (setCaretPos(i))
setDirty();
resetSelection();
if(setCaretPos(toCaretPos(x)))
setDirty();
}
EditableWidget::handleMouseDown(x, y, b, clickCount);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -19,6 +19,7 @@
#include "StellaKeys.hxx"
#include "FBSurface.hxx"
#include "Font.hxx"
#include "ContextMenu.hxx"
#include "OSystem.hxx"
#include "EventHandler.hxx"
#include "UndoHandler.hxx"
@ -39,6 +40,9 @@ EditableWidget::EditableWidget(GuiObject* boss, const GUI::Font& font,
_bgcolorlo = kDlgColor;
_textcolor = kTextColor;
_textcolorhi = kTextColor;
// add mouse context menu
myMouseMenu = make_unique<ContextMenu>(this, font, EmptyVarList);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -120,6 +124,115 @@ void EditableWidget::lostFocusWidget()
_selectSize = 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int EditableWidget::toCaretPos(int x) const
{
int i;
x += caretOfs();
for(i = 0; i < _editString.size(); ++i)
{
x -= _font.getCharWidth(_editString[i]);
if(x <= 0)
break;
}
return i;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EditableWidget::handleMouseDown(int x, int y, MouseButton b, int clickCount)
{
// Grab right mouse button for context menu, send left to base class
if(b == MouseButton::RIGHT && isEnabled() && !myMouseMenu->isVisible())
{
VariantList items;
#ifndef BSPF_MACOS
if(isEditable())
VarList::push_back(items, " Cut Ctrl+X ", "cut");
VarList::push_back(items, " Copy Ctrl+C ", "copy");
if(isEditable())
VarList::push_back(items, " Paste Ctrl+V ", "paste");
#else
if(isEditable())
VarList::push_back(items, " Cut Cmd+X ", "cut");
VarList::push_back(items, " Copy Cmd+C ", "copy");
if(isEditable())
VarList::push_back(items, " Paste Cmd+V ", "paste");
#endif
myMouseMenu->addItems(items);
// Add menu at current x,y mouse location
myMouseMenu->show(x + getAbsX(), y + getAbsY(), dialog().surface().dstRect());
return;
}
else if(b == MouseButton::LEFT && isEnabled())
{
_isDragging = true;
if(clickCount == 2)
{
// If left mouse button is double clicked, mark word under cursor
markWord();
return;
}
}
Widget::handleMouseDown(x, y, b, clickCount);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EditableWidget::handleMouseUp(int x, int y, MouseButton b, int clickCount)
{
_isDragging = false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EditableWidget::handleMouseMoved(int x, int y)
{
if(isEditable() && _isDragging)
{
int deltaPos = toCaretPos(x) - _caretPos;
if(deltaPos)
{
moveCaretPos(deltaPos);
setDirty();
}
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EditableWidget::handleCommand(CommandSender* sender, int cmd, int data, int id)
{
if(cmd == ContextMenu::kItemSelectedCmd)
{
const string& rmb = myMouseMenu->getSelectedTag().toString();
if(rmb == "cut")
{
if(cutSelectedText())
sendCommand(EditableWidget::kChangedCmd, 0, _id);
}
else if(rmb == "copy")
{
if(!isEditable())
{
// Copy everything if widget is not editable
_caretPos = 0;
_selectSize = int(_editString.length());
}
copySelectedText();
}
else if(rmb == "paste")
{
if(pasteSelectedText())
sendCommand(EditableWidget::kChangedCmd, 0, _id);
}
setDirty();
}
else
Widget::handleCommand(sender, cmd, data, id);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool EditableWidget::tryInsertChar(char c, int pos)
{
@ -634,6 +747,28 @@ bool EditableWidget::moveWord(int direction, bool select)
return handled;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool EditableWidget::markWord()
{
_selectSize = 0;
while(_caretPos + _selectSize < int(_editString.size()))
{
if(_editString[_caretPos + _selectSize] == ' ')
break;
_selectSize++;
}
while(_caretPos > 0)
{
if(_editString[_caretPos - 1] == ' ')
break;
_caretPos--;
_selectSize++;
}
return _selectSize > 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const string EditableWidget::selectString() const
{

View File

@ -22,6 +22,7 @@
#include "Widget.hxx"
#include "Rect.hxx"
#include "ContextMenu.hxx"
#include "UndoHandler.hxx"
/**
@ -66,6 +67,13 @@ class EditableWidget : public Widget, public CommandSender
void setTextFilter(const TextFilter& filter) { _filter = filter; }
protected:
void handleMouseDown(int x, int y, MouseButton b, int clickCount) override;
void handleMouseUp(int x, int y, MouseButton b, int clickCount) override;
void handleMouseMoved(int x, int y) override;
void handleCommand(CommandSender* sender, int cmd, int data, int id);
virtual int caretOfs() const { return _editScrollOffset; }
int toCaretPos(int x) const;
void receivedFocusWidget() override;
void lostFocusWidget() override;
void tick() override;
@ -95,6 +103,7 @@ class EditableWidget : public Widget, public CommandSender
bool killLine(int direction);
bool killWord(int direction);
bool moveWord(int direction, bool select);
bool markWord();
bool killSelectedText(bool addEdit = true);
int selectStartPos();
@ -109,9 +118,12 @@ class EditableWidget : public Widget, public CommandSender
bool tryInsertChar(char c, int pos);
private:
unique_ptr<ContextMenu> myMouseMenu;
bool _isDragging{false};
bool _editable{true};
string _editString;
int _maxLen{0};
int _maxLen{0};
unique_ptr<UndoHandler> myUndoHandler;
int _caretPos{0};

View File

@ -634,9 +634,28 @@ void LauncherDialog::showOnlyROMs(bool state)
void LauncherDialog::handleKeyDown(StellaKey key, StellaMod mod, bool repeated)
{
// Grab the key before passing it to the actual dialog and check for
// Control-R (reload ROM listing)
if(StellaModTest::isControl(mod) && key == KBDK_R)
reload();
// context menu keys
if(StellaModTest::isControl(mod))
{
switch(key)
{
case KBDK_P:
myGlobalProps->open();
break;
case KBDK_H:
if(instance().highScores().enabled())
openHighScores();
break;
case KBDK_R:
reload();
break;
default:
break;
}
}
else
#if defined(RETRON77)
// handle keys used by R77
@ -725,21 +744,22 @@ Event::Type LauncherDialog::getJoyAxisEvent(int stick, JoyAxis axis, JoyDir adir
void LauncherDialog::handleMouseDown(int x, int y, MouseButton b, int clickCount)
{
// Grab right mouse button for context menu, send left to base class
if(b == MouseButton::RIGHT)
if(b == MouseButton::RIGHT
&& x + getAbsX() >= myList->getLeft() && x + getAbsX() <= myList->getRight()
&& y + getAbsY() >= myList->getTop() && y + getAbsY() <= myList->getBottom())
{
// Dynamically create context menu for ROM list options
VariantList items;
if(!currentNode().isDirectory() && Bankswitch::isValidRomName(currentNode()))
VarList::push_back(items, "Power-on options" + ELLIPSIS, "override");
VarList::push_back(items, " Power-on options" + ELLIPSIS + " Ctrl+P", "override");
if(instance().highScores().enabled())
VarList::push_back(items, "High scores" + ELLIPSIS, "highscores");
VarList::push_back(items, "Reload listing", "reload");
VarList::push_back(items, " High scores" + ELLIPSIS + " Ctrl+H", "highscores");
VarList::push_back(items, " Reload listing Ctrl+R ", "reload");
myMenu->addItems(items);
// Add menu at current x,y mouse location
myMenu->show(x + getAbsX(), y + getAbsY(), surface().dstRect());
}
else
Dialog::handleMouseDown(x, y, b, clickCount);

View File

@ -32,7 +32,8 @@ PopUpWidget::PopUpWidget(GuiObject* boss, const GUI::Font& font,
_label(label),
_labelWidth(labelWidth)
{
_flags = Widget::FLAG_ENABLED | Widget::FLAG_RETAIN_FOCUS;
_flags = Widget::FLAG_ENABLED | Widget::FLAG_RETAIN_FOCUS
| Widget::FLAG_TRACK_MOUSE;
_bgcolor = kDlgColor;
_bgcolorhi = kDlgColor; // do not highlight the background
_textcolor = kTextColor;
@ -51,7 +52,7 @@ PopUpWidget::PopUpWidget(GuiObject* boss, const GUI::Font& font,
myTextY = (_h - _font.getFontHeight()) / 2;
myArrowsY = (_h - _arrowHeight) / 2;
myMenu = make_unique<ContextMenu>(this, font, list, cmd, w);
myMenu = make_unique<ContextMenu>(this, font, list, cmd, w + dropDownWidth(font));
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -127,33 +128,25 @@ const Variant& PopUpWidget::getSelectedTag() const
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PopUpWidget::handleMouseDown(int x, int y, MouseButton b, int clickCount)
{
resetSelection();
if(!isEditable() || x > _w - dropDownWidth(_font))
if(b == MouseButton::LEFT)
{
if(isEnabled() && !myMenu->isVisible())
resetSelection();
if(!isEditable() || x > _w - dropDownWidth(_font))
{
// Add menu just underneath parent widget
myMenu->show(getAbsX() + _labelWidth, getAbsY() + getHeight(),
dialog().surface().dstRect(), myMenu->getSelected());
if(isEnabled() && !myMenu->isVisible())
{
// Add menu just underneath parent widget
myMenu->show(getAbsX() + _labelWidth, getAbsY() + getHeight(),
dialog().surface().dstRect(), myMenu->getSelected());
}
}
else
{
if(setCaretPos(toCaretPos(x)))
setDirty();
}
}
else
{
x += _editScrollOffset - _labelWidth;
int width = 0;
uInt32 i;
for(i = 0; i < editString().size(); ++i)
{
width += _font.getCharWidth(editString()[i]);
if(width >= x)
break;
}
if(setCaretPos(i))
setDirty();
}
EditableWidget::handleMouseDown(x, y, b, clickCount);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -72,6 +72,7 @@ class PopUpWidget : public EditableWidget
void handleMouseWheel(int x, int y, int direction) override;
bool handleEvent(Event::Type e) override;
void handleCommand(CommandSender* sender, int cmd, int data, int id) override;
int caretOfs() const override { return _editScrollOffset - _labelWidth; }
void setArrow();
void drawWidget(bool hilite) override;

View File

@ -49,6 +49,7 @@ WhatsNewDialog::WhatsNewDialog(OSystem& osystem, DialogContainer& parent, const
#else
add(ypos, "added high scores saving");
add(ypos, "enhanced cut/copy/paste and undo/redo for text editing");
add(ypos, "added mouse support for text editing");
add(ypos, "added wildcard support to launcher dialog filter");
add(ypos, "added option to search subdirectories in launcher");
add(ypos, "added tooltips to many UI items");