Fixed 'rom info viewer' mode, and added a checkbox to 'UI Settings' to

enable/disable it.  Currently, you have to exit and restart the program
for this to take effect.

Fixed issues with resizing and toggling video renderers and the
image not being updated correctly.  Also, saving a snapshot within
emulation mode and exiting to launcher mode now shows the new
snapshot.

Currently, the rom info viewer only works with PNG images 320x250 or
less (ie, 1x zoom mode in Stella).  If the image is bigger, a message
is displayed stating that fact.  At some point I have to add another
snapshot mode where it always saves in 1x mode (or maybe not; it
depends on how many people will want to save snapshots for viewing in
the rom info viewer).


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@1428 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2008-03-13 22:58:07 +00:00
parent 90dce82289
commit b6598c1d9b
20 changed files with 274 additions and 219 deletions

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: FrameBufferGL.cxx,v 1.98 2008-03-08 13:22:12 stephena Exp $
// $Id: FrameBufferGL.cxx,v 1.99 2008-03-13 22:58:05 stephena Exp $
//============================================================================
#ifdef DISPLAY_OPENGL
@ -578,23 +578,27 @@ void FrameBufferGL::drawBitmap(uInt32* bitmap, Int32 tx, Int32 ty,
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferGL::drawSurface(const GUI::Surface* surface, Int32 x, Int32 y)
{
SDL_Rect clip;
clip.x = x;
clip.y = y;
SDL_Rect dstrect;
dstrect.x = x;
dstrect.y = y;
SDL_Rect srcrect;
srcrect.x = 0;
srcrect.y = 0;
srcrect.w = surface->myClipWidth;
srcrect.h = surface->myClipHeight;
SDL_BlitSurface(surface->myData, 0, myTexture, &clip);
SDL_BlitSurface(surface->myData, &srcrect, myTexture, &dstrect);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferGL::bytesToSurface(GUI::Surface* surface, int row,
uInt8* data) const
uInt8* data, int rowbytes) const
{
SDL_Surface* s = surface->myData;
uInt16* pixels = (uInt16*) s->pixels;
pixels += (row * s->pitch/2);
int rowsize = surface->getWidth() * 3;
for(int c = 0; c < rowsize; c += 3)
for(int c = 0; c < rowbytes; c += 3)
*pixels++ = SDL_MapRGB(s->format, data[c], data[c+1], data[c+2]);
}

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: FrameBufferGL.hxx,v 1.51 2008-02-06 13:45:19 stephena Exp $
// $Id: FrameBufferGL.hxx,v 1.52 2008-03-13 22:58:06 stephena Exp $
//============================================================================
#ifndef FRAMEBUFFER_GL_HXX
@ -35,7 +35,7 @@ class GUI::Font;
This class implements an SDL OpenGL framebuffer.
@author Stephen Anthony
@version $Id: FrameBufferGL.hxx,v 1.51 2008-02-06 13:45:19 stephena Exp $
@version $Id: FrameBufferGL.hxx,v 1.52 2008-03-13 22:58:06 stephena Exp $
*/
class FrameBufferGL : public FrameBuffer
{
@ -203,8 +203,10 @@ class FrameBufferGL : public FrameBuffer
@param surface The data to draw
@param row The row of the surface the data should be placed in
@param data The data in uInt8 R/G/B format
@param rowbytes The number of bytes in row of 'data'
*/
void bytesToSurface(GUI::Surface* surface, int row, uInt8* data) const;
void bytesToSurface(GUI::Surface* surface, int row,
uInt8* data, int rowbytes) const;
/**
This method translates the given coordinates to their

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: FrameBufferSoft.cxx,v 1.76 2008-02-19 12:33:02 stephena Exp $
// $Id: FrameBufferSoft.cxx,v 1.77 2008-03-13 22:58:06 stephena Exp $
//============================================================================
#include <sstream>
@ -640,51 +640,33 @@ void FrameBufferSoft::drawBitmap(uInt32* bitmap, Int32 xorig, Int32 yorig,
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferSoft::drawSurface(const GUI::Surface* surface, Int32 x, Int32 y)
{
SDL_Rect clip;
clip.x = x * myZoomLevel + myImageDim.x;
clip.y = y * myZoomLevel + myImageDim.y;
SDL_Rect dstrect;
dstrect.x = x * myZoomLevel + myImageDim.x;
dstrect.y = y * myZoomLevel + myImageDim.y;
SDL_Rect srcrect;
srcrect.x = 0;
srcrect.y = 0;
srcrect.w = surface->myClipWidth * myZoomLevel;
srcrect.h = surface->myClipHeight * myZoomLevel;
SDL_BlitSurface(surface->myData, 0, myScreen, &clip);
SDL_BlitSurface(surface->myData, &srcrect, myScreen, &dstrect);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferSoft::bytesToSurface(GUI::Surface* surface, int row,
uInt8* data) const
uInt8* data, int rowbytes) const
{
SDL_Surface* s = surface->myData;
int rowbytes = s->w * 3;
row *= myZoomLevel;
switch(myBytesPerPixel)
{
case 2:
{
uInt16* pixels = (uInt16*) s->pixels;
int surfbytes = s->pitch/2;
pixels += (row * surfbytes);
uInt8* pixel_ptr = (uInt8*)pixels;
// Calculate a scanline of zoomed surface data
for(int c = 0; c < rowbytes/myZoomLevel; c += 3)
SDL_Surface* s = surface->myData;
SDL_Rect rect;
rect.x = 0;
rect.y = row * myZoomLevel;
for(int c = 0; c < rowbytes; c += 3)
{
uInt32 pixel = SDL_MapRGB(s->format, data[c], data[c+1], data[c+2]);
uInt32 xstride = myZoomLevel;
while(xstride--)
*pixels++ = pixel;
}
// Now duplicate the scanlines (we've already done the first one)
uInt32 ystride = myZoomLevel-1;
while(ystride--)
{
memcpy(pixel_ptr + s->pitch, pixel_ptr, s->pitch);
pixel_ptr += s->pitch;
}
break;
}
default:
break;
rect.x += myZoomLevel;
rect.w = rect.h = myZoomLevel;
SDL_FillRect(surface->myData, &rect, pixel);
}
}

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: FrameBufferSoft.hxx,v 1.49 2008-02-06 13:45:19 stephena Exp $
// $Id: FrameBufferSoft.hxx,v 1.50 2008-03-13 22:58:06 stephena Exp $
//============================================================================
#ifndef FRAMEBUFFER_SOFT_HXX
@ -33,7 +33,7 @@ class RectList;
This class implements an SDL software framebuffer.
@author Stephen Anthony
@version $Id: FrameBufferSoft.hxx,v 1.49 2008-02-06 13:45:19 stephena Exp $
@version $Id: FrameBufferSoft.hxx,v 1.50 2008-03-13 22:58:06 stephena Exp $
*/
class FrameBufferSoft : public FrameBuffer
{
@ -192,8 +192,10 @@ class FrameBufferSoft : public FrameBuffer
@param surface The data to draw
@param row The row of the surface the data should be placed in
@param data The data in uInt8 R/G/B format
@param rowbytes The number of bytes in row of 'data'
*/
void bytesToSurface(GUI::Surface* surface, int row, uInt8* data) const;
void bytesToSurface(GUI::Surface* surface, int row,
uInt8* data, int rowbytes) const;
/**
This method translates the given coordinates to their

View File

@ -14,7 +14,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: EventHandler.cxx,v 1.217 2008-03-03 16:14:50 stephena Exp $
// $Id: EventHandler.cxx,v 1.218 2008-03-13 22:58:06 stephena Exp $
//============================================================================
#include <sstream>
@ -756,7 +756,8 @@ void EventHandler::poll(uInt32 time)
myOverlay->updateTime(time);
}
// Turn off relative events
// Turn off relative events; we assume they've been taken care of
// in at least one of the ::update() methods above
myEvent->set(Event::MouseAxisXValue, 0);
myEvent->set(Event::MouseAxisYValue, 0);
}
@ -898,8 +899,10 @@ void EventHandler::handleJoyHatEvent(int stick, int hat, int value)
void EventHandler::handleResizeEvent()
{
// For now, only the overlay cares about resize events
if(myOverlay != NULL)
myOverlay->handleResizeEvent();
// We don't know which one wants it, so we send it to all of them
// These events need to be sent even if the overlay isn't active
if(&myOSystem->launcher())
myOSystem->launcher().handleResizeEvent();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -1800,8 +1803,7 @@ void EventHandler::takeSnapshot()
if(sspath.length() > 0)
if(sspath.substr(sspath.length()-1) != BSPF_PATH_SEPARATOR)
sspath += BSPF_PATH_SEPARATOR;
sspath += myOSystem->console().properties().get(Cartridge_Name) + "." +
myOSystem->console().properties().get(Cartridge_MD5);
sspath += myOSystem->console().properties().get(Cartridge_Name);
// Check whether we want multiple snapshots created
if(!myOSystem->settings().getBool("sssingle"))

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: FrameBuffer.cxx,v 1.125 2008-02-06 13:45:21 stephena Exp $
// $Id: FrameBuffer.cxx,v 1.126 2008-03-13 22:58:06 stephena Exp $
//============================================================================
#include <sstream>
@ -456,19 +456,13 @@ void FrameBuffer::setCursorState()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBuffer::showCursor(bool show)
{
if(show)
SDL_ShowCursor(SDL_ENABLE);
else
SDL_ShowCursor(SDL_DISABLE);
SDL_ShowCursor(show ? SDL_ENABLE : SDL_DISABLE);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBuffer::grabMouse(bool grab)
{
if(grab)
SDL_WM_GrabInput(SDL_GRAB_ON);
else
SDL_WM_GrabInput(SDL_GRAB_OFF);
SDL_WM_GrabInput(grab ? SDL_GRAB_ON : SDL_GRAB_OFF);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: FrameBuffer.hxx,v 1.93 2008-02-06 13:45:21 stephena Exp $
// $Id: FrameBuffer.hxx,v 1.94 2008-03-13 22:58:06 stephena Exp $
//============================================================================
#ifndef FRAMEBUFFER_HXX
@ -101,7 +101,7 @@ enum {
All GUI elements (ala ScummVM) are drawn here as well.
@author Stephen Anthony
@version $Id: FrameBuffer.hxx,v 1.93 2008-02-06 13:45:21 stephena Exp $
@version $Id: FrameBuffer.hxx,v 1.94 2008-03-13 22:58:06 stephena Exp $
*/
class FrameBuffer
{
@ -385,9 +385,10 @@ class FrameBuffer
@param surface The data to draw
@param row The row of the surface the data should be placed in
@param data The data in uInt8 R/G/B format
@param rowbytes The number of bytes in row of 'data'
*/
virtual void bytesToSurface(GUI::Surface* surface, int row,
uInt8* data) const = 0;
uInt8* data, int rowbytes) const = 0;
/**
This method should be called to translate the given coordinates

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: OSystem.cxx,v 1.116 2008-03-03 14:53:34 stephena Exp $
// $Id: OSystem.cxx,v 1.117 2008-03-13 22:58:06 stephena Exp $
//============================================================================
#include <cassert>
@ -320,28 +320,6 @@ bool OSystem::createFrameBuffer(bool showmessage)
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string OSystem::getFilename(const string& path, const Properties& props,
const string& ext) const
{
const string& full_name =
path + BSPF_PATH_SEPARATOR + props.get(Cartridge_Name) + "." +
props.get(Cartridge_MD5) + "." + ext;
const string& rom_name =
path + BSPF_PATH_SEPARATOR + props.get(Cartridge_Name) + "." + ext;
const string& md5_name =
path + BSPF_PATH_SEPARATOR + props.get(Cartridge_MD5) + "." + ext;
if(FilesystemNode::fileExists(full_name))
return full_name;
else if(FilesystemNode::fileExists(rom_name))
return rom_name;
else if(FilesystemNode::fileExists(md5_name))
return md5_name;
else
return EmptyString;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void OSystem::toggleFrameBuffer()
{

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: OSystem.hxx,v 1.60 2008-02-06 13:45:22 stephena Exp $
// $Id: OSystem.hxx,v 1.61 2008-03-13 22:58:06 stephena Exp $
//============================================================================
#ifndef OSYSTEM_HXX
@ -55,7 +55,7 @@ typedef Common::Array<Resolution> ResolutionList;
other objects belong.
@author Stephen Anthony
@version $Id: OSystem.hxx,v 1.60 2008-02-06 13:45:22 stephena Exp $
@version $Id: OSystem.hxx,v 1.61 2008-03-13 22:58:06 stephena Exp $
*/
class OSystem
{
@ -289,23 +289,6 @@ class OSystem
*/
const string& romFile() const { return myRomFile; }
/**
Determines a valid filename for the given properties and extension.
Currently, there are three possibilities, in order of precedence:
Cart_Name.Cart_MD5.ext
Cart_Name.ext
Cart_MD5.ext
@param path The full path to prepend to the filename
@param props The ROM properties for the given ROM
@param ext The extension to append to the filename
@return A valid file (which exists), or the empty string
*/
string getFilename(const string& path, const Properties& props,
const string& ext) const;
/**
Switches between software and OpenGL framebuffer modes.
*/

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: FrameBufferGP2X.cxx,v 1.25 2008-02-20 00:17:49 stephena Exp $
// $Id: FrameBufferGP2X.cxx,v 1.26 2008-03-13 22:58:06 stephena Exp $
//============================================================================
#include <SDL.h>
@ -345,19 +345,21 @@ void FrameBufferGP2X::drawBitmap(uInt32* bitmap, Int32 xorig, Int32 yorig,
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferGP2X::drawSurface(const GUI::Surface* surface, Int32 x, Int32 y)
{
/* TODO - not supported yet
SDL_Rect clip;
clip.x = x;
clip.y = y;
SDL_BlitSurface(surface->myData, 0, myScreen, &clip);
*/
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferGP2X::bytesToSurface(GUI::Surface* surface, int row,
uInt8* data) const
uInt8* data, int rowbytes) const
{
/* TODO - not supported yet
SDL_Surface* s = surface->myData;
int rowbytes = s->w * 3;
uInt16* pixels = (uInt16*) s->pixels;
int surfbytes = s->pitch/2;
@ -369,6 +371,7 @@ void FrameBufferGP2X::bytesToSurface(GUI::Surface* surface, int row,
uInt32 pixel = SDL_MapRGB(s->format, data[c], data[c+1], data[c+2]);
*pixels++ = pixel;
}
*/
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: FrameBufferGP2X.hxx,v 1.12 2008-02-20 00:17:49 stephena Exp $
// $Id: FrameBufferGP2X.hxx,v 1.13 2008-03-13 22:58:06 stephena Exp $
//============================================================================
#ifndef FRAMEBUFFER_GP2X_HXX
@ -32,7 +32,7 @@ class GUI::Font;
This class implements an SDL hardware framebuffer for the GP2X device.
@author Stephen Anthony
@version $Id: FrameBufferGP2X.hxx,v 1.12 2008-02-20 00:17:49 stephena Exp $
@version $Id: FrameBufferGP2X.hxx,v 1.13 2008-03-13 22:58:06 stephena Exp $
*/
class FrameBufferGP2X : public FrameBuffer
{
@ -194,9 +194,10 @@ class FrameBufferGP2X : public FrameBuffer
@param surface The data to draw
@param row The row of the surface the data should be placed in
@param data The data in uInt8 R/G/B format
@param rowbytes The number of bytes in row of 'data'
*/
void bytesToSurface(GUI::Surface* surface, int row, uInt8* data) const;
void bytesToSurface(GUI::Surface* surface, int row,
uInt8* data, int rowbytes) const;
/**
This method translates the given coordinates to their

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: DialogContainer.cxx,v 1.40 2008-03-02 19:20:50 stephena Exp $
// $Id: DialogContainer.cxx,v 1.41 2008-03-13 22:58:06 stephena Exp $
//============================================================================
#include "OSystem.hxx"
@ -329,10 +329,8 @@ void DialogContainer::handleJoyHatEvent(int stick, int hat, int value)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void DialogContainer::handleResizeEvent()
{
// Send resize events to all dialogs
// It's up to a specific dialog to actually listen
for(int i = 0; i < myDialogStack.size(); i++)
myDialogStack[i]->handleCommand(NULL, kResizeCmd, 0, 0);
// Send resize event to base dialog; it's up to the dialog to actually listen
myBaseDialog->handleCommand(NULL, kResizeCmd, 0, 0);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: LauncherDialog.cxx,v 1.78 2008-03-12 22:04:52 stephena Exp $
// $Id: LauncherDialog.cxx,v 1.79 2008-03-13 22:58:06 stephena Exp $
//
// Based on code from ScummVM - Scumm Interpreter
// Copyright (C) 2002-2004 The ScummVM project
@ -201,6 +201,9 @@ void LauncherDialog::loadConfig()
updateListing();
}
Dialog::setFocus(getFocusList()[mySelectedItem]);
if(myRomInfoFlag)
myRomInfoWidget->loadConfig();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -370,7 +373,7 @@ void LauncherDialog::createListCache()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void LauncherDialog::loadRomInfo()
{
if(!myRomInfoFlag) return;
if(!(myRomInfoFlag && myRomInfoWidget)) return;
int item = myList->getSelected();
if(item < 0 || myGameList->isDir(item)) return;
@ -385,10 +388,10 @@ void LauncherDialog::loadRomInfo()
const string& md5 = myGameList->md5(item);
instance()->propSet().getMD5(md5, props);
myRomInfoWidget->showInfo(props);
myRomInfoWidget->setProperties(props);
}
else
myRomInfoWidget->clearInfo();
myRomInfoWidget->clearProperties();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -489,7 +492,11 @@ void LauncherDialog::handleCommand(CommandSender* sender, int cmd,
case kResizeCmd:
// Instead of figuring out how to resize the snapshot image,
// we just reload it
if(myRomInfoFlag)
{
myRomInfoWidget->initialize();
loadRomInfo();
}
break;
default:

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: OptionsDialog.cxx,v 1.64 2008-03-12 22:04:53 stephena Exp $
// $Id: OptionsDialog.cxx,v 1.65 2008-03-13 22:58:07 stephena Exp $
//
// Based on code from ScummVM - Scumm Interpreter
// Copyright (C) 2002-2004 The ScummVM project
@ -124,7 +124,7 @@ OptionsDialog::OptionsDialog(OSystem* osystem, DialogContainer* parent,
#endif
myInputDialog = new InputDialog(myOSystem, parent, font, x, y, w, h);
w = 200; h = 155;
w = 200; h = 175;
myUIDialog = new UIDialog(myOSystem, parent, font, x, y, w, h);
w = 280; h = 180;

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: RomInfoWidget.cxx,v 1.4 2008-03-08 13:22:12 stephena Exp $
// $Id: RomInfoWidget.cxx,v 1.5 2008-03-13 22:58:07 stephena Exp $
//============================================================================
#include <cstring>
@ -31,7 +31,9 @@
RomInfoWidget::RomInfoWidget(GuiObject* boss, const GUI::Font& font,
int x, int y, int w, int h)
: Widget(boss, font, x, y, w, h),
mySurface(NULL)
mySurface(NULL),
myDrawSurface(false),
myHaveProperties(false)
{
_flags = WIDGET_ENABLED | WIDGET_RETAIN_FOCUS;
_bgcolor = _bgcolorhi = kWidColor;
@ -40,17 +42,75 @@ RomInfoWidget::RomInfoWidget(GuiObject* boss, const GUI::Font& font,
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
RomInfoWidget::~RomInfoWidget()
{
clearInfo(false);
if(mySurface)
{
delete mySurface;
mySurface = NULL;
}
myRomInfo.clear();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void RomInfoWidget::loadConfig()
{
// 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();
setDirty(); draw();
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void RomInfoWidget::showInfo(const Properties& props)
void RomInfoWidget::setProperties(const Properties& props)
{
myHaveProperties = true;
myProperties = props;
// Decide whether the information should be shown immediately
if(instance()->eventHandler().state() == EventHandler::S_LAUNCHER)
{
parseProperties();
setDirty(); draw();
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void RomInfoWidget::clearProperties()
{
myHaveProperties = myDrawSurface = false;
// Decide whether the information should be shown immediately
if(instance()->eventHandler().state() == EventHandler::S_LAUNCHER)
{
setDirty(); draw();
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void RomInfoWidget::initialize()
{
// Delete surface; a new one will be created by parseProperties
delete mySurface;
mySurface = NULL;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void RomInfoWidget::parseProperties()
{
// Initialize to empty properties entry
mySurfaceErrorMsg = "";
myDrawSurface = false;
myRomInfo.clear();
// 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 == NULL)
mySurface = instance()->frameBuffer().createSurface(320, 250);
// The input stream for the PNG file
ifstream in;
@ -63,11 +123,11 @@ void RomInfoWidget::showInfo(const Properties& props)
StringList textChucks;
// Get a valid filename representing a snapshot file for this rom
const string& path = instance()->settings().getString("ssdir");
const string& filename = instance()->getFilename(path, props, "png");
const string& filename =
instance()->settings().getString("ssdir") + BSPF_PATH_SEPARATOR +
myProperties.get(Cartridge_Name) + ".png";
// Open the PNG and check for a valid signature
clearInfo(false);
in.open(filename.c_str(), ios_base::binary);
if(in)
{
@ -76,7 +136,7 @@ void RomInfoWidget::showInfo(const Properties& props)
uInt8 header[8];
in.read((char*)header, 8);
if(!isValidPNGHeader(header))
throw "RomInfoWidget: Not a PNG image";
throw "Invalid PNG image";
// Read all chunks until we reach the end
int width = 0, height = 0;
@ -84,18 +144,19 @@ void RomInfoWidget::showInfo(const Properties& props)
{
readPNGChunk(in, type, &data, size);
if(type == "IHDR" && !parseIHDR(width, height, data, size))
throw "RomInfoWidget: IHDR chunk not supported";
if(type == "IHDR")
{
if(!parseIHDR(width, height, data, size))
throw "Invalid PNG image (IHDR)";
mySurface->setClipWidth(width);
mySurface->setClipHeight(height);
}
else if(type == "IDAT")
{
// Restrict surface size to available space
int s_width = BSPF_min(320, width);
int s_height = BSPF_min(250, height);
FrameBuffer& fb = instance()->frameBuffer();
mySurface = fb.createSurface(s_width, s_height);
if(!parseIDATChunk(fb, mySurface, width, height, data, size))
throw "RomInfoWidget: IDAT processing failed";
if(!parseIDATChunk(instance()->frameBuffer(), mySurface,
width, height, data, size))
throw "PNG image too large";
}
else if(type == "tEXt")
textChucks.push_back(parseTextChunk(data, size));
@ -104,41 +165,32 @@ void RomInfoWidget::showInfo(const Properties& props)
}
in.close();
myDrawSurface = true;
}
catch(const char* msg)
{
clearInfo(false);
myDrawSurface = false;
myRomInfo.clear();
if(data) delete[] data;
data = NULL;
in.close();
cerr << msg << endl;
mySurfaceErrorMsg = msg;
return;
}
}
else
mySurfaceErrorMsg = "No image found";
// Now add some info for the message box below the image
myRomInfo.push_back("Name: " + props.get(Cartridge_Name));
myRomInfo.push_back("Manufacturer: " + props.get(Cartridge_Manufacturer));
myRomInfo.push_back("Model: " + props.get(Cartridge_ModelNo));
myRomInfo.push_back("Rarity: " + props.get(Cartridge_Rarity));
myRomInfo.push_back("Note: " + props.get(Cartridge_Note));
myRomInfo.push_back("Controllers: " + props.get(Controller_Left) +
" (left), " + props.get(Controller_Right) + " (right)");
myRomInfo.push_back("Name: " + myProperties.get(Cartridge_Name));
myRomInfo.push_back("Manufacturer: " + myProperties.get(Cartridge_Manufacturer));
myRomInfo.push_back("Model: " + myProperties.get(Cartridge_ModelNo));
myRomInfo.push_back("Rarity: " + myProperties.get(Cartridge_Rarity));
myRomInfo.push_back("Note: " + myProperties.get(Cartridge_Note));
myRomInfo.push_back("Controllers: " + myProperties.get(Controller_Left) +
" (left), " + myProperties.get(Controller_Right) + " (right)");
// TODO - add the PNG tEXt chunks
setDirty(); draw();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void RomInfoWidget::clearInfo(bool redraw)
{
if(mySurface)
delete mySurface;
mySurface = NULL;
myRomInfo.clear();
if(redraw)
{
setDirty(); draw();
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -150,12 +202,19 @@ void RomInfoWidget::drawWidget(bool hilite)
fb.box(_x, _y, _w, _h, kColor, kShadowColor);
fb.box(_x, _y+254, _w, _h-254, kColor, kShadowColor);
if(mySurface)
if(!myHaveProperties) return;
if(myDrawSurface && mySurface)
{
int x = (_w - mySurface->getWidth()) >> 1;
int y = (256 - mySurface->getHeight()) >> 1;
int x = (_w - mySurface->getClipWidth()) >> 1;
int y = (256 - mySurface->getClipHeight()) >> 1;
fb.drawSurface(mySurface, x + getAbsX(), y + getAbsY());
}
else if(mySurfaceErrorMsg != "")
{
int x = _x + ((_w - _font->getStringWidth(mySurfaceErrorMsg)) >> 1);
fb.drawString(_font, mySurfaceErrorMsg, x, 120, _w - 10, _textcolor);
}
int xpos = _x + 5, ypos = _y + 256 + 5;
for(unsigned int i = 0; i < myRomInfo.size(); ++i)
{
@ -208,6 +267,10 @@ bool RomInfoWidget::parseIHDR(int& width, int& height, uInt8* data, int size)
width = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
height = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7];
// Make sure image can fit in widget bounds
width = BSPF_min(320, width);
height = BSPF_min(250, height);
uInt8 trailer[5] = { 8, 2, 0, 0, 0 }; // 24-bit RGB
return memcmp(trailer, data + 8, 5) == 0;
}
@ -220,28 +283,21 @@ bool RomInfoWidget::parseIDATChunk(const FrameBuffer& fb, GUI::Surface* surface,
uLongf bufsize = (width * 3 + 1) * height;
uInt8* buffer = new uInt8[bufsize];
// Only get as many scanlines as necessary to fill the surface
height = BSPF_min(250, height);
int pitch = width * 3; // bytes per line of the image
if(uncompress(buffer, &bufsize, data, size) == Z_OK)
{
uInt8* buf_ptr = buffer;
int pitch = width * 3; // bytes per line of the image
for(int row = 0; row < height; row++, buf_ptr += pitch)
{
buf_ptr++; // skip past first byte (PNG filter type)
fb.bytesToSurface(surface, row, buf_ptr);
fb.bytesToSurface(surface, row, buf_ptr, pitch);
}
}
else
{
cerr << "RomInfoWidget: error decompressing data\n";
return false;
}
delete[] buffer;
return true;
}
delete[] buffer;
return false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string RomInfoWidget::parseTextChunk(uInt8* data, int size)

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: RomInfoWidget.hxx,v 1.3 2008-02-06 13:45:24 stephena Exp $
// $Id: RomInfoWidget.hxx,v 1.4 2008-03-13 22:58:07 stephena Exp $
//============================================================================
#ifndef ROM_INFO_WIDGET_HXX
@ -37,14 +37,16 @@ class RomInfoWidget : public Widget
int x, int y, int w, int h);
virtual ~RomInfoWidget();
void showInfo(const Properties& props);
void clearInfo(bool redraw = true);
void setProperties(const Properties& props);
void clearProperties();
void initialize();
void loadConfig();
protected:
void loadConfig();
void drawWidget(bool hilite);
private:
void parseProperties();
static bool isValidPNGHeader(uInt8* header);
static void readPNGChunk(ifstream& in, string& type, uInt8** data, int& size);
static bool parseIHDR(int& width, int& height, uInt8* data, int size);
@ -56,8 +58,20 @@ class RomInfoWidget : public Widget
// Surface holding the scaled PNG image
GUI::Surface* mySurface;
// Whether the surface should be redrawn by drawWidget()
bool myDrawSurface;
// Some ROM properties info, as well as 'tEXt' chunks from the PNG image
StringList myRomInfo;
// The properties for the currently selected ROM
Properties myProperties;
// Indicates if the current properties should actually be used
bool myHaveProperties;
// Indicates if an error occurred in creating/displaying the surface
string mySurfaceErrorMsg;
};
#endif

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Surface.cxx,v 1.2 2008-02-06 13:45:24 stephena Exp $
// $Id: Surface.cxx,v 1.3 2008-03-13 22:58:07 stephena Exp $
//
// Based on code from ScummVM - Scumm Interpreter
// Copyright (C) 2002-2004 The ScummVM project
@ -29,6 +29,8 @@ namespace GUI {
Surface::Surface(int width, int height, SDL_Surface* data)
: myBaseWidth(width),
myBaseHeight(height),
myClipWidth(width),
myClipHeight(height),
myData(data)
{
}

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Surface.hxx,v 1.2 2008-02-06 13:45:24 stephena Exp $
// $Id: Surface.hxx,v 1.3 2008-03-13 22:58:07 stephena Exp $
//============================================================================
#ifndef GUI_SURFACE_HXX
@ -26,26 +26,36 @@ namespace GUI {
/**
This class is basically a thin wrapper around an SDL_Surface structure.
We do it this way so the SDL stuff won't be dragged into the depths of
the codebase.
the codebase. Although everything is public and SDL structures can be
used directly, it's recommended to only access the variables from the
advertised interface, or from FrameBuffer-derived classes.
@author Stephen Anthony
@version $Id: Surface.hxx,v 1.2 2008-02-06 13:45:24 stephena Exp $
@version $Id: Surface.hxx,v 1.3 2008-03-13 22:58:07 stephena Exp $
*/
class Surface
{
friend class FrameBuffer;
public:
Surface(int width, int height, SDL_Surface* surface);
virtual ~Surface();
int getWidth() const { return myBaseWidth; }
int getHeight() const { return myBaseHeight; }
/** Actual width and height of the SDL surface */
inline int getWidth() const { return myBaseWidth; }
inline int getHeight() const { return myBaseHeight; }
/** Clipped/drawn width and height of the SDL surface */
inline int getClipWidth() const { return myClipWidth; }
inline int getClipHeight() const { return myClipHeight; }
inline void setClipWidth(int w) { myClipWidth = w; }
inline void setClipHeight(int h) { myClipHeight = h; }
public:
int myBaseWidth;
int myBaseHeight;
int myClipWidth;
int myClipHeight;
SDL_Surface* myData;
};

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: UIDialog.cxx,v 1.9 2008-02-06 13:45:24 stephena Exp $
// $Id: UIDialog.cxx,v 1.10 2008-03-13 22:58:07 stephena Exp $
//
// Based on code from ScummVM - Scumm Interpreter
// Copyright (C) 2002-2004 The ScummVM project
@ -128,6 +128,11 @@ UIDialog::UIDialog(OSystem* osystem, DialogContainer* parent,
wid.push_back(myPalettePopup);
ypos += lineHeight + 4;
// ROM info viewer
xpos += ((_w - 40 - font.getStringWidth("ROM Info viewer (*)")) >> 1);
myRomViewerCheckbox = new CheckboxWidget(this, font, xpos, ypos,
"ROM Info viewer (*)", 0);
// Add message concerning usage
lwidth = font.getStringWidth("(*) Requires application restart");
new StaticTextWidget(this, font, 10, _h - 38, lwidth, fontHeight,
@ -212,6 +217,10 @@ void UIDialog::loadConfig()
int i = instance()->settings().getInt("uipalette");
if(i < 1 || i > 2) i = 1;
myPalettePopup->setSelectedTag(i);
// ROM info viewer
bool b = instance()->settings().getBool("romviewer");
myRomViewerCheckbox->setState(b);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -233,13 +242,17 @@ void UIDialog::saveConfig()
// UI palette
instance()->settings().setInt("uipalette",
myPalettePopup->getSelectedTag());
// ROM info viewer
instance()->settings().setBool("romviewer",
myRomViewerCheckbox->getState());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void UIDialog::setDefaults()
{
int w = BSPF_min(instance()->desktopWidth(), (const uInt32) 400);
int h = BSPF_min(instance()->desktopHeight(), (const uInt32) 300);
int w = BSPF_min(instance()->desktopWidth(), 400u);
int h = BSPF_min(instance()->desktopHeight(), 300u);
myLauncherWidthSlider->setValue(w);
myLauncherWidthLabel->setValue(w);
myLauncherHeightSlider->setValue(h);

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: UIDialog.hxx,v 1.6 2008-02-06 13:45:24 stephena Exp $
// $Id: UIDialog.hxx,v 1.7 2008-03-13 22:58:07 stephena Exp $
//
// Based on code from ScummVM - Scumm Interpreter
// Copyright (C) 2002-2004 The ScummVM project
@ -25,6 +25,7 @@
class CommandSender;
class Dialog;
class DialogContainer;
class CheckboxWidget;
class PopUpWidget;
class SliderWidget;
class StaticTextWidget;
@ -55,6 +56,8 @@ class UIDialog : public Dialog
PopUpWidget* myPalettePopup;
CheckboxWidget* myRomViewerCheckbox;
private:
void loadConfig();
void saveConfig();