scummvm/engines/saga2/grequest.cpp
2022-10-29 13:41:51 +02:00

443 lines
10 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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 3 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
* aint32 with this program; if not, write to the Free Software
*
*
* Based on the original sources
* Faery Tale II -- The Halls of the Dead
* (c) 1993-1996 The Wyrmkeep Entertainment Co.
*/
#include "saga2/saga2.h"
#include "saga2/grequest.h"
#include "saga2/modal.h"
#include "saga2/mouseimg.h"
namespace Saga2 {
extern gFont *mainFont;
extern vDisplayPage *drawPage;
const int maxLines = 16,
maxButtons = 16,
maxText = 512,
maxButtonText = 128,
buttonWidth = 60;
// This function takes a string which is composed of several
// substrings, each separated by a delimiter character, and
// breaks it up into the individual sub-strings.
int16 SplitString(
char *text,
char *textStart[],
int16 maxStrings,
char delimiter) {
int16 count;
for (count = 0; count < maxStrings;) {
textStart[count++] = text;
if ((text = strchr(text, delimiter)) == nullptr) break;
*text++ = '\0';
}
return count;
}
static void handleRequestEvent(gEvent &ev) {
gWindow *win;
requestInfo *ri;
if (ev.panel && ev.eventType == kEventNewValue && ev.value) {
win = ev.panel->getWindow(); // get the window pointer
ri = win ? (requestInfo *)win->_userData : nullptr;
if (ri) {
ri->running = 0;
ri->result = ev.panel->_id;
}
}
}
/* ===================================================================== *
ModalDialogWindow class: The base class for modal dialog windows
* ===================================================================== */
class ModalDialogWindow : public ModalWindow {
int16 _titleCount;
Point16 _titlePos[maxLines];
char *_titleStrings[maxLines];
char _titleBuf[maxText];
void positionText(
char *windowText,
va_list args,
const Rect16 &textArea);
public:
ModalDialogWindow(const Rect16 &r,
uint16 ident,
AppFunc *cmd,
char *windowText,
va_list args);
ModalDialogWindow(const Rect16 &r,
uint16 ident,
AppFunc *cmd,
char *windowText,
va_list args,
const Rect16 &textArea);
void drawClipped(
gPort &port,
const Point16 &offset,
const Rect16 &r) override;
};
void ModalDialogWindow::positionText(
char *windowText,
va_list args,
const Rect16 &textArea) {
if (windowText) {
int16 i,
yPos,
maxY;
int16 fontHeight = mainFont->height;
// make a copy of the window text string
Common::vsprintf_s(_titleBuf, windowText, args);
// break up the title text string
_titleCount = SplitString(_titleBuf, _titleStrings, maxLines, '\n');
yPos = textArea.y +
((textArea.height - _titleCount * fontHeight) >> 1);
yPos = MAX(yPos, textArea.y);
maxY = textArea.y + textArea.height - fontHeight;
for (i = 0; i < _titleCount; i++, yPos += fontHeight) {
if (yPos < maxY) {
_titlePos[i].y = yPos;
_titlePos[i].x =
textArea.x +
((textArea.width -
TextWidth(mainFont, _titleStrings[i], -1, 0))
>> 1);
} else _titleCount = i;
}
} else _titleCount = 0;
}
ModalDialogWindow::ModalDialogWindow(
const Rect16 &r,
uint16 ident,
AppFunc *cmd,
char *windowText,
va_list args) :
ModalWindow(r, ident, cmd) {
positionText(windowText, args, Rect16(0, 0, r.width, r.height));
}
ModalDialogWindow::ModalDialogWindow(
const Rect16 &r,
uint16 ident,
AppFunc *cmd,
char *windowText,
va_list args,
const Rect16 &textArea) :
ModalWindow(r, ident, cmd) {
positionText(windowText, args, textArea);
}
void ModalDialogWindow::drawClipped(
gPort &port,
const Point16 &offset,
const Rect16 &r) {
if (!_extent.overlap(r)) return;
int16 i;
Point16 origin;
gFont *textFont = mainFont;
Rect16 rect;
SAVE_GPORT_STATE(port);
origin.x = _extent.x - offset.x;
origin.y = _extent.y - offset.y;
rect.x = origin.x;
rect.y = origin.y;
rect.width = _extent.width;
rect.height = _extent.height;
port.setColor(4);
port.frameRect(rect, 2);
rect.expand(-2, -2);
port.setColor(12);
port.fillRect(rect);
port.setFont(textFont);
for (i = 0; i < _titleCount; i++) {
Point16 textPos = origin + _titlePos[i];
port.moveTo(textPos + Point16(-1, -1));
port.setColor(2);
port.drawText(_titleStrings[i], -1);
port.moveTo(textPos + Point16(1, 1));
port.setColor(14);
port.drawText(_titleStrings[i], -1);
port.moveTo(textPos);
port.setColor(8);
port.drawText(_titleStrings[i], -1);
}
ModalWindow::drawClipped(port, offset, r);
}
/* ===================================================================== *
ModalRequestWindow class: A modal request dialog box
* ===================================================================== */
class ModalRequestWindow : public ModalDialogWindow {
char _buttonBuf[maxButtonText];
static Rect16 getTextArea(const Rect16 &r) {
return Rect16(2, 2, r.width - 4, r.height - mainFont->height - 12);
}
public:
ModalRequestWindow(
const Rect16 &r,
uint16 ident,
AppFunc *cmd,
char *windowText,
char *buttonText,
va_list args);
};
ModalRequestWindow::ModalRequestWindow(
const Rect16 &r,
uint16 ident,
AppFunc *cmd,
char *windowText,
char *buttonText,
va_list args) :
ModalDialogWindow(r, ident, cmd, windowText, args, getTextArea(r)) {
int16 i;
int16 xPos;
int16 extraSpace,
intervals;
int16 buttonCount;
char *buttonStrings[maxButtons];
int16 fontHeight = mainFont->height;
Common::strlcpy(_buttonBuf, (buttonText ? buttonText : "_OK"), sizeof(_buttonBuf));
// break up the button text string
buttonCount = SplitString(_buttonBuf, buttonStrings, maxButtons, '|');
extraSpace = r.width - buttonWidth * buttonCount;
intervals = buttonCount * 2 + 1;
xPos = 0;
for (i = 0; i < buttonCount; i++) {
int16 width,
extra;
width = buttonWidth;
if (intervals > 0) {
extra = extraSpace / intervals;
extraSpace -= extra;
intervals--;
xPos += extra;
}
if (intervals > 0) {
extra = extraSpace / intervals;
extraSpace -= extra;
intervals--;
} else extra = 0;
width += extra;
new LabeledButton(*this,
Rect16(xPos,
r.height - fontHeight - 8,
width,
fontHeight + 6),
*mouseCursors[kMouseCloseBx2Image],
*mouseCursors[kMouseCloseBx1Image],
buttonStrings[i],
i,
handleRequestEvent);
xPos += width;
}
}
/* ===================================================================== *
ModalDisplayWindow class: A modal text display window
* ===================================================================== */
class ModalDisplayWindow : public ModalDialogWindow {
public:
ModalDisplayWindow(
const Rect16 &r,
uint16 ident,
AppFunc *cmd,
char *windowText,
va_list args) :
ModalDialogWindow(r, ident, cmd, windowText, args) {
}
void pointerRelease(gPanelMessage &) override;
bool keyStroke(gPanelMessage &) override;
};
void ModalDisplayWindow::pointerRelease(gPanelMessage &) {
requestInfo *ri = (requestInfo *)_userData;
if (ri) ri->running = false;
}
bool ModalDisplayWindow::keyStroke(gPanelMessage &) {
requestInfo *ri = (requestInfo *)_userData;
if (ri) ri->running = false;
return true;
}
/* ===================================================================== *
Modal game dialog functions
* ===================================================================== */
int16 GameDialogA(
char *windowText,
char *buttonText,
int /*resnum*/,
va_list args) {
requestInfo rInfo;
ModalRequestWindow *win;
rInfo.result = -1;
rInfo.running = true;
win = new ModalRequestWindow(
Rect16((drawPage->_size.x - 200) / 2,
(drawPage->_size.y - 100) / 3,
200,
100),
0,
nullptr,
windowText,
buttonText,
args);
if (win == nullptr) {
// REM: perhaps a memory alert of some sort???
error("Unable to open requester window.");
}
win->_userData = &rInfo;
win->open();
EventLoop(rInfo.running, false);
delete win;
return rInfo.result;
}
int16 GameDialog(
char *windowText,
char *buttonText,
int resNum,
...) {
int16 result;
va_list argptr;
va_start(argptr, resNum);
result = GameDialogA(windowText,
buttonText,
resNum,
argptr);
va_end(argptr);
return result;
}
int16 GameDisplayA(
char *windowText,
int /*resnum*/,
va_list args) {
requestInfo rInfo;
ModalDisplayWindow *win;
rInfo.result = -1;
rInfo.running = true;
win = new ModalDisplayWindow(
Rect16((drawPage->_size.x - 200) / 2,
(drawPage->_size.y - 100) / 3,
200,
100),
0,
nullptr,
windowText,
args);
if (win == nullptr) {
// REM: perhaps a memory alert of some sort???
error("Unable to open requester window.");
}
win->_userData = &rInfo;
win->open();
EventLoop(rInfo.running, false);
delete win;
return rInfo.result;
}
int16 GameDisplay(
char *windowText,
int resNum,
...) {
int16 result;
va_list argptr;
va_start(argptr, resNum);
result = GameDisplayA(windowText,
resNum,
argptr);
va_end(argptr);
return result;
}
} // end of namespace Saga2