Countless changes to the New GUI; some hightligths: new ScrollBarWidget class; ListWidget is usable (demo shows it off); added custom String/StringList classes

svn-id: r4521
This commit is contained in:
Max Horn 2002-07-12 16:24:11 +00:00
parent c99d9a57c0
commit e34571dca9
14 changed files with 736 additions and 188 deletions

View file

@ -6,7 +6,8 @@ ZIPFILE := scummvm-`date '+%Y-%m-%d'`.zip
INCS = scumm.h scummsys.h stdafx.h
OBJS += gui/widget.o gui/dialog.o gui/ListWidget.o newgui.o \
OBJS += gui/widget.o gui/dialog.o gui/util.o newgui.o \
gui/ListWidget.o gui/ScrollBarWidget.o \
actor.o boxes.o costume.o gfx.o object.o resource.o \
saveload.o script.o scummvm.o sound.o string.o \
sys.o verbs.o script_v1.o script_v2.o debug.o gui.o \

View file

@ -908,11 +908,12 @@ const char *Gui::queryString(int stringno, int id)
result = (char *)_s->getStringAddress(string);
if (!result) // Gracelessly degrade to english :)
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;
}

View file

@ -20,20 +20,19 @@
#include "stdafx.h"
#include "ListWidget.h"
#include "ScrollBarWidget.h"
#include "dialog.h"
#include "newgui.h"
/*
* Some thoughts:
* - We should split out the scrollbar into a seperate widget. This will
* simplify the drawing & mouse handling considerably, but also requires
* us to come up with a way to couple both widgets (shouldn't be to hard)
* - Write a class to encapsulate the data instead of using std::list<string>.
* How exactly this will look and what it does has yet to be determined.
* TODO:
* - The handleKey method of widgets is currently never called, code for that has
* to be added to dialog.cpp
* - ...
* - Once the above item is done, implement scrolling using arrow keys,
* pageup/pagedown, home/end keys etc.
* - Allow user to select an entry w/ the mouse
* - Implement editing of the selected string in a generic fashion
*/
@ -41,85 +40,87 @@
#define LINE_HEIGHT 10
// Up/down arrow for the scrollbar
static uint32 up_arrow[8] = {
0x00000000,
0x00000000,
0x00001000,
0x00001000,
0x00011100,
0x00011100,
0x00110110,
0x00100010,
};
static uint32 down_arrow[8] = {
0x00000000,
0x00000000,
0x00100010,
0x00110110,
0x00011100,
0x00011100,
0x00001000,
0x00001000,
};
ListWidget::ListWidget(Dialog *boss, int x, int y, int w, int h)
: Widget(boss, x, y, w, h)
: Widget(boss, x, y, w - SCROLLBAR_WIDTH, h)
{
_flags = WIDGET_ENABLED | WIDGET_TRACK_MOUSE | WIDGET_CLEARBG;
_flags = WIDGET_ENABLED | WIDGET_CLEARBG;
_type = kListWidget;
_numberingMode = kListNumberingOne;
_entriesPerPage = (_h - 4) / LINE_HEIGHT;
_currentPos = 3;
_scrollBar = new ScrollBarWidget(boss, _x + _w, _y, SCROLLBAR_WIDTH, _h);
_scrollBar->setTarget(this);
// FIXME - fill in dummy data for now
_list.push_back("A simple game?");
_list.push_back("This space for rent!");
_list.push_back("To be or not to be...");
_list.push_back("It's not easy come up with dummy text :-)");
_list.push_back("Foo bar baz");
_list.push_back("Empty slots follow:");
_list.push_back("");
_list.push_back("");
_list.push_back("Now again a filled slot");
_list.push_back("We need some more text!");
_list.push_back("Because only this way...");
_list.push_back("...can you see the scrollbar...");
_list.push_back("...and verify that it works!");
_list.push_back("One");
_list.push_back("Two");
_list.push_back("Three");
_list.push_back("Four");
_list.push_back("The End");
_scrollBar->_numEntries = _list.size();
_scrollBar->_entriesPerPage = _entriesPerPage;
_scrollBar->_currentPos = _currentPos;
_scrollBar->recalc();
}
ListWidget::~ListWidget()
{
}
void ListWidget::handleClick(int button)
void ListWidget::handleClick(int x, int y, int button)
{
if (_flags & WIDGET_ENABLED) {
}
}
void ListWidget::handleMouseMoved(int x, int y, int state)
{
}
void ListWidget::handleKey(char key, int modifiers)
{
}
void ListWidget::handleCommand(CommandSender *sender, uint32 cmd, uint32 data)
{
switch (cmd) {
case kSetPositionCmd:
if (_currentPos != data) {
_currentPos = data;
draw();
}
break;
}
}
void ListWidget::drawWidget(bool hilite)
{
NewGui *gui = _boss->getGui();
int rightX = _x + _w - 1;
int leftX = rightX - 8;
int bottomY = _y + _h;
NewGui *gui = _boss->getGui();
int i, pos;
String buffer;
gui->frameRect(leftX, _y, 9, _h, gui->_shadowcolor);
// Up arrow
gui->fillRect(leftX, _y, 9, 10, gui->_bgcolor);
gui->frameRect(leftX, _y, 9, 10, gui->_color);
gui->drawBitmap(up_arrow, leftX, _y, gui->_textcolor);
// Down arrow
gui->fillRect(leftX, bottomY - 9, 9, 10, gui->_bgcolor);
gui->frameRect(leftX, bottomY - 9, 9, 10, gui->_color);
gui->drawBitmap(down_arrow, leftX, bottomY - 9, gui->_textcolor);
// Slider
// FIXME - determine slider position and size. This depends on:
// * the number of entries/page
// * total number of entries
// * current scroll position (i.e. idx of "first" visible entry
gui->fillRect(leftX, _y+20, 9, 4, gui->_textcolor);
gui->frameRect(leftX, _y+20, 9, 4, gui->_color);
// Now draw the list items
// Draw the list items
// FIXME - this is just a temporary demo hack
gui->drawString("1. A simple game", _x+1, _y+1, _w - 10, gui->_textcolor);
gui->drawString("2. This space for rent", _x+1, _y+1 + LINE_HEIGHT, _w - 10, gui->_textcolorhi);
gui->drawString("3. To be or not to be", _x+1, _y+1 + LINE_HEIGHT*2, _w - 10, gui->_textcolor);
for (i = 0, pos = _currentPos; i < _entriesPerPage; i++, pos++) {
if (_numberingMode == kListNumberingZero || _numberingMode == kListNumberingOne) {
char temp[10];
sprintf(temp, "%2d. ", (pos + _numberingMode));
buffer = temp;
} else
buffer = "";
buffer += _list[pos];
gui->drawString(buffer, _x+5, _y+2 + LINE_HEIGHT * i, _w - 10, gui->_textcolor);
}
}

View file

@ -22,13 +22,9 @@
#define LISTWIDGET_H
#include "widget.h"
#include "util.h"
// FIXME - use own list class later, this is for rapid development
//#include <string>
//#include <vector>
//typedef std::vector<std::string> StringList;
typedef int StringList; // FIXME placeholder
class ScrollBarWidget;
enum {
kListNumberingOff = -1,
@ -37,13 +33,14 @@ enum {
};
/* ListWidget */
class ListWidget : public Widget {
class ListWidget : public Widget, public CommandReceiver {
protected:
StringList _list;
bool _editable;
int _numberingMode;
int _currentPos;
StringList _list;
bool _editable;
int _numberingMode;
int _currentPos;
int _entriesPerPage;
ScrollBarWidget *_scrollBar;
public:
ListWidget(Dialog *boss, int x, int y, int w, int h);
virtual ~ListWidget();
@ -53,9 +50,9 @@ public:
void setNumberingMode(int numberingMode) { _numberingMode = numberingMode; }
virtual void handleClick(int button);
virtual void handleMouseMoved(int x, int y, int button);
virtual void handleClick(int x, int y, int button);
virtual void handleKey(char key, int modifiers);
virtual void handleCommand(CommandSender *sender, uint32 cmd, uint32 data);
protected:
void drawWidget(bool hilite);

157
gui/ScrollBarWidget.cpp Normal file
View file

@ -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$
*/
#include "stdafx.h"
#include "ScrollBarWidget.h"
#include "dialog.h"
#include "newgui.h"
/*
* TODO:
* - Dragging the slider with the mouse
* - Auto-repeast: if one clicks & holds on one of the arrows, then after a
* brief delay, it should start to contiously scroll
* - Allow for a horizontal scrollbar, too?
*/
// Up arrow
static uint32 up_arrow[8] = {
0x00000000,
0x00000000,
0x00001000,
0x00001000,
0x00011100,
0x00011100,
0x00110110,
0x00100010,
};
// Up arrow
static uint32 down_arrow[8] = {
0x00000000,
0x00000000,
0x00100010,
0x00110110,
0x00011100,
0x00011100,
0x00001000,
0x00001000,
};
ScrollBarWidget::ScrollBarWidget(Dialog *boss, int x, int y, int w, int h)
: Widget(boss, x, y, w, h), CommandSender(boss)
{
_flags = WIDGET_ENABLED | WIDGET_TRACK_MOUSE | WIDGET_CLEARBG;
_type = kScrollBarWidget;
_part = kNoPart;
}
void ScrollBarWidget::handleClick(int x, int y, int button)
{
int old_pos = _currentPos;
if (y <= 10) {
// Up arrow
_currentPos--;
} else if (y >= _h-10) {
// Down arrow
_currentPos++;
} else if (y < _sliderPos) {
_currentPos -= _entriesPerPage;
} else if (y >= _sliderPos + _sliderHeight) {
_currentPos += _entriesPerPage;
} else {
printf("Slider\n");
}
// Bound checking
if (_currentPos > _numEntries - _entriesPerPage)
_currentPos = _numEntries - _entriesPerPage;
else if (_currentPos < 0)
_currentPos = 0;
// Redraw & notify, but only if the position really changed
if (old_pos != _currentPos) {
recalc();
draw();
sendCommand(kSetPositionCmd, _currentPos);
}
}
void ScrollBarWidget::handleMouseMoved(int x, int y, int button)
{
int old_part = _part;
if (y <= 10) // Up arrow
_part = kUpArrowPart;
else if (y >= _h-10) // Down arrow
_part = kDownArrowPart;
else if (y < _sliderPos)
_part = kPageUpPart;
else if (y >= _sliderPos + _sliderHeight)
_part = kPageDownPart;
else
_part = kSliderPart;
if (old_part != _part)
draw();
}
void ScrollBarWidget::recalc()
{
_sliderHeight = (_h-20) * _entriesPerPage / _numEntries;
if (_sliderHeight < 4)
_sliderHeight = 4;
_sliderPos = 10 + (_h-20-_sliderHeight+1) *_currentPos / (_numEntries - _entriesPerPage);
if (_sliderPos < 0)
_sliderPos = 0;
}
void ScrollBarWidget::drawWidget(bool hilite)
{
NewGui *gui = _boss->getGui();
int bottomY = _y + _h;
gui->frameRect(_x, _y, _w, _h, gui->_shadowcolor);
// Up arrow
gui->frameRect(_x, _y, _w, 10, gui->_color);
gui->drawBitmap(up_arrow, _x, _y,
(hilite && _part == kUpArrowPart) ? gui->_textcolorhi : gui->_textcolor);
// Down arrow
gui->frameRect(_x, bottomY - 9, _w, 10, gui->_color);
gui->drawBitmap(down_arrow, _x, bottomY - 9,
(hilite && _part == kDownArrowPart) ? gui->_textcolorhi : gui->_textcolor);
// Slider
// FIXME - determine slider position and size. This depends on:
// * the number of entries per page
// * total number of entries
// * current scroll position (i.e. index of "first" visible entry)
gui->checkerRect(_x, _y + _sliderPos, _w, _sliderHeight,
(hilite && _part == kSliderPart) ? gui->_textcolorhi : gui->_textcolor);
gui->frameRect(_x, _y + _sliderPos, _w, _sliderHeight, gui->_color);
}

65
gui/ScrollBarWidget.h Normal file
View file

@ -0,0 +1,65 @@
/* 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 SCROLLBARWIDGET_H
#define SCROLLBARWIDGET_H
#include "widget.h"
#define SCROLLBAR_WIDTH 9
enum {
kSetPositionCmd = 'SETP'
};
class ScrollBarWidget : public Widget, public CommandSender {
protected:
enum {
kNoPart,
kUpArrowPart,
kDownArrowPart,
kSliderPart,
kPageUpPart,
kPageDownPart
} _part;
int _sliderHeight;
int _sliderPos;
public:
int _numEntries;
int _entriesPerPage;
int _currentPos;
public:
ScrollBarWidget(Dialog *boss, int x, int y, int w, int h);
// virtual ~ScrollBarWidget();
void handleClick(int x, int y, int button);
void handleMouseMoved(int x, int y, int button);
void handleMouseEntered(int button) { setFlags(WIDGET_HILITED); }
void handleMouseLeft(int button) { clearFlags(WIDGET_HILITED); _part = kNoPart; draw(); }
void recalc();
protected:
void drawWidget(bool hilite);
};
#endif

View file

@ -84,7 +84,7 @@ void Dialog::handleClick(int x, int y, int button)
{
Widget *w = findWidget(x - _x, y - _y);
if (w)
w->handleClick(button);
w->handleClick(x - _x - w->_x, y - _y - w->_y, button);
}
void Dialog::handleKey(char key, int modifiers)
@ -98,7 +98,7 @@ void Dialog::handleKey(char key, int modifiers)
key = toupper(key);
while (w) {
if (w->_type == kButtonWidget && key == toupper(((ButtonWidget *)w)->_hotkey)) {
w->handleClick(1);
w->handleClick(0, 0, 1);
break;
}
w = w->_next;
@ -130,7 +130,7 @@ void Dialog::handleMouseMoved(int x, int y, int button)
}
void Dialog::handleCommand(uint32 cmd)
void Dialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data)
{
switch (cmd) {
case kCloseCmd:
@ -205,10 +205,10 @@ SaveLoadDialog::SaveLoadDialog(NewGui *gui)
new SliderWidget(this, 110, 20, 80, 16, "Volume", 0);
// FIXME - test
new ListWidget(this, 10, 40, 180, 70);
new ListWidget(this, 10, 40, 180, 74);
}
void SaveLoadDialog::handleCommand(uint32 cmd)
void SaveLoadDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data)
{
switch (cmd) {
case kSaveCmd:
@ -225,7 +225,7 @@ void SaveLoadDialog::handleCommand(uint32 cmd)
exit(1);
break;
default:
Dialog::handleCommand(cmd);
Dialog::handleCommand(sender, cmd, data);
}
}
@ -249,7 +249,7 @@ OptionsDialog::OptionsDialog(NewGui *gui)
addButton(150, 35, 40, 15, CUSTOM_STRING(23), kCloseCmd, 'C'); // Close dialog - FIXME
}
void OptionsDialog::handleCommand(uint32 cmd)
void OptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data)
{
switch (cmd) {
case kSoundCmd:
@ -262,7 +262,7 @@ void OptionsDialog::handleCommand(uint32 cmd)
case kMiscCmd:
break;
default:
Dialog::handleCommand(cmd);
Dialog::handleCommand(sender, cmd, data);
}
}

View file

@ -22,9 +22,8 @@
#define DIALOG_H
#include "scummsys.h"
#include "widget.h"
class Widget;
class NewGui;
#define RES_STRING(id) _gui->queryResString(id)
@ -35,7 +34,7 @@ enum {
kCloseCmd = 'clos'
};
class Dialog {
class Dialog : public CommandReceiver {
friend class Widget;
protected:
NewGui *_gui;
@ -57,7 +56,7 @@ public:
virtual void handleClick(int x, int y, int button);
virtual void handleKey(char key, int modifiers); // modifiers = alt/shift/ctrl etc.
virtual void handleMouseMoved(int x, int y, int button);
virtual void handleCommand(uint32 cmd);
virtual void handleCommand(CommandSender *sender, uint32 cmd, uint32 data);
NewGui *getGui() { return _gui; }
@ -77,7 +76,7 @@ class SaveLoadDialog : public Dialog {
public:
SaveLoadDialog(NewGui *gui);
virtual void handleCommand(uint32 cmd);
virtual void handleCommand(CommandSender *sender, uint32 cmd, uint32 data);
};
@ -94,7 +93,7 @@ protected:
public:
OptionsDialog(NewGui *gui);
virtual void handleCommand(uint32 cmd);
virtual void handleCommand(CommandSender *sender, uint32 cmd, uint32 data);
};
class PauseDialog : public Dialog {

246
gui/util.cpp Normal file
View file

@ -0,0 +1,246 @@
/* 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 "util.h"
// 8-bit alpha blending routines
int BlendCache[256][256];
int RGBMatch(byte *palette, int r, int g, int b)
{
int i, bestidx = 0, besterr = 0xFFFFFF;
int error = 0;
for (i = 0;i < 256;i++) {
byte *pal = palette + (i * 3);
int r_diff = r - (int)*pal++;
int g_diff = g - (int)*pal++;
int b_diff = b - (int)*pal++;
r_diff *= r_diff; g_diff *= g_diff; b_diff *= b_diff;
error = r_diff + g_diff + b_diff;
if (error < besterr) {
besterr = error;
bestidx = i;
}
}
return bestidx;
}
int Blend(int src, int dst, byte *palette)
{
int r, g, b;
int alpha = 128; // Level of transparency [0-256]
byte *srcpal = palette + (dst * 3);
byte *dstpal = palette + (src * 3);
if (BlendCache[dst][src] > -1)
return BlendCache[dst][src];
r = (*srcpal++ * alpha);
r += (*dstpal++ * (256-alpha));
r /= 256;
g = (*srcpal++ * alpha);
g += (*dstpal++ * (256-alpha));
g /= 256;
b = (*srcpal++ * alpha);
b += (*dstpal++ * (256-alpha));
b /= 256;
return (BlendCache[dst][src] = RGBMatch(palette, r , g , b ));
}
void ClearBlendCache(byte *palette, int weight)
{
for (int i = 0; i < 256; i++)
for (int j = 0 ; j < 256 ; j++)
// BlendCache[i][j] = i; // No alphablending
// BlendCache[i][j] = j; // 100% translucent
BlendCache[i][j] = -1; // Enable alphablending
}
#pragma mark -
String::String(const char *str)
{
_capacity = _len = strlen(str);
_str = (char *)calloc(1, _capacity+1);
memcpy(_str, str, _len+1);
}
String::String(const String &str)
{
_capacity = str._capacity;
_len = str._len;
_str = (char *)calloc(1, _capacity+1);
memcpy(_str, str._str, _len+1);
}
String::~String()
{
if (_str)
free(_str);
}
String& String::operator =(const char* str)
{
int len = strlen(str);
ensureCapacity(len, false);
_len = len;
memcpy(_str, str, _len + 1);
return *this;
}
String& String::operator =(const String& str)
{
int len = str._len;
ensureCapacity(len, false);
_len = len;
memcpy(_str, str._str, _len + 1);
return *this;
}
String& String::operator +=(const char* str)
{
int len = strlen(str);
ensureCapacity(_len + len, true);
memcpy(_str + _len, str, len + 1);
_len += len;
return *this;
}
String& String::operator +=(const String& str)
{
int len = str._len;
ensureCapacity(_len + len, true);
memcpy(_str + _len, str._str, len + 1);
_len += len;
return *this;
}
String& String::operator +=(char c)
{
int len = _len + 1;
ensureCapacity(len, true);
_str[_len++] = c;
_str[_len] = 0;
return *this;
}
void String::ensureCapacity(int new_len, bool keep_old)
{
if (new_len <= _capacity)
return;
char *old_str = _str;
_capacity = new_len + 32;
_str = (char *)calloc(1, _capacity+1);
if (old_str) {
if (keep_old)
memcpy(_str, old_str, _len+1);
free(old_str);
}
}
#pragma mark -
StringList::StringList(const StringList& list)
: _capacity(0), _size(0), _data(0)
{
printf("EEEEK! StringList copy constructor called!\n");
assert(0);
}
StringList::~StringList()
{
if (_data)
free(_data);
}
void StringList::push_back(const char* str)
{
ensureCapacity(_size + 1);
if (!_data[_size])
_data[_size] = new String(str);
else
*_data[_size] = str;
_size++;
}
void StringList::push_back(const String& str)
{
ensureCapacity(_size + 1);
if (!_data[_size])
_data[_size] = new String(str);
else
*_data[_size] = str;
_size++;
}
String& StringList::operator [](int idx)
{
assert(idx >= 0 && idx < _size);
return *_data[idx];
}
const String& StringList::operator [](int idx) const
{
assert(idx >= 0 && idx < _size);
return *_data[idx];
}
void StringList::ensureCapacity(int new_len)
{
if (new_len <= _capacity)
return;
String **old_data = _data;
_capacity = new_len + 32;
_data = (String **)calloc(sizeof(String*), _capacity);
if (old_data) {
memcpy(_data, old_data, _size * sizeof(String*));
free(old_data);
}
}

83
gui/util.h Normal file
View file

@ -0,0 +1,83 @@
/* 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 UTIL_H
#define UTIL_H
#include "scummsys.h"
int RGBMatch(byte *palette, int r, int g, int b);
int Blend(int src, int dst, byte *palette);
void ClearBlendCache(byte *palette, int weight);
class String {
protected:
int _capacity;
int _len;
char *_str;
public:
String() : _capacity(0), _len(0), _str(0) {}
String(const char *str);
String(const String &str);
~String();
String& operator =(const char* str);
String& operator =(const String& str);
String& operator +=(const char* str);
String& operator +=(const String& str);
String& operator +=(char c);
// operator char *() { return _str; }
operator const char *() const { return _str; }
const char *c_str() const { return _str; }
int size() const { return _len; }
protected:
void ensureCapacity(int new_len, bool keep_old);
};
class StringList {
protected:
int _capacity;
int _size;
String **_data;
public:
StringList() : _capacity(0), _size(0), _data(0) {}
StringList(const StringList& list);
~StringList();
void push_back(const char* str);
void push_back(const String& str);
// TODO: insert, remove, ...
String& operator [](int idx);
const String& operator [](int idx) const;
int size() const { return _size; }
protected:
void ensureCapacity(int new_len);
};
#endif

View file

@ -44,7 +44,7 @@ void Widget::draw()
_y += _boss->_y;
// Clear background (unless alpha blending is enabled)
if (_flags & WIDGET_CLEARBG && !_boss->_screenBuf)
if (_flags & WIDGET_CLEARBG)
gui->fillRect(_x, _y, _w, _h, gui->_bgcolor);
// Draw border
@ -74,37 +74,37 @@ void Widget::draw()
StaticTextWidget::StaticTextWidget(Dialog *boss, int x, int y, int w, int h, const char *text)
: Widget (boss, x, y, w, h), _text(0)
: Widget (boss, x, y, w, h), _label(0)
{
_type = kStaticTextWidget;
setText(text);
setLabel(text);
}
StaticTextWidget::~StaticTextWidget()
{
if (_text) {
free(_text);
_text = 0;
if (_label) {
free(_label);
_label = 0;
}
}
void StaticTextWidget::setText(const char *text)
void StaticTextWidget::setLabel(const char *label)
{
// Free old text if any
if (_text)
free(_text);
// Free old label if any
if (_label)
free(_label);
// Duplicate new text
if (text)
_text = strdup(text);
// Duplicate new label
if (label)
_label = strdup(label);
else
_text = 0;
_label = 0;
}
void StaticTextWidget::drawWidget(bool hilite)
{
NewGui *gui = _boss->getGui();
gui->drawString(_text, _x, _y, _w, hilite ? gui->_textcolorhi : gui->_textcolor);
gui->drawString(_label, _x, _y, _w, hilite ? gui->_textcolorhi : gui->_textcolor);
}
@ -112,18 +112,26 @@ void StaticTextWidget::drawWidget(bool hilite)
ButtonWidget::ButtonWidget(Dialog *boss, int x, int y, int w, int h, const char *label, uint32 cmd, uint8 hotkey)
: StaticTextWidget(boss, x, y, w, h, label), _cmd(cmd), _hotkey(hotkey)
: StaticTextWidget(boss, x, y, w, h, label), CommandSender(boss), _cmd(cmd), _hotkey(hotkey)
{
assert(label);
_flags = WIDGET_ENABLED | WIDGET_BORDER | WIDGET_CLEARBG ;
_type = kButtonWidget;
}
void ButtonWidget::handleClick(int button)
ButtonWidget::~ButtonWidget()
{
if (_flags & WIDGET_ENABLED && _cmd)
_boss->handleCommand(_cmd);
if (_label) {
free(_label);
_label = 0;
}
}
void ButtonWidget::handleClick(int x, int y, int button)
{
if (_flags & WIDGET_ENABLED)
sendCommand(_cmd, 0);
}
#pragma mark -
@ -147,13 +155,12 @@ CheckboxWidget::CheckboxWidget(Dialog *boss, int x, int y, int w, int h, const c
_type = kCheckboxWidget;
}
void CheckboxWidget::handleClick(int button)
void CheckboxWidget::handleClick(int x, int y, int button)
{
if (_flags & WIDGET_ENABLED) {
_state = !_state;
draw();
if (_cmd)
_boss->handleCommand(_cmd);
sendCommand(_cmd, 0);
}
}
@ -171,7 +178,7 @@ void CheckboxWidget::drawWidget(bool hilite)
gui->fillRect(_x + 2, _y + 2, 10, 10, gui->_bgcolor);
// Finally draw the label
gui->drawString(_text, _x + 20, _y + 3, _w, gui->_textcolor);
gui->drawString(_label, _x + 20, _y + 3, _w, gui->_textcolor);
}
#pragma mark -

View file

@ -41,7 +41,35 @@ enum {
kButtonWidget = 'BTTN',
kCheckboxWidget = 'CHKB',
kSliderWidget = 'SLDE',
kListWidget = 'LIST'
kListWidget = 'LIST',
kScrollBarWidget = 'SCRB'
};
class CommandReceiver;
class CommandSender;
class CommandReceiver
{
friend class CommandSender;
protected:
virtual void handleCommand(CommandSender *sender, uint32 cmd, uint32 data) = 0;
};
class CommandSender
{
protected:
CommandReceiver *_target;
public:
CommandSender(CommandReceiver *target) : _target(target) {}
void setTarget(CommandReceiver *target) { _target = target; }
CommandReceiver *getTarget() const { return _target; }
virtual void sendCommand(uint32 cmd, uint32 data)
{
if (_target && cmd)
_target->handleCommand(this, cmd, data);
}
};
/* Widget */
@ -59,7 +87,7 @@ public:
Widget(Dialog *boss, int x, int y, int w, int h);
virtual ~Widget() {}
virtual void handleClick(int button) {}
virtual void handleClick(int x, int y, int button) {}
virtual void handleMouseEntered(int button) {}
virtual void handleMouseLeft(int button) {}
virtual void handleMouseMoved(int x, int y, int button) {}
@ -78,12 +106,12 @@ protected:
/* StaticTextWidget */
class StaticTextWidget : public Widget {
protected:
char *_text;
char *_label;
public:
StaticTextWidget(Dialog *boss, int x, int y, int w, int h, const char *text);
~StaticTextWidget();
void setText(const char *text);
const char *getText() const { return _text; }
void setLabel(const char *label);
const char *getLabel() const { return _label; }
protected:
void drawWidget(bool hilite);
@ -91,17 +119,19 @@ protected:
/* ButtonWidget */
class ButtonWidget : public StaticTextWidget {
friend class Dialog;
class ButtonWidget : public StaticTextWidget, public CommandSender {
friend class Dialog; // Needed for the hotkey handling
protected:
uint32 _cmd;
uint8 _hotkey;
uint32 _cmd;
uint8 _hotkey;
public:
ButtonWidget(Dialog *boss, int x, int y, int w, int h, const char *label, uint32 cmd = 0, uint8 hotkey = 0);
void setCmd(uint32 cmd) { _cmd = cmd; }
uint32 getCmd() const { return _cmd; }
virtual ~ButtonWidget();
void handleClick(int button);
void setCmd(uint32 cmd) { _cmd = cmd; }
uint32 getCmd() const { return _cmd; }
void handleClick(int x, int y, int button);
void handleMouseEntered(int button) { setFlags(WIDGET_HILITED); draw(); }
void handleMouseLeft(int button) { clearFlags(WIDGET_HILITED); draw(); }
};
@ -115,7 +145,7 @@ public:
void setState(bool state) { _state = state; }
bool getState() const { return _state; }
void handleClick(int button);
void handleClick(int x, int y, int button);
virtual void handleMouseEntered(int button) {}
virtual void handleMouseLeft(int button) {}

View file

@ -23,65 +23,10 @@
#include "newgui.h"
#include "guimaps.h"
#include "gui/dialog.h"
// 8-bit alpha blending routines
int BlendCache[256][256];
int RGBMatch(byte *palette, int r, int g, int b) {
int i, bestidx = 0, besterr = 0xFFFFFF;
int error = 0;
for (i = 0;i < 256;i++) {
byte *pal = palette + (i * 3);
int r_diff = r - (int)*pal++;
int g_diff = g - (int)*pal++;
int b_diff = b - (int)*pal++;
r_diff *= r_diff; g_diff *= g_diff; b_diff *= b_diff;
error = r_diff + g_diff + b_diff;
if (error < besterr) {
besterr = error;
bestidx = i;
}
}
return bestidx;
}
int Blend(int src, int dst, byte *palette) {
int r, g, b;
int alpha = 128; // Level of transparency [0-256]
byte *srcpal = palette + (dst * 3);
byte *dstpal = palette + (src * 3);
if (BlendCache[dst][src] > -1)
return BlendCache[dst][src];
r = (*srcpal++ * alpha);
r += (*dstpal++ * (256-alpha));
r /= 256;
g = (*srcpal++ * alpha);
g += (*dstpal++ * (256-alpha));
g /= 256;
b = (*srcpal++ * alpha);
b += (*dstpal++ * (256-alpha));
b /= 256;
return (BlendCache[dst][src] = RGBMatch(palette, r , g , b ));
}
void ClearBlendCache(byte *palette, int weight) {
for (int i = 0; i < 256; i++)
for (int j = 0 ; j < 256 ; j++)
// BlendCache[i][j] = i; // No alphablending
// BlendCache[i][j] = j; // 100% translucent
BlendCache[i][j] = -1; // Enable alphablending
}
#include "gui/util.h"
/*
* TODO list
* - keep a copy of the original game background, for alpha/moving
* - implement the missing / incomplete dialogs
* - add more widgets
* - add support for right/center aligned text
@ -357,6 +302,21 @@ void NewGui::fillRect(int x, int y, int w, int h, byte color)
}
}
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;

View file

@ -102,6 +102,7 @@ public:
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);