Starting to add GUI code from ScummVM.

git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@377 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2005-02-27 23:41:19 +00:00
parent f3b4648eac
commit 5489ca7248
15 changed files with 1124 additions and 108 deletions

View File

@ -12,12 +12,15 @@
Release History
===============================================================================
1.4.2a to 1.4.2b: MacOSX version only (February 27, 2005)
* Added fix to mute sound while user is loading a new cartridge, or using
the Preferences window.
1.4.2 to 1.4.2a: MacOSX version only (February 21, 2005)
* Fixed problem in timing loop which was causing crashes after 15-30
minutes.
* Turned optimization on in compiler settings, which had somehow gotten
turned off.

View File

@ -1,13 +1,11 @@
Please distribute this file with the SDL runtime environment:
The Simple DirectMedia Layer (SDL for short) is a cross-platfrom library
designed to make it easy to write multi-media software, such as games and
emulators.
The Simple DirectMedia Layer library source code is available from:
http://www.libsdl.org/
This library is distributed under the terms of the GNU LGPL license:
http://www.gnu.org/copyleft/lesser.html
Please distribute this file with the SDL runtime environment:
The Simple DirectMedia Layer (SDL for short) is a cross-platfrom library
designed to make it easy to write multi-media software, such as games and
emulators.
The Simple DirectMedia Layer library source code is available from:
http://www.libsdl.org/
This library is distributed under the terms of the GNU LGPL license:
http://www.gnu.org/copyleft/lesser.html

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: makefile,v 1.61 2005-02-22 02:59:52 stephena Exp $
## $Id: makefile,v 1.62 2005-02-27 23:41:17 stephena Exp $
##============================================================================
##============================================================================
@ -32,7 +32,7 @@ OPTIMIZATIONS =
### to include support for saving snapshots in png format
### (requires PNG library)
SNAPSHOT_SUPPORT = 1
# SNAPSHOT_SUPPORT = 1
### to include support for game developers
### enables some extra commandline options that allow the user
@ -41,7 +41,7 @@ OPTIMIZATIONS =
### to build on SMP (or distcc-based) machines
### change to number of CPU's you have
NUMBER_CPU = 1
NUMBER_CPU = 3
##============================================================================
## All done, type make to get a list of frontends

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: mainSDL.cxx,v 1.26 2005-02-25 02:29:37 stephena Exp $
// $Id: mainSDL.cxx,v 1.27 2005-02-27 23:41:17 stephena Exp $
//============================================================================
#include <fstream>
@ -876,7 +876,7 @@ int main(int argc, char* argv[])
theShowInfoFlag = theSettings->getBool("showinfo");
theGrabMouseIndicator = theSettings->getBool("grabmouse");
theHideCursorIndicator = theSettings->getBool("hidecursor");
bool theRomLauncherFlag = true;//theSettings->getBool("romlauncher");
bool theRomLauncherFlag = false;//true;//FIXMEtheSettings->getBool("romlauncher");
// Create a properties set for us to use and set it up
PropertiesSet propertiesSet;
@ -971,9 +971,10 @@ int main(int argc, char* argv[])
break;
else
{
cerr << "Attempting to open " << romfile << endl;
theConsole = CreateConsole(romfile);
mainGameLoop();
if((theConsole = CreateConsole(romfile)) != NULL)
mainGameLoop();
else
break;
}
}
}

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: EventHandler.cxx,v 1.34 2005-02-25 02:29:38 stephena Exp $
// $Id: EventHandler.cxx,v 1.35 2005-02-27 23:41:18 stephena Exp $
//============================================================================
#include <algorithm>
@ -127,10 +127,6 @@ void EventHandler::handleKeyEvent(SDLKey key, SDLMod mod, uInt8 state)
// Determine which mode we're in, then send the event to the appropriate place
switch(myState)
{
case S_NONE:
return;
break;
case S_EMULATE:
// if(mod & KMOD_ALT && state)
// handleEvent(myAltKeyTable[key], state);
@ -140,17 +136,21 @@ void EventHandler::handleKeyEvent(SDLKey key, SDLMod mod, uInt8 state)
handleEvent(myKeyTable[key], state);
break;
case S_BROWSER:
//FIXME myOSystem->gui().browser().handleKeyEvent(key, mod, state);
break;
case S_MENU:
//FIXME myOSystem->gui().menu().handleKeyEvent(key, mod, state);
break;
case S_BROWSER:
//FIXME myOSystem->gui().browser().handleKeyEvent(key, mod, state);
break;
case S_DEBUGGER:
// Not yet implemented
break;
case S_NONE:
return;
break;
}
}

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: EventHandler.hxx,v 1.17 2005-02-25 02:29:38 stephena Exp $
// $Id: EventHandler.hxx,v 1.18 2005-02-27 23:41:19 stephena Exp $
//============================================================================
#ifndef EVENTHANDLER_HXX
@ -32,17 +32,16 @@ class OSystem;
This class takes care of event remapping and dispatching for the
Stella core, as well as keeping track of the current 'mode'.
The frontends will send translated events here, and the handler will
check to see what the current 'mode' is. For now, the modes can be
normal and menu mode.
The frontend will send translated events here, and the handler will
check to see what the current 'mode' is.
If in normal mode, events received from the frontends are remapped and
If in emulation mode, events received from the frontend are remapped and
sent to the emulation core. If in menu mode, the events are sent
unchanged to the user interface, where (among other things) changing key
unchanged to the menu class, where (among other things) changing key
mapping can take place.
@author Stephen Anthony
@version $Id: EventHandler.hxx,v 1.17 2005-02-25 02:29:38 stephena Exp $
@version $Id: EventHandler.hxx,v 1.18 2005-02-27 23:41:19 stephena Exp $
*/
class EventHandler
{

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.16 2005-02-22 18:40:59 stephena Exp $
// $Id: FrameBuffer.cxx,v 1.17 2005-02-27 23:41:19 stephena Exp $
//============================================================================
#include <sstream>
@ -192,82 +192,96 @@ void FrameBuffer::update()
// Do any pre-frame stuff
preFrameUpdate();
// Determine which mode we are in (normal or menu mode)
// In normal mode, only the mediasource or messages are shown,
// and they are shown per-frame
// In menu mode, any of the menus are shown, but the mediasource
// is not updated, and all updates depend on whether the screen is dirty
if(!myMenuMode)
// Determine which mode we are in (from the EventHandler)
// Take care of S_EMULATE mode here, otherwise let the GUI
// figure out what to draw
switch(myOSystem->eventHandler().state())
{
// Draw changes to the mediasource
if(!myPauseStatus)
myOSystem->console().mediaSource().update();
// We always draw the screen, even if the core is paused
drawMediaSource();
if(!myPauseStatus)
case EventHandler::S_EMULATE:
{
// Draw any pending messages
if(myMessageTime > 0)
{
uInt32 width = myMessageText.length()*FONTWIDTH + FONTWIDTH;
uInt32 height = LINEOFFSET + FONTHEIGHT;
uInt32 x = (myWidth >> 1) - (width >> 1);
uInt32 y = myHeight - height - LINEOFFSET/2;
// Draw changes to the mediasource
if(!myPauseStatus)
myOSystem->console().mediaSource().update();
// Draw the bounded box and text
drawBoundedBox(x, y+1, width, height-2);
drawText(x + XBOXOFFSET/2, LINEOFFSET/2 + y, myMessageText);
myMessageTime--;
// Erase this message on next update
if(myMessageTime == 0)
theRedrawEntireFrameIndicator = true;
}
}
}
else // we are in MENU_MODE
{
// Only update the screen if it's been invalidated
// or the menus have changed
if(theMenuChangedIndicator || theRedrawEntireFrameIndicator)
{
// We always draw the screen, even if the core is paused
drawMediaSource();
// Then overlay any menu items
switch(myCurrentWidget)
if(!myPauseStatus)
{
case W_NONE:
break;
// Draw any pending messages
if(myMessageTime > 0)
{
uInt32 width = myMessageText.length()*FONTWIDTH + FONTWIDTH;
uInt32 height = LINEOFFSET + FONTHEIGHT;
uInt32 x = (myWidth >> 1) - (width >> 1);
uInt32 y = myHeight - height - LINEOFFSET/2;
case MAIN_MENU:
drawMainMenu();
break;
// Draw the bounded box and text
drawBoundedBox(x, y+1, width, height-2);
drawText(x + XBOXOFFSET/2, LINEOFFSET/2 + y, myMessageText);
myMessageTime--;
case REMAP_MENU:
drawRemapMenu();
break;
case INFO_MENU:
drawInfoMenu();
break;
default:
break;
// Erase this message on next update
if(myMessageTime == 0)
theRedrawEntireFrameIndicator = true;
}
}
// Now the screen is up to date
theRedrawEntireFrameIndicator = false;
// This is a performance hack to only draw the menus when necessary
// Software mode is single-buffered, so we don't have to worry
// However, OpenGL mode is double-buffered, so we need to draw the
// menus at least twice (so they'll be in both buffers)
// Otherwise, we get horrible flickering
myMenuRedraws--;
theMenuChangedIndicator = (myMenuRedraws != 0);
break; // S_EMULATE
}
case EventHandler::S_MENU: // FIXME - this whole thing will disappear into the gui().menu class
{
// Only update the screen if it's been invalidated
// or the menus have changed
if(theMenuChangedIndicator || theRedrawEntireFrameIndicator)
{
drawMediaSource();
// Then overlay any menu items
// FIXME myOSystem->gui().menu().draw();
switch(myCurrentWidget)
{
case W_NONE:
break;
case MAIN_MENU:
drawMainMenu();
break;
case REMAP_MENU:
drawRemapMenu();
break;
case INFO_MENU:
drawInfoMenu();
break;
default:
break;
}
// Now the screen is up to date
theRedrawEntireFrameIndicator = false;
// This is a performance hack to only draw the menus when necessary
// Software mode is single-buffered, so we don't have to worry
// However, OpenGL mode is double-buffered, so we need to draw the
// menus at least twice (so they'll be in both buffers)
// Otherwise, we get horrible flickering
myMenuRedraws--;
theMenuChangedIndicator = (myMenuRedraws != 0);
}
break;
}
case EventHandler::S_BROWSER:
// FIXME myOSystem->gui().browser().draw();
break;
case EventHandler::S_DEBUGGER:
// Not yet implemented
break;
case EventHandler::S_NONE:
return;
break;
}
// Do any post-frame stuff

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.16 2005-02-22 18:41:11 stephena Exp $
// $Id: FrameBuffer.hxx,v 1.17 2005-02-27 23:41:19 stephena Exp $
//============================================================================
#ifndef FRAMEBUFFER_HXX
@ -39,7 +39,7 @@ FIXME This class also implements a MAME-like user interface where Stella settin
can be changed.
@author Stephen Anthony
@version $Id: FrameBuffer.hxx,v 1.16 2005-02-22 18:41:11 stephena Exp $
@version $Id: FrameBuffer.hxx,v 1.17 2005-02-27 23:41:19 stephena Exp $
*/
class FrameBuffer
{
@ -160,8 +160,8 @@ FIXME
void refresh(bool now = false)
{
theRedrawEntireFrameIndicator = true;
if(now)
drawMediaSource();
myMenuRedraws = 2;
if(now) drawMediaSource();
}
/**

277
stella/src/gui/Dialog.cxx Normal file
View File

@ -0,0 +1,277 @@
/* ScummVM - Scumm Interpreter
* Copyright (C) 2002-2004 The ScummVM project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Header: /home/stephena/STELLA_CVS-to-SVN/stella/src/gui/Dialog.cxx,v 1.1 2005-02-27 23:41:19 stephena Exp $
*/
#include <ctype.h>
#include "stdafx.h"
#include "newgui.h"
#include "dialog.h"
#include "widget.h"
namespace GUI {
/*
* TODO list
* - add some sense of the window being "active" (i.e. in front) or not. If it
* was inactive and just became active, reset certain vars (like who is focused).
* Maybe we should just add lostFocus and receivedFocus methods to Dialog, just
* like we have for class Widget?
* ...
*/
Dialog::~Dialog() {
delete _firstWidget;
_firstWidget = 0;
}
int Dialog::runModal() {
// Open up
open();
// Start processing events
g_gui.runLoop();
// Return the result code
return _result;
}
void Dialog::open() {
Widget *w = _firstWidget;
_result = 0;
_visible = true;
g_gui.openDialog(this);
// Search for the first objects that wantsFocus() (if any) and give it the focus
while (w && !w->wantsFocus()) {
w = w->_next;
}
if (w) {
w->receivedFocus();
_focusedWidget = w;
}
}
void Dialog::close() {
_visible = false;
g_gui.closeTopDialog();
if (_mouseWidget) {
_mouseWidget->handleMouseLeft(0);
_mouseWidget = 0;
}
releaseFocus();
}
void Dialog::releaseFocus() {
if (_focusedWidget) {
_focusedWidget->lostFocus();
_focusedWidget = 0;
}
}
void Dialog::draw() {
g_gui._needRedraw = true;
}
void Dialog::drawDialog() {
if (!isVisible())
return;
g_gui.blendRect(_x, _y, _w, _h, g_gui._bgcolor);
g_gui.box(_x, _y, _w, _h, g_gui._color, g_gui._shadowcolor);
// Draw all children
Widget *w = _firstWidget;
while (w) {
w->draw();
w = w->_next;
}
// Flag the draw area as dirty
g_gui.addDirtyRect(_x, _y, _w, _h);
}
void Dialog::handleMouseDown(int x, int y, int button, int clickCount) {
Widget *w;
w = findWidget(x, y);
// If the click occured inside a widget which is not the currently
// focused one, change the focus to that widget.
// TODO: use the wantsFocus() method to objects, so that only fields
// that want it get the focus (like edit fields, list field...)
// However, right now we "abuse" the focus also for the click&drag
// behaviour of buttons. This should probably be changed by adding
// a nother field, e.g. _clickedWidget or _dragWidget.
if (w && w != _focusedWidget) {
// The focus will change. Tell the old focused widget (if any)
// that it lost the focus.
releaseFocus();
// Tell the new focused widget (if any) that it just gained the focus.
if (w)
w->receivedFocus();
_focusedWidget = w;
}
if (w && w == _focusedWidget)
_focusedWidget->handleMouseDown(x - (_focusedWidget->getAbsX() - _x), y - (_focusedWidget->getAbsY() - _y), button, clickCount);
}
void Dialog::handleMouseUp(int x, int y, int button, int clickCount) {
Widget *w;
if (_focusedWidget) {
w = _focusedWidget;
// Lose focus on mouseup unless the widget requested to retain the focus
if (! (_focusedWidget->getFlags() & WIDGET_RETAIN_FOCUS )) {
releaseFocus();
}
} else {
w = findWidget(x, y);
}
if (w)
w->handleMouseUp(x - (w->getAbsX() - _x), y - (w->getAbsY() - _y), button, clickCount);
}
void Dialog::handleMouseWheel(int x, int y, int direction) {
Widget *w;
// This may look a bit backwards, but I think it makes more sense for
// the mouse wheel to primarily affect the widget the mouse is at than
// the widget that happens to be focused.
w = findWidget(x, y);
if (!w)
w = _focusedWidget;
if (w)
w->handleMouseWheel(x, y, direction);
}
void Dialog::handleKeyDown(uint16 ascii, int keycode, int modifiers) {
if (_focusedWidget) {
if (_focusedWidget->handleKeyDown(ascii, keycode, modifiers))
return;
}
// Hotkey handling
if (ascii != 0) {
Widget *w = _firstWidget;
ascii = toupper(ascii);
while (w) {
if (w->_type == kButtonWidget && ascii == toupper(((ButtonWidget *)w)->_hotkey)) {
// The hotkey for widget w was pressed. We fake a mouse click into the
// button by invoking the appropriate methods.
w->handleMouseDown(0, 0, 1, 1);
w->handleMouseUp(0, 0, 1, 1);
return;
}
w = w->_next;
}
}
// ESC closes all dialogs by default
if (keycode == 27) {
setResult(-1);
close();
}
// TODO: tab/shift-tab should focus the next/previous focusable widget
}
void Dialog::handleKeyUp(uint16 ascii, int keycode, int modifiers) {
// Focused widget receives keyup events
if (_focusedWidget)
_focusedWidget->handleKeyUp(ascii, keycode, modifiers);
}
void Dialog::handleMouseMoved(int x, int y, int button) {
Widget *w;
if (_focusedWidget) {
w = _focusedWidget;
int wx = w->getAbsX() - _x;
int wy = w->getAbsY() - _y;
// We still send mouseEntered/Left messages to the focused item
// (but to no other items).
bool mouseInFocusedWidget = (x >= wx && x < wx + w->_w && y >= wy && y < wy + w->_h);
if (mouseInFocusedWidget && _mouseWidget != w) {
_mouseWidget = w;
w->handleMouseEntered(button);
} else if (!mouseInFocusedWidget && _mouseWidget == w) {
_mouseWidget = 0;
w->handleMouseLeft(button);
}
w->handleMouseMoved(x - wx, y - wy, button);
}
w = findWidget(x, y);
if (_mouseWidget != w) {
if (_mouseWidget)
_mouseWidget->handleMouseLeft(button);
if (w)
w->handleMouseEntered(button);
_mouseWidget = w;
}
if (!w || !(w->getFlags() & WIDGET_TRACK_MOUSE)) {
return;
}
w->handleMouseMoved(x - (w->getAbsX() - _x), y - (w->getAbsY() - _y), button);
}
void Dialog::handleTickle() {
// Focused widget receives tickle notifications
if (_focusedWidget && _focusedWidget->getFlags() & WIDGET_WANT_TICKLE) {
_focusedWidget->handleTickle();
}
}
void Dialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
switch (cmd) {
case kCloseCmd:
close();
break;
}
}
/*
* Determine the widget at location (x,y) if any. Assumes the coordinates are
* in the local coordinate system, i.e. relative to the top left of the dialog.
*/
Widget *Dialog::findWidget(int x, int y) {
return Widget::findWidgetInChain(_firstWidget, x, y);
}
ButtonWidget *Dialog::addButton(int x, int y, const Common::String &label, uint32 cmd, char hotkey) {
return new ButtonWidget(this, x, y, kButtonWidth, 16, label, cmd, hotkey);
}
} // End of namespace GUI

87
stella/src/gui/Dialog.hxx Normal file
View File

@ -0,0 +1,87 @@
//============================================================================
//
// 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-2005 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Dialog.hxx,v 1.1 2005-02-27 23:41:19 stephena Exp $
//============================================================================
#ifndef DIALOG_HXX
#define DIALOG_HXX
#include "bspf.hxx"
#include "common/scummsys.h"
#include "common/str.h"
#include "gui/object.h"
/**
This is the base class for all dialog boxes.
@author Stephen Anthony
@version $Id: Dialog.hxx,v 1.1 2005-02-27 23:41:19 stephena Exp $
*/
class Dialog
{
public:
Dialog(uInt16 x, uInt16 y, uInt16 w, uInt16 h)
: GuiObject(x, y, w, h),
_mouseWidget(0), _focusedWidget(0), _visible(false) {
}
virtual ~Dialog();
virtual int runModal();
bool isVisible() const { return _visible; }
void releaseFocus();
protected:
virtual void open();
virtual void close();
virtual void draw();
virtual void drawDialog();
virtual void handleTickle(); // Called periodically (in every guiloop() )
virtual void handleMouseDown(int x, int y, int button, int clickCount);
virtual void handleMouseUp(int x, int y, int button, int clickCount);
virtual void handleMouseWheel(int x, int y, int direction);
virtual void handleKeyDown(uint16 ascii, int keycode, int modifiers);
virtual void handleKeyUp(uint16 ascii, int keycode, int modifiers);
virtual void handleMouseMoved(int x, int y, int button);
virtual void handleCommand(CommandSender *sender, uint32 cmd, uint32 data);
virtual void handleScreenChanged() {}
Widget *findWidget(int x, int y); // Find the widget at pos x,y if any
ButtonWidget *addButton(int x, int y, const Common::String &label, uint32 cmd, char hotkey);
void setResult(int result) { _result = result; }
int getResult() const { return _result; }
protected:
Widget *_mouseWidget;
Widget *_focusedWidget;
bool _visible;
private:
int _result;
};
} // End of namespace GUI
#endif

View File

@ -0,0 +1,60 @@
//============================================================================
//
// 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-2005 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: GuiObject.hxx,v 1.1 2005-02-27 23:41:19 stephena Exp $
//============================================================================
#ifndef GUI_OBJECT_HXX
#define GUI_OBJECT_HXX
class Widget;
#include "bspf.hxx"
/**
This is the base class for all GUI objects/widgets.
@author Stephen Anthony
@version $Id: GuiObject.hxx,v 1.1 2005-02-27 23:41:19 stephena Exp $
*/
class GuiObject
{
//friend class Widget;
public:
GuiObject(int x, int y, int w, int h) : _x(x), _y(y), _w(w), _h(h), _firstWidget(0) { }
virtual Int16 getAbsX() const { return _x; }
virtual Int16 getAbsY() const { return _y; }
virtual Int16 getChildX() const { return getAbsX(); }
virtual Int16 getChildY() const { return getAbsY(); }
virtual uInt16 getWidth() const { return _w; }
virtual uInt16 getHeight() const { return _h; }
virtual bool isVisible() const = 0;
virtual void draw() = 0;
protected:
Int16 _x, _y;
uInt16 _w, _h;
Widget* _firstWidget;
protected:
virtual void releaseFocus() = 0;
};
#endif

47
stella/src/gui/Menu.cxx Normal file
View File

@ -0,0 +1,47 @@
//============================================================================
//
// 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-2005 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Menu.cxx,v 1.1 2005-02-27 23:41:19 stephena Exp $
//============================================================================
#include <SDL.h>
#include "bspf.hxx"
#include "Menu.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Menu::Menu()
{
cerr << "Menu::Menu()\n";
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Menu::~Menu()
{
cerr << "Menu::~Menu()\n";
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Menu::handleKeyEvent(SDLKey key, SDLMod mod, uInt8 state)
{
cerr << "Menu::handleKeyEvent()\n";
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Menu::draw()
{
cerr << "Menu::draw()\n";
}

67
stella/src/gui/Menu.hxx Normal file
View File

@ -0,0 +1,67 @@
//============================================================================
//
// 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-2005 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Menu.hxx,v 1.1 2005-02-27 23:41:19 stephena Exp $
//============================================================================
#ifndef MENU_HXX
#define MENU_HXX
#include "bspf.hxx"
/**
The base class for all menus in Stella.
This class keeps track of all configuration menus. organizes them into
a stack, and handles their events.
@author Stephen Anthony
@version $Id: Menu.hxx,v 1.1 2005-02-27 23:41:19 stephena Exp $
*/
class Menu
{
public:
/**
Create a new menu stack
*/
Menu();
/**
Destructor
*/
virtual ~Menu();
public:
/**
Handle a keyboard event.
@param key keysym
@param mod modifiers
@param state state of key
*/
void handleKeyEvent(SDLKey key, SDLMod mod, uInt8 state);
// FIXME - add mouse and joystick handlers
/**
Draw the stack of menus.
*/
void draw();
private:
};
#endif

267
stella/src/gui/Widget.cxx Normal file
View File

@ -0,0 +1,267 @@
//============================================================================
//
// 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-2005 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Widget.cxx,v 1.1 2005-02-27 23:41:19 stephena Exp $
//============================================================================
#include "Dialog.hxx"
#include "GuiObject.hxx"
#include "bspf.hxx"
#include "Widget.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Widget::Widget(GuiObject* boss, uInt32 x, uInt32 y, uInt32 w, uInt32 h)
: GuiObject(x, y, w, h), _type(0), _boss(boss),
_id(0), _flags(0), _hasFocus(false)
{
// Insert into the widget list of the boss
_next = _boss->_firstWidget;
_boss->_firstWidget = this;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Widget::~Widget()
{
delete _next;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Widget::draw()
{
NewGui *gui = &g_gui;
if (!isVisible() || !_boss->isVisible())
return;
int oldX = _x, oldY = _y;
// Account for our relative position in the dialog
_x = getAbsX();
_y = getAbsY();
// Clear background (unless alpha blending is enabled)
if (_flags & WIDGET_CLEARBG)
gui->fillRect(_x, _y, _w, _h, gui->_bgcolor);
// Draw border
if (_flags & WIDGET_BORDER) {
OverlayColor colorA = gui->_color;
OverlayColor colorB = gui->_shadowcolor;
if ((_flags & WIDGET_INV_BORDER) == WIDGET_INV_BORDER)
SWAP(colorA, colorB);
gui->box(_x, _y, _w, _h, colorA, colorB);
_x += 4;
_y += 4;
_w -= 8;
_h -= 8;
}
// Now perform the actual widget draw
drawWidget((_flags & WIDGET_HILITED) ? true : false);
// Restore x/y
if (_flags & WIDGET_BORDER) {
_x -= 4;
_y -= 4;
_w += 8;
_h += 8;
}
// Flag the draw area as dirty
gui->addDirtyRect(_x, _y, _w, _h);
_x = oldX;
_y = oldY;
// Draw all children
Widget *w = _firstWidget;
while (w) {
w->draw();
w = w->_next;
}
}
Widget *Widget::findWidgetInChain(Widget *w, int x, int y) {
while (w) {
// Stop as soon as we find a widget that contains the point (x,y)
if (x >= w->_x && x < w->_x + w->_w && y >= w->_y && y < w->_y + w->_h)
break;
w = w->_next;
}
if (w)
w = w->findWidget(x - w->_x, y - w->_y);
return w;
}
#pragma mark -
StaticTextWidget::StaticTextWidget(GuiObject *boss, int x, int y, int w, int h, const String &text, TextAlignment align)
: Widget(boss, x, y, w, h), _align(align) {
_flags = WIDGET_ENABLED;
_type = kStaticTextWidget;
setLabel(text);
}
void StaticTextWidget::setValue(int value) {
char buf[256];
sprintf(buf, "%d", value);
_label = buf;
}
void StaticTextWidget::drawWidget(bool hilite) {
NewGui *gui = &g_gui;
gui->drawString(_label, _x, _y, _w, isEnabled() ? gui->_textcolor : gui->_color, _align);
}
#pragma mark -
ButtonWidget::ButtonWidget(GuiObject *boss, int x, int y, int w, int h, const String &label, uint32 cmd, uint8 hotkey)
: StaticTextWidget(boss, x, y, w, h, label, kTextAlignCenter), CommandSender(boss),
_cmd(cmd), _hotkey(hotkey) {
_flags = WIDGET_ENABLED | WIDGET_BORDER | WIDGET_CLEARBG;
_type = kButtonWidget;
}
void ButtonWidget::handleMouseUp(int x, int y, int button, int clickCount) {
if (isEnabled() && x >= 0 && x < _w && y >= 0 && y < _h)
sendCommand(_cmd, 0);
}
void ButtonWidget::drawWidget(bool hilite) {
NewGui *gui = &g_gui;
gui->drawString(_label, _x, _y + (_h - kLineHeight)/2 + 1, _w,
!isEnabled() ? gui->_color :
hilite ? gui->_textcolorhi : gui->_textcolor, _align);
}
#pragma mark -
/* 8x8 checkbox bitmap */
static uint32 checked_img[8] = {
0x00000000,
0x01000010,
0x00100100,
0x00011000,
0x00011000,
0x00100100,
0x01000010,
0x00000000,
};
CheckboxWidget::CheckboxWidget(GuiObject *boss, int x, int y, int w, int h, const String &label, uint32 cmd, uint8 hotkey)
: ButtonWidget(boss, x, y, w, h, label, cmd, hotkey), _state(false) {
_flags = WIDGET_ENABLED;
_type = kCheckboxWidget;
}
void CheckboxWidget::handleMouseUp(int x, int y, int button, int clickCount) {
if (isEnabled() && x >= 0 && x < _w && y >= 0 && y < _h) {
toggleState();
}
}
void CheckboxWidget::setState(bool state) {
if (_state != state) {
_state = state;
_flags ^= WIDGET_INV_BORDER;
draw();
}
sendCommand(_cmd, _state);
}
void CheckboxWidget::drawWidget(bool hilite) {
NewGui *gui = &g_gui;
// Draw the box
gui->box(_x, _y, 14, 14, gui->_color, gui->_shadowcolor);
// If checked, draw cross inside the box
if (_state)
gui->drawBitmap(checked_img, _x + 3, _y + 3, isEnabled() ? gui->_textcolor : gui->_color);
else
gui->fillRect(_x + 2, _y + 2, 10, 10, gui->_bgcolor);
// Finally draw the label
gui->drawString(_label, _x + 20, _y + 3, _w, isEnabled() ? gui->_textcolor : gui->_color);
}
#pragma mark -
SliderWidget::SliderWidget(GuiObject *boss, int x, int y, int w, int h, const String &label, uint labelWidth, uint32 cmd, uint8 hotkey)
: ButtonWidget(boss, x, y, w, h, label, cmd, hotkey),
_value(0), _oldValue(0),_valueMin(0), _valueMax(100), _isDragging(false),
_labelWidth(labelWidth) {
_flags = WIDGET_ENABLED | WIDGET_TRACK_MOUSE | WIDGET_CLEARBG;
_type = kSliderWidget;
}
void SliderWidget::handleMouseMoved(int x, int y, int button) {
// TODO: when the mouse is dragged outside the widget, the slider should
// snap back to the old value.
if (isEnabled() && _isDragging && x >= (int)_labelWidth) {
int newValue = posToValue(x - _labelWidth);
if (newValue < _valueMin)
newValue = _valueMin;
else if (newValue > _valueMax)
newValue = _valueMax;
if (newValue != _value) {
_value = newValue;
draw();
sendCommand(_cmd, _value); // FIXME - hack to allow for "live update" in sound dialog
}
}
}
void SliderWidget::handleMouseDown(int x, int y, int button, int clickCount) {
if (isEnabled()) {
_isDragging = true;
handleMouseMoved(x, y, button);
}
}
void SliderWidget::handleMouseUp(int x, int y, int button, int clickCount) {
if (isEnabled() && _isDragging) {
sendCommand(_cmd, _value);
}
_isDragging = false;
}
void SliderWidget::drawWidget(bool hilite) {
NewGui *gui = &g_gui;
// Draw the label, if any
if (_labelWidth > 0)
gui->drawString(_label, _x, _y + 2, _labelWidth, isEnabled() ? gui->_textcolor : gui->_color, kTextAlignRight);
// Draw the box
gui->box(_x + _labelWidth, _y, _w - _labelWidth, _h, gui->_color, gui->_shadowcolor);
// Draw the 'bar'
gui->fillRect(_x + _labelWidth + 2, _y + 2, valueToPos(_value), _h - 4,
!isEnabled() ? gui->_color :
hilite ? gui->_textcolorhi : gui->_textcolor);
}
int SliderWidget::valueToPos(int value) {
return ((_w - _labelWidth - 4) * (value - _valueMin) / (_valueMax - _valueMin));
}
int SliderWidget::posToValue(int pos) {
return (pos) * (_valueMax - _valueMin) / (_w - _labelWidth - 4) + _valueMin;
}
} // End of namespace GUI

196
stella/src/gui/Widget.hxx Normal file
View File

@ -0,0 +1,196 @@
//============================================================================
//
// 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-2005 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Widget.hxx,v 1.1 2005-02-27 23:41:19 stephena Exp $
//============================================================================
#ifndef WIDGET_HXX
#define WIDGET_HXX
class Dialog;
#include "GuiObject.hxx"
#include "bspf.hxx"
/**
This is the base class for all widgets.
@author Stephen Anthony
@version $Id: Widget.hxx,v 1.1 2005-02-27 23:41:19 stephena Exp $
*/
class Widget : public GuiObject
{
friend class Dialog;
public:
Widget(GuiObject* boss, uInt32 x, uInt32 y, uInt32 w, uInt32 h);
virtual ~Widget();
virtual Int16 getAbsX() const { return _x + _boss->getChildX(); }
virtual Int16 getAbsY() const { return _y + _boss->getChildY(); }
virtual void handleMouseDown(uInt32 x, uInt32 y, uInt32 button, uInt32 clickCount) {}
virtual void handleMouseUp(uInt32 x, uInt32 y, uInt32 button, uInt32 clickCount) {}
virtual void handleMouseEntered(uInt32 button) {}
virtual void handleMouseLeft(uInt32 button) {}
virtual void handleMouseMoved(uInt32 x, uInt32 y, uInt32 button) {}
virtual void handleMouseWheel(uInt32 x, uInt32 y, uInt32 direction) {}
//FIXME virtual bool handleKeyDown(uint16 ascii, int keycode, int modifiers) { return false; } // Return true if the event was handled
//FIXME virtual bool handleKeyUp(uint16 ascii, int keycode, int modifiers) { return false; } // Return true if the event was handled
virtual void handleTickle() {}
void draw();
void receivedFocus() { _hasFocus = true; receivedFocusWidget(); }
void lostFocus() { _hasFocus = false; lostFocusWidget(); }
virtual bool wantsFocus() { return false; };
void setFlags(int flags) { _flags |= flags; }
void clearFlags(int flags) { _flags &= ~flags; }
uInt32 getFlags() const { return _flags; }
void setEnabled(bool e) { if (e) setFlags(WIDGET_ENABLED); else clearFlags(WIDGET_ENABLED); }
bool isEnabled() const { return _flags & WIDGET_ENABLED; }
bool isVisible() const { return !(_flags & WIDGET_INVISIBLE); }
protected:
virtual void drawWidget(bool hilite) {}
virtual void receivedFocusWidget() {}
virtual void lostFocusWidget() {}
virtual Widget *findWidget(uInt32 x, uInt32 y) { return this; }
void releaseFocus() { assert(_boss); _boss->releaseFocus(); }
// By default, delegate unhandled commands to the boss
void handleCommand(CommandSender *sender, uint32 cmd, uint32 data)
{ assert(_boss); _boss->handleCommand(sender, cmd, data); }
protected:
uInt32 _type;
GuiObject* _boss;
Widget* _next;
uInt16 _id;
uInt16 _flags;
bool _hasFocus;
public:
static Widget *findWidgetInChain(Widget *start, uInt32 x, uInt32 y);
};
/* StaticTextWidget */
class StaticTextWidget : public Widget
{
public:
StaticTextWidget(GuiObject* boss, uInt32 x, uInt32 y, uInt32 w, uInt32 h,
const String &text, TextAlignment align);
void setValue(uInt32 value);
void setLabel(const string& label) { _label = label; }
const string& getLabel() const { return _label; }
void setAlign(TextAlignment align) { _align = align; }
TextAlignment getAlign() const { return _align; }
protected:
void drawWidget(bool hilite);
protected:
// typedef Graphics::TextAlignment TextAlignment;
string _label;
// TextAlignment _align;
};
/* ButtonWidget */
class ButtonWidget : public StaticTextWidget
{
public:
ButtonWidget(GuiObject* boss, uInt32 x, uInt32 y, uInt32 w, uInt32 h,
const string& label, uInt32 cmd = 0, uInt8 hotkey = 0);
void setCmd(uint32 cmd) { _cmd = cmd; }
uint32 getCmd() const { return _cmd; }
void handleMouseUp(uInt32 x, uInt32 y, uInt32 button, uInt32 clickCount);
void handleMouseEntered(uInt32 button) { setFlags(WIDGET_HILITED); draw(); }
void handleMouseLeft(uInt32 button) { clearFlags(WIDGET_HILITED); draw(); }
protected:
void drawWidget(bool hilite);
protected:
uInt32 _cmd;
uInt8 _hotkey;
};
/* CheckboxWidget */
class CheckboxWidget : public ButtonWidget
{
public:
CheckboxWidget(GuiObject* boss, uInt32 x, uInt32 y, uInt32 w, uInt32 h,
const string& label, uInt32 cmd = 0, uInt8 hotkey = 0);
void handleMouseUp(uInt32 x, uInt32 y, uInt32 button, uInt32 clickCount);
virtual void handleMouseEntered(uInt32 button) {}
virtual void handleMouseLeft(uInt32 button) {}
void setState(bool state);
void toggleState() { setState(!_state); }
bool getState() const { return _state; }
protected:
void drawWidget(bool hilite);
protected:
bool _state;
};
/* SliderWidget */
class SliderWidget : public ButtonWidget
{
public:
SliderWidget(GuiObject *boss, int x, int y, int w, int h, const string& label = "",
uInt32 labelWidth = 0, uInt32 cmd = 0, uInt8 hotkey = 0);
void setValue(uInt32 value) { _value = value; }
uInt32 getValue() const { return _value; }
void setMinValue(uInt32 value) { _valueMin = value; }
uInt32 getMinValue() const { return _valueMin; }
void setMaxValue(uInt32 value) { _valueMax = value; }
uInt32 getMaxValue() const { return _valueMax; }
void handleMouseMoved(uInt32 x, uInt32 y, uInt32 button);
void handleMouseDown(uInt32 x, uInt32 y, uInt32 button, uInt32 clickCount);
void handleMouseUp(uInt32 x, uInt32 y, uInt32 button, uInt32 clickCount);
protected:
void drawWidget(bool hilite);
uInt32 valueToPos(uInt32 value);
uInt32 posToValue(uInt32 pos);
protected:
uInt32 _value, _oldValue;
uInt32 _valueMin, _valueMax;
bool _isDragging;
uInt32 _labelWidth;
};
#endif