mirror of https://github.com/stella-emu/stella.git
Merge remote-tracking branch 'remotes/origin/feature/multiimages'
This commit is contained in:
commit
d1412c31c8
|
@ -38,7 +38,7 @@ PNGLibrary::PNGLibrary(OSystem& osystem)
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void PNGLibrary::loadImage(const string& filename, FBSurface& surface)
|
void PNGLibrary::loadImage(const string& filename, FBSurface& surface, VariantList& comments)
|
||||||
{
|
{
|
||||||
png_structp png_ptr{nullptr};
|
png_structp png_ptr{nullptr};
|
||||||
png_infop info_ptr{nullptr};
|
png_infop info_ptr{nullptr};
|
||||||
|
@ -114,6 +114,9 @@ void PNGLibrary::loadImage(const string& filename, FBSurface& surface)
|
||||||
// We're finished reading
|
// We're finished reading
|
||||||
png_read_end(png_ptr, info_ptr);
|
png_read_end(png_ptr, info_ptr);
|
||||||
|
|
||||||
|
// Read the comments we got
|
||||||
|
readComments(png_ptr, info_ptr, comments);
|
||||||
|
|
||||||
// Load image into the surface, setting the correct dimensions
|
// Load image into the surface, setting the correct dimensions
|
||||||
loadImagetoSurface(surface);
|
loadImagetoSurface(surface);
|
||||||
|
|
||||||
|
@ -335,6 +338,7 @@ void PNGLibrary::takeSnapshot(uInt32 number)
|
||||||
// Some text fields to add to the PNG snapshot
|
// Some text fields to add to the PNG snapshot
|
||||||
VariantList comments;
|
VariantList comments;
|
||||||
ostringstream version;
|
ostringstream version;
|
||||||
|
VarList::push_back(comments, "Title", "Snapshot");
|
||||||
version << "Stella " << STELLA_VERSION << " (Build " << STELLA_BUILD << ") ["
|
version << "Stella " << STELLA_VERSION << " (Build " << STELLA_BUILD << ") ["
|
||||||
<< BSPF::ARCH << "]";
|
<< BSPF::ARCH << "]";
|
||||||
VarList::push_back(comments, "Software", version.str());
|
VarList::push_back(comments, "Software", version.str());
|
||||||
|
@ -448,6 +452,23 @@ void PNGLibrary::writeComments(const png_structp png_ptr, png_infop info_ptr,
|
||||||
png_set_text(png_ptr, info_ptr, text_ptr.data(), numComments);
|
png_set_text(png_ptr, info_ptr, text_ptr.data(), numComments);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
void PNGLibrary::readComments(const png_structp png_ptr, png_infop info_ptr,
|
||||||
|
VariantList& comments)
|
||||||
|
{
|
||||||
|
png_textp text_ptr;
|
||||||
|
int numComments = 0;
|
||||||
|
|
||||||
|
// TODO: currently works only if comments are *before* the image data
|
||||||
|
png_get_text(png_ptr, info_ptr, &text_ptr, &numComments);
|
||||||
|
|
||||||
|
comments.clear();
|
||||||
|
for(int i = 0; i < numComments; ++i)
|
||||||
|
{
|
||||||
|
VarList::push_back(comments, text_ptr[i].key, text_ptr[i].text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void PNGLibrary::png_read_data(const png_structp ctx, png_bytep area, png_size_t size)
|
void PNGLibrary::png_read_data(const png_structp ctx, png_bytep area, png_size_t size)
|
||||||
{
|
{
|
||||||
|
|
|
@ -52,7 +52,7 @@ class PNGLibrary
|
||||||
runtime_error is thrown containing a more detailed
|
runtime_error is thrown containing a more detailed
|
||||||
error message.
|
error message.
|
||||||
*/
|
*/
|
||||||
void loadImage(const string& filename, FBSurface& surface);
|
void loadImage(const string& filename, FBSurface& surface, VariantList& comments);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Save the current FrameBuffer image to a PNG file. Note that in most
|
Save the current FrameBuffer image to a PNG file. Note that in most
|
||||||
|
@ -183,6 +183,12 @@ class PNGLibrary
|
||||||
void writeComments(const png_structp png_ptr, png_infop info_ptr,
|
void writeComments(const png_structp png_ptr, png_infop info_ptr,
|
||||||
const VariantList& comments);
|
const VariantList& comments);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Read PNG tEXt chunks from the image.
|
||||||
|
*/
|
||||||
|
void readComments(const png_structp png_ptr, png_infop info_ptr,
|
||||||
|
VariantList& comments);
|
||||||
|
|
||||||
/** PNG library callback functions */
|
/** PNG library callback functions */
|
||||||
static void png_read_data(const png_structp ctx, png_bytep area, png_size_t size);
|
static void png_read_data(const png_structp ctx, png_bytep area, png_size_t size);
|
||||||
static void png_write_data(const png_structp ctx, png_bytep area, png_size_t size);
|
static void png_write_data(const png_structp ctx, png_bytep area, png_size_t size);
|
||||||
|
|
|
@ -319,6 +319,65 @@ namespace BSPF
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
inline size_t matchWithJoker(const string& str, const string& pattern)
|
||||||
|
{
|
||||||
|
if(str.length() >= pattern.length())
|
||||||
|
{
|
||||||
|
// optimize a bit
|
||||||
|
if(pattern.find('?') != string::npos)
|
||||||
|
{
|
||||||
|
for(size_t pos = 0; pos < str.length() - pattern.length() + 1; ++pos)
|
||||||
|
{
|
||||||
|
bool found = true;
|
||||||
|
|
||||||
|
for(size_t i = 0; found && i < pattern.length(); ++i)
|
||||||
|
if(pattern[i] != str[pos + i] && pattern[i] != '?')
|
||||||
|
found = false;
|
||||||
|
|
||||||
|
if(found)
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return str.find(pattern);
|
||||||
|
}
|
||||||
|
return string::npos;
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
inline bool matchWithWildcards(const string& str, const string& pattern)
|
||||||
|
{
|
||||||
|
string pat = pattern;
|
||||||
|
|
||||||
|
// remove leading and trailing '*'
|
||||||
|
size_t i = 0;
|
||||||
|
while(pat[i++] == '*');
|
||||||
|
pat = pat.substr(i - 1);
|
||||||
|
|
||||||
|
i = pat.length();
|
||||||
|
while(pat[--i] == '*');
|
||||||
|
pat.erase(i + 1);
|
||||||
|
|
||||||
|
// Search for first '*'
|
||||||
|
const size_t pos = pat.find('*');
|
||||||
|
|
||||||
|
if(pos != string::npos)
|
||||||
|
{
|
||||||
|
// '*' found, split pattern into left and right part, search recursively
|
||||||
|
const string leftPat = pat.substr(0, pos);
|
||||||
|
const string rightPat = pat.substr(pos + 1);
|
||||||
|
const size_t posLeft = matchWithJoker(str, leftPat);
|
||||||
|
|
||||||
|
if(posLeft != string::npos)
|
||||||
|
return matchWithWildcards(str.substr(pos + posLeft), rightPat);
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// no further '*' found
|
||||||
|
return matchWithJoker(str, pat) != string::npos;
|
||||||
|
}
|
||||||
|
|
||||||
// Modify 'str', replacing all occurrences of 'from' with 'to'
|
// Modify 'str', replacing all occurrences of 'from' with 'to'
|
||||||
inline void replaceAll(string& str, const string& from, const string& to)
|
inline void replaceAll(string& str, const string& from, const string& to)
|
||||||
{
|
{
|
||||||
|
|
|
@ -97,13 +97,13 @@ Bankswitch::BSList = {{
|
||||||
{ "AUTO" , "Auto-detect" },
|
{ "AUTO" , "Auto-detect" },
|
||||||
{ "0840" , "0840 (8K EconoBanking)" },
|
{ "0840" , "0840 (8K EconoBanking)" },
|
||||||
{ "0FA0" , "0FA0 (8K Fotomania)" },
|
{ "0FA0" , "0FA0 (8K Fotomania)" },
|
||||||
{ "2IN1" , "2IN1 Multicart (4-64K)" },
|
{ "2IN1" , "2in1 Multicart (4-64K)" },
|
||||||
{ "4IN1" , "4IN1 Multicart (8-64K)" },
|
{ "4IN1" , "4in1 Multicart (8-64K)" },
|
||||||
{ "8IN1" , "8IN1 Multicart (16-64K)" },
|
{ "8IN1" , "8in1 Multicart (16-64K)" },
|
||||||
{ "16IN1" , "16IN1 Multicart (32-128K)" },
|
{ "16IN1" , "16in1 Multicart (32-128K)" },
|
||||||
{ "32IN1" , "32IN1 Multicart (64/128K)" },
|
{ "32IN1" , "32in1 Multicart (64/128K)" },
|
||||||
{ "64IN1" , "64IN1 Multicart (128/256K)" },
|
{ "64IN1" , "64in1 Multicart (128/256K)" },
|
||||||
{ "128IN1" , "128IN1 Multicart (256/512K)" },
|
{ "128IN1" , "128in1 Multicart (256/512K)" },
|
||||||
{ "2K" , "2K (32-2048 bytes Atari)" },
|
{ "2K" , "2K (32-2048 bytes Atari)" },
|
||||||
{ "3E" , "3E (Tigervision, 32K RAM)" },
|
{ "3E" , "3E (Tigervision, 32K RAM)" },
|
||||||
{ "3EX" , "3EX (Tigervision, 256K RAM)" },
|
{ "3EX" , "3EX (Tigervision, 256K RAM)" },
|
||||||
|
|
|
@ -45,10 +45,10 @@
|
||||||
#include "StellaKeys.hxx"
|
#include "StellaKeys.hxx"
|
||||||
#include "Props.hxx"
|
#include "Props.hxx"
|
||||||
#include "PropsSet.hxx"
|
#include "PropsSet.hxx"
|
||||||
|
#include "RomImageWidget.hxx"
|
||||||
#include "RomInfoWidget.hxx"
|
#include "RomInfoWidget.hxx"
|
||||||
#include "TIAConstants.hxx"
|
#include "TIAConstants.hxx"
|
||||||
#include "Settings.hxx"
|
#include "Settings.hxx"
|
||||||
#include "Widget.hxx"
|
|
||||||
#include "Font.hxx"
|
#include "Font.hxx"
|
||||||
#include "StellaFont.hxx"
|
#include "StellaFont.hxx"
|
||||||
#include "ConsoleBFont.hxx"
|
#include "ConsoleBFont.hxx"
|
||||||
|
@ -305,8 +305,8 @@ void LauncherDialog::addRomWidgets(int ypos)
|
||||||
const int listHeight = _h - ypos - VBORDER - buttonHeight - VGAP * 3;
|
const int listHeight = _h - ypos - VBORDER - buttonHeight - VGAP * 3;
|
||||||
|
|
||||||
const float imgZoom = getRomInfoZoom(listHeight);
|
const float imgZoom = getRomInfoZoom(listHeight);
|
||||||
const int romWidth = imgZoom * TIAConstants::viewableWidth;
|
const int imageWidth = imgZoom * TIAConstants::viewableWidth;
|
||||||
const int listWidth = _w - (romWidth > 0 ? romWidth + fontWidth : 0) - HBORDER * 2;
|
const int listWidth = _w - (imageWidth > 0 ? imageWidth + fontWidth : 0) - HBORDER * 2;
|
||||||
|
|
||||||
// remember initial ROM directory for returning there via home button
|
// remember initial ROM directory for returning there via home button
|
||||||
instance().settings().setValue("startromdir", getRomDir());
|
instance().settings().setValue("startromdir", getRomDir());
|
||||||
|
@ -319,7 +319,7 @@ void LauncherDialog::addRomWidgets(int ypos)
|
||||||
wid.push_back(myList);
|
wid.push_back(myList);
|
||||||
|
|
||||||
// Add ROM info area (if enabled)
|
// Add ROM info area (if enabled)
|
||||||
if(romWidth > 0)
|
if(imageWidth > 0)
|
||||||
{
|
{
|
||||||
xpos += myList->getWidth() + fontWidth;
|
xpos += myList->getWidth() + fontWidth;
|
||||||
|
|
||||||
|
@ -327,12 +327,22 @@ void LauncherDialog::addRomWidgets(int ypos)
|
||||||
const Common::Size imgSize(TIAConstants::viewableWidth * imgZoom,
|
const Common::Size imgSize(TIAConstants::viewableWidth * imgZoom,
|
||||||
TIAConstants::viewableHeight * imgZoom);
|
TIAConstants::viewableHeight * imgZoom);
|
||||||
// Calculate font area, and in the process the font that can be used
|
// 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);
|
|
||||||
|
|
||||||
|
// Infofont is unknown yet, but used in image label too. Assuming maximum font height.
|
||||||
|
int imageHeight = imgSize.h + RomImageWidget::labelHeight(_font);
|
||||||
|
|
||||||
|
const Common::Size fontArea(imageWidth - fontWidth * 2,
|
||||||
|
myList->getHeight() - imageHeight - VGAP * 4);
|
||||||
setRomInfoFont(fontArea);
|
setRomInfoFont(fontArea);
|
||||||
|
|
||||||
|
// Now we have the correct font height
|
||||||
|
imageHeight = imgSize.h + RomImageWidget::labelHeight(*myROMInfoFont);
|
||||||
|
myRomImageWidget = new RomImageWidget(this, *myROMInfoFont,
|
||||||
|
xpos, ypos, imageWidth, imageHeight);
|
||||||
|
|
||||||
|
const int yofs = imageHeight + VGAP * 2;
|
||||||
myRomInfoWidget = new RomInfoWidget(this, *myROMInfoFont,
|
myRomInfoWidget = new RomInfoWidget(this, *myROMInfoFont,
|
||||||
xpos, ypos, romWidth, myList->getHeight(), imgSize);
|
xpos, ypos + yofs, imageWidth, myList->getHeight() - yofs);
|
||||||
}
|
}
|
||||||
addToFocusList(wid);
|
addToFocusList(wid);
|
||||||
}
|
}
|
||||||
|
@ -503,7 +513,10 @@ void LauncherDialog::loadConfig()
|
||||||
Dialog::setFocus(getFocusList()[mySelectedItem]);
|
Dialog::setFocus(getFocusList()[mySelectedItem]);
|
||||||
|
|
||||||
if(myRomInfoWidget)
|
if(myRomInfoWidget)
|
||||||
|
{
|
||||||
|
myRomImageWidget->reloadProperties(currentNode());
|
||||||
myRomInfoWidget->reloadProperties(currentNode());
|
myRomInfoWidget->reloadProperties(currentNode());
|
||||||
|
}
|
||||||
|
|
||||||
myList->clearFlags(Widget::FLAG_WANTS_RAWDATA); // always reset this
|
myList->clearFlags(Widget::FLAG_WANTS_RAWDATA); // always reset this
|
||||||
}
|
}
|
||||||
|
@ -716,14 +729,20 @@ void LauncherDialog::setRomInfoFont(const Common::Size& area)
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void LauncherDialog::loadRomInfo()
|
void LauncherDialog::loadRomInfo()
|
||||||
{
|
{
|
||||||
if(!myRomInfoWidget)
|
if(!myRomImageWidget || !myROMInfoFont)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const string& md5 = selectedRomMD5();
|
const string& md5 = selectedRomMD5();
|
||||||
if(md5 != EmptyString)
|
if(md5 != EmptyString)
|
||||||
|
{
|
||||||
|
myRomImageWidget->setProperties(currentNode(), md5);
|
||||||
myRomInfoWidget->setProperties(currentNode(), md5);
|
myRomInfoWidget->setProperties(currentNode(), md5);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
myRomImageWidget->clearProperties();
|
||||||
myRomInfoWidget->clearProperties();
|
myRomInfoWidget->clearProperties();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -860,6 +879,14 @@ void LauncherDialog::handleKeyDown(StellaKey key, StellaMod mod, bool repeated)
|
||||||
reload();
|
reload();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case KBDK_LEFT:
|
||||||
|
myRomImageWidget->changeImage(-1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case KBDK_RIGHT:
|
||||||
|
myRomImageWidget->changeImage(1);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
handled = false;
|
handled = false;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -27,6 +27,7 @@ class Properties;
|
||||||
class EditTextWidget;
|
class EditTextWidget;
|
||||||
class NavigationWidget;
|
class NavigationWidget;
|
||||||
class LauncherFileListWidget;
|
class LauncherFileListWidget;
|
||||||
|
class RomImageWidget;
|
||||||
class RomInfoWidget;
|
class RomInfoWidget;
|
||||||
class StaticTextWidget;
|
class StaticTextWidget;
|
||||||
|
|
||||||
|
@ -213,6 +214,7 @@ class LauncherDialog : public Dialog, CommandSender
|
||||||
ButtonWidget* myOptionsButton{nullptr};
|
ButtonWidget* myOptionsButton{nullptr};
|
||||||
ButtonWidget* myQuitButton{nullptr};
|
ButtonWidget* myQuitButton{nullptr};
|
||||||
|
|
||||||
|
RomImageWidget* myRomImageWidget{nullptr};
|
||||||
RomInfoWidget* myRomInfoWidget{nullptr};
|
RomInfoWidget* myRomInfoWidget{nullptr};
|
||||||
|
|
||||||
std::unordered_map<string,string> myMD5List;
|
std::unordered_map<string,string> myMD5List;
|
||||||
|
|
|
@ -0,0 +1,307 @@
|
||||||
|
//============================================================================
|
||||||
|
//
|
||||||
|
// 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 "bspf.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 | Widget::FLAG_TRACK_MOUSE;
|
||||||
|
_bgcolor = kDlgColor;
|
||||||
|
_bgcolorlo = kBGColorLo;
|
||||||
|
myImageHeight = _h - labelHeight(font);
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
if(myNavSurface == nullptr)
|
||||||
|
{
|
||||||
|
// Create navigation surface
|
||||||
|
myNavSurface = instance().frameBuffer().allocateSurface(
|
||||||
|
_w, myImageHeight);
|
||||||
|
|
||||||
|
FBSurface::Attributes& attr = myNavSurface->attributes();
|
||||||
|
|
||||||
|
attr.blending = true;
|
||||||
|
attr.blendalpha = 60;
|
||||||
|
myNavSurface->applyAttributes();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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, myImageHeight, ScalingInterpolation::blur);
|
||||||
|
mySurface->applyAttributes();
|
||||||
|
|
||||||
|
dialog().addRenderCallback([this]() {
|
||||||
|
if(mySurfaceIsValid)
|
||||||
|
{
|
||||||
|
mySurface->render();
|
||||||
|
if(isHighlighted())
|
||||||
|
myNavSurface->render();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize to empty properties entry
|
||||||
|
mySurfaceErrorMsg = "";
|
||||||
|
mySurfaceIsValid = false;
|
||||||
|
|
||||||
|
#ifdef PNG_SUPPORT
|
||||||
|
// TODO: RETRON_77
|
||||||
|
|
||||||
|
// Get a valid filename representing a snapshot file for this rom and load the snapshot
|
||||||
|
const string& path = instance().snapshotLoadDir().getPath();
|
||||||
|
|
||||||
|
myImageList.clear();
|
||||||
|
myImageIdx = 0;
|
||||||
|
// 1. Try to load snapshots by property name
|
||||||
|
if(getImageList(path + myProperties.get(PropType::Cart_Name)))
|
||||||
|
mySurfaceIsValid = loadPng(myImageList[0].getPath());
|
||||||
|
|
||||||
|
// 2. Also try to load snapshot images by filename
|
||||||
|
if(getImageList(path + node.getNameWithExt("")))
|
||||||
|
mySurfaceIsValid = loadPng(myImageList[0].getPath());
|
||||||
|
|
||||||
|
if(!mySurfaceIsValid)
|
||||||
|
{
|
||||||
|
// 3. If no ROM snapshots exist, 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
bool RomImageWidget::changeImage(int direction)
|
||||||
|
{
|
||||||
|
if(direction == -1 && myImageIdx)
|
||||||
|
return loadPng(myImageList[--myImageIdx].getPath());
|
||||||
|
else if(direction == 1 && myImageIdx < myImageList.size() - 1)
|
||||||
|
return loadPng(myImageList[++myImageIdx].getPath());
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef PNG_SUPPORT
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
bool RomImageWidget::getImageList(const string& filename)
|
||||||
|
{
|
||||||
|
FSNode::NameFilter filter = ([&](const FSNode& node) {
|
||||||
|
return (!node.isDirectory() &&
|
||||||
|
(node.getPath() == filename + ".png" ||
|
||||||
|
BSPF::matchWithWildcards(node.getPath(), filename + "#*.png")));
|
||||||
|
});
|
||||||
|
|
||||||
|
FSNode node(instance().snapshotLoadDir().getPath());
|
||||||
|
|
||||||
|
node.getChildren(myImageList, FSNode::ListMode::FilesOnly, filter, false, false);
|
||||||
|
return myImageList.size() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
bool RomImageWidget::loadPng(const string& filename)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
VariantList comments;
|
||||||
|
instance().png().loadImage(filename, *mySurface, comments);
|
||||||
|
|
||||||
|
// Scale surface to available image area
|
||||||
|
const Common::Rect& src = mySurface->srcRect();
|
||||||
|
const float scale = std::min(float(_w) / src.w(), float(myImageHeight) / src.h()) *
|
||||||
|
instance().frameBuffer().hidpiScaleFactor();
|
||||||
|
mySurface->setDstSize(static_cast<uInt32>(src.w() * scale), static_cast<uInt32>(src.h() * scale));
|
||||||
|
|
||||||
|
// Retrieve label for loaded image
|
||||||
|
myLabel = "";
|
||||||
|
for(auto comment = comments.begin(); comment != comments.end(); ++comment)
|
||||||
|
{
|
||||||
|
if(comment->first == "Title")
|
||||||
|
{
|
||||||
|
myLabel = comment->second.toString();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(comment->first == "Software"
|
||||||
|
&& comment->second.toString().find("Stella") == 0)
|
||||||
|
myLabel = "Snapshot"; // default for Stella snapshots with missing "Title" comment
|
||||||
|
}
|
||||||
|
|
||||||
|
setDirty();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch(const runtime_error& e)
|
||||||
|
{
|
||||||
|
mySurfaceErrorMsg = e.what();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
void RomImageWidget::handleMouseUp(int x, int y, MouseButton b, int clickCount)
|
||||||
|
{
|
||||||
|
if(isEnabled() && x >= 0 && x < _w && y >= 0 && y < myImageHeight)
|
||||||
|
changeImage(x < _w / 2 ? 1 : -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
void RomImageWidget::handleMouseMoved(int x, int y)
|
||||||
|
{
|
||||||
|
if(x < _w / 2 != myMouseX < _w / 2)
|
||||||
|
setDirty();
|
||||||
|
myMouseX = x;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
void RomImageWidget::drawWidget(bool hilite)
|
||||||
|
{
|
||||||
|
FBSurface& s = dialog().surface();
|
||||||
|
const int yoff = myImageHeight;
|
||||||
|
|
||||||
|
s.fillRect(_x+1, _y+1, _w-2, _h-1, _bgcolor);
|
||||||
|
s.frameRect(_x, _y, _w, myImageHeight, 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 + ((myImageHeight * 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());
|
||||||
|
|
||||||
|
// Draw the image label and counter
|
||||||
|
ostringstream buf;
|
||||||
|
buf << myImageIdx + 1 << "/" << myImageList.size();
|
||||||
|
const int yText = _y + myImageHeight + _font.getFontHeight() / 8;
|
||||||
|
const int wText = _font.getStringWidth(buf.str());
|
||||||
|
|
||||||
|
if(myLabel.length())
|
||||||
|
s.drawString(_font, myLabel, _x, yText, _w - wText - _font.getMaxCharWidth() * 2, _textcolor);
|
||||||
|
if(myImageList.size())
|
||||||
|
s.drawString(_font, buf.str(), _x + _w - wText, yText, wText, _textcolor);
|
||||||
|
|
||||||
|
// Draw the navigation arrows
|
||||||
|
const bool leftArrow = myMouseX < _w / 2;
|
||||||
|
|
||||||
|
myNavSurface->invalidate();
|
||||||
|
if(isHighlighted() &&
|
||||||
|
((leftArrow && myImageIdx) || (!leftArrow && myImageIdx < myImageList.size() - 1)) || true)
|
||||||
|
{
|
||||||
|
const int w = _w / 64;
|
||||||
|
const int w2 = 1; // w / 2;
|
||||||
|
const int ax = leftArrow ? _w / 12 - w / 2 : _w - _w / 12 - w / 2;
|
||||||
|
const int ay = myImageHeight >> 1;
|
||||||
|
const int dx = (_w / 32) * (leftArrow ? 1 : -1);
|
||||||
|
const int dy = myImageHeight / 16;
|
||||||
|
|
||||||
|
for(int i = 0; i < w; ++i)
|
||||||
|
{
|
||||||
|
myNavSurface->line(ax + dx + i + w2, ay - dy, ax + i + w2, ay, kBGColor);
|
||||||
|
myNavSurface->line(ax + dx + i + w2, ay + dy, ax + i + w2, ay, kBGColor);
|
||||||
|
myNavSurface->line(ax + dx + i, ay - dy + w2, ax + i, ay + w2, kBGColor);
|
||||||
|
myNavSurface->line(ax + dx + i, ay + dy + w2, ax + i, ay + w2, kBGColor);
|
||||||
|
myNavSurface->line(ax + dx + i + w2, ay - dy + w2, ax + i + w2, ay + w2, kBGColor);
|
||||||
|
myNavSurface->line(ax + dx + i + w2, ay + dy + w2, ax + i + w2, ay + w2, kBGColor);
|
||||||
|
}
|
||||||
|
for(int i = 0; i < w; ++i)
|
||||||
|
{
|
||||||
|
myNavSurface->line(ax + dx + i, ay - dy, ax + i, ay, kColorInfo);
|
||||||
|
myNavSurface->line(ax + dx + i, ay + dy, ax + i, ay, kColorInfo);
|
||||||
|
}
|
||||||
|
myNavSurface->setDstRect(mySurface->dstRect());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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();
|
||||||
|
}
|
|
@ -0,0 +1,101 @@
|
||||||
|
//============================================================================
|
||||||
|
//
|
||||||
|
// 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:
|
||||||
|
RomImageWidget(GuiObject *boss, const GUI::Font& font,
|
||||||
|
int x, int y, int w, int h);
|
||||||
|
~RomImageWidget() override = default;
|
||||||
|
|
||||||
|
static int labelHeight(const GUI::Font& font)
|
||||||
|
{
|
||||||
|
return font.getFontHeight() * 9 / 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setProperties(const FSNode& node, const string& md5);
|
||||||
|
void clearProperties();
|
||||||
|
void reloadProperties(const FSNode& node);
|
||||||
|
bool changeImage(int direction = 1);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void drawWidget(bool hilite) override;
|
||||||
|
#ifdef PNG_SUPPORT
|
||||||
|
void handleMouseUp(int x, int y, MouseButton b, int clickCount) override;
|
||||||
|
void handleMouseMoved(int x, int y) override;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
void parseProperties(const FSNode& node);
|
||||||
|
#ifdef PNG_SUPPORT
|
||||||
|
bool getImageList(const string& filename);
|
||||||
|
bool loadPng(const string& filename);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Surface pointer holding the PNG image
|
||||||
|
shared_ptr<FBSurface> mySurface;
|
||||||
|
|
||||||
|
// Surface pointer holding the navigation elements
|
||||||
|
shared_ptr<FBSurface> myNavSurface;
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
// Height of the image area
|
||||||
|
int myImageHeight{0};
|
||||||
|
|
||||||
|
// Contains the list of image names for the current ROM
|
||||||
|
FSList myImageList;
|
||||||
|
|
||||||
|
// Index of currently displayed image
|
||||||
|
int myImageIdx{0};
|
||||||
|
|
||||||
|
// Current x-position of the mouse
|
||||||
|
int myMouseX{0};
|
||||||
|
|
||||||
|
// Label for the loaded image
|
||||||
|
string myLabel;
|
||||||
|
|
||||||
|
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
|
|
@ -24,21 +24,15 @@
|
||||||
#include "ControllerDetector.hxx"
|
#include "ControllerDetector.hxx"
|
||||||
#include "Bankswitch.hxx"
|
#include "Bankswitch.hxx"
|
||||||
#include "CartDetector.hxx"
|
#include "CartDetector.hxx"
|
||||||
#include "Logger.hxx"
|
|
||||||
#include "Props.hxx"
|
#include "Props.hxx"
|
||||||
#include "PNGLibrary.hxx"
|
|
||||||
#include "PropsSet.hxx"
|
#include "PropsSet.hxx"
|
||||||
#include "Rect.hxx"
|
|
||||||
#include "Widget.hxx"
|
|
||||||
#include "RomInfoWidget.hxx"
|
#include "RomInfoWidget.hxx"
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
RomInfoWidget::RomInfoWidget(GuiObject* boss, const GUI::Font& font,
|
RomInfoWidget::RomInfoWidget(GuiObject* boss, const GUI::Font& font,
|
||||||
int x, int y, int w, int h,
|
int x, int y, int w, int h)
|
||||||
const Common::Size& imgSize)
|
|
||||||
: Widget(boss, font, x, y, w, h),
|
: Widget(boss, font, x, y, w, h),
|
||||||
CommandSender(boss),
|
CommandSender(boss)
|
||||||
myAvail{imgSize}
|
|
||||||
{
|
{
|
||||||
_flags = Widget::FLAG_ENABLED;
|
_flags = Widget::FLAG_ENABLED;
|
||||||
_bgcolor = kDlgColor;
|
_bgcolor = kDlgColor;
|
||||||
|
@ -64,9 +58,7 @@ void RomInfoWidget::setProperties(const FSNode& node, const string& md5)
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void RomInfoWidget::clearProperties()
|
void RomInfoWidget::clearProperties()
|
||||||
{
|
{
|
||||||
myHaveProperties = mySurfaceIsValid = false;
|
myHaveProperties = false;
|
||||||
if(mySurface)
|
|
||||||
mySurface->setVisible(mySurfaceIsValid);
|
|
||||||
|
|
||||||
// Decide whether the information should be shown immediately
|
// Decide whether the information should be shown immediately
|
||||||
if(instance().eventHandler().state() == EventHandlerState::LAUNCHER)
|
if(instance().eventHandler().state() == EventHandlerState::LAUNCHER)
|
||||||
|
@ -87,51 +79,9 @@ void RomInfoWidget::reloadProperties(const FSNode& node)
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void RomInfoWidget::parseProperties(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
|
// Initialize to empty properties entry
|
||||||
mySurfaceErrorMsg = "";
|
|
||||||
mySurfaceIsValid = false;
|
|
||||||
myRomInfo.clear();
|
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);
|
myUrl = myProperties.get(PropType::Cart_Url);
|
||||||
|
|
||||||
// Now add some info for the message box below the image
|
// Now add some info for the message box below the image
|
||||||
|
@ -207,36 +157,13 @@ void RomInfoWidget::parseProperties(const FSNode& node)
|
||||||
setDirty();
|
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<uInt32>(src.w() * scale), static_cast<uInt32>(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)
|
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);
|
sendCommand(kClickedCmd, 0, _id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -245,11 +172,9 @@ void RomInfoWidget::handleMouseUp(int x, int y, MouseButton b, int clickCount)
|
||||||
void RomInfoWidget::drawWidget(bool hilite)
|
void RomInfoWidget::drawWidget(bool hilite)
|
||||||
{
|
{
|
||||||
FBSurface& s = dialog().surface();
|
FBSurface& s = dialog().surface();
|
||||||
const int yoff = myAvail.h + _font.getFontHeight() / 2;
|
|
||||||
|
|
||||||
s.fillRect(_x+2, _y+2, _w-4, _h-4, _bgcolor);
|
s.fillRect(_x+2, _y+2, _w-4, _h-4, _bgcolor);
|
||||||
s.frameRect(_x, _y, _w, myAvail.h, kColor);
|
s.frameRect(_x, _y, _w, _h, kColor);
|
||||||
s.frameRect(_x, _y+yoff, _w, _h-yoff, kColor);
|
|
||||||
|
|
||||||
if(!myHaveProperties)
|
if(!myHaveProperties)
|
||||||
{
|
{
|
||||||
|
@ -257,27 +182,8 @@ void RomInfoWidget::drawWidget(bool hilite)
|
||||||
return;
|
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;
|
const int xpos = _x + 8;
|
||||||
int ypos = _y + yoff + 5;
|
int ypos = _y + 5;
|
||||||
for(const auto& info : myRomInfo)
|
for(const auto& info : myRomInfo)
|
||||||
{
|
{
|
||||||
if(info.length() * _font.getMaxCharWidth() <= static_cast<size_t>(_w - 16))
|
if(info.length() * _font.getMaxCharWidth() <= static_cast<size_t>(_w - 16))
|
||||||
|
|
|
@ -20,9 +20,6 @@
|
||||||
|
|
||||||
class FBSurface;
|
class FBSurface;
|
||||||
class Properties;
|
class Properties;
|
||||||
namespace Common {
|
|
||||||
struct Size;
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "Widget.hxx"
|
#include "Widget.hxx"
|
||||||
#include "bspf.hxx"
|
#include "bspf.hxx"
|
||||||
|
@ -36,8 +33,7 @@ class RomInfoWidget : public Widget, public CommandSender
|
||||||
|
|
||||||
public:
|
public:
|
||||||
RomInfoWidget(GuiObject *boss, const GUI::Font& font,
|
RomInfoWidget(GuiObject *boss, const GUI::Font& font,
|
||||||
int x, int y, int w, int h,
|
int x, int y, int w, int h);
|
||||||
const Common::Size& imgSize);
|
|
||||||
~RomInfoWidget() override = default;
|
~RomInfoWidget() override = default;
|
||||||
|
|
||||||
void setProperties(const FSNode& node, const string& md5);
|
void setProperties(const FSNode& node, const string& md5);
|
||||||
|
@ -52,17 +48,8 @@ class RomInfoWidget : public Widget, public CommandSender
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void parseProperties(const FSNode& node);
|
void parseProperties(const FSNode& node);
|
||||||
#ifdef PNG_SUPPORT
|
|
||||||
bool loadPng(const string& filename);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Surface pointer holding the PNG image
|
|
||||||
shared_ptr<FBSurface> 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
|
// Some ROM properties info, as well as 'tEXt' chunks from the PNG image
|
||||||
StringList myRomInfo;
|
StringList myRomInfo;
|
||||||
|
|
||||||
|
@ -75,12 +62,6 @@ class RomInfoWidget : public Widget, public CommandSender
|
||||||
// Optional cart link URL
|
// Optional cart link URL
|
||||||
string myUrl;
|
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:
|
private:
|
||||||
// Following constructors and assignment operators not supported
|
// Following constructors and assignment operators not supported
|
||||||
RomInfoWidget() = delete;
|
RomInfoWidget() = delete;
|
||||||
|
|
|
@ -47,6 +47,7 @@ MODULE_OBJS := \
|
||||||
src/gui/R77HelpDialog.o \
|
src/gui/R77HelpDialog.o \
|
||||||
src/gui/RadioButtonWidget.o \
|
src/gui/RadioButtonWidget.o \
|
||||||
src/gui/RomAuditDialog.o \
|
src/gui/RomAuditDialog.o \
|
||||||
|
src/gui/RomImageWidget.o \
|
||||||
src/gui/RomInfoWidget.o \
|
src/gui/RomInfoWidget.o \
|
||||||
src/gui/ScrollBarWidget.o \
|
src/gui/ScrollBarWidget.o \
|
||||||
src/gui/SnapshotDialog.o \
|
src/gui/SnapshotDialog.o \
|
||||||
|
|
|
@ -929,6 +929,7 @@
|
||||||
<ClCompile Include="..\gui\QuadTariDialog.cxx" />
|
<ClCompile Include="..\gui\QuadTariDialog.cxx" />
|
||||||
<ClCompile Include="..\gui\R77HelpDialog.cxx" />
|
<ClCompile Include="..\gui\R77HelpDialog.cxx" />
|
||||||
<ClCompile Include="..\gui\RadioButtonWidget.cxx" />
|
<ClCompile Include="..\gui\RadioButtonWidget.cxx" />
|
||||||
|
<ClCompile Include="..\gui\RomImageWidget.cxx" />
|
||||||
<ClCompile Include="..\gui\SnapshotDialog.cxx" />
|
<ClCompile Include="..\gui\SnapshotDialog.cxx" />
|
||||||
<ClCompile Include="..\gui\StellaSettingsDialog.cxx" />
|
<ClCompile Include="..\gui\StellaSettingsDialog.cxx" />
|
||||||
<ClCompile Include="..\gui\TimeLineWidget.cxx" />
|
<ClCompile Include="..\gui\TimeLineWidget.cxx" />
|
||||||
|
@ -2146,6 +2147,7 @@
|
||||||
<ClInclude Include="..\gui\R77HelpDialog.hxx" />
|
<ClInclude Include="..\gui\R77HelpDialog.hxx" />
|
||||||
<ClInclude Include="..\gui\RadioButtonWidget.hxx" />
|
<ClInclude Include="..\gui\RadioButtonWidget.hxx" />
|
||||||
<ClInclude Include="..\gui\Icons.hxx" />
|
<ClInclude Include="..\gui\Icons.hxx" />
|
||||||
|
<ClInclude Include="..\gui\RomImageWidget.hxx" />
|
||||||
<ClInclude Include="..\gui\SnapshotDialog.hxx" />
|
<ClInclude Include="..\gui\SnapshotDialog.hxx" />
|
||||||
<ClInclude Include="..\gui\Stella12x24tFont.hxx" />
|
<ClInclude Include="..\gui\Stella12x24tFont.hxx" />
|
||||||
<ClInclude Include="..\gui\Stella14x28tFont.hxx" />
|
<ClInclude Include="..\gui\Stella14x28tFont.hxx" />
|
||||||
|
|
|
@ -1146,6 +1146,9 @@
|
||||||
<ClCompile Include="..\debugger\gui\Joy2BPlusWidget.cxx">
|
<ClCompile Include="..\debugger\gui\Joy2BPlusWidget.cxx">
|
||||||
<Filter>Source Files\debugger</Filter>
|
<Filter>Source Files\debugger</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\gui\RomImageWidget.cxx">
|
||||||
|
<Filter>Source Files\gui</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\common\bspf.hxx">
|
<ClInclude Include="..\common\bspf.hxx">
|
||||||
|
@ -2372,6 +2375,9 @@
|
||||||
<ClInclude Include="..\debugger\gui\Joy2BPlusWidget.hxx">
|
<ClInclude Include="..\debugger\gui\Joy2BPlusWidget.hxx">
|
||||||
<Filter>Header Files\debugger</Filter>
|
<Filter>Header Files\debugger</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\gui\RomImageWidget.hxx">
|
||||||
|
<Filter>Header Files\gui</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="stella.ico">
|
<None Include="stella.ico">
|
||||||
|
|
Loading…
Reference in New Issue