mirror of https://github.com/stella-emu/stella.git
Merge remote-tracking branch 'origin/master' into feature/json-mappings
This commit is contained in:
commit
730932355f
18
Changes.txt
18
Changes.txt
|
@ -14,7 +14,23 @@
|
|||
|
||||
6.4 to 6.5 (December XX, 2020)
|
||||
|
||||
* Enhanced cut/copy/paste to allow selecting text (TODO: PromptWidget, doc)
|
||||
* Enhanced cut/copy/paste for text editing. (TODO: PromptWidget)
|
||||
|
||||
* Added undo and redo to text editing. (TODO: PromptWidget)
|
||||
|
||||
* Added wildcard support to launcher dialog filter.
|
||||
|
||||
* Added option to search subdirectories in launcher.
|
||||
|
||||
* Added static tooltips to some UI items.
|
||||
|
||||
* Added dynamic tooltips to most debugger items.
|
||||
|
||||
* Increased sample size for CDFJ+.
|
||||
|
||||
* Fixed autofire bug for trackball controllers.
|
||||
|
||||
* Codebase now uses C++17 features.
|
||||
|
||||
-Have fun!
|
||||
|
||||
|
|
8
Makefile
8
Makefile
|
@ -48,11 +48,11 @@ endif
|
|||
CXXFLAGS+= -Wall -Wextra -Wno-unused-parameter
|
||||
|
||||
ifdef HAVE_GCC
|
||||
CXXFLAGS+= -Wno-multichar -Wunused -fno-rtti -Woverloaded-virtual -Wnon-virtual-dtor -std=c++14
|
||||
CXXFLAGS+= -Wno-multichar -Wunused -Woverloaded-virtual -Wnon-virtual-dtor -std=c++17
|
||||
endif
|
||||
|
||||
ifdef HAVE_CLANG
|
||||
CXXFLAGS+= -Wno-multichar -Wunused -fno-rtti -Woverloaded-virtual -Wnon-virtual-dtor -std=c++14
|
||||
CXXFLAGS+= -Wno-multichar -Wunused -Woverloaded-virtual -Wnon-virtual-dtor -std=c++17
|
||||
endif
|
||||
|
||||
ifdef CLANG_WARNINGS
|
||||
|
@ -81,8 +81,8 @@ else
|
|||
endif
|
||||
|
||||
ifdef RELEASE
|
||||
CXXFLAGS += -flto
|
||||
LDFLAGS += -flto
|
||||
CXXFLAGS += -flto -fno-rtti
|
||||
LDFLAGS += -flto -fno-rtti
|
||||
endif
|
||||
|
||||
#######################################################################
|
||||
|
|
|
@ -385,7 +385,7 @@ else
|
|||
fi
|
||||
|
||||
for compiler in $compilers; do
|
||||
if test_compiler "$compiler -std=c++14"; then
|
||||
if test_compiler "$compiler -std=c++17"; then
|
||||
CXX=$compiler
|
||||
echo $CXX
|
||||
break
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 44 KiB |
Binary file not shown.
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 36 KiB |
Binary file not shown.
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 74 KiB |
|
@ -260,7 +260,7 @@
|
|||
<h2><b><a name="Features">Features</a></b></h2>
|
||||
|
||||
<ul>
|
||||
<li>High speed emulation using optimized C++14 code</li>
|
||||
<li>High speed emulation using optimized C++17 code</li>
|
||||
<li>Supports high quality TIA emulation using the cycle-exact TIA core from
|
||||
<a href="https://github.com/6502ts/6502.ts">6502.ts</a> by
|
||||
Christian Speckner</li>
|
||||
|
@ -350,7 +350,7 @@
|
|||
<li>OpenGL capable video card</li>
|
||||
<li>Other architectures (MIPS, PPC, PPC64, etc.) have been confirmed to work,
|
||||
but aren't as well tested as i386/x86_64</li>
|
||||
<li>GNU g++ v/6 or Clang v/3.9 (with C++14 support) and the make utility are required for compiling the Stella source code</li>
|
||||
<li>GNU g++ v/7 or Clang v/5 (with C++17 support) and the make utility are required for compiling the Stella source code</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
|
@ -3689,15 +3689,29 @@
|
|||
<p>ROM Info Viewer width at 50% , UI sized 1280x900, large launcher font:</p>
|
||||
<img src="graphics/rominfo_2x_small.png">
|
||||
|
||||
<p>The text box in the upper right corner can be used to narrow down the
|
||||
results in the ROM listing. When this box is empty, all files are shown
|
||||
(subject to the restrictions from the filtering option, explained below).
|
||||
Typing characters here will show only those files that match that
|
||||
<p>The dialog items at the top can be used to define the listed files:</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
The 'Show all files' checkbox allows displaying files which do not
|
||||
have a valid ROM extension.
|
||||
</li><li>
|
||||
If 'Incl. subdirectories' is checked, Stella will list matching files
|
||||
from all subdirectories too.
|
||||
</li><li>
|
||||
The 'Filter' text box can be used to narrow down the results in the
|
||||
ROM listing. When this box is empty, all files are shown. Typing
|
||||
characters here will show only those files that match that
|
||||
pattern. For example, typing 'Activision' will show only files that
|
||||
contain the word 'Activision' in their name. This is very useful for
|
||||
quickly finding a group of related ROMs. Note that the search is not
|
||||
case sensitive, so you don't need to worry about capital or lower-case
|
||||
letters.</p>
|
||||
quickly finding a group of related ROMs.</br>
|
||||
Note that the search is not case sensitive, so you don't need to worry
|
||||
about capital or lower-case letters. You also can use '*' and '?' as
|
||||
wildcards. E.g. for '(198?)*atari' only ROMs from the 1980s made by
|
||||
Atari will be listed.
|
||||
</li>
|
||||
</ul>
|
||||
</br>
|
||||
|
||||
<h3><b><a name="ROMLauncherContextMenu">ROM Launcher Context Menu</a></b></h3>
|
||||
|
||||
|
@ -3735,12 +3749,6 @@
|
|||
</tr>
|
||||
</table>
|
||||
</li>
|
||||
<br><li><b>Show only ROM files</b>: Selecting this reloads the current listing,
|
||||
showing only files that have a valid ROM extension.</li>
|
||||
|
||||
<br><li><b>Show all files</b>: Selecting this reloads the current listing,
|
||||
showing <i>all</i> files (with no restriction on file name).</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'
|
||||
key combo.</li>
|
||||
|
|
|
@ -100,6 +100,7 @@ CheatCodeDialog::CheatCodeDialog(OSystem& osystem, DialogContainer& parent,
|
|||
return (c >= 'a' && c <= 'f') || (c >= '0' && c <= '9');
|
||||
};
|
||||
myCheatInput->setTextFilter(f1, 1);
|
||||
myCheatInput->setToolTip("See Stella documentation for details.", 1);
|
||||
|
||||
addToFocusList(wid);
|
||||
|
||||
|
|
|
@ -45,6 +45,8 @@ EventHandlerSDL2::EventHandlerSDL2(OSystem& osystem)
|
|||
}
|
||||
Logger::debug("EventHandlerSDL2::EventHandlerSDL2 SDL_INIT_JOYSTICK");
|
||||
#endif
|
||||
|
||||
SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1");
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -104,41 +104,49 @@ const Common::Rect& FBSurfaceSDL2::dstRect() const
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FBSurfaceSDL2::setSrcPos(uInt32 x, uInt32 y)
|
||||
{
|
||||
if(x != static_cast<uInt32>(mySrcR.x) || y != static_cast<uInt32>(mySrcR.y))
|
||||
{
|
||||
setSrcPosInternal(x, y);
|
||||
if(setSrcPosInternal(x, y))
|
||||
reinitializeBlitter();
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FBSurfaceSDL2::setSrcSize(uInt32 w, uInt32 h)
|
||||
{
|
||||
if(w != static_cast<uInt32>(mySrcR.w) || h != static_cast<uInt32>(mySrcR.h))
|
||||
{
|
||||
setSrcSizeInternal(w, h);
|
||||
if(setSrcSizeInternal(w, h))
|
||||
reinitializeBlitter();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FBSurfaceSDL2::setSrcRect(const Common::Rect& r)
|
||||
{
|
||||
const bool posChanged = setSrcPosInternal(r.x(), r.y()),
|
||||
sizeChanged = setSrcSizeInternal(r.w(), r.h());
|
||||
|
||||
if(posChanged || sizeChanged)
|
||||
reinitializeBlitter();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FBSurfaceSDL2::setDstPos(uInt32 x, uInt32 y)
|
||||
{
|
||||
if(x != static_cast<uInt32>(myDstR.x) || y != static_cast<uInt32>(myDstR.y))
|
||||
{
|
||||
setDstPosInternal(x, y);
|
||||
if(setDstPosInternal(x, y))
|
||||
reinitializeBlitter();
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FBSurfaceSDL2::setDstSize(uInt32 w, uInt32 h)
|
||||
{
|
||||
if(w != static_cast<uInt32>(myDstR.w) || h != static_cast<uInt32>(myDstR.h))
|
||||
{
|
||||
setDstSizeInternal(w, h);
|
||||
if(setDstSizeInternal(w, h))
|
||||
reinitializeBlitter();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FBSurfaceSDL2::setDstRect(const Common::Rect& r)
|
||||
{
|
||||
const bool posChanged = setDstPosInternal(r.x(), r.y()),
|
||||
sizeChanged = setDstSizeInternal(r.w(), r.h());
|
||||
|
||||
if(posChanged || sizeChanged)
|
||||
reinitializeBlitter();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -176,6 +184,22 @@ void FBSurfaceSDL2::invalidate()
|
|||
SDL_FillRect(mySurface, nullptr, 0);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FBSurfaceSDL2::invalidateRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h)
|
||||
{
|
||||
ASSERT_MAIN_THREAD;
|
||||
|
||||
// Clear the rectangle
|
||||
SDL_Rect tmp;
|
||||
tmp.x = x;
|
||||
tmp.y = y;
|
||||
tmp.w = w;
|
||||
tmp.h = h;
|
||||
// Note: Transparency has to be 0 to clear the rectangle foreground
|
||||
// without affecting the background display.
|
||||
SDL_FillRect(mySurface, &tmp, 0);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FBSurfaceSDL2::free()
|
||||
{
|
||||
|
|
|
@ -48,13 +48,18 @@ class FBSurfaceSDL2 : public FBSurface
|
|||
const Common::Rect& dstRect() const override;
|
||||
void setSrcPos(uInt32 x, uInt32 y) override;
|
||||
void setSrcSize(uInt32 w, uInt32 h) override;
|
||||
void setSrcRect(const Common::Rect& r) override;
|
||||
void setDstPos(uInt32 x, uInt32 y) override;
|
||||
void setDstSize(uInt32 w, uInt32 h) override;
|
||||
void setDstRect(const Common::Rect& r) override;
|
||||
|
||||
void setVisible(bool visible) override;
|
||||
|
||||
void translateCoords(Int32& x, Int32& y) const override;
|
||||
bool render() override;
|
||||
void invalidate() override;
|
||||
void invalidateRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h) override;
|
||||
|
||||
void free() override;
|
||||
void reload() override;
|
||||
void resize(uInt32 width, uInt32 height) override;
|
||||
|
@ -65,21 +70,41 @@ class FBSurfaceSDL2 : public FBSurface
|
|||
void applyAttributes() override;
|
||||
|
||||
private:
|
||||
inline void setSrcPosInternal(uInt32 x, uInt32 y) {
|
||||
inline bool setSrcPosInternal(uInt32 x, uInt32 y) {
|
||||
if(x != static_cast<uInt32>(mySrcR.x) || y != static_cast<uInt32>(mySrcR.y))
|
||||
{
|
||||
mySrcR.x = x; mySrcR.y = y;
|
||||
mySrcGUIR.moveTo(x, y);
|
||||
return true;
|
||||
}
|
||||
inline void setSrcSizeInternal(uInt32 w, uInt32 h) {
|
||||
return false;
|
||||
}
|
||||
inline bool setSrcSizeInternal(uInt32 w, uInt32 h) {
|
||||
if(w != static_cast<uInt32>(mySrcR.w) || h != static_cast<uInt32>(mySrcR.h))
|
||||
{
|
||||
mySrcR.w = w; mySrcR.h = h;
|
||||
mySrcGUIR.setWidth(w); mySrcGUIR.setHeight(h);
|
||||
return true;
|
||||
}
|
||||
inline void setDstPosInternal(uInt32 x, uInt32 y) {
|
||||
return false;
|
||||
}
|
||||
inline bool setDstPosInternal(uInt32 x, uInt32 y) {
|
||||
if(x != static_cast<uInt32>(myDstR.x) || y != static_cast<uInt32>(myDstR.y))
|
||||
{
|
||||
myDstR.x = x; myDstR.y = y;
|
||||
myDstGUIR.moveTo(x, y);
|
||||
return true;
|
||||
}
|
||||
inline void setDstSizeInternal(uInt32 w, uInt32 h) {
|
||||
return false;
|
||||
}
|
||||
inline bool setDstSizeInternal(uInt32 w, uInt32 h) {
|
||||
if(w != static_cast<uInt32>(myDstR.w) || h != static_cast<uInt32>(myDstR.h))
|
||||
{
|
||||
myDstR.w = w; myDstR.h = h;
|
||||
myDstGUIR.setWidth(w); myDstGUIR.setHeight(h);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void createSurface(uInt32 width, uInt32 height, const uInt32* data);
|
||||
|
@ -101,7 +126,7 @@ class FBSurfaceSDL2 : public FBSurface
|
|||
{ScalingInterpolation::none};
|
||||
|
||||
SDL_Surface* mySurface{nullptr};
|
||||
SDL_Rect mySrcR{0, 0, 0, 0}, myDstR{0, 0, 0, 0};
|
||||
SDL_Rect mySrcR{-1, -1, -1, -1}, myDstR{-1, -1, -1, -1};
|
||||
|
||||
bool myIsVisible{true};
|
||||
bool myIsStatic{false};
|
||||
|
|
|
@ -267,7 +267,7 @@ void PNGLibrary::toggleContinuousSnapshots(bool perFrame)
|
|||
buf << "Enabling snapshots in " << interval << " second intervals";
|
||||
interval *= uInt32(myOSystem.frameRate());
|
||||
}
|
||||
myOSystem.frameBuffer().showMessage(buf.str());
|
||||
myOSystem.frameBuffer().showTextMessage(buf.str());
|
||||
setContinuousSnapInterval(interval);
|
||||
}
|
||||
else
|
||||
|
@ -276,7 +276,7 @@ void PNGLibrary::toggleContinuousSnapshots(bool perFrame)
|
|||
buf << "Disabling snapshots, generated "
|
||||
<< (mySnapCounter / mySnapInterval)
|
||||
<< " files";
|
||||
myOSystem.frameBuffer().showMessage(buf.str());
|
||||
myOSystem.frameBuffer().showTextMessage(buf.str());
|
||||
setContinuousSnapInterval(0);
|
||||
}
|
||||
}
|
||||
|
@ -378,7 +378,7 @@ void PNGLibrary::takeSnapshot(uInt32 number)
|
|||
// Re-enable old messages
|
||||
myOSystem.frameBuffer().enableMessages(true);
|
||||
}
|
||||
myOSystem.frameBuffer().showMessage(message);
|
||||
myOSystem.frameBuffer().showTextMessage(message);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -69,7 +69,7 @@ void PaletteHandler::cyclePalette(int direction)
|
|||
const string palette = toPaletteName(PaletteType(type));
|
||||
const string message = MESSAGES[type] + " palette";
|
||||
|
||||
myOSystem.frameBuffer().showMessage(message);
|
||||
myOSystem.frameBuffer().showTextMessage(message);
|
||||
|
||||
setPalette(palette);
|
||||
}
|
||||
|
@ -112,7 +112,7 @@ void PaletteHandler::showAdjustableMessage()
|
|||
const float value =
|
||||
myOSystem.console().timing() == ConsoleTiming::pal ? myPhasePAL : myPhaseNTSC;
|
||||
buf << std::fixed << std::setprecision(1) << value << DEGREE;
|
||||
myOSystem.frameBuffer().showMessage(
|
||||
myOSystem.frameBuffer().showGaugeMessage(
|
||||
"Palette phase shift", buf.str(), value,
|
||||
(isNTSC ? DEF_NTSC_SHIFT : DEF_PAL_SHIFT) - MAX_PHASE_SHIFT,
|
||||
(isNTSC ? DEF_NTSC_SHIFT : DEF_PAL_SHIFT) + MAX_PHASE_SHIFT);
|
||||
|
@ -122,7 +122,7 @@ void PaletteHandler::showAdjustableMessage()
|
|||
const float value = *myAdjustables[myCurrentAdjustable].value;
|
||||
|
||||
buf << std::fixed << std::setprecision(1) << value << DEGREE;
|
||||
myOSystem.frameBuffer().showMessage(
|
||||
myOSystem.frameBuffer().showGaugeMessage(
|
||||
msg.str(), buf.str(), value, -MAX_RGB_SHIFT, +MAX_RGB_SHIFT);
|
||||
}
|
||||
else
|
||||
|
@ -131,7 +131,7 @@ void PaletteHandler::showAdjustableMessage()
|
|||
? scaleRGBTo100(*myAdjustables[myCurrentAdjustable].value)
|
||||
: scaleTo100(*myAdjustables[myCurrentAdjustable].value);
|
||||
buf << value << "%";
|
||||
myOSystem.frameBuffer().showMessage(
|
||||
myOSystem.frameBuffer().showGaugeMessage(
|
||||
msg.str(), buf.str(), value);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ struct Point
|
|||
x = y = 0;
|
||||
}
|
||||
bool operator==(const Point& p) const { return x == p.x && y == p.y; }
|
||||
bool operator!=(const Point & p) const { return x != p.x || y != p.y; }
|
||||
bool operator!=(const Point& p) const { return !(*this == p); }
|
||||
|
||||
friend ostream& operator<<(ostream& os, const Point& p) {
|
||||
os << p.x << "x" << p.y;
|
||||
|
@ -75,11 +75,11 @@ struct Size
|
|||
}
|
||||
|
||||
bool operator==(const Size& s) const { return w == s.w && h == s.h; }
|
||||
bool operator!=(const Size& s) const { return w != s.w || h != s.h; }
|
||||
bool operator< (const Size& s) const { return w < s.w && h < s.h; }
|
||||
bool operator<=(const Size& s) const { return w <= s.w && h <= s.h; }
|
||||
bool operator> (const Size& s) const { return w > s.w || h > s.h; }
|
||||
bool operator>=(const Size& s) const { return w >= s.w || h >= s.h; }
|
||||
bool operator!=(const Size& s) const { return !(*this == s); }
|
||||
bool operator<=(const Size& s) const { return !(*this > s); }
|
||||
bool operator>=(const Size& s) const { return !(*this < s); }
|
||||
|
||||
friend ostream& operator<<(ostream& os, const Size& s) {
|
||||
os << s.w << "x" << s.h;
|
||||
|
@ -175,6 +175,11 @@ struct Rect
|
|||
return r.left != x || r.top != y;
|
||||
}
|
||||
|
||||
bool operator==(const Rect& r) const {
|
||||
return top == r.top && left == r.left && bottom == r.bottom && right == r.right;
|
||||
}
|
||||
bool operator!=(const Rect& r) const { return !(*this == r); }
|
||||
|
||||
friend ostream& operator<<(ostream& os, const Rect& r) {
|
||||
os << r.point() << "," << r.size();
|
||||
return os;
|
||||
|
|
|
@ -37,7 +37,6 @@ RewindManager::RewindManager(OSystem& system, StateManager& statemgr)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void RewindManager::setup()
|
||||
{
|
||||
myStateSize = 0;
|
||||
myLastTimeMachineAdd = false;
|
||||
|
||||
const string& prefix = myOSystem.settings().getBool("dev.settings") ? "dev." : "plr.";
|
||||
|
@ -138,7 +137,6 @@ bool RewindManager::addState(const string& message, bool timeMachine)
|
|||
s.rewind(); // rewind Serializer internal buffers
|
||||
if(myStateManager.saveState(s) && myOSystem.console().tia().saveDisplay(s))
|
||||
{
|
||||
myStateSize = std::max(myStateSize, uInt32(s.size()));
|
||||
state.message = message;
|
||||
state.cycles = myOSystem.console().tia().cycles();
|
||||
myLastTimeMachineAdd = timeMachine;
|
||||
|
@ -183,7 +181,7 @@ uInt32 RewindManager::rewindStates(uInt32 numStates)
|
|||
|
||||
if(myOSystem.eventHandler().state() != EventHandlerState::TIMEMACHINE
|
||||
&& myOSystem.eventHandler().state() != EventHandlerState::PLAYBACK)
|
||||
myOSystem.frameBuffer().showMessage(message);
|
||||
myOSystem.frameBuffer().showTextMessage(message);
|
||||
return i;
|
||||
}
|
||||
|
||||
|
@ -218,7 +216,7 @@ uInt32 RewindManager::unwindStates(uInt32 numStates)
|
|||
|
||||
if(myOSystem.eventHandler().state() != EventHandlerState::TIMEMACHINE
|
||||
&& myOSystem.eventHandler().state() != EventHandlerState::PLAYBACK)
|
||||
myOSystem.frameBuffer().showMessage(message);
|
||||
myOSystem.frameBuffer().showTextMessage(message);
|
||||
return i;
|
||||
}
|
||||
|
||||
|
@ -256,18 +254,22 @@ string RewindManager::saveAllStates()
|
|||
buf.str("");
|
||||
out.putString(STATE_HEADER);
|
||||
out.putShort(numStates);
|
||||
out.putInt(myStateSize);
|
||||
|
||||
unique_ptr<uInt8[]> buffer = make_unique<uInt8[]>(myStateSize);
|
||||
for (uInt32 i = 0; i < numStates; ++i)
|
||||
{
|
||||
RewindState& state = myStateList.current();
|
||||
Serializer& s = state.data;
|
||||
uInt32 stateSize = uInt32(s.size());
|
||||
unique_ptr<uInt8[]> buffer = make_unique<uInt8[]>(stateSize);
|
||||
|
||||
out.putInt(stateSize);
|
||||
|
||||
// Rewind Serializer internal buffers
|
||||
s.rewind();
|
||||
|
||||
// Save state
|
||||
s.getByteArray(buffer.get(), myStateSize);
|
||||
out.putByteArray(buffer.get(), myStateSize);
|
||||
s.getByteArray(buffer.get(), stateSize);
|
||||
out.putByteArray(buffer.get(), stateSize);
|
||||
out.putString(state.message);
|
||||
out.putLong(state.cycles);
|
||||
|
||||
|
@ -310,25 +312,27 @@ string RewindManager::loadAllStates()
|
|||
if (in.getString() != STATE_HEADER)
|
||||
return "Incompatible all states file";
|
||||
numStates = in.getShort();
|
||||
myStateSize = in.getInt();
|
||||
|
||||
unique_ptr<uInt8[]> buffer = make_unique<uInt8[]>(myStateSize);
|
||||
for (uInt32 i = 0; i < numStates; ++i)
|
||||
{
|
||||
if (myStateList.full())
|
||||
compressStates();
|
||||
|
||||
uInt32 stateSize = in.getInt();
|
||||
unique_ptr<uInt8[]> buffer = make_unique<uInt8[]>(stateSize);
|
||||
|
||||
// Add new state at the end of the list (queue adds at end)
|
||||
// This updates the 'current' iterator inside the list
|
||||
myStateList.addLast();
|
||||
RewindState& state = myStateList.current();
|
||||
Serializer& s = state.data;
|
||||
|
||||
// Rewind Serializer internal buffers
|
||||
s.rewind();
|
||||
|
||||
// Fill new state with saved values
|
||||
in.getByteArray(buffer.get(), myStateSize);
|
||||
s.putByteArray(buffer.get(), myStateSize);
|
||||
in.getByteArray(buffer.get(), stateSize);
|
||||
s.putByteArray(buffer.get(), stateSize);
|
||||
state.message = in.getString();
|
||||
state.cycles = in.getLong();
|
||||
}
|
||||
|
|
|
@ -144,7 +144,6 @@ class RewindManager
|
|||
bool atLast() const { return myStateList.atLast(); }
|
||||
void resize(uInt32 size) { myStateList.resize(size); }
|
||||
void clear() {
|
||||
myStateSize = 0;
|
||||
myStateList.clear();
|
||||
}
|
||||
|
||||
|
@ -176,7 +175,6 @@ class RewindManager
|
|||
uInt64 myHorizon{0};
|
||||
double myFactor{0.0};
|
||||
bool myLastTimeMachineAdd{false};
|
||||
uInt32 myStateSize{0};
|
||||
|
||||
struct RewindState {
|
||||
Serializer data; // actual save state
|
||||
|
|
|
@ -224,7 +224,7 @@ bool SoundSDL2::toggleMute()
|
|||
string message = "Sound ";
|
||||
message += enabled ? "unmuted" : "muted";
|
||||
|
||||
myOSystem.frameBuffer().showMessage(message);
|
||||
myOSystem.frameBuffer().showTextMessage(message);
|
||||
|
||||
//ostringstream strval;
|
||||
//uInt32 volume;
|
||||
|
@ -282,7 +282,7 @@ void SoundSDL2::adjustVolume(int direction)
|
|||
strval << percent << "%";
|
||||
else
|
||||
strval << "Off";
|
||||
myOSystem.frameBuffer().showMessage("Volume", strval.str(), percent);
|
||||
myOSystem.frameBuffer().showGaugeMessage("Volume", strval.str(), percent);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -132,9 +132,9 @@ void StateManager::toggleTimeMachine()
|
|||
|
||||
myActiveMode = myActiveMode == Mode::TimeMachine ? Mode::Off : Mode::TimeMachine;
|
||||
if(myActiveMode == Mode::TimeMachine)
|
||||
myOSystem.frameBuffer().showMessage("Time Machine enabled");
|
||||
myOSystem.frameBuffer().showTextMessage("Time Machine enabled");
|
||||
else
|
||||
myOSystem.frameBuffer().showMessage("Time Machine disabled");
|
||||
myOSystem.frameBuffer().showTextMessage("Time Machine disabled");
|
||||
myOSystem.settings().setValue(devSettings ? "dev.timemachine" : "plr.timemachine", myActiveMode == Mode::TimeMachine);
|
||||
}
|
||||
|
||||
|
@ -215,7 +215,7 @@ void StateManager::loadState(int slot)
|
|||
{
|
||||
buf.str("");
|
||||
buf << "Can't open/load from state file " << slot;
|
||||
myOSystem.frameBuffer().showMessage(buf.str());
|
||||
myOSystem.frameBuffer().showTextMessage(buf.str());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -239,7 +239,7 @@ void StateManager::loadState(int slot)
|
|||
buf << "Invalid data in state " << slot << " file";
|
||||
}
|
||||
|
||||
myOSystem.frameBuffer().showMessage(buf.str());
|
||||
myOSystem.frameBuffer().showTextMessage(buf.str());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -261,7 +261,7 @@ void StateManager::saveState(int slot)
|
|||
{
|
||||
buf.str("");
|
||||
buf << "Can't open/save to state file " << slot;
|
||||
myOSystem.frameBuffer().showMessage(buf.str());
|
||||
myOSystem.frameBuffer().showTextMessage(buf.str());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -274,7 +274,7 @@ void StateManager::saveState(int slot)
|
|||
catch(...)
|
||||
{
|
||||
buf << "Error saving state " << slot;
|
||||
myOSystem.frameBuffer().showMessage(buf.str());
|
||||
myOSystem.frameBuffer().showTextMessage(buf.str());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -292,7 +292,7 @@ void StateManager::saveState(int slot)
|
|||
else
|
||||
buf << "Error saving state " << slot;
|
||||
|
||||
myOSystem.frameBuffer().showMessage(buf.str());
|
||||
myOSystem.frameBuffer().showTextMessage(buf.str());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -307,7 +307,7 @@ void StateManager::changeState(int direction)
|
|||
buf << "Changed to state slot " << myCurrentSlot;
|
||||
else
|
||||
buf << "State slot " << myCurrentSlot;
|
||||
myOSystem.frameBuffer().showMessage(buf.str());
|
||||
myOSystem.frameBuffer().showTextMessage(buf.str());
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -318,7 +318,7 @@ void StateManager::toggleAutoSlot()
|
|||
// Print appropriate message
|
||||
ostringstream buf;
|
||||
buf << "Automatic slot change " << (autoSlot ? "enabled" : "disabled");
|
||||
myOSystem.frameBuffer().showMessage(buf.str());
|
||||
myOSystem.frameBuffer().showTextMessage(buf.str());
|
||||
|
||||
myOSystem.settings().setValue("autoslot", autoSlot);
|
||||
}
|
||||
|
|
|
@ -605,7 +605,8 @@ bool CartDebug::removeLabel(const string& label)
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool CartDebug::getLabel(ostream& buf, uInt16 addr, bool isRead, int places) const
|
||||
bool CartDebug::getLabel(ostream& buf, uInt16 addr, bool isRead,
|
||||
int places, bool isRam) const
|
||||
{
|
||||
switch(addressType(addr))
|
||||
{
|
||||
|
@ -662,21 +663,24 @@ bool CartDebug::getLabel(ostream& buf, uInt16 addr, bool isRead, int places) con
|
|||
{
|
||||
// RAM can use user-defined labels; otherwise we default to
|
||||
// standard mnemonics
|
||||
auto iter = myUserLabels.find(addr);
|
||||
if(iter != myUserLabels.end())
|
||||
{
|
||||
buf << iter->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
AddrToLabel::const_iterator iter;
|
||||
uInt16 a = addr & 0xFF, offset = addr & 0xFF00;
|
||||
if((iter = myUserLabels.find(a)) != myUserLabels.end())
|
||||
bool found = false;
|
||||
|
||||
// Search for nearest label
|
||||
for(uInt16 i = a; i >= 0x80; --i)
|
||||
if((iter = myUserLabels.find(i)) != myUserLabels.end())
|
||||
{
|
||||
buf << iter->second;
|
||||
else
|
||||
if(a != i)
|
||||
buf << "+$" << Base::HEX1 << (a - i);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
if(!found)
|
||||
buf << ourZPMnemonic[a - 0x80];
|
||||
if(offset > 0)
|
||||
buf << "|$" << Base::HEX2 << offset;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -684,12 +688,29 @@ bool CartDebug::getLabel(ostream& buf, uInt16 addr, bool isRead, int places) con
|
|||
case AddrType::ROM:
|
||||
{
|
||||
// These addresses can never be in the system labels list
|
||||
if(isRam) // cartridge RAM
|
||||
{
|
||||
AddrToLabel::const_iterator iter;
|
||||
|
||||
// Search for nearest label
|
||||
for(uInt16 i = addr; i >= (addr & 0xf000); --i)
|
||||
if((iter = myUserLabels.find(i)) != myUserLabels.end())
|
||||
{
|
||||
buf << iter->second;
|
||||
if(addr != i)
|
||||
buf << "+$" << Base::HEX1 << (addr - i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto& iter = myUserLabels.find(addr);
|
||||
if(iter != myUserLabels.end())
|
||||
{
|
||||
buf << iter->second;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -713,10 +734,10 @@ bool CartDebug::getLabel(ostream& buf, uInt16 addr, bool isRead, int places) con
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string CartDebug::getLabel(uInt16 addr, bool isRead, int places) const
|
||||
string CartDebug::getLabel(uInt16 addr, bool isRead, int places, bool isRam) const
|
||||
{
|
||||
ostringstream buf;
|
||||
getLabel(buf, addr, isRead, places);
|
||||
getLabel(buf, addr, isRead, places, isRam);
|
||||
return buf.str();
|
||||
}
|
||||
|
||||
|
|
|
@ -211,8 +211,10 @@ class CartDebug : public DebuggerSystem
|
|||
If places is not -1 and a label hasn't been defined, return a
|
||||
formatted hexidecimal address
|
||||
*/
|
||||
bool getLabel(ostream& buf, uInt16 addr, bool isRead, int places = -1) const;
|
||||
string getLabel(uInt16 addr, bool isRead, int places = -1) const;
|
||||
bool getLabel(ostream& buf, uInt16 addr, bool isRead,
|
||||
int places = -1, bool isRam = false) const;
|
||||
string getLabel(uInt16 addr, bool isRead,
|
||||
int places = -1, bool isRam = false) const;
|
||||
int getAddress(const string& label) const;
|
||||
|
||||
/**
|
||||
|
|
|
@ -118,7 +118,8 @@ FBInitStatus Debugger::initializeVideo()
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool Debugger::start(const string& message, int address, bool read)
|
||||
bool Debugger::start(const string& message, int address, bool read,
|
||||
const string& toolTip)
|
||||
{
|
||||
if(myOSystem.eventHandler().enterDebugMode())
|
||||
{
|
||||
|
@ -129,6 +130,7 @@ bool Debugger::start(const string& message, int address, bool read)
|
|||
if(address > -1)
|
||||
buf << cartDebug().getLabel(address, read, 4);
|
||||
myDialog->message().setText(buf.str());
|
||||
myDialog->message().setToolTip(toolTip);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -97,7 +97,8 @@ class Debugger : public DialogContainer
|
|||
@param message Message to display when entering debugger
|
||||
@param address An address associated with the message
|
||||
*/
|
||||
bool start(const string& message = "", int address = -1, bool read = true);
|
||||
bool start(const string& message = "", int address = -1, bool read = true,
|
||||
const string& toolTip = "");
|
||||
bool startWithFatalError(const string& message = "");
|
||||
|
||||
/**
|
||||
|
|
|
@ -1747,9 +1747,13 @@ void DebuggerParser::executeRunTo()
|
|||
// Create a progress dialog box to show the progress searching through the
|
||||
// disassembly, since this may be a time-consuming operation
|
||||
ostringstream buf;
|
||||
buf << "RunTo searching through " << max_iterations << " disassembled instructions";
|
||||
ProgressDialog progress(debugger.baseDialog(), debugger.lfont(), buf.str());
|
||||
ProgressDialog progress(debugger.baseDialog(), debugger.lfont());
|
||||
|
||||
buf << "RunTo searching through " << max_iterations << " disassembled instructions"
|
||||
<< progress.ELLIPSIS;
|
||||
progress.setMessage(buf.str());
|
||||
progress.setRange(0, max_iterations, 5);
|
||||
progress.open();
|
||||
|
||||
bool done = false;
|
||||
do {
|
||||
|
@ -1763,8 +1767,8 @@ void DebuggerParser::executeRunTo()
|
|||
done = (BSPF::findIgnoreCase(next, argStrings[0]) != string::npos);
|
||||
}
|
||||
// Update the progress bar
|
||||
progress.setProgress(count);
|
||||
} while(!done && ++count < max_iterations);
|
||||
progress.incProgress();
|
||||
} while(!done && ++count < max_iterations && !progress.isCancelled());
|
||||
|
||||
progress.close();
|
||||
|
||||
|
@ -1789,13 +1793,15 @@ void DebuggerParser::executeRunToPc()
|
|||
|
||||
uInt32 count = 0;
|
||||
bool done = false;
|
||||
constexpr uInt32 max_iterations = 1000000;
|
||||
// Create a progress dialog box to show the progress searching through the
|
||||
// disassembly, since this may be a time-consuming operation
|
||||
ostringstream buf;
|
||||
buf << "RunTo PC searching through " << max_iterations << " instructions";
|
||||
ProgressDialog progress(debugger.baseDialog(), debugger.lfont(), buf.str());
|
||||
progress.setRange(0, max_iterations, 5);
|
||||
ProgressDialog progress(debugger.baseDialog(), debugger.lfont());
|
||||
|
||||
buf << " RunTo PC running" << progress.ELLIPSIS << " ";
|
||||
progress.setMessage(buf.str());
|
||||
progress.setRange(0, 100000, 5);
|
||||
progress.open();
|
||||
|
||||
do {
|
||||
debugger.step(false);
|
||||
|
@ -1803,8 +1809,9 @@ void DebuggerParser::executeRunToPc()
|
|||
// Update romlist to point to current PC
|
||||
int pcline = cartdbg.addressToLine(debugger.cpuDebug().pc());
|
||||
done = (pcline >= 0) && (list[pcline].address == args[0]);
|
||||
progress.setProgress(count);
|
||||
} while(!done && ++count < max_iterations/*list.size()*/);
|
||||
progress.incProgress();
|
||||
++count;
|
||||
} while(!done && !progress.isCancelled());
|
||||
progress.close();
|
||||
|
||||
if(done)
|
||||
|
@ -1953,20 +1960,24 @@ void DebuggerParser::executeStepwhile()
|
|||
Expression* expr = YaccParser::getResult();
|
||||
int ncycles = 0;
|
||||
uInt32 count = 0;
|
||||
constexpr uInt32 max_iterations = 1000000;
|
||||
|
||||
// Create a progress dialog box to show the progress searching through the
|
||||
// disassembly, since this may be a time-consuming operation
|
||||
ostringstream buf;
|
||||
buf << "stepwhile running through " << max_iterations << " disassembled instructions";
|
||||
ProgressDialog progress(debugger.baseDialog(), debugger.lfont(), buf.str());
|
||||
progress.setRange(0, max_iterations, 5);
|
||||
ProgressDialog progress(debugger.baseDialog(), debugger.lfont());
|
||||
|
||||
buf << "stepwhile running through disassembled instructions"
|
||||
<< progress.ELLIPSIS;
|
||||
progress.setMessage(buf.str());
|
||||
progress.setRange(0, 100000, 5);
|
||||
progress.open();
|
||||
|
||||
do {
|
||||
ncycles += debugger.step(false);
|
||||
|
||||
progress.setProgress(count);
|
||||
} while (expr->evaluate() && ++count < max_iterations);
|
||||
progress.incProgress();
|
||||
++count;
|
||||
} while (expr->evaluate() && !progress.isCancelled());
|
||||
|
||||
progress.close();
|
||||
commandResult << "executed " << ncycles << " cycles";
|
||||
|
|
|
@ -117,7 +117,7 @@ void Cartridge3EWidget::loadConfig()
|
|||
myBankWidgets[1]->setSelectedIndex(bank - myCart.romBankCount(), oldBank != bank);
|
||||
}
|
||||
|
||||
CartDebugWidget::loadConfig();
|
||||
CartDebugWidget::loadConfig(); // Intentionally calling grand-parent method
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -392,5 +392,5 @@ uInt8 CartridgeEnhancedWidget::internalRamGetValue(int addr)
|
|||
string CartridgeEnhancedWidget::internalRamLabel(int addr)
|
||||
{
|
||||
CartDebug& dbg = instance().debugger().cartDebug();
|
||||
return dbg.getLabel(addr + ADDR_BASE + myCart.myReadOffset, false);
|
||||
return dbg.getLabel(addr + ADDR_BASE + myCart.myReadOffset, false, -1, true);
|
||||
}
|
||||
|
|
|
@ -67,11 +67,11 @@ class CartRamWidget : public Widget, public CommandSender
|
|||
int x, int y, int w, int h,
|
||||
CartDebugWidget& cartDebug);
|
||||
~InternalRamWidget() override = default;
|
||||
string getLabel(int addr) const override;
|
||||
|
||||
private:
|
||||
uInt8 getValue(int addr) const override;
|
||||
void setValue(int addr, uInt8 value) override;
|
||||
string getLabel(int addr) const override;
|
||||
|
||||
void fillList(uInt32 start, uInt32 size, IntArray& alist,
|
||||
IntArray& vlist, BoolArray& changed) const override;
|
||||
|
|
|
@ -85,18 +85,19 @@ CpuWidget::CpuWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& n
|
|||
_w = lwidth + myPCGrid->getWidth() + myPCLabel->getWidth() + 20;
|
||||
|
||||
// Create labels showing the source of data for SP/A/X/Y registers
|
||||
const std::array<string, 4> labels = { "SP", "A", "X", "Y" };
|
||||
xpos += myCpuGridBinValue->getWidth() + 20;
|
||||
int src_y = ypos, src_w = (max_w - xpos + x) - 10;
|
||||
for(int i = 0; i < 4; ++i)
|
||||
{
|
||||
myCpuDataSrc[i] = new EditTextWidget(boss, nfont, xpos, src_y, src_w, fontHeight + 1);
|
||||
myCpuDataSrc[i]->setToolTip("Source label of last read for " + labels[i] + ".");
|
||||
myCpuDataSrc[i]->setEditable(false, true);
|
||||
src_y += fontHeight + 2;
|
||||
}
|
||||
|
||||
// Add labels for other CPU registers
|
||||
xpos = x;
|
||||
const std::array<string, 4> labels = { "SP ", "A ", "X ", "Y " };
|
||||
for(int row = 0; row < 4; ++row)
|
||||
{
|
||||
new StaticTextWidget(boss, lfont, xpos, ypos + row*lineHeight + 2,
|
||||
|
@ -109,10 +110,10 @@ CpuWidget::CpuWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& n
|
|||
{
|
||||
new StaticTextWidget(boss, lfont, myCpuGridDecValue->getLeft() - fontWidth,
|
||||
ypos + row * lineHeight + 2,
|
||||
lwidth - 2, fontHeight, "#");
|
||||
fontWidth, fontHeight, "#");
|
||||
new StaticTextWidget(boss, lfont, myCpuGridBinValue->getLeft() - fontWidth,
|
||||
ypos + row * lineHeight + 2,
|
||||
lwidth - 2, fontHeight, "%");
|
||||
fontWidth, fontHeight, "%");
|
||||
}
|
||||
|
||||
// Create a bitfield widget for changing the processor status
|
||||
|
@ -139,10 +140,9 @@ CpuWidget::CpuWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& n
|
|||
xpos = myCpuDataSrc[0]->getLeft();
|
||||
new StaticTextWidget(boss, lfont, xpos - fontWidth * 4.5, ypos + 2, "Dest");
|
||||
myCpuDataDest = new EditTextWidget(boss, nfont, xpos, ypos, src_w, fontHeight + 1);
|
||||
myCpuDataDest->setToolTip("Destination label of last write.");
|
||||
myCpuDataDest->setEditable(false, true);
|
||||
|
||||
|
||||
|
||||
_h = ypos + myPSRegister->getHeight() - y;
|
||||
}
|
||||
|
||||
|
|
|
@ -33,31 +33,38 @@ DataGridOpsWidget::DataGridOpsWidget(GuiObject* boss, const GUI::Font& font,
|
|||
xpos = x; ypos = y;
|
||||
_zeroButton = new ButtonWidget(boss, font, xpos, ypos, bwidth, bheight,
|
||||
"0", kDGZeroCmd);
|
||||
_zeroButton->setToolTip("Zero currently selected value");
|
||||
|
||||
ypos += bheight + space;
|
||||
_invButton = new ButtonWidget(boss, font, xpos, ypos, bwidth, bheight,
|
||||
"Inv", kDGInvertCmd);
|
||||
_invButton->setToolTip("Invert currently selected value");
|
||||
|
||||
ypos += bheight + space;
|
||||
_incButton = new ButtonWidget(boss, font, xpos, ypos, bwidth, bheight,
|
||||
"++", kDGIncCmd);
|
||||
_incButton->setToolTip("Increase currently selected value.");
|
||||
|
||||
ypos += bheight + space;
|
||||
_shiftLeftButton = new ButtonWidget(boss, font, xpos, ypos, bwidth, bheight,
|
||||
"<<", kDGShiftLCmd);
|
||||
_shiftLeftButton->setToolTip("Shift currently selected value left");
|
||||
|
||||
// Move to next column, skip a row
|
||||
xpos = x + bwidth + space; ypos = y + bheight + space;
|
||||
_negButton = new ButtonWidget(boss, font, xpos, ypos, bwidth, bheight,
|
||||
"Neg", kDGNegateCmd);
|
||||
_negButton->setToolTip("Negate currently selected value");
|
||||
|
||||
ypos += bheight + space;
|
||||
_decButton = new ButtonWidget(boss, font, xpos, ypos, bwidth, bheight,
|
||||
"--", kDGDecCmd);
|
||||
_decButton->setToolTip("Decrease currently selected value");
|
||||
|
||||
ypos += bheight + space;
|
||||
_shiftRightButton = new ButtonWidget(boss, font, xpos, ypos, bwidth, bheight,
|
||||
">>", kDGShiftRCmd);
|
||||
_shiftRightButton->setToolTip("Shift currently selected value right");
|
||||
|
||||
// Calculate real dimensions
|
||||
_w = 2 * (bwidth+space);
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
//============================================================================
|
||||
//
|
||||
// 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-2020 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.
|
||||
//============================================================================
|
||||
|
||||
#include "RamWidget.hxx"
|
||||
#include "DataGridRamWidget.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
DataGridRamWidget::DataGridRamWidget(GuiObject* boss, const RamWidget& ram,
|
||||
const GUI::Font& font,
|
||||
int x, int y, int cols, int rows,
|
||||
int colchars, int bits,
|
||||
Common::Base::Fmt base,
|
||||
bool useScrollbar)
|
||||
: DataGridWidget(boss, font, x, y, cols, rows, colchars,
|
||||
bits, base, useScrollbar),
|
||||
_ram(ram)
|
||||
{
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string DataGridRamWidget::getToolTip(const Common::Point& pos) const
|
||||
{
|
||||
const int idx = getToolTipIndex(pos);
|
||||
|
||||
if(idx < 0)
|
||||
return EmptyString;
|
||||
|
||||
const Int32 addr = _addrList[idx];
|
||||
const string label = _ram.getLabel(addr);
|
||||
const string tip = DataGridWidget::getToolTip(pos);
|
||||
|
||||
if(label.empty())
|
||||
return tip;
|
||||
|
||||
ostringstream buf;
|
||||
|
||||
buf << label << '\n' << tip;
|
||||
|
||||
return buf.str();
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
//============================================================================
|
||||
//
|
||||
// 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-2020 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.
|
||||
//============================================================================
|
||||
|
||||
#ifndef DATA_GRID_RAM_WIDGET_HXX
|
||||
#define DATA_GRID_RAM_WIDGET_HXX
|
||||
|
||||
class RamWidget;
|
||||
|
||||
#include "DataGridWidget.hxx"
|
||||
#include "Base.hxx"
|
||||
|
||||
class DataGridRamWidget : public DataGridWidget
|
||||
{
|
||||
public:
|
||||
DataGridRamWidget(GuiObject* boss, const RamWidget& ram,
|
||||
const GUI::Font& font,
|
||||
int x, int y, int cols, int rows,
|
||||
int colchars, int bits,
|
||||
Common::Base::Fmt format = Common::Base::Fmt::_DEFAULT,
|
||||
bool useScrollbar = false);
|
||||
~DataGridRamWidget() override = default;
|
||||
|
||||
string getToolTip(const Common::Point& pos) const override;
|
||||
|
||||
private:
|
||||
const RamWidget& _ram;
|
||||
|
||||
private:
|
||||
// Following constructors and assignment operators not supported
|
||||
DataGridRamWidget() = delete;
|
||||
DataGridRamWidget(const DataGridRamWidget&) = delete;
|
||||
DataGridRamWidget(DataGridRamWidget&&) = delete;
|
||||
DataGridRamWidget& operator=(const DataGridRamWidget&) = delete;
|
||||
DataGridRamWidget& operator=(DataGridRamWidget&&) = delete;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "Widget.hxx"
|
||||
#include "Dialog.hxx"
|
||||
#include "ToolTip.hxx"
|
||||
#include "Font.hxx"
|
||||
#include "OSystem.hxx"
|
||||
#include "Debugger.hxx"
|
||||
|
@ -45,6 +46,7 @@ DataGridWidget::DataGridWidget(GuiObject* boss, const GUI::Font& font,
|
|||
_base(base)
|
||||
{
|
||||
_flags = Widget::FLAG_ENABLED | Widget::FLAG_RETAIN_FOCUS | Widget::FLAG_WANTS_RAWDATA;
|
||||
_editMode = false;
|
||||
|
||||
// Make sure all lists contain some default values
|
||||
_hiliteList.clear();
|
||||
|
@ -114,6 +116,12 @@ cerr << "alist.size() = " << alist.size()
|
|||
int size = int(vlist.size()); // assume the alist is the same size
|
||||
assert(size == _rows * _cols);
|
||||
|
||||
bool dirty = _editMode
|
||||
|| !std::equal(_valueList.begin(), _valueList.end(),
|
||||
vlist.begin(), vlist.end())
|
||||
|| !std::equal(_changedList.begin(), _changedList.end(),
|
||||
changed.begin(), changed.end());
|
||||
|
||||
_addrList.clear();
|
||||
_valueList.clear();
|
||||
_valueStringList.clear();
|
||||
|
@ -137,11 +145,14 @@ cerr << "_addrList.size() = " << _addrList.size()
|
|||
*/
|
||||
enableEditMode(false);
|
||||
|
||||
if(dirty)
|
||||
{
|
||||
// Send item selected signal for starting with cell 0
|
||||
sendCommand(DataGridWidget::kSelectionChangedCmd, _selectedItem, _id);
|
||||
|
||||
setDirty();
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void DataGridWidget::setList(int a, int v, bool c)
|
||||
|
@ -239,20 +250,6 @@ void DataGridWidget::setRange(int lower, int upper)
|
|||
_upperBound = std::min(1 << _bits, upper);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void DataGridWidget::handleMouseEntered()
|
||||
{
|
||||
setFlags(Widget::FLAG_HILITED);
|
||||
setDirty();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void DataGridWidget::handleMouseLeft()
|
||||
{
|
||||
clearFlags(Widget::FLAG_HILITED);
|
||||
setDirty();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void DataGridWidget::handleMouseDown(int x, int y, MouseButton b, int clickCount)
|
||||
{
|
||||
|
@ -307,6 +304,7 @@ void DataGridWidget::handleMouseWheel(int x, int y, int direction)
|
|||
else if(direction < 0)
|
||||
incrementCell();
|
||||
}
|
||||
dialog().tooltip().hide();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -504,6 +502,7 @@ bool DataGridWidget::handleKeyDown(StellaKey key, StellaMod mod)
|
|||
sendCommand(DataGridWidget::kSelectionChangedCmd, _selectedItem, _id);
|
||||
|
||||
setDirty();
|
||||
dialog().tooltip().hide();
|
||||
}
|
||||
|
||||
_currentKeyDown = key;
|
||||
|
@ -583,14 +582,56 @@ void DataGridWidget::handleCommand(CommandSender* sender, int cmd,
|
|||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
int DataGridWidget::getToolTipIndex(const Common::Point& pos) const
|
||||
{
|
||||
const int col = (pos.x - getAbsX()) / _colWidth;
|
||||
const int row = (pos.y - getAbsY()) / _rowHeight;
|
||||
|
||||
if(row >= 0 && row < _rows && col >= 0 && col < _cols)
|
||||
return row * _cols + col;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string DataGridWidget::getToolTip(const Common::Point& pos) const
|
||||
{
|
||||
const int idx = getToolTipIndex(pos);
|
||||
|
||||
if(idx < 0)
|
||||
return EmptyString;
|
||||
|
||||
const Int32 val = _valueList[idx];
|
||||
ostringstream buf;
|
||||
|
||||
buf << _toolTipText
|
||||
<< "$" << Common::Base::toString(val, Common::Base::Fmt::_16)
|
||||
<< " = #" << val;
|
||||
if(val < 0x100)
|
||||
{
|
||||
if(val >= 0x80)
|
||||
buf << '/' << -(0x100 - val);
|
||||
buf << " = %" << Common::Base::toString(val, Common::Base::Fmt::_2);
|
||||
}
|
||||
|
||||
return buf.str();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool DataGridWidget::changedToolTip(const Common::Point& oldPos,
|
||||
const Common::Point& newPos) const
|
||||
{
|
||||
return getToolTipIndex(oldPos) != getToolTipIndex(newPos);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void DataGridWidget::drawWidget(bool hilite)
|
||||
{
|
||||
FBSurface& s = _boss->dialog().surface();
|
||||
bool onTop = _boss->dialog().isOnTop();
|
||||
int row, col;
|
||||
|
||||
s.fillRect(_x, _y, _w, _h, hilite && isEnabled() && isEditable() ? _bgcolorhi : onTop ? _bgcolor : kBGColorHi);
|
||||
s.fillRect(_x, _y, _w, _h, hilite && isEnabled() && isEditable() ? _bgcolorhi : _bgcolor);
|
||||
// Draw the internal grid and labels
|
||||
int linewidth = _cols * _colWidth;
|
||||
s.frameRect(_x, _y, _w, _h, hilite && isEnabled() && isEditable() ? kWidColorHi : kColor);
|
||||
|
@ -609,7 +650,7 @@ void DataGridWidget::drawWidget(bool hilite)
|
|||
int x = _x + 4 + (col * _colWidth);
|
||||
int y = _y + 2 + (row * _rowHeight);
|
||||
int pos = row*_cols + col;
|
||||
ColorId textColor = onTop ? kTextColor : kColor;
|
||||
ColorId textColor = kTextColor;
|
||||
|
||||
// Draw the selected item inverted, on a highlighted background.
|
||||
if (_currentRow == row && _currentCol == col &&
|
||||
|
@ -629,13 +670,12 @@ void DataGridWidget::drawWidget(bool hilite)
|
|||
{
|
||||
if(_changedList[pos])
|
||||
{
|
||||
s.fillRect(x - 3, y - 1, _colWidth-1, _rowHeight-1,
|
||||
onTop ? kDbgChangedColor : _bgcolorlo);
|
||||
s.fillRect(x - 3, y - 1, _colWidth-1, _rowHeight-1, kDbgChangedColor);
|
||||
|
||||
if(_hiliteList[pos])
|
||||
textColor = kDbgColorHi;
|
||||
else
|
||||
textColor = onTop ? kDbgChangedTextColor : textColor;
|
||||
textColor = kDbgChangedTextColor;
|
||||
}
|
||||
else if(_hiliteList[pos])
|
||||
textColor = kDbgColorHi;
|
||||
|
@ -677,11 +717,22 @@ int DataGridWidget::getWidth() const
|
|||
return _w + (_scrollBar ? ScrollBarWidget::scrollBarWidth(_font) : 0);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void DataGridWidget::setCrossed(bool enable)
|
||||
{
|
||||
if(_crossGrid != enable)
|
||||
{
|
||||
_crossGrid = enable;
|
||||
setDirty();
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void DataGridWidget::startEditMode()
|
||||
{
|
||||
if (isEditable() && !_editMode && _selectedItem >= 0)
|
||||
{
|
||||
dialog().tooltip().hide();
|
||||
enableEditMode(true);
|
||||
setText("", true); // Erase current entry when starting editing
|
||||
}
|
||||
|
|
|
@ -82,7 +82,10 @@ class DataGridWidget : public EditableWidget
|
|||
|
||||
void setOpsWidget(DataGridOpsWidget* w) { _opsWidget = w; }
|
||||
|
||||
void setCrossed(bool enable) { _crossGrid = enable; }
|
||||
void setCrossed(bool enable);
|
||||
|
||||
string getToolTip(const Common::Point& pos) const override;
|
||||
bool changedToolTip(const Common::Point& oldPos, const Common::Point& newPos) const override;
|
||||
|
||||
protected:
|
||||
void drawWidget(bool hilite) override;
|
||||
|
@ -98,11 +101,12 @@ class DataGridWidget : public EditableWidget
|
|||
void receivedFocusWidget() override;
|
||||
void lostFocusWidget() override;
|
||||
|
||||
bool hasToolTip() const override { return true; }
|
||||
int getToolTipIndex(const Common::Point& pos) const;
|
||||
|
||||
void handleMouseDown(int x, int y, MouseButton b, int clickCount) override;
|
||||
void handleMouseUp(int x, int y, MouseButton b, int clickCount) override;
|
||||
void handleMouseWheel(int x, int y, int direction) override;
|
||||
void handleMouseEntered() override;
|
||||
void handleMouseLeft() override;
|
||||
bool handleText(char text) override;
|
||||
bool handleKeyDown(StellaKey key, StellaMod mod) override;
|
||||
bool handleKeyUp(StellaKey key, StellaMod mod) override;
|
||||
|
@ -128,7 +132,6 @@ class DataGridWidget : public EditableWidget
|
|||
BoolArray _changedList;
|
||||
BoolArray _hiliteList;
|
||||
|
||||
bool _editMode{false};
|
||||
int _selectedItem{0};
|
||||
StellaKey _currentKeyDown{KBDK_UNKNOWN};
|
||||
string _backupString;
|
||||
|
@ -148,6 +151,7 @@ class DataGridWidget : public EditableWidget
|
|||
|
||||
void enableEditMode(bool state) { _editMode = state; }
|
||||
|
||||
|
||||
private:
|
||||
// Following constructors and assignment operators not supported
|
||||
DataGridWidget() = delete;
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "Cart.hxx"
|
||||
#include "Widget.hxx"
|
||||
#include "Dialog.hxx"
|
||||
#include "ToolTip.hxx"
|
||||
#include "Settings.hxx"
|
||||
#include "StellaKeys.hxx"
|
||||
#include "EventHandler.hxx"
|
||||
|
@ -93,6 +94,7 @@ void DebuggerDialog::loadConfig()
|
|||
myRomTab->loadConfig();
|
||||
|
||||
myMessageBox->setText("");
|
||||
myMessageBox->setToolTip("");
|
||||
}
|
||||
|
||||
void DebuggerDialog::saveConfig()
|
||||
|
@ -270,84 +272,72 @@ void DebuggerDialog::handleCommand(CommandSender* sender, int cmd,
|
|||
void DebuggerDialog::doStep()
|
||||
{
|
||||
instance().debugger().parser().run("step");
|
||||
setDirty();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void DebuggerDialog::doTrace()
|
||||
{
|
||||
instance().debugger().parser().run("trace");
|
||||
setDirty();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void DebuggerDialog::doAdvance()
|
||||
{
|
||||
instance().debugger().parser().run("frame #1");
|
||||
setDirty();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void DebuggerDialog::doScanlineAdvance()
|
||||
{
|
||||
instance().debugger().parser().run("scanline #1");
|
||||
setDirty();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void DebuggerDialog::doRewind()
|
||||
{
|
||||
instance().debugger().parser().run("rewind");
|
||||
setDirty();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void DebuggerDialog::doUnwind()
|
||||
{
|
||||
instance().debugger().parser().run("unwind");
|
||||
setDirty();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void DebuggerDialog::doRewind10()
|
||||
{
|
||||
instance().debugger().parser().run("rewind #10");
|
||||
setDirty();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void DebuggerDialog::doUnwind10()
|
||||
{
|
||||
instance().debugger().parser().run("unwind #10");
|
||||
setDirty();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void DebuggerDialog::doRewindAll()
|
||||
{
|
||||
instance().debugger().parser().run("rewind #1000");
|
||||
setDirty();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void DebuggerDialog::doUnwindAll()
|
||||
{
|
||||
instance().debugger().parser().run("unwind #1000");
|
||||
setDirty();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void DebuggerDialog::doExitDebugger()
|
||||
{
|
||||
instance().debugger().parser().run("run");
|
||||
setDirty();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void DebuggerDialog::doExitRom()
|
||||
{
|
||||
instance().debugger().parser().run("exitrom");
|
||||
setDirty();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -406,6 +396,7 @@ void DebuggerDialog::createFont()
|
|||
break;
|
||||
}
|
||||
}
|
||||
tooltip().setFont(*myNFont);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -76,7 +76,7 @@ class DebuggerDialog : public Dialog
|
|||
void saveConfig() override;
|
||||
|
||||
private:
|
||||
void center() override { positionAt(0); }
|
||||
void setPosition() override { positionAt(0); }
|
||||
void loadConfig() override;
|
||||
void handleKeyDown(StellaKey key, StellaMod mod, bool repeated) override;
|
||||
void handleCommand(CommandSender* sender, int cmd, int data, int id) override;
|
||||
|
|
|
@ -50,7 +50,11 @@ void DelayQueueWidget::loadConfig() {
|
|||
using Common::Base;
|
||||
for (auto&& line : myLines) {
|
||||
if (!delayQueueIterator->isValid()) {
|
||||
if(line != "")
|
||||
{
|
||||
setDirty();
|
||||
line = "";
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -81,7 +85,11 @@ void DelayQueueWidget::loadConfig() {
|
|||
break;
|
||||
}
|
||||
|
||||
if(line != ss.str())
|
||||
{
|
||||
setDirty();
|
||||
line = ss.str();
|
||||
}
|
||||
delayQueueIterator->next();
|
||||
}
|
||||
}
|
||||
|
@ -90,7 +98,6 @@ void DelayQueueWidget::loadConfig() {
|
|||
void DelayQueueWidget::drawWidget(bool hilite)
|
||||
{
|
||||
FBSurface& surface = _boss->dialog().surface();
|
||||
bool onTop = _boss->dialog().isOnTop();
|
||||
|
||||
int y = _y,
|
||||
x = _x,
|
||||
|
@ -102,14 +109,14 @@ void DelayQueueWidget::drawWidget(bool hilite)
|
|||
y += 1;
|
||||
x += 1;
|
||||
w -= 1;
|
||||
surface.fillRect(x, y, w - 1, _h - 2, onTop ? kDlgColor : _bgcolorlo);
|
||||
surface.fillRect(x, y, w - 1, _h - 2, kDlgColor);
|
||||
|
||||
y += 2;
|
||||
x += 2;
|
||||
w -= 3;
|
||||
|
||||
for (const auto& line : myLines) {
|
||||
surface.drawString(_font, line, x, y, w, onTop ? _textcolor : kColor);
|
||||
surface.drawString(_font, line, x, y, w, _textcolor);
|
||||
y += lineHeight;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,9 +81,7 @@ void PromptWidget::drawWidget(bool hilite)
|
|||
{
|
||||
//cerr << "PromptWidget::drawWidget\n";
|
||||
ColorId fgcolor, bgcolor;
|
||||
|
||||
FBSurface& s = _boss->dialog().surface();
|
||||
bool onTop = _boss->dialog().isOnTop();
|
||||
|
||||
// Draw text
|
||||
int start = _scrollLine - _linesPerPage + 1;
|
||||
|
@ -104,7 +102,7 @@ void PromptWidget::drawWidget(bool hilite)
|
|||
else
|
||||
fgcolor = ColorId(c >> 8);
|
||||
|
||||
s.drawChar(_font, c & 0x7f, x, y, onTop ? fgcolor : kColor);
|
||||
s.drawChar(_font, c & 0x7f, x, y, fgcolor);
|
||||
x += _kConsoleCharWidth;
|
||||
}
|
||||
y += _kConsoleLineHeight;
|
||||
|
@ -938,8 +936,6 @@ void PromptWidget::drawCaret()
|
|||
{
|
||||
//cerr << "PromptWidget::drawCaret()\n";
|
||||
FBSurface& s = _boss->dialog().surface();
|
||||
bool onTop = _boss->dialog().isOnTop();
|
||||
|
||||
int line = _currentPos / _lineWidth;
|
||||
|
||||
// Don't draw the cursor if it's not in the current view
|
||||
|
@ -951,7 +947,7 @@ void PromptWidget::drawCaret()
|
|||
int y = _y + displayLine * _kConsoleLineHeight;
|
||||
|
||||
char c = buffer(_currentPos); //FIXME: int to char??
|
||||
s.fillRect(x, y, _kConsoleCharWidth, _kConsoleLineHeight, onTop ? kTextColor : kColor);
|
||||
s.fillRect(x, y, _kConsoleCharWidth, _kConsoleLineHeight, kTextColor);
|
||||
s.drawChar(_font, c, x, y + 2, kBGColor);
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#include "DataGridWidget.hxx"
|
||||
#include "DataGridRamWidget.hxx"
|
||||
#include "EditTextWidget.hxx"
|
||||
#include "GuiObject.hxx"
|
||||
#include "InputTextDialog.hxx"
|
||||
|
@ -54,7 +54,7 @@ RamWidget::RamWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& n
|
|||
// Add RAM grid (with scrollbar)
|
||||
int xpos = x + _font.getStringWidth("xxxx");
|
||||
bool useScrollbar = ramsize / numrows > 16;
|
||||
myRamGrid = new DataGridWidget(_boss, _nfont, xpos, ypos,
|
||||
myRamGrid = new DataGridRamWidget(_boss, *this, _nfont, xpos, ypos,
|
||||
16, myNumRows, 2, 8, Common::Base::Fmt::_16, useScrollbar);
|
||||
myRamGrid->setTarget(this);
|
||||
myRamGrid->setID(kRamGridID);
|
||||
|
@ -78,18 +78,21 @@ RamWidget::RamWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& n
|
|||
by += bheight + VGAP * 6;
|
||||
mySearchButton = new ButtonWidget(boss, lfont, bx, by, bwidth, bheight,
|
||||
"Search" + ELLIPSIS, kSearchCmd);
|
||||
mySearchButton->setToolTip("Search and highlight found values.");
|
||||
wid.push_back(mySearchButton);
|
||||
mySearchButton->setTarget(this);
|
||||
|
||||
by += bheight + VGAP;
|
||||
myCompareButton = new ButtonWidget(boss, lfont, bx, by, bwidth, bheight,
|
||||
"Compare" + ELLIPSIS, kCmpCmd);
|
||||
myCompareButton->setToolTip("Compare highlighted values.");
|
||||
wid.push_back(myCompareButton);
|
||||
myCompareButton->setTarget(this);
|
||||
|
||||
by += bheight + VGAP;
|
||||
myRestartButton = new ButtonWidget(boss, lfont, bx, by, bwidth, bheight,
|
||||
"Reset", kRestartCmd);
|
||||
myRestartButton->setToolTip("Reset search/compare mode.");
|
||||
wid.push_back(myRestartButton);
|
||||
myRestartButton->setTarget(this);
|
||||
|
||||
|
@ -366,6 +369,9 @@ void RamWidget::showInputBox(int cmd)
|
|||
myInputBox->show(x, y, dialog().surface().dstRect());
|
||||
myInputBox->setText("");
|
||||
myInputBox->setMessage("");
|
||||
myInputBox->setToolTip(cmd == kSValEntered
|
||||
? "Enter search value (leave blank for all)."
|
||||
: "Enter relative or absolute value\nto compare with searched values.");
|
||||
myInputBox->setFocus(0);
|
||||
myInputBox->setEmitSignal(cmd);
|
||||
myInputBox->setTitle(cmd == kSValEntered ? "Search" : "Compare");
|
||||
|
|
|
@ -22,6 +22,7 @@ class GuiObject;
|
|||
class ButtonWidget;
|
||||
class DataGridWidget;
|
||||
class DataGridOpsWidget;
|
||||
class DataGridRamWidget;
|
||||
class EditTextWidget;
|
||||
class StaticTextWidget;
|
||||
class InputTextDialog;
|
||||
|
@ -41,11 +42,12 @@ class RamWidget : public Widget, public CommandSender
|
|||
void setOpsWidget(DataGridOpsWidget* w);
|
||||
void handleCommand(CommandSender* sender, int cmd, int data, int id) override;
|
||||
|
||||
virtual string getLabel(int addr) const = 0;
|
||||
|
||||
private:
|
||||
// To be implemented by derived classes
|
||||
virtual uInt8 getValue(int addr) const = 0;
|
||||
virtual void setValue(int addr, uInt8 value) = 0;
|
||||
virtual string getLabel(int addr) const = 0;
|
||||
|
||||
virtual void fillList(uInt32 start, uInt32 size,
|
||||
IntArray& alist, IntArray& vlist,
|
||||
|
@ -97,7 +99,7 @@ class RamWidget : public Widget, public CommandSender
|
|||
StaticTextWidget* myRamStart{nullptr};
|
||||
std::array<StaticTextWidget*, 16> myRamLabels{nullptr};
|
||||
|
||||
DataGridWidget* myRamGrid{nullptr};
|
||||
DataGridRamWidget* myRamGrid{nullptr};
|
||||
DataGridWidget* myHexValue{nullptr};
|
||||
DataGridWidget* myDecValue{nullptr};
|
||||
DataGridWidget* myBinValue{nullptr};
|
||||
|
|
|
@ -36,10 +36,11 @@ class RiotRamWidget : public RamWidget
|
|||
int x, int y, int w);
|
||||
~RiotRamWidget() override = default;
|
||||
|
||||
string getLabel(int addr) const override;
|
||||
|
||||
private:
|
||||
uInt8 getValue(int addr) const override;
|
||||
void setValue(int addr, uInt8 value) override;
|
||||
string getLabel(int addr) const override;
|
||||
|
||||
void fillList(uInt32 start, uInt32 size, IntArray& alist,
|
||||
IntArray& vlist, BoolArray& changed) const override;
|
||||
|
|
|
@ -66,11 +66,13 @@ RiotWidget::RiotWidget(GuiObject* boss, const GUI::Font& lfont,
|
|||
on.push_back("1");
|
||||
}
|
||||
|
||||
StringList labels;
|
||||
|
||||
#define CREATE_IO_REGS(desc, bits, bitsID, editable) \
|
||||
t = new StaticTextWidget(boss, lfont, xpos, ypos+2, lwidth, fontHeight,\
|
||||
desc, TextAlign::Left); \
|
||||
desc); \
|
||||
xpos += t->getWidth() + 5; \
|
||||
bits = new ToggleBitWidget(boss, nfont, xpos, ypos, 8, 1); \
|
||||
bits = new ToggleBitWidget(boss, nfont, xpos, ypos, 8, 1, 1, labels); \
|
||||
bits->setTarget(this); \
|
||||
bits->setID(bitsID); \
|
||||
if(editable) addFocusWidget(bits); else bits->setEditable(false); \
|
||||
|
@ -78,6 +80,7 @@ RiotWidget::RiotWidget(GuiObject* boss, const GUI::Font& lfont,
|
|||
bits->setList(off, on);
|
||||
|
||||
// SWCHA bits in 'poke' mode
|
||||
labels.clear();
|
||||
CREATE_IO_REGS("SWCHA(W)", mySWCHAWriteBits, kSWCHABitsID, true)
|
||||
col = xpos + 20; // remember this for adding widgets to the second column
|
||||
|
||||
|
@ -87,10 +90,20 @@ RiotWidget::RiotWidget(GuiObject* boss, const GUI::Font& lfont,
|
|||
|
||||
// SWCHA bits in 'peek' mode
|
||||
xpos = 10; ypos += lineHeight + 5;
|
||||
labels.clear();
|
||||
labels.push_back("P0 right");
|
||||
labels.push_back("P0 left");
|
||||
labels.push_back("P0 down");
|
||||
labels.push_back("P0 up");
|
||||
labels.push_back("P1 right");
|
||||
labels.push_back("P1 left");
|
||||
labels.push_back("P1 down");
|
||||
labels.push_back("P1 up");
|
||||
CREATE_IO_REGS("SWCHA(R)", mySWCHAReadBits, kSWCHARBitsID, true)
|
||||
|
||||
// SWCHB bits in 'poke' mode
|
||||
xpos = 10; ypos += 2 * lineHeight;
|
||||
labels.clear();
|
||||
CREATE_IO_REGS("SWCHB(W)", mySWCHBWriteBits, kSWCHBBitsID, true)
|
||||
|
||||
// SWBCNT bits
|
||||
|
@ -99,6 +112,15 @@ RiotWidget::RiotWidget(GuiObject* boss, const GUI::Font& lfont,
|
|||
|
||||
// SWCHB bits in 'peek' mode
|
||||
xpos = 10; ypos += lineHeight + 5;
|
||||
labels.clear();
|
||||
labels.push_back("P1 difficulty");
|
||||
labels.push_back("P0 difficulty");
|
||||
labels.push_back("");
|
||||
labels.push_back("");
|
||||
labels.push_back("Color/B+W");
|
||||
labels.push_back("");
|
||||
labels.push_back("Select");
|
||||
labels.push_back("Reset");
|
||||
CREATE_IO_REGS("SWCHB(R)", mySWCHBReadBits, kSWCHBRBitsID, true)
|
||||
|
||||
// Timer registers (R/W)
|
||||
|
|
|
@ -100,7 +100,7 @@ void RomListSettings::show(uInt32 x, uInt32 y, const Common::Rect& bossRect, int
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void RomListSettings::center()
|
||||
void RomListSettings::setPosition()
|
||||
{
|
||||
// First set position according to original coordinates
|
||||
surface().setDstPos(_xorig, _yorig);
|
||||
|
|
|
@ -38,8 +38,8 @@ class RomListSettings : public Dialog, public CommandSender
|
|||
('data' will be the currently selected line number in RomListWidget) */
|
||||
void show(uInt32 x, uInt32 y, const Common::Rect& bossRect, int data = -1);
|
||||
|
||||
/** This dialog uses its own positioning, so we override Dialog::center() */
|
||||
void center() override;
|
||||
/** This dialog uses its own positioning, so we override Dialog::setPosition() */
|
||||
void setPosition() override;
|
||||
|
||||
private:
|
||||
uInt32 _xorig{0}, _yorig{0};
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
#include "Debugger.hxx"
|
||||
#include "DiStella.hxx"
|
||||
#include "Widget.hxx"
|
||||
#include "Dialog.hxx"
|
||||
#include "ToolTip.hxx"
|
||||
#include "StellaKeys.hxx"
|
||||
#include "FBSurface.hxx"
|
||||
#include "Font.hxx"
|
||||
|
@ -39,6 +41,9 @@ RomListWidget::RomListWidget(GuiObject* boss, const GUI::Font& lfont,
|
|||
_textcolor = kTextColor;
|
||||
_textcolorhi = kTextColor;
|
||||
|
||||
_editMode = false;
|
||||
_dyText = -1; // fixes the vertical position of selected text
|
||||
|
||||
_cols = w / _fontWidth;
|
||||
_rows = h / _lineHeight;
|
||||
|
||||
|
@ -242,6 +247,7 @@ void RomListWidget::handleMouseDown(int x, int y, MouseButton b, int clickCount)
|
|||
// Set selected and add menu at current x,y mouse location
|
||||
_selectedItem = findItem(x, y);
|
||||
scrollToSelected();
|
||||
dialog().tooltip().hide();
|
||||
myMenu->show(x + getAbsX(), y + getAbsY(),
|
||||
dialog().surface().dstRect(), _selectedItem);
|
||||
}
|
||||
|
@ -282,20 +288,6 @@ void RomListWidget::handleMouseWheel(int x, int y, int direction)
|
|||
myScrollBar->handleMouseWheel(x, y, direction);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void RomListWidget::handleMouseEntered()
|
||||
{
|
||||
setFlags(Widget::FLAG_HILITED);
|
||||
setDirty();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void RomListWidget::handleMouseLeft()
|
||||
{
|
||||
clearFlags(Widget::FLAG_HILITED);
|
||||
setDirty();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool RomListWidget::handleText(char text)
|
||||
{
|
||||
|
@ -454,14 +446,86 @@ void RomListWidget::lostFocusWidget()
|
|||
abortEditMode();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Common::Point RomListWidget::getToolTipIndex(const Common::Point& pos) const
|
||||
{
|
||||
const Common::Rect& r = getEditRect();
|
||||
const int col = (pos.x - r.x() - getAbsX()) / _font.getMaxCharWidth();
|
||||
const int row = (pos.y - getAbsY()) / _lineHeight;
|
||||
|
||||
if(col < 0 || col >= 8
|
||||
|| row < 0 || row + _currentPos >= int(myDisasm->list.size()))
|
||||
return Common::Point(-1, -1);
|
||||
else
|
||||
return Common::Point(col, row + _currentPos);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string RomListWidget::getToolTip(const Common::Point& pos) const
|
||||
{
|
||||
const Common::Point& idx = getToolTipIndex(pos);
|
||||
|
||||
if(idx.y < 0)
|
||||
return EmptyString;
|
||||
|
||||
const string bytes = myDisasm->list[idx.y].bytes;
|
||||
|
||||
if(static_cast<Int32>(bytes.length()) < idx.x + 1)
|
||||
return EmptyString;
|
||||
|
||||
Int32 val;
|
||||
if(bytes.length() == 8 && bytes[2] != ' ')
|
||||
{
|
||||
// Binary value
|
||||
val = static_cast<Int32>(stol(bytes, nullptr, 2));
|
||||
}
|
||||
else
|
||||
{
|
||||
// 1..3 hex values
|
||||
if(idx.x == 2)
|
||||
// Skip gap after first byte
|
||||
return EmptyString;
|
||||
|
||||
string valStr;
|
||||
|
||||
if(idx.x < 2 || bytes.length() < 8)
|
||||
// 1 or 2 hex bytes, get one hex byte
|
||||
valStr = bytes.substr((idx.x / 3) * 3, 2);
|
||||
else
|
||||
// 3 hex bytes, get two rightmost hex bytes
|
||||
valStr = bytes.substr(6, 2) + bytes.substr(3, 2);
|
||||
|
||||
val = static_cast<Int32>(stol(valStr, nullptr, 16));
|
||||
}
|
||||
ostringstream buf;
|
||||
|
||||
buf << _toolTipText
|
||||
<< "$" << Common::Base::toString(val, Common::Base::Fmt::_16)
|
||||
<< " = #" << val;
|
||||
if(val < 0x100)
|
||||
{
|
||||
if(val >= 0x80)
|
||||
buf << '/' << -(0x100 - val);
|
||||
buf << " = %" << Common::Base::toString(val, Common::Base::Fmt::_2);
|
||||
}
|
||||
|
||||
return buf.str();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool RomListWidget::changedToolTip(const Common::Point& oldPos,
|
||||
const Common::Point& newPos) const
|
||||
{
|
||||
return getToolTipIndex(oldPos) != getToolTipIndex(newPos);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void RomListWidget::drawWidget(bool hilite)
|
||||
{
|
||||
FBSurface& s = _boss->dialog().surface();
|
||||
bool onTop = _boss->dialog().isOnTop();
|
||||
const CartDebug::DisassemblyList& dlist = myDisasm->list;
|
||||
int i, pos, xpos, ypos, len = int(dlist.size());
|
||||
ColorId textColor = onTop ? kTextColor : kColor;
|
||||
ColorId textColor = kTextColor;
|
||||
|
||||
const Common::Rect& r = getEditRect();
|
||||
const Common::Rect& l = getLineRect();
|
||||
|
@ -484,17 +548,18 @@ void RomListWidget::drawWidget(bool hilite)
|
|||
{
|
||||
ColorId bytesColor = textColor;
|
||||
|
||||
// Draw checkboxes for correct lines (takes scrolling into account)
|
||||
// Mark checkboxes dirty for correct lines (takes scrolling into account)
|
||||
myCheckList[i]->setState(instance().debugger().
|
||||
checkBreakPoint(dlist[pos].address,
|
||||
instance().debugger().cartDebug().getBank(dlist[pos].address)));
|
||||
|
||||
myCheckList[i]->setDirty();
|
||||
// All checkboxes have to be redrawn because RomListWidget clears its whole area
|
||||
// Also draw immediately, because chain order is not deterministic
|
||||
myCheckList[i]->draw();
|
||||
|
||||
// Draw highlighted item in a frame
|
||||
if(_highlightedItem == pos)
|
||||
s.frameRect(_x + l.x() - 3, ypos - 1, _w - l.x(), _lineHeight, onTop ? kWidColorHi : kBGColorLo);
|
||||
s.frameRect(_x + l.x() - 3, ypos - 1, _w - l.x(), _lineHeight, kWidColorHi);
|
||||
|
||||
// Draw the selected item inverted, on a highlighted background.
|
||||
if(_selectedItem == pos && _hasFocus)
|
||||
|
@ -580,8 +645,8 @@ Common::Rect RomListWidget::getEditRect() const
|
|||
{
|
||||
const int yoffset = std::max(0, (_selectedItem - _currentPos) * _lineHeight);
|
||||
|
||||
return Common::Rect(2 + _w - _bytesWidth, 1 + yoffset,
|
||||
_w, _lineHeight + yoffset);
|
||||
return Common::Rect(2 + _w - _bytesWidth, 1 + yoffset + 1,
|
||||
_w, _lineHeight + yoffset + 1);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -594,6 +659,7 @@ void RomListWidget::startEditMode()
|
|||
return;
|
||||
|
||||
_editMode = true;
|
||||
dialog().tooltip().hide();
|
||||
switch(myDisasm->list[_selectedItem].type)
|
||||
{
|
||||
case Device::GFX:
|
||||
|
|
|
@ -56,12 +56,13 @@ class RomListWidget : public EditableWidget
|
|||
void setSelected(int item);
|
||||
void setHighlighted(int item);
|
||||
|
||||
string getToolTip(const Common::Point& pos) const override;
|
||||
bool changedToolTip(const Common::Point& oldPos, const Common::Point& newPos) const override;
|
||||
|
||||
protected:
|
||||
void handleMouseDown(int x, int y, MouseButton b, int clickCount) override;
|
||||
void handleMouseUp(int x, int y, MouseButton b, int clickCount) override;
|
||||
void handleMouseWheel(int x, int y, int direction) override;
|
||||
void handleMouseEntered() override;
|
||||
void handleMouseLeft() override;
|
||||
bool handleText(char text) override;
|
||||
bool handleKeyDown(StellaKey key, StellaMod mod) override;
|
||||
bool handleKeyUp(StellaKey key, StellaMod mod) override;
|
||||
|
@ -79,11 +80,15 @@ class RomListWidget : public EditableWidget
|
|||
void endEditMode() override;
|
||||
void abortEditMode() override;
|
||||
void lostFocusWidget() override;
|
||||
|
||||
bool hasToolTip() const override { return true; }
|
||||
|
||||
void scrollToSelected() { scrollToCurrent(_selectedItem); }
|
||||
void scrollToHighlighted() { scrollToCurrent(_highlightedItem); }
|
||||
|
||||
private:
|
||||
void scrollToCurrent(int item);
|
||||
Common::Point getToolTipIndex(const Common::Point& pos) const;
|
||||
|
||||
private:
|
||||
unique_ptr<RomListSettings> myMenu;
|
||||
|
@ -96,7 +101,6 @@ class RomListWidget : public EditableWidget
|
|||
int _currentPos{0}; // position of first line in visible window
|
||||
int _selectedItem{-1};
|
||||
int _highlightedItem{-1};
|
||||
bool _editMode{false};
|
||||
StellaKey _currentKeyDown{KBDK_UNKNOWN};
|
||||
Common::Base::Fmt _base{Common::Base::Fmt::_DEFAULT}; // base used during editing
|
||||
|
||||
|
|
|
@ -90,10 +90,6 @@ void RomWidget::handleCommand(CommandSender* sender, int cmd, int data, int id)
|
|||
case RomListWidget::kBPointChangedCmd:
|
||||
// 'data' is the line in the disassemblylist to be accessed
|
||||
toggleBreak(data);
|
||||
// Refresh the romlist, since the breakpoint may not have
|
||||
// actually changed
|
||||
myRomList->setDirty();
|
||||
myRomList->draw();
|
||||
break;
|
||||
|
||||
case RomListWidget::kRomChangedCmd:
|
||||
|
@ -199,7 +195,7 @@ void RomWidget::runtoPC(int disasm_line)
|
|||
ostringstream command;
|
||||
command << "runtopc #" << address;
|
||||
string msg = instance().debugger().run(command.str());
|
||||
instance().frameBuffer().showMessage(msg);
|
||||
instance().frameBuffer().showTextMessage(msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -60,18 +60,21 @@ TiaInfoWidget::TiaInfoWidget(GuiObject* boss, const GUI::Font& lfont,
|
|||
xpos = x;
|
||||
new StaticTextWidget(boss, lfont, xpos, ypos + 1, longstr ? "Frame Cycls" : "F. Cycls");
|
||||
myFrameCycles = new EditTextWidget(boss, nfont, xpos + lwidth, ypos - 1, fwidth, lineHeight);
|
||||
myFrameCycles->setToolTip("CPU cycles executed this frame.");
|
||||
myFrameCycles->setEditable(false, true);
|
||||
|
||||
// Left: WSync Cycles
|
||||
ypos += lineHeight + VGAP;
|
||||
new StaticTextWidget(boss, lfont, xpos, ypos + 1, longstr ? "WSync Cycls" : "WSync C.");
|
||||
myWSyncCylces = new EditTextWidget(boss, nfont, xpos + lwidth, ypos - 1, fwidth, lineHeight);
|
||||
myWSyncCylces->setToolTip("CPU cycles used for WSYNC this frame.");
|
||||
myWSyncCylces->setEditable(false, true);
|
||||
|
||||
// Left: Timer Cycles
|
||||
ypos += lineHeight + VGAP;
|
||||
new StaticTextWidget(boss, lfont, xpos, ypos + 1, longstr ? "Timer Cycls" : "Timer C.");
|
||||
myTimerCylces = new EditTextWidget(boss, nfont, xpos + lwidth, ypos - 1, fwidth, lineHeight);
|
||||
myTimerCylces->setToolTip("CPU cycles roughly used for INTIM reads this frame.");
|
||||
myTimerCylces->setEditable(false, true);
|
||||
|
||||
// Left: Total Cycles
|
||||
|
@ -84,6 +87,7 @@ TiaInfoWidget::TiaInfoWidget(GuiObject* boss, const GUI::Font& lfont,
|
|||
ypos += lineHeight + VGAP;
|
||||
new StaticTextWidget(boss, lfont, xpos, ypos + 1, "Delta");
|
||||
myDeltaCycles = new EditTextWidget(boss, nfont, xpos + lwidth8, ypos - 1, twidth, lineHeight);
|
||||
myDeltaCycles->setToolTip("CPU cycles executed since last debug break.");
|
||||
myDeltaCycles->setEditable(false, true);
|
||||
|
||||
// Right column
|
||||
|
@ -93,6 +97,7 @@ TiaInfoWidget::TiaInfoWidget(GuiObject* boss, const GUI::Font& lfont,
|
|||
// Right: Frame Count
|
||||
new StaticTextWidget(boss, lfont, xpos, ypos + 1, longstr ? "Frame Cnt." : "Frame");
|
||||
myFrameCount = new EditTextWidget(boss, nfont, xpos + lwidthR, ypos - 1, fwidth, lineHeight);
|
||||
myFrameCount->setToolTip("Total number of frames executed this session.");
|
||||
myFrameCount->setEditable(false, true);
|
||||
|
||||
lwidth = lfont.getStringWidth(longstr ? "Color Clock " : "Pixel Pos ") + LGAP;
|
||||
|
@ -102,28 +107,33 @@ TiaInfoWidget::TiaInfoWidget(GuiObject* boss, const GUI::Font& lfont,
|
|||
ypos += lineHeight + VGAP;
|
||||
new StaticTextWidget(boss, lfont, xpos, ypos + 1, longstr ? "Scanline" : "Scn Ln");
|
||||
myScanlineCountLast = new EditTextWidget(boss, nfont, xpos + lwidth, ypos - 1, fwidth, lineHeight);
|
||||
myScanlineCountLast->setToolTip("Number of scanlines of last frame.");
|
||||
myScanlineCountLast->setEditable(false, true);
|
||||
myScanlineCount = new EditTextWidget(boss, nfont,
|
||||
xpos + lwidth - myScanlineCountLast->getWidth() - 2, ypos - 1,
|
||||
fwidth, lineHeight);
|
||||
myScanlineCount->setToolTip("Current scanline of this frame.");
|
||||
myScanlineCount->setEditable(false, true);
|
||||
|
||||
// Right: Scan Cycle
|
||||
ypos += lineHeight + VGAP;
|
||||
new StaticTextWidget(boss, lfont, xpos, ypos + 1, longstr ? "Scan Cycle" : "Scn Cycle");
|
||||
myScanlineCycles = new EditTextWidget(boss, nfont, xpos + lwidth, ypos - 1, fwidth, lineHeight);
|
||||
myScanlineCycles->setToolTip("CPU cycles in current scanline.");
|
||||
myScanlineCycles->setEditable(false, true);
|
||||
|
||||
// Right: Pixel Pos
|
||||
ypos += lineHeight + VGAP;
|
||||
new StaticTextWidget(boss, lfont, xpos, ypos + 1, "Pixel Pos");
|
||||
myPixelPosition = new EditTextWidget(boss, nfont, xpos + lwidth, ypos - 1, fwidth, lineHeight);
|
||||
myPixelPosition->setToolTip("Pixel position in current scanline.");
|
||||
myPixelPosition->setEditable(false, true);
|
||||
|
||||
// Right: Color Clock
|
||||
ypos += lineHeight + VGAP;
|
||||
new StaticTextWidget(boss, lfont, xpos, ypos + 1, longstr ? "Color Clock" : "Color Clk");
|
||||
myColorClocks = new EditTextWidget(boss, nfont, xpos + lwidth, ypos - 1, fwidth, lineHeight);
|
||||
myColorClocks->setToolTip("Color clocks in current scanline.");
|
||||
myColorClocks->setEditable(false, true);
|
||||
|
||||
// Calculate actual dimensions
|
||||
|
@ -159,7 +169,10 @@ void TiaInfoWidget::loadConfig()
|
|||
uInt64 total = tia.cyclesLo() + (uInt64(tia.cyclesHi()) << 32);
|
||||
uInt64 totalOld = oldTia.info[2] + (uInt64(oldTia.info[3]) << 32);
|
||||
myTotalCycles->setText(Common::Base::toString(uInt32(total) / 1000000, Common::Base::Fmt::_10_6) + "e6",
|
||||
total != totalOld);
|
||||
total / 1000000 != totalOld / 1000000);
|
||||
myTotalCycles->setToolTip("Total CPU cycles (E notation) executed for this session ("
|
||||
+ std::to_string(total) + ").");
|
||||
|
||||
uInt64 delta = total - totalOld;
|
||||
myDeltaCycles->setText(Common::Base::toString(uInt32(delta), Common::Base::Fmt::_10_8)); // no coloring
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "FBSurface.hxx"
|
||||
#include "Widget.hxx"
|
||||
#include "GuiObject.hxx"
|
||||
#include "Dialog.hxx"
|
||||
#include "ContextMenu.hxx"
|
||||
#include "TiaZoomWidget.hxx"
|
||||
#include "Debugger.hxx"
|
||||
|
@ -55,6 +56,7 @@ TiaOutputWidget::TiaOutputWidget(GuiObject* boss, const GUI::Font& font,
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void TiaOutputWidget::loadConfig()
|
||||
{
|
||||
setEnabled(true);
|
||||
setDirty();
|
||||
}
|
||||
|
||||
|
@ -92,10 +94,10 @@ void TiaOutputWidget::saveSnapshot(int execDepth, const string& execPrefix)
|
|||
message = e.what();
|
||||
}
|
||||
if (execDepth == 0) {
|
||||
instance().frameBuffer().showMessage(message);
|
||||
instance().frameBuffer().showTextMessage(message);
|
||||
}
|
||||
#else
|
||||
instance().frameBuffer().showMessage("PNG image saving not supported");
|
||||
instance().frameBuffer().showTextMessage("PNG image saving not supported");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -108,7 +110,7 @@ void TiaOutputWidget::handleMouseDown(int x, int y, MouseButton b, int clickCoun
|
|||
else if(b == MouseButton::RIGHT)
|
||||
{
|
||||
myClickX = x;
|
||||
myClickY = y;
|
||||
myClickY = y - 1;
|
||||
|
||||
// Add menu at current x,y mouse location
|
||||
myMenu->show(x + getAbsX(), y + getAbsY(), dialog().surface().dstRect());
|
||||
|
@ -135,7 +137,7 @@ void TiaOutputWidget::handleCommand(CommandSender* sender, int cmd, int data, in
|
|||
{
|
||||
command << "scanline #" << lines;
|
||||
string message = instance().debugger().parser().run(command.str());
|
||||
instance().frameBuffer().showMessage(message);
|
||||
instance().frameBuffer().showTextMessage(message);
|
||||
}
|
||||
}
|
||||
else if(rmb == "bp")
|
||||
|
@ -144,7 +146,7 @@ void TiaOutputWidget::handleCommand(CommandSender* sender, int cmd, int data, in
|
|||
int scanline = myClickY + startLine;
|
||||
command << "breakif _scan==#" << scanline;
|
||||
string message = instance().debugger().parser().run(command.str());
|
||||
instance().frameBuffer().showMessage(message);
|
||||
instance().frameBuffer().showTextMessage(message);
|
||||
}
|
||||
else if(rmb == "zoom")
|
||||
{
|
||||
|
@ -158,6 +160,52 @@ void TiaOutputWidget::handleCommand(CommandSender* sender, int cmd, int data, in
|
|||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Common::Point TiaOutputWidget::getToolTipIndex(const Common::Point& pos) const
|
||||
{
|
||||
const Int32 width = instance().console().tia().width();
|
||||
const Int32 height = instance().console().tia().height();
|
||||
const int col = (pos.x - 1 - getAbsX()) >> 1;
|
||||
const int row = pos.y - 1 - getAbsY();
|
||||
|
||||
if(col < 0 || col >= width || row < 0 || row >= height)
|
||||
return Common::Point(-1, -1);
|
||||
else
|
||||
return Common::Point(col, row);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string TiaOutputWidget::getToolTip(const Common::Point& pos) const
|
||||
{
|
||||
const Common::Point& idx = getToolTipIndex(pos);
|
||||
|
||||
if(idx.x < 0)
|
||||
return EmptyString;
|
||||
|
||||
const uInt32 startLine = instance().console().tia().startLine();
|
||||
const uInt32 height = instance().console().tia().height();
|
||||
// limit to 274 lines (PAL default without scaling)
|
||||
const uInt32 yStart = height <= FrameManager::Metrics::baseHeightPAL
|
||||
? 0 : (height - FrameManager::Metrics::baseHeightPAL) >> 1;
|
||||
const Int32 i = idx.x + (yStart + idx.y) * instance().console().tia().width();
|
||||
uInt8* tiaOutputBuffer = instance().console().tia().outputBuffer();
|
||||
ostringstream buf;
|
||||
|
||||
buf << _toolTipText
|
||||
<< "X: #" << idx.x
|
||||
<< "\nY: #" << idx.y + startLine
|
||||
<< "\nC: $" << Common::Base::toString(tiaOutputBuffer[i], Common::Base::Fmt::_16);
|
||||
|
||||
return buf.str();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool TiaOutputWidget::changedToolTip(const Common::Point& oldPos,
|
||||
const Common::Point& newPos) const
|
||||
{
|
||||
return getToolTipIndex(oldPos) != getToolTipIndex(newPos);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void TiaOutputWidget::drawWidget(bool hilite)
|
||||
{
|
||||
|
|
|
@ -47,6 +47,13 @@ class TiaOutputWidget : public Widget, public CommandSender
|
|||
bool handleKeyDown(StellaKey key, StellaMod mod) override;
|
||||
bool handleKeyUp(StellaKey key, StellaMod mod) override;
|
||||
*/
|
||||
string getToolTip(const Common::Point& pos) const override;
|
||||
bool changedToolTip(const Common::Point& oldPos, const Common::Point& newPos) const override;
|
||||
|
||||
protected:
|
||||
bool hasToolTip() const override { return true; }
|
||||
Common::Point getToolTipIndex(const Common::Point& pos) const;
|
||||
|
||||
private:
|
||||
unique_ptr<ContextMenu> myMenu;
|
||||
TiaZoomWidget* myZoom{nullptr};
|
||||
|
|
|
@ -563,7 +563,7 @@ TiaWidget::TiaWidget(GuiObject* boss, const GUI::Font& lfont,
|
|||
new StaticTextWidget(boss, lfont, xpos, ypos+2, 2*fontWidth, fontHeight,
|
||||
"PF", TextAlign::Left);
|
||||
xpos += 2*fontWidth + 5;
|
||||
myPF[0] = new TogglePixelWidget(boss, nfont, xpos, ypos+1, 4, 1);
|
||||
myPF[0] = new TogglePixelWidget(boss, nfont, xpos, ypos+1, 4, 1, 4);
|
||||
myPF[0]->setTarget(this);
|
||||
myPF[0]->setID(kPF0ID);
|
||||
addFocusWidget(myPF[0]);
|
||||
|
@ -1043,8 +1043,8 @@ void TiaWidget::loadConfig()
|
|||
myGRP0Old->setColor(kBGColorLo);
|
||||
myGRP0Old->setCrossed(true);
|
||||
}
|
||||
myGRP0->setIntState(state.gr[TiaState::P0], false);
|
||||
myGRP0Old->setIntState(state.gr[TiaState::P0+2], false);
|
||||
myGRP0->setIntState(state.gr[TiaState::P0], state.ref[TiaState::P0]);
|
||||
myGRP0Old->setIntState(state.gr[TiaState::P0+2], state.ref[TiaState::P0]);
|
||||
|
||||
// posP0
|
||||
myPosP0->setList(0, state.pos[TiaState::P0],
|
||||
|
@ -1079,8 +1079,8 @@ void TiaWidget::loadConfig()
|
|||
myGRP1Old->setColor(kBGColorLo);
|
||||
myGRP1Old->setCrossed(true);
|
||||
}
|
||||
myGRP1->setIntState(state.gr[TiaState::P1], false);
|
||||
myGRP1Old->setIntState(state.gr[TiaState::P1+2], false);
|
||||
myGRP1->setIntState(state.gr[TiaState::P1], state.ref[TiaState::P1]);
|
||||
myGRP1Old->setIntState(state.gr[TiaState::P1+2], state.ref[TiaState::P1]);
|
||||
|
||||
// posP1
|
||||
myPosP1->setList(0, state.pos[TiaState::P1],
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
#include "FBSurface.hxx"
|
||||
#include "Widget.hxx"
|
||||
#include "GuiObject.hxx"
|
||||
#include "Dialog.hxx"
|
||||
#include "ToolTip.hxx"
|
||||
#include "ContextMenu.hxx"
|
||||
#include "FrameManager.hxx"
|
||||
#include "TiaZoomWidget.hxx"
|
||||
|
@ -115,7 +117,7 @@ void TiaZoomWidget::recalc()
|
|||
void TiaZoomWidget::handleMouseDown(int x, int y, MouseButton b, int clickCount)
|
||||
{
|
||||
myClickX = x;
|
||||
myClickY = y;
|
||||
myClickY = y - 1;
|
||||
|
||||
// Button 1 is for 'drag'/movement of the image
|
||||
// Button 2 is for context menu
|
||||
|
@ -141,9 +143,11 @@ void TiaZoomWidget::handleMouseUp(int x, int y, MouseButton b, int clickCount)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void TiaZoomWidget::handleMouseWheel(int x, int y, int direction)
|
||||
{
|
||||
dialog().tooltip().hide();
|
||||
|
||||
// zoom towards mouse position
|
||||
myClickX = x;
|
||||
myClickY = y;
|
||||
myClickY = y - 1;
|
||||
|
||||
if(direction > 0)
|
||||
{
|
||||
|
@ -162,6 +166,7 @@ void TiaZoomWidget::handleMouseMoved(int x, int y)
|
|||
{
|
||||
if(myMouseMoving)
|
||||
{
|
||||
y--;
|
||||
int diffx = x + myOffXLo - myClickX;
|
||||
int diffy = y + myOffYLo - myClickY;
|
||||
|
||||
|
@ -178,19 +183,11 @@ void TiaZoomWidget::handleMouseMoved(int x, int y)
|
|||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void TiaZoomWidget::handleMouseEntered()
|
||||
{
|
||||
setFlags(Widget::FLAG_HILITED);
|
||||
setDirty();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void TiaZoomWidget::handleMouseLeft()
|
||||
{
|
||||
clearFlags(Widget::FLAG_HILITED);
|
||||
setDirty();
|
||||
myMouseMoving = false;
|
||||
Widget::handleMouseLeft();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -262,7 +259,7 @@ void TiaZoomWidget::handleCommand(CommandSender* sender, int cmd, int data, int
|
|||
{
|
||||
command << "scanline #" << lines;
|
||||
string message = instance().debugger().parser().run(command.str());
|
||||
instance().frameBuffer().showMessage(message);
|
||||
instance().frameBuffer().showTextMessage(message);
|
||||
}
|
||||
}
|
||||
else if(rmb == "bp")
|
||||
|
@ -271,7 +268,7 @@ void TiaZoomWidget::handleCommand(CommandSender* sender, int cmd, int data, int
|
|||
int scanline = myClickY / myZoomLevel + myOffY + startLine;
|
||||
command << "breakif _scan==#" << scanline;
|
||||
string message = instance().debugger().parser().run(command.str());
|
||||
instance().frameBuffer().showMessage(message);
|
||||
instance().frameBuffer().showTextMessage(message);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -282,6 +279,48 @@ void TiaZoomWidget::handleCommand(CommandSender* sender, int cmd, int data, int
|
|||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Common::Point TiaZoomWidget::getToolTipIndex(const Common::Point& pos) const
|
||||
{
|
||||
const Int32 width = instance().console().tia().width() * 2;
|
||||
const Int32 height = instance().console().tia().height();
|
||||
const int col = (pos.x - 1 - getAbsX()) / (myZoomLevel << 1) + (myOffX >> 1);
|
||||
const int row = (pos.y - 1 - getAbsY()) / myZoomLevel + myOffY;
|
||||
|
||||
if(col < 0 || col >= width || row < 0 || row >= height)
|
||||
return Common::Point(-1, -1);
|
||||
else
|
||||
return Common::Point(col, row);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string TiaZoomWidget::getToolTip(const Common::Point& pos) const
|
||||
{
|
||||
const Common::Point& idx = getToolTipIndex(pos);
|
||||
|
||||
if(idx.x < 0)
|
||||
return EmptyString;
|
||||
|
||||
const Int32 i = idx.x + idx.y * instance().console().tia().width();
|
||||
const uInt32 startLine = instance().console().tia().startLine();
|
||||
uInt8* tiaOutputBuffer = instance().console().tia().outputBuffer();
|
||||
ostringstream buf;
|
||||
|
||||
buf << _toolTipText
|
||||
<< "X: #" << idx.x
|
||||
<< "\nY: #" << idx.y + startLine
|
||||
<< "\nC: $" << Common::Base::toString(tiaOutputBuffer[i], Common::Base::Fmt::_16);
|
||||
|
||||
return buf.str();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool TiaZoomWidget::changedToolTip(const Common::Point& oldPos,
|
||||
const Common::Point& newPos) const
|
||||
{
|
||||
return getToolTipIndex(oldPos) != getToolTipIndex(newPos);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void TiaZoomWidget::drawWidget(bool hilite)
|
||||
{
|
||||
|
|
|
@ -27,15 +27,21 @@ class ContextMenu;
|
|||
class TiaZoomWidget : public Widget, public CommandSender
|
||||
{
|
||||
public:
|
||||
using Widget::setPos;
|
||||
|
||||
TiaZoomWidget(GuiObject *boss, const GUI::Font& font,
|
||||
int x, int y, int w, int h);
|
||||
~TiaZoomWidget() override = default;
|
||||
|
||||
void loadConfig() override;
|
||||
void setPos(int x, int y);
|
||||
void setPos(int x, int y) override;
|
||||
|
||||
string getToolTip(const Common::Point& pos) const override;
|
||||
bool changedToolTip(const Common::Point& oldPos, const Common::Point& newPos) const override;
|
||||
|
||||
protected:
|
||||
void handleMouseEntered() override;
|
||||
bool hasToolTip() const override { return true; }
|
||||
Common::Point getToolTipIndex(const Common::Point& pos) const;
|
||||
|
||||
private:
|
||||
void zoom(int level);
|
||||
|
|
|
@ -25,8 +25,10 @@
|
|||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
ToggleBitWidget::ToggleBitWidget(GuiObject* boss, const GUI::Font& font,
|
||||
int x, int y, int cols, int rows, int colchars)
|
||||
: ToggleWidget(boss, font, x, y, cols, rows, 1)
|
||||
int x, int y, int cols, int rows, int colchars,
|
||||
const StringList& labels)
|
||||
: ToggleWidget(boss, font, x, y, cols, rows),
|
||||
_labelList(labels)
|
||||
{
|
||||
_rowHeight = font.getLineHeight();
|
||||
_colWidth = colchars * font.getMaxCharWidth() + 8;
|
||||
|
@ -47,6 +49,13 @@ ToggleBitWidget::ToggleBitWidget(GuiObject* boss, const GUI::Font& font,
|
|||
_h = _rowHeight * rows + 1;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
ToggleBitWidget::ToggleBitWidget(GuiObject* boss, const GUI::Font& font,
|
||||
int x, int y, int cols, int rows, int colchars)
|
||||
: ToggleBitWidget(boss, font, x, y, cols, rows, colchars, StringList())
|
||||
{
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void ToggleBitWidget::setList(const StringList& off, const StringList& on)
|
||||
{
|
||||
|
@ -61,12 +70,35 @@ void ToggleBitWidget::setList(const StringList& off, const StringList& on)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void ToggleBitWidget::setState(const BoolArray& state, const BoolArray& changed)
|
||||
{
|
||||
if(!std::equal(_changedList.begin(), _changedList.end(),
|
||||
changed.begin(), changed.end()))
|
||||
setDirty();
|
||||
|
||||
_stateList.clear();
|
||||
_stateList = state;
|
||||
_changedList.clear();
|
||||
_changedList = changed;
|
||||
}
|
||||
|
||||
setDirty();
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string ToggleBitWidget::getToolTip(const Common::Point& pos) const
|
||||
{
|
||||
const Common::Point& idx = getToolTipIndex(pos);
|
||||
|
||||
if(idx.y < 0)
|
||||
return EmptyString;
|
||||
|
||||
const string tip = ToggleWidget::getToolTip(pos);
|
||||
|
||||
if(idx.x < static_cast<int>(_labelList.size()))
|
||||
{
|
||||
const string label = _labelList[idx.x];
|
||||
|
||||
if(!label.empty())
|
||||
return tip + "\n" + label;
|
||||
}
|
||||
return tip;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -74,7 +106,6 @@ void ToggleBitWidget::drawWidget(bool hilite)
|
|||
{
|
||||
//cerr << "ToggleBitWidget::drawWidget\n";
|
||||
FBSurface& s = dialog().surface();
|
||||
bool onTop = _boss->dialog().isOnTop();
|
||||
int row, col;
|
||||
string buffer;
|
||||
|
||||
|
@ -116,18 +147,16 @@ void ToggleBitWidget::drawWidget(bool hilite)
|
|||
// Highlight changes
|
||||
if(_changedList[pos])
|
||||
{
|
||||
s.fillRect(x - 3, y - 1, _colWidth-1, _rowHeight-1,
|
||||
onTop ? kDbgChangedColor : _bgcolorlo);
|
||||
s.drawString(_font, buffer, x, y, _colWidth, onTop ? kDbgChangedTextColor : kColor);
|
||||
s.fillRect(x - 3, y - 1, _colWidth-1, _rowHeight-1, kDbgChangedColor);
|
||||
s.drawString(_font, buffer, x, y, _colWidth, kDbgChangedTextColor);
|
||||
}
|
||||
else
|
||||
s.drawString(_font, buffer, x, y, _colWidth,
|
||||
onTop ? textColor : kColor);
|
||||
s.drawString(_font, buffer, x, y, _colWidth, textColor);
|
||||
}
|
||||
else
|
||||
{
|
||||
s.fillRect(x - 3, y - 1, _colWidth-1, _rowHeight-1, onTop ? kBGColorHi : kDlgColor);
|
||||
s.drawString(_font, buffer, x, y, _colWidth, onTop ? kTextColor : kColor);
|
||||
s.fillRect(x - 3, y - 1, _colWidth-1, _rowHeight-1, kBGColorHi);
|
||||
s.drawString(_font, buffer, x, y, _colWidth, kTextColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,17 +26,23 @@ class ToggleBitWidget : public ToggleWidget
|
|||
public:
|
||||
ToggleBitWidget(GuiObject* boss, const GUI::Font& font,
|
||||
int x, int y, int cols, int rows, int colchars = 1);
|
||||
ToggleBitWidget(GuiObject* boss, const GUI::Font& font,
|
||||
int x, int y, int cols, int rows, int colchars,
|
||||
const StringList& labels);
|
||||
~ToggleBitWidget() override = default;
|
||||
|
||||
void setList(const StringList& off, const StringList& on);
|
||||
void setState(const BoolArray& state, const BoolArray& changed);
|
||||
|
||||
string getToolTip(const Common::Point& pos) const override;
|
||||
|
||||
protected:
|
||||
void drawWidget(bool hilite) override;
|
||||
|
||||
protected:
|
||||
StringList _offList;
|
||||
StringList _onList;
|
||||
StringList _labelList;
|
||||
|
||||
private:
|
||||
// Following constructors and assignment operators not supported
|
||||
|
|
|
@ -24,8 +24,9 @@
|
|||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
TogglePixelWidget::TogglePixelWidget(GuiObject* boss, const GUI::Font& font,
|
||||
int x, int y, int cols, int rows)
|
||||
: ToggleWidget(boss, font, x, y, cols, rows, 1)
|
||||
int x, int y, int cols, int rows,
|
||||
int shiftBits)
|
||||
: ToggleWidget(boss, font, x, y, cols, rows, shiftBits)
|
||||
{
|
||||
_rowHeight = _colWidth = font.getLineHeight();
|
||||
|
||||
|
@ -50,15 +51,18 @@ void TogglePixelWidget::setState(const BoolArray& state)
|
|||
for(int col = 0; col < _cols; col++)
|
||||
{
|
||||
int pos = row * _cols + col;
|
||||
bool changed = _stateList[pos] != state[pos];
|
||||
|
||||
_changedList[pos] = _stateList[pos] != state[pos];
|
||||
if(_changedList[pos] != changed)
|
||||
{
|
||||
_changedList[pos] = changed;
|
||||
setDirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_stateList.clear();
|
||||
_stateList = state;
|
||||
|
||||
setDirty();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -112,12 +116,21 @@ int TogglePixelWidget::getIntState()
|
|||
return value;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void TogglePixelWidget::setCrossed(bool enable)
|
||||
{
|
||||
if(_crossBits != enable)
|
||||
{
|
||||
_crossBits = enable;
|
||||
setDirty();
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void TogglePixelWidget::drawWidget(bool hilite)
|
||||
{
|
||||
//cerr << "TogglePixelWidget::drawWidget\n";
|
||||
FBSurface& s = dialog().surface();
|
||||
bool onTop = _boss->dialog().isOnTop();
|
||||
int row, col;
|
||||
|
||||
s.frameRect(_x, _y, _w, _h, hilite && isEnabled() && isEditable() ? kWidColorHi : kColor);
|
||||
|
@ -145,7 +158,7 @@ void TogglePixelWidget::drawWidget(bool hilite)
|
|||
|
||||
// Either draw the pixel in given color, or erase (show background)
|
||||
s.fillRect(x - 3, y - 1, _colWidth-1, _rowHeight-1,
|
||||
_stateList[pos] ? onTop ? _pixelColor : kColor : onTop ? _backgroundColor : kBGColorLo);
|
||||
_stateList[pos] ? _pixelColor : _backgroundColor);
|
||||
if (_changedList[pos])
|
||||
s.frameRect(x - 3, y - 1, _colWidth - 1, _rowHeight - 1, kDbgChangedColor);
|
||||
}
|
||||
|
|
|
@ -25,7 +25,8 @@ class TogglePixelWidget : public ToggleWidget
|
|||
{
|
||||
public:
|
||||
TogglePixelWidget(GuiObject* boss, const GUI::Font& font,
|
||||
int x, int y, int cols, int rows);
|
||||
int x, int y, int cols = 1, int rows = 1,
|
||||
int shiftBits = 0);
|
||||
~TogglePixelWidget() override = default;
|
||||
|
||||
void setColor(ColorId color) { _pixelColor = color; }
|
||||
|
@ -35,14 +36,13 @@ class TogglePixelWidget : public ToggleWidget
|
|||
|
||||
void setState(const BoolArray& state);
|
||||
|
||||
void setIntState(int value, bool swap);
|
||||
void setIntState(int value, bool swap = false);
|
||||
int getIntState();
|
||||
|
||||
void setCrossed(bool enable) { _crossBits = enable; }
|
||||
void setCrossed(bool enable);
|
||||
|
||||
private:
|
||||
ColorId _pixelColor{kNone}, _backgroundColor{kDlgColor};
|
||||
bool _swapBits{false};
|
||||
bool _crossBits{false};
|
||||
|
||||
private:
|
||||
|
|
|
@ -16,44 +16,26 @@
|
|||
//============================================================================
|
||||
|
||||
#include "OSystem.hxx"
|
||||
#include "Base.hxx"
|
||||
#include "StellaKeys.hxx"
|
||||
#include "Widget.hxx"
|
||||
#include "Dialog.hxx"
|
||||
#include "ToolTip.hxx"
|
||||
#include "ToggleWidget.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
ToggleWidget::ToggleWidget(GuiObject* boss, const GUI::Font& font,
|
||||
int x, int y, int cols, int rows,
|
||||
int clicksToChange)
|
||||
int x, int y, int cols, int rows, int shiftBits)
|
||||
: Widget(boss, font, x, y, 16, 16),
|
||||
CommandSender(boss),
|
||||
_rows(rows),
|
||||
_cols(cols),
|
||||
_currentRow(0),
|
||||
_currentCol(0),
|
||||
_rowHeight(0),
|
||||
_colWidth(0),
|
||||
_selectedItem(0),
|
||||
_clicksToChange(clicksToChange),
|
||||
_editable(true)
|
||||
_shiftBits(shiftBits)
|
||||
{
|
||||
_flags = Widget::FLAG_ENABLED | Widget::FLAG_CLEARBG | Widget::FLAG_RETAIN_FOCUS |
|
||||
Widget::FLAG_WANTS_RAWDATA;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void ToggleWidget::handleMouseEntered()
|
||||
{
|
||||
setFlags(Widget::FLAG_HILITED);
|
||||
setDirty();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void ToggleWidget::handleMouseLeft()
|
||||
{
|
||||
clearFlags(Widget::FLAG_HILITED);
|
||||
setDirty();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void ToggleWidget::handleMouseDown(int x, int y, MouseButton b, int clickCount)
|
||||
{
|
||||
|
@ -71,6 +53,7 @@ void ToggleWidget::handleMouseDown(int x, int y, MouseButton b, int clickCount)
|
|||
_selectedItem = newSelectedItem;
|
||||
_currentRow = _selectedItem / _cols;
|
||||
_currentCol = _selectedItem - (_currentRow * _cols);
|
||||
dialog().tooltip().hide();
|
||||
setDirty();
|
||||
}
|
||||
}
|
||||
|
@ -83,7 +66,7 @@ void ToggleWidget::handleMouseUp(int x, int y, MouseButton b, int clickCount)
|
|||
|
||||
// If this was a double click and the mouse is still over the selected item,
|
||||
// send the double click command
|
||||
if (clickCount == _clicksToChange && (_selectedItem == findItem(x, y)))
|
||||
if (clickCount == 1 && (_selectedItem == findItem(x, y)))
|
||||
{
|
||||
_stateList[_selectedItem] = !_stateList[_selectedItem];
|
||||
_changedList[_selectedItem] = !_changedList[_selectedItem];
|
||||
|
@ -202,6 +185,7 @@ bool ToggleWidget::handleKeyDown(StellaKey key, StellaMod mod)
|
|||
_stateList[_selectedItem] = !_stateList[_selectedItem];
|
||||
_changedList[_selectedItem] = !_changedList[_selectedItem];
|
||||
sendCommand(ToggleWidget::kItemDataChangedCmd, _selectedItem, _id);
|
||||
dialog().tooltip().hide();
|
||||
}
|
||||
|
||||
setDirty();
|
||||
|
@ -223,3 +207,56 @@ void ToggleWidget::handleCommand(CommandSender* sender, int cmd,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Common::Point ToggleWidget::getToolTipIndex(const Common::Point& pos) const
|
||||
{
|
||||
const int col = (pos.x - getAbsX()) / _colWidth;
|
||||
const int row = (pos.y - getAbsY()) / _rowHeight;
|
||||
|
||||
if(row >= 0 && row < _rows && col >= 0 && col < _cols)
|
||||
return Common::Point(col, row);
|
||||
else
|
||||
return Common::Point(-1, -1);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string ToggleWidget::getToolTip(const Common::Point& pos) const
|
||||
{
|
||||
const int idx = getToolTipIndex(pos).y * _cols;
|
||||
|
||||
if(idx < 0)
|
||||
return EmptyString;
|
||||
|
||||
Int32 val = 0;
|
||||
ostringstream buf;
|
||||
|
||||
if(_swapBits)
|
||||
for(int col = _cols - 1; col >= 0; --col)
|
||||
{
|
||||
val <<= 1;
|
||||
val += _stateList[idx + col];
|
||||
}
|
||||
else
|
||||
for(int col = 0; col < _cols; ++col)
|
||||
{
|
||||
val <<= 1;
|
||||
val += _stateList[idx + col];
|
||||
}
|
||||
val <<= _shiftBits;
|
||||
|
||||
buf << _toolTipText
|
||||
<< "$" << Common::Base::toString(val, Common::Base::Fmt::_16)
|
||||
<< " = #" << val;
|
||||
if(val < 0x100)
|
||||
buf << " = %" << Common::Base::toString(val, Common::Base::Fmt::_2);
|
||||
|
||||
return buf.str();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool ToggleWidget::changedToolTip(const Common::Point& oldPos,
|
||||
const Common::Point& newPos) const
|
||||
{
|
||||
return getToolTipIndex(oldPos) != getToolTipIndex(newPos);
|
||||
}
|
||||
|
|
|
@ -33,8 +33,8 @@ class ToggleWidget : public Widget, public CommandSender
|
|||
|
||||
public:
|
||||
ToggleWidget(GuiObject* boss, const GUI::Font& font,
|
||||
int x, int y, int cols, int rows,
|
||||
int clicksToChange = 2);
|
||||
int x, int y, int cols = 1, int rows = 1,
|
||||
int shiftBits = 0);
|
||||
~ToggleWidget() override = default;
|
||||
|
||||
const BoolArray& getState() { return _stateList; }
|
||||
|
@ -46,18 +46,24 @@ class ToggleWidget : public Widget, public CommandSender
|
|||
void setEditable(bool editable) { _editable = editable; }
|
||||
bool isEditable() const { return _editable; }
|
||||
|
||||
protected:
|
||||
string getToolTip(const Common::Point& pos) const override;
|
||||
bool changedToolTip(const Common::Point& oldPos, const Common::Point& newPos) const override;
|
||||
|
||||
protected:
|
||||
int _rows;
|
||||
int _cols;
|
||||
int _currentRow;
|
||||
int _currentCol;
|
||||
int _rowHeight; // explicitly set in child classes
|
||||
int _colWidth; // explicitly set in child classes
|
||||
int _selectedItem;
|
||||
int _clicksToChange; // number of clicks to register a change
|
||||
bool _editable;
|
||||
bool hasToolTip() const override { return true; }
|
||||
Common::Point getToolTipIndex(const Common::Point& pos) const;
|
||||
|
||||
protected:
|
||||
int _rows{0};
|
||||
int _cols{0};
|
||||
int _currentRow{0};
|
||||
int _currentCol{0};
|
||||
int _rowHeight{0}; // explicitly set in child classes
|
||||
int _colWidth{0}; // explicitly set in child classes
|
||||
int _selectedItem{0};
|
||||
bool _editable{true};
|
||||
bool _swapBits{false};
|
||||
int _shiftBits{0}; // shift bits for tooltip display
|
||||
|
||||
BoolArray _stateList;
|
||||
BoolArray _changedList;
|
||||
|
@ -68,8 +74,6 @@ class ToggleWidget : public Widget, public CommandSender
|
|||
|
||||
void handleMouseDown(int x, int y, MouseButton b, int clickCount) override;
|
||||
void handleMouseUp(int x, int y, MouseButton b, int clickCount) override;
|
||||
void handleMouseEntered() override;
|
||||
void handleMouseLeft() override;
|
||||
bool handleKeyDown(StellaKey key, StellaMod mod) override;
|
||||
void handleCommand(CommandSender* sender, int cmd, int data, int id) override;
|
||||
|
||||
|
|
|
@ -55,6 +55,7 @@ MODULE_OBJS := \
|
|||
src/debugger/gui/CartDebugWidget.o \
|
||||
src/debugger/gui/CpuWidget.o \
|
||||
src/debugger/gui/DataGridOpsWidget.o \
|
||||
src/debugger/gui/DataGridRamWidget.o \
|
||||
src/debugger/gui/DataGridWidget.o \
|
||||
src/debugger/gui/DebuggerDialog.o \
|
||||
src/debugger/gui/DelayQueueWidget.o \
|
||||
|
|
|
@ -277,7 +277,8 @@ uInt8 CartridgeCDF::peek(uInt16 address)
|
|||
if DIGITAL_AUDIO_ON
|
||||
{
|
||||
// retrieve packed sample (max size is 2K, or 4K of unpacked data)
|
||||
uInt32 sampleaddress = getSample() + (myMusicCounters[0] >> 21);
|
||||
|
||||
uInt32 sampleaddress = getSample() + (myMusicCounters[0] >> (isCDFJplus() ? 13 : 21));
|
||||
|
||||
// get sample value from ROM or RAM
|
||||
if (sampleaddress < 0x00080000)
|
||||
|
@ -288,7 +289,7 @@ uInt8 CartridgeCDF::peek(uInt16 address)
|
|||
peekvalue = 0;
|
||||
|
||||
// make sure current volume value is in the lower nybble
|
||||
if ((myMusicCounters[0] & (1<<20)) == 0)
|
||||
if ((myMusicCounters[0] & (1<<(isCDFJplus() ? 12 : 20))) == 0)
|
||||
peekvalue >>= 4;
|
||||
peekvalue &= 0x0f;
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ CartridgeEnhanced::CartridgeEnhanced(const ByteBuffer& image, size_t size,
|
|||
void CartridgeEnhanced::install(System& system)
|
||||
{
|
||||
// limit banked RAM size to the size of one RAM bank
|
||||
const uInt32 ramSize = myRamBankCount > 0 ? 1 << (myBankShift - 1) : uInt32(myRamSize);
|
||||
const uInt16 ramSize = myRamBankCount > 0 ? 1 << (myBankShift - 1) : uInt16(myRamSize);
|
||||
|
||||
// calculate bank switching and RAM sizes and masks
|
||||
myBankSize = 1 << myBankShift; // e.g. = 2 ^ 12 = 4K = 0x1000
|
||||
|
@ -93,7 +93,7 @@ void CartridgeEnhanced::install(System& system)
|
|||
// Set the page accessing method for the RAM writing pages
|
||||
// Note: Writes are mapped to poke() (NOT using direcPokeBase) to check for read from write port (RWP)
|
||||
access.type = System::PageAccessType::WRITE;
|
||||
for(size_t addr = ROM_OFFSET + myWriteOffset; addr < ROM_OFFSET + myWriteOffset + myRamSize; addr += System::PAGE_SIZE)
|
||||
for(uInt16 addr = ROM_OFFSET + myWriteOffset; addr < ROM_OFFSET + myWriteOffset + myRamSize; addr += System::PAGE_SIZE)
|
||||
{
|
||||
const uInt16 offset = addr & myRamMask;
|
||||
|
||||
|
@ -105,7 +105,7 @@ void CartridgeEnhanced::install(System& system)
|
|||
|
||||
// Set the page accessing method for the RAM reading pages
|
||||
access.type = System::PageAccessType::READ;
|
||||
for(size_t addr = ROM_OFFSET + myReadOffset; addr < ROM_OFFSET + myReadOffset + myRamSize; addr += System::PAGE_SIZE)
|
||||
for(uInt16 addr = ROM_OFFSET + myReadOffset; addr < ROM_OFFSET + myReadOffset + myRamSize; addr += System::PAGE_SIZE)
|
||||
{
|
||||
const uInt16 offset = addr & myRamMask;
|
||||
|
||||
|
|
|
@ -476,7 +476,7 @@ void Console::setFormat(uInt32 format, bool force)
|
|||
initializeAudio(); // ensure that audio synthesis is set up to match emulation rate
|
||||
myOSystem.resetFps(); // Reset FPS measurement
|
||||
|
||||
myOSystem.frameBuffer().showMessage(message);
|
||||
myOSystem.frameBuffer().showTextMessage(message);
|
||||
|
||||
// Let the other devices know about the console change
|
||||
mySystem->consoleChanged(myConsoleTiming);
|
||||
|
@ -493,10 +493,10 @@ void Console::toggleColorLoss(bool toggle)
|
|||
|
||||
string message = string("PAL color-loss ") +
|
||||
(colorloss ? "enabled" : "disabled");
|
||||
myOSystem.frameBuffer().showMessage(message);
|
||||
myOSystem.frameBuffer().showTextMessage(message);
|
||||
}
|
||||
else
|
||||
myOSystem.frameBuffer().showMessage(
|
||||
myOSystem.frameBuffer().showTextMessage(
|
||||
"PAL color-loss not available in non PAL modes");
|
||||
}
|
||||
|
||||
|
@ -521,7 +521,7 @@ void Console::toggleInter(bool toggle)
|
|||
ostringstream ss;
|
||||
|
||||
ss << "Interpolation " << (enabled ? "enabled" : "disabled");
|
||||
myOSystem.frameBuffer().showMessage(ss.str());
|
||||
myOSystem.frameBuffer().showTextMessage(ss.str());
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -539,7 +539,7 @@ void Console::toggleTurbo()
|
|||
|
||||
ostringstream ss;
|
||||
ss << "Turbo mode " << (!enabled ? "enabled" : "disabled");
|
||||
myOSystem.frameBuffer().showMessage(ss.str());
|
||||
myOSystem.frameBuffer().showTextMessage(ss.str());
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -564,7 +564,7 @@ void Console::changeSpeed(int direction)
|
|||
ostringstream val;
|
||||
|
||||
val << formatSpeed(speed) << "%";
|
||||
myOSystem.frameBuffer().showMessage("Emulation speed", val.str(), speed, MIN_SPEED, MAX_SPEED);
|
||||
myOSystem.frameBuffer().showGaugeMessage("Emulation speed", val.str(), speed, MIN_SPEED, MAX_SPEED);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -574,13 +574,13 @@ void Console::togglePhosphor()
|
|||
{
|
||||
myProperties.set(PropType::Display_Phosphor, "NO");
|
||||
myOSystem.frameBuffer().tiaSurface().enablePhosphor(false);
|
||||
myOSystem.frameBuffer().showMessage("Phosphor effect disabled");
|
||||
myOSystem.frameBuffer().showTextMessage("Phosphor effect disabled");
|
||||
}
|
||||
else
|
||||
{
|
||||
myProperties.set(PropType::Display_Phosphor, "YES");
|
||||
myOSystem.frameBuffer().tiaSurface().enablePhosphor(true);
|
||||
myOSystem.frameBuffer().showMessage("Phosphor effect enabled");
|
||||
myOSystem.frameBuffer().showTextMessage("Phosphor effect enabled");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -605,7 +605,7 @@ void Console::changePhosphor(int direction)
|
|||
val.str("");
|
||||
val << "Off";
|
||||
}
|
||||
myOSystem.frameBuffer().showMessage("Phosphor blend", val.str(), blend);
|
||||
myOSystem.frameBuffer().showGaugeMessage("Phosphor blend", val.str(), blend);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -699,7 +699,7 @@ void Console::changeVerticalCenter(int direction)
|
|||
if (vcenter != myTIA->vcenter()) myTIA->setVcenter(vcenter);
|
||||
|
||||
val << (vcenter ? vcenter > 0 ? "+" : "" : " ") << vcenter << "px";
|
||||
myOSystem.frameBuffer().showMessage("V-Center", val.str(), vcenter,
|
||||
myOSystem.frameBuffer().showGaugeMessage("V-Center", val.str(), vcenter,
|
||||
myTIA->minVcenter(), myTIA->maxVcenter());
|
||||
}
|
||||
|
||||
|
@ -729,7 +729,7 @@ void Console::changeVSizeAdjust(int direction)
|
|||
|
||||
val << (newAdjustVSize ? newAdjustVSize > 0 ? "+" : "" : " ")
|
||||
<< newAdjustVSize << "%";
|
||||
myOSystem.frameBuffer().showMessage("V-Size", val.str(), newAdjustVSize, -5, 5);
|
||||
myOSystem.frameBuffer().showGaugeMessage("V-Size", val.str(), newAdjustVSize, -5, 5);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -746,7 +746,7 @@ void Console::toggleCorrectAspectRatio(bool toggle)
|
|||
const string& message = string("Correct aspect ratio ") +
|
||||
(enabled ? "enabled" : "disabled");
|
||||
|
||||
myOSystem.frameBuffer().showMessage(message);
|
||||
myOSystem.frameBuffer().showTextMessage(message);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -920,7 +920,7 @@ unique_ptr<Controller> Console::getControllerPort(const Controller::Type type,
|
|||
Controller::onMessageCallback callback = [&os = myOSystem](const string& msg) {
|
||||
bool devSettings = os.settings().getBool("dev.settings");
|
||||
if(os.settings().getBool(devSettings ? "dev.eepromaccess" : "plr.eepromaccess"))
|
||||
os.frameBuffer().showMessage(msg);
|
||||
os.frameBuffer().showTextMessage(msg);
|
||||
};
|
||||
controller = make_unique<AtariVox>(port, myEvent, *mySystem,
|
||||
myOSystem.settings().getString("avoxport"), nvramfile, callback);
|
||||
|
@ -933,7 +933,7 @@ unique_ptr<Controller> Console::getControllerPort(const Controller::Type type,
|
|||
Controller::onMessageCallback callback = [&os = myOSystem](const string& msg) {
|
||||
bool devSettings = os.settings().getBool("dev.settings");
|
||||
if(os.settings().getBool(devSettings ? "dev.eepromaccess" : "plr.eepromaccess"))
|
||||
os.frameBuffer().showMessage(msg);
|
||||
os.frameBuffer().showTextMessage(msg);
|
||||
};
|
||||
controller = make_unique<SaveKey>(port, myEvent, *mySystem, nvramfile, callback);
|
||||
break;
|
||||
|
@ -987,7 +987,7 @@ void Console::changeAutoFireRate(int direction)
|
|||
else
|
||||
val << "Off";
|
||||
|
||||
myOSystem.frameBuffer().showMessage("Autofire rate", val.str(), rate, 0, isNTSC ? 30 : 25);
|
||||
myOSystem.frameBuffer().showGaugeMessage("Autofire rate", val.str(), rate, 0, isNTSC ? 30 : 25);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -1012,7 +1012,7 @@ void Console::toggleTIABit(TIABit bit, const string& bitname, bool show, bool to
|
|||
bool result = myTIA->toggleBit(bit, toggle ? 2 : 3);
|
||||
const string message = bitname + (result ? " enabled" : " disabled");
|
||||
|
||||
myOSystem.frameBuffer().showMessage(message);
|
||||
myOSystem.frameBuffer().showTextMessage(message);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -1021,7 +1021,7 @@ void Console::toggleBits(bool toggle) const
|
|||
bool enabled = myTIA->toggleBits(toggle);
|
||||
const string message = string("TIA bits ") + (enabled ? "enabled" : "disabled");
|
||||
|
||||
myOSystem.frameBuffer().showMessage(message);
|
||||
myOSystem.frameBuffer().showTextMessage(message);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -1030,7 +1030,7 @@ void Console::toggleTIACollision(TIABit bit, const string& bitname, bool show, b
|
|||
bool result = myTIA->toggleCollision(bit, toggle ? 2 : 3);
|
||||
const string message = bitname + (result ? " collision enabled" : " collision disabled");
|
||||
|
||||
myOSystem.frameBuffer().showMessage(message);
|
||||
myOSystem.frameBuffer().showTextMessage(message);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -1039,7 +1039,7 @@ void Console::toggleCollisions(bool toggle) const
|
|||
bool enabled = myTIA->toggleCollisions(toggle);
|
||||
const string message = string("TIA collisions ") + (enabled ? "enabled" : "disabled");
|
||||
|
||||
myOSystem.frameBuffer().showMessage(message);
|
||||
myOSystem.frameBuffer().showTextMessage(message);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -1048,7 +1048,7 @@ void Console::toggleFixedColors(bool toggle) const
|
|||
bool enabled = toggle ? myTIA->toggleFixedColors() : myTIA->usingFixedColors();
|
||||
const string message = string("Fixed debug colors ") + (enabled ? "enabled" : "disabled");
|
||||
|
||||
myOSystem.frameBuffer().showMessage(message);
|
||||
myOSystem.frameBuffer().showTextMessage(message);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -1057,7 +1057,7 @@ void Console::toggleJitter(bool toggle) const
|
|||
bool enabled = myTIA->toggleJitter(toggle ? 2 : 3);
|
||||
const string message = string("TV scanline jitter ") + (enabled ? "enabled" : "disabled");
|
||||
|
||||
myOSystem.frameBuffer().showMessage(message);
|
||||
myOSystem.frameBuffer().showTextMessage(message);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -31,11 +31,13 @@ void DispatchResult::setOk(uInt64 cycles)
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void DispatchResult::setDebugger(uInt64 cycles, const string& message, int address, bool wasReadTrap)
|
||||
void DispatchResult::setDebugger(uInt64 cycles, const string& message,
|
||||
const string& tooltip, int address, bool wasReadTrap)
|
||||
{
|
||||
myStatus = Status::debugger;
|
||||
myCycles = cycles;
|
||||
myMessage = message;
|
||||
myToolTip = tooltip;
|
||||
myAddress = address;
|
||||
myWasReadTrap = wasReadTrap;
|
||||
}
|
||||
|
|
|
@ -37,12 +37,14 @@ class DispatchResult
|
|||
|
||||
bool wasReadTrap() const { assertStatus(Status::debugger); return myWasReadTrap; }
|
||||
|
||||
const string& getToolTip() const { assertStatus(Status::debugger, Status::fatal); return myToolTip; }
|
||||
|
||||
bool isSuccess() const;
|
||||
|
||||
void setOk(uInt64 cycles);
|
||||
|
||||
void setDebugger(uInt64 cycles, const string& message = "", int address = -1,
|
||||
bool wasReadTrap = true);
|
||||
void setDebugger(uInt64 cycles, const string& message = "",
|
||||
const string& tooltip = "", int address = -1, bool wasReadTrap = true);
|
||||
|
||||
void setFatal(uInt64 cycles);
|
||||
|
||||
|
@ -73,6 +75,8 @@ class DispatchResult
|
|||
int myAddress{0};
|
||||
|
||||
bool myWasReadTrap{false};
|
||||
|
||||
string myToolTip;
|
||||
};
|
||||
|
||||
#endif // DISPATCH_RESULT_HXX
|
||||
|
|
|
@ -191,12 +191,12 @@ void EventHandler::toggleSAPortOrder()
|
|||
if(saport == "lr")
|
||||
{
|
||||
mapStelladaptors("rl");
|
||||
myOSystem.frameBuffer().showMessage("Stelladaptor ports right/left");
|
||||
myOSystem.frameBuffer().showTextMessage("Stelladaptor ports right/left");
|
||||
}
|
||||
else
|
||||
{
|
||||
mapStelladaptors("lr");
|
||||
myOSystem.frameBuffer().showMessage("Stelladaptor ports left/right");
|
||||
myOSystem.frameBuffer().showTextMessage("Stelladaptor ports left/right");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -214,7 +214,7 @@ void EventHandler::set7800Mode()
|
|||
void EventHandler::handleMouseControl()
|
||||
{
|
||||
if(myMouseControl)
|
||||
myOSystem.frameBuffer().showMessage(myMouseControl->next());
|
||||
myOSystem.frameBuffer().showTextMessage(myMouseControl->next());
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -323,7 +323,8 @@ void EventHandler::handleSystemEvent(SystemEvent e, int, int)
|
|||
{
|
||||
case SystemEvent::WINDOW_EXPOSED:
|
||||
case SystemEvent::WINDOW_RESIZED:
|
||||
myOSystem.frameBuffer().update(true); // force full update
|
||||
// Force full render update
|
||||
myOSystem.frameBuffer().update(FrameBuffer::UpdateMode::RERENDER);
|
||||
break;
|
||||
#ifdef BSPF_UNIX
|
||||
case SystemEvent::WINDOW_FOCUS_GAINED:
|
||||
|
@ -550,7 +551,7 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated)
|
|||
default:
|
||||
break;
|
||||
}
|
||||
myOSystem.frameBuffer().showMessage(msg + " settings");
|
||||
myOSystem.frameBuffer().showTextMessage(msg + " settings");
|
||||
myAdjustActive = false;
|
||||
}
|
||||
break;
|
||||
|
@ -1210,7 +1211,7 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated)
|
|||
|
||||
case Event::SaveAllStates:
|
||||
if (pressed && !repeated)
|
||||
myOSystem.frameBuffer().showMessage(myOSystem.state().rewindManager().saveAllStates());
|
||||
myOSystem.frameBuffer().showTextMessage(myOSystem.state().rewindManager().saveAllStates());
|
||||
return;
|
||||
|
||||
case Event::PreviousState:
|
||||
|
@ -1243,7 +1244,7 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated)
|
|||
|
||||
case Event::LoadAllStates:
|
||||
if (pressed && !repeated)
|
||||
myOSystem.frameBuffer().showMessage(myOSystem.state().rewindManager().loadAllStates());
|
||||
myOSystem.frameBuffer().showTextMessage(myOSystem.state().rewindManager().loadAllStates());
|
||||
return;
|
||||
|
||||
case Event::RewindPause:
|
||||
|
@ -1476,7 +1477,7 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated)
|
|||
{
|
||||
myEvent.set(Event::ConsoleBlackWhite, 0);
|
||||
myEvent.set(Event::ConsoleColor, 1);
|
||||
myOSystem.frameBuffer().showMessage(myIs7800 ? "Pause released" : "Color Mode");
|
||||
myOSystem.frameBuffer().showTextMessage(myIs7800 ? "Pause released" : "Color Mode");
|
||||
myOSystem.console().switches().update();
|
||||
}
|
||||
return;
|
||||
|
@ -1485,7 +1486,7 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated)
|
|||
{
|
||||
myEvent.set(Event::ConsoleBlackWhite, 1);
|
||||
myEvent.set(Event::ConsoleColor, 0);
|
||||
myOSystem.frameBuffer().showMessage(myIs7800 ? "Pause pushed" : "B/W Mode");
|
||||
myOSystem.frameBuffer().showTextMessage(myIs7800 ? "Pause pushed" : "B/W Mode");
|
||||
myOSystem.console().switches().update();
|
||||
}
|
||||
return;
|
||||
|
@ -1496,13 +1497,13 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated)
|
|||
{
|
||||
myEvent.set(Event::ConsoleBlackWhite, 1);
|
||||
myEvent.set(Event::ConsoleColor, 0);
|
||||
myOSystem.frameBuffer().showMessage(myIs7800 ? "Pause pushed" : "B/W Mode");
|
||||
myOSystem.frameBuffer().showTextMessage(myIs7800 ? "Pause pushed" : "B/W Mode");
|
||||
}
|
||||
else
|
||||
{
|
||||
myEvent.set(Event::ConsoleBlackWhite, 0);
|
||||
myEvent.set(Event::ConsoleColor, 1);
|
||||
myOSystem.frameBuffer().showMessage(myIs7800 ? "Pause released" : "Color Mode");
|
||||
myOSystem.frameBuffer().showTextMessage(myIs7800 ? "Pause released" : "Color Mode");
|
||||
}
|
||||
myOSystem.console().switches().update();
|
||||
}
|
||||
|
@ -1514,7 +1515,7 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated)
|
|||
myEvent.set(Event::ConsoleBlackWhite, 0);
|
||||
myEvent.set(Event::ConsoleColor, 0);
|
||||
if (myIs7800)
|
||||
myOSystem.frameBuffer().showMessage("Pause pressed");
|
||||
myOSystem.frameBuffer().showTextMessage("Pause pressed");
|
||||
myOSystem.console().switches().update();
|
||||
}
|
||||
return;
|
||||
|
@ -1524,7 +1525,7 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated)
|
|||
{
|
||||
myEvent.set(Event::ConsoleLeftDiffA, 1);
|
||||
myEvent.set(Event::ConsoleLeftDiffB, 0);
|
||||
myOSystem.frameBuffer().showMessage(GUI::LEFT_DIFFICULTY + " A");
|
||||
myOSystem.frameBuffer().showTextMessage(GUI::LEFT_DIFFICULTY + " A");
|
||||
myOSystem.console().switches().update();
|
||||
}
|
||||
return;
|
||||
|
@ -1533,7 +1534,7 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated)
|
|||
{
|
||||
myEvent.set(Event::ConsoleLeftDiffA, 0);
|
||||
myEvent.set(Event::ConsoleLeftDiffB, 1);
|
||||
myOSystem.frameBuffer().showMessage(GUI::LEFT_DIFFICULTY + " B");
|
||||
myOSystem.frameBuffer().showTextMessage(GUI::LEFT_DIFFICULTY + " B");
|
||||
myOSystem.console().switches().update();
|
||||
}
|
||||
return;
|
||||
|
@ -1544,13 +1545,13 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated)
|
|||
{
|
||||
myEvent.set(Event::ConsoleLeftDiffA, 0);
|
||||
myEvent.set(Event::ConsoleLeftDiffB, 1);
|
||||
myOSystem.frameBuffer().showMessage(GUI::LEFT_DIFFICULTY + " B");
|
||||
myOSystem.frameBuffer().showTextMessage(GUI::LEFT_DIFFICULTY + " B");
|
||||
}
|
||||
else
|
||||
{
|
||||
myEvent.set(Event::ConsoleLeftDiffA, 1);
|
||||
myEvent.set(Event::ConsoleLeftDiffB, 0);
|
||||
myOSystem.frameBuffer().showMessage(GUI::LEFT_DIFFICULTY + " A");
|
||||
myOSystem.frameBuffer().showTextMessage(GUI::LEFT_DIFFICULTY + " A");
|
||||
}
|
||||
myOSystem.console().switches().update();
|
||||
}
|
||||
|
@ -1561,7 +1562,7 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated)
|
|||
{
|
||||
myEvent.set(Event::ConsoleRightDiffA, 1);
|
||||
myEvent.set(Event::ConsoleRightDiffB, 0);
|
||||
myOSystem.frameBuffer().showMessage(GUI::RIGHT_DIFFICULTY + " A");
|
||||
myOSystem.frameBuffer().showTextMessage(GUI::RIGHT_DIFFICULTY + " A");
|
||||
myOSystem.console().switches().update();
|
||||
}
|
||||
return;
|
||||
|
@ -1570,7 +1571,7 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated)
|
|||
{
|
||||
myEvent.set(Event::ConsoleRightDiffA, 0);
|
||||
myEvent.set(Event::ConsoleRightDiffB, 1);
|
||||
myOSystem.frameBuffer().showMessage(GUI::RIGHT_DIFFICULTY + " B");
|
||||
myOSystem.frameBuffer().showTextMessage(GUI::RIGHT_DIFFICULTY + " B");
|
||||
myOSystem.console().switches().update();
|
||||
}
|
||||
return;
|
||||
|
@ -1581,13 +1582,13 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated)
|
|||
{
|
||||
myEvent.set(Event::ConsoleRightDiffA, 0);
|
||||
myEvent.set(Event::ConsoleRightDiffB, 1);
|
||||
myOSystem.frameBuffer().showMessage(GUI::RIGHT_DIFFICULTY + " B");
|
||||
myOSystem.frameBuffer().showTextMessage(GUI::RIGHT_DIFFICULTY + " B");
|
||||
}
|
||||
else
|
||||
{
|
||||
myEvent.set(Event::ConsoleRightDiffA, 1);
|
||||
myEvent.set(Event::ConsoleRightDiffB, 0);
|
||||
myOSystem.frameBuffer().showMessage(GUI::RIGHT_DIFFICULTY + " A");
|
||||
myOSystem.frameBuffer().showTextMessage(GUI::RIGHT_DIFFICULTY + " A");
|
||||
}
|
||||
myOSystem.console().switches().update();
|
||||
}
|
||||
|
@ -2287,6 +2288,7 @@ void EventHandler::enterMenuMode(EventHandlerState state)
|
|||
void EventHandler::leaveMenuMode()
|
||||
{
|
||||
#ifdef GUI_SUPPORT
|
||||
myOverlay->removeDialog(); // remove the base dialog from dialog stack
|
||||
setState(EventHandlerState::EMULATION);
|
||||
myOSystem.sound().mute(false);
|
||||
#endif
|
||||
|
@ -2312,14 +2314,15 @@ bool EventHandler::enterDebugMode()
|
|||
myOSystem.debugger().setQuitState();
|
||||
setState(EventHandlerState::EMULATION);
|
||||
if(fbstatus == FBInitStatus::FailTooLarge)
|
||||
myOSystem.frameBuffer().showMessage("Debugger window too large for screen",
|
||||
myOSystem.frameBuffer().showTextMessage("Debugger window too large for screen",
|
||||
MessagePosition::BottomCenter, true);
|
||||
return false;
|
||||
}
|
||||
myOverlay->reStack();
|
||||
myOSystem.sound().mute(true);
|
||||
|
||||
#else
|
||||
myOSystem.frameBuffer().showMessage("Debugger support not included",
|
||||
myOSystem.frameBuffer().showTextMessage("Debugger support not included",
|
||||
MessagePosition::BottomCenter, true);
|
||||
#endif
|
||||
|
||||
|
|
|
@ -296,27 +296,47 @@ void FBSurface::frameRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h,
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FBSurface::wrapString(const string& inStr, int pos, string& leftStr, string& rightStr) const
|
||||
void FBSurface::splitString(const GUI::Font& font, const string& s, int w,
|
||||
string& left, string& right) const
|
||||
{
|
||||
#ifdef GUI_SUPPORT
|
||||
uInt32 pos;
|
||||
int w2 = 0;
|
||||
bool split = false;
|
||||
|
||||
// SLOW algorithm to find the acceptable length. But it is good enough for now.
|
||||
for(pos = 0; pos < s.size(); ++pos)
|
||||
{
|
||||
int charWidth = font.getCharWidth(s[pos]);
|
||||
if(w2 + charWidth > w || s[pos] == '\n')
|
||||
{
|
||||
split = true;
|
||||
break;
|
||||
}
|
||||
w2 += charWidth;
|
||||
}
|
||||
|
||||
if(split)
|
||||
for(int i = pos; i > 0; --i)
|
||||
{
|
||||
if(isWhiteSpace(inStr[i]))
|
||||
if(isWhiteSpace(s[i]))
|
||||
{
|
||||
leftStr = inStr.substr(0, i);
|
||||
if(inStr[i] == ' ') // skip leading space after line break
|
||||
left = s.substr(0, i);
|
||||
if(s[i] == ' ' || s[pos] == '\n') // skip leading space after line break
|
||||
i++;
|
||||
rightStr = inStr.substr(i);
|
||||
right = s.substr(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
leftStr = inStr.substr(0, pos);
|
||||
rightStr = inStr.substr(pos);
|
||||
left = s.substr(0, pos);
|
||||
right = s.substr(pos);
|
||||
#endif
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool FBSurface::isWhiteSpace(const char s) const
|
||||
{
|
||||
const string WHITESPACES = " ,.;:+-";
|
||||
const string WHITESPACES = " ,.;:+-*/\\'([\n";
|
||||
|
||||
for(size_t i = 0; i < WHITESPACES.length(); ++i)
|
||||
if(s == WHITESPACES[i])
|
||||
|
@ -331,37 +351,30 @@ int FBSurface::drawString(const GUI::Font& font, const string& s,
|
|||
ColorId color, TextAlign align,
|
||||
int deltax, bool useEllipsis, ColorId shadowColor)
|
||||
{
|
||||
int lines = 1;
|
||||
int lines = 0;
|
||||
|
||||
#ifdef GUI_SUPPORT
|
||||
string inStr = s;
|
||||
|
||||
// draw multiline string
|
||||
while (font.getStringWidth(inStr) > w && h >= font.getFontHeight() * 2)
|
||||
//while (font.getStringWidth(inStr) > w && h >= font.getFontHeight() * 2)
|
||||
while(inStr.length() && h >= font.getFontHeight() * 2)
|
||||
{
|
||||
// String is too wide.
|
||||
uInt32 i;
|
||||
string leftStr, rightStr;
|
||||
int w2 = 0;
|
||||
|
||||
// SLOW algorithm to find the acceptable length. But it is good enough for now.
|
||||
for(i = 0; i < inStr.size(); ++i)
|
||||
{
|
||||
int charWidth = font.getCharWidth(inStr[i]);
|
||||
if(w2 + charWidth > w)
|
||||
break;
|
||||
|
||||
w2 += charWidth;
|
||||
//str += inStr[i];
|
||||
}
|
||||
wrapString(inStr, i, leftStr, rightStr);
|
||||
splitString(font, inStr, w, leftStr, rightStr);
|
||||
drawString(font, leftStr, x, y, w, color, align, deltax, false, shadowColor);
|
||||
h -= font.getFontHeight();
|
||||
y += font.getFontHeight();
|
||||
inStr = rightStr;
|
||||
lines++;
|
||||
}
|
||||
if(inStr.length())
|
||||
{
|
||||
drawString(font, inStr, x, y, w, color, align, deltax, useEllipsis, shadowColor);
|
||||
lines++;
|
||||
}
|
||||
#endif
|
||||
return lines;
|
||||
}
|
||||
|
|
|
@ -247,6 +247,18 @@ class FBSurface
|
|||
ColorId color, TextAlign align = TextAlign::Left,
|
||||
int deltax = 0, bool useEllipsis = true, ColorId shadowColor = kNone);
|
||||
|
||||
/**
|
||||
Splits a given string to a given width considering whitespaces.
|
||||
|
||||
@param font The font to draw the string with
|
||||
@param s The string to split
|
||||
@param w The width of the string area
|
||||
@param left The left part of the split string
|
||||
@param right The right part of the split string
|
||||
*/
|
||||
void splitString(const GUI::Font& font, const string& s, int w,
|
||||
string& left, string& right) const;
|
||||
|
||||
/**
|
||||
The rendering attributes that can be modified for this texture.
|
||||
These probably can only be implemented in child FBSurfaces where
|
||||
|
@ -292,11 +304,14 @@ class FBSurface
|
|||
These methods set the origin point and width/height for the
|
||||
specified service. They are defined as separate x/y and w/h
|
||||
methods since these items are sometimes set separately.
|
||||
Other times they are set together, so we can use a Rect instead.
|
||||
*/
|
||||
virtual void setSrcPos(uInt32 x, uInt32 y) = 0;
|
||||
virtual void setSrcSize(uInt32 w, uInt32 h) = 0;
|
||||
virtual void setSrcRect(const Common::Rect& r) = 0;
|
||||
virtual void setDstPos(uInt32 x, uInt32 y) = 0;
|
||||
virtual void setDstSize(uInt32 w, uInt32 h) = 0;
|
||||
virtual void setDstRect(const Common::Rect& r) = 0;
|
||||
|
||||
/**
|
||||
This method should be called to enable/disable showing the surface
|
||||
|
@ -323,7 +338,18 @@ class FBSurface
|
|||
This method should be called to reset the surface to empty
|
||||
pixels / colour black.
|
||||
*/
|
||||
virtual void invalidate() = 0;
|
||||
virtual void invalidate() {}
|
||||
|
||||
/**
|
||||
This method should be called to reset a surface area to empty
|
||||
|
||||
@param x The x coordinate
|
||||
@param y The y coordinate
|
||||
@param w The width of the area
|
||||
@param h The height of the area
|
||||
*/
|
||||
virtual void invalidateRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h) = 0;
|
||||
|
||||
|
||||
/**
|
||||
This method should be called to free any resources being used by
|
||||
|
@ -369,9 +395,6 @@ class FBSurface
|
|||
*/
|
||||
bool checkBounds(const uInt32 x, const uInt32 y) const;
|
||||
|
||||
void wrapString(const string& inStr, int pos,
|
||||
string& leftStr, string& rightStr) const;
|
||||
|
||||
/**
|
||||
Check if the given character is a whitespace.
|
||||
@param s Character to check
|
||||
|
|
|
@ -76,10 +76,64 @@ bool FilesystemNode::exists() const
|
|||
return _realNode ? _realNode->exists() : false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool FilesystemNode::getAllChildren(FSList& fslist, ListMode mode,
|
||||
const NameFilter& filter,
|
||||
bool includeParentDirectory,
|
||||
const CancelCheck& isCancelled) const
|
||||
{
|
||||
if(getChildren(fslist, mode, filter, includeParentDirectory, true, isCancelled))
|
||||
{
|
||||
// Sort only once at the end
|
||||
#if defined(ZIP_SUPPORT)
|
||||
// before sorting, replace single file ZIP archive names with contained file names
|
||||
// because they are displayed using their contained file names
|
||||
for(auto& i : fslist)
|
||||
{
|
||||
if(BSPF::endsWithIgnoreCase(i.getPath(), ".zip"))
|
||||
{
|
||||
FilesystemNodeZIP zipNode(i.getPath());
|
||||
|
||||
i.setName(zipNode.getName());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
std::sort(fslist.begin(), fslist.end(),
|
||||
[](const FilesystemNode& node1, const FilesystemNode& node2)
|
||||
{
|
||||
if(node1.isDirectory() != node2.isDirectory())
|
||||
return node1.isDirectory();
|
||||
else
|
||||
return BSPF::compareIgnoreCase(node1.getName(), node2.getName()) < 0;
|
||||
}
|
||||
);
|
||||
|
||||
#if defined(ZIP_SUPPORT)
|
||||
// After sorting replace zip files with zip nodes
|
||||
for(auto& i : fslist)
|
||||
{
|
||||
if(BSPF::endsWithIgnoreCase(i.getPath(), ".zip"))
|
||||
{
|
||||
// Force ZIP c'tor to be called
|
||||
AbstractFSNodePtr ptr = FilesystemNodeFactory::create(i.getPath(),
|
||||
FilesystemNodeFactory::Type::ZIP);
|
||||
FilesystemNode zipNode(ptr);
|
||||
i = zipNode;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool FilesystemNode::getChildren(FSList& fslist, ListMode mode,
|
||||
const NameFilter& filter,
|
||||
bool includeParentDirectory) const
|
||||
bool includeChildDirectories,
|
||||
bool includeParentDirectory,
|
||||
const CancelCheck& isCancelled) const
|
||||
{
|
||||
if (!_realNode || !_realNode->isDirectory())
|
||||
return false;
|
||||
|
@ -90,6 +144,12 @@ bool FilesystemNode::getChildren(FSList& fslist, ListMode mode,
|
|||
if (!_realNode->getChildren(tmp, mode))
|
||||
return false;
|
||||
|
||||
// when incuding child directories, everything must be sorted once at the end
|
||||
if(!includeChildDirectories)
|
||||
{
|
||||
if(isCancelled())
|
||||
return false;
|
||||
|
||||
#if defined(ZIP_SUPPORT)
|
||||
// before sorting, replace single file ZIP archive names with contained file names
|
||||
// because they are displayed using their contained file names
|
||||
|
@ -113,6 +173,7 @@ bool FilesystemNode::getChildren(FSList& fslist, ListMode mode,
|
|||
return BSPF::compareIgnoreCase(node1->getName(), node2->getName()) < 0;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Add parent node, if it is valid to do so
|
||||
if (includeParentDirectory && hasParent())
|
||||
|
@ -125,16 +186,29 @@ bool FilesystemNode::getChildren(FSList& fslist, ListMode mode,
|
|||
// And now add the rest of the entries
|
||||
for (const auto& i: tmp)
|
||||
{
|
||||
if(isCancelled())
|
||||
return false;
|
||||
|
||||
#if defined(ZIP_SUPPORT)
|
||||
if (BSPF::endsWithIgnoreCase(i->getPath(), ".zip"))
|
||||
{
|
||||
// Force ZIP c'tor to be called
|
||||
AbstractFSNodePtr ptr = FilesystemNodeFactory::create(i->getPath(),
|
||||
FilesystemNodeFactory::Type::ZIP);
|
||||
FilesystemNode node(ptr);
|
||||
if (filter(node))
|
||||
FilesystemNode zipNode(ptr);
|
||||
|
||||
if(filter(zipNode))
|
||||
{
|
||||
if(!includeChildDirectories)
|
||||
fslist.emplace_back(zipNode);
|
||||
else
|
||||
{
|
||||
// filter by zip node but add file node
|
||||
FilesystemNode node(i);
|
||||
fslist.emplace_back(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
|
@ -143,11 +217,23 @@ bool FilesystemNode::getChildren(FSList& fslist, ListMode mode,
|
|||
i->setName(" [" + i->getName() + "]");
|
||||
|
||||
FilesystemNode node(i);
|
||||
|
||||
if(includeChildDirectories)
|
||||
{
|
||||
if(i->isDirectory())
|
||||
node.getChildren(fslist, mode, filter, includeChildDirectories, false, isCancelled);
|
||||
else
|
||||
// do not add directories in this mode
|
||||
if(filter(node))
|
||||
fslist.emplace_back(node);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(filter(node))
|
||||
fslist.emplace_back(node);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -57,6 +57,7 @@ class FilesystemNode
|
|||
/** Function used to filter the file listing. Returns true if the filename
|
||||
should be included, else false.*/
|
||||
using NameFilter = std::function<bool(const FilesystemNode& node)>;
|
||||
using CancelCheck = std::function<bool()> const;
|
||||
|
||||
/**
|
||||
* Create a new pathless FilesystemNode. Since there's no path associated
|
||||
|
@ -114,6 +115,18 @@ class FilesystemNode
|
|||
*/
|
||||
bool exists() const;
|
||||
|
||||
/**
|
||||
* Return a list of child nodes of this and all sub-directories. If called on a node
|
||||
* that does not represent a directory, false is returned.
|
||||
*
|
||||
* @return true if successful, false otherwise (e.g. when the directory
|
||||
* does not exist).
|
||||
*/
|
||||
bool getAllChildren(FSList& fslist, ListMode mode = ListMode::DirectoriesOnly,
|
||||
const NameFilter& filter = [](const FilesystemNode&) { return true; },
|
||||
bool includeParentDirectory = true,
|
||||
const CancelCheck& isCancelled = []() { return false; }) const;
|
||||
|
||||
/**
|
||||
* Return a list of child nodes of this directory node. If called on a node
|
||||
* that does not represent a directory, false is returned.
|
||||
|
@ -123,7 +136,9 @@ class FilesystemNode
|
|||
*/
|
||||
bool getChildren(FSList& fslist, ListMode mode = ListMode::DirectoriesOnly,
|
||||
const NameFilter& filter = [](const FilesystemNode&){ return true; },
|
||||
bool includeParentDirectory = true) const;
|
||||
bool includeChildDirectories = false,
|
||||
bool includeParentDirectory = true,
|
||||
const CancelCheck& isCancelled = []() { return false; }) const;
|
||||
|
||||
/**
|
||||
* Set/get a string representation of the name of the file. This is can be
|
||||
|
@ -273,8 +288,8 @@ class FilesystemNode
|
|||
string getPathWithExt(const string& ext) const;
|
||||
|
||||
private:
|
||||
AbstractFSNodePtr _realNode;
|
||||
explicit FilesystemNode(const AbstractFSNodePtr& realNode);
|
||||
AbstractFSNodePtr _realNode;
|
||||
void setPath(const string& path);
|
||||
};
|
||||
|
||||
|
|
|
@ -198,7 +198,7 @@ void FrameBuffer::setupFonts()
|
|||
FontDesc FrameBuffer::getFontDesc(const string& name) const
|
||||
{
|
||||
if(name == "small")
|
||||
return GUI::consoleBDesc; // 8x13
|
||||
return GUI::consoleDesc; // 8x13
|
||||
else if(name == "low_medium")
|
||||
return GUI::consoleMediumBDesc; // 9x15
|
||||
else if(name == "medium")
|
||||
|
@ -270,7 +270,7 @@ FBInitStatus FrameBuffer::createDisplay(const string& title, BufferType type,
|
|||
|
||||
#ifdef GUI_SUPPORT
|
||||
// Erase any messages from a previous run
|
||||
myMsg.counter = 0;
|
||||
myMsg.enabled = false;
|
||||
|
||||
// Create surfaces for TIA statistics and general messages
|
||||
const GUI::Font& f = hidpiEnabled() ? infoFont() : font();
|
||||
|
@ -311,7 +311,7 @@ FBInitStatus FrameBuffer::createDisplay(const string& title, BufferType type,
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameBuffer::update(bool force)
|
||||
void FrameBuffer::update(UpdateMode mode)
|
||||
{
|
||||
// Onscreen messages are a special case and require different handling than
|
||||
// other objects; they aren't UI dialogs in the normal sense nor are they
|
||||
|
@ -322,13 +322,14 @@ void FrameBuffer::update(bool force)
|
|||
// - at the bottom of ::update(), to actually draw them (this must come
|
||||
// last, since they are always drawn on top of everything else).
|
||||
|
||||
// Full rendering is required when messages are enabled
|
||||
force = force || myMsg.counter >= 0;
|
||||
bool forceRedraw = mode & UpdateMode::REDRAW;
|
||||
bool redraw = forceRedraw;
|
||||
|
||||
// Detect when a message has been turned off; one last redraw is required
|
||||
// in this case, to draw over the area that the message occupied
|
||||
if(myMsg.counter == 0)
|
||||
myMsg.counter = -1;
|
||||
// Forced render without draw required if messages or dialogs were closed
|
||||
// Note: For dialogs only relevant when two or more dialogs were stacked
|
||||
bool rerender = (mode & (UpdateMode::REDRAW | UpdateMode::RERENDER))
|
||||
|| myPendingRender;
|
||||
myPendingRender = false;
|
||||
|
||||
switch(myOSystem.eventHandler().state())
|
||||
{
|
||||
|
@ -343,59 +344,69 @@ void FrameBuffer::update(bool force)
|
|||
if(myPausedCount-- <= 0)
|
||||
{
|
||||
myPausedCount = uInt32(7 * myOSystem.frameRate());
|
||||
showMessage("Paused", MessagePosition::MiddleCenter);
|
||||
}
|
||||
if(force)
|
||||
showTextMessage("Paused", MessagePosition::MiddleCenter);
|
||||
myTIASurface->render();
|
||||
}
|
||||
if(rerender)
|
||||
myTIASurface->render();
|
||||
|
||||
break; // EventHandlerState::PAUSE
|
||||
}
|
||||
|
||||
#ifdef GUI_SUPPORT
|
||||
case EventHandlerState::OPTIONSMENU:
|
||||
{
|
||||
force = force || myOSystem.menu().needsRedraw();
|
||||
if(force)
|
||||
myOSystem.menu().tick();
|
||||
redraw |= myOSystem.menu().needsRedraw();
|
||||
if(redraw)
|
||||
{
|
||||
clear();
|
||||
myTIASurface->render();
|
||||
myOSystem.menu().draw(force);
|
||||
myOSystem.menu().draw(forceRedraw);
|
||||
}
|
||||
else if(rerender)
|
||||
{
|
||||
clear();
|
||||
myTIASurface->render();
|
||||
myOSystem.menu().render();
|
||||
}
|
||||
break; // EventHandlerState::OPTIONSMENU
|
||||
}
|
||||
|
||||
case EventHandlerState::CMDMENU:
|
||||
{
|
||||
force = force || myOSystem.commandMenu().needsRedraw();
|
||||
if(force)
|
||||
myOSystem.commandMenu().tick();
|
||||
redraw |= myOSystem.commandMenu().needsRedraw();
|
||||
if(redraw)
|
||||
{
|
||||
clear();
|
||||
myTIASurface->render();
|
||||
myOSystem.commandMenu().draw(force);
|
||||
myOSystem.commandMenu().draw(forceRedraw);
|
||||
}
|
||||
break; // EventHandlerState::CMDMENU
|
||||
}
|
||||
|
||||
case EventHandlerState::MESSAGEMENU:
|
||||
{
|
||||
force = force || myOSystem.messageMenu().needsRedraw();
|
||||
if (force)
|
||||
myOSystem.messageMenu().tick();
|
||||
redraw |= myOSystem.messageMenu().needsRedraw();
|
||||
if(redraw)
|
||||
{
|
||||
clear();
|
||||
myTIASurface->render();
|
||||
myOSystem.messageMenu().draw(force);
|
||||
myOSystem.messageMenu().draw(forceRedraw);
|
||||
}
|
||||
break; // EventHandlerState::MESSAGEMENU
|
||||
}
|
||||
|
||||
case EventHandlerState::TIMEMACHINE:
|
||||
{
|
||||
force = force || myOSystem.timeMachine().needsRedraw();
|
||||
if(force)
|
||||
myOSystem.timeMachine().tick();
|
||||
redraw |= myOSystem.timeMachine().needsRedraw();
|
||||
if(redraw)
|
||||
{
|
||||
clear();
|
||||
myTIASurface->render();
|
||||
myOSystem.timeMachine().draw(force);
|
||||
myOSystem.timeMachine().draw(forceRedraw);
|
||||
}
|
||||
break; // EventHandlerState::TIMEMACHINE
|
||||
}
|
||||
|
@ -420,8 +431,8 @@ void FrameBuffer::update(bool force)
|
|||
r.rewindStates(1);
|
||||
}
|
||||
|
||||
force = force || success;
|
||||
if (force)
|
||||
redraw |= success;
|
||||
if(redraw)
|
||||
myTIASurface->render();
|
||||
|
||||
// Stop playback mode at the end of the state buffer
|
||||
|
@ -436,12 +447,12 @@ void FrameBuffer::update(bool force)
|
|||
|
||||
case EventHandlerState::LAUNCHER:
|
||||
{
|
||||
force = force || myOSystem.launcher().needsRedraw();
|
||||
if(force)
|
||||
{
|
||||
clear();
|
||||
myOSystem.launcher().draw(force);
|
||||
}
|
||||
myOSystem.launcher().tick();
|
||||
redraw |= myOSystem.launcher().needsRedraw();
|
||||
if(redraw)
|
||||
myOSystem.launcher().draw(forceRedraw);
|
||||
else if(rerender)
|
||||
myOSystem.launcher().render();
|
||||
break; // EventHandlerState::LAUNCHER
|
||||
}
|
||||
#endif
|
||||
|
@ -449,12 +460,12 @@ void FrameBuffer::update(bool force)
|
|||
#ifdef DEBUGGER_SUPPORT
|
||||
case EventHandlerState::DEBUGGER:
|
||||
{
|
||||
force = force || myOSystem.debugger().needsRedraw();
|
||||
if(force)
|
||||
{
|
||||
clear();
|
||||
myOSystem.debugger().draw(force);
|
||||
}
|
||||
myOSystem.debugger().tick();
|
||||
redraw |= myOSystem.debugger().needsRedraw();
|
||||
if(redraw)
|
||||
myOSystem.debugger().draw(forceRedraw);
|
||||
else if(rerender)
|
||||
myOSystem.debugger().render();
|
||||
break; // EventHandlerState::DEBUGGER
|
||||
}
|
||||
#endif
|
||||
|
@ -468,10 +479,10 @@ void FrameBuffer::update(bool force)
|
|||
// indicates that, and then the code at the top of this method sees
|
||||
// the change and redraws everything
|
||||
if(myMsg.enabled)
|
||||
drawMessage();
|
||||
redraw |= drawMessage();
|
||||
|
||||
// Push buffers to screen only when necessary
|
||||
if(force)
|
||||
if(redraw || rerender)
|
||||
myBackend->renderToScreen();
|
||||
}
|
||||
|
||||
|
@ -501,19 +512,15 @@ void FrameBuffer::updateInEmulationMode(float framesPerSecond)
|
|||
myBackend->renderToScreen();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameBuffer::showMessage(const string& message, MessagePosition position,
|
||||
bool force)
|
||||
{
|
||||
#ifdef GUI_SUPPORT
|
||||
void FrameBuffer::createMessage(const string& message, MessagePosition position, bool force)
|
||||
{
|
||||
// Only show messages if they've been enabled
|
||||
if(myMsg.surface == nullptr || !(force || myOSystem.settings().getBool("uimessages")))
|
||||
return;
|
||||
|
||||
const int fontWidth = font().getMaxCharWidth(),
|
||||
fontHeight = font().getFontHeight();
|
||||
const int fontHeight = font().getFontHeight();
|
||||
const int VBORDER = fontHeight / 4;
|
||||
const int HBORDER = fontWidth * 1.25 / 2.0;
|
||||
|
||||
myMsg.counter = uInt32(myOSystem.frameRate()) * 2; // Show message for 2 seconds
|
||||
if(myMsg.counter == 0)
|
||||
|
@ -522,39 +529,40 @@ void FrameBuffer::showMessage(const string& message, MessagePosition position,
|
|||
// Precompute the message coordinates
|
||||
myMsg.text = message;
|
||||
myMsg.color = kBtnTextColor;
|
||||
myMsg.showGauge = false;
|
||||
myMsg.w = std::min(fontWidth * (MESSAGE_WIDTH) - HBORDER * 2,
|
||||
font().getStringWidth(myMsg.text) + HBORDER * 2);
|
||||
myMsg.h = fontHeight + VBORDER * 2;
|
||||
myMsg.position = position;
|
||||
myMsg.enabled = true;
|
||||
myMsg.dirty = true;
|
||||
|
||||
myMsg.surface->setSrcSize(myMsg.w, myMsg.h);
|
||||
myMsg.surface->setDstSize(myMsg.w * hidpiScaleFactor(), myMsg.h * hidpiScaleFactor());
|
||||
}
|
||||
#endif
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameBuffer::showTextMessage(const string& message, MessagePosition position,
|
||||
bool force)
|
||||
{
|
||||
#ifdef GUI_SUPPORT
|
||||
const int fontWidth = font().getMaxCharWidth();
|
||||
const int HBORDER = fontWidth * 1.25 / 2.0;
|
||||
|
||||
myMsg.showGauge = false;
|
||||
myMsg.w = std::min(fontWidth * (MESSAGE_WIDTH) - HBORDER * 2,
|
||||
font().getStringWidth(message) + HBORDER * 2);
|
||||
|
||||
createMessage(message, position, force);
|
||||
#endif
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameBuffer::showMessage(const string& message, const string& valueText,
|
||||
void FrameBuffer::showGaugeMessage(const string& message, const string& valueText,
|
||||
float value, float minValue, float maxValue)
|
||||
{
|
||||
#ifdef GUI_SUPPORT
|
||||
// Only show messages if they've been enabled
|
||||
if(myMsg.surface == nullptr || !myOSystem.settings().getBool("uimessages"))
|
||||
return;
|
||||
|
||||
const int fontWidth = font().getMaxCharWidth(),
|
||||
fontHeight = font().getFontHeight();
|
||||
const int VBORDER = fontHeight / 4;
|
||||
const int fontWidth = font().getMaxCharWidth();
|
||||
const int HBORDER = fontWidth * 1.25 / 2.0;
|
||||
|
||||
myMsg.counter = uInt32(myOSystem.frameRate()) * 2; // Show message for 2 seconds
|
||||
if(myMsg.counter == 0)
|
||||
myMsg.counter = 120;
|
||||
|
||||
// Precompute the message coordinates
|
||||
myMsg.text = message;
|
||||
myMsg.color = kBtnTextColor;
|
||||
myMsg.showGauge = true;
|
||||
if(maxValue - minValue != 0)
|
||||
myMsg.value = (value - minValue) / (maxValue - minValue) * 100.F;
|
||||
|
@ -562,16 +570,12 @@ void FrameBuffer::showMessage(const string& message, const string& valueText,
|
|||
myMsg.value = 100.F;
|
||||
myMsg.valueText = valueText;
|
||||
myMsg.w = std::min(fontWidth * MESSAGE_WIDTH,
|
||||
font().getStringWidth(myMsg.text)
|
||||
font().getStringWidth(message)
|
||||
+ fontWidth * (GAUGEBAR_WIDTH + 2)
|
||||
+ font().getStringWidth(myMsg.valueText))
|
||||
+ font().getStringWidth(valueText))
|
||||
+ HBORDER * 2;
|
||||
myMsg.h = fontHeight + VBORDER * 2;
|
||||
myMsg.position = MessagePosition::BottomCenter;
|
||||
myMsg.enabled = true;
|
||||
|
||||
myMsg.surface->setSrcSize(myMsg.w, myMsg.h);
|
||||
myMsg.surface->setDstSize(myMsg.w * hidpiScaleFactor(), myMsg.h * hidpiScaleFactor());
|
||||
createMessage(message, MessagePosition::BottomCenter);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -652,7 +656,7 @@ void FrameBuffer::toggleFrameStats(bool toggle)
|
|||
myOSystem.settings().setValue(
|
||||
myOSystem.settings().getBool("dev.settings") ? "dev.stats" : "plr.stats", myStatsEnabled);
|
||||
|
||||
myOSystem.frameBuffer().showMessage(string("Console info ") +
|
||||
myOSystem.frameBuffer().showTextMessage(string("Console info ") +
|
||||
(myStatsEnabled ? "enabled" : "disabled"));
|
||||
}
|
||||
|
||||
|
@ -676,12 +680,19 @@ void FrameBuffer::enableMessages(bool enable)
|
|||
myStatsMsg.enabled = false;
|
||||
|
||||
// Erase old messages on the screen
|
||||
myMsg.enabled = false;
|
||||
myMsg.counter = 0;
|
||||
update(true); // Force update immediately
|
||||
hideMessage();
|
||||
|
||||
update(); // update immediately
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameBuffer::hideMessage()
|
||||
{
|
||||
myPendingRender = myMsg.enabled;
|
||||
myMsg.enabled = false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
inline bool FrameBuffer::drawMessage()
|
||||
{
|
||||
|
@ -690,15 +701,15 @@ inline bool FrameBuffer::drawMessage()
|
|||
// or show again this frame
|
||||
if(myMsg.counter == 0)
|
||||
{
|
||||
myMsg.enabled = false;
|
||||
return true;
|
||||
}
|
||||
else if(myMsg.counter < 0)
|
||||
{
|
||||
myMsg.enabled = false;
|
||||
hideMessage();
|
||||
return false;
|
||||
}
|
||||
|
||||
if(myMsg.dirty)
|
||||
{
|
||||
cerr << "m";
|
||||
//cerr << "--- draw message ---" << endl;
|
||||
|
||||
// Draw the bounded box and text
|
||||
const Common::Rect& dst = myMsg.surface->dstRect();
|
||||
const int fontWidth = font().getMaxCharWidth(),
|
||||
|
@ -794,11 +805,16 @@ inline bool FrameBuffer::drawMessage()
|
|||
x + swidth + fontWidth, VBORDER,
|
||||
myMsg.w, myMsg.color);
|
||||
}
|
||||
myMsg.dirty = false;
|
||||
myMsg.surface->render();
|
||||
return true;
|
||||
}
|
||||
|
||||
myMsg.counter--;
|
||||
myMsg.surface->render();
|
||||
#endif
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -845,7 +861,7 @@ void FrameBuffer::resetSurfaces()
|
|||
freeSurfaces();
|
||||
reloadSurfaces();
|
||||
|
||||
update(true); // force full update
|
||||
update(UpdateMode::REDRAW); // force full update
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -898,10 +914,9 @@ void FrameBuffer::setUIPalette()
|
|||
void FrameBuffer::stateChanged(EventHandlerState state)
|
||||
{
|
||||
// Make sure any onscreen messages are removed
|
||||
myMsg.enabled = false;
|
||||
myMsg.counter = 0;
|
||||
hideMessage();
|
||||
|
||||
update(true); // force full update
|
||||
update(); // update immediately
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -990,7 +1005,9 @@ void FrameBuffer::setFullscreen(bool enable)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameBuffer::toggleFullscreen(bool toggle)
|
||||
{
|
||||
switch(myOSystem.eventHandler().state())
|
||||
EventHandlerState state = myOSystem.eventHandler().state();
|
||||
|
||||
switch(state)
|
||||
{
|
||||
case EventHandlerState::LAUNCHER:
|
||||
case EventHandlerState::EMULATION:
|
||||
|
@ -1000,17 +1017,27 @@ void FrameBuffer::toggleFullscreen(bool toggle)
|
|||
const bool isFullscreen = toggle ? !fullScreen() : fullScreen();
|
||||
setFullscreen(isFullscreen);
|
||||
|
||||
if(myBufferType != BufferType::Launcher)
|
||||
if(state != EventHandlerState::LAUNCHER)
|
||||
{
|
||||
ostringstream msg;
|
||||
msg << "Fullscreen ";
|
||||
|
||||
if(state != EventHandlerState::DEBUGGER)
|
||||
{
|
||||
if(isFullscreen)
|
||||
msg << "enabled (" << myBackend->refreshRate() << " Hz, ";
|
||||
else
|
||||
msg << "disabled (";
|
||||
msg << "Zoom " << myActiveVidMode.zoom * 100 << "%)";
|
||||
|
||||
showMessage(msg.str());
|
||||
}
|
||||
else
|
||||
{
|
||||
if(isFullscreen)
|
||||
msg << "enabled";
|
||||
else
|
||||
msg << "disabled";
|
||||
}
|
||||
showTextMessage(msg.str());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -1043,7 +1070,7 @@ void FrameBuffer::toggleAdaptRefresh(bool toggle)
|
|||
msg << (isAdaptRefresh ? "enabled" : "disabled");
|
||||
msg << " (" << myBackend->refreshRate() << " Hz)";
|
||||
|
||||
showMessage(msg.str());
|
||||
showTextMessage(msg.str());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -1069,7 +1096,7 @@ void FrameBuffer::changeOverscan(int direction)
|
|||
val << (overscan > 0 ? "+" : "" ) << overscan << "%";
|
||||
else
|
||||
val << "Off";
|
||||
myOSystem.frameBuffer().showMessage("Overscan", val.str(), overscan, 0, 10);
|
||||
myOSystem.frameBuffer().showGaugeMessage("Overscan", val.str(), overscan, 0, 10);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1106,9 +1133,9 @@ void FrameBuffer::switchVideoMode(int direction)
|
|||
if(applyVideoMode() == FBInitStatus::Success)
|
||||
{
|
||||
if(fullScreen())
|
||||
showMessage(myActiveVidMode.description);
|
||||
showTextMessage(myActiveVidMode.description);
|
||||
else
|
||||
showMessage("Zoom", myActiveVidMode.description, myActiveVidMode.zoom,
|
||||
showGaugeMessage("Zoom", myActiveVidMode.description, myActiveVidMode.zoom,
|
||||
supportedTIAMinZoom(), myTIAMaxZoom);
|
||||
}
|
||||
}
|
||||
|
@ -1163,6 +1190,7 @@ FBInitStatus FrameBuffer::applyVideoMode()
|
|||
|
||||
resetSurfaces();
|
||||
setCursorState();
|
||||
myPendingRender = true;
|
||||
}
|
||||
else
|
||||
Logger::error("ERROR: Couldn't initialize video subsystem");
|
||||
|
@ -1248,7 +1276,7 @@ void FrameBuffer::toggleGrabMouse()
|
|||
myGrabMouse = !myGrabMouse;
|
||||
setCursorState();
|
||||
myOSystem.settings().setValue("grabmouse", myGrabMouse);
|
||||
myOSystem.frameBuffer().showMessage(oldState != myGrabMouse ? myGrabMouse
|
||||
myOSystem.frameBuffer().showTextMessage(oldState != myGrabMouse ? myGrabMouse
|
||||
? "Grab mouse enabled" : "Grab mouse disabled"
|
||||
: "Grab mouse not allowed while cursor shown");
|
||||
}
|
||||
|
@ -1299,8 +1327,6 @@ void FrameBuffer::toggleGrabMouse()
|
|||
kColorInfo TIA output position color
|
||||
kColorTitleBar Title bar color
|
||||
kColorTitleText Title text color
|
||||
kColorTitleBarLo Disabled title bar color
|
||||
kColorTitleTextLo Disabled title text color
|
||||
*/
|
||||
UIPaletteArray FrameBuffer::ourStandardUIPalette = {
|
||||
{ 0x686868, 0x000000, 0xa38c61, 0xdccfa5, 0x404040, // base
|
||||
|
@ -1311,7 +1337,7 @@ UIPaletteArray FrameBuffer::ourStandardUIPalette = {
|
|||
0xac3410, 0xd55941, // scrollbar
|
||||
0xc80000, 0xffff80, 0xc8c8ff, 0xc80000, // debugger
|
||||
0xac3410, 0xd55941, 0xdccfa5, 0xf0f0cf, 0xa38c61, // slider
|
||||
0xffffff, 0xac3410, 0xf0f0cf, 0x686868, 0xdccfa5 // other
|
||||
0xffffff, 0xac3410, 0xf0f0cf // other
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1324,7 +1350,7 @@ UIPaletteArray FrameBuffer::ourClassicUIPalette = {
|
|||
0x20a020, 0x00ff00, // scrollbar
|
||||
0xc80000, 0x00ff00, 0xc8c8ff, 0xc80000, // debugger
|
||||
0x20a020, 0x00ff00, 0x404040, 0x686868, 0x404040, // slider
|
||||
0x00ff00, 0x20a020, 0x000000, 0x686868, 0x404040 // other
|
||||
0x00ff00, 0x20a020, 0x000000 // other
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1337,7 +1363,7 @@ UIPaletteArray FrameBuffer::ourLightUIPalette = {
|
|||
0xc0c0c0, 0x808080, // scrollbar
|
||||
0xffc0c0, 0x000000, 0xe00000, 0xc00000, // debugger
|
||||
0x333333, 0x0078d7, 0xc0c0c0, 0xffffff, 0xc0c0c0, // slider 0xBDDEF9| 0xe1e1e1 | 0xffffff
|
||||
0xffffff, 0x333333, 0xf0f0f0, 0x808080, 0xc0c0c0 // other
|
||||
0xffffff, 0x333333, 0xf0f0f0 // other
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1350,6 +1376,6 @@ UIPaletteArray FrameBuffer::ourDarkUIPalette = {
|
|||
0x3c3c3c, 0x646464, // scrollbar
|
||||
0x7f2020, 0xc0c0c0, 0xe00000, 0xc00000, // debugger
|
||||
0x989898, 0x0059a3, 0x3c3c3c, 0x000000, 0x3c3c3c, // slider
|
||||
0x000000, 0x989898, 0x202020, 0x646464, 0x3c3c3c // other
|
||||
0x000000, 0x989898, 0x202020 // other
|
||||
}
|
||||
};
|
||||
|
|
|
@ -55,6 +55,12 @@ class FrameBuffer
|
|||
// Zoom level step interval
|
||||
static constexpr float ZOOM_STEPS = 0.25;
|
||||
|
||||
enum UpdateMode {
|
||||
NONE = 0,
|
||||
REDRAW = 1,
|
||||
RERENDER = 2
|
||||
};
|
||||
|
||||
public:
|
||||
FrameBuffer(OSystem& osystem);
|
||||
~FrameBuffer();
|
||||
|
@ -84,7 +90,7 @@ class FrameBuffer
|
|||
Updates the display, which depending on the current mode could mean
|
||||
drawing the TIA, any pending menus, etc.
|
||||
*/
|
||||
void update(bool force = false);
|
||||
void update(UpdateMode mode = UpdateMode::NONE);
|
||||
|
||||
/**
|
||||
There is a dedicated update method for emulation mode.
|
||||
|
@ -92,13 +98,18 @@ class FrameBuffer
|
|||
void updateInEmulationMode(float framesPerSecond);
|
||||
|
||||
/**
|
||||
Shows a message onscreen.
|
||||
Set pending rendering flag.
|
||||
*/
|
||||
void setPendingRender() { myPendingRender = true; }
|
||||
|
||||
/**
|
||||
Shows a text message onscreen.
|
||||
|
||||
@param message The message to be shown
|
||||
@param position Onscreen position for the message
|
||||
@param force Force showing this message, even if messages are disabled
|
||||
*/
|
||||
void showMessage(const string& message,
|
||||
void showTextMessage(const string& message,
|
||||
MessagePosition position = MessagePosition::BottomCenter,
|
||||
bool force = false);
|
||||
/**
|
||||
|
@ -110,7 +121,7 @@ class FrameBuffer
|
|||
@param minValue The minimal value of the gauge bar
|
||||
@param maxValue The maximal value of the gauge bar
|
||||
*/
|
||||
void showMessage(const string& message, const string& valueText,
|
||||
void showGaugeMessage(const string& message, const string& valueText,
|
||||
float value, float minValue = 0.F, float maxValue = 100.F);
|
||||
|
||||
bool messageShown() const;
|
||||
|
@ -375,6 +386,18 @@ class FrameBuffer
|
|||
*/
|
||||
void resetSurfaces();
|
||||
|
||||
#ifdef GUI_SUPPORT
|
||||
/**
|
||||
Helps to create a basic message onscreen.
|
||||
|
||||
@param message The message to be shown
|
||||
@param position Onscreen position for the message
|
||||
@param force Force showing this message, even if messages are disabled
|
||||
*/
|
||||
void createMessage(const string& message, MessagePosition position,
|
||||
bool force = false);
|
||||
#endif
|
||||
|
||||
/**
|
||||
Draw pending messages.
|
||||
|
||||
|
@ -382,6 +405,11 @@ class FrameBuffer
|
|||
*/
|
||||
bool drawMessage();
|
||||
|
||||
/**
|
||||
Hide pending messages.
|
||||
*/
|
||||
void hideMessage();
|
||||
|
||||
/**
|
||||
Draws the frame stats overlay.
|
||||
*/
|
||||
|
@ -443,6 +471,9 @@ class FrameBuffer
|
|||
// Supported renderers
|
||||
VariantList myRenderers;
|
||||
|
||||
// Flag for pending render
|
||||
bool myPendingRender{false};
|
||||
|
||||
// The VideoModeHandler class takes responsibility for all video
|
||||
// mode functionality
|
||||
VideoModeHandler myVidModeHandler;
|
||||
|
@ -478,6 +509,7 @@ class FrameBuffer
|
|||
ColorId color{kNone};
|
||||
shared_ptr<FBSurface> surface;
|
||||
bool enabled{false};
|
||||
bool dirty{false};
|
||||
bool showGauge{false};
|
||||
float value{0.0F};
|
||||
string valueText;
|
||||
|
|
|
@ -109,9 +109,7 @@ static constexpr ColorId
|
|||
kColorInfo = 287,
|
||||
kColorTitleBar = 288,
|
||||
kColorTitleText = 289,
|
||||
kColorTitleBarLo = 290,
|
||||
kColorTitleTextLo = 291,
|
||||
kNumColors = 292,
|
||||
kNumColors = 290,
|
||||
kNone = 0 // placeholder to represent default/no color
|
||||
;
|
||||
|
||||
|
|
|
@ -243,7 +243,9 @@ inline void M6502::_execute(uInt64 cycles, DispatchResult& result)
|
|||
myJustHitReadTrapFlag = myJustHitWriteTrapFlag = false;
|
||||
|
||||
myLastBreakCycle = mySystem->cycles();
|
||||
result.setDebugger(currentCycles, myHitTrapInfo.message, myHitTrapInfo.address, read);
|
||||
result.setDebugger(currentCycles, myHitTrapInfo.message,
|
||||
read ? "Read trap" : "Write trap",
|
||||
myHitTrapInfo.address, read);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -264,7 +266,7 @@ inline void M6502::_execute(uInt64 cycles, DispatchResult& result)
|
|||
ostringstream msg;
|
||||
|
||||
msg << "BP: $" << Common::Base::HEX4 << PC << ", bank #" << std::dec << int(bank);
|
||||
result.setDebugger(currentCycles, msg.str());
|
||||
result.setDebugger(currentCycles, msg.str(), "Breakpoint");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -278,7 +280,7 @@ inline void M6502::_execute(uInt64 cycles, DispatchResult& result)
|
|||
msg << "CBP[" << Common::Base::HEX2 << cond << "]: " << myCondBreakNames[cond];
|
||||
|
||||
myLastBreakCycle = mySystem->cycles();
|
||||
result.setDebugger(currentCycles, msg.str());
|
||||
result.setDebugger(currentCycles, msg.str(), "Conditional breakpoint");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -327,7 +329,7 @@ inline void M6502::_execute(uInt64 cycles, DispatchResult& result)
|
|||
{
|
||||
ostringstream msg;
|
||||
msg << "RWP[@ $" << Common::Base::HEX4 << rwpAddr << "]: ";
|
||||
result.setDebugger(currentCycles, msg.str(), oldPC);
|
||||
result.setDebugger(currentCycles, msg.str(), "Read from write port", oldPC);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -339,7 +341,7 @@ inline void M6502::_execute(uInt64 cycles, DispatchResult& result)
|
|||
{
|
||||
ostringstream msg;
|
||||
msg << "WRP[@ $" << Common::Base::HEX4 << wrpAddr << "]: ";
|
||||
result.setDebugger(currentCycles, msg.str(), oldPC);
|
||||
result.setDebugger(currentCycles, msg.str(), "Write to read port", oldPC);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -348,7 +350,7 @@ inline void M6502::_execute(uInt64 cycles, DispatchResult& result)
|
|||
myExecutionStatus |= FatalErrorBit;
|
||||
result.setMessage(e.what());
|
||||
} catch (const EmulationWarning& e) {
|
||||
result.setDebugger(currentCycles, e.what(), PC);
|
||||
result.setDebugger(currentCycles, e.what(), "Emulation exception", PC);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -475,9 +475,9 @@ string OSystem::createConsole(const FilesystemNode& rom, const string& md5sum,
|
|||
{
|
||||
const string& id = myConsole->cartridge().multiCartID();
|
||||
if(id == "")
|
||||
myFrameBuffer->showMessage("New console created");
|
||||
myFrameBuffer->showTextMessage("New console created");
|
||||
else
|
||||
myFrameBuffer->showMessage("Multicart " +
|
||||
myFrameBuffer->showTextMessage("Multicart " +
|
||||
myConsole->cartridge().detectedType() + ", loading ROM" + id);
|
||||
}
|
||||
buf << "Game console created:" << endl
|
||||
|
@ -506,7 +506,7 @@ string OSystem::createConsole(const FilesystemNode& rom, const string& md5sum,
|
|||
msg << myConsole->leftController().name() << "/" << myConsole->rightController().name()
|
||||
<< " - " << myConsole->cartridge().detectedType()
|
||||
<< " - " << myConsole->getFormatString();
|
||||
myFrameBuffer->showMessage(msg.str());
|
||||
myFrameBuffer->showTextMessage(msg.str());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -775,7 +775,8 @@ double OSystem::dispatchEmulation(EmulationWorker& emulationWorker)
|
|||
myDebugger->start(
|
||||
dispatchResult.getMessage(),
|
||||
dispatchResult.getAddress(),
|
||||
dispatchResult.wasReadTrap()
|
||||
dispatchResult.wasReadTrap(),
|
||||
dispatchResult.getToolTip()
|
||||
);
|
||||
#endif
|
||||
|
||||
|
|
|
@ -81,7 +81,7 @@ void PointingDevice::update()
|
|||
return;
|
||||
|
||||
// Update horizontal direction
|
||||
cerr << myEvent.get(Event::MouseAxisXMove) << ", " << myHCounterRemainder << endl;
|
||||
//cerr << myEvent.get(Event::MouseAxisXMove) << ", " << myHCounterRemainder << endl;
|
||||
updateDirection( myEvent.get(Event::MouseAxisXMove), myHCounterRemainder,
|
||||
myTrackBallLeft, myTrackBallLinesH, myScanCountH, myFirstScanOffsetH);
|
||||
|
||||
|
@ -90,7 +90,7 @@ void PointingDevice::update()
|
|||
myTrackBallDown, myTrackBallLinesV, myScanCountV, myFirstScanOffsetV);
|
||||
|
||||
// We allow left and right mouse buttons for fire button
|
||||
setPin(DigitalPin::Six, !getAutoFireState(myEvent.get(Event::JoystickZeroFire) == 0 ||
|
||||
setPin(DigitalPin::Six, !getAutoFireState(myEvent.get(Event::JoystickZeroFire) ||
|
||||
myEvent.get(Event::MouseButtonLeftValue) || myEvent.get(Event::MouseButtonRightValue)));
|
||||
}
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@ unique_ptr<Controller> QuadTari::addController(const Controller::Type type, bool
|
|||
Controller::onMessageCallback callback = [&os = myOSystem](const string& msg) {
|
||||
bool devSettings = os.settings().getBool("dev.settings");
|
||||
if(os.settings().getBool(devSettings ? "dev.eepromaccess" : "plr.eepromaccess"))
|
||||
os.frameBuffer().showMessage(msg);
|
||||
os.frameBuffer().showTextMessage(msg);
|
||||
};
|
||||
|
||||
switch(type)
|
||||
|
|
|
@ -91,6 +91,8 @@ void Serializer::rewind()
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
size_t Serializer::size() const
|
||||
{
|
||||
myStream->seekp(0, std::ios::end);
|
||||
|
||||
return myStream->tellp();
|
||||
}
|
||||
|
||||
|
|
|
@ -145,6 +145,7 @@ Settings::Settings()
|
|||
setPermanent("launcherres", Common::Size(900, 600));
|
||||
setPermanent("launcherfont", "medium");
|
||||
setPermanent("launcherroms", "true");
|
||||
setPermanent("launchersubdirs", "false");
|
||||
setPermanent("romviewer", "1");
|
||||
setPermanent("lastrom", "");
|
||||
|
||||
|
@ -542,6 +543,7 @@ void Settings::usage() const
|
|||
<< " large12|large14|\n"
|
||||
<< " large16>\n"
|
||||
<< " -launcherroms <1|0> Show only ROMs in the launcher (vs. all files)\n"
|
||||
<< " -launchersubdirs <1|0> Show files from subdirectories too\n"
|
||||
<< " -romviewer <float> Show ROM info viewer at given zoom level in ROM\n"
|
||||
<< " launcher (use 0 for off)\n"
|
||||
<< " -followlauncher <0|1> Default ROM path follows launcher navigation\n"
|
||||
|
|
|
@ -184,7 +184,7 @@ void TIASurface::setNTSC(NTSCFilter::Preset preset, bool show)
|
|||
}
|
||||
myOSystem.settings().setValue("tv.filter", int(preset));
|
||||
|
||||
if(show) myFB.showMessage(buf.str());
|
||||
if(show) myFB.showTextMessage(buf.str());
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -221,7 +221,7 @@ void TIASurface::setNTSCAdjustable(int direction)
|
|||
|
||||
setNTSC(NTSCFilter::Preset::CUSTOM);
|
||||
ntsc().selectAdjustable(direction, text, valueText, value);
|
||||
myOSystem.frameBuffer().showMessage(text, valueText, value);
|
||||
myOSystem.frameBuffer().showGaugeMessage(text, valueText, value);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -232,7 +232,7 @@ void TIASurface::changeNTSCAdjustable(int adjustable, int direction)
|
|||
|
||||
setNTSC(NTSCFilter::Preset::CUSTOM);
|
||||
ntsc().changeAdjustable(adjustable, direction, text, valueText, newValue);
|
||||
myOSystem.frameBuffer().showMessage(text, valueText, newValue);
|
||||
myOSystem.frameBuffer().showGaugeMessage(text, valueText, newValue);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -243,7 +243,7 @@ void TIASurface::changeCurrentNTSCAdjustable(int direction)
|
|||
|
||||
setNTSC(NTSCFilter::Preset::CUSTOM);
|
||||
ntsc().changeCurrentAdjustable(direction, text, valueText, newValue);
|
||||
myOSystem.frameBuffer().showMessage(text, valueText, newValue);
|
||||
myOSystem.frameBuffer().showGaugeMessage(text, valueText, newValue);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -259,7 +259,7 @@ void TIASurface::setScanlineIntensity(int direction)
|
|||
buf << intensity << "%";
|
||||
else
|
||||
buf << "Off";
|
||||
myFB.showMessage("Scanline intensity", buf.str(), intensity);
|
||||
myFB.showGaugeMessage("Scanline intensity", buf.str(), intensity);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -67,11 +67,12 @@ AboutDialog::AboutDialog(OSystem& osystem, DialogContainer& parent,
|
|||
addCancelWidget(b);
|
||||
|
||||
xpos = HBORDER; ypos = _th + VBORDER + (buttonHeight - fontHeight) / 2;
|
||||
myTitle = new StaticTextWidget(this, font, xpos, ypos, _w - xpos * 2, fontHeight,
|
||||
"", TextAlign::Center);
|
||||
int bwidth = font.getStringWidth("What's New" + ELLIPSIS) + fontWidth * 2.5;
|
||||
|
||||
myTitle = new StaticTextWidget(this, font, xpos + bwidth, ypos, _w - (xpos + bwidth) * 2,
|
||||
fontHeight, "", TextAlign::Center);
|
||||
myTitle->setTextColor(kTextColorEm);
|
||||
|
||||
int bwidth = font.getStringWidth("What's New" + ELLIPSIS) + fontWidth * 2.5;
|
||||
myWhatsNewButton =
|
||||
new ButtonWidget(this, font, _w - HBORDER - bwidth, ypos - (buttonHeight - fontHeight) / 2,
|
||||
bwidth, buttonHeight, "What's New" + ELLIPSIS, kWhatsNew);
|
||||
|
|
|
@ -46,20 +46,6 @@ CheckListWidget::CheckListWidget(GuiObject* boss, const GUI::Font& font,
|
|||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CheckListWidget::handleMouseEntered()
|
||||
{
|
||||
setFlags(Widget::FLAG_HILITED);
|
||||
setDirty();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CheckListWidget::handleMouseLeft()
|
||||
{
|
||||
clearFlags(Widget::FLAG_HILITED);
|
||||
setDirty();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CheckListWidget::setList(const StringList& list, const BoolArray& state)
|
||||
{
|
||||
|
@ -95,7 +81,6 @@ void CheckListWidget::drawWidget(bool hilite)
|
|||
{
|
||||
//cerr << "CheckListWidget::drawWidget\n";
|
||||
FBSurface& s = _boss->dialog().surface();
|
||||
bool onTop = _boss->dialog().isOnTop();
|
||||
int i, pos, len = int(_list.size());
|
||||
|
||||
// Draw a thin frame around the list and to separate columns
|
||||
|
@ -126,18 +111,17 @@ void CheckListWidget::drawWidget(bool hilite)
|
|||
}
|
||||
else
|
||||
s.frameRect(_x + r.x() - 3, _y + 1 + _lineHeight * i,
|
||||
_w - r.x(), _lineHeight, onTop ? kTextColorHi : kColor);
|
||||
_w - r.x(), _lineHeight, kTextColorHi);
|
||||
}
|
||||
|
||||
if (_selectedItem == pos && _editMode)
|
||||
{
|
||||
adjustOffset();
|
||||
s.drawString(_font, editString(), _x + r.x(), y, r.w(), onTop ? kTextColor : kColor,
|
||||
s.drawString(_font, editString(), _x + r.x(), y, r.w(), kTextColor,
|
||||
TextAlign::Left, -_editScrollOffset, false);
|
||||
}
|
||||
else
|
||||
s.drawString(_font, _list[pos], _x + r.x(), y, r.w(),
|
||||
onTop ? textColor : kColor);
|
||||
s.drawString(_font, _list[pos], _x + r.x(), y, r.w(), textColor);
|
||||
}
|
||||
|
||||
// Only draw the caret while editing, and if it's in the current viewport
|
||||
|
|
|
@ -42,10 +42,6 @@ class CheckListWidget : public ListWidget
|
|||
bool getState(int line);
|
||||
bool getSelectedState() { return getState(_selectedItem); }
|
||||
|
||||
protected:
|
||||
void handleMouseEntered() override;
|
||||
void handleMouseLeft() override;
|
||||
|
||||
private:
|
||||
bool handleEvent(Event::Type e) override;
|
||||
void handleCommand(CommandSender* sender, int cmd, int data, int id) override;
|
||||
|
|
|
@ -36,16 +36,28 @@ ColorWidget::ColorWidget(GuiObject* boss, const GUI::Font& font,
|
|||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void ColorWidget::setColor(ColorId color)
|
||||
{
|
||||
if(_color != color)
|
||||
{
|
||||
_color = color;
|
||||
setDirty();
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void ColorWidget::setCrossed(bool enable)
|
||||
{
|
||||
if(_crossGrid != enable)
|
||||
{
|
||||
_crossGrid = enable;
|
||||
setDirty();
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void ColorWidget::drawWidget(bool hilite)
|
||||
{
|
||||
FBSurface& s = dialog().surface();
|
||||
bool onTop = _boss->dialog().isOnTop();
|
||||
|
||||
if(_framed)
|
||||
{
|
||||
|
@ -53,11 +65,11 @@ void ColorWidget::drawWidget(bool hilite)
|
|||
s.frameRect(_x, _y, _w, _h + 1, kColor);
|
||||
|
||||
// Show the currently selected color
|
||||
s.fillRect(_x + 1, _y + 1, _w - 2, _h - 1, onTop ? isEnabled() ? _color : kWidColor : kBGColorLo);
|
||||
s.fillRect(_x + 1, _y + 1, _w - 2, _h - 1, isEnabled() ? _color : kWidColor);
|
||||
}
|
||||
else
|
||||
{
|
||||
s.fillRect(_x, _y, _w, _h, onTop ? isEnabled() ? _color : kWidColor : kBGColorLo);
|
||||
s.fillRect(_x, _y, _w, _h, isEnabled() ? _color : kWidColor);
|
||||
}
|
||||
|
||||
// Cross out the grid?
|
||||
|
|
|
@ -42,7 +42,7 @@ class ColorWidget : public Widget, public CommandSender
|
|||
void setColor(ColorId color);
|
||||
ColorId getColor() const { return _color; }
|
||||
|
||||
void setCrossed(bool enable) { _crossGrid = enable; }
|
||||
void setCrossed(bool enable);
|
||||
|
||||
protected:
|
||||
void drawWidget(bool hilite) override;
|
||||
|
|
|
@ -77,7 +77,7 @@ void ContextMenu::show(uInt32 x, uInt32 y, const Common::Rect& bossRect, int ite
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void ContextMenu::center()
|
||||
void ContextMenu::setPosition()
|
||||
{
|
||||
// First set position according to original coordinates
|
||||
surface().setDstPos(_xorig, _yorig);
|
||||
|
@ -346,9 +346,13 @@ int ContextMenu::findItem(int x, int y) const
|
|||
void ContextMenu::drawCurrentSelection(int item)
|
||||
{
|
||||
// Change selection
|
||||
if(_selectedOffset != item)
|
||||
{
|
||||
_selectedOffset = item;
|
||||
cerr << "ContextMenu" << endl;
|
||||
setDirty();
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void ContextMenu::sendSelection()
|
||||
|
@ -621,5 +625,5 @@ void ContextMenu::drawDialog()
|
|||
s.drawBitmap(_downImg, ((_w-_x)>>1)-4, (_rowHeight>>1)+y-4, _scrollDnColor, _arrowSize);
|
||||
}
|
||||
|
||||
setDirty();
|
||||
clearDirty();
|
||||
}
|
||||
|
|
|
@ -45,6 +45,8 @@ class ContextMenu : public Dialog, public CommandSender
|
|||
const VariantList& items, int cmd = 0, int width = 0);
|
||||
~ContextMenu() override = default;
|
||||
|
||||
bool isShading() const override { return false; }
|
||||
|
||||
/** Set the parent widget's ID */
|
||||
void setID(uInt32 id) { _id = id; }
|
||||
|
||||
|
@ -71,8 +73,8 @@ class ContextMenu : public Dialog, public CommandSender
|
|||
const string& getSelectedName() const;
|
||||
const Variant& getSelectedTag() const;
|
||||
|
||||
/** This dialog uses its own positioning, so we override Dialog::center() */
|
||||
void center() override;
|
||||
/** This dialog uses its own positioning, so we override Dialog::setPosition() */
|
||||
void setPosition() override;
|
||||
|
||||
/** The following methods are used when we want to select *and*
|
||||
send a command for the new selection. They are only to be used
|
||||
|
|
|
@ -115,10 +115,11 @@ void DeveloperDialog::addEmulationTab(const GUI::Font& font)
|
|||
"Console info overlay");
|
||||
wid.push_back(myFrameStatsWidget);
|
||||
|
||||
|
||||
myDetectedInfoWidget = new CheckboxWidget(myTab, font,
|
||||
myFrameStatsWidget->getRight() + fontWidth * 2.5, ypos + 1,
|
||||
"Detected settings info");
|
||||
myDetectedInfoWidget->setToolTip("Display detected controllers, bankswitching\n"
|
||||
"and TV types at ROM start.");
|
||||
wid.push_back(myDetectedInfoWidget);
|
||||
ypos += lineHeight + VGAP;
|
||||
|
||||
|
@ -131,6 +132,8 @@ void DeveloperDialog::addEmulationTab(const GUI::Font& font)
|
|||
|
||||
myConsoleWidget = new PopUpWidget(myTab, font, HBORDER + INDENT * 1, ypos, pwidth, lineHeight, items,
|
||||
"Console ", lwidth, kConsole);
|
||||
myConsoleWidget->setToolTip("Emulate Color/B&W/Pause key and zero\n"
|
||||
"page RAM initialization differenly.");
|
||||
wid.push_back(myConsoleWidget);
|
||||
ypos += lineHeight + VGAP;
|
||||
|
||||
|
@ -141,6 +144,8 @@ void DeveloperDialog::addEmulationTab(const GUI::Font& font)
|
|||
|
||||
myRandomBankWidget = new CheckboxWidget(myTab, font, HBORDER + INDENT * 2, ypos + 1,
|
||||
"Random startup bank");
|
||||
myRandomBankWidget->setToolTip("Randomize the startup bank for\n"
|
||||
"most classic bankswitching types.");
|
||||
wid.push_back(myRandomBankWidget);
|
||||
ypos += lineHeight + VGAP;
|
||||
|
||||
|
@ -168,17 +173,23 @@ void DeveloperDialog::addEmulationTab(const GUI::Font& font)
|
|||
// How to handle undriven TIA pins
|
||||
myUndrivenPinsWidget = new CheckboxWidget(myTab, font, HBORDER + INDENT * 1, ypos + 1,
|
||||
"Drive unused TIA pins randomly on a read/peek");
|
||||
myUndrivenPinsWidget->setToolTip("Read TIA pins random instead of last databus values.\n"
|
||||
"Helps detecting missing '#' for immediate loads.");
|
||||
wid.push_back(myUndrivenPinsWidget);
|
||||
ypos += lineHeight + VGAP;
|
||||
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
myRWPortBreakWidget = new CheckboxWidget(myTab, font, HBORDER + INDENT * 1, ypos + 1,
|
||||
"Break on reads from write ports");
|
||||
myRWPortBreakWidget->setToolTip("Cause reads from write ports to interrupt\n"
|
||||
"emulation and enter debugger.");
|
||||
wid.push_back(myRWPortBreakWidget);
|
||||
ypos += lineHeight + VGAP;
|
||||
|
||||
myWRPortBreakWidget = new CheckboxWidget(myTab, font, HBORDER + INDENT * 1, ypos + 1,
|
||||
"Break on writes to read ports");
|
||||
myWRPortBreakWidget->setToolTip("Cause writes to read ports to interrupt\n"
|
||||
"emulation and enter debugger.");
|
||||
wid.push_back(myWRPortBreakWidget);
|
||||
ypos += lineHeight + VGAP;
|
||||
#endif
|
||||
|
@ -186,12 +197,16 @@ void DeveloperDialog::addEmulationTab(const GUI::Font& font)
|
|||
// Thumb ARM emulation exception
|
||||
myThumbExceptionWidget = new CheckboxWidget(myTab, font, HBORDER + INDENT * 1, ypos + 1,
|
||||
"Fatal ARM emulation error throws exception");
|
||||
myThumbExceptionWidget->setToolTip("Cause Thumb ARM emulation to throw exceptions\n"
|
||||
"on fatal errors and enter the debugger.");
|
||||
wid.push_back(myThumbExceptionWidget);
|
||||
ypos += lineHeight + VGAP;
|
||||
|
||||
// AtariVox/SaveKey EEPROM access
|
||||
myEEPROMAccessWidget = new CheckboxWidget(myTab, font, HBORDER + INDENT * 1, ypos + 1,
|
||||
"Display AtariVox/SaveKey EEPROM R/W access");
|
||||
myEEPROMAccessWidget->setToolTip("Cause message display when AtariVox/\n"
|
||||
"SaveKey EEPROM is read or written.");
|
||||
wid.push_back(myEEPROMAccessWidget);
|
||||
|
||||
// Add items for tab 0
|
||||
|
@ -239,11 +254,15 @@ void DeveloperDialog::addTiaTab(const GUI::Font& font)
|
|||
VarList::push_back(items, "Custom", "custom");
|
||||
myTIATypeWidget = new PopUpWidget(myTab, font, HBORDER + INDENT, ypos - 1,
|
||||
pwidth, lineHeight, items, "Chip type ", 0, kTIAType);
|
||||
myTIATypeWidget->setToolTip("Select which TIA chip type to emulate.\n"
|
||||
"Some types cause defined glitches.");
|
||||
wid.push_back(myTIATypeWidget);
|
||||
ypos += lineHeight + VGAP * 1;
|
||||
|
||||
myInvPhaseLabel = new StaticTextWidget(myTab, font, HBORDER + INDENT * 2, ypos + 1,
|
||||
"Inverted HMOVE clock phase for");
|
||||
myInvPhaseLabel->setToolTip("Objects react different to too\n"
|
||||
"early HM" + ELLIPSIS + " after HMOVE changes.");
|
||||
wid.push_back(myInvPhaseLabel);
|
||||
ypos += lineHeight + VGAP * 1;
|
||||
|
||||
|
@ -262,6 +281,7 @@ void DeveloperDialog::addTiaTab(const GUI::Font& font)
|
|||
|
||||
myPlayfieldLabel = new StaticTextWidget(myTab, font, HBORDER + INDENT * 2, ypos + 1,
|
||||
"Delayed playfield");
|
||||
myPlayfieldLabel->setToolTip("Playfield reacts one color clock slower to updates.");
|
||||
wid.push_back(myPlayfieldLabel);
|
||||
ypos += lineHeight + VGAP * 1;
|
||||
|
||||
|
@ -275,6 +295,7 @@ void DeveloperDialog::addTiaTab(const GUI::Font& font)
|
|||
|
||||
myBackgroundLabel = new StaticTextWidget(myTab, font, HBORDER + INDENT * 2, ypos + 1,
|
||||
"Delayed background");
|
||||
myBackgroundLabel->setToolTip("Background color reacts one color clock slower to updates.");
|
||||
wid.push_back(myBackgroundLabel);
|
||||
ypos += lineHeight + VGAP * 1;
|
||||
|
||||
|
@ -285,6 +306,7 @@ void DeveloperDialog::addTiaTab(const GUI::Font& font)
|
|||
ostringstream ss;
|
||||
ss << "Delayed VDEL" << ELLIPSIS << " swap for";
|
||||
mySwapLabel = new StaticTextWidget(myTab, font, HBORDER + INDENT * 2, ypos + 1, ss.str());
|
||||
mySwapLabel->setToolTip("VDELed objects react one color clock slower to updates.");
|
||||
wid.push_back(mySwapLabel);
|
||||
ypos += lineHeight + VGAP * 1;
|
||||
|
||||
|
@ -332,12 +354,14 @@ void DeveloperDialog::addVideoTab(const GUI::Font& font)
|
|||
// TV jitter effect
|
||||
myTVJitterWidget = new CheckboxWidget(myTab, font, HBORDER + INDENT * 1, ypos + 1,
|
||||
"Jitter/roll effect", kTVJitter);
|
||||
myTVJitterWidget->setToolTip("Enable to emulate TV loss of sync.");
|
||||
wid.push_back(myTVJitterWidget);
|
||||
myTVJitterRecWidget = new SliderWidget(myTab, font,
|
||||
myTVJitterWidget->getRight() + fontWidth * 3, ypos - 1,
|
||||
"Recovery ", 0, kTVJitterChanged);
|
||||
myTVJitterRecWidget->setMinValue(1); myTVJitterRecWidget->setMaxValue(20);
|
||||
myTVJitterRecWidget->setTickmarkIntervals(5);
|
||||
myTVJitterRecWidget->setToolTip("Define speed of sync recovery.");
|
||||
wid.push_back(myTVJitterRecWidget);
|
||||
myTVJitterRecLabelWidget = new StaticTextWidget(myTab, font,
|
||||
myTVJitterRecWidget->getRight() + 4,
|
||||
|
@ -347,6 +371,8 @@ void DeveloperDialog::addVideoTab(const GUI::Font& font)
|
|||
|
||||
myColorLossWidget = new CheckboxWidget(myTab, font, HBORDER + INDENT * 1, ypos + 1,
|
||||
"PAL color-loss");
|
||||
myColorLossWidget->setToolTip("PAL games with odd scanline count\n"
|
||||
"will be displayed without color.");
|
||||
wid.push_back(myColorLossWidget);
|
||||
ypos += lineHeight + VGAP;
|
||||
|
||||
|
@ -485,6 +511,7 @@ void DeveloperDialog::addTimeMachineTab(const GUI::Font& font)
|
|||
#endif
|
||||
myStateSizeWidget->setStepValue(20);
|
||||
myStateSizeWidget->setTickmarkIntervals(5);
|
||||
myStateSizeWidget->setToolTip("Define the total Time Machine buffer size.");
|
||||
wid.push_back(myStateSizeWidget);
|
||||
ypos += lineHeight + VGAP;
|
||||
|
||||
|
@ -498,6 +525,9 @@ void DeveloperDialog::addTimeMachineTab(const GUI::Font& font)
|
|||
#endif
|
||||
myUncompressedWidget->setStepValue(20);
|
||||
myUncompressedWidget->setTickmarkIntervals(5);
|
||||
myUncompressedWidget->setToolTip("Define the number of completely kept states.\n"
|
||||
"States beyond this number will be slowly removed\n"
|
||||
"to fit the requested horizon into the buffer.");
|
||||
wid.push_back(myUncompressedWidget);
|
||||
ypos += lineHeight + VGAP;
|
||||
|
||||
|
@ -507,6 +537,7 @@ void DeveloperDialog::addTimeMachineTab(const GUI::Font& font)
|
|||
int pwidth = font.getStringWidth("10 seconds");
|
||||
myStateIntervalWidget = new PopUpWidget(myTab, font, xpos, ypos, pwidth,
|
||||
lineHeight, items, "Interval ", 0, kIntervalChanged);
|
||||
myStateIntervalWidget->setToolTip("Define the interval between each saved state.");
|
||||
wid.push_back(myStateIntervalWidget);
|
||||
ypos += lineHeight + VGAP;
|
||||
|
||||
|
@ -515,6 +546,8 @@ void DeveloperDialog::addTimeMachineTab(const GUI::Font& font)
|
|||
VarList::push_back(items, HORIZONS[i], HOR_SETTINGS[i]);
|
||||
myStateHorizonWidget = new PopUpWidget(myTab, font, xpos, ypos, pwidth,
|
||||
lineHeight, items, "Horizon ~ ", 0, kHorizonChanged);
|
||||
myStateHorizonWidget->setToolTip("Define how far the Time Machine\n"
|
||||
"will allow moving back in time.");
|
||||
wid.push_back(myStateHorizonWidget);
|
||||
|
||||
// Add message concerning usage
|
||||
|
@ -598,6 +631,7 @@ void DeveloperDialog::addDebuggerTab(const GUI::Font& font)
|
|||
|
||||
myGhostReadsTrapWidget = new CheckboxWidget(myTab, font, HBORDER, ypos + 1,
|
||||
"Trap on 'ghost' reads");
|
||||
myGhostReadsTrapWidget->setToolTip("Traps will consider CPU 'ghost' reads too.");
|
||||
wid.push_back(myGhostReadsTrapWidget);
|
||||
|
||||
// Add message concerning usage
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "Dialog.hxx"
|
||||
#include "Widget.hxx"
|
||||
#include "TabWidget.hxx"
|
||||
#include "ToolTip.hxx"
|
||||
|
||||
#include "ContextMenu.hxx"
|
||||
#include "PopUpWidget.hxx"
|
||||
|
@ -49,10 +50,24 @@ Dialog::Dialog(OSystem& instance, DialogContainer& parent, const GUI::Font& font
|
|||
const string& title, int x, int y, int w, int h)
|
||||
: GuiObject(instance, parent, *this, x, y, w, h),
|
||||
_font(font),
|
||||
_title(title),
|
||||
_flags(Widget::FLAG_ENABLED | Widget::FLAG_BORDER | Widget::FLAG_CLEARBG)
|
||||
_title(title)
|
||||
{
|
||||
_flags = Widget::FLAG_ENABLED | Widget::FLAG_BORDER | Widget::FLAG_CLEARBG;
|
||||
setTitle(title);
|
||||
|
||||
// Create shading surface
|
||||
uInt32 data = 0xff000000;
|
||||
|
||||
_shadeSurface = instance.frameBuffer().allocateSurface(
|
||||
1, 1, ScalingInterpolation::sharp, &data);
|
||||
|
||||
FBSurface::Attributes& attr = _shadeSurface->attributes();
|
||||
|
||||
attr.blending = true;
|
||||
attr.blendalpha = 25; // darken background dialogs by 25%
|
||||
_shadeSurface->applyAttributes();
|
||||
|
||||
_toolTip = make_unique<ToolTip>(*this, font);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -91,7 +106,7 @@ void Dialog::open()
|
|||
const uInt32 scale = instance().frameBuffer().hidpiScaleFactor();
|
||||
_surface->setDstSize(_w * scale, _h * scale);
|
||||
|
||||
center();
|
||||
setPosition();
|
||||
|
||||
if(_myTabList.size())
|
||||
// (Re)-build the focus list to use for all widgets of all tabs
|
||||
|
@ -110,8 +125,6 @@ void Dialog::open()
|
|||
loadConfig(); // has to be done AFTER (re)building the focus list
|
||||
|
||||
_visible = true;
|
||||
|
||||
setDirty();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -128,7 +141,6 @@ void Dialog::close()
|
|||
_visible = false;
|
||||
|
||||
parent().removeDialog();
|
||||
setDirty();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -144,11 +156,36 @@ void Dialog::setTitle(const string& title)
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Dialog::center()
|
||||
void Dialog::setPosition()
|
||||
{
|
||||
positionAt(instance().settings().getInt("dialogpos"));
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Dialog::setDirty()
|
||||
{
|
||||
_dirty = true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Dialog::setDirtyChain()
|
||||
{
|
||||
_dirtyChain = true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Dialog::tick()
|
||||
{
|
||||
// Recursively tick dialog and all child dialogs and widgets
|
||||
Widget* w = _firstWidget;
|
||||
|
||||
while(w)
|
||||
{
|
||||
w->tick();
|
||||
w = w->_next;
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Dialog::positionAt(uInt32 pos)
|
||||
{
|
||||
|
@ -190,14 +227,24 @@ void Dialog::positionAt(uInt32 pos)
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool Dialog::render()
|
||||
void Dialog::redraw(bool force)
|
||||
{
|
||||
if(!_dirty || !isVisible())
|
||||
return false;
|
||||
if(!isVisible())
|
||||
return;
|
||||
|
||||
if(force)
|
||||
setDirty();
|
||||
|
||||
// Draw this dialog
|
||||
center();
|
||||
setPosition();
|
||||
drawDialog();
|
||||
// full rendering is caused in dialog container
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Dialog::render()
|
||||
{
|
||||
//cerr << " render " << typeid(*this).name() << endl;
|
||||
|
||||
// Update dialog surface; also render any extra surfaces
|
||||
// Extra surfaces must be rendered afterwards, so they are drawn on top
|
||||
|
@ -207,9 +254,22 @@ bool Dialog::render()
|
|||
surface->render();
|
||||
});
|
||||
}
|
||||
_dirty = false;
|
||||
|
||||
return true;
|
||||
// A dialog is still on top if a non-shading dialog (e.g. ContextMenu)
|
||||
// is opended above it.
|
||||
bool onTop = parent().myDialogStack.top() == this
|
||||
|| (parent().myDialogStack.get(parent().myDialogStack.size() - 2) == this
|
||||
&& !parent().myDialogStack.top()->isShading());
|
||||
|
||||
if(!onTop)
|
||||
{
|
||||
//cerr << " shade " << typeid(*this).name() << endl;
|
||||
|
||||
_shadeSurface->setDstRect(_surface->dstRect());
|
||||
_shadeSurface->render();
|
||||
}
|
||||
|
||||
_toolTip->render();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -305,7 +365,7 @@ void Dialog::setFocus(Widget* w)
|
|||
{
|
||||
// If the click occured inside a widget which is not the currently
|
||||
// focused one, change the focus to that widget.
|
||||
if(w && w != _focusedWidget && w->wantsFocus())
|
||||
if(w && w != _focusedWidget && w->wantsFocus() && w->isEnabled())
|
||||
{
|
||||
// Redraw widgets for new focus
|
||||
_focusedWidget = Widget::setFocusForChain(this, getFocusList(), w, 0);
|
||||
|
@ -371,39 +431,43 @@ void Dialog::drawDialog()
|
|||
|
||||
FBSurface& s = surface();
|
||||
|
||||
// Dialog is still on top if e.g a ContextMenu is opened
|
||||
_onTop = parent().myDialogStack.top() == this
|
||||
|| (parent().myDialogStack.get(parent().myDialogStack.size() - 2) == this
|
||||
&& !parent().myDialogStack.top()->hasTitle());
|
||||
if(isDirty())
|
||||
{
|
||||
cerr << endl << "d";
|
||||
//cerr << "*** draw dialog " << typeid(*this).name() << " ***" << endl;
|
||||
|
||||
if(_flags & Widget::FLAG_CLEARBG)
|
||||
if(clearsBackground())
|
||||
{
|
||||
// cerr << "Dialog::drawDialog(): w = " << _w << ", h = " << _h << " @ " << &s << endl << endl;
|
||||
s.fillRect(_x, _y + _th, _w, _h - _th, _onTop ? kDlgColor : kBGColorLo);
|
||||
|
||||
if(hasBackground())
|
||||
s.fillRect(_x, _y + _th, _w, _h - _th, kDlgColor);
|
||||
else
|
||||
s.invalidateRect(_x, _y + _th, _w, _h - _th);
|
||||
if(_th)
|
||||
{
|
||||
s.fillRect(_x, _y, _w, _th, _onTop ? kColorTitleBar : kColorTitleBarLo);
|
||||
s.fillRect(_x, _y, _w, _th, kColorTitleBar);
|
||||
s.drawString(_font, _title, _x + _font.getMaxCharWidth() * 1.25, _y + _font.getFontHeight() / 6,
|
||||
_font.getStringWidth(_title),
|
||||
_onTop ? kColorTitleText : kColorTitleTextLo);
|
||||
_font.getStringWidth(_title), kColorTitleText);
|
||||
}
|
||||
}
|
||||
else {
|
||||
s.invalidate();
|
||||
//cerr << "invalidate " << typeid(*this).name() << endl;
|
||||
}
|
||||
if(hasBorder()) // currently only used by Dialog itself
|
||||
s.frameRect(_x, _y, _w, _h, kColor);
|
||||
|
||||
// Make all child widgets dirty
|
||||
Widget::setDirtyInChain(_firstWidget);
|
||||
|
||||
clearDirty();
|
||||
}
|
||||
else
|
||||
s.invalidate();
|
||||
if(_flags & Widget::FLAG_BORDER) // currently only used by Dialog itself
|
||||
s.frameRect(_x, _y, _w, _h, _onTop ? kColor : kShadowColor);
|
||||
|
||||
// Make all child widget dirty
|
||||
Widget* w = _firstWidget;
|
||||
Widget::setDirtyInChain(w);
|
||||
cerr << endl;
|
||||
|
||||
// Draw all children
|
||||
w = _firstWidget;
|
||||
while(w)
|
||||
{
|
||||
w->draw();
|
||||
w = w->_next;
|
||||
}
|
||||
drawChain();
|
||||
|
||||
// Draw outlines for focused widgets
|
||||
// Don't change focus, since this will trigger lost and received
|
||||
|
@ -412,8 +476,25 @@ void Dialog::drawDialog()
|
|||
{
|
||||
_focusedWidget = Widget::setFocusForChain(this, getFocusList(),
|
||||
_focusedWidget, 0, false);
|
||||
if(_focusedWidget)
|
||||
_focusedWidget->draw(); // make sure the highlight color is drawn initially
|
||||
//if(_focusedWidget)
|
||||
// _focusedWidget->draw(); // make sure the highlight color is drawn initially
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Dialog::drawChain()
|
||||
{
|
||||
// Clear chain *before* drawing, because some widgets may set it again when
|
||||
// being drawn (e.g. RomListWidget)
|
||||
clearDirtyChain();
|
||||
|
||||
Widget* w = _firstWidget;
|
||||
|
||||
while(w)
|
||||
{
|
||||
if(w->needsRedraw())
|
||||
w->draw();
|
||||
w = w->_next;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -430,6 +511,8 @@ void Dialog::handleKeyDown(StellaKey key, StellaMod mod, bool repeated)
|
|||
{
|
||||
Event::Type e = Event::NoType;
|
||||
|
||||
tooltip().hide();
|
||||
|
||||
// FIXME - I don't think this will compile!
|
||||
#if defined(RETRON77)
|
||||
// special keys used for R77
|
||||
|
@ -556,6 +639,11 @@ void Dialog::handleMouseMoved(int x, int y)
|
|||
|
||||
if (w && (w->getFlags() & Widget::FLAG_TRACK_MOUSE))
|
||||
w->handleMouseMoved(x - (w->getAbsX() - _x), y - (w->getAbsY() - _y));
|
||||
|
||||
#ifndef RETRON77
|
||||
// Update mouse coordinates for tooltips
|
||||
_toolTip->update(_mouseWidget, Common::Point(x, y));
|
||||
#endif
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -26,6 +26,7 @@ class OSystem;
|
|||
class DialogContainer;
|
||||
class TabWidget;
|
||||
class CommandSender;
|
||||
class ToolTip;
|
||||
|
||||
#include "Stack.hxx"
|
||||
#include "Widget.hxx"
|
||||
|
@ -54,19 +55,20 @@ class Dialog : public GuiObject
|
|||
void close();
|
||||
|
||||
bool isVisible() const override { return _visible; }
|
||||
bool isOnTop() const { return _onTop; }
|
||||
|
||||
virtual void center();
|
||||
virtual void setPosition();
|
||||
virtual void drawDialog();
|
||||
virtual void loadConfig() { }
|
||||
virtual void saveConfig() { }
|
||||
virtual void setDefaults() { }
|
||||
|
||||
// A dialog being dirty indicates that its underlying surface needs to be
|
||||
// redrawn and then re-rendered; this is taken care of in ::render()
|
||||
void setDirty() override { _dirty = true; }
|
||||
bool isDirty() const { return _dirty; }
|
||||
bool render();
|
||||
void setDirty() override;
|
||||
void setDirtyChain() override;
|
||||
void redraw(bool force = false);
|
||||
void drawChain() override;
|
||||
void render();
|
||||
|
||||
void tick() override;
|
||||
|
||||
void addFocusWidget(Widget* w) override;
|
||||
void addToFocusList(WidgetArray& list) override;
|
||||
|
@ -89,13 +91,11 @@ class Dialog : public GuiObject
|
|||
*/
|
||||
void addSurface(const shared_ptr<FBSurface>& surface);
|
||||
|
||||
void setFlags(int flags) { _flags |= flags; setDirty(); }
|
||||
void clearFlags(int flags) { _flags &= ~flags; setDirty(); }
|
||||
int getFlags() const { return _flags; }
|
||||
|
||||
void setTitle(const string& title);
|
||||
bool hasTitle() { return !_title.empty(); }
|
||||
|
||||
virtual bool isShading() const { return true; }
|
||||
|
||||
/**
|
||||
Determine the maximum width/height of a dialog based on the minimum
|
||||
allowable bounds, also taking into account the current window size.
|
||||
|
@ -124,6 +124,8 @@ class Dialog : public GuiObject
|
|||
*/
|
||||
bool shouldResize(uInt32& w, uInt32& h) const;
|
||||
|
||||
ToolTip& tooltip() { return *_toolTip; }
|
||||
|
||||
protected:
|
||||
void draw() override { }
|
||||
void releaseFocus() override;
|
||||
|
@ -197,11 +199,11 @@ class Dialog : public GuiObject
|
|||
Widget* _cancelWidget{nullptr};
|
||||
|
||||
bool _visible{false};
|
||||
bool _onTop{true};
|
||||
bool _processCancel{false};
|
||||
string _title;
|
||||
int _th{0};
|
||||
int _layer{0};
|
||||
unique_ptr<ToolTip> _toolTip;
|
||||
|
||||
Common::FixedStack<shared_ptr<FBSurface>> mySurfaceStack;
|
||||
|
||||
|
@ -232,10 +234,9 @@ class Dialog : public GuiObject
|
|||
|
||||
WidgetArray _buttonGroup;
|
||||
shared_ptr<FBSurface> _surface;
|
||||
shared_ptr<FBSurface> _shadeSurface;
|
||||
|
||||
int _tabID{0};
|
||||
int _flags{0};
|
||||
bool _dirty{false};
|
||||
uInt32 _max_w{0}; // maximum wanted width
|
||||
uInt32 _max_h{0}; // maximum wanted height
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "OSystem.hxx"
|
||||
#include "Dialog.hxx"
|
||||
#include "ToolTip.hxx"
|
||||
#include "Stack.hxx"
|
||||
#include "EventHandler.hxx"
|
||||
#include "FrameBuffer.hxx"
|
||||
|
@ -89,31 +90,53 @@ void DialogContainer::updateTime(uInt64 time)
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool DialogContainer::draw(bool full)
|
||||
void DialogContainer::draw(bool full)
|
||||
{
|
||||
if(myDialogStack.empty())
|
||||
return false;
|
||||
return;
|
||||
|
||||
// Make the top dialog dirty if a full redraw is requested
|
||||
if(full)
|
||||
myDialogStack.top()->setDirty();
|
||||
|
||||
// If the top dialog is dirty, then all below it must be redrawn too
|
||||
const bool dirty = needsRedraw();
|
||||
//cerr << "draw " << full << " " << typeid(*this).name() << endl;
|
||||
|
||||
// Draw and render all dirty dialogs
|
||||
myDialogStack.applyAll([&](Dialog*& d) {
|
||||
if(dirty)
|
||||
d->setDirty();
|
||||
full |= d->render();
|
||||
if(full || d->needsRedraw())
|
||||
d->redraw(full);
|
||||
});
|
||||
// Always render all surfaces, bottom to top
|
||||
render();
|
||||
}
|
||||
|
||||
return full;
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void DialogContainer::tick()
|
||||
{
|
||||
if(!myDialogStack.empty())
|
||||
myDialogStack.top()->tick();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void DialogContainer::render()
|
||||
{
|
||||
if(myDialogStack.empty())
|
||||
return;
|
||||
|
||||
//cerr << "full re-render " << typeid(*this).name() << endl;
|
||||
|
||||
// Make sure we start in a clean state (with zero'ed buffers)
|
||||
if(!myOSystem.eventHandler().inTIAMode())
|
||||
myOSystem.frameBuffer().clear();
|
||||
|
||||
// Render all dialogs
|
||||
myDialogStack.applyAll([&](Dialog*& d) {
|
||||
d->render();
|
||||
});
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool DialogContainer::needsRedraw() const
|
||||
{
|
||||
return !myDialogStack.empty() ? myDialogStack.top()->isDirty() : false;
|
||||
return !myDialogStack.empty()
|
||||
? myDialogStack.top()->needsRedraw()
|
||||
: false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -129,10 +152,14 @@ int DialogContainer::addDialog(Dialog* d)
|
|||
const uInt32 scale = myOSystem.frameBuffer().hidpiScaleFactor();
|
||||
|
||||
if(uInt32(d->getWidth() * scale) > r.w() || uInt32(d->getHeight() * scale) > r.h())
|
||||
myOSystem.frameBuffer().showMessage(
|
||||
"Unable to show dialog box; FIX THE CODE");
|
||||
myOSystem.frameBuffer().showTextMessage(
|
||||
"Unable to show dialog box; FIX THE CODE", MessagePosition::BottomCenter, true);
|
||||
else
|
||||
{
|
||||
// Close all open tooltips
|
||||
if(!myDialogStack.empty())
|
||||
myDialogStack.top()->tooltip().hide();
|
||||
|
||||
d->setDirty();
|
||||
myDialogStack.push(d);
|
||||
}
|
||||
|
@ -144,9 +171,11 @@ void DialogContainer::removeDialog()
|
|||
{
|
||||
if(!myDialogStack.empty())
|
||||
{
|
||||
//cerr << "remove dialog " << typeid(*myDialogStack.top()).name() << endl;
|
||||
myDialogStack.pop();
|
||||
if(!myDialogStack.empty())
|
||||
myDialogStack.top()->setDirty();
|
||||
|
||||
// Inform the frame buffer that it has to render all surfaces
|
||||
myOSystem.frameBuffer().setPendingRender();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -157,6 +186,9 @@ void DialogContainer::reStack()
|
|||
while(!myDialogStack.empty())
|
||||
myDialogStack.top()->close();
|
||||
|
||||
// Make sure that all surfaces are cleared
|
||||
myOSystem.frameBuffer().clear();
|
||||
|
||||
baseDialog()->open();
|
||||
|
||||
// Reset all continuous events
|
||||
|
|
|
@ -120,11 +120,19 @@ class DialogContainer
|
|||
void handleJoyHatEvent(int stick, int hat, JoyHatDir hdir, int button);
|
||||
|
||||
/**
|
||||
Draw the stack of menus (full indicates to redraw all items).
|
||||
|
||||
@return Answers whether any drawing actually occurred.
|
||||
Tick the dialog and all its widgets.
|
||||
*/
|
||||
bool draw(bool full = false);
|
||||
void tick();
|
||||
|
||||
/**
|
||||
Draw the stack of menus (full indicates to redraw all items).
|
||||
*/
|
||||
void draw(bool full = false);
|
||||
|
||||
/**
|
||||
Render the stack of menus.
|
||||
*/
|
||||
void render();
|
||||
|
||||
/**
|
||||
Answers whether a full redraw is required.
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "OSystem.hxx"
|
||||
#include "FBSurface.hxx"
|
||||
#include "Dialog.hxx"
|
||||
#include "ToolTip.hxx"
|
||||
#include "Font.hxx"
|
||||
#include "EditTextWidget.hxx"
|
||||
|
||||
|
@ -45,21 +46,11 @@ void EditTextWidget::setText(const string& str, bool changed)
|
|||
{
|
||||
EditableWidget::setText(str, changed);
|
||||
_backupString = str;
|
||||
if(_changed != changed)
|
||||
{
|
||||
_changed = changed;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void EditTextWidget::handleMouseEntered()
|
||||
{
|
||||
setFlags(Widget::FLAG_HILITED);
|
||||
setDirty();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void EditTextWidget::handleMouseLeft()
|
||||
{
|
||||
clearFlags(Widget::FLAG_HILITED);
|
||||
setDirty();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -89,13 +80,12 @@ void EditTextWidget::handleMouseDown(int x, int y, MouseButton b, int clickCount
|
|||
void EditTextWidget::drawWidget(bool hilite)
|
||||
{
|
||||
FBSurface& s = _boss->dialog().surface();
|
||||
bool onTop = _boss->dialog().isOnTop();
|
||||
|
||||
// Highlight changes
|
||||
if(_changed && onTop)
|
||||
if(_changed)
|
||||
s.fillRect(_x, _y, _w, _h, kDbgChangedColor);
|
||||
else if(!isEditable() || !isEnabled())
|
||||
s.fillRect(_x, _y, _w, _h, onTop ? kDlgColor : kBGColorLo);
|
||||
s.fillRect(_x, _y, _w, _h, kDlgColor);
|
||||
|
||||
// Draw a thin frame around us.
|
||||
s.frameRect(_x, _y, _w, _h, hilite && isEditable() && isEnabled() ? kWidColorHi : kColor);
|
||||
|
@ -103,9 +93,9 @@ void EditTextWidget::drawWidget(bool hilite)
|
|||
// Draw the text
|
||||
adjustOffset();
|
||||
s.drawString(_font, editString(), _x + _textOfs, _y + 2, getEditRect().w(), getEditRect().h(),
|
||||
_changed && onTop && isEnabled()
|
||||
_changed && isEnabled()
|
||||
? kDbgChangedTextColor
|
||||
: onTop && isEnabled() ? _textcolor : kColor,
|
||||
: isEnabled() ? _textcolor : kColor,
|
||||
TextAlign::Left, scrollOffset(), !isEditable());
|
||||
|
||||
// Draw the caret and selection
|
||||
|
|
|
@ -54,8 +54,6 @@ class EditTextWidget : public EditableWidget
|
|||
Common::Rect getEditRect() const override;
|
||||
|
||||
void handleMouseDown(int x, int y, MouseButton b, int clickCount) override;
|
||||
void handleMouseEntered() override;
|
||||
void handleMouseLeft() override;
|
||||
|
||||
protected:
|
||||
string _backupString;
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "OSystem.hxx"
|
||||
#include "EventHandler.hxx"
|
||||
#include "UndoHandler.hxx"
|
||||
#include "ToolTip.hxx"
|
||||
#include "EditableWidget.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -42,14 +43,18 @@ EditableWidget::EditableWidget(GuiObject* boss, const GUI::Font& font,
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void EditableWidget::setText(const string& str, bool)
|
||||
void EditableWidget::setText(const string& str, bool changed)
|
||||
{
|
||||
const string oldEditString = _editString;
|
||||
// Filter input string
|
||||
_editString = "";
|
||||
for(char c: str)
|
||||
if(_filter(tolower(c)))
|
||||
_editString.push_back(c);
|
||||
|
||||
if(oldEditString != _editString)
|
||||
setDirty();
|
||||
|
||||
myUndoHandler->reset();
|
||||
myUndoHandler->doo(_editString);
|
||||
|
||||
|
@ -59,9 +64,29 @@ void EditableWidget::setText(const string& str, bool)
|
|||
_editScrollOffset = (_font.getStringWidth(_editString) - (getEditRect().w()));
|
||||
if (_editScrollOffset < 0)
|
||||
_editScrollOffset = 0;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void EditableWidget::tick()
|
||||
{
|
||||
if(_hasFocus && isEditable() && _editMode && isVisible() && _boss->isVisible())
|
||||
{
|
||||
_caretTimer++;
|
||||
if(_caretTimer > 40) // switch every 2/3rd seconds
|
||||
{
|
||||
_caretTimer = 0;
|
||||
_caretEnabled = !_caretEnabled;
|
||||
setDirty();
|
||||
}
|
||||
}
|
||||
Widget::tick();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool EditableWidget::wantsToolTip() const
|
||||
{
|
||||
return !(_hasFocus && isEditable() && _editMode) && Widget::wantsToolTip();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void EditableWidget::setEditable(bool editable, bool hiliteBG)
|
||||
|
@ -79,6 +104,14 @@ void EditableWidget::setEditable(bool editable, bool hiliteBG)
|
|||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void EditableWidget::receivedFocusWidget()
|
||||
{
|
||||
_caretTimer = 0;
|
||||
_caretEnabled = true;
|
||||
dialog().tooltip().hide();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void EditableWidget::lostFocusWidget()
|
||||
{
|
||||
|
@ -107,7 +140,7 @@ bool EditableWidget::handleText(char text)
|
|||
|
||||
if(tryInsertChar(text, _caretPos))
|
||||
{
|
||||
_caretPos++;
|
||||
setCaretPos(_caretPos + 1);
|
||||
sendCommand(EditableWidget::kChangedCmd, 0, _id);
|
||||
setDirty();
|
||||
return true;
|
||||
|
@ -265,7 +298,7 @@ bool EditableWidget::handleKeyDown(StellaKey key, StellaMod mod)
|
|||
{
|
||||
// Put caret at last difference
|
||||
myUndoHandler->lastDiff(_editString, oldString);
|
||||
_caretPos = myUndoHandler->lastDiff(_editString, oldString);
|
||||
setCaretPos(myUndoHandler->lastDiff(_editString, oldString));
|
||||
_selectSize = 0;
|
||||
sendCommand(EditableWidget::kChangedCmd, key, _id);
|
||||
}
|
||||
|
@ -316,22 +349,16 @@ void EditableWidget::drawCaretSelection()
|
|||
if (!_editable || !isVisible() || !_boss->isVisible() || !_hasFocus)
|
||||
return;
|
||||
|
||||
// Draw the selection
|
||||
if(_selectSize)
|
||||
{
|
||||
FBSurface& s = _boss->dialog().surface();
|
||||
const Common::Rect& editRect = getEditRect();
|
||||
int x = editRect.x();
|
||||
int y = editRect.y();
|
||||
|
||||
x += getCaretOffset();
|
||||
|
||||
x += _x;
|
||||
y += _y;
|
||||
|
||||
FBSurface& s = _boss->dialog().surface();
|
||||
s.vLine(x, y + 2, y + editRect.h() - 2, kTextColorHi);
|
||||
s.vLine(x-1, y + 2, y + editRect.h() - 2, kTextColorHi);
|
||||
|
||||
if(_selectSize)
|
||||
{
|
||||
string text = selectString();
|
||||
|
||||
x = editRect.x();
|
||||
y = editRect.y();
|
||||
int w = editRect.w();
|
||||
|
@ -355,9 +382,27 @@ void EditableWidget::drawCaretSelection()
|
|||
y += _y;
|
||||
|
||||
s.fillRect(x - 1, y + 1, w + 1, h - 3, kTextColorHi);
|
||||
s.drawString(_font, text, x, y + 1, w, h,
|
||||
s.drawString(_font, text, x, y + 1 + _dyText, w, h,
|
||||
kTextColorInv, TextAlign::Left, 0, false);
|
||||
}
|
||||
|
||||
// Draw the caret
|
||||
if(_caretEnabled ^ (_selectSize != 0))
|
||||
{
|
||||
FBSurface& s = _boss->dialog().surface();
|
||||
const Common::Rect& editRect = getEditRect();
|
||||
int x = editRect.x();
|
||||
int y = editRect.y();
|
||||
ColorId color = _caretEnabled ? kTextColorHi : kTextColorInv;
|
||||
|
||||
x += getCaretOffset();
|
||||
x += _x;
|
||||
y += _y;
|
||||
|
||||
s.vLine(x, y + 1, y + editRect.h() - 3, color);
|
||||
s.vLine(x - 1, y + 1, y + editRect.h() - 3, color);
|
||||
clearDirty();
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -366,6 +411,9 @@ bool EditableWidget::setCaretPos(int newPos)
|
|||
assert(newPos >= 0 && newPos <= int(_editString.size()));
|
||||
_caretPos = newPos;
|
||||
|
||||
_caretTimer = 0;
|
||||
_caretEnabled = true;
|
||||
|
||||
return adjustOffset();
|
||||
}
|
||||
|
||||
|
@ -375,6 +423,8 @@ bool EditableWidget::moveCaretPos(int direction)
|
|||
if(setCaretPos(_caretPos + direction))
|
||||
{
|
||||
_selectSize -= direction;
|
||||
_caretTimer = 0;
|
||||
_caretEnabled = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -452,6 +502,7 @@ bool EditableWidget::killChar(int direction, bool addEdit)
|
|||
{
|
||||
myUndoHandler->endChars(_editString);
|
||||
_editString.erase(_caretPos, 1);
|
||||
setCaretPos(_caretPos);
|
||||
|
||||
if(addEdit)
|
||||
myUndoHandler->doo(_editString);
|
||||
|
@ -556,7 +607,7 @@ bool EditableWidget::moveWord(int direction, bool select)
|
|||
if(select)
|
||||
_selectSize++;
|
||||
}
|
||||
_caretPos = currentPos;
|
||||
setCaretPos(currentPos);
|
||||
handled = true;
|
||||
}
|
||||
else if(direction == +1) // move to first character of next word
|
||||
|
@ -575,7 +626,7 @@ bool EditableWidget::moveWord(int direction, bool select)
|
|||
if(select)
|
||||
_selectSize--;
|
||||
}
|
||||
_caretPos = currentPos;
|
||||
setCaretPos(currentPos);
|
||||
handled = true;
|
||||
}
|
||||
|
||||
|
@ -630,6 +681,7 @@ bool EditableWidget::killSelectedText(bool addEdit)
|
|||
_selectSize = -_selectSize;
|
||||
}
|
||||
_editString.erase(_caretPos, _selectSize);
|
||||
setCaretPos(_caretPos);
|
||||
_selectSize = 0;
|
||||
if(addEdit)
|
||||
myUndoHandler->doo(_editString);
|
||||
|
@ -689,7 +741,7 @@ bool EditableWidget::pasteSelectedText()
|
|||
|
||||
_editString.insert(_caretPos, buf.str());
|
||||
// position cursor at the end of pasted text
|
||||
_caretPos += int(buf.str().length());
|
||||
setCaretPos(_caretPos + int(buf.str().length()));
|
||||
|
||||
if(selected || !pasted.empty())
|
||||
{
|
||||
|
|
|
@ -65,7 +65,10 @@ class EditableWidget : public Widget, public CommandSender
|
|||
void setTextFilter(const TextFilter& filter) { _filter = filter; }
|
||||
|
||||
protected:
|
||||
void receivedFocusWidget() override;
|
||||
void lostFocusWidget() override;
|
||||
void tick() override;
|
||||
bool wantsToolTip() const override;
|
||||
|
||||
virtual void startEditMode() { setFlags(Widget::FLAG_WANTS_RAWDATA); }
|
||||
virtual void endEditMode() { clearFlags(Widget::FLAG_WANTS_RAWDATA); }
|
||||
|
@ -110,6 +113,8 @@ class EditableWidget : public Widget, public CommandSender
|
|||
unique_ptr<UndoHandler> myUndoHandler;
|
||||
|
||||
int _caretPos{0};
|
||||
int _caretTimer{0};
|
||||
bool _caretEnabled{true};
|
||||
|
||||
// Size of current selected text
|
||||
// 0 = no selection
|
||||
|
@ -119,6 +124,8 @@ class EditableWidget : public Widget, public CommandSender
|
|||
|
||||
protected:
|
||||
int _editScrollOffset{0};
|
||||
bool _editMode{true};
|
||||
int _dyText{0};
|
||||
|
||||
private:
|
||||
TextFilter _filter;
|
||||
|
|
|
@ -99,6 +99,7 @@ EmulationDialog::EmulationDialog(OSystem& osystem, DialogContainer& parent,
|
|||
|
||||
// Use sync to vblank
|
||||
myUseVSync = new CheckboxWidget(this, _font, xpos, ypos + 1, "VSync");
|
||||
myUseVSync->setToolTip("Check to enable vertical synced display updates.");
|
||||
wid.push_back(myUseVSync);
|
||||
ypos += lineHeight + VGAP;
|
||||
|
||||
|
|
|
@ -97,6 +97,7 @@ EventMappingWidget::EventMappingWidget(GuiObject* boss, const GUI::Font& font,
|
|||
myCancelMapButton = new ButtonWidget(boss, font, xpos, ypos,
|
||||
buttonWidth, buttonHeight,
|
||||
"Cancel", kStopMapCmd);
|
||||
myCancelMapButton->setToolTip("Cancel current mapping.");
|
||||
myCancelMapButton->setTarget(this);
|
||||
myCancelMapButton->clearFlags(Widget::FLAG_ENABLED);
|
||||
addFocusWidget(myCancelMapButton);
|
||||
|
@ -106,12 +107,14 @@ EventMappingWidget::EventMappingWidget(GuiObject* boss, const GUI::Font& font,
|
|||
buttonWidth, buttonHeight,
|
||||
"Erase", kEraseCmd);
|
||||
myEraseButton->setTarget(this);
|
||||
myEraseButton->setToolTip("Erase any mapping for selected event.");
|
||||
addFocusWidget(myEraseButton);
|
||||
|
||||
ypos += buttonHeight + VGAP;
|
||||
myResetButton = new ButtonWidget(boss, font, xpos, ypos,
|
||||
buttonWidth, buttonHeight,
|
||||
"Reset", kResetCmd);
|
||||
myResetButton->setToolTip("Reset mapping for selected event to defaults.");
|
||||
myResetButton->setTarget(this);
|
||||
addFocusWidget(myResetButton);
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "ScrollBarWidget.hxx"
|
||||
#include "FileListWidget.hxx"
|
||||
#include "TimerManager.hxx"
|
||||
#include "ProgressDialog.hxx"
|
||||
|
||||
#include "bspf.hxx"
|
||||
|
||||
|
@ -50,7 +51,7 @@ void FileListWidget::setDirectory(const FilesystemNode& node,
|
|||
|
||||
// Initialize history
|
||||
FilesystemNode tmp = _node;
|
||||
while(tmp.hasParent())
|
||||
while(tmp.hasParent() && !_history.full())
|
||||
{
|
||||
string name = tmp.getName();
|
||||
if(name.back() == '/' || name.back() == '\\')
|
||||
|
@ -72,22 +73,52 @@ void FileListWidget::setDirectory(const FilesystemNode& node,
|
|||
void FileListWidget::setLocation(const FilesystemNode& node,
|
||||
const string& select)
|
||||
{
|
||||
progress().resetProgress();
|
||||
progress().open();
|
||||
FilesystemNode::CancelCheck isCancelled = []() {
|
||||
return myProgressDialog->isCancelled();
|
||||
};
|
||||
|
||||
_node = node;
|
||||
|
||||
// Read in the data from the file system (start with an empty list)
|
||||
_fileList.clear();
|
||||
_fileList.reserve(512);
|
||||
_node.getChildren(_fileList, _fsmode, _filter);
|
||||
|
||||
// Now fill the list widget with the names from the file list
|
||||
if(_includeSubDirs)
|
||||
{
|
||||
// Actually this could become HUGE
|
||||
_fileList.reserve(0x2000);
|
||||
_node.getAllChildren(_fileList, _fsmode, _filter, true, isCancelled);
|
||||
}
|
||||
else
|
||||
{
|
||||
_fileList.reserve(0x200);
|
||||
_node.getChildren(_fileList, _fsmode, _filter, false, true, isCancelled);
|
||||
}
|
||||
|
||||
// Now fill the list widget with the names from the file list,
|
||||
// even if cancelled
|
||||
StringList l;
|
||||
size_t orgLen = node.getShortPath().length();
|
||||
|
||||
_dirList.clear();
|
||||
for(const auto& file : _fileList)
|
||||
{
|
||||
const string path = file.getShortPath();
|
||||
|
||||
l.push_back(file.getName());
|
||||
// display only relative path in tooltip
|
||||
if(path.length() >= orgLen)
|
||||
_dirList.push_back(path.substr(orgLen));
|
||||
else
|
||||
_dirList.push_back(path);
|
||||
}
|
||||
|
||||
setList(l);
|
||||
setSelected(select);
|
||||
|
||||
ListWidget::recalc();
|
||||
|
||||
progress().close();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -114,6 +145,21 @@ void FileListWidget::reload()
|
|||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
ProgressDialog& FileListWidget::progress()
|
||||
{
|
||||
if(myProgressDialog == nullptr)
|
||||
myProgressDialog = make_unique<ProgressDialog>(this, _font, "");
|
||||
|
||||
return *myProgressDialog;
|
||||
}
|
||||
|
||||
void FileListWidget::incProgress()
|
||||
{
|
||||
if(_includeSubDirs)
|
||||
progress().incProgress();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool FileListWidget::handleText(char text)
|
||||
{
|
||||
|
@ -200,5 +246,28 @@ void FileListWidget::handleCommand(CommandSender* sender, int cmd, int data, int
|
|||
setTarget(this);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string FileListWidget::getToolTip(const Common::Point& pos) const
|
||||
{
|
||||
Common::Rect rect = getEditRect();
|
||||
int idx = getToolTipIndex(pos);
|
||||
|
||||
if(idx < 0)
|
||||
return EmptyString;
|
||||
|
||||
if(_includeSubDirs && static_cast<int>(_dirList.size()) > idx)
|
||||
return _toolTipText + _dirList[idx];
|
||||
|
||||
const string value = _list[idx];
|
||||
|
||||
if(uInt32(_font.getStringWidth(value)) > rect.w())
|
||||
return _toolTipText + value;
|
||||
else
|
||||
return _toolTipText;
|
||||
}
|
||||
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt64 FileListWidget::_QUICK_SELECT_DELAY = 300;
|
||||
|
||||
unique_ptr<ProgressDialog> FileListWidget::myProgressDialog{nullptr};
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#define FILE_LIST_WIDGET_HXX
|
||||
|
||||
class CommandSender;
|
||||
class ProgressDialog;
|
||||
|
||||
#include "FSNode.hxx"
|
||||
#include "Stack.hxx"
|
||||
|
@ -52,6 +53,8 @@ class FileListWidget : public StringListWidget
|
|||
int x, int y, int w, int h);
|
||||
~FileListWidget() override = default;
|
||||
|
||||
string getToolTip(const Common::Point& pos) const override;
|
||||
|
||||
/** Determines how to display files/folders; either setDirectory or reload
|
||||
must be called after any of these are called. */
|
||||
void setListMode(FilesystemNode::ListMode mode) { _fsmode = mode; }
|
||||
|
@ -59,6 +62,9 @@ class FileListWidget : public StringListWidget
|
|||
_filter = filter;
|
||||
}
|
||||
|
||||
// When enabled, all subdirectories will be searched too.
|
||||
void setIncludeSubDirs(bool enable) { _includeSubDirs = enable; }
|
||||
|
||||
/**
|
||||
Set initial directory, and optionally select the given item.
|
||||
|
||||
|
@ -83,6 +89,13 @@ class FileListWidget : public StringListWidget
|
|||
const FilesystemNode& currentDir() const { return _node; }
|
||||
|
||||
static void setQuickSelectDelay(uInt64 time) { _QUICK_SELECT_DELAY = time; }
|
||||
uInt64 getQuickSelectDelay() { return _QUICK_SELECT_DELAY; }
|
||||
|
||||
ProgressDialog& progress();
|
||||
void incProgress();
|
||||
|
||||
protected:
|
||||
static unique_ptr<ProgressDialog> myProgressDialog;
|
||||
|
||||
private:
|
||||
/** Very similar to setDirectory(), but also updates the history */
|
||||
|
@ -99,6 +112,9 @@ class FileListWidget : public StringListWidget
|
|||
FilesystemNode::NameFilter _filter;
|
||||
FilesystemNode _node;
|
||||
FSList _fileList;
|
||||
bool _includeSubDirs{false};
|
||||
|
||||
StringList _dirList;
|
||||
|
||||
Common::FixedStack<string> _history;
|
||||
uInt32 _selected{0};
|
||||
|
|
|
@ -855,12 +855,12 @@ void GameInfoDialog::saveCurrentPropertiesToDisk()
|
|||
propfile /= myGameFile.getNameWithExt(".pro");
|
||||
|
||||
propfile.write(out);
|
||||
instance().frameBuffer().showMessage("Properties saved to " +
|
||||
instance().frameBuffer().showTextMessage("Properties saved to " +
|
||||
propfile.getShortPath());
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
instance().frameBuffer().showMessage("Error saving properties");
|
||||
instance().frameBuffer().showTextMessage("Error saving properties");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,21 @@ class GuiObject : public CommandReceiver
|
|||
friend class Widget;
|
||||
friend class DialogContainer;
|
||||
|
||||
public:
|
||||
enum : uInt32 {
|
||||
FLAG_ENABLED = 1 << 0,
|
||||
FLAG_INVISIBLE = 1 << 1,
|
||||
FLAG_HILITED = 1 << 2,
|
||||
FLAG_BORDER = 1 << 3,
|
||||
FLAG_CLEARBG = 1 << 4,
|
||||
FLAG_TRACK_MOUSE = 1 << 5,
|
||||
FLAG_RETAIN_FOCUS = 1 << 6,
|
||||
FLAG_WANTS_TAB = 1 << 7,
|
||||
FLAG_WANTS_RAWDATA = 1 << 8,
|
||||
FLAG_NOBG = 1 << 9,
|
||||
FLAG_MOUSE_FOCUS = 1 << 10
|
||||
};
|
||||
|
||||
public:
|
||||
// The commands generated by various widgets
|
||||
enum {
|
||||
|
@ -77,7 +92,41 @@ class GuiObject : public CommandReceiver
|
|||
virtual void setHeight(int h) { _h = h; }
|
||||
|
||||
virtual bool isVisible() const = 0;
|
||||
|
||||
virtual void setDirty() = 0;
|
||||
virtual void setDirtyChain() = 0;
|
||||
void clearDirty() { _dirty = false; }
|
||||
void clearDirtyChain() { _dirtyChain = false; }
|
||||
bool isDirty() const { return _dirty; }
|
||||
bool isChainDirty() const { return _dirtyChain; }
|
||||
|
||||
// The GUI indicates if its underlying surface needs to be redrawn
|
||||
// and then re-rendered
|
||||
virtual bool needsRedraw() { return isDirty() || isChainDirty(); }
|
||||
|
||||
virtual void tick() = 0;
|
||||
|
||||
void setFlags(uInt32 flags, bool updateDirty = true)
|
||||
{
|
||||
uInt32 oldFlags = _flags;
|
||||
|
||||
_flags |= flags;
|
||||
if(updateDirty && oldFlags != _flags)
|
||||
setDirty();
|
||||
}
|
||||
void clearFlags(uInt32 flags, bool updateDirty = true)
|
||||
{
|
||||
uInt32 oldFlags = _flags;
|
||||
|
||||
_flags &= ~flags;
|
||||
if(updateDirty && oldFlags != _flags)
|
||||
setDirty();
|
||||
}
|
||||
uInt32 getFlags() const { return _flags; }
|
||||
|
||||
bool hasBorder() const { return _flags & FLAG_BORDER; }
|
||||
bool clearsBackground() const { return _flags & FLAG_CLEARBG; }
|
||||
bool hasBackground() const { return !(_flags & FLAG_NOBG); }
|
||||
|
||||
/** Add given widget(s) to the focus list */
|
||||
virtual void addFocusWidget(Widget* w) = 0;
|
||||
|
@ -96,6 +145,7 @@ class GuiObject : public CommandReceiver
|
|||
protected:
|
||||
virtual void releaseFocus() = 0;
|
||||
virtual void draw() = 0;
|
||||
virtual void drawChain() = 0;
|
||||
|
||||
private:
|
||||
OSystem& myOSystem;
|
||||
|
@ -104,6 +154,9 @@ class GuiObject : public CommandReceiver
|
|||
|
||||
protected:
|
||||
int _x{0}, _y{0}, _w{0}, _h{0};
|
||||
bool _dirty{false};
|
||||
bool _dirtyChain{false};
|
||||
uInt32 _flags{0};
|
||||
|
||||
Widget* _firstWidget{nullptr};
|
||||
WidgetArray _focusList;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue