mirror of
https://github.com/scummvm/scummvm.git
synced 2026-06-20 05:45:29 +00:00
Previously, a C-style cast was used to convert a Common::Array<Plugin *>, populated with pointers to StaticPlugin and DynamicPlugin instances, to a Common::Array<PluginSubclass<T> *>, but PluginSubclass<T> is a *sibling* class to StaticPlugin/DynamicPlugin, so this cast was invalid and the results undefined. The methods for retrieving subclasses of plugins can't be easily changed to just generate an array of temporary wrapper objects that expose an identical API which dereferences to the preferred PluginObject subclass because pointers to these objects are retained by other parts of ScummVM, so the wrappers would needed to be persisted or they would need to just re-expose the underlying Plugin object again. This indicated that a way to solve this problem is to have the callers receive Plugin objects and get the PluginObject from the Plugin by explicitly stating their desired type, in a similar manner to std::get(std::variant), so that the pattern used by this patch to solve the problem. Closes gh-1051.
322 lines
9.2 KiB
C++
322 lines
9.2 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
*/
|
|
|
|
#include "engines/metaengine.h"
|
|
#include "base/plugins.h"
|
|
#include "base/version.h"
|
|
#include "common/events.h"
|
|
#include "common/system.h"
|
|
#include "common/translation.h"
|
|
#include "common/util.h"
|
|
#include "gui/about.h"
|
|
#include "gui/gui-manager.h"
|
|
#include "gui/ThemeEval.h"
|
|
|
|
namespace GUI {
|
|
|
|
enum {
|
|
kScrollStartDelay = 1500,
|
|
kScrollMillisPerPixel = 60
|
|
};
|
|
|
|
// Every Line should start with a letter followed by a digit. Currently those can be
|
|
// (all subject to change)
|
|
// Letter:
|
|
// C, L, R -- set center/left/right alignment
|
|
// A -- ASCII text to replace the next (latin1) line
|
|
// Digit:
|
|
// 0 - 2 -- set a custom color:
|
|
// 0 normal text
|
|
// 1 highlighted text
|
|
// 2 disabled text
|
|
// TODO: Maybe add a tab/indent feature; that is, make it possible to specify
|
|
// an amount by which that line shall be indented (the indent of course would have
|
|
// to be considered while performing any word wrapping, too).
|
|
//
|
|
// TODO: Add different font sizes (for bigger headlines)
|
|
// TODO: Allow color change in the middle of a line...
|
|
|
|
static const char *copyright_text[] = {
|
|
"",
|
|
"C0""Copyright (C) 2001-2017 The ScummVM Team",
|
|
"C0""http://www.scummvm.org",
|
|
"",
|
|
"C0""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 binary.",
|
|
"",
|
|
};
|
|
|
|
static const char *gpl_text[] = {
|
|
"",
|
|
"C0""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.",
|
|
"C0""",
|
|
"C0""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.",
|
|
"",
|
|
"C0""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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.",
|
|
"",
|
|
};
|
|
|
|
#include "gui/credits.h"
|
|
|
|
AboutDialog::AboutDialog()
|
|
: Dialog(10, 20, 300, 174),
|
|
_scrollPos(0), _scrollTime(0), _willClose(false) {
|
|
|
|
reflowLayout();
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < 1; i++)
|
|
_lines.push_back("");
|
|
|
|
Common::String version("C0""ScummVM ");
|
|
version += gScummVMVersion;
|
|
_lines.push_back(version);
|
|
|
|
Common::String date = Common::String::format(_("(built on %s)"), gScummVMBuildDate);
|
|
_lines.push_back("C2" + date);
|
|
|
|
for (i = 0; i < ARRAYSIZE(copyright_text); i++)
|
|
addLine(copyright_text[i]);
|
|
|
|
Common::String features("C1");
|
|
features += _("Features compiled in:");
|
|
addLine(features.c_str());
|
|
Common::String featureList("C0");
|
|
featureList += gScummVMFeatures;
|
|
addLine(featureList.c_str());
|
|
|
|
_lines.push_back("");
|
|
|
|
Common::String engines("C1");
|
|
engines += _("Available engines:");
|
|
addLine(engines.c_str());
|
|
|
|
const PluginList &plugins = EngineMan.getPlugins();
|
|
PluginList::const_iterator iter = plugins.begin();
|
|
for (; iter != plugins.end(); ++iter) {
|
|
Common::String str;
|
|
str = "C0";
|
|
str += (*iter)->getName();
|
|
addLine(str.c_str());
|
|
|
|
str = "C2";
|
|
str += (*iter)->get<MetaEngine>().getOriginalCopyright();
|
|
addLine(str.c_str());
|
|
|
|
//addLine("");
|
|
}
|
|
|
|
for (i = 0; i < ARRAYSIZE(gpl_text); i++)
|
|
addLine(gpl_text[i]);
|
|
|
|
_lines.push_back("");
|
|
|
|
for (i = 0; i < ARRAYSIZE(credits); i++)
|
|
addLine(credits[i]);
|
|
}
|
|
|
|
void AboutDialog::addLine(const char *str) {
|
|
if (*str == 0) {
|
|
_lines.push_back("");
|
|
} else {
|
|
Common::String format(str, 2);
|
|
str += 2;
|
|
|
|
static Common::String asciiStr;
|
|
if (format[0] == 'A') {
|
|
bool useAscii = false;
|
|
#ifdef USE_TRANSLATION
|
|
// We could use TransMan.getCurrentCharset() but rather than compare strings
|
|
// it is easier to use TransMan.getCharsetMapping() (non null in case of non
|
|
// ISO-8859-1 mapping)
|
|
useAscii = (TransMan.getCharsetMapping() != NULL);
|
|
#endif
|
|
if (useAscii)
|
|
asciiStr = str;
|
|
return;
|
|
}
|
|
StringArray wrappedLines;
|
|
if (!asciiStr.empty()) {
|
|
g_gui.getFont().wordWrapText(asciiStr, _w - 2 * _xOff, wrappedLines);
|
|
asciiStr.clear();
|
|
} else
|
|
g_gui.getFont().wordWrapText(str, _w - 2 * _xOff, wrappedLines);
|
|
|
|
for (StringArray::const_iterator i = wrappedLines.begin(); i != wrappedLines.end(); ++i) {
|
|
_lines.push_back(format + *i);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void AboutDialog::open() {
|
|
_scrollTime = g_system->getMillis() + kScrollStartDelay;
|
|
_scrollPos = 0;
|
|
_willClose = false;
|
|
|
|
Dialog::open();
|
|
}
|
|
|
|
void AboutDialog::close() {
|
|
Dialog::close();
|
|
}
|
|
|
|
void AboutDialog::drawDialog() {
|
|
Dialog::drawDialog();
|
|
|
|
setTextDrawableArea(Common::Rect(_x, _y, _x + _w, _y + _h));
|
|
|
|
// Draw text
|
|
// TODO: Add a "fade" effect for the top/bottom text lines
|
|
// TODO: Maybe prerender all of the text into another surface,
|
|
// and then simply compose that over the screen surface
|
|
// in the right way. Should be even faster...
|
|
const int firstLine = _scrollPos / _lineHeight;
|
|
const int lastLine = MIN((_scrollPos + _h) / _lineHeight + 1, (uint32)_lines.size());
|
|
int y = _y + _yOff - (_scrollPos % _lineHeight);
|
|
|
|
for (int line = firstLine; line < lastLine; line++) {
|
|
const char *str = _lines[line].c_str();
|
|
Graphics::TextAlign align = Graphics::kTextAlignCenter;
|
|
ThemeEngine::WidgetStateInfo state = ThemeEngine::kStateEnabled;
|
|
if (*str) {
|
|
switch (str[0]) {
|
|
case 'C':
|
|
align = Graphics::kTextAlignCenter;
|
|
break;
|
|
case 'L':
|
|
align = Graphics::kTextAlignLeft;
|
|
break;
|
|
case 'R':
|
|
align = Graphics::kTextAlignRight;
|
|
break;
|
|
default:
|
|
error("Unknown scroller opcode '%c'", str[0]);
|
|
break;
|
|
}
|
|
switch (str[1]) {
|
|
case '0':
|
|
state = ThemeEngine::kStateEnabled;
|
|
break;
|
|
case '1':
|
|
state = ThemeEngine::kStateHighlight;
|
|
break;
|
|
case '2':
|
|
state = ThemeEngine::kStateDisabled;
|
|
break;
|
|
case '3':
|
|
warning("Need state for color 3");
|
|
// color = g_gui._shadowcolor;
|
|
break;
|
|
case '4':
|
|
warning("Need state for color 4");
|
|
// color = g_gui._bgcolor;
|
|
break;
|
|
default:
|
|
error("Unknown color type '%c'", str[1]);
|
|
}
|
|
str += 2;
|
|
}
|
|
// Trim leading whitespaces if center mode is on
|
|
if (align == Graphics::kTextAlignCenter)
|
|
while (*str && *str == ' ')
|
|
str++;
|
|
|
|
if (*str)
|
|
g_gui.theme()->drawText(Common::Rect(_x + _xOff, y, _x + _w - _xOff, y + g_gui.theme()->getFontHeight()), str, state, align, ThemeEngine::kTextInversionNone, 0, false, ThemeEngine::kFontStyleBold, ThemeEngine::kFontColorNormal, true, _textDrawableArea);
|
|
y += _lineHeight;
|
|
}
|
|
}
|
|
|
|
void AboutDialog::handleTickle() {
|
|
const uint32 t = g_system->getMillis();
|
|
int scrollOffset = ((int)t - (int)_scrollTime) / kScrollMillisPerPixel;
|
|
if (scrollOffset > 0) {
|
|
int modifiers = g_system->getEventManager()->getModifierState();
|
|
|
|
// Scroll faster when shift is pressed
|
|
if (modifiers & Common::KBD_SHIFT)
|
|
scrollOffset *= 4;
|
|
// Reverse scrolling when alt is pressed
|
|
if (modifiers & Common::KBD_ALT)
|
|
scrollOffset *= -1;
|
|
_scrollPos += scrollOffset;
|
|
_scrollTime = t;
|
|
|
|
if (_scrollPos < 0) {
|
|
_scrollPos = 0;
|
|
} else if ((uint32)_scrollPos > _lines.size() * _lineHeight) {
|
|
_scrollPos = 0;
|
|
_scrollTime += kScrollStartDelay;
|
|
}
|
|
drawDialog();
|
|
}
|
|
}
|
|
|
|
void AboutDialog::handleMouseUp(int x, int y, int button, int clickCount) {
|
|
// Close upon any mouse click
|
|
close();
|
|
}
|
|
|
|
void AboutDialog::handleKeyDown(Common::KeyState state) {
|
|
if (state.ascii)
|
|
_willClose = true;
|
|
}
|
|
|
|
void AboutDialog::handleKeyUp(Common::KeyState state) {
|
|
if (state.ascii && _willClose)
|
|
close();
|
|
}
|
|
|
|
void AboutDialog::reflowLayout() {
|
|
Dialog::reflowLayout();
|
|
int i;
|
|
const int screenW = g_system->getOverlayWidth();
|
|
const int screenH = g_system->getOverlayHeight();
|
|
|
|
_xOff = g_gui.xmlEval()->getVar("Globals.About.XOffset", 5);
|
|
_yOff = g_gui.xmlEval()->getVar("Globals.About.YOffset", 5);
|
|
int outerBorder = g_gui.xmlEval()->getVar("Globals.About.OuterBorder");
|
|
|
|
_w = screenW - 2 * outerBorder;
|
|
_h = screenH - 2 * outerBorder;
|
|
|
|
_lineHeight = g_gui.getFontHeight() + 3;
|
|
|
|
// Heuristic to compute 'optimal' dialog width
|
|
int maxW = _w - 2*_xOff;
|
|
_w = 0;
|
|
for (i = 0; i < ARRAYSIZE(credits); i++) {
|
|
int tmp = g_gui.getStringWidth(credits[i]) + 5;
|
|
if (_w < tmp && tmp <= maxW) {
|
|
_w = tmp;
|
|
}
|
|
}
|
|
_w += 2*_xOff;
|
|
|
|
// Center the dialog
|
|
_x = (screenW - _w) / 2;
|
|
_y = (screenH - _h) / 2;
|
|
}
|
|
|
|
} // End of namespace GUI
|