diff options
author | Max Horn | 2002-08-21 16:07:07 +0000 |
---|---|---|
committer | Max Horn | 2002-08-21 16:07:07 +0000 |
commit | ce46866403fdcc479cf9d67e4d430409b15dadc3 (patch) | |
tree | 75ebfaa1ed13f549959d76d3ce101c3e66f5451b /gui | |
parent | 662256f25dbe43abf67077a804e225738765f009 (diff) | |
download | scummvm-rg350-ce46866403fdcc479cf9d67e4d430409b15dadc3.tar.gz scummvm-rg350-ce46866403fdcc479cf9d67e4d430409b15dadc3.tar.bz2 scummvm-rg350-ce46866403fdcc479cf9d67e4d430409b15dadc3.zip |
Initial revision
svn-id: r4785
Diffstat (limited to 'gui')
-rw-r--r-- | gui/dialog.cpp | 22 | ||||
-rw-r--r-- | gui/dialog.h | 2 | ||||
-rw-r--r-- | gui/gui.cpp | 1252 | ||||
-rw-r--r-- | gui/gui.h | 124 | ||||
-rw-r--r-- | gui/guimaps.h | 157 | ||||
-rw-r--r-- | gui/newgui.cpp | 541 | ||||
-rw-r--r-- | gui/newgui.h | 151 |
7 files changed, 2247 insertions, 2 deletions
diff --git a/gui/dialog.cpp b/gui/dialog.cpp index ecc444b71d..71b55f8c80 100644 --- a/gui/dialog.cpp +++ b/gui/dialog.cpp @@ -28,7 +28,7 @@ #include "ListWidget.h" #include "config-file.h" #include "sound/mididrv.h" -#include "sound/imuse.h" +#include "scumm/imuse.h" /* * TODO list @@ -407,11 +407,29 @@ AboutDialog::AboutDialog(NewGui *gui) } PauseDialog::PauseDialog(NewGui *gui) - : Dialog (gui, 50, 80, 220, 16) + : Dialog (gui, 60, 20, 100, 100) { addResText(4, 4, 220, 16, 10); } +void PauseDialog::draw() +{ + if (_screenBuf) { + _gui->blitFrom(_screenBuf, _x, _y, _w, _h); + } else { + _gui->fillRect(_x, _y, _w, _h, _gui->_bgcolor); + _gui->box(_x, _y, _w, _h); + } + _gui->addDirtyRect(_x, _y, _w, _h); + + _gui->frameRect(10 + _x, 15 + _y, 100, 100, _gui->_color); + for (int y = 0; y < 16; ++y) + for (int x = 0; x < 16; ++x) + _gui->fillRect(10 + _x + x*5, 15 + _y + y*5, 5, 5, y*16 + x); + + +} + SoundDialog::SoundDialog(NewGui *gui) : Dialog (gui, 30, 20, 260, 110) { diff --git a/gui/dialog.h b/gui/dialog.h index 0e9b46222a..55fd464a42 100644 --- a/gui/dialog.h +++ b/gui/dialog.h @@ -116,6 +116,8 @@ class PauseDialog : public Dialog { public: PauseDialog(NewGui *gui); + virtual void draw(); + virtual void handleMouseDown(int x, int y, int button, int clickCount) { close(); } virtual void handleKeyDown(char key, int modifiers) diff --git a/gui/gui.cpp b/gui/gui.cpp new file mode 100644 index 0000000000..270641ae17 --- /dev/null +++ b/gui/gui.cpp @@ -0,0 +1,1252 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001/2002 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$ + */ + +#include "stdafx.h" +#include "scumm.h" +#include "sound/mididrv.h" +#include "scumm/imuse.h" +#include "gui.h" +#include "guimaps.h" +#include "config-file.h" + +#include <ctype.h> + +#define hline(x, y, x2, color) line(x, y, x2, y, color); +#define vline(x, y, y2, color) line(x, y, x, y2, color); + +#ifdef _WIN32_WCE +// Additional variables for WinCE specific GUI +#include "gapi_keys.h" +extern bool toolbar_drawn; +extern bool hide_toolbar; +extern bool draw_keyboard; +extern bool get_key_mapping; +extern struct keyops keyMapping; +extern void save_key_mapping(void); +extern void do_hide(bool); +extern void do_quit(); +uint16 _key_mapping_required; +uint16 _current_page; +bool keyboard_override; +bool save_hide_toolbar; +#else +#define save_key_mapping() ; +bool get_key_mapping; +uint16 _key_mapping_required; +#endif + +enum { + GUI_NONE = 0, + GUI_RESTEXT = 1, + GUI_IMAGE = 2, + GUI_STAT = 3, + GUI_CUSTOMTEXT = 4, + GUI_VARTEXT = 5, + GUI_ACTIONTEXT = 6, + GUI_KEYTEXT = 7, + GUI_SCROLLTEXT = 8, + GUI_NEXTTEXT = 9, + GUI_UPDOWNARROW = 10, + GUI_CHECKBOX = 11 +}; + +enum { + GWF_BORDER = 1, + GWF_CLEARBG = 2, + GWF_PARENT = 4, + GWF_DELAY = 8, + GWF_DEFAULT = GWF_BORDER | GWF_CLEARBG, + GWF_BUTTON = GWF_BORDER | GWF_CLEARBG | GWF_DELAY +}; + +struct GuiWidget { + byte _type; + byte _page; + byte _flags; + int16 _x, _y; + uint16 _w, _h; + uint16 _id; + byte _string_number; + uint8 _hotkey; +}; + +enum { + SAVELOAD_DIALOG, + PAUSE_DIALOG, + SOUND_DIALOG, + KEYS_DIALOG, + OPTIONS_DIALOG, + ABOUT_DIALOG, + LAUNCHER_DIALOG, + MISC_DIALOG +}; + + +#define IMG_SIZE 8 + +// Triangles pointing up-/downwards, used for save/load dialog +static uint32 up_arrow[IMG_SIZE] = { + 0x00011000, + 0x00011000, + 0x00100100, + 0x00100100, + 0x01000010, + 0x01000010, + 0x10000001, + 0x10000001, +}; + +static uint32 down_arrow[IMG_SIZE] = { + 0x10000001, + 0x10000001, + 0x01000010, + 0x01000010, + 0x00100100, + 0x00100100, + 0x00011000, + 0x00011000, +}; + +static uint32 checked_img[IMG_SIZE] = { + 0x00000000, + 0x01000010, + 0x00100100, + 0x00011000, + 0x00011000, + 0x00100100, + 0x01000010, + 0x00000000, +}; + +const GuiWidget launcher_dialog[] = { + {GUI_STAT, 0xFF, GWF_DEFAULT, 0, 0, 320, 200, 0, 0}, + {GUI_CUSTOMTEXT, 0x01, GWF_CLEARBG, 5, 180, 45, 15, 20, 12}, + {GUI_CUSTOMTEXT, 0x01, GWF_CLEARBG, 130, 180, 65, 15, 21, 17}, + {GUI_CUSTOMTEXT, 0x01, GWF_CLEARBG, 265, 180, 50, 15, 22, 7}, + {0, 0, 0, 0, 0, 0, 0, 0, 0} +}; + +const GuiWidget keys_dialog[] = { + {GUI_STAT, 0xFF, GWF_DEFAULT, 30, 10, 260, 130, 0, 0}, + + // First action + {GUI_CUSTOMTEXT, 0x01, GWF_BUTTON, 30 + 11, 10 + 10, 15, 15, 10, 3}, // CUSTOMTEXT_PLUS + {GUI_CUSTOMTEXT, 0x01, GWF_BUTTON, 30 + 33, 10 + 10, 15, 15, 11, 4}, // CUSTOMTEXT_MINUS + {GUI_ACTIONTEXT, 0x01, GWF_BUTTON, 30 + 11 + 33 + 10, 10 + 10, 100, 15, 100, 1}, + {GUI_KEYTEXT, 0x01, 0, 30 + 11 + 33 + 120, 10 + 10 + 3, 100, 15, 1, 1}, + + //Second action + {GUI_CUSTOMTEXT, 0x01, GWF_BUTTON, 30 + 11, 10 + 10 + 15 + 5, 15, 15, 20, 3}, // CUSTOMTEXT_PLUS + {GUI_CUSTOMTEXT, 0x01, GWF_BUTTON, 30 + 33, 10 + 10 + 15 + 5, 15, 15, 21, 4}, // CUSTOMTEXT_MINUS + {GUI_ACTIONTEXT, 0x01, GWF_BUTTON, 30 + 10 + 33 + 10, 10 + 10 + 15 + 5, 100, 15, 101, 2}, + {GUI_KEYTEXT, 0x01, 0, 30 + 11 + 33 + 120, 10 + 10 + 15 + 5 + 3, 100, 15, 2, 2}, + + //Third action + {GUI_CUSTOMTEXT, 0x01, GWF_BUTTON, 30 + 11, 10 + 10 + 15 + 5 + 15 + 5, 15, 15, 30, 3}, // CUSTOMTEXT_PLUS + {GUI_CUSTOMTEXT, 0x01, GWF_BUTTON, 30 + 33, 10 + 10 + 15 + 5 + 15 + 5, 15, 15, 31, 4}, // CUSTOMTEXT_MINUS + {GUI_ACTIONTEXT, 0x01, GWF_BUTTON, 30 + 10 + 33 + 10, 10 + 10 + 15 + 5 + 15 + 5, 100, 15, 102, 3}, + {GUI_KEYTEXT, 0x01, 0, 30 + 11 + 33 + 120, 10 + 10 + 15 + 5 + 15 + 5 + 3, 100, 15, 3, 3}, + + //Fourth action + {GUI_CUSTOMTEXT, 0x01, GWF_BUTTON, 30 + 11, 10 + 10 + 15 + 5 + 15 + 5 + 15 + 5, 15, 15, 40, 3}, + {GUI_CUSTOMTEXT, 0x01, GWF_BUTTON, 30 + 33, 10 + 10 + 15 + 5 + 15 + 5 + 15 + 5, 15, 15, 41, 4}, + {GUI_ACTIONTEXT, 0x01, GWF_BUTTON, 30 + 10 + 33 + 10, 10 + 10 + 15 + 5 + 15 + 5 + 15 + 5, 100, 15, + 103, 4}, + {GUI_KEYTEXT, 0x01, 0, 30 + 11 + 33 + 120, 10 + 10 + 15 + 5 + 15 + 5 + 15 + 5 + 3, 100, 15, 4, 4}, + + //Fifth action + {GUI_CUSTOMTEXT, 0x01, GWF_BUTTON, 30 + 11, 10 + 10 + 15 + 5 + 15 + 5 + 15 + 5 + 15 + 5, 15, 15, + 50, 3}, + {GUI_CUSTOMTEXT, 0x01, GWF_BUTTON, 30 + 33, 10 + 10 + 15 + 5 + 15 + 5 + 15 + 5 + 15 + 5, 15, 15, + 51, 4}, + {GUI_ACTIONTEXT, 0x01, GWF_BUTTON, 30 + 10 + 33 + 10, 10 + 10 + 15 + 5 + 15 + 5 + 15 + 5 + 15 + 5, + 100, 15, 104, 5}, + {GUI_KEYTEXT, 0x01, 0, 30 + 11 + 33 + 120, 10 + 10 + 15 + 5 + 15 + 5 + 15 + 5 + 15 + 5 + 3, 100, + 15, 5, 5}, + + //OK + {GUI_RESTEXT, 0x01, GWF_BUTTON, 30 + 60, 10 + 106, 54, 16, 60, 9}, + //Previous-Next + {GUI_NEXTTEXT, 0x01, GWF_BUTTON, 30 + 120, 10 + 106, 54, 16, 61, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0} +}; + +const GuiWidget about_dialog[] = { + {GUI_STAT, 0xFF, GWF_DEFAULT, 30, 10, 260, 134, 0, 0}, + {GUI_CUSTOMTEXT, 0x01, 0, 30 + 68, 10 + 20, 160, 15, 0, 9}, // Build + {GUI_CUSTOMTEXT, 0x01, 0, 30 + 10, 10 + 35, 240, 15, 0, 10}, // ScummVM Url + {GUI_CUSTOMTEXT, 0x01, 0, 30 + 75, 10 + 65, 150, 15, 0, 11}, // Lucasarts + {GUI_CUSTOMTEXT, 0x01, 0, 30 + 110, 10 + 80, 40, 15, 0, 21}, // Except: + {GUI_CUSTOMTEXT, 0x01, 0, 30 + 25, 10 + 95, 210, 15, 0, 22}, // Adventuresoft + {GUI_SCROLLTEXT, 0x01, 0, 30 + 95, 10 + 10, 100, 15, 0}, + {GUI_RESTEXT, 0x01, GWF_BUTTON, 30 + 100, 10 + 112, 54, 16, 40, 9}, + {0, 0, 0, 0, 0, 0, 0, 0, 0} +}; + +const GuiWidget options_dialog[] = { + // Only display the "Keys" options for WinCE +#ifdef _WIN32_WCE + {GUI_STAT, 0xFF, GWF_DEFAULT, 50, 80, 210, 60, 0, 0}, + {GUI_CUSTOMTEXT, 0x01, GWF_BUTTON, 50 + 10, 80 + 10, 40, 15, 1, 5, 'S'}, // Sound + {GUI_CUSTOMTEXT, 0x01, GWF_BUTTON, 50 + 10 + 40 + 30, 80 + 10, 40, 15, 2, 6, 'K'}, // Keys + {GUI_CUSTOMTEXT, 0x01, GWF_BUTTON, 50 + 10 + 40 + 30 + 40 + 30, 80 + 10, 40, 15, 3, 7, 'A'}, // About + {GUI_CUSTOMTEXT, 0x01, GWF_BUTTON, 50 + 10, 80 + 10 + 15 + 10, 40, 15, 4, 18, 'M'}, // Misc + {0, 0, 0, 0, 0, 0, 0, 0, 0} +#else + {GUI_STAT, 0xFF, GWF_DEFAULT, 50, 80, 210, 40, 0, 0}, + {GUI_CUSTOMTEXT, 0x01, GWF_BUTTON, 50 + 10, 80 + 10, 40, 15, 1, 5, 'S'}, // Sound + {GUI_CUSTOMTEXT, 0x01, GWF_BUTTON, 50 + 10 + 40 + 30, 80 + 10, 40, 15, 3, 7, 'A'}, // About + {GUI_CUSTOMTEXT, 0x01, GWF_BUTTON, 50 + 10 + 40 + 30 + 40 + 30, 80 + 10, 40, 15, 4, 18, 'M'}, // Misc + {0, 0, 0, 0, 0, 0, 0, 0, 0} +#endif +}; + +const GuiWidget misc_dialog[] = { + {GUI_STAT, 0xFF, GWF_DEFAULT, 50, 80, 210, 65, 0, 0}, + {GUI_CHECKBOX, 0x01, GWF_DEFAULT, 50 + 10, 80 + 6, 14, 14, 1, 0, 'S'}, // checkbox for subtitles + {GUI_CUSTOMTEXT, 0x01, 0, 50 + 10 + 20, 80 + 10, 140, 15, 0, 19}, // "Show speech subtitles" + {GUI_CHECKBOX, 0x01, GWF_DEFAULT, 50 + 10, 80 + 6 + 16, 14, 14, 5, 0, 'A'}, // checkbox for amiga pallete + {GUI_CUSTOMTEXT, 0x01, 0, 50 + 10 + 20, 80 + 10 + 15, 140, 15, 0, 20}, // "Amiga pallete conversion" + {GUI_RESTEXT, 0x01, GWF_BUTTON, 50 + 10 + 20, 80 + 10 + 15 + 20, 54, 16, 3, 9, 13}, // ok + {GUI_RESTEXT, 0x01, GWF_BUTTON, 50 + 10 + 20 + 80, 80 + 10 + 15 + 20, 54, 16, 4, 7}, // cancel + {0, 0, 0, 0, 0, 0, 0, 0, 0} +}; + +const GuiWidget sound_dialog[] = { + {GUI_STAT, 0xFF, GWF_DEFAULT, 30, 20, 260, 120, 0, 0}, + {GUI_CUSTOMTEXT, 0x01, GWF_BUTTON, 30 + 11, 20 + 11, 15, 15, 1, 3}, // Plus + {GUI_CUSTOMTEXT, 0x01, GWF_BUTTON, 30 + 33, 20 + 11, 15, 15, 2, 4}, // Minus + {GUI_VARTEXT, 0x01, GWF_DEFAULT, 30 + 73, 20 + 11, 128, 15, 3, 0}, // Master + {GUI_CUSTOMTEXT, 0x01, GWF_BUTTON, 30 + 11, 20 + 25 + 11, 15, 15, 11, 3}, // Plus + {GUI_CUSTOMTEXT, 0x01, GWF_BUTTON, 30 + 33, 20 + 25 + 11, 15, 15, 12, 4}, // Minus + {GUI_VARTEXT, 0x01, GWF_BUTTON, 30 + 73, 20 + 25 + 11, 128, 15, 13, 1}, // Music + {GUI_CUSTOMTEXT, 0x01, GWF_BUTTON, 30 + 11, 20 + 25 + 25 + 11, 15, 15, 21, 3}, // Plus + {GUI_CUSTOMTEXT, 0x01, GWF_BUTTON, 30 + 33, 20 + 25 + 25 + 11, 15, 15, 22, 4}, // Minus + {GUI_VARTEXT, 0x01, GWF_BUTTON, 30 + 73, 20 + 25 + 25 + 11, 128, 15, 23, 2}, // SFX + {GUI_RESTEXT, 0x01, GWF_BUTTON, 30 + (260 / 2) - 80, 20 + 25 + 25 + 11 + 25, 54, 16, 40, 9, 13}, /* OK */ + {GUI_RESTEXT, 0x01, GWF_BUTTON, 30 + (260 / 2), 20 + 25 + 25 + 11 + 25, 54, 16, 50, 7}, /* Cancel */ + {0, 0, 0, 0, 0, 0, 0, 0, 0} +}; + +const GuiWidget save_load_dialog[] = { + {GUI_STAT, 0xFF, GWF_DEFAULT | GWF_PARENT, 30, 20, 260, 124, 0, 0}, + {GUI_RESTEXT, 0x01, 0, 10, 7, 240, 16, 0, 1}, /* How may I serve you? */ + {GUI_RESTEXT, 0x02, 0, 10, 7, 240, 16, 0, 2}, /* Select a game to LOAD */ + {GUI_RESTEXT, 0x04, 0, 10, 7, 240, 16, 0, 3}, /* Name your SAVE game */ + + {GUI_STAT, 0xFF, GWF_DEFAULT, 6, 20, 170, 96, 0, 0}, + {GUI_UPDOWNARROW, 0x01, GWF_BUTTON, 180, 24, 16, 40, 0, 0}, /* Up (dummy) */ + {GUI_UPDOWNARROW, 0x01, GWF_BUTTON, 180, 72, 16, 40, 0, 1}, /* Down (dummy) */ + {GUI_UPDOWNARROW, 0xFE, GWF_BUTTON, 180, 24, 16, 40, 1, 0}, /* Up */ + {GUI_UPDOWNARROW, 0xFE, GWF_BUTTON, 180, 72, 16, 40, 2, 1}, /* Down */ + + {GUI_RESTEXT, 0x06, GWF_CLEARBG, 10, 24, 160, 10, 20, 0}, + {GUI_RESTEXT, 0x06, GWF_CLEARBG, 10, 34, 160, 10, 21, 0}, + {GUI_RESTEXT, 0x06, GWF_CLEARBG, 10, 44, 160, 10, 22, 0}, + {GUI_RESTEXT, 0x06, GWF_CLEARBG, 10, 54, 160, 10, 23, 0}, + {GUI_RESTEXT, 0x06, GWF_CLEARBG, 10, 64, 160, 10, 24, 0}, + {GUI_RESTEXT, 0x06, GWF_CLEARBG, 10, 74, 160, 10, 25, 0}, + {GUI_RESTEXT, 0x06, GWF_CLEARBG, 10, 84, 160, 10, 26, 0}, + {GUI_RESTEXT, 0x06, GWF_CLEARBG, 10, 94, 160, 10, 27, 0}, + {GUI_RESTEXT, 0x06, GWF_CLEARBG, 10, 104, 160, 10, 28, 0}, + + {GUI_RESTEXT, 0x01, GWF_BUTTON, 200, 20, 54, 16, 3, 4, 'S'}, /* Save */ + {GUI_RESTEXT, 0x01, GWF_BUTTON, 200, 40, 54, 16, 4, 5, 'L'}, /* Load */ + {GUI_RESTEXT, 0x01, GWF_BUTTON, 200, 60, 54, 16, 5, 6, 'P'}, /* Play */ + {GUI_CUSTOMTEXT, 0x01, GWF_BUTTON, 200, 80, 54, 16, 9, 17, 'O'}, /* Options */ + {GUI_RESTEXT, 0x01, GWF_BUTTON, 200, 100, 54, 16, 6, 8, 'Q'}, /* Quit */ + + {GUI_RESTEXT, 0x02, GWF_BUTTON, 200, 60, 54, 16, 7, 7}, /* Cancel */ + + {GUI_RESTEXT, 0x04, GWF_BUTTON, 200, 40, 54, 16, 8, 9}, /* Ok */ + {GUI_RESTEXT, 0x04, GWF_BUTTON, 200, 60, 54, 16, 7, 7}, /* Cancel */ + {0, 0, 0, 0, 0, 0, 0, 0, 0} +}; + +const GuiWidget pause_dialog[] = { + {GUI_RESTEXT, 0x01, GWF_DEFAULT, 50, 80, 220, 16, 0, 10}, + {0, 0, 0, 0, 0, 0, 0, 0, 0} +}; + + +void Gui::draw(int start, int end) +{ + int i; + + if (end == -1) + end = start; + + for (i = 0; i < (int)(sizeof(_widgets) / sizeof(_widgets[0])); i++) { + const GuiWidget *w = _widgets[i]; + if (w) { + _parentX = 0; + _parentY = 0; + while (w->_type != GUI_NONE) { + if (w->_id >= start && w->_id <= end && (w->_page & (1 << _cur_page))) { + drawWidget(w); + } + if (w->_flags & GWF_PARENT) { + _parentX += w->_x; + _parentY += w->_y; + } + w++; + } + } + } +} + +const GuiWidget *Gui::widgetFromPos(int x, int y) +{ + int i; + + for (i = sizeof(_widgets) / sizeof(_widgets[0]) - 1; i >= 0; i--) { + const GuiWidget *w = _widgets[i]; + if (w) { + while (w->_type != GUI_NONE) { + if ((w->_page & (1 << _cur_page)) && w->_id && + (uint16)(x - w->_x) < w->_w && (uint16)(y - w->_y) < w->_h) + return w; + if (w->_flags & GWF_PARENT) { + x -= w->_x; + y -= w->_y; + } + w++; + } + } + } + return NULL; +} + +void Gui::drawChar(const char str, int xx, int yy) +{ + unsigned int buffer = 0, mask = 0, x, y; + byte *tmp; + int tempc = _color; + _color = _textcolor; + + tmp = &guifont[0]; + tmp += 224 + (str + 1) * 8; + + byte *ptr = getBasePtr(xx, yy); + if (ptr == NULL) + return; + + for (y = 0; y < 8; y++) { + for (x = 0; x < 8; x++) { + unsigned char color; + if ((mask >>= 1) == 0) { + buffer = *tmp++; + mask = 0x80; + } + color = ((buffer & mask) != 0); + if (color) + ptr[x] = _color; + } + ptr += 320; + } + _color = tempc; + +} +void Gui::drawString(const char *str, int x, int y, int w, byte color, bool center) +{ + StringTab *st = &_s->string[5]; + st->charset = 1; + st->center = center; + st->color = color; + st->xpos = x; + st->ypos = y; + st->right = x + w; + + if (_s->_gameId) { /* If a game is active.. */ + _s->_messagePtr = (byte *)str; + _s->drawString(5); + } else { + for (uint letter = 0; letter < strlen(str); letter++) + drawChar(str[letter], st->xpos + (letter * 8), st->ypos); + } +} + +void Gui::drawWidget(const GuiWidget *w) +{ + const char *s; + int x, y; + + x = w->_x; + y = w->_y; + + if (w->_flags & GWF_CLEARBG) + widgetClear(w); + + if (w->_flags & GWF_BORDER) { + widgetBorder(w); + x += 4; + y += 4; + } + + switch (w->_type) { + case GUI_CUSTOMTEXT: + case GUI_VARTEXT: + case GUI_KEYTEXT: + case GUI_ACTIONTEXT: + case GUI_RESTEXT: + case GUI_NEXTTEXT: + { + char text[500]; + text[0] = '\0'; + + switch (w->_type) { + case GUI_CUSTOMTEXT: + strcpy(text, string_map_table_custom[w->_string_number]); + break; + case GUI_RESTEXT: + s = queryString(w->_string_number, w->_id); + if (s) + strcpy(text, s); + break; + case GUI_VARTEXT: + sprintf(text, "%s %d", string_map_table_custom[w->_string_number], + _gui_variables[w->_string_number]); + break; + case GUI_SCROLLTEXT: + sprintf(text, "%s", _gui_scroller); + break; +#ifdef _WIN32_WCE + case GUI_KEYTEXT: + strcpy(text, getGAPIKeyName(getAction((_current_page * 5) + w->_string_number - 1)->action_key)); + break; + case GUI_ACTIONTEXT: + strcpy(text, getActionName(getAction((_current_page * 5) + w->_string_number - 1)->action_type)); + break; + case GUI_NEXTTEXT: + if (_current_page == 0) + strcpy(text, "Next"); + else + strcpy(text, "Prev"); + break; + +#endif + } + + if (*text) { + drawString(text, x + _parentX, y + _parentY, w->_w, + (_clickWidget && _clickWidget == w->_id) ? _textcolorhi : _textcolor, false); + } + break; + } + case GUI_IMAGE: + break; + case GUI_UPDOWNARROW: + case GUI_CHECKBOX: + { + uint32 *data; + byte color = (_clickWidget && _clickWidget == w->_id) ? _textcolorhi : _textcolor; + + if (w->_type == GUI_UPDOWNARROW) { + if (w->_string_number == 0) + data = up_arrow; + else + data = down_arrow; + // if not an updownarrow, it must be a checkbox + } else { + data = checked_img; + } + + // Center the image + x += w->_w / 2 - IMG_SIZE / 2; + y += w->_h / 2 - IMG_SIZE / 2; + if (w->_flags & GWF_BORDER) { + x -= 4; + y -= 4; + } + + byte *ptr = getBasePtr(x, y); + if (ptr == NULL) + return; + + // If the checkbox is checked, or this is not a checkbox, draw the image + if ((getCheckboxChecked(w->_id) == true) || (w->_type != GUI_CHECKBOX)) { + for (int y2 = 0; y2 < IMG_SIZE; y2++) { + uint32 mask = 0xF0000000; + for (int x2 = 0; x2 < IMG_SIZE; x2++) { + if (data[y2] & mask) + ptr[x2] = color; + mask >>= 4; + } + ptr += 320; + } + } + } + break; + } +} + +void Gui::widgetClear(const GuiWidget *wid) +{ + int x = wid->_x; + int y = wid->_y; + int w = wid->_w; + int h = wid->_h; + int i; + + byte *ptr = getBasePtr(x, y); + if (ptr == NULL) + return; + + _s->setVirtscreenDirty(_vs, x + _parentX, y + _parentY, x + _parentX + w, y + _parentY + h); + + if (wid->_flags & GWF_BORDER) { + // Inset by 1 pixel in all directions + ptr += 320 + 1; + w -= 2; + h -= 2; + } + + while (h--) { + for (i = 0; i < w; i++) + ptr[i] = _bgcolor; + ptr += 320; + } +} + +void Gui::widgetBorder(const GuiWidget *w) +{ + box(w->_x, w->_y, w->_w, w->_h); +} + +void Gui::box(int x, int y, int width, int height) +{ + hline(x + 1, y, x + width - 2, _color); + hline(x, y + 1, x + width - 1, _color); + vline(x, y + 1, y + height - 2, _color); + vline(x + 1, y, y + height - 1, _color); + + hline(x + 1, y + height - 2, x + width - 1, _shadowcolor); + hline(x + 1, y + height - 1, x + width - 2, _shadowcolor); + vline(x + width - 1, y + 1, y + height - 2, _shadowcolor); + vline(x + width - 2, y + 1, y + height - 1, _shadowcolor); +} + +byte *Gui::getBasePtr(int x, int y) +{ + x += _parentX; + y += _parentY; + _vs = _s->findVirtScreen(y); + + if (_vs == NULL) + return NULL; + + return _vs->screenPtr + x + (y - _vs->topline) * 320 + + _s->_screenStartStrip * 8 + (_s->camera._cur.y - 100) * 320; +} + +void Gui::line(int x, int y, int x2, int y2, byte color) +{ + byte *ptr; + + if (x2 < x) + x2 ^= x ^= x2 ^= x; // Swap x2 and x + + if (y2 < y) + y2 ^= y ^= y2 ^= y; // Swap y2 and y + + ptr = getBasePtr(x, y); + + if (ptr == NULL) + return; + + if (x == x2) { + /* vertical line */ + while (y++ <= y2) { + *ptr = color; + ptr += 320; + } + } else if (y == y2) { + /* horizontal line */ + while (x++ <= x2) { + *ptr++ = color; + } + } +} + +void Gui::leftMouseClick(int x, int y) +{ + const GuiWidget *w = widgetFromPos(x, y); + int old; + + _clickTimer = 0; + + old = _clickWidget; + _clickWidget = w ? w->_id : 0; + + if (old) + draw(old); + if (_clickWidget) { + draw(_clickWidget); + if (w->_flags & GWF_DELAY) + _clickTimer = 5; + else + handleCommand(_clickWidget); + } + + if (_dialog == PAUSE_DIALOG) + close(); +} + +void Gui::handleSoundDialogCommand(int cmd) +{ + if (cmd == 50) { + close(); + } else if (cmd == 40) { + _s->_sound->_sound_volume_master = _gui_variables[0]; // Master + _s->_sound->_sound_volume_music = _gui_variables[1]; // Music + _s->_sound->_sound_volume_sfx = _gui_variables[2]; // SFX + + _s->_imuse->set_music_volume(_s->_sound->_sound_volume_music); + _s->_imuse->set_master_volume(_s->_sound->_sound_volume_master); + _s->_mixer->set_volume(_s->_sound->_sound_volume_sfx); + _s->_mixer->set_music_volume(_s->_sound->_sound_volume_music); + + scummcfg->set("master_volume", _s->_sound->_sound_volume_master); + scummcfg->set("music_volume", _s->_sound->_sound_volume_music); + scummcfg->set("sfx_volume", _s->_sound->_sound_volume_sfx); + scummcfg->flush(); + + close(); + } else { + if ((cmd % 10) == 1) { + _gui_variables[cmd / 10] += 5; + if (_gui_variables[cmd / 10] > 256) + _gui_variables[cmd / 10] = 256; + } else { + _gui_variables[cmd / 10] -= 5; + if (_gui_variables[cmd / 10] < 0) + _gui_variables[cmd / 10] = 0; + } + + draw((cmd / 10) * 10 + 3, (cmd / 10) * 10 + 3); + } +} + +void Gui::handleOptionsDialogCommand(int cmd) +{ + switch (cmd) { + case 1: + _widgets[0] = sound_dialog; + _gui_variables[0] = _s->_sound->_sound_volume_master; + _gui_variables[1] = _s->_sound->_sound_volume_music; + _gui_variables[2] = _s->_sound->_sound_volume_sfx; + _active = true; + _cur_page = 0; + _dialog = SOUND_DIALOG; + draw(0, 100); + return; + case 2: + _key_mapping_required = 0; + get_key_mapping = true; + _widgets[0] = keys_dialog; + _active = true; + _cur_page = 0; + _dialog = KEYS_DIALOG; + draw(0, 200); + return; + case 3: + _widgets[0] = about_dialog; + _active = true; + _cur_page = 0; + _return_to = 0; + _dialog = ABOUT_DIALOG; + draw(0, 100); + return; + case 4: + _widgets[0] = misc_dialog; + _active = true; + _cur_page = 0; + _return_to = 0; + _dialog = MISC_DIALOG; + clearCheckboxes(); + setCheckbox(!(_s->_noSubtitles), 1); + if (_s->_features & GF_AMIGA) + setCheckbox(true, 5); + else + setCheckbox(false, 5); + draw(0, 100); + return; + } +} + +void Gui::handleMiscDialogCommand(int cmd) +{ + switch (cmd) { + case 1: + if ((getCheckboxChecked(1)) == true) + setCheckbox(false, 1); + else + setCheckbox(true, 1); + draw(1, 1); + return; + case 5: + if (getCheckboxChecked(5) == true) + setCheckbox(false, 5); + else + setCheckbox(true, 5); + draw(5, 5); + return; + case 3: + case 4: + // OK button - perform the actions of the checkboxes + if (cmd == 3) { + // The opposite of the checkbox(1) is set because the internal variable is 'no subtitles' but + // a "Show subtitles" option makes more usability sense + _s->_noSubtitles = (!getCheckboxChecked(1)); + + // Amiga pallete conversion checkbox + if (getCheckboxChecked(5)) + _s->_features = _s->_features | GF_AMIGA; + else + _s->_features = _s->_features & ~GF_AMIGA; + _s->_fullRedraw = true; + } + close(); + } +} + +void Gui::handleKeysDialogCommand(int cmd) +{ +#ifdef _WIN32_WCE + if (cmd < 100 && cmd != 60 && cmd != 61) { + + if ((cmd % 10) == 1) + setNextType((_current_page * 5) + (cmd / 10) - 1); + else + setPreviousType((_current_page * 5) + (cmd / 10) - 1); + + draw(0, 200); + + return; + } + + if (cmd >= 100) + _key_mapping_required = cmd; + + if (cmd == 60) { + get_key_mapping = false; + save_key_mapping(); + close(); + } + + if (cmd == 61) { + if (!_current_page) + _current_page = 1; + else + _current_page = 0; + draw(0, 200); + return; + } +#else + close(); +#endif +} + +void Gui::handleLauncherDialogCommand(int cmd) +{ + debug(9, "handle launcher command\n"); + switch (cmd) { + case 20: + close(); + break; + case 21: + // Nothing yet + break; + case 22: + _widgets[0] = about_dialog; + _active = true; + _cur_page = 0; + _return_to = LAUNCHER_DIALOG; + _dialog = ABOUT_DIALOG; + draw(0, 100); + debug(9, "about dialog\n"); + break; + default: + debug(9, "default\n"); + close(); + } +} + +void Gui::handleCommand(int cmd) +{ + int lastEdit = _editString; + showCaret(false); + + switch (_dialog) { + case LAUNCHER_DIALOG: + handleLauncherDialogCommand(cmd); + return; + case SOUND_DIALOG: + handleSoundDialogCommand(cmd); + return; + case OPTIONS_DIALOG: + handleOptionsDialogCommand(cmd); + return; + case MISC_DIALOG: + handleMiscDialogCommand(cmd); + return; + case KEYS_DIALOG: + handleKeysDialogCommand(cmd); + return; + case ABOUT_DIALOG: + if (_return_to == LAUNCHER_DIALOG) { + _widgets[0] = launcher_dialog; + _active = true; + _cur_page = 0; + _dialog = LAUNCHER_DIALOG; + draw(0, 100); + } else + close(); + return; + } + + // If we get here, it's the SAVELOAD_DIALOG + + switch (cmd) { + case 1: /* up button */ + if (_slotIndex - 9 < 0) + return; + getSavegameNames(_slotIndex - 9); + draw(20, 28); + return; + case 2: /* down button */ + if (_slotIndex + 9 > 80) + return; + getSavegameNames(_slotIndex + 9); + draw(20, 28); + return; + case 3: /* save button */ + _cur_page = 2; + getSavegameNames(1); /* Start at 1, since slot 0 is reserved for autosave */ + draw(0, 100); + return; + case 4: /* load button */ + _cur_page = 1; + getSavegameNames(0); + draw(0, 100); + return; + case 5: /* play button */ + close(); + return; + case 6: /* quit button */ +#ifdef _WIN32_WCE + do_quit(); +#endif + exit(1); + return; + case 7: /* cancel button */ + _cur_page = 0; + draw(0, 100); + return; + case 8: /* ok button (save game) */ + if (lastEdit == -1 || game_names[lastEdit][0] == 0) + return; + + _s->_saveLoadSlot = lastEdit + _slotIndex; + _s->_saveLoadCompatible = false; + _s->_saveLoadFlag = 1; + memcpy(_s->_saveLoadName, game_names[lastEdit], sizeof(_s->_saveLoadName)); + close(); + return; + case 9: /* options button */ + options(); + draw(0, 100); + return; + default: + if (cmd >= 20 && cmd <= 28) { + if (_cur_page == 1) { + if (valid_games[cmd - 20]) { + _s->_saveLoadSlot = cmd - 20 + _slotIndex; + _s->_saveLoadCompatible = false; + _s->_saveLoadFlag = 2; + close(); + } + return; + } else if (_cur_page == 2) { + _clickWidget = cmd; + editString(cmd - 20); + } + } + } + +} + +void Gui::getSavegameNames(int start) +{ + int i; + _slotIndex = start; + + for (i = 0; i < 9; i++) { + valid_games[i] = _s->getSavegameName(start + i, game_names[i]); + } +} + +const char *Gui::queryString(int stringno, int id) +{ + static char namebuf[64]; + char *result; + int string; + + if (id >= 20 && id <= 28) { + // Save game names + sprintf(namebuf, "%2d. %s", id - 20 + _slotIndex, game_names[id - 20]); + return namebuf; + } + + if (stringno == 0) + return NULL; + + if (_s->_features & GF_AFTER_V7) + string = _s->_vars[string_map_table_v7[stringno - 1].num]; + else if (_s->_features & GF_AFTER_V6) + string = _s->_vars[string_map_table_v6[stringno - 1].num]; + else + string = string_map_table_v5[stringno - 1].num; + + result = (char *)_s->getStringAddress(string); + + if (!result) { // Gracelessly degrade to english :) + if (_s->_features & GF_AFTER_V6) + return string_map_table_v6[stringno - 1].string; + else + return string_map_table_v5[stringno - 1].string; + } + + return result; +} + +void Gui::showCaret(bool show) +{ + int i; + char *s; + + if (_editString == -1) + return; + + i = _editLen; + s = game_names[_editString]; + + if (show) { + if (i < SAVEGAME_NAME_LEN - 1) { + s[i] = '_'; + s[i + 1] = 0; + } + } else { + s[i] = 0; + } + + draw(_editString + 20); + + if (!show) + _editString = -1; +} + +void Gui::editString(int i) +{ + char *s = game_names[i]; + if (!valid_games[i]) { + valid_games[i] = true; + *s = 0; + } + _editString = i; + _editLen = strlen(s); + showCaret(true); +} + +void Gui::addLetter(byte letter) +{ + switch (_dialog) { + case SAVELOAD_DIALOG: + if (_editString == -1) + return; + +/* + FIXME - this code here has no effect at all, since Scumm::convertKeysToClicks() + swallows all return key events. + // Return pressed? + if (letter == '\n' || letter == '\r') { + handleCommand(8); + return; + } +*/ + + if (letter >= 32 && letter < 128 && _editLen < SAVEGAME_NAME_LEN - 1) { + game_names[_editString][_editLen++] = letter; + } else if (letter == 8 && _editLen > 0) { + _editLen--; + } + showCaret(true); + break; + case PAUSE_DIALOG: + if (letter == 32) + close(); + break; + +#ifdef _WIN32_WCE + case KEYS_DIALOG: + clearActionKey(letter); + if (_key_mapping_required) + getAction((_current_page * 5) + _key_mapping_required - 100)->action_key = letter; + _key_mapping_required = 0; + draw(0, 200); + break; +#endif + } +} + +bool Gui::getCheckboxChecked(int id) +{ + return _cbox_checked[id]; +} + +void Gui::setCheckbox(bool state, int id) +{ + _cbox_checked[id] = state; +} + +void Gui::clearCheckboxes() +{ + for (int id = 0; id <= 100; id++) { + _cbox_checked[id] = false; + } +} + +void Gui::init(Scumm *s) +{ + /* Default GUI colors */ + _bgcolor = 0; + _color = 0; + _textcolor = 8; // 15 is nice + _textcolorhi = 15; + _shadowcolor = 0; + _s = s; + + strcpy(_gui_scroller, "Brought to you by:"); +} + +void Gui::loop() +{ + if (_active && !_inited) { + _inited = true; + draw(0, 200); // was 100 + _old_soundsPaused = _s->_sound->_soundsPaused; + _s->_sound->pauseSounds(true); + + // Backup old cursor + memcpy(_old_grabbedCursor, _s->_grabbedCursor, sizeof(_old_grabbedCursor)); + _old_cursorWidth = _s->_cursorWidth; + _old_cursorHeight = _s->_cursorHeight; + _old_cursorHotspotX = _s->_cursorHotspotX; + _old_cursorHotspotY = _s->_cursorHotspotY; + _old_cursor_mode = _s->_system->show_mouse(true); + + _s->_cursorAnimate++; + _s->gdi._cursorActive = 1; + } + _s->animateCursor(); + _s->getKeyInput(0); + if (_s->_mouseButStat & MBS_LEFT_CLICK) { + leftMouseClick(_s->mouse.x, _s->mouse.y); + } else if (_s->_lastKeyHit) { + if (_dialog != KEYS_DIALOG) { + if (_s->_lastKeyHit == 27) + close(); + else { + addLetter((unsigned char)_s->_lastKeyHit); + checkHotKey(_s->_lastKeyHit); + } +#ifdef _WIN32_WCE + } else if (_s->_lastKeyHit > 1000) { // GAPI + addLetter(_s->_lastKeyHit - 1000); +#endif + } + } + + if (_clickTimer && !--_clickTimer) { + int old = _clickWidget; + _clickWidget = 0; + draw(old); + handleCommand(old); + } + + _s->drawDirtyScreenParts(); + _s->_mouseButStat = 0; +} + +void Gui::close() +{ + _s->_fullRedraw = true; + _s->_completeScreenRedraw = true; + _s->_cursorAnimate--; + + // Restore old cursor + memcpy(_s->_grabbedCursor, _old_grabbedCursor, sizeof(_old_grabbedCursor)); + _s->_cursorWidth = _old_cursorWidth; + _s->_cursorHeight = _old_cursorHeight; + _s->_cursorHotspotX = _old_cursorHotspotX; + _s->_cursorHotspotY = _old_cursorHotspotY; + _s->updateCursor(); + + _s->_system->show_mouse(_old_cursor_mode); + + _s->_sound->pauseSounds(_old_soundsPaused); + _active = false; + _inited = false; + +#ifdef _WIN32_WCE + + // Option dialog can be accessed from the file dialog now, always check + if (save_hide_toolbar) { + do_hide(true); + save_hide_toolbar = false; + } + if (keyboard_override) { + keyboard_override = false; + draw_keyboard = false; + toolbar_drawn = false; + } +#endif +} + +void Gui::checkHotKey(int keycode) +{ + byte page; + for (int i = 0; i < (int)(sizeof(_widgets) / sizeof(_widgets[0])); i++) { + const GuiWidget *w = _widgets[i]; + if (w) { + while (w->_type != GUI_NONE) { + + // This rubbish is needed because the current page is 0 when really it should be 1 + if (_cur_page == 0) + page = 1; + else + page = _cur_page; + + // Only check for widgets that are on the current GUI page (otherwise save dialog problems occur) + if (w->_page == page) { + // Check the actual key pressed, and the uppercase version. For people who have caps lock on + if (keycode == w->_hotkey || toupper(keycode) == w->_hotkey) + handleCommand(w->_id); + } + w++; + } + } + } +} + +void Gui::saveLoadDialog() +{ + _widgets[0] = save_load_dialog; + _editString = -1; + _active = true; + _cur_page = 0; + _dialog = SAVELOAD_DIALOG; + +#ifdef _WIN32_WCE + save_hide_toolbar = hide_toolbar; + if (save_hide_toolbar) { + // Display the keyboard while the dialog is running + do_hide(false); + } + if (!draw_keyboard) { + keyboard_override = true; + draw_keyboard = true; + toolbar_drawn = false; + } +#endif + +} + +void Gui::pause() +{ + _widgets[0] = pause_dialog; + _active = true; + _cur_page = 0; + _dialog = PAUSE_DIALOG; +} + +void Gui::options() +{ +#ifdef _WIN32_WCE + _current_page = 0; +#endif + _widgets[0] = options_dialog; + _active = true; + _cur_page = 0; + _dialog = OPTIONS_DIALOG; +} + +void Gui::launcher() +{ + _widgets[0] = launcher_dialog; + _active = true; + _cur_page = 0; + _dialog = LAUNCHER_DIALOG; +} + + + + + + + + + + + + + + + + + + +/* +void Gui::loop() +{ + if (_active && !_inited) { + _inited = true; + _old_soundsPaused = _s->_soundsPaused; + _s->pauseSounds(true); + + // Backup old cursor + memcpy(_old_grabbedCursor, _s->_grabbedCursor, sizeof(_old_grabbedCursor)); + _old_cursorWidth = _s->_cursorWidth; + _old_cursorHeight = _s->_cursorHeight; + _old_cursorHotspotX = _s->_cursorHotspotX; + _old_cursorHotspotY = _s->_cursorHotspotY; + _old_cursor_mode = _s->_system->show_mouse(true); + + _s->_cursorAnimate++; + _s->gdi._cursorActive = 1; + } + _s->animateCursor(); + _s->getKeyInput(0); + + _s->drawDirtyScreenParts(); + _s->_mouseButStat = 0; +} +*/ diff --git a/gui/gui.h b/gui/gui.h new file mode 100644 index 0000000000..b7755cf226 --- /dev/null +++ b/gui/gui.h @@ -0,0 +1,124 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2002 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$ + */ + +#ifndef GUI_H +#define GUI_H + +// Forward declaration for GuiWidget +struct GuiWidget; + +#define SAVEGAME_NAME_LEN 32 + +class Gui { +public: + byte _color,_shadowcolor; + byte _bgcolor; + byte _textcolor; + byte _textcolorhi; + + // Init + void init(Scumm *s); + + // Dialogs + void saveLoadDialog(); + void pause(); + void options(); + void launcher(); + + void loop(); + + bool isActive() { return _active; } + +protected: + Scumm *_s; + const GuiWidget *_widgets[4]; + int _return_to; + VirtScreen *_vs; + int _parentX, _parentY; + bool _active; + bool _inited; + byte _clickTimer; + byte _cur_page; + byte _dialog; + int _clickWidget; + char *_queryMess; + bool _old_soundsPaused; + + // mouse cursor state + bool _old_cursor_mode; + int _old_cursorHotspotX, _old_cursorHotspotY, _old_cursorWidth, _old_cursorHeight; + byte _old_grabbedCursor[2048]; + + // optiondialog specifics + int _gui_variables[100]; + + // checkboxes + bool _cbox_checked[100]; + const char *_cbox_cfg_key[100]; + + // savedialog specifics + int _slotIndex; + int _editString; + int _editLen; + bool valid_games[9]; + char game_names[9][SAVEGAME_NAME_LEN]; + + // Drawing + void draw(int start, int end); + void draw(int item) { draw(item,-1); } + void drawWidget(const GuiWidget *w); + + void line(int x, int y, int x2, int y2, byte color); + void box(int x, int y, int width, int height); + + //void hline(int x, int y, int x2, byte color); + //void vline(int x, int y, int y2, byte color); + void drawChar(const char str, int xx, int yy); + void drawString(const char *str, int x, int y, int w, byte color, bool center); + void widgetClear(const GuiWidget *w); + void widgetBorder(const GuiWidget *w); + byte *getBasePtr(int x, int y); + const GuiWidget *widgetFromPos(int x, int y); + + // Actions + void leftMouseClick(int x, int y); + void handleCommand(int cmd); + void close(); + const char *queryString(int string, int id); + void getSavegameNames(int start); + void editString(int index); + void showCaret(bool show); + void addLetter(byte letter); + void queryMessage(const char *msg, const char *alts); + byte getDefaultColor(int color); + bool getCheckboxChecked(int id); + void setCheckbox(bool state, int id); + void clearCheckboxes(); + void checkHotKey(int keycode); + + char _gui_scroller[255]; + + void handleSoundDialogCommand(int cmd); + void handleOptionsDialogCommand(int cmd); + void handleKeysDialogCommand(int cmd); + void handleLauncherDialogCommand(int cmd); + void handleMiscDialogCommand(int cmd); +}; +#endif diff --git a/gui/guimaps.h b/gui/guimaps.h new file mode 100644 index 0000000000..181dbb6bc9 --- /dev/null +++ b/gui/guimaps.h @@ -0,0 +1,157 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2002 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$ + */ + +#if !defined(guimaps_h) +#define guimaps_h + +struct ResString { + int num; + char string[80]; +}; + +// String maps +static const char* string_map_table_custom[] = { + "Master Volume :", //0 + "Music Volume :", //1 + "SFX Volume :", //2 + "+", //3 + "-", //4 + "Sound", //5 + "Keys", //6 + "About", //7 + "Pocket ScummVM", //8 + "Build " SCUMMVM_VERSION " (" SCUMMVM_CVS ")", //9 + "ScummVM http://scummvm.sourceforge.net", //10 + "All games (c) LucasArts", //11 + "Quit", //12 + "Pause", //13 + "Save", //14 + "Skip", //15 + "Hide", //16 + "Options", //17 + "Misc", //18 + "Show speech subtitles", //19 + "Amiga palette conversion", //20 + "Except:", //21 + "Simon the Sorcerer (c) Adventuresoft", //22 + "Close" //23 +}; + +static ResString string_map_table_v7[] = { + {96, "game name and version"}, //that's how it's supposed to be + {77, "Select a game to LOAD"}, + {76, "Name your SAVE game"}, + {70, "save"}, //boot8 + {71, "load"}, //boot9 + {72, "play"}, //boot10 + {73, "cancel"}, //boot11 + {74, "quit"}, //boot12 + {75, "ok"}, //boot13 + {85, "game paused"}, // boot3 + + /* this is the almost complete string map for v7 + {63, "how may I serve you?"}, + {64, "the dig v1.0"}, //(game name/version) + {67, "text display only"}, + {68, "c:\\dig"}, //boot007 (save path ?) + {69, "the dig"}, //boot21 (game name) + {70, "save"}, //boot8 + {71, "load"}, //boot9 + {72, "play"}, //boot10 + {73, "cancel"}, //boot11 + {74, "quit"}, //boot12 + {75, "ok"}, //boot13 + {76, "name your save game"}, //boot19 + {77, "select a game to load"}, //boot20 + {78, "you must enter a name"},//boot14 + {79, "saving '%s'"}, //boot17 + {80, "loading '%s'"}, //boot18 + {81, "the game was NOT saved"}, //boot15 + {82, "the game was NOT loaded"}, //boot16 + {83, "how may I serve you?"}, + {84, "how may I serve you?"}, + {85, "game paused"}, // boot3 + {86, "Are you sure you want to restart"}, + {87, "Are you sure you want to quit?"}, //boot05 + {89, "how may I serve you?"}, + {90, "music"}, //boot22 + {91, "voice"}, //boot23 + {92, "sfx"}, //boot24 + {93, "disabled"}, //boot25 + {94, "text speed"}, //boot26 + {95, "text display"}, //boot27 + {96, "the dig v1.0"},*/ + +}; + +static ResString string_map_table_v6[] = { + {117, "How may I serve you?"}, + {109, "Select a game to LOAD"}, + {108, "Name your SAVE game"}, + {96, "Save"}, + {97, "Load"}, + {98, "Play"}, + {99, "Cancel"}, + {100, "Quit"}, + {101, "Ok"}, + {93, "Game paused"}, +}; + +static ResString string_map_table_v5[] = { + {28, "How may I serve you?"}, + {20, "Select a game to LOAD"}, + {19, "Name your SAVE game"}, + {7, "Save"}, + {8, "Load"}, + {9, "Play"}, + {10, "Cancel"}, + {11, "Quit"}, + {12, "Ok"}, + {4, "Game paused"} +}; + +// Built-in font +static byte guifont[] = {0,0,99,1,226,8,4,8,6,8,6,0,0,0,0,0,0,0,0,0,0,0,8,2,1,8,0,0,0,0,0,0,0,0,0,0,0,0,4,3,7,8,7,7,8,4,5,5,8,7,4,7,3,8,7,7,7,7,8,7,7,7,7,7,3,4,7,5,7,7,8,7,7,7,7,7,7,7,7,5,7,7, +7,8,7,7,7,7,7,7,7,7,7,8,7,7,7,5,8,5,8,8,7,7,7,6,7,7,7,7,7,5,6,7,5,8,7,7,7,7,7,7,7,7,7,8,7,7,7,5,3,5,0,8,7,7,7,7,7,7,0,6,7,7,7,5,5,5,7,0,6,8,8,7,7,7,7,7,0,7,7,0,0, +0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,1,3,6,12, +24,62,3,0,128,192,96,48,24,124,192,0,0,3,62,24,12,6,3,1,0,192,124,24,48,96,192,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,237,74,72,0,0,0,0,0,128,128,128,0,0,0,0,0,0,0,0,0,0,0,0,0,60,66,153,161,161,153,66,60,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,96,96,96,96,0,0,96,0,102,102,102,0,0,0,0,0,102,102,255,102,255,102,102,0,24,62,96,60,6,124,24,0,98,102,12,24,48,102,70,0,60,102,60,56,103,102,63,0,96,48,16,0,0,0,0,0,24,48,96,96,96,48,24,0,96,48,24,24,24,48,96,0, +0,102,60,255,60,102,0,0,0,24,24,126,24,24,0,0,0,0,0,0,0,48,48,96,0,0,0,126,0,0,0,0,0,0,0,0,0,96,96,0,0,3,6,12,24,48,96,0,60,102,102,102,102,102,60,0,24,24,56,24,24,24,126,0,60,102,6,12,48,96,126,0,60,102,6,28,6,102,60,0,6, +14,30,102,127,6,6,0,126,96,124,6,6,102,60,0,60,102,96,124,102,102,60,0,126,102,12,24,24,24,24,0,60,102,102,60,102,102,60,0,60,102,102,62,6,102,60,0,0,0,96,0,0,96,0,0,0,0,48,0,0,48,48,96,14,24,48,96,48,24,14,0,0,0,120,0,120,0,0,0,112,24, +12,6,12,24,112,0,60,102,6,12,24,0,24,0,0,0,0,255,255,0,0,0,24,60,102,126,102,102,102,0,124,102,102,124,102,102,124,0,60,102,96,96,96,102,60,0,120,108,102,102,102,108,120,0,126,96,96,120,96,96,126,0,126,96,96,120,96,96,96,0,60,102,96,110,102,102,60,0,102,102,102, +126,102,102,102,0,120,48,48,48,48,48,120,0,30,12,12,12,12,108,56,0,102,108,120,112,120,108,102,0,96,96,96,96,96,96,126,0,99,119,127,107,99,99,99,0,102,118,126,126,110,102,102,0,60,102,102,102,102,102,60,0,124,102,102,124,96,96,96,0,60,102,102,102,102,60,14,0,124,102,102,124, +120,108,102,0,60,102,96,60,6,102,60,0,126,24,24,24,24,24,24,0,102,102,102,102,102,102,60,0,102,102,102,102,102,60,24,0,99,99,99,107,127,119,99,0,102,102,60,24,60,102,102,0,102,102,102,60,24,24,24,0,126,6,12,24,48,96,126,0,120,96,96,96,96,96,120,0,3,6,12,24,48, +96,192,0,120,24,24,24,24,24,120,0,0,0,0,0,0,219,219,0,0,0,0,0,0,0,0,255,102,102,102,0,0,0,0,0,0,0,60,6,62,102,62,0,0,96,96,124,102,102,124,0,0,0,60,96,96,96,60,0,0,6,6,62,102,102,62,0,0,0,60,102,126,96,60,0,0,14,24,62,24,24, +24,0,0,0,62,102,102,62,6,124,0,96,96,124,102,102,102,0,0,48,0,112,48,48,120,0,0,12,0,12,12,12,12,120,0,96,96,108,120,108,102,0,0,112,48,48,48,48,120,0,0,0,102,127,127,107,99,0,0,0,124,102,102,102,102,0,0,0,60,102,102,102,60,0,0,0,124,102,102,124,96, +96,0,0,62,102,102,62,6,6,0,0,124,102,96,96,96,0,0,0,62,96,60,6,124,0,0,24,126,24,24,24,14,0,0,0,102,102,102,102,62,0,0,0,102,102,102,60,24,0,0,0,99,107,127,62,54,0,0,0,102,60,24,60,102,0,0,0,102,102,102,62,12,120,0,0,126,12,24,48,126,0, +24,48,48,96,48,48,24,0,96,96,96,0,96,96,96,0,96,48,48,24,48,48,96,0,0,0,0,0,0,0,0,0,8,12,14,255,255,14,12,8,60,102,96,96,102,60,24,56,102,0,102,102,102,102,62,0,12,24,60,102,126,96,60,0,24,36,60,6,62,102,62,0,102,0,60,6,62,102,62,0,48, +24,60,6,62,102,62,0,0,0,0,0,0,0,0,0,0,60,96,96,96,60,24,56,24,36,60,102,126,96,60,0,102,0,60,102,126,96,60,0,48,24,60,102,126,96,60,0,0,216,0,112,48,48,120,0,48,72,0,112,48,48,120,0,96,48,0,112,48,48,120,0,102,24,60,102,126,102,102,0,0,0, +0,0,0,0,0,0,24,48,124,96,120,96,124,0,0,0,108,26,126,216,110,0,30,40,40,126,72,136,142,0,24,36,60,102,102,102,60,0,102,0,60,102,102,102,60,0,48,24,60,102,102,102,60,0,24,36,0,102,102,102,62,0,48,24,102,102,102,102,62,0,0,0,0,0,0,0,0,0,102,60,102, +102,102,102,60,0,102,0,102,102,102,102,60,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,24,60,6,62,102,62,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,28,54,54,124,102,102,124,64,0,0,0}; +#endif diff --git a/gui/newgui.cpp b/gui/newgui.cpp new file mode 100644 index 0000000000..8b4cca035a --- /dev/null +++ b/gui/newgui.cpp @@ -0,0 +1,541 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2002 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$ + */ + +#include "stdafx.h" +#include "scumm.h" +#include "newgui.h" +#include "guimaps.h" +#include "gui/dialog.h" +#include "util.h" + +/* + * TODO list + * - implement the missing / incomplete dialogs + * - add more widgets + * - allow multi line (l/c/r aligned) text via StaticTextWidget ? + * - add "close" widget to all dialogs (with a flag to turn it off) ? + * - make dialogs "moveable" ? + * - come up with a new look&feel / theme for the GUI + * - ... + */ + +#define ABS(x) ((x) < 0 ? -(x) : (x)) + +NewGui::NewGui(Scumm *s) : _s(s), _use_alpha_blending(false), + _need_redraw(false),_prepare_for_gui(true), + _pauseDialog(0), _saveLoadDialog(0), _aboutDialog(0), _optionsDialog(0), + _currentKeyDown(0) +{ +} + +void NewGui::pauseDialog() +{ + if (!_pauseDialog) + _pauseDialog = new PauseDialog(this); + _pauseDialog->open(); +} + +void NewGui::saveloadDialog() +{ + if (!_saveLoadDialog) + _saveLoadDialog = new SaveLoadDialog(this); + _saveLoadDialog->open(); +} + +void NewGui::aboutDialog() +{ + if (!_aboutDialog) + _aboutDialog = new AboutDialog(this); + _aboutDialog->open(); +} + +void NewGui::optionsDialog() +{ + if (!_optionsDialog) + _optionsDialog = new OptionsDialog(this); + _optionsDialog->open(); +} + +void NewGui::soundDialog() +{ + if (!_soundDialog) + _soundDialog = new SoundDialog(this); + _soundDialog->open(); +} + +void NewGui::loop() +{ + Dialog *activeDialog = _dialogStack.top(); + int i; + + if (_prepare_for_gui) { + ClearBlendCache(_s->_currentPalette, 128); + saveState(); + if (_use_alpha_blending) + activeDialog->setupScreenBuf(); +#if 1 + // FIXME - hack to encode our own custom GUI colors. Since we have to live + // with a given 8 bit palette, the result is not always as nice as one + // would wish, but this is just an experiment after all. + _bgcolor = RGBMatch(_s->_currentPalette, 0, 0, 0); + + _color = RGBMatch(_s->_currentPalette, 80, 80, 80); + _shadowcolor = RGBMatch(_s->_currentPalette, 64, 64, 64); + + _textcolor = RGBMatch(_s->_currentPalette, 32, 192, 32); + _textcolorhi = RGBMatch(_s->_currentPalette, 0, 256, 0); +#endif + + _eventList.clear(); + _currentKeyDown = 0; + + _lastClick.x = _lastClick.y = 0; + _lastClick.time = 0; + _lastClick.count = 0; + + _prepare_for_gui = false; + } + + activeDialog->handleTickle(); + + if (_need_redraw) { + for (i = 0; i < _dialogStack.size(); i++) + _dialogStack[i]->draw(); + _need_redraw = false; + } + + _s->animateCursor(); + + if (_eventList.size() > 0) + { + OSystem::Event t; + + for (i = 0; i < _eventList.size(); i++) + { + t = _eventList[i]; + + switch(t.event_code) { + case OSystem::EVENT_KEYDOWN: + activeDialog->handleKeyDown(t.kbd.ascii, t.kbd.flags); + + // init continuous event stream + _currentKeyDown = t.kbd.ascii; + _currentKeyDownFlags = t.kbd.flags; + _keyRepeatEvenCount = 1; + _keyRepeatLoopCount = 0; + break; + case OSystem::EVENT_KEYUP: + activeDialog->handleKeyUp(t.kbd.ascii, t.kbd.flags); + if (t.kbd.ascii == _currentKeyDown) + // only stop firing events if it's the current key + _currentKeyDown = 0; + break; + case OSystem::EVENT_MOUSEMOVE: + activeDialog->handleMouseMoved(t.mouse.x - activeDialog->_x, t.mouse.y - activeDialog->_y, 0); + break; + // We don't distinguish between mousebuttons (for now at least) + case OSystem::EVENT_LBUTTONDOWN: + case OSystem::EVENT_RBUTTONDOWN: { + uint32 time = _s->_system->get_msecs(); + if (_lastClick.count && (time < _lastClick.time + 1000) + && ABS(_lastClick.x - t.mouse.x) < 3 + && ABS(_lastClick.y - t.mouse.y) < 3) { + _lastClick.count++; + } else { + _lastClick.x = t.mouse.x; + _lastClick.y = t.mouse.y; + _lastClick.count = 1; + } + _lastClick.time = time; + } + activeDialog->handleMouseDown(t.mouse.x - activeDialog->_x, t.mouse.y - activeDialog->_y, 1, _lastClick.count); + break; + case OSystem::EVENT_LBUTTONUP: + case OSystem::EVENT_RBUTTONUP: + activeDialog->handleMouseUp(t.mouse.x - activeDialog->_x, t.mouse.y - activeDialog->_y, 1, _lastClick.count); + break; + } + } + + _eventList.clear(); + } + + // check if event should be sent again (keydown) + if (_currentKeyDown != 0) + { + // if only fired once, wait longer + if ( _keyRepeatLoopCount >= ((_keyRepeatEvenCount > 1) ? 2 : 4) ) + // ^ loops to wait first event + // ^ loops to wait after first event + { + // fire event + activeDialog->handleKeyDown(_currentKeyDown, _currentKeyDownFlags); + _keyRepeatEvenCount++; + _keyRepeatLoopCount = 0; + } + _keyRepeatLoopCount++; + } + + _s->drawDirtyScreenParts(); +} + +#pragma mark - + +void NewGui::saveState() +{ + _old_soundsPaused = _s->_sound->_soundsPaused; + _s->_sound->pauseSounds(true); + + // Backup old cursor + memcpy(_old_grabbedCursor, _s->_grabbedCursor, sizeof(_old_grabbedCursor)); + _old_cursorWidth = _s->_cursorWidth; + _old_cursorHeight = _s->_cursorHeight; + _old_cursorHotspotX = _s->_cursorHotspotX; + _old_cursorHotspotY = _s->_cursorHotspotY; + _old_cursor_mode = _s->_system->show_mouse(true); + + _s->_cursorAnimate++; + _s->gdi._cursorActive = 1; +} + +void NewGui::restoreState() +{ + _s->_fullRedraw = true; + _s->_completeScreenRedraw = true; + _s->_cursorAnimate--; + + // Restore old cursor + memcpy(_s->_grabbedCursor, _old_grabbedCursor, sizeof(_old_grabbedCursor)); + _s->_cursorWidth = _old_cursorWidth; + _s->_cursorHeight = _old_cursorHeight; + _s->_cursorHotspotX = _old_cursorHotspotX; + _s->_cursorHotspotY = _old_cursorHotspotY; + _s->updateCursor(); + + _s->_system->show_mouse(_old_cursor_mode); + + _s->_sound->pauseSounds(_old_soundsPaused); +} + +void NewGui::openDialog(Dialog *dialog) +{ + if (_dialogStack.empty()) + _prepare_for_gui = true; + else if (_use_alpha_blending) + dialog->setupScreenBuf(); + + _dialogStack.push(dialog); + _need_redraw = true; +} + +void NewGui::closeTopDialog() +{ + // Don't do anything if no dialog is open + if (_dialogStack.empty()) + return; + + // Tear down its screenBuf + if (_use_alpha_blending) + _dialogStack.top()->teardownScreenBuf(); + + // Remove the dialog from the stack + _dialogStack.pop(); + if (_dialogStack.empty()) + restoreState(); + else + _need_redraw = true; +} + +#pragma mark - + +const char *NewGui::queryResString(int stringno) +{ + char *result; + int string; + + if (stringno == 0) + return NULL; + + if (_s->_features & GF_AFTER_V7) + string = _s->_vars[string_map_table_v7[stringno - 1].num]; + else if (_s->_features & GF_AFTER_V6) + string = _s->_vars[string_map_table_v6[stringno - 1].num]; + else + string = string_map_table_v5[stringno - 1].num; + + result = (char *)_s->getStringAddress(string); + + if (!result) { // Gracelessly degrade to english :) + if (_s->_features & GF_AFTER_V6) + return string_map_table_v6[stringno - 1].string; + else + return string_map_table_v5[stringno - 1].string; + } + + return result; +} + +const char *NewGui::queryCustomString(int stringno) +{ + return string_map_table_custom[stringno]; +} + + +#pragma mark - + + +byte *NewGui::getBasePtr(int x, int y) +{ + VirtScreen *vs = _s->findVirtScreen(y); + + if (vs == NULL) + return NULL; + + return vs->screenPtr + x + (y - vs->topline) * 320 + + _s->_screenStartStrip * 8 + (_s->camera._cur.y - 100) * 320; +} + +void NewGui::box(int x, int y, int width, int height) +{ + hline(x + 1, y, x + width - 2, _color); + hline(x, y + 1, x + width - 1, _color); + vline(x, y + 1, y + height - 2, _color); + vline(x + 1, y, y + height - 1, _color); + + hline(x + 1, y + height - 2, x + width - 1, _shadowcolor); + hline(x + 1, y + height - 1, x + width - 2, _shadowcolor); + vline(x + width - 1, y + 1, y + height - 2, _shadowcolor); + vline(x + width - 2, y + 1, y + height - 1, _shadowcolor); +} + +void NewGui::line(int x, int y, int x2, int y2, byte color) +{ + byte *ptr; + + if (x2 < x) + x2 ^= x ^= x2 ^= x; // Swap x2 and x + + if (y2 < y) + y2 ^= y ^= y2 ^= y; // Swap y2 and y + + ptr = getBasePtr(x, y); + + if (ptr == NULL) + return; + + if (x == x2) { + /* vertical line */ + while (y++ <= y2) { + *ptr = color; + ptr += 320; + } + } else if (y == y2) { + /* horizontal line */ + while (x++ <= x2) { + *ptr++ = color; + } + } +} + +void NewGui::blendRect(int x, int y, int w, int h, byte color) +{ + byte *ptr = getBasePtr(x, y); + if (ptr == NULL) + return; + + while (h--) { + for (int i = 0; i < w; i++) { + ptr[i] = Blend(ptr[i], color, _s->_currentPalette); + } + ptr += 320; + } +} + +void NewGui::fillRect(int x, int y, int w, int h, byte color) +{ + byte *ptr = getBasePtr(x, y); + if (ptr == NULL) + return; + + while (h--) { + for (int i = 0; i < w; i++) { + ptr[i] = color; + } + ptr += 320; + } +} + +void NewGui::checkerRect(int x, int y, int w, int h, byte color) +{ + byte *ptr = getBasePtr(x, y); + if (ptr == NULL) + return; + + while (h--) { + for (int i = 0; i < w; i++) { + if ((h ^ i) & 1) + ptr[i] = color; + } + ptr += 320; + } +} + +void NewGui::frameRect(int x, int y, int w, int h, byte color) +{ + int i; + byte *ptr, *basePtr = getBasePtr(x, y); + if (basePtr == NULL) + return; + + ptr = basePtr; + for (i = 0; i < w; i++, ptr++) + *ptr = color; + ptr--; + for (i = 0; i < h; i++, ptr += 320) + *ptr = color; + ptr = basePtr; + for (i = 0; i < h; i++, ptr += 320) + *ptr = color; + ptr -= 320; + for (i = 0; i < w; i++, ptr++) + *ptr = color; +} + +void NewGui::addDirtyRect(int x, int y, int w, int h) +{ + VirtScreen *vs = _s->findVirtScreen(y); + + if (vs != NULL) + _s->setVirtscreenDirty(vs, x, y, x + w, y + h); +} + +void NewGui::drawChar(const char str, int xx, int yy) +{ + unsigned int buffer = 0, mask = 0, x, y; + byte *tmp; + int tempc = _color; + _color = _textcolor; + + tmp = &guifont[0]; + tmp += 224 + (str + 1) * 8; + + byte *ptr = getBasePtr(xx, yy); + if (ptr == NULL) + return; + + for (y = 0; y < 8; y++) { + for (x = 0; x < 8; x++) { + unsigned char color; + if ((mask >>= 1) == 0) { + buffer = *tmp++; + mask = 0x80; + } + color = ((buffer & mask) != 0); + if (color) + ptr[x] = _color; + } + ptr += 320; + } + _color = tempc; + +} + +void NewGui::drawString(const char *str, int x, int y, int w, byte color, int align) +{ + if (_s->_gameId) { /* If a game is active.. */ + StringTab *st = &_s->string[5]; + st->charset = 1; + st->center = (align == kTextAlignCenter); + st->color = color; + + if (align == kTextAlignLeft) + st->xpos = x; + else if (align == kTextAlignCenter) + st->xpos = x + w/2; + else if (align == kTextAlignRight) + st->xpos = x + w - _s->charset.getStringWidth(0, (byte *)str, 0); + + st->ypos = y; + st->right = x + w; + + _s->_messagePtr = (byte *)str; + _s->drawString(5); + } else { + // FIXME - support center/right align, use nicer custom font. + // Ultimately, we might want to *always* draw our messages this way, + // but only if we have a nice font. + uint len = strlen(str); + for (uint letter = 0; letter < len; letter++) + drawChar(str[letter], x + (letter * 8), y); + } +} + +/* + * Draw an 8x8 bitmap at location (x,y) + */ +void NewGui::drawBitmap(uint32 bitmap[8], int x, int y, byte color) +{ + byte *ptr = getBasePtr(x, y); + if (ptr == NULL) + return; + + for (int y2 = 0; y2 < 8; y2++) { + uint32 mask = 0xF0000000; + for (int x2 = 0; x2 < 8; x2++) { + if (bitmap[y2] & mask) + ptr[x2] = color; + mask >>= 4; + } + ptr += 320; + } +} + +void NewGui::blitTo(byte buffer[320*200], int x, int y, int w, int h) +{ + byte *dstPtr = buffer + x + y*320; + byte *srcPtr = getBasePtr(x, y); + if (srcPtr == NULL) + return; + + while (h--) { + for (int i = 0; i < w; i++) { + *dstPtr++ = *srcPtr++; + } + dstPtr += 320 - w; + srcPtr += 320 - w; + } +} + +void NewGui::blitFrom(byte buffer[320*200], int x, int y, int w, int h) +{ + byte *srcPtr = buffer + x + y*320; + byte *dstPtr = getBasePtr(x, y); + if (dstPtr == NULL) + return; + + while (h--) { + for (int i = 0; i < w; i++) { + *dstPtr++ = *srcPtr++; + } + dstPtr += 320 - w; + srcPtr += 320 - w; + } +} + diff --git a/gui/newgui.h b/gui/newgui.h new file mode 100644 index 0000000000..f78f31ee2d --- /dev/null +++ b/gui/newgui.h @@ -0,0 +1,151 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2002 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$ + */ + +#ifndef NEWGUI_H +#define NEWGUI_H + +#include "scummsys.h" +#include "system.h" // For events +#include "util.h" + +class Dialog; +class Scumm; + +#define hline(x, y, x2, color) line(x, y, x2, y, color); +#define vline(x, y, y2, color) line(x, y, x, y2, color); + +enum { + kTextAlignLeft, + kTextAlignCenter, + kTextAlignRight, +}; + +// Extremly simple stack class, doesn't even do any error checking (for now) +class DialogStack { +protected: + Dialog *_stack[10]; // Anybody nesting dialogs deeper than 4 is mad anyway + int _size; +public: + DialogStack() : _size(0) {} + + bool empty() const { return _size <= 0; } + void push(Dialog *d) { _stack[_size++] = d; } + Dialog *top() const { return _stack[_size-1]; } + void pop() { if (_size > 0) _stack[--_size] = 0; } + int size() const { return _size; } + Dialog *operator [](int i) { return _stack[i]; } +}; + +typedef ScummVM::List<OSystem::Event> EventList; + +// This class hopefully will replace the old Gui class completly one day +class NewGui { + friend class Dialog; +public: + byte _color, _shadowcolor; + byte _bgcolor; + byte _textcolor; + byte _textcolorhi; + + // Dialogs + void pauseDialog(); + void saveloadDialog(); + void aboutDialog(); + void optionsDialog(); + void soundDialog(); + + void loop(); + + bool isActive() { return ! _dialogStack.empty(); } + + NewGui(Scumm *s); + + void handleEvent(const OSystem::Event &event) { _eventList.push_back(event); } + + Scumm *getScumm() { return _s; } + +protected: + Scumm *_s; + bool _use_alpha_blending; + bool _need_redraw; + bool _prepare_for_gui; + DialogStack _dialogStack; + + Dialog *_pauseDialog; + Dialog *_saveLoadDialog; + Dialog *_aboutDialog; + Dialog *_optionsDialog; + Dialog *_soundDialog; + + // for continuous events (keyDown) + int _currentKeyDown, _currentKeyDownFlags; + int _keyRepeatLoopCount; + int _keyRepeatEvenCount; + + // sound state + bool _old_soundsPaused; + + // mouse cursor state + bool _old_cursor_mode; + int _old_cursorHotspotX, _old_cursorHotspotY, _old_cursorWidth, _old_cursorHeight; + byte _old_grabbedCursor[2048]; + + // position and time of last mouse click (used to detect double clicks) + struct { + int16 x, y; // Position of mouse when the click occured + uint32 time; // Time + int count; // How often was it already pressed? + } _lastClick; + + // List of events to be handled + EventList _eventList; + + void saveState(); + void restoreState(); + + void openDialog(Dialog *dialog); + void closeTopDialog(); + +public: + // Drawing + byte *getBasePtr(int x, int y); + void box(int x, int y, int width, int height); + void line(int x, int y, int x2, int y2, byte color); + void blendRect(int x, int y, int w, int h, byte color); + void fillRect(int x, int y, int w, int h, byte color); + void checkerRect(int x, int y, int w, int h, byte color); + void frameRect(int x, int y, int w, int h, byte color); + void addDirtyRect(int x, int y, int w, int h); + void drawChar(const char c, int x, int y); + void drawString(const char *str, int x, int y, int w, byte color, int align = kTextAlignLeft); + + void drawBitmap(uint32 bitmap[8], int x, int y, byte color); + void blitTo(byte buffer[320*200], int x, int y, int w, int h); + void blitFrom(byte buffer[320*200], int x, int y, int w, int h); + + // Query a string from the resources + const char *queryResString(int stringno); + + // Query a custom string. This is in a seperate method so that we + // can easily localize the messages in the future if we want to. + const char *queryCustomString(int stringno); +}; + +#endif |