ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

dialogbox.cpp

Go to the documentation of this file.
00001 /* ResidualVM - A 3D game interpreter
00002  *
00003  * ResidualVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the AUTHORS
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #include "engines/stark/ui/dialogbox.h"
00024 
00025 #include "engines/stark/gfx/driver.h"
00026 #include "engines/stark/gfx/surfacerenderer.h"
00027 #include "engines/stark/gfx/texture.h"
00028 #include "engines/stark/services/services.h"
00029 #include "engines/stark/services/fontprovider.h"
00030 #include "engines/stark/ui/cursor.h"
00031 #include "engines/stark/visual/text.h"
00032 
00033 #include "common/memstream.h"
00034 #include "common/stream.h"
00035 #include "common/winexe_pe.h"
00036 #include "graphics/surface.h"
00037 #include "image/bmp.h"
00038 
00039 
00040 namespace Stark {
00041 
00042 static const uint dialogMaxWidth         = 450;
00043 static const uint dialogHorizontalMargin = 10;
00044 static const uint dialogVerticalMargin   = 20;
00045 static const uint buttonHorizontalMargin = 25;
00046 static const uint buttonVerticalMargin   = 5;
00047 static const Color textColor = Color(0xFF, 0xFF, 0xFF);
00048 
00049 DialogBox::DialogBox(Gfx::Driver *gfx, Cursor *cursor) :
00050         Window(gfx, cursor),
00051         _foregroundTexture(nullptr),
00052         _confirmCallback(nullptr) {
00053 
00054     _surfaceRenderer = gfx->createSurfaceRenderer();
00055 
00056     Graphics::Surface *background = loadBackground();
00057     if (!background) {
00058         // If we were not able to load the background, fallback to dark blue
00059         background = new Graphics::Surface();
00060         background->create(256, 256, Gfx::Driver::getRGBAPixelFormat());
00061 
00062         uint32 blue = background->format.RGBToColor(26, 28, 57);
00063         background->fillRect(Common::Rect(256, 256), blue);
00064     }
00065     _backgroundTexture = gfx->createTexture(background);
00066     _backgroundTexture->setSamplingFilter(Gfx::Texture::kLinear);
00067 
00068     background->free();
00069     delete background;
00070 
00071     _messageVisual = new VisualText(gfx);
00072     _messageVisual->setColor(textColor);
00073     _messageVisual->setTargetWidth(dialogMaxWidth - 2 * dialogHorizontalMargin);
00074     _messageVisual->setAlign(Graphics::kTextAlignCenter);
00075 
00076     _confirmLabelVisual = new VisualText(gfx);
00077     _confirmLabelVisual->setColor(textColor);
00078     _confirmLabelVisual->setTargetWidth(96);
00079 
00080     _cancelLabelVisual = new VisualText(gfx);
00081     _cancelLabelVisual->setColor(textColor);
00082     _cancelLabelVisual->setTargetWidth(96);
00083 }
00084 
00085 DialogBox::~DialogBox() {
00086     close();
00087 
00088     delete _messageVisual;
00089     delete _confirmLabelVisual;
00090     delete _cancelLabelVisual;
00091 
00092     delete _backgroundTexture;
00093 
00094     delete _surfaceRenderer;
00095 }
00096 
00097 void DialogBox::open(const Common::String &message, ConfirmCallback *confirmCallback,
00098         const Common::String &confirmLabel, const Common::String &cancelLabel) {
00099     assert(confirmCallback);
00100 
00101     _visible = true;
00102 
00103     _cursor->setCursorType(Cursor::kDefault);
00104     _cursor->setMouseHint("");
00105 
00106     _messageVisual->setText(message);
00107     _confirmLabelVisual->setText(confirmLabel);
00108     _cancelLabelVisual->setText(cancelLabel);
00109 
00110     _confirmCallback = confirmCallback;
00111 
00112     recomputeLayout();
00113 }
00114 
00115 void DialogBox::close() {
00116     freeForeground();
00117 
00118     delete _confirmCallback;
00119     _confirmCallback = nullptr;
00120 
00121     _visible = false;
00122 }
00123 
00124 void DialogBox::recomputeLayout() {
00125     freeForeground();
00126 
00127     _messageRect = _messageVisual->getRect();
00128 
00129     uint buttonY = dialogVerticalMargin * 2 + _messageRect.height();
00130     uint32 dialogWidth  = _messageRect.width() + 2 * dialogHorizontalMargin;
00131 
00132     // The button size is computed based on the largest label
00133     Common::Rect labelSize = _confirmLabelVisual->getRect();
00134     labelSize.extend(_cancelLabelVisual->getRect());
00135 
00136     _confirmButtonRect = Common::Rect(
00137             labelSize.width() + buttonHorizontalMargin * 2,
00138             labelSize.height() + buttonVerticalMargin * 2);
00139 
00140     _cancelButtonRect = Common::Rect(
00141             labelSize.width() + buttonHorizontalMargin * 2,
00142             labelSize.height() + buttonVerticalMargin * 2);
00143 
00144     uint buttonSpacing;
00145     if (dialogWidth > (uint32)(_confirmButtonRect.width() + _cancelButtonRect.width())) {
00146         buttonSpacing = (dialogWidth - _confirmButtonRect.width() - _cancelButtonRect.width()) / 3;
00147     } else {
00148         buttonSpacing = buttonHorizontalMargin;
00149         dialogWidth = buttonSpacing * 3 + _confirmButtonRect.width() + _cancelButtonRect.width();
00150     }
00151 
00152     _messageRect.translate((dialogWidth - _messageRect.width()) / 2, dialogVerticalMargin);
00153 
00154     _confirmButtonRect.translate(buttonSpacing, buttonY);
00155     _cancelButtonRect.translate(buttonSpacing * 2 + _confirmButtonRect.width(), buttonY);
00156 
00157     uint32 dialogHeight = _confirmButtonRect.bottom + dialogVerticalMargin;
00158 
00159     Graphics::Surface foreground;
00160     foreground.create(dialogWidth, dialogHeight, Gfx::Driver::getRGBAPixelFormat());
00161 
00162     drawBevel(&foreground, Common::Rect(0, 0, foreground.w, foreground.h));
00163 
00164     uint32 buttonColor = foreground.format.RGBToColor(0, 0, 0);
00165     foreground.fillRect(_confirmButtonRect, buttonColor);
00166     foreground.fillRect(_cancelButtonRect, buttonColor);
00167 
00168     drawBevel(&foreground, _confirmButtonRect);
00169     drawBevel(&foreground, _cancelButtonRect);
00170 
00171     _foregroundTexture = _gfx->createTexture(&foreground);
00172     _foregroundTexture->setSamplingFilter(Gfx::Texture::kLinear);
00173 
00174     foreground.free();
00175 
00176     Common::Point screenCenter(Gfx::Driver::kOriginalWidth / 2, Gfx::Driver::kOriginalHeight / 2);
00177     _position = Common::Rect::center(screenCenter.x, screenCenter.y,
00178                                      _foregroundTexture->width(), _foregroundTexture->height());
00179 }
00180 
00181 void DialogBox::freeForeground() {
00182     delete _foregroundTexture;
00183     _foregroundTexture = nullptr;
00184 
00185     if (_messageVisual) {
00186         _messageVisual->resetTexture();
00187     }
00188 
00189     if (_confirmLabelVisual) {
00190         _confirmLabelVisual->resetTexture();
00191     }
00192 
00193     if (_cancelLabelVisual) {
00194         _cancelLabelVisual->resetTexture();
00195     }
00196 }
00197 
00198 void DialogBox::onScreenChanged() {
00199     recomputeLayout();
00200 }
00201 
00202 void DialogBox::onClick(const Common::Point &pos) {
00203     if (_cancelButtonRect.contains(pos)) {
00204         close();
00205     } else if (_confirmButtonRect.contains(pos)) {
00206         assert(_confirmCallback);
00207 
00208         (*_confirmCallback)();
00209         close();
00210     }
00211 }
00212 
00213 void DialogBox::onKeyPress(const Common::KeyState &keyState) {
00214     if (keyState.keycode == Common::KEYCODE_ESCAPE) {
00215         close();
00216     }
00217 }
00218 
00219 Graphics::Surface *DialogBox::loadBackground() {
00220     Common::PEResources executable;
00221     if (!executable.loadFromEXE("game.exe") && !executable.loadFromEXE("game.dll")) {
00222         warning("Unable to load 'game.exe' to read the modal dialog background image");
00223         return nullptr;
00224     }
00225 
00226     Common::SeekableReadStream *stream = executable.getResource(Common::kPEBitmap, 147);
00227     if (!stream) {
00228         warning("Unable to find the modal dialog background bitmap in 'game.exe'");
00229         return nullptr;
00230     }
00231 
00232     const uint32 bitmapWithHeaderLen = stream->size() + 14;
00233     byte *bitmapWithHeader = new byte[bitmapWithHeaderLen];
00234 
00235     Common::MemoryWriteStream bitmapWithHeaderWriteStream(bitmapWithHeader, bitmapWithHeaderLen);
00236     bitmapWithHeaderWriteStream.write("BM", 2);
00237     bitmapWithHeaderWriteStream.writeUint32LE(bitmapWithHeaderLen); // Filesize
00238     bitmapWithHeaderWriteStream.writeUint32LE(0);                   // res1 & res2
00239     bitmapWithHeaderWriteStream.writeUint32LE(0x436);               // image offset
00240 
00241     stream->read(bitmapWithHeader + 14, stream->size());
00242     delete stream;
00243 
00244     Common::MemoryReadStream bitmapWithHeaderReadStream(bitmapWithHeader, bitmapWithHeaderLen);
00245 
00246     Image::BitmapDecoder decoder;
00247     if (!decoder.loadStream(bitmapWithHeaderReadStream)) {
00248         warning("Unable decode the modal dialog background bitmap from 'game.exe'");
00249         return nullptr;
00250     }
00251 
00252     delete[] bitmapWithHeader;
00253 
00254     return decoder.getSurface()->convertTo(Gfx::Driver::getRGBAPixelFormat(), decoder.getPalette());
00255 }
00256 
00257 void DialogBox::onRender() {
00258     uint32 backgroundRepeatX = ceil(_foregroundTexture->width() / (float)_backgroundTexture->width());
00259     for (uint i = 0; i < backgroundRepeatX; i++) {
00260         _surfaceRenderer->render(_backgroundTexture, Common::Point(i * _backgroundTexture->width(), 0));
00261     }
00262 
00263     _surfaceRenderer->render(_foregroundTexture, Common::Point(0, 0));
00264 
00265     _messageVisual->render(Common::Point(_messageRect.left, _messageRect.top));
00266 
00267     Common::Rect confirmLabelRect = centerRect(_confirmButtonRect, _confirmLabelVisual->getRect());
00268     Common::Rect cancelLabelRect = centerRect(_cancelButtonRect, _cancelLabelVisual->getRect());
00269 
00270     _confirmLabelVisual->render(Common::Point(confirmLabelRect.left, confirmLabelRect.top));
00271     _cancelLabelVisual->render(Common::Point(cancelLabelRect.left, cancelLabelRect.top));
00272 }
00273 
00274 void DialogBox::drawBevel(Graphics::Surface *surface, const Common::Rect &rect) {
00275     uint32 topColor1    = surface->format.RGBToColor(191, 191, 191);
00276     uint32 topColor2    = surface->format.RGBToColor(159, 159, 159);
00277     uint32 bottomColor1 = surface->format.RGBToColor(64, 64, 64);
00278     uint32 bottomColor2 = surface->format.RGBToColor(96, 96, 96);
00279 
00280     // Top
00281     surface->drawLine(rect.left,     rect.top,     rect.right - 1, rect.top,     topColor1);
00282     surface->drawLine(rect.left + 1, rect.top + 1, rect.right - 2, rect.top + 1, topColor2);
00283 
00284     // Left
00285     surface->drawLine(rect.left,     rect.top,     rect.left,     rect.bottom - 1, topColor1);
00286     surface->drawLine(rect.left + 1, rect.top + 1, rect.left + 1, rect.bottom - 2, topColor2);
00287 
00288     // Right
00289     surface->drawLine(rect.right - 1, rect.top,     rect.right - 1, rect.bottom - 1, bottomColor2);
00290     surface->drawLine(rect.right - 2, rect.top + 1, rect.right - 2, rect.bottom - 2, bottomColor1);
00291 
00292     // Bottom
00293     surface->drawLine(rect.left,     rect.bottom - 1, rect.right - 1, rect.bottom - 1, bottomColor2);
00294     surface->drawLine(rect.left + 1, rect.bottom - 2, rect.right - 2, rect.bottom - 2, bottomColor1);
00295 }
00296 
00297 Common::Rect DialogBox::centerRect(const Common::Rect &container, const Common::Rect &size) {
00298     Common::Point center(
00299             (container.left + container.right) / 2,
00300             (container.top + container.bottom) / 2);
00301 
00302     return Common::Rect::center(
00303             center.x, center.y,
00304             size.width(), size.height());
00305 }
00306 
00307 } // End of namespace Stark


Generated on Sat Mar 23 2019 05:01:31 for ResidualVM by doxygen 1.7.1
curved edge   curved edge