From df95dd0df8926ab8505cd64ef39c105a6388b65a Mon Sep 17 00:00:00 2001 From: Thomas Jentzsch Date: Wed, 10 Aug 2022 08:19:12 +0200 Subject: [PATCH] preparing for #916 --- src/emucore/Bankswitch.cxx | 14 +- src/gui/LauncherDialog.cxx | 21 ++- src/gui/LauncherDialog.hxx | 2 + src/gui/RomImageWidget.cxx | 199 +++++++++++++++++++++++++++++ src/gui/RomImageWidget.hxx | 78 +++++++++++ src/gui/RomInfoWidget.cxx | 110 ++-------------- src/gui/RomInfoWidget.hxx | 21 +-- src/gui/module.mk | 1 + src/windows/Stella.vcxproj | 2 + src/windows/Stella.vcxproj.filters | 6 + 10 files changed, 321 insertions(+), 133 deletions(-) create mode 100644 src/gui/RomImageWidget.cxx create mode 100644 src/gui/RomImageWidget.hxx diff --git a/src/emucore/Bankswitch.cxx b/src/emucore/Bankswitch.cxx index 61d91a498..a1fb614e0 100644 --- a/src/emucore/Bankswitch.cxx +++ b/src/emucore/Bankswitch.cxx @@ -97,13 +97,13 @@ Bankswitch::BSList = {{ { "AUTO" , "Auto-detect" }, { "0840" , "0840 (8K EconoBanking)" }, { "0FA0" , "0FA0 (8K Fotomania)" }, - { "2IN1" , "2IN1 Multicart (4-64K)" }, - { "4IN1" , "4IN1 Multicart (8-64K)" }, - { "8IN1" , "8IN1 Multicart (16-64K)" }, - { "16IN1" , "16IN1 Multicart (32-128K)" }, - { "32IN1" , "32IN1 Multicart (64/128K)" }, - { "64IN1" , "64IN1 Multicart (128/256K)" }, - { "128IN1" , "128IN1 Multicart (256/512K)" }, + { "2IN1" , "2in1 Multicart (4-64K)" }, + { "4IN1" , "4in1 Multicart (8-64K)" }, + { "8IN1" , "8in1 Multicart (16-64K)" }, + { "16IN1" , "16in1 Multicart (32-128K)" }, + { "32IN1" , "32in1 Multicart (64/128K)" }, + { "64IN1" , "64in1 Multicart (128/256K)" }, + { "128IN1" , "128in1 Multicart (256/512K)" }, { "2K" , "2K (32-2048 bytes Atari)" }, { "3E" , "3E (Tigervision, 32K RAM)" }, { "3EX" , "3EX (Tigervision, 256K RAM)" }, diff --git a/src/gui/LauncherDialog.cxx b/src/gui/LauncherDialog.cxx index 128f2eee2..43e31b5a4 100644 --- a/src/gui/LauncherDialog.cxx +++ b/src/gui/LauncherDialog.cxx @@ -45,10 +45,10 @@ #include "StellaKeys.hxx" #include "Props.hxx" #include "PropsSet.hxx" +#include "RomImageWidget.hxx" #include "RomInfoWidget.hxx" #include "TIAConstants.hxx" #include "Settings.hxx" -#include "Widget.hxx" #include "Font.hxx" #include "StellaFont.hxx" #include "ConsoleBFont.hxx" @@ -329,10 +329,14 @@ void LauncherDialog::addRomWidgets(int ypos) // Calculate font area, and in the process the font that can be used const Common::Size fontArea(romWidth - fontWidth * 2, myList->getHeight() - imgSize.h - VGAP * 3); - setRomInfoFont(fontArea); + + myRomImageWidget = new RomImageWidget(this, *myROMInfoFont, + xpos, ypos, romWidth, imgSize.h); + + int yofs = imgSize.h + _font.getFontHeight() / 2; myRomInfoWidget = new RomInfoWidget(this, *myROMInfoFont, - xpos, ypos, romWidth, myList->getHeight(), imgSize); + xpos, ypos + yofs, romWidth, myList->getHeight() - yofs); } addToFocusList(wid); } @@ -503,7 +507,10 @@ void LauncherDialog::loadConfig() Dialog::setFocus(getFocusList()[mySelectedItem]); if(myRomInfoWidget) + { + myRomImageWidget->reloadProperties(currentNode()); myRomInfoWidget->reloadProperties(currentNode()); + } myList->clearFlags(Widget::FLAG_WANTS_RAWDATA); // always reset this } @@ -716,14 +723,20 @@ void LauncherDialog::setRomInfoFont(const Common::Size& area) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void LauncherDialog::loadRomInfo() { - if(!myRomInfoWidget) + if(!myRomImageWidget || !myROMInfoFont) return; const string& md5 = selectedRomMD5(); if(md5 != EmptyString) + { + myRomImageWidget->setProperties(currentNode(), md5); myRomInfoWidget->setProperties(currentNode(), md5); + } else + { + myRomImageWidget->clearProperties(); myRomInfoWidget->clearProperties(); + } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/gui/LauncherDialog.hxx b/src/gui/LauncherDialog.hxx index 289fa0f6e..193860676 100644 --- a/src/gui/LauncherDialog.hxx +++ b/src/gui/LauncherDialog.hxx @@ -27,6 +27,7 @@ class Properties; class EditTextWidget; class NavigationWidget; class LauncherFileListWidget; +class RomImageWidget; class RomInfoWidget; class StaticTextWidget; @@ -213,6 +214,7 @@ class LauncherDialog : public Dialog, CommandSender ButtonWidget* myOptionsButton{nullptr}; ButtonWidget* myQuitButton{nullptr}; + RomImageWidget* myRomImageWidget{nullptr}; RomInfoWidget* myRomInfoWidget{nullptr}; std::unordered_map myMD5List; diff --git a/src/gui/RomImageWidget.cxx b/src/gui/RomImageWidget.cxx new file mode 100644 index 000000000..a1832304c --- /dev/null +++ b/src/gui/RomImageWidget.cxx @@ -0,0 +1,199 @@ +//============================================================================ +// +// 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-2022 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 "EventHandler.hxx" +#include "FrameBuffer.hxx" +#include "Dialog.hxx" +#include "FBSurface.hxx" +#include "Font.hxx" +#include "OSystem.hxx" +#include "PNGLibrary.hxx" +#include "Props.hxx" +#include "PropsSet.hxx" +#include "RomImageWidget.hxx" + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +RomImageWidget::RomImageWidget(GuiObject* boss, const GUI::Font& font, + int x, int y, int w, int h) + : Widget(boss, font, x, y, w, h), + CommandSender(boss) +{ + _flags = Widget::FLAG_ENABLED; + _bgcolor = kDlgColor; + _bgcolorlo = kBGColorLo; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void RomImageWidget::setProperties(const FSNode& node, const string& md5) +{ + myHaveProperties = true; + + // Make sure to load a per-ROM properties entry, if one exists + instance().propSet().loadPerROM(node, md5); + + // And now get the properties for this ROM + instance().propSet().getMD5(md5, myProperties); + + // Decide whether the information should be shown immediately + if(instance().eventHandler().state() == EventHandlerState::LAUNCHER) + parseProperties(node); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void RomImageWidget::clearProperties() +{ + myHaveProperties = mySurfaceIsValid = false; + if(mySurface) + mySurface->setVisible(mySurfaceIsValid); + + // Decide whether the information should be shown immediately + if(instance().eventHandler().state() == EventHandlerState::LAUNCHER) + setDirty(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void RomImageWidget::reloadProperties(const FSNode& node) +{ + // The ROM may have changed since we were last in the browser, either + // by saving a different image or through a change in video renderer, + // so we reload the properties + if(myHaveProperties) + parseProperties(node); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void RomImageWidget::parseProperties(const FSNode& node) +{ + // Check if a surface has ever been created; if so, we use it + // The surface will always be the maximum size, but sometimes we'll + // only draw certain parts of it + if(mySurface == nullptr) + { + mySurface = instance().frameBuffer().allocateSurface( + _w, _h, ScalingInterpolation::blur); + mySurface->applyAttributes(); + + dialog().addRenderCallback([this]() { + if(mySurfaceIsValid) + mySurface->render(); + } + ); + } + + // Initialize to empty properties entry + mySurfaceErrorMsg = ""; + mySurfaceIsValid = false; + +#ifdef PNG_SUPPORT + // Get a valid filename representing a snapshot file for this rom and load the snapshot + const string& path = instance().snapshotLoadDir().getPath(); + + // 1. Try to load snapshot by property name + mySurfaceIsValid = loadPng(path + myProperties.get(PropType::Cart_Name) + ".png"); + + if(!mySurfaceIsValid) + { + // 2. If no snapshot with property name exists, try to load snapshot image by filename + mySurfaceIsValid = loadPng(path + node.getNameWithExt("") + ".png"); + + if(!mySurfaceIsValid) + { + // 3. If no ROM snapshot exists, try to load a default snapshot + mySurfaceIsValid = loadPng(path + "default_snapshot.png"); + } + } +#else + mySurfaceErrorMsg = "PNG image loading not supported"; +#endif + if(mySurface) + mySurface->setVisible(mySurfaceIsValid); + + setDirty(); +} + +#ifdef PNG_SUPPORT +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool RomImageWidget::loadPng(const string& filename) +{ + try + { + instance().png().loadImage(filename, *mySurface); + + // Scale surface to available image area + const Common::Rect& src = mySurface->srcRect(); + const float scale = std::min(float(_w) / src.w(), float(_h) / src.h()) * + instance().frameBuffer().hidpiScaleFactor(); + mySurface->setDstSize(static_cast(src.w() * scale), static_cast(src.h() * scale)); + + return true; + } + catch(const runtime_error& e) + { + mySurfaceErrorMsg = e.what(); + } + return false; +} +#endif + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//void RomImageWidget::handleMouseUp(int x, int y, MouseButton b, int clickCount) +//{ +// if(isEnabled() && isHighlighted() +// && x >= 0 && x < _w +// && y >= static_cast(_h) + _font.getFontHeight() / 2 && y < _h) +// { +// clearFlags(Widget::FLAG_HILITED); // avoid double clicks and opened URLs +// sendCommand(kClickedCmd, 0, _id); +// } +//} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void RomImageWidget::drawWidget(bool hilite) +{ + FBSurface& s = dialog().surface(); + const int yoff = _h + _font.getFontHeight() / 2; + + s.fillRect(_x+2, _y+2, _w-4, _h-4, _bgcolor); + s.frameRect(_x, _y, _w, _h, kColor); + + if(!myHaveProperties) + { + clearDirty(); + return; + } + + if(mySurfaceIsValid) + { + const Common::Rect& dst = mySurface->dstRect(); + const uInt32 scale = instance().frameBuffer().hidpiScaleFactor(); + const uInt32 x = _x * scale + ((_w * scale - dst.w()) >> 1); + const uInt32 y = _y * scale + ((_h * scale - dst.h()) >> 1); + + // Make sure when positioning the snapshot surface that we take + // the dialog surface position into account + const Common::Rect& s_dst = s.dstRect(); + mySurface->setDstPos(x + s_dst.x(), y + s_dst.y()); + } + else if(mySurfaceErrorMsg != "") + { + const uInt32 x = _x + ((_w - _font.getStringWidth(mySurfaceErrorMsg)) >> 1); + const uInt32 y = _y + ((yoff - _font.getLineHeight()) >> 1); + s.drawString(_font, mySurfaceErrorMsg, x, y, _w - 10, _textcolor); + } + + clearDirty(); +} diff --git a/src/gui/RomImageWidget.hxx b/src/gui/RomImageWidget.hxx new file mode 100644 index 000000000..bc6c8826f --- /dev/null +++ b/src/gui/RomImageWidget.hxx @@ -0,0 +1,78 @@ +//============================================================================ +// +// 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-2022 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 ROM_IMAGE_WIDGET_HXX +#define ROM_IMAGE_WIDGET_HXX + +class FBSurface; +class Properties; + +#include "Widget.hxx" +#include "bspf.hxx" + +class RomImageWidget : public Widget, public CommandSender +{ + public: + //enum { + // kClickedCmd = 'RIcl' + //}; + + public: + RomImageWidget(GuiObject *boss, const GUI::Font& font, + int x, int y, int w, int h); + ~RomImageWidget() override = default; + + void setProperties(const FSNode& node, const string& md5); + void clearProperties(); + void reloadProperties(const FSNode& node); + + protected: + void drawWidget(bool hilite) override; + //void handleMouseUp(int x, int y, MouseButton b, int clickCount) override; + + private: + void parseProperties(const FSNode& node); + #ifdef PNG_SUPPORT + bool loadPng(const string& filename); + #endif + + private: + // Surface pointer holding the PNG image + shared_ptr mySurface; + + // Whether the surface should be redrawn by drawWidget() + bool mySurfaceIsValid{false}; + + // The properties for the currently selected ROM + Properties myProperties; + + // Indicates if the current properties should actually be used + bool myHaveProperties{false}; + + // Indicates if an error occurred in creating/displaying the surface + string mySurfaceErrorMsg; + + private: + // Following constructors and assignment operators not supported + RomImageWidget() = delete; + RomImageWidget(const RomImageWidget&) = delete; + RomImageWidget(RomImageWidget&&) = delete; + RomImageWidget& operator=(const RomImageWidget&) = delete; + RomImageWidget& operator=(RomImageWidget&&) = delete; +}; + +#endif diff --git a/src/gui/RomInfoWidget.cxx b/src/gui/RomInfoWidget.cxx index 4ead37fb3..3638b19dd 100644 --- a/src/gui/RomInfoWidget.cxx +++ b/src/gui/RomInfoWidget.cxx @@ -24,21 +24,15 @@ #include "ControllerDetector.hxx" #include "Bankswitch.hxx" #include "CartDetector.hxx" -#include "Logger.hxx" #include "Props.hxx" -#include "PNGLibrary.hxx" #include "PropsSet.hxx" -#include "Rect.hxx" -#include "Widget.hxx" #include "RomInfoWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - RomInfoWidget::RomInfoWidget(GuiObject* boss, const GUI::Font& font, - int x, int y, int w, int h, - const Common::Size& imgSize) + int x, int y, int w, int h) : Widget(boss, font, x, y, w, h), - CommandSender(boss), - myAvail{imgSize} + CommandSender(boss) { _flags = Widget::FLAG_ENABLED; _bgcolor = kDlgColor; @@ -64,9 +58,7 @@ void RomInfoWidget::setProperties(const FSNode& node, const string& md5) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomInfoWidget::clearProperties() { - myHaveProperties = mySurfaceIsValid = false; - if(mySurface) - mySurface->setVisible(mySurfaceIsValid); + myHaveProperties = false; // Decide whether the information should be shown immediately if(instance().eventHandler().state() == EventHandlerState::LAUNCHER) @@ -87,51 +79,9 @@ void RomInfoWidget::reloadProperties(const FSNode& node) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomInfoWidget::parseProperties(const FSNode& node) { - // Check if a surface has ever been created; if so, we use it - // The surface will always be the maximum size, but sometimes we'll - // only draw certain parts of it - if(mySurface == nullptr) - { - mySurface = instance().frameBuffer().allocateSurface( - myAvail.w, myAvail.h, ScalingInterpolation::blur); - mySurface->applyAttributes(); - - dialog().addRenderCallback([this]() { - if(mySurfaceIsValid) - mySurface->render(); - } - ); - } - // Initialize to empty properties entry - mySurfaceErrorMsg = ""; - mySurfaceIsValid = false; myRomInfo.clear(); -#ifdef PNG_SUPPORT - // Get a valid filename representing a snapshot file for this rom and load the snapshot - const string& path = instance().snapshotLoadDir().getPath(); - - // 1. Try to load snapshot by property name - mySurfaceIsValid = loadPng(path + myProperties.get(PropType::Cart_Name) + ".png"); - - if(!mySurfaceIsValid) - { - // 2. If no snapshot with property name exists, try to load snapshot image by filename - mySurfaceIsValid = loadPng(path + node.getNameWithExt("") + ".png"); - - if(!mySurfaceIsValid) - { - // 3. If no ROM snapshot exists, try to load a default snapshot - mySurfaceIsValid = loadPng(path + "default_snapshot.png"); - } - } -#else - mySurfaceErrorMsg = "PNG image loading not supported"; -#endif - if(mySurface) - mySurface->setVisible(mySurfaceIsValid); - myUrl = myProperties.get(PropType::Cart_Url); // Now add some info for the message box below the image @@ -207,36 +157,13 @@ void RomInfoWidget::parseProperties(const FSNode& node) setDirty(); } -#ifdef PNG_SUPPORT -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool RomInfoWidget::loadPng(const string& filename) -{ - try - { - instance().png().loadImage(filename, *mySurface); - - // Scale surface to available image area - const Common::Rect& src = mySurface->srcRect(); - const float scale = std::min(float(myAvail.w) / src.w(), float(myAvail.h) / src.h()) * - instance().frameBuffer().hidpiScaleFactor(); - mySurface->setDstSize(static_cast(src.w() * scale), static_cast(src.h() * scale)); - - return true; - } - catch(const runtime_error& e) - { - mySurfaceErrorMsg = e.what(); - } - return false; -} -#endif - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomInfoWidget::handleMouseUp(int x, int y, MouseButton b, int clickCount) { - if(isEnabled() && x >= 0 && x < _w && y >= 0 && y < _h) + if(isEnabled() && isHighlighted() + && x >= 0 && x < _w && y >= 0 && y < _h) { - clearFlags(Widget::FLAG_HILITED); + clearFlags(Widget::FLAG_HILITED); // avoid double clicks and opened URLs sendCommand(kClickedCmd, 0, _id); } } @@ -245,11 +172,9 @@ void RomInfoWidget::handleMouseUp(int x, int y, MouseButton b, int clickCount) void RomInfoWidget::drawWidget(bool hilite) { FBSurface& s = dialog().surface(); - const int yoff = myAvail.h + _font.getFontHeight() / 2; s.fillRect(_x+2, _y+2, _w-4, _h-4, _bgcolor); - s.frameRect(_x, _y, _w, myAvail.h, kColor); - s.frameRect(_x, _y+yoff, _w, _h-yoff, kColor); + s.frameRect(_x, _y, _w, _h, kColor); if(!myHaveProperties) { @@ -257,27 +182,8 @@ void RomInfoWidget::drawWidget(bool hilite) return; } - if(mySurfaceIsValid) - { - const Common::Rect& dst = mySurface->dstRect(); - const uInt32 scale = instance().frameBuffer().hidpiScaleFactor(); - const uInt32 x = _x * scale + ((_w * scale - dst.w()) >> 1); - const uInt32 y = _y * scale + ((myAvail.h * scale - dst.h()) >> 1); - - // Make sure when positioning the snapshot surface that we take - // the dialog surface position into account - const Common::Rect& s_dst = s.dstRect(); - mySurface->setDstPos(x + s_dst.x(), y + s_dst.y()); - } - else if(mySurfaceErrorMsg != "") - { - const uInt32 x = _x + ((_w - _font.getStringWidth(mySurfaceErrorMsg)) >> 1); - const uInt32 y = _y + ((yoff - _font.getLineHeight()) >> 1); - s.drawString(_font, mySurfaceErrorMsg, x, y, _w - 10, _textcolor); - } - const int xpos = _x + 8; - int ypos = _y + yoff + 5; + int ypos = _y + 5; for(const auto& info : myRomInfo) { if(info.length() * _font.getMaxCharWidth() <= static_cast(_w - 16)) diff --git a/src/gui/RomInfoWidget.hxx b/src/gui/RomInfoWidget.hxx index fc3b449e6..06cb977c9 100644 --- a/src/gui/RomInfoWidget.hxx +++ b/src/gui/RomInfoWidget.hxx @@ -20,9 +20,6 @@ class FBSurface; class Properties; -namespace Common { - struct Size; -} #include "Widget.hxx" #include "bspf.hxx" @@ -36,8 +33,7 @@ class RomInfoWidget : public Widget, public CommandSender public: RomInfoWidget(GuiObject *boss, const GUI::Font& font, - int x, int y, int w, int h, - const Common::Size& imgSize); + int x, int y, int w, int h); ~RomInfoWidget() override = default; void setProperties(const FSNode& node, const string& md5); @@ -52,17 +48,8 @@ class RomInfoWidget : public Widget, public CommandSender private: void parseProperties(const FSNode& node); - #ifdef PNG_SUPPORT - bool loadPng(const string& filename); - #endif private: - // Surface pointer holding the PNG image - shared_ptr mySurface; - - // Whether the surface should be redrawn by drawWidget() - bool mySurfaceIsValid{false}; - // Some ROM properties info, as well as 'tEXt' chunks from the PNG image StringList myRomInfo; @@ -75,12 +62,6 @@ class RomInfoWidget : public Widget, public CommandSender // Optional cart link URL string myUrl; - // Indicates if an error occurred in creating/displaying the surface - string mySurfaceErrorMsg; - - // How much space available for the PNG image - Common::Size myAvail; - private: // Following constructors and assignment operators not supported RomInfoWidget() = delete; diff --git a/src/gui/module.mk b/src/gui/module.mk index a31c859b7..f8e33c993 100644 --- a/src/gui/module.mk +++ b/src/gui/module.mk @@ -47,6 +47,7 @@ MODULE_OBJS := \ src/gui/R77HelpDialog.o \ src/gui/RadioButtonWidget.o \ src/gui/RomAuditDialog.o \ + src/gui/RomImageWidget.o \ src/gui/RomInfoWidget.o \ src/gui/ScrollBarWidget.o \ src/gui/SnapshotDialog.o \ diff --git a/src/windows/Stella.vcxproj b/src/windows/Stella.vcxproj index 1fd59827a..e889ba1d6 100755 --- a/src/windows/Stella.vcxproj +++ b/src/windows/Stella.vcxproj @@ -929,6 +929,7 @@ + @@ -2146,6 +2147,7 @@ + diff --git a/src/windows/Stella.vcxproj.filters b/src/windows/Stella.vcxproj.filters index d44dbcaa5..7e3371379 100644 --- a/src/windows/Stella.vcxproj.filters +++ b/src/windows/Stella.vcxproj.filters @@ -1146,6 +1146,9 @@ Source Files\debugger + + Source Files\gui + @@ -2372,6 +2375,9 @@ Header Files\debugger + + Header Files\gui +