aboutsummaryrefslogtreecommitdiff
path: root/gui/newgui.cpp
diff options
context:
space:
mode:
authorMax Horn2002-08-21 16:07:07 +0000
committerMax Horn2002-08-21 16:07:07 +0000
commitce46866403fdcc479cf9d67e4d430409b15dadc3 (patch)
tree75ebfaa1ed13f549959d76d3ce101c3e66f5451b /gui/newgui.cpp
parent662256f25dbe43abf67077a804e225738765f009 (diff)
downloadscummvm-rg350-ce46866403fdcc479cf9d67e4d430409b15dadc3.tar.gz
scummvm-rg350-ce46866403fdcc479cf9d67e4d430409b15dadc3.tar.bz2
scummvm-rg350-ce46866403fdcc479cf9d67e4d430409b15dadc3.zip
Initial revision
svn-id: r4785
Diffstat (limited to 'gui/newgui.cpp')
-rw-r--r--gui/newgui.cpp541
1 files changed, 541 insertions, 0 deletions
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;
+ }
+}
+