Initial commit
This commit is contained in:
252
engines/bagel/spacebar/boflib/app.cpp
Normal file
252
engines/bagel/spacebar/boflib/app.cpp
Normal file
@@ -0,0 +1,252 @@
|
||||
/* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "graphics/framelimiter.h"
|
||||
#include "graphics/palette.h"
|
||||
#include "graphics/paletteman.h"
|
||||
#include "video/smk_decoder.h"
|
||||
|
||||
#include "bagel/spacebar/baglib/bagel.h"
|
||||
#include "bagel/spacebar/boflib/debug.h"
|
||||
#include "bagel/spacebar/boflib/app.h"
|
||||
#include "bagel/spacebar/boflib/timer.h"
|
||||
#include "bagel/spacebar/boflib/gfx/text.h"
|
||||
#include "bagel/boflib/sound.h"
|
||||
#include "bagel/bagel.h"
|
||||
|
||||
namespace Bagel {
|
||||
namespace SpaceBar {
|
||||
|
||||
#define DEBUG_LOG "DEBUG.LOG"
|
||||
#define DEBUG_INI "BOFFO.INI"
|
||||
|
||||
#define BOFDISP 0
|
||||
|
||||
CBofApp *CBofApp::_pBofApp;
|
||||
|
||||
CBofApp::CBofApp() {
|
||||
StartupCode();
|
||||
}
|
||||
|
||||
CBofApp::CBofApp(const char *pszAppName) {
|
||||
StartupCode();
|
||||
|
||||
setAppName(pszAppName);
|
||||
}
|
||||
|
||||
CBofApp::~CBofApp() {
|
||||
ShutDownCode();
|
||||
|
||||
_szAppName[0] = '\0';
|
||||
_pMainWnd = nullptr;
|
||||
_pPalette = nullptr;
|
||||
_pBofApp = nullptr;
|
||||
}
|
||||
|
||||
|
||||
void CBofApp::StartupCode() {
|
||||
_pBofApp = this;
|
||||
|
||||
// Open the Boffo debug options file (BOFFO.INI)
|
||||
g_pDebugOptions = new CBofDebugOptions(DEBUG_INI);
|
||||
g_pDebugOptions->readSetting("DebugOptions", "MainLoops", &_nIterations, DEFAULT_MAINLOOPS);
|
||||
|
||||
//
|
||||
// Initialize the boffo libraries
|
||||
//
|
||||
|
||||
// Init the Window library
|
||||
CBofWindow::initialize();
|
||||
|
||||
// Init the text library
|
||||
CBofText::initialize();
|
||||
}
|
||||
|
||||
|
||||
void CBofApp::ShutDownCode() {
|
||||
// Un-initialize the text library
|
||||
CBofText::shutdown();
|
||||
|
||||
// Shut down the Window library
|
||||
CBofWindow::shutdown();
|
||||
|
||||
// Kill any shared palette
|
||||
CBofPalette::setSharedPalette(nullptr);
|
||||
|
||||
if (g_pDebugOptions != nullptr) {
|
||||
delete g_pDebugOptions;
|
||||
g_pDebugOptions = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ErrorCode CBofApp::preInit() {
|
||||
if ((_pPalette == nullptr) && (_pDefPalette == nullptr)) {
|
||||
_pDefPalette = new CBofPalette();
|
||||
_pDefPalette->createDefault();
|
||||
setPalette(_pDefPalette);
|
||||
}
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
|
||||
ErrorCode CBofApp::initialize() {
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
|
||||
ErrorCode CBofApp::runApp() {
|
||||
int nCount = _nIterations;
|
||||
|
||||
// Acquire and dispatch messages until we need to quit, or too many errors
|
||||
|
||||
Graphics::FrameLimiter limiter(g_system, 60, false);
|
||||
while (!g_engine->shouldQuit() && CBofError::getErrorCount() < MAX_ERRORS) {
|
||||
// Support for playing videos via the console
|
||||
if (_consoleVideo && _consoleVideo->isPlaying()) {
|
||||
if (_consoleVideo->needsUpdate()) {
|
||||
const Graphics::Surface *s = _consoleVideo->decodeNextFrame();
|
||||
Graphics::Palette pal(_consoleVideo->getPalette(), 256);
|
||||
g_engine->getScreen()->blitFrom(*s, Common::Point(0, 0), &pal);
|
||||
}
|
||||
|
||||
limiter.delayBeforeSwap();
|
||||
g_engine->getScreen()->update();
|
||||
limiter.startFrame();
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
delete _consoleVideo;
|
||||
_consoleVideo = nullptr;
|
||||
|
||||
// Handle sounds and timers
|
||||
CBofSound::audioTask();
|
||||
CBofTimer::handleTimers();
|
||||
|
||||
if (nCount < 0) {
|
||||
nCount++;
|
||||
if (nCount == 0)
|
||||
nCount = 1;
|
||||
|
||||
} else {
|
||||
for (int i = 0; i < nCount; i++) {
|
||||
// Give each window it's own main loop (sort-of)
|
||||
CBofWindow *pWindow = CBofWindow::getWindowList();
|
||||
while (pWindow != nullptr) {
|
||||
if (shouldQuit())
|
||||
return ERR_NONE;
|
||||
|
||||
if (pWindow->isCreated()) {
|
||||
pWindow->onMainLoop();
|
||||
}
|
||||
|
||||
pWindow = (CBofWindow *)pWindow->getNext();
|
||||
}
|
||||
}
|
||||
|
||||
nCount = _nIterations;
|
||||
}
|
||||
|
||||
// Handle events
|
||||
_pMainWnd->handleEvents();
|
||||
|
||||
limiter.delayBeforeSwap();
|
||||
g_engine->getScreen()->update();
|
||||
limiter.startFrame();
|
||||
}
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
|
||||
ErrorCode CBofApp::shutdown() {
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
|
||||
void CBofApp::postShutDown() {
|
||||
delete _pWindow;
|
||||
_pWindow = nullptr;
|
||||
|
||||
// No more palettes
|
||||
_pPalette = nullptr;
|
||||
|
||||
delete _pDefPalette;
|
||||
_pDefPalette = nullptr;
|
||||
}
|
||||
|
||||
void CBofApp::setPalette(CBofPalette *pPalette) {
|
||||
_pPalette = pPalette;
|
||||
|
||||
if (pPalette != nullptr) {
|
||||
if (g_system->getScreenFormat().bytesPerPixel == 1) {
|
||||
const auto &pal = pPalette->getPalette();
|
||||
g_system->getPaletteManager()->setPalette(pal._data, 0, pal._numColors);
|
||||
}
|
||||
|
||||
} else {
|
||||
// Use default palette
|
||||
_pPalette = _pDefPalette;
|
||||
}
|
||||
}
|
||||
|
||||
void CBofApp::addCursor(CBofCursor &cCursor) {
|
||||
_cCursorList.addToTail(cCursor);
|
||||
}
|
||||
|
||||
void CBofApp::delCursor(int nIndex) {
|
||||
_cCursorList.remove(nIndex);
|
||||
}
|
||||
|
||||
bool CBofApp::consolePlayVideo(const Common::Path &path) {
|
||||
delete _consoleVideo;
|
||||
|
||||
_consoleVideo = new Video::SmackerDecoder();
|
||||
_consoleVideo->setSoundType(Audio::Mixer::kSFXSoundType);
|
||||
if (_consoleVideo->loadFile(path)) {
|
||||
_consoleVideo->start();
|
||||
return true;
|
||||
|
||||
} else {
|
||||
delete _consoleVideo;
|
||||
_consoleVideo = nullptr;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Global routines
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CBofPoint getMousePos() {
|
||||
return CBofWindow::getMousePos();
|
||||
}
|
||||
|
||||
|
||||
void bofMessageBox(const char *pszTitle, const char *pszMessage) {
|
||||
Common::String msg = Common::String::format("%s - %s", pszTitle, pszMessage);
|
||||
g_engine->errorDialog(msg.c_str());
|
||||
}
|
||||
|
||||
} // namespace SpaceBar
|
||||
} // namespace Bagel
|
||||
165
engines/bagel/spacebar/boflib/app.h
Normal file
165
engines/bagel/spacebar/boflib/app.h
Normal file
@@ -0,0 +1,165 @@
|
||||
|
||||
/* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BAGEL_BOFLIB_APP_H
|
||||
#define BAGEL_BOFLIB_APP_H
|
||||
|
||||
#include "video/video_decoder.h"
|
||||
#include "bagel/spacebar/boflib/gui/window.h"
|
||||
#include "bagel/spacebar/boflib/gfx/cursor.h"
|
||||
#include "bagel/boflib/error.h"
|
||||
#include "bagel/spacebar/boflib/list.h"
|
||||
|
||||
namespace Bagel {
|
||||
namespace SpaceBar {
|
||||
|
||||
#define MAX_APP_NAME 128
|
||||
#define DEFAULT_MAINLOOPS 1
|
||||
#define kReallyFastPPC 50
|
||||
#define kReallySlowPPC 200
|
||||
|
||||
class CBofApp : public CBofError {
|
||||
private:
|
||||
CBofWindow *_pWindow = nullptr;
|
||||
CBofWindow *_captureControl = nullptr;
|
||||
CBofWindow *_focusControl = nullptr;
|
||||
Video::VideoDecoder *_consoleVideo = nullptr;
|
||||
|
||||
protected:
|
||||
void StartupCode();
|
||||
void ShutDownCode();
|
||||
|
||||
char _szAppName[MAX_APP_NAME] = { 0 };
|
||||
CBofList<CBofCursor> _cCursorList;
|
||||
CBofCursor _cDefaultCursor;
|
||||
|
||||
CBofWindow *_pMainWnd = nullptr;
|
||||
CBofPalette *_pPalette = nullptr;
|
||||
CBofPalette *_pDefPalette = nullptr;
|
||||
int _nScreenDX = 0;
|
||||
int _nScreenDY = 0;
|
||||
int _nColorDepth = 0;
|
||||
|
||||
int _nIterations = DEFAULT_MAINLOOPS;
|
||||
|
||||
static CBofApp *_pBofApp;
|
||||
|
||||
virtual bool shouldQuit() const = 0;
|
||||
|
||||
public:
|
||||
CBofApp();
|
||||
CBofApp(const char *pszAppName);
|
||||
virtual ~CBofApp();
|
||||
|
||||
ErrorCode preInit();
|
||||
void postShutDown();
|
||||
|
||||
// These functions can be overridden by the child class
|
||||
virtual ErrorCode initialize();
|
||||
virtual ErrorCode runApp();
|
||||
virtual ErrorCode shutdown();
|
||||
|
||||
virtual void setAppName(const char *pszNewAppName) {
|
||||
Common::strcpy_s(_szAppName, pszNewAppName);
|
||||
}
|
||||
|
||||
const char *getAppName() const {
|
||||
return (const char *)_szAppName;
|
||||
}
|
||||
|
||||
void setMainWindow(CBofWindow *pWnd) {
|
||||
_pMainWnd = pWnd;
|
||||
}
|
||||
CBofWindow *getMainWindow() const {
|
||||
return _pMainWnd;
|
||||
}
|
||||
|
||||
CBofWindow *getActualWindow() const {
|
||||
return _pWindow;
|
||||
}
|
||||
|
||||
void setPalette(CBofPalette *pPalette);
|
||||
|
||||
CBofPalette *getPalette() const {
|
||||
return _pPalette;
|
||||
}
|
||||
|
||||
int screenWidth() const {
|
||||
return _nScreenDX;
|
||||
}
|
||||
int screenHeight() const {
|
||||
return _nScreenDY;
|
||||
}
|
||||
int screenDepth() const {
|
||||
return _nColorDepth;
|
||||
}
|
||||
|
||||
CBofCursor getDefaultCursor() const {
|
||||
return _cDefaultCursor;
|
||||
}
|
||||
void setDefaultCursor(CBofCursor &cCursor) {
|
||||
_cDefaultCursor = cCursor;
|
||||
}
|
||||
|
||||
void addCursor(CBofCursor &cCursor);
|
||||
void delCursor(int nIndex);
|
||||
|
||||
CBofCursor getCursor(int nIndex) {
|
||||
return _cCursorList[nIndex];
|
||||
}
|
||||
int getNumberOfCursors() const {
|
||||
return _cCursorList.getCount();
|
||||
}
|
||||
|
||||
void setCaptureControl(CBofWindow *ctl) {
|
||||
_captureControl = ctl;
|
||||
}
|
||||
CBofWindow *getCaptureControl() const {
|
||||
return _captureControl;
|
||||
}
|
||||
void setFocusControl(CBofWindow *ctl) {
|
||||
_focusControl = ctl;
|
||||
}
|
||||
CBofWindow *getFocusControl() const {
|
||||
return _focusControl;
|
||||
}
|
||||
bool consolePlayVideo(const Common::Path &path);
|
||||
|
||||
static uint32 getMachineSpeed() {
|
||||
return kReallyFastPPC;
|
||||
}
|
||||
|
||||
static CBofApp *getApp() {
|
||||
return _pBofApp;
|
||||
}
|
||||
};
|
||||
|
||||
// Global routines
|
||||
//
|
||||
void bofMessageBox(const char *pszTitle, const char *pszMessage);
|
||||
|
||||
CBofPoint getMousePos();
|
||||
|
||||
} // namespace SpaceBar
|
||||
} // namespace Bagel
|
||||
|
||||
#endif
|
||||
57
engines/bagel/spacebar/boflib/array.h
Normal file
57
engines/bagel/spacebar/boflib/array.h
Normal file
@@ -0,0 +1,57 @@
|
||||
|
||||
/* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BAGEL_BOFLIB_ARRAY_H
|
||||
#define BAGEL_BOFLIB_ARRAY_H
|
||||
|
||||
#include "common/array.h"
|
||||
|
||||
namespace Bagel {
|
||||
namespace SpaceBar {
|
||||
|
||||
template<class T>
|
||||
class Array : public Common::Array<T> {
|
||||
public:
|
||||
int indexOf(T t) {
|
||||
for (int i = 0; i < (int)this->size(); ++i) {
|
||||
if (this->operator[](i) == t)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool contains(T t) const {
|
||||
return this->indexOf(t) != -1;
|
||||
}
|
||||
|
||||
void remove(T t) {
|
||||
int idx = this->indexOf(t);
|
||||
if (idx != -1)
|
||||
this->remove_at(idx);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace SpaceBar
|
||||
} // namespace Bagel
|
||||
|
||||
#endif
|
||||
132
engines/bagel/spacebar/boflib/crc.cpp
Normal file
132
engines/bagel/spacebar/boflib/crc.cpp
Normal file
@@ -0,0 +1,132 @@
|
||||
/* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "bagel/spacebar/boflib/crc.h"
|
||||
|
||||
namespace Bagel {
|
||||
namespace SpaceBar {
|
||||
|
||||
static const uint16 crc32tabLo[256] = {
|
||||
0x0000, 0x3096, 0x612c, 0x51ba, 0xc419, 0xf48f, 0xa535, 0x95a3,
|
||||
0x8832, 0xb8a4, 0xe91e, 0xd988, 0x4c2b, 0x7cbd, 0x2d07, 0x1d91,
|
||||
0x1064, 0x20f2, 0x7148, 0x41de, 0xd47d, 0xe4eb, 0xb551, 0x85c7,
|
||||
0x9856, 0xa8c0, 0xf97a, 0xc9ec, 0x5c4f, 0x6cd9, 0x3d63, 0x0df5,
|
||||
0x20c8, 0x105e, 0x41e4, 0x7172, 0xe4d1, 0xd447, 0x85fd, 0xb56b,
|
||||
0xa8fa, 0x986c, 0xc9d6, 0xf940, 0x6ce3, 0x5c75, 0x0dcf, 0x3d59,
|
||||
0x30ac, 0x003a, 0x5180, 0x6116, 0xf4b5, 0xc423, 0x9599, 0xa50f,
|
||||
0xb89e, 0x8808, 0xd9b2, 0xe924, 0x7c87, 0x4c11, 0x1dab, 0x2d3d,
|
||||
0x4190, 0x7106, 0x20bc, 0x102a, 0x8589, 0xb51f, 0xe4a5, 0xd433,
|
||||
0xc9a2, 0xf934, 0xa88e, 0x9818, 0x0dbb, 0x3d2d, 0x6c97, 0x5c01,
|
||||
0x51f4, 0x6162, 0x30d8, 0x004e, 0x95ed, 0xa57b, 0xf4c1, 0xc457,
|
||||
0xd9c6, 0xe950, 0xb8ea, 0x887c, 0x1ddf, 0x2d49, 0x7cf3, 0x4c65,
|
||||
0x6158, 0x51ce, 0x0074, 0x30e2, 0xa541, 0x95d7, 0xc46d, 0xf4fb,
|
||||
0xe96a, 0xd9fc, 0x8846, 0xb8d0, 0x2d73, 0x1de5, 0x4c5f, 0x7cc9,
|
||||
0x713c, 0x41aa, 0x1010, 0x2086, 0xb525, 0x85b3, 0xd409, 0xe49f,
|
||||
0xf90e, 0xc998, 0x9822, 0xa8b4, 0x3d17, 0x0d81, 0x5c3b, 0x6cad,
|
||||
0x8320, 0xb3b6, 0xe20c, 0xd29a, 0x4739, 0x77af, 0x2615, 0x1683,
|
||||
0x0b12, 0x3b84, 0x6a3e, 0x5aa8, 0xcf0b, 0xff9d, 0xae27, 0x9eb1,
|
||||
0x9344, 0xa3d2, 0xf268, 0xc2fe, 0x575d, 0x67cb, 0x3671, 0x06e7,
|
||||
0x1b76, 0x2be0, 0x7a5a, 0x4acc, 0xdf6f, 0xeff9, 0xbe43, 0x8ed5,
|
||||
0xa3e8, 0x937e, 0xc2c4, 0xf252, 0x67f1, 0x5767, 0x06dd, 0x364b,
|
||||
0x2bda, 0x1b4c, 0x4af6, 0x7a60, 0xefc3, 0xdf55, 0x8eef, 0xbe79,
|
||||
0xb38c, 0x831a, 0xd2a0, 0xe236, 0x7795, 0x4703, 0x16b9, 0x262f,
|
||||
0x3bbe, 0x0b28, 0x5a92, 0x6a04, 0xffa7, 0xcf31, 0x9e8b, 0xae1d,
|
||||
0xc2b0, 0xf226, 0xa39c, 0x930a, 0x06a9, 0x363f, 0x6785, 0x5713,
|
||||
0x4a82, 0x7a14, 0x2bae, 0x1b38, 0x8e9b, 0xbe0d, 0xefb7, 0xdf21,
|
||||
0xd2d4, 0xe242, 0xb3f8, 0x836e, 0x16cd, 0x265b, 0x77e1, 0x4777,
|
||||
0x5ae6, 0x6a70, 0x3bca, 0x0b5c, 0x9eff, 0xae69, 0xffd3, 0xcf45,
|
||||
0xe278, 0xd2ee, 0x8354, 0xb3c2, 0x2661, 0x16f7, 0x474d, 0x77db,
|
||||
0x6a4a, 0x5adc, 0x0b66, 0x3bf0, 0xae53, 0x9ec5, 0xcf7f, 0xffe9,
|
||||
0xf21c, 0xc28a, 0x9330, 0xa3a6, 0x3605, 0x0693, 0x5729, 0x67bf,
|
||||
0x7a2e, 0x4ab8, 0x1b02, 0x2b94, 0xbe37, 0x8ea1, 0xdf1b, 0xef8d
|
||||
};
|
||||
|
||||
static const uint16 crc32tabHi[256] = {
|
||||
0x0000, 0x7707, 0xee0e, 0x9909, 0x076d, 0x706a, 0xe963, 0x9e64,
|
||||
0x0edb, 0x79dc, 0xe0d5, 0x97d2, 0x09b6, 0x7eb1, 0xe7b8, 0x90bf,
|
||||
0x1db7, 0x6ab0, 0xf3b9, 0x84be, 0x1ada, 0x6ddd, 0xf4d4, 0x83d3,
|
||||
0x136c, 0x646b, 0xfd62, 0x8a65, 0x1401, 0x6306, 0xfa0f, 0x8d08,
|
||||
0x3b6e, 0x4c69, 0xd560, 0xa267, 0x3c03, 0x4b04, 0xd20d, 0xa50a,
|
||||
0x35b5, 0x42b2, 0xdbbb, 0xacbc, 0x32d8, 0x45df, 0xdcd6, 0xabd1,
|
||||
0x26d9, 0x51de, 0xc8d7, 0xbfd0, 0x21b4, 0x56b3, 0xcfba, 0xb8bd,
|
||||
0x2802, 0x5f05, 0xc60c, 0xb10b, 0x2f6f, 0x5868, 0xc161, 0xb666,
|
||||
0x76dc, 0x01db, 0x98d2, 0xefd5, 0x71b1, 0x06b6, 0x9fbf, 0xe8b8,
|
||||
0x7807, 0x0f00, 0x9609, 0xe10e, 0x7f6a, 0x086d, 0x9164, 0xe663,
|
||||
0x6b6b, 0x1c6c, 0x8565, 0xf262, 0x6c06, 0x1b01, 0x8208, 0xf50f,
|
||||
0x65b0, 0x12b7, 0x8bbe, 0xfcb9, 0x62dd, 0x15da, 0x8cd3, 0xfbd4,
|
||||
0x4db2, 0x3ab5, 0xa3bc, 0xd4bb, 0x4adf, 0x3dd8, 0xa4d1, 0xd3d6,
|
||||
0x4369, 0x346e, 0xad67, 0xda60, 0x4404, 0x3303, 0xaa0a, 0xdd0d,
|
||||
0x5005, 0x2702, 0xbe0b, 0xc90c, 0x5768, 0x206f, 0xb966, 0xce61,
|
||||
0x5ede, 0x29d9, 0xb0d0, 0xc7d7, 0x59b3, 0x2eb4, 0xb7bd, 0xc0ba,
|
||||
0xedb8, 0x9abf, 0x03b6, 0x74b1, 0xead5, 0x9dd2, 0x04db, 0x73dc,
|
||||
0xe363, 0x9464, 0x0d6d, 0x7a6a, 0xe40e, 0x9309, 0x0a00, 0x7d07,
|
||||
0xf00f, 0x8708, 0x1e01, 0x6906, 0xf762, 0x8065, 0x196c, 0x6e6b,
|
||||
0xfed4, 0x89d3, 0x10da, 0x67dd, 0xf9b9, 0x8ebe, 0x17b7, 0x60b0,
|
||||
0xd6d6, 0xa1d1, 0x38d8, 0x4fdf, 0xd1bb, 0xa6bc, 0x3fb5, 0x48b2,
|
||||
0xd80d, 0xaf0a, 0x3603, 0x4104, 0xdf60, 0xa867, 0x316e, 0x4669,
|
||||
0xcb61, 0xbc66, 0x256f, 0x5268, 0xcc0c, 0xbb0b, 0x2202, 0x5505,
|
||||
0xc5ba, 0xb2bd, 0x2bb4, 0x5cb3, 0xc2d7, 0xb5d0, 0x2cd9, 0x5bde,
|
||||
0x9b64, 0xec63, 0x756a, 0x026d, 0x9c09, 0xeb0e, 0x7207, 0x0500,
|
||||
0x95bf, 0xe2b8, 0x7bb1, 0x0cb6, 0x92d2, 0xe5d5, 0x7cdc, 0x0bdb,
|
||||
0x86d3, 0xf1d4, 0x68dd, 0x1fda, 0x81be, 0xf6b9, 0x6fb0, 0x18b7,
|
||||
0x8808, 0xff0f, 0x6606, 0x1101, 0x8f65, 0xf862, 0x616b, 0x166c,
|
||||
0xa00a, 0xd70d, 0x4e04, 0x3903, 0xa767, 0xd060, 0x4969, 0x3e6e,
|
||||
0xaed1, 0xd9d6, 0x40df, 0x37d8, 0xa9bc, 0xdebb, 0x47b2, 0x30b5,
|
||||
0xbdbd, 0xcaba, 0x53b3, 0x24b4, 0xbad0, 0xcdd7, 0x54de, 0x23d9,
|
||||
0xb366, 0xc461, 0x5d68, 0x2a6f, 0xb40b, 0xc30c, 0x5a05, 0x2d02
|
||||
};
|
||||
|
||||
uint32 calculateCRC(const void *pBuffer, int32 lBufLen, uint32 lCrcValue) {
|
||||
assert(pBuffer != nullptr);
|
||||
assert(lBufLen > 0);
|
||||
|
||||
const byte *p = (const byte *)pBuffer;
|
||||
int32 i = -1;
|
||||
while (++i < lBufLen) {
|
||||
|
||||
byte c = (byte)(*p ^ (byte)lCrcValue);
|
||||
lCrcValue = (lCrcValue >> 8) ^ crc32tabLo[c] ^ ((uint32)crc32tabHi[c] << 16);
|
||||
|
||||
p++;
|
||||
}
|
||||
|
||||
return lCrcValue;
|
||||
}
|
||||
|
||||
uint32 calculateCRC(const int32 *pBuffer, int32 lBufLen, uint32 lCrcValue) {
|
||||
assert(pBuffer != nullptr);
|
||||
assert(lBufLen > 0);
|
||||
|
||||
const int32 *p = pBuffer;
|
||||
for (int i = 0; i < lBufLen; ++i) {
|
||||
uint32 val = *(const uint32 *)p++;
|
||||
|
||||
for (int j = 0; j < 4; ++j, val >>= 8) {
|
||||
byte c = (byte)((val & 0xff) ^ (byte)lCrcValue);
|
||||
lCrcValue = (lCrcValue >> 8) ^ crc32tabLo[c] ^ ((uint32)crc32tabHi[c] << 16);
|
||||
}
|
||||
}
|
||||
|
||||
return lCrcValue;
|
||||
}
|
||||
|
||||
} // namespace SpaceBar
|
||||
} // namespace Bagel
|
||||
44
engines/bagel/spacebar/boflib/crc.h
Normal file
44
engines/bagel/spacebar/boflib/crc.h
Normal file
@@ -0,0 +1,44 @@
|
||||
|
||||
/* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BAGEL_BOFLIB_CRC_H
|
||||
#define BAGEL_BOFLIB_CRC_H
|
||||
|
||||
#include "bagel/boflib/stdinc.h"
|
||||
|
||||
namespace Bagel {
|
||||
namespace SpaceBar {
|
||||
|
||||
/**
|
||||
* Calculates the CRC (Cyclic Redundancy Check) for a buffer
|
||||
* @param pBuffer Pointer to buffer
|
||||
* @param lBufLen Length of this buffer
|
||||
* @param lCrcValue Previous CRC value (if running CRC)
|
||||
* @return New CRC value
|
||||
*/
|
||||
extern uint32 calculateCRC(const void *pBuffer, int32 lBufLen, uint32 lCrcValue = 0);
|
||||
extern uint32 calculateCRC(const int32 *pBuffer, int32 lBufLen, uint32 lCrcValue = 0);
|
||||
|
||||
} // namespace SpaceBar
|
||||
} // namespace Bagel
|
||||
|
||||
#endif
|
||||
820
engines/bagel/spacebar/boflib/dat_file.cpp
Normal file
820
engines/bagel/spacebar/boflib/dat_file.cpp
Normal file
@@ -0,0 +1,820 @@
|
||||
/* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "bagel/spacebar/boflib/dat_file.h"
|
||||
#include "bagel/spacebar/boflib/crc.h"
|
||||
#include "bagel/spacebar/boflib/debug.h"
|
||||
#include "bagel/boflib/log.h"
|
||||
#include "bagel/boflib/misc.h"
|
||||
#include "bagel/boflib/stdinc.h"
|
||||
#include "bagel/boflib/file_functions.h"
|
||||
|
||||
namespace Bagel {
|
||||
namespace SpaceBar {
|
||||
|
||||
// Local prototypes
|
||||
static uint32 CreateHashCode(const byte *);
|
||||
|
||||
void HeaderRec::synchronize(Common::Serializer &s) {
|
||||
s.syncAsSint32LE(_lOffset);
|
||||
s.syncAsSint32LE(_lLength);
|
||||
s.syncAsUint32LE(_lCrc);
|
||||
s.syncAsUint32LE(_lKey);
|
||||
}
|
||||
|
||||
void HeadInfo::synchronize(Common::Serializer &s) {
|
||||
s.syncAsSint32LE(_lNumRecs);
|
||||
s.syncAsSint32LE(_lAddress);
|
||||
s.syncAsUint32LE(_lFlags);
|
||||
s.syncAsUint32LE(_lFootCrc);
|
||||
}
|
||||
|
||||
|
||||
CBofDataFile::CBofDataFile() {
|
||||
_szFileName[0] = '\0';
|
||||
_szPassWord[0] = '\0';
|
||||
_lHeaderLength = 0;
|
||||
_lNumRecs = 0;
|
||||
_pHeader = nullptr;
|
||||
_bHeaderDirty = false;
|
||||
}
|
||||
|
||||
ErrorCode CBofDataFile::setFile(const char *pszFileName, uint32 lFlags) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
// Validate input
|
||||
assert(pszFileName != nullptr);
|
||||
assert(strlen(pszFileName) < MAX_FNAME);
|
||||
|
||||
// Release any previous data-file
|
||||
releaseFile();
|
||||
|
||||
// All data files are binary, so force it
|
||||
lFlags |= CBF_BINARY;
|
||||
|
||||
// Remember the flags
|
||||
_lFlags = lFlags;
|
||||
|
||||
if (fileGetFullPath(_szFileName, pszFileName) != nullptr) {
|
||||
if (open() == ERR_NONE) {
|
||||
|
||||
// Read header block
|
||||
readHeader();
|
||||
|
||||
// Close data file if we are not keeping it open
|
||||
if (!(_lFlags & CDF_KEEPOPEN)) {
|
||||
close();
|
||||
}
|
||||
} else
|
||||
reportError(ERR_FOPEN, "Could not open file %s", _szFileName);
|
||||
|
||||
} else {
|
||||
reportError(ERR_FFIND, "Could not build full path to %s", pszFileName);
|
||||
}
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
CBofDataFile::~CBofDataFile() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
releaseFile();
|
||||
}
|
||||
|
||||
ErrorCode CBofDataFile::releaseFile() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
// If header was modified
|
||||
if (_bHeaderDirty) {
|
||||
// Write header to disk
|
||||
writeHeader();
|
||||
}
|
||||
|
||||
close();
|
||||
|
||||
// Free header buffer
|
||||
delete[] _pHeader;
|
||||
_pHeader = nullptr;
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
ErrorCode CBofDataFile::create() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
HeadInfo stHeaderInfo;
|
||||
|
||||
// Only continue if there is no current error
|
||||
if (_errCode == ERR_NONE) {
|
||||
if (_stream != nullptr) {
|
||||
close();
|
||||
}
|
||||
|
||||
// Re-initialize
|
||||
delete[] _pHeader;
|
||||
_pHeader = nullptr;
|
||||
|
||||
_stream = nullptr;
|
||||
_lHeaderLength = 0;
|
||||
_bHeaderDirty = false;
|
||||
|
||||
stHeaderInfo._lNumRecs = _lNumRecs = 0;
|
||||
stHeaderInfo._lAddress = HeadInfo::size();
|
||||
|
||||
// Create the file
|
||||
if (CBofFile::create(_szFileName, _lFlags) == ERR_NONE) {
|
||||
// Write empty header info
|
||||
if (write(stHeaderInfo) != ERR_NONE) {
|
||||
_errCode = ERR_FWRITE;
|
||||
}
|
||||
|
||||
seek(0);
|
||||
|
||||
} else {
|
||||
_errCode = ERR_FOPEN;
|
||||
}
|
||||
}
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
ErrorCode CBofDataFile::open() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
// Only continue if there is no current error
|
||||
if (_errCode == ERR_NONE && _stream == nullptr) {
|
||||
if (!(_lFlags & CDF_READONLY)) {
|
||||
if (_lFlags & CDF_SAVEFILE) {
|
||||
if (_lFlags & CDF_CREATE)
|
||||
create();
|
||||
} else if (!fileExists(_szFileName))
|
||||
create();
|
||||
}
|
||||
|
||||
if (_stream == nullptr) {
|
||||
// Open data file
|
||||
CBofFile::open(_szFileName, _lFlags);
|
||||
}
|
||||
}
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
ErrorCode CBofDataFile::close() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
if (_stream != nullptr) {
|
||||
if (_bHeaderDirty) {
|
||||
writeHeader();
|
||||
}
|
||||
|
||||
CBofFile::close();
|
||||
}
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
ErrorCode CBofDataFile::readHeader() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
// Only continue if there is no current error
|
||||
if (_errCode == ERR_NONE) {
|
||||
if (_stream == nullptr) {
|
||||
open();
|
||||
}
|
||||
|
||||
if (!errorOccurred()) {
|
||||
// Determine number of records in file
|
||||
HeadInfo stHeaderInfo;
|
||||
if (read(stHeaderInfo) == ERR_NONE) {
|
||||
_lNumRecs = stHeaderInfo._lNumRecs;
|
||||
_lHeaderStart = stHeaderInfo._lAddress;
|
||||
|
||||
// Length of header is number of records * header-record size
|
||||
_lHeaderLength = _lNumRecs * HeaderRec::size();
|
||||
|
||||
Common::SeekableReadStream *rs = dynamic_cast<Common::SeekableReadStream *>(_stream);
|
||||
assert(rs);
|
||||
int32 lfileLength = rs->size();
|
||||
|
||||
// Make sure header contains valid info
|
||||
if ((_lHeaderStart >= HeadInfo::size()) &&
|
||||
(_lHeaderStart <= lfileLength) && (_lHeaderLength >= 0) &&
|
||||
(_lHeaderLength < lfileLength)) {
|
||||
|
||||
// Force Encrypted, and Compress if existing file has them
|
||||
_lFlags |= stHeaderInfo._lFlags & CDF_ENCRYPT;
|
||||
_lFlags |= stHeaderInfo._lFlags & CDF_COMPRESSED;
|
||||
|
||||
if (_lHeaderLength != 0) {
|
||||
// Allocate buffer to hold header
|
||||
_pHeader = new HeaderRec[(int)_lNumRecs];
|
||||
|
||||
// Seek to start of header
|
||||
seek(_lHeaderStart);
|
||||
|
||||
// Read header
|
||||
ErrorCode errorCode = ERR_NONE;
|
||||
for (int i = 0; i < _lNumRecs && errorCode == ERR_NONE; ++i) {
|
||||
errorCode = read(_pHeader[i]);
|
||||
}
|
||||
|
||||
if (errorCode == ERR_NONE) {
|
||||
uint32 lCrc = calculateCRC(&_pHeader->_lOffset, 4 * _lNumRecs);
|
||||
|
||||
if (lCrc != stHeaderInfo._lFootCrc) {
|
||||
logError(buildString("Error: '%s' has invalid footer", _szFileName));
|
||||
_errCode = ERR_CRC;
|
||||
}
|
||||
|
||||
} else {
|
||||
logError(buildString("Error: Could not read footer in file '%s'", _szFileName));
|
||||
_errCode = ERR_FREAD;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
logError(buildString("Error: '%s' has invalid header", _szFileName));
|
||||
_errCode = ERR_FTYPE;
|
||||
}
|
||||
|
||||
} else {
|
||||
logError(buildString("Error: Could not read header in file '%s'", _szFileName));
|
||||
_errCode = ERR_FREAD;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
ErrorCode CBofDataFile::writeHeader() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
// Only continue if there is no current error
|
||||
if (_errCode == ERR_NONE) {
|
||||
// Open the data file if it's not already open
|
||||
if (_stream == nullptr) {
|
||||
open();
|
||||
}
|
||||
|
||||
if (_errCode == ERR_NONE) {
|
||||
// Header starts at the end of the last record
|
||||
HeaderRec *pRec = &_pHeader[_lNumRecs - 1];
|
||||
_lHeaderStart = pRec->_lOffset + pRec->_lLength;
|
||||
|
||||
HeadInfo stHeaderInfo;
|
||||
stHeaderInfo._lNumRecs = _lNumRecs;
|
||||
stHeaderInfo._lAddress = _lHeaderStart;
|
||||
stHeaderInfo._lFlags = _lFlags;
|
||||
stHeaderInfo._lFootCrc = calculateCRC(&_pHeader->_lOffset, 4 * _lNumRecs);
|
||||
|
||||
// Seek to front of file to write header info
|
||||
seekToBeginning();
|
||||
|
||||
if (write(stHeaderInfo) == ERR_NONE) {
|
||||
// Seek to start of where header is to be written
|
||||
seek(_lHeaderStart);
|
||||
|
||||
// Write header to data file
|
||||
ErrorCode errorCode = ERR_NONE;
|
||||
for (int i = 0; i < _lNumRecs && errorCode == ERR_NONE; ++i) {
|
||||
errorCode = write(_pHeader[i]);
|
||||
}
|
||||
|
||||
if (errorCode == ERR_NONE) {
|
||||
// Header is now clean
|
||||
_bHeaderDirty = false;
|
||||
|
||||
} else {
|
||||
logError(buildString("Error writing footer to file '%s'", _szFileName));
|
||||
_errCode = ERR_FWRITE;
|
||||
}
|
||||
|
||||
} else {
|
||||
logError(buildString("Error writing header to file '%s'", _szFileName));
|
||||
_errCode = ERR_FWRITE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
ErrorCode CBofDataFile::readRecord(int32 lRecNum, void *pBuf) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
// Only continue if there is no current error
|
||||
if (_errCode == ERR_NONE) {
|
||||
// Can't write to nullptr pointers
|
||||
assert(pBuf != nullptr);
|
||||
|
||||
// Validate record number
|
||||
assert(lRecNum >= 0 && lRecNum < _lNumRecs);
|
||||
|
||||
// Make sure we have a valid header
|
||||
assert(_pHeader != nullptr);
|
||||
// Get info about address of where record starts
|
||||
// and how large the record is.
|
||||
HeaderRec *pRecInfo = &_pHeader[(int)lRecNum];
|
||||
|
||||
// Open the data file if it's not already open
|
||||
if (_stream == nullptr) {
|
||||
open();
|
||||
}
|
||||
|
||||
if (_errCode == ERR_NONE) {
|
||||
// Seek to that point in the file
|
||||
seek(pRecInfo->_lOffset);
|
||||
|
||||
// Read in the record
|
||||
if (read(pBuf, pRecInfo->_lLength) == ERR_NONE) {
|
||||
// If this file is encrypted, then decrypt it
|
||||
if (_lFlags & CDF_ENCRYPT) {
|
||||
decrypt(pBuf, (int)pRecInfo->_lLength, _szPassWord);
|
||||
}
|
||||
|
||||
// Calculate and verify this record's CRC value
|
||||
uint32 lCrc = calculateCRC(pBuf, (int)pRecInfo->_lLength);
|
||||
|
||||
if (lCrc != pRecInfo->_lCrc) {
|
||||
_errCode = ERR_CRC;
|
||||
}
|
||||
|
||||
} else {
|
||||
logError(buildString("Error reading record %d in file '%s'", lRecNum, _szFileName));
|
||||
_errCode = ERR_FREAD;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
ErrorCode CBofDataFile::readFromFile(int32 lRecNum, void *pBuf, int32 lBytes) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
// Only continue if there is no current error
|
||||
if (_errCode == ERR_NONE) {
|
||||
// Can't write to nullptr pointers
|
||||
assert(pBuf != nullptr);
|
||||
|
||||
// Validate record number
|
||||
assert(lRecNum >= 0 && lRecNum < _lNumRecs);
|
||||
|
||||
// Make sure we have a valid header
|
||||
assert(_pHeader != nullptr);
|
||||
|
||||
// Get info about address of where record starts
|
||||
// and how large the record is.
|
||||
HeaderRec *pRecInfo = &_pHeader[(int)lRecNum];
|
||||
|
||||
// Open the data file if it's not already open
|
||||
if (_stream == nullptr) {
|
||||
open();
|
||||
}
|
||||
|
||||
if (_errCode == ERR_NONE) {
|
||||
// Seek to that point in the file
|
||||
seek(pRecInfo->_lOffset);
|
||||
|
||||
// Read in the requested bytes...
|
||||
if (read(pBuf, lBytes) == ERR_NONE) {
|
||||
// If this file is encrypted, then decrypt it
|
||||
if (_lFlags & CDF_ENCRYPT) {
|
||||
decryptPartial(pBuf, (int32)pRecInfo->_lLength, (int32)lBytes, _szPassWord);
|
||||
}
|
||||
|
||||
// Don't bother with a CRC as this chunk of input won't generate a proper
|
||||
// CRC anyway.
|
||||
} else {
|
||||
logError(buildString("Error reading record %u in file '%s'", lRecNum, _szFileName));
|
||||
_errCode = ERR_FREAD;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
ErrorCode CBofDataFile::writeRecord(int32 lRecNum, void *pBuf, int32 lSize, bool bUpdateHeader, uint32 lKey) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
// Only continue if there is no current error
|
||||
if (_errCode == ERR_NONE) {
|
||||
// Validate record number
|
||||
assert(lRecNum >= 0 && lRecNum < _lNumRecs);
|
||||
|
||||
// Validate input buffer
|
||||
assert(pBuf != nullptr);
|
||||
|
||||
// There must already be a valid header
|
||||
assert(_pHeader != nullptr);
|
||||
|
||||
if (lSize == -1)
|
||||
lSize = _pHeader[(int)lRecNum]._lLength;
|
||||
|
||||
int32 lPrevOffset = HeadInfo::size();
|
||||
int32 lPrevLength = 0;
|
||||
|
||||
if (lRecNum != 0) {
|
||||
lPrevOffset = _pHeader[(int)lRecNum - 1]._lOffset;
|
||||
lPrevLength = _pHeader[(int)lRecNum - 1]._lLength;
|
||||
}
|
||||
|
||||
HeaderRec *pRecInfo = &_pHeader[(int)lRecNum];
|
||||
|
||||
// Header needs to updated
|
||||
_bHeaderDirty = true;
|
||||
|
||||
if (_stream == nullptr) {
|
||||
open();
|
||||
}
|
||||
|
||||
// This record starts at the end of the last record
|
||||
pRecInfo->_lOffset = lPrevOffset + lPrevLength;
|
||||
|
||||
// Seek to where we want to write this record
|
||||
seek(pRecInfo->_lOffset);
|
||||
|
||||
// Calculate new hash code based on this records key
|
||||
pRecInfo->_lKey = lKey;
|
||||
if (lKey == 0xFFFFFFFF) {
|
||||
pRecInfo->_lKey = CreateHashCode((const byte *)pBuf);
|
||||
}
|
||||
|
||||
// Calculate this record's CRC value
|
||||
pRecInfo->_lCrc = calculateCRC(pBuf, lSize);
|
||||
|
||||
if (_lFlags & CDF_ENCRYPT) {
|
||||
encrypt(pBuf, lSize, _szPassWord);
|
||||
}
|
||||
|
||||
// If new record is larger then original
|
||||
if (lSize > pRecInfo->_lLength) {
|
||||
// How many bytes back do we have to write?
|
||||
int32 lDiff = lSize - pRecInfo->_lLength;
|
||||
|
||||
//
|
||||
// Move the rest of file back that many bytes
|
||||
//
|
||||
|
||||
// Read the rest of the file in chunks (of 200k or less),
|
||||
// and write each chunk back in it's new position.
|
||||
//
|
||||
int32 lBufLength = getLength() - (pRecInfo->_lOffset + pRecInfo->_lLength);
|
||||
int32 lChunkSize = MIN(lBufLength, (int32)200000);
|
||||
|
||||
// Allocate a buffer big enough for one chunk
|
||||
byte *pTmpBuf = (byte *)bofAlloc(lChunkSize);
|
||||
|
||||
// While there is data to move
|
||||
while (lBufLength > 0) {
|
||||
// Seek to beginning of the source for this chunk
|
||||
setPosition(pRecInfo->_lOffset + pRecInfo->_lLength + lBufLength - lChunkSize);
|
||||
|
||||
// Read the chunk
|
||||
read(pTmpBuf, lChunkSize);
|
||||
|
||||
// Seek to this chunks new position (offset by 'lDiff' bytes)
|
||||
setPosition(pRecInfo->_lOffset + pRecInfo->_lLength + lBufLength - lChunkSize + lDiff);
|
||||
|
||||
// Write chunk to new position
|
||||
write(pTmpBuf, lChunkSize);
|
||||
|
||||
// That much less to do next time through
|
||||
lBufLength -= lChunkSize;
|
||||
|
||||
// Last chunk is lBufLength
|
||||
lChunkSize = MIN(lBufLength, lChunkSize);
|
||||
}
|
||||
|
||||
// Don't need that temp buffer anymore
|
||||
bofFree(pTmpBuf);
|
||||
|
||||
// Tell the rest of the records that they moved
|
||||
for (int i = lRecNum + 1; i < getNumberOfRecs(); i++) {
|
||||
_pHeader[i]._lOffset += lDiff;
|
||||
}
|
||||
|
||||
// Remember it's new length
|
||||
pRecInfo->_lLength = lSize;
|
||||
|
||||
// Seek to where we want to write this record
|
||||
seek(pRecInfo->_lOffset);
|
||||
|
||||
// Write this record
|
||||
write(pBuf, lSize);
|
||||
|
||||
// If we are to update the header now
|
||||
if (bUpdateHeader) {
|
||||
writeHeader();
|
||||
}
|
||||
|
||||
} else {
|
||||
// Write this record
|
||||
if (write(pBuf, lSize) == ERR_NONE) {
|
||||
// If this record got smaller
|
||||
if (pRecInfo->_lLength > lSize) {
|
||||
// Remember it's length
|
||||
pRecInfo->_lLength = lSize;
|
||||
|
||||
int bufferSize = getMaxRecSize();
|
||||
if (bufferSize <= 0)
|
||||
fatalError(ERR_FREAD, "Invalid size read in header data");
|
||||
|
||||
// Allocate a buffer that could hold the largest record
|
||||
byte *pTmpBuf = (byte *)bofAlloc(bufferSize);
|
||||
|
||||
for (int i = (int)lRecNum + 1; i < (int)_lNumRecs - 1; i++) {
|
||||
_errCode = readRecord(i, pTmpBuf);
|
||||
if (_errCode != ERR_NONE)
|
||||
break;
|
||||
|
||||
_errCode = writeRecord(i + 1, pTmpBuf);
|
||||
if (_errCode != ERR_NONE)
|
||||
break;
|
||||
}
|
||||
|
||||
bofFree(pTmpBuf);
|
||||
}
|
||||
|
||||
// If we are to update the header now
|
||||
if (bUpdateHeader) {
|
||||
writeHeader();
|
||||
}
|
||||
|
||||
} else {
|
||||
_errCode = ERR_FWRITE;
|
||||
}
|
||||
}
|
||||
|
||||
// If this record is encrypted the decrypt it
|
||||
if (_lFlags & CDF_ENCRYPT) {
|
||||
decrypt(pBuf, (int)pRecInfo->_lLength, _szPassWord);
|
||||
}
|
||||
}
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
ErrorCode CBofDataFile::verifyRecord(int32 lRecNum) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
if (_errCode == ERR_NONE) {
|
||||
// Validate record number
|
||||
assert(lRecNum >= 0 && lRecNum < _lNumRecs);
|
||||
|
||||
// Allocate space to hold this record
|
||||
void *pBuf = bofAlloc((int)getRecSize(lRecNum));
|
||||
|
||||
_errCode = readRecord(lRecNum, pBuf);
|
||||
bofFree(pBuf);
|
||||
}
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
ErrorCode CBofDataFile::verifyAllRecords() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
if (_errCode == ERR_NONE) {
|
||||
int32 n = getNumberOfRecs();
|
||||
for (int32 i = 0; i < n; i++) {
|
||||
_errCode = verifyRecord(i);
|
||||
if (_errCode != ERR_NONE) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
ErrorCode CBofDataFile::addRecord(void *pBuf, int32 lLength, bool bUpdateHeader, uint32 lKey) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
// Only continue if there is no current error
|
||||
if (_errCode == ERR_NONE) {
|
||||
|
||||
// Validate input
|
||||
assert(pBuf != nullptr);
|
||||
assert(lLength > 0);
|
||||
|
||||
if (lLength > 0) {
|
||||
if (_stream == nullptr) {
|
||||
open();
|
||||
}
|
||||
|
||||
if (_errCode == ERR_NONE) {
|
||||
_lNumRecs++;
|
||||
|
||||
HeaderRec *pTmpHeader = new HeaderRec[(int)_lNumRecs];
|
||||
|
||||
for (int i = 0; i < _lNumRecs; ++i) {
|
||||
pTmpHeader[i]._lOffset = pTmpHeader[i]._lLength = 0;
|
||||
pTmpHeader[i]._lCrc = pTmpHeader[i]._lKey = 0;
|
||||
}
|
||||
|
||||
if (_pHeader != nullptr) {
|
||||
memcpy(pTmpHeader, _pHeader, (size_t)(HeaderRec::size() * (_lNumRecs - 1)));
|
||||
delete[] _pHeader;
|
||||
}
|
||||
|
||||
_pHeader = pTmpHeader;
|
||||
|
||||
int32 lRecNum = _lNumRecs - 1;
|
||||
HeaderRec *pCurRec = &_pHeader[lRecNum];
|
||||
int32 lPrevLength = HeadInfo::size();
|
||||
int32 lPrevOffset = 0;
|
||||
|
||||
if (lRecNum != 0) {
|
||||
lPrevLength = _pHeader[lRecNum - 1]._lLength;
|
||||
lPrevOffset = _pHeader[lRecNum - 1]._lOffset;
|
||||
}
|
||||
|
||||
pCurRec->_lLength = lLength;
|
||||
pCurRec->_lOffset = lPrevOffset + lPrevLength;
|
||||
|
||||
writeRecord(lRecNum, pBuf, lLength, bUpdateHeader, lKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
int32 CBofDataFile::findRecord(uint32 lKey) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
// Assume no match
|
||||
int32 lRecNum = -1;
|
||||
|
||||
// Only continue if there is no current error
|
||||
if (_errCode == ERR_NONE) {
|
||||
// Scan the header for the key matching the hash code
|
||||
for (int32 i = 0; i < _lNumRecs; i++) {
|
||||
// Header records must be valid
|
||||
assert(_pHeader != nullptr);
|
||||
|
||||
if (_pHeader[i]._lKey == lKey) {
|
||||
lRecNum = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return lRecNum;
|
||||
}
|
||||
|
||||
int32 CBofDataFile::getRecSize(int32 lRecNum) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
int32 lSize = -1;
|
||||
|
||||
// Only continue if there is no current error
|
||||
if (_errCode == ERR_NONE) {
|
||||
// Validate record number
|
||||
assert(lRecNum >= 0 && lRecNum < _lNumRecs);
|
||||
|
||||
assert(_pHeader != nullptr);
|
||||
|
||||
lSize = _pHeader[lRecNum]._lLength;
|
||||
}
|
||||
|
||||
return lSize;
|
||||
}
|
||||
|
||||
int32 CBofDataFile::getMaxRecSize() const {
|
||||
assert(isValidObject(this));
|
||||
|
||||
int32 lLargest = -1;
|
||||
|
||||
// Only continue if there is no current error
|
||||
if (_errCode == ERR_NONE) {
|
||||
// Validate header
|
||||
assert(_pHeader != nullptr);
|
||||
|
||||
for (int i = 0; i < (int)_lNumRecs; i++) {
|
||||
lLargest = MAX(lLargest, _pHeader[i]._lLength);
|
||||
}
|
||||
}
|
||||
|
||||
return lLargest;
|
||||
}
|
||||
|
||||
void CBofDataFile::setPassword(const char *pszPassword) {
|
||||
assert(isValidObject(this));
|
||||
_szPassWord[0] = '\0';
|
||||
|
||||
if (pszPassword != nullptr) {
|
||||
assert(strlen(pszPassword) < MAX_PW_LEN);
|
||||
|
||||
Common::strcpy_s(_szPassWord, pszPassword);
|
||||
}
|
||||
}
|
||||
|
||||
ErrorCode CBofDataFile::read(void *pDestBuf, int32 lBytes) {
|
||||
return CBofFile::read(pDestBuf, lBytes);
|
||||
}
|
||||
|
||||
ErrorCode CBofDataFile::read(HeadInfo &rec) {
|
||||
byte buf[16];
|
||||
ErrorCode errorCode = read(&buf[0], 16);
|
||||
|
||||
Common::MemoryReadStream mem(buf, 16);
|
||||
Common::Serializer s(&mem, nullptr);
|
||||
rec.synchronize(s);
|
||||
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
ErrorCode CBofDataFile::read(HeaderRec &rec) {
|
||||
byte buf[16];
|
||||
ErrorCode errorCode = read(&buf[0], 16);
|
||||
|
||||
Common::MemoryReadStream mem(buf, 16);
|
||||
Common::Serializer s(&mem, nullptr);
|
||||
rec.synchronize(s);
|
||||
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
ErrorCode CBofDataFile::write(const void *pSrcBuf, int32 lBytes) {
|
||||
return CBofFile::write(pSrcBuf, lBytes);
|
||||
}
|
||||
|
||||
ErrorCode CBofDataFile::write(HeadInfo &rec) {
|
||||
byte buf[16];
|
||||
|
||||
Common::MemoryWriteStream mem(buf, 16);
|
||||
Common::Serializer s(nullptr, &mem);
|
||||
rec.synchronize(s);
|
||||
|
||||
return write(&buf[0], 16);
|
||||
}
|
||||
|
||||
ErrorCode CBofDataFile::write(HeaderRec &rec) {
|
||||
byte buf[16];
|
||||
|
||||
Common::MemoryWriteStream mem(buf, 16);
|
||||
Common::Serializer s(nullptr, &mem);
|
||||
rec.synchronize(s);
|
||||
|
||||
return write(&buf[0], 16);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a Hash code based on a key.
|
||||
* @param pKey Key
|
||||
* @return Hash code
|
||||
*/
|
||||
uint32 CreateHashCode(const byte *pKey) {
|
||||
// validate input
|
||||
assert(pKey != nullptr);
|
||||
|
||||
uint32 lCode = ((uint32) * pKey << 24) | ((uint32) * (pKey + 1) << 16) | ((uint32) * (pKey + 2) << 8) | *(pKey + 3);
|
||||
|
||||
return lCode;
|
||||
}
|
||||
|
||||
void SwapHeadInfo(HeadInfo *stHI) {
|
||||
// Macintosh is big endian, so we must swap our bytes
|
||||
stHI->_lNumRecs = SWAPLONG(stHI->_lNumRecs);
|
||||
stHI->_lAddress = SWAPLONG(stHI->_lAddress);
|
||||
stHI->_lFlags = SWAPLONG(stHI->_lFlags);
|
||||
stHI->_lFootCrc = SWAPLONG(stHI->_lFootCrc);
|
||||
}
|
||||
|
||||
void SwapHeaderRec(HeaderRec *stHR, int nRecords) {
|
||||
HeaderRec *p = stHR;
|
||||
for (int i = 0; i < nRecords; i++) {
|
||||
p->_lOffset = SWAPLONG(p->_lOffset);
|
||||
p->_lLength = SWAPLONG(p->_lLength);
|
||||
p->_lCrc = SWAPLONG(p->_lCrc);
|
||||
p->_lKey = SWAPLONG(p->_lKey);
|
||||
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace SpaceBar
|
||||
} // namespace Bagel
|
||||
245
engines/bagel/spacebar/boflib/dat_file.h
Normal file
245
engines/bagel/spacebar/boflib/dat_file.h
Normal file
@@ -0,0 +1,245 @@
|
||||
|
||||
/* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BAGEL_BOFLIB_DAT_FILE_H
|
||||
#define BAGEL_BOFLIB_DAT_FILE_H
|
||||
|
||||
#include "common/serializer.h"
|
||||
#include "bagel/spacebar/boflib/file.h"
|
||||
|
||||
namespace Bagel {
|
||||
namespace SpaceBar {
|
||||
|
||||
#define CDF_NOFLAGS 0x00000000
|
||||
#define CDF_READONLY CBF_READONLY // Open for Read-only access
|
||||
#define CDF_OVERWRITE CBF_OVERWRITE // *Overwrite any existing data-file
|
||||
#define CDF_SHARED CBF_SHARED // *Open for Shared access
|
||||
#define CDF_CREATE CBF_CREATE // *Create new file if not exist
|
||||
#define CDF_SAVEFILE CBF_SAVEFILE
|
||||
|
||||
#define CDF_MEMORY 0x00010000 // *header/footer should stay in memory
|
||||
#define CDF_ENCRYPT 0x00020000 // Specifies if data should use encryption
|
||||
#define CDF_KEEPOPEN 0x00040000 // File should be kept open after construction
|
||||
#define CDF_COMPRESSED 0x00080000 // *Specifies if data should be compressed
|
||||
// * = indicates feature not yet implemented
|
||||
|
||||
#define CDF_DEFAULT (CDF_MEMORY | CDF_ENCRYPT | CDF_SHARED | CDF_KEEPOPEN | CDF_READONLY)
|
||||
|
||||
#define MAX_PW_LEN 32 // Max Password length
|
||||
|
||||
struct HeaderRec {
|
||||
public:
|
||||
int32 _lOffset;
|
||||
int32 _lLength;
|
||||
uint32 _lCrc;
|
||||
uint32 _lKey;
|
||||
|
||||
void synchronize(Common::Serializer &s);
|
||||
static int size() {
|
||||
return 16;
|
||||
}
|
||||
};
|
||||
|
||||
struct HeadInfo {
|
||||
int32 _lNumRecs; // Number of records in this file
|
||||
int32 _lAddress; // starting address of footer
|
||||
uint32 _lFlags; // contains flags for this file
|
||||
uint32 _lFootCrc; // CRC of the footer
|
||||
|
||||
void synchronize(Common::Serializer &s);
|
||||
static int size() {
|
||||
return 16;
|
||||
}
|
||||
};
|
||||
|
||||
class CBofDataFile : public CBofFile {
|
||||
private:
|
||||
char _szPassWord[MAX_PW_LEN];
|
||||
int32 _lHeaderLength = 0;
|
||||
int32 _lHeaderStart = 0;
|
||||
int32 _lNumRecs = 0;
|
||||
HeaderRec *_pHeader = nullptr;
|
||||
|
||||
bool _bHeaderDirty;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Read the header (actually a footer) from the data-file.
|
||||
* @return Error return code
|
||||
*/
|
||||
ErrorCode readHeader();
|
||||
|
||||
/**
|
||||
* Writes the header (actually a footer) to the data-file.
|
||||
* @return Error return code
|
||||
*/
|
||||
ErrorCode writeHeader();
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
CBofDataFile();
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~CBofDataFile();
|
||||
|
||||
/**
|
||||
* Initializes a CBofDataFile with specified info
|
||||
* @param pszFileName Name of .DAT file
|
||||
* @param lFlags Flags for open, and encryption, etc.
|
||||
* @return Error return code
|
||||
*/
|
||||
ErrorCode setFile(const char *pszFileName, uint32 lFlags);
|
||||
|
||||
/**
|
||||
* Free memory used by this object
|
||||
* @return Error return code
|
||||
*/
|
||||
ErrorCode releaseFile();
|
||||
|
||||
/**
|
||||
* Retrieves size of specified record.
|
||||
* @param lRecNum Index of record to get size of
|
||||
* @return Size of specified record
|
||||
*/
|
||||
int32 getRecSize(int32 lRecNum);
|
||||
int32 getNumberOfRecs() const {
|
||||
return _lNumRecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves size of the largest record.
|
||||
* @return Size of largest record in the data-file
|
||||
*/
|
||||
int32 getMaxRecSize() const;
|
||||
|
||||
/**
|
||||
* Opens an existing data-file, or creates a new one.
|
||||
* @return Error return code
|
||||
*/
|
||||
ErrorCode open();
|
||||
|
||||
/**
|
||||
* Closes current data-file, if it's not already closed
|
||||
* @return Error return code
|
||||
*/
|
||||
ErrorCode close() override;
|
||||
|
||||
/**
|
||||
* Destroys current data-file, if any, and starts a new empty one
|
||||
* @return Error return code
|
||||
*/
|
||||
ErrorCode create();
|
||||
|
||||
/**
|
||||
* Reads specified record from data-file.
|
||||
* @param lRecNum Record number to read
|
||||
* @param pBuf Buffer to store record
|
||||
* @return Error return code
|
||||
*/
|
||||
ErrorCode readRecord(int32 lRecNum, void *pBuf);
|
||||
|
||||
/**
|
||||
* Read a set number of bytes from the beginning of a file,
|
||||
* don't bother with a CRC, but decrypt if necessary. This is dependent upon
|
||||
* the decryption being based on a single byte ordering scheme.
|
||||
*/
|
||||
ErrorCode readFromFile(int32 lRecNum, void *pBuf, int32 lBytes);
|
||||
|
||||
/**
|
||||
* Writes specified to data-file.
|
||||
* @param lRecNum Record number to read
|
||||
* @param pBuf Buffer to write data from
|
||||
* @param lSize Size of buffer
|
||||
* @param bUpdateHeader True if header is to be committed to disk
|
||||
* @param lKey Hash key
|
||||
* @return Error return code
|
||||
*/
|
||||
ErrorCode writeRecord(int32 lRecNum, void *pBuf, int32 lSize = -1, bool bUpdateHeader = false, uint32 lKey = 0xFFFFFFFF);
|
||||
|
||||
/**
|
||||
* Verifies specified record in data-file.
|
||||
* @param lRecNum Record number to verify
|
||||
* @return Error return code
|
||||
*/
|
||||
ErrorCode verifyRecord(int32 lRecNum);
|
||||
|
||||
/**
|
||||
* Verifies all records in this file
|
||||
* @return Error return code
|
||||
*/
|
||||
ErrorCode verifyAllRecords();
|
||||
|
||||
/**
|
||||
* Adds a new record to the data-file.
|
||||
* @param pBuf Buffer to write data from
|
||||
* @param lLength Size of buffer
|
||||
* @param bUpdateHeader true if header is to be committed to disk
|
||||
* @param lKey hash Key
|
||||
* @return Error return code
|
||||
*/
|
||||
ErrorCode addRecord(void *pBuf, int32 lLength, bool bUpdateHeader = false, uint32 lKey = 0xFFFFFFFF);
|
||||
|
||||
/**
|
||||
* Finds record by it's key.
|
||||
* @param lKey Key to search records with
|
||||
* @return Index of record matching key, or -1
|
||||
*/
|
||||
int32 findRecord(uint32 lKey);
|
||||
|
||||
/**
|
||||
* Sets encryption password
|
||||
* @param pszPassword New password
|
||||
*/
|
||||
void setPassword(const char *pszPassword);
|
||||
const char *getPassword() const {
|
||||
return _szPassWord;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read from a currently open file
|
||||
* @param pDestBuf Destination buffer
|
||||
* @param lBytes Number of bytes
|
||||
* @return Error code
|
||||
*/
|
||||
ErrorCode read(void *pDestBuf, int32 lBytes) override;
|
||||
ErrorCode read(HeaderRec &rec);
|
||||
ErrorCode read(HeadInfo &rec);
|
||||
|
||||
/**
|
||||
* Write to a currently open file
|
||||
* @param pSrcBuf Source buffer
|
||||
* @param lBytes Number of bytes
|
||||
* @return Error code
|
||||
*/
|
||||
ErrorCode write(const void *pSrcBuf, int32 lBytes) override;
|
||||
ErrorCode write(HeaderRec &rec);
|
||||
ErrorCode write(HeadInfo &rec);
|
||||
};
|
||||
|
||||
} // namespace SpaceBar
|
||||
} // namespace Bagel
|
||||
|
||||
#endif
|
||||
51
engines/bagel/spacebar/boflib/debug.cpp
Normal file
51
engines/bagel/spacebar/boflib/debug.cpp
Normal file
@@ -0,0 +1,51 @@
|
||||
/* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/config-manager.h"
|
||||
#include "common/debug.h"
|
||||
#include "bagel/spacebar/boflib/debug.h"
|
||||
#include "bagel/bagel.h"
|
||||
|
||||
namespace Bagel {
|
||||
namespace SpaceBar {
|
||||
|
||||
CBofDebugOptions *g_pDebugOptions = nullptr;
|
||||
|
||||
CBofDebugOptions::CBofDebugOptions(const char *pszFileName) : CBofOptions(pszFileName) {
|
||||
// Add programmer definable debug options here
|
||||
ConfMan.registerDefault("AbortsOn", true);
|
||||
ConfMan.registerDefault("MessageBoxOn", true);
|
||||
ConfMan.registerDefault("RandomOn", true);
|
||||
ConfMan.registerDefault("DebugLevel", gDebugLevel);
|
||||
ConfMan.registerDefault("ShowIO", false);
|
||||
ConfMan.registerDefault("MessageSpy", false);
|
||||
|
||||
|
||||
readSetting("DebugOptions", "AbortsOn", &_bAbortsOn, ConfMan.getBool("AbortsOn"));
|
||||
readSetting("DebugOptions", "MessageBoxOn", &_bMessageBoxOn, ConfMan.getBool("MessageBoxOn"));
|
||||
readSetting("DebugOptions", "RandomOn", &_bRandomOn, ConfMan.getBool("RandomOn"));
|
||||
readSetting("DebugOptions", "DebugLevel", &_nDebugLevel, ConfMan.getInt("DebugLevel"));
|
||||
readSetting("DebugOptions", "ShowIO", &_bShowIO, ConfMan.getBool("ShowIO"));
|
||||
readSetting("DebugOptions", "MessageSpy", &_bShowMessages, ConfMan.getBool("MessageSpy"));
|
||||
}
|
||||
|
||||
} // namespace SpaceBar
|
||||
} // namespace Bagel
|
||||
55
engines/bagel/spacebar/boflib/debug.h
Normal file
55
engines/bagel/spacebar/boflib/debug.h
Normal file
@@ -0,0 +1,55 @@
|
||||
|
||||
/* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BAGEL_BOFLIB_DEBUG_H
|
||||
#define BAGEL_BOFLIB_DEBUG_H
|
||||
|
||||
#include "bagel/spacebar/boflib/options.h"
|
||||
|
||||
namespace Bagel {
|
||||
namespace SpaceBar {
|
||||
|
||||
/**
|
||||
* Declare a debug-options (.INI) file
|
||||
*/
|
||||
class CBofDebugOptions : public CBofOptions {
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
* @param pszFileName Name of debug options file
|
||||
*/
|
||||
CBofDebugOptions(const char *pszFileName);
|
||||
|
||||
int _nDebugLevel;
|
||||
bool _bAbortsOn;
|
||||
bool _bMessageBoxOn;
|
||||
bool _bRandomOn;
|
||||
bool _bShowIO;
|
||||
bool _bShowMessages;
|
||||
};
|
||||
|
||||
extern CBofDebugOptions *g_pDebugOptions;
|
||||
|
||||
} // namespace SpaceBar
|
||||
} // namespace Bagel
|
||||
|
||||
#endif
|
||||
44
engines/bagel/spacebar/boflib/events.h
Normal file
44
engines/bagel/spacebar/boflib/events.h
Normal file
@@ -0,0 +1,44 @@
|
||||
|
||||
/* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BAGEL_BOFLIB_EVENTS_H
|
||||
#define BAGEL_BOFLIB_EVENTS_H
|
||||
|
||||
#include "common/events.h"
|
||||
|
||||
namespace Bagel {
|
||||
namespace SpaceBar {
|
||||
|
||||
/**
|
||||
* Enum for custom ScummVM events
|
||||
*/
|
||||
enum BagelEventType {
|
||||
// EVENT user stores a message num in mouse.x, and param in mouse.y
|
||||
EVENT_USER = 1001,
|
||||
// TIMER events
|
||||
EVENT_TIMER = 1002
|
||||
};
|
||||
|
||||
} // namespace SpaceBar
|
||||
} // namespace Bagel
|
||||
|
||||
#endif
|
||||
297
engines/bagel/spacebar/boflib/file.cpp
Normal file
297
engines/bagel/spacebar/boflib/file.cpp
Normal file
@@ -0,0 +1,297 @@
|
||||
/* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/macresman.h"
|
||||
#include "common/stream.h"
|
||||
#include "common/system.h"
|
||||
#include "common/savefile.h"
|
||||
#include "bagel/bagel.h"
|
||||
#include "bagel/spacebar/boflib/file.h"
|
||||
#include "bagel/boflib/file_functions.h"
|
||||
#include "bagel/spacebar/boflib/debug.h"
|
||||
#include "bagel/boflib/log.h"
|
||||
|
||||
namespace Bagel {
|
||||
namespace SpaceBar {
|
||||
|
||||
#define CHUNK_SIZE 0x00007FFF
|
||||
|
||||
CBofFile::CBofFile() {
|
||||
_szFileName[0] = '\0';
|
||||
}
|
||||
|
||||
CBofFile::CBofFile(const char *pszFileName, uint32 lFlags) {
|
||||
_szFileName[0] = '\0';
|
||||
assert(pszFileName != nullptr);
|
||||
|
||||
// Open now?
|
||||
if (pszFileName != nullptr) {
|
||||
open(pszFileName, lFlags);
|
||||
}
|
||||
}
|
||||
|
||||
CBofFile::~CBofFile() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
close();
|
||||
}
|
||||
|
||||
ErrorCode CBofFile::create(const char *pszFileName, uint32 lFlags) {
|
||||
assert(isValidObject(this));
|
||||
assert(pszFileName != nullptr);
|
||||
assert(strlen(pszFileName) < MAX_DIRPATH);
|
||||
assert(*pszFileName != '\0');
|
||||
|
||||
// Can't create a read-only file
|
||||
assert(!(lFlags & CBF_READONLY));
|
||||
|
||||
_lFlags = lFlags;
|
||||
|
||||
// Remember this files name
|
||||
Common::strcpy_s(_szFileName, pszFileName);
|
||||
|
||||
// Create the file
|
||||
Common::OutSaveFile *save = g_system->getSavefileManager()->openForSaving(pszFileName, false);
|
||||
if (save != nullptr) {
|
||||
_stream = new SaveReadWriteStream(save);
|
||||
|
||||
if (g_pDebugOptions != nullptr && g_pDebugOptions->_bShowIO) {
|
||||
logInfo(buildString("Creating file '%s'", _szFileName));
|
||||
}
|
||||
|
||||
} else {
|
||||
reportError(ERR_FOPEN, "Unable to create %s", _szFileName);
|
||||
}
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
ErrorCode CBofFile::open(const char *pszFileName, uint32 lFlags) {
|
||||
assert(isValidObject(this));
|
||||
assert(pszFileName != nullptr);
|
||||
assert(strlen(pszFileName) < MAX_DIRPATH);
|
||||
assert(*pszFileName != '\0');
|
||||
|
||||
// Can't open for both Text and Binary modes
|
||||
assert(!((lFlags & CBF_TEXT) && (lFlags & CBF_BINARY)));
|
||||
|
||||
// Can't overwrite a readonly file
|
||||
assert(!((lFlags & CBF_READONLY) && (lFlags & CBF_OVERWRITE)));
|
||||
|
||||
// Can't create a new file to be readonly (there would be nothing to read!)
|
||||
assert(!((lFlags & CBF_READONLY) && (lFlags & CBF_CREATE)));
|
||||
|
||||
// Keep a copy of these flags
|
||||
_lFlags = lFlags;
|
||||
|
||||
if (_stream)
|
||||
return _errCode;
|
||||
|
||||
if ((lFlags & CBF_CREATE) && ((lFlags & CBF_SAVEFILE) ||
|
||||
!fileExists(pszFileName))) {
|
||||
create(pszFileName, lFlags);
|
||||
|
||||
} else {
|
||||
// Remember this files' name
|
||||
Common::strcpy_s(_szFileName, pszFileName);
|
||||
|
||||
if (lFlags & CBF_SAVEFILE) {
|
||||
_stream = g_system->getSavefileManager()->openForLoading(pszFileName);
|
||||
|
||||
if (!_stream)
|
||||
reportError(ERR_FOPEN, "Could not open %s", pszFileName);
|
||||
|
||||
} else {
|
||||
if (g_engine->getPlatform() == Common::kPlatformMacintosh) {
|
||||
_stream = Common::MacResManager::openFileOrDataFork(pszFileName);
|
||||
} else {
|
||||
_stream = SearchMan.createReadStreamForMember(pszFileName);
|
||||
}
|
||||
|
||||
if (_stream) {
|
||||
if (g_pDebugOptions != nullptr && g_pDebugOptions->_bShowIO) {
|
||||
logInfo(buildString("Opened file '%s'", _szFileName));
|
||||
}
|
||||
} else {
|
||||
reportError(ERR_FOPEN, "Could not open %s", pszFileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
ErrorCode CBofFile::close() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
if (_stream != nullptr) {
|
||||
if (g_pDebugOptions != nullptr && g_pDebugOptions->_bShowIO) {
|
||||
logInfo(buildString("Closed file '%s'", _szFileName));
|
||||
}
|
||||
|
||||
delete _stream;
|
||||
_stream = nullptr;
|
||||
}
|
||||
|
||||
return ERR_NONE;
|
||||
}
|
||||
|
||||
ErrorCode CBofFile::read(void *pDestBuf, int32 lBytes) {
|
||||
assert(isValidObject(this));
|
||||
assert(pDestBuf != nullptr);
|
||||
assert(lBytes >= 0);
|
||||
|
||||
Common::SeekableReadStream *rs = dynamic_cast<Common::SeekableReadStream *>(_stream);
|
||||
assert(rs);
|
||||
|
||||
if (!errorOccurred()) {
|
||||
if (rs != nullptr) {
|
||||
byte *pBuf = (byte *)pDestBuf;
|
||||
|
||||
while (lBytes > 0) {
|
||||
int nLength = (int)MIN(lBytes, (int32)CHUNK_SIZE);
|
||||
lBytes -= CHUNK_SIZE;
|
||||
|
||||
if ((int)rs->read(pBuf, nLength) != nLength) {
|
||||
reportError(ERR_FREAD, "Unable to read %d bytes from %s", nLength, _szFileName);
|
||||
}
|
||||
|
||||
pBuf += nLength;
|
||||
}
|
||||
|
||||
} else {
|
||||
error("Attempt to read from a file that is not open for reading: %s", _szFileName);
|
||||
}
|
||||
}
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
ErrorCode CBofFile::write(const void *pSrcBuf, int32 lBytes) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
Common::WriteStream *ws = dynamic_cast<Common::WriteStream *>(_stream);
|
||||
|
||||
if (ws != nullptr) {
|
||||
// As long as this file is not set for readonly, then write the buffer
|
||||
if (!(_lFlags & CBF_READONLY)) {
|
||||
const byte *pBuf = (const byte *)pSrcBuf;
|
||||
|
||||
while (lBytes > 0) {
|
||||
int nLength = (int)MIN(lBytes, (int32)CHUNK_SIZE);
|
||||
lBytes -= CHUNK_SIZE;
|
||||
|
||||
if ((int)ws->write(pBuf, nLength) != nLength) {
|
||||
reportError(ERR_FWRITE, "Unable to write %d bytes to %s", nLength, _szFileName);
|
||||
}
|
||||
|
||||
pBuf += nLength;
|
||||
}
|
||||
|
||||
// Flush this file's buffer back out right now
|
||||
commit();
|
||||
|
||||
} else {
|
||||
logWarning(buildString("Attempted to write to the READONLY file '%s'", _szFileName));
|
||||
}
|
||||
|
||||
} else {
|
||||
logWarning("Attempt to write to a file that is not open");
|
||||
}
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
ErrorCode CBofFile::setPosition(uint32 lPos) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
// Only supports files up to 2Gig
|
||||
assert(lPos < 0x80000000);
|
||||
|
||||
Common::SeekableReadStream *rs = dynamic_cast<Common::SeekableReadStream *>(_stream);
|
||||
Common::SeekableWriteStream *ws = dynamic_cast<Common::SeekableWriteStream *>(_stream);
|
||||
|
||||
if (rs && !rs->seek(lPos)) {
|
||||
reportError(ERR_FSEEK, "Unable to seek to %u in rs", lPos);
|
||||
}
|
||||
|
||||
if (ws && !ws->seek(lPos)) {
|
||||
reportError(ERR_FSEEK, "Unable to seek to %u in ws", lPos);
|
||||
}
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
uint32 CBofFile::getPosition() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
Common::SeekableReadStream *rs = dynamic_cast<Common::SeekableReadStream *>(_stream);
|
||||
Common::SeekableWriteStream *ws = dynamic_cast<Common::SeekableWriteStream *>(_stream);
|
||||
|
||||
if (rs)
|
||||
return rs->pos();
|
||||
|
||||
if (ws)
|
||||
return ws->pos();
|
||||
|
||||
error("getPosition on closed file");
|
||||
}
|
||||
|
||||
ErrorCode CBofFile::seekToEnd() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
Common::SeekableReadStream *rs = dynamic_cast<Common::SeekableReadStream *>(_stream);
|
||||
Common::SeekableWriteStream *ws = dynamic_cast<Common::SeekableWriteStream *>(_stream);
|
||||
|
||||
if (rs)
|
||||
rs->seek(0, SEEK_END);
|
||||
else if (ws)
|
||||
ws->seek(0, SEEK_END);
|
||||
else
|
||||
error("Seek in closed file");
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
uint32 CBofFile::getLength() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
Common::SeekableReadStream *rs = dynamic_cast<Common::SeekableReadStream *>(_stream);
|
||||
Common::SeekableWriteStream *ws = dynamic_cast<Common::SeekableWriteStream *>(_stream);
|
||||
|
||||
if (rs)
|
||||
return rs->size();
|
||||
if (ws)
|
||||
return ws->size();
|
||||
|
||||
error("getLength in closed file");
|
||||
}
|
||||
|
||||
void CBofFile::commit() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
Common::SeekableWriteStream *ws = dynamic_cast<Common::SeekableWriteStream *>(_stream);
|
||||
if (ws)
|
||||
ws->finalize();
|
||||
}
|
||||
|
||||
} // namespace SpaceBar
|
||||
} // namespace Bagel
|
||||
210
engines/bagel/spacebar/boflib/file.h
Normal file
210
engines/bagel/spacebar/boflib/file.h
Normal file
@@ -0,0 +1,210 @@
|
||||
|
||||
/* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BAGEL_BOFLIB_FILE_H
|
||||
#define BAGEL_BOFLIB_FILE_H
|
||||
|
||||
#include "common/algorithm.h"
|
||||
#include "common/memstream.h"
|
||||
#include "common/stream.h"
|
||||
#include "bagel/boflib/stdinc.h"
|
||||
#include "bagel/boflib/object.h"
|
||||
#include "bagel/boflib/error.h"
|
||||
|
||||
namespace Bagel {
|
||||
namespace SpaceBar {
|
||||
|
||||
#define CBF_TEXT 0x00000001
|
||||
#define CBF_BINARY 0x00000002
|
||||
#define CBF_READONLY 0x00000004
|
||||
#define CBF_OVERWRITE 0x00000008
|
||||
#define CBF_SHARED 0x00000010
|
||||
#define CBF_CREATE 0x00000020
|
||||
#define CBF_SAVEFILE 0x100
|
||||
|
||||
#define CBF_DEFAULT (CBF_BINARY | CBF_READONLY)
|
||||
|
||||
#define CBOFFILE_TEXT CBF_TEXT
|
||||
#define CBOFFILE_READONLY CBF_READONLY
|
||||
#define CBOFFILE_OVERWRITE CBF_OVERWRITE
|
||||
|
||||
#define CBOFFILE_DEFAULT CBF_DEFAULT
|
||||
|
||||
class SaveReadStream : public Common::SeekableReadStream {
|
||||
private:
|
||||
Common::MemoryWriteStreamDynamic *_owner;
|
||||
public:
|
||||
SaveReadStream(Common::MemoryWriteStreamDynamic *owner) : _owner(owner) {
|
||||
}
|
||||
|
||||
bool eos() const override {
|
||||
return _owner->pos() >= _owner->size();
|
||||
}
|
||||
uint32 read(void *dataPtr, uint32 dataSize) override {
|
||||
int bytesToCopy = MIN<int>(dataSize, _owner->size() - _owner->pos());
|
||||
const byte *src = _owner->getData() + _owner->pos();
|
||||
Common::copy(src, src + bytesToCopy, (byte *)dataPtr);
|
||||
seek(bytesToCopy, SEEK_CUR);
|
||||
return bytesToCopy;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Used as a wrapper for writing out original saves using the console,
|
||||
* since it also does reads from the stream whilst open
|
||||
*/
|
||||
class SaveReadWriteStream : public Common::MemoryWriteStreamDynamic, SaveReadStream {
|
||||
private:
|
||||
Common::WriteStream *_save;
|
||||
|
||||
public:
|
||||
SaveReadWriteStream(Common::WriteStream *save) :
|
||||
Common::MemoryWriteStreamDynamic(DisposeAfterUse::YES),
|
||||
SaveReadStream(this), _save(save) {
|
||||
}
|
||||
~SaveReadWriteStream() {
|
||||
_save->write(getData(), Common::MemoryWriteStreamDynamic::size());
|
||||
delete _save;
|
||||
}
|
||||
|
||||
int64 pos() const override {
|
||||
return Common::MemoryWriteStreamDynamic::pos();
|
||||
}
|
||||
bool seek(int64 offset, int whence = SEEK_SET) override {
|
||||
return Common::MemoryWriteStreamDynamic::seek(offset, whence);
|
||||
}
|
||||
int64 size() const override {
|
||||
return Common::MemoryWriteStreamDynamic::size();
|
||||
}
|
||||
};
|
||||
|
||||
class CBofFile : public CBofObject, public CBofError {
|
||||
protected:
|
||||
char _szFileName[MAX_FNAME];
|
||||
Common::Stream *_stream = nullptr;
|
||||
uint32 _lFlags = CBF_DEFAULT;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
CBofFile();
|
||||
|
||||
/**
|
||||
* Open a specified file for access
|
||||
* @param pszFileName Filename
|
||||
* @param lFlags Access flags
|
||||
*/
|
||||
CBofFile(const char *pszFileName, uint32 lFlags = CBF_DEFAULT);
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~CBofFile();
|
||||
|
||||
/**
|
||||
* Open specified file into this object
|
||||
* @param pszFileName Filename
|
||||
* @param lFlags Access flags
|
||||
*/
|
||||
ErrorCode open(const char *pszFileName, uint32 lFlags = CBF_DEFAULT);
|
||||
|
||||
/**
|
||||
* Creates specified file
|
||||
* @param pszFileName Filename
|
||||
* @param lFlags Access flags
|
||||
*/
|
||||
ErrorCode create(const char *pszFileName, uint32 lFlags = CBF_DEFAULT | CBF_CREATE);
|
||||
|
||||
/**
|
||||
* Close a currently open file
|
||||
*/
|
||||
virtual ErrorCode close();
|
||||
|
||||
/**
|
||||
* Read from a currently open file
|
||||
* @param pDestBuf Destination buffer
|
||||
* @param lBytes Number of bytes
|
||||
* @return Error code
|
||||
*/
|
||||
virtual ErrorCode read(void *pDestBuf, int32 lBytes);
|
||||
|
||||
/**
|
||||
* Write to a currently open file
|
||||
* @param pSrcBuf Source buffer
|
||||
* @param lBytes Number of bytes
|
||||
* @return Error code
|
||||
*/
|
||||
virtual ErrorCode write(const void *pSrcBuf, int32 lBytes);
|
||||
|
||||
/**
|
||||
* Flushes I/O stream
|
||||
*/
|
||||
void commit();
|
||||
|
||||
/**
|
||||
* Seek to a specified location in the file
|
||||
* @return Error code
|
||||
*/
|
||||
ErrorCode seek(uint32 lPos) {
|
||||
return (setPosition(lPos));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the file pointer to the beginning of the file
|
||||
* @return Error code
|
||||
*/
|
||||
ErrorCode seekToBeginning() {
|
||||
return (setPosition(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the file pointer to the end of the file
|
||||
* @return Error code
|
||||
*/
|
||||
ErrorCode seekToEnd();
|
||||
|
||||
/**
|
||||
* Sets the current file-seek position to that specified
|
||||
* @param lPos New position
|
||||
*/
|
||||
ErrorCode setPosition(uint32 lPos);
|
||||
|
||||
/**
|
||||
* Retrieves the current seek position
|
||||
*/
|
||||
uint32 getPosition();
|
||||
|
||||
/**
|
||||
* Get the length of a file
|
||||
*/
|
||||
uint32 getLength();
|
||||
|
||||
operator Common::SeekableReadStream *() const {
|
||||
return dynamic_cast<Common::SeekableReadStream *>(_stream);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace SpaceBar
|
||||
} // namespace Bagel
|
||||
|
||||
#endif
|
||||
107
engines/bagel/spacebar/boflib/fixed.h
Normal file
107
engines/bagel/spacebar/boflib/fixed.h
Normal file
@@ -0,0 +1,107 @@
|
||||
|
||||
/* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BAGEL_BOFLIB_FIXED_H
|
||||
#define BAGEL_BOFLIB_FIXED_H
|
||||
|
||||
#include "bagel/boflib/object.h"
|
||||
#include "bagel/boflib/misc.h"
|
||||
|
||||
namespace Bagel {
|
||||
namespace SpaceBar {
|
||||
|
||||
class CBofFixed : public CBofObject {
|
||||
private:
|
||||
Fixed _lVal;
|
||||
CBofFixed(const Fixed Arg) {
|
||||
_lVal = Arg;
|
||||
}
|
||||
|
||||
public:
|
||||
// Constructors
|
||||
CBofFixed() {
|
||||
_lVal = 0L;
|
||||
}
|
||||
CBofFixed(const CBofFixed &Arg) {
|
||||
_lVal = Arg._lVal;
|
||||
}
|
||||
CBofFixed(const int Arg) {
|
||||
_lVal = (Fixed)(((long)(Arg)) << 16);
|
||||
}
|
||||
CBofFixed(const double Arg) {
|
||||
_lVal = (Fixed)(Arg * (1 << 16));
|
||||
}
|
||||
|
||||
// Operators
|
||||
// inline CBofFixed operator =(const CBofFixed& Arg) const;
|
||||
CBofFixed operator+(const CBofFixed &Arg) const {
|
||||
return _lVal + Arg._lVal;
|
||||
}
|
||||
CBofFixed operator-(const CBofFixed &Arg) const {
|
||||
return _lVal - Arg._lVal;
|
||||
}
|
||||
|
||||
CBofFixed operator*(const CBofFixed &Arg) const {
|
||||
return fixedMultiply(_lVal, Arg._lVal);
|
||||
}
|
||||
|
||||
CBofFixed operator/(const CBofFixed &Arg) const {
|
||||
return fixedDivide(_lVal, Arg._lVal);
|
||||
}
|
||||
|
||||
CBofFixed operator-=(const CBofFixed &Arg) {
|
||||
_lVal -= Arg._lVal;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CBofFixed operator+=(const CBofFixed &Arg) {
|
||||
_lVal += Arg._lVal;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CBofFixed operator*=(const CBofFixed &Arg) {
|
||||
_lVal = _lVal * Arg._lVal;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
CBofFixed operator/=(const CBofFixed &Arg) {
|
||||
_lVal = _lVal / Arg._lVal;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
CBofFixed operator=(const CBofFixed &Arg) {
|
||||
_lVal = Arg._lVal;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Conversion operators
|
||||
operator int() {
|
||||
return (int)(((int32)_lVal) >> 16);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace SpaceBar
|
||||
} // namespace Bagel
|
||||
|
||||
#endif
|
||||
1125
engines/bagel/spacebar/boflib/gfx/bitmap.cpp
Normal file
1125
engines/bagel/spacebar/boflib/gfx/bitmap.cpp
Normal file
File diff suppressed because it is too large
Load Diff
446
engines/bagel/spacebar/boflib/gfx/bitmap.h
Normal file
446
engines/bagel/spacebar/boflib/gfx/bitmap.h
Normal file
@@ -0,0 +1,446 @@
|
||||
|
||||
/* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BAGEL_BOFLIB_GFX_BMP_H
|
||||
#define BAGEL_BOFLIB_GFX_BMP_H
|
||||
|
||||
#include "graphics/managed_surface.h"
|
||||
#include "bagel/boflib/palette.h"
|
||||
#include "bagel/boflib/cache.h"
|
||||
#include "bagel/boflib/error.h"
|
||||
#include "bagel/boflib/object.h"
|
||||
#include "bagel/boflib/point.h"
|
||||
#include "bagel/boflib/rect.h"
|
||||
#include "bagel/boflib/size.h"
|
||||
#include "bagel/boflib/stdinc.h"
|
||||
|
||||
namespace Bagel {
|
||||
namespace SpaceBar {
|
||||
|
||||
// Color constants
|
||||
//
|
||||
enum {
|
||||
NOT_TRANSPARENT = -1,
|
||||
COLOR_WHITE = 255,
|
||||
COLOR_BLACK = 0
|
||||
};
|
||||
|
||||
#define CBMP_FADE_SPEED 10
|
||||
#define CBMP_FADE_SIZE 4
|
||||
|
||||
#define CBMP_CURT_SPEED 8 // Must be a power of 2
|
||||
|
||||
#define CBMP_LINE_SPEED 32 // Should be a power of 4
|
||||
|
||||
// forward declare CBofWindow
|
||||
class CBofWindow;
|
||||
|
||||
class CBofBitmap : public CBofError, public CBofObject, public CCache {
|
||||
protected:
|
||||
/**
|
||||
* Does the actual allocation for this bitmap
|
||||
* @return true is this bitmap was successfully loaded into the cache
|
||||
*/
|
||||
bool alloc() override;
|
||||
|
||||
/**
|
||||
* Frees the data used by this bitmap (removes from cache)
|
||||
*/
|
||||
void free() override;
|
||||
|
||||
//
|
||||
// data members
|
||||
//
|
||||
static bool _bUseBackdrop;
|
||||
|
||||
char _szFileName[MAX_FNAME];
|
||||
|
||||
Graphics::ManagedSurface _bitmap;
|
||||
|
||||
byte *_pBits = nullptr;
|
||||
|
||||
CBofPalette *_pPalette = nullptr;
|
||||
|
||||
int _nScanDX = 0;
|
||||
int _nDX = 0;
|
||||
int _nDY = 0;
|
||||
bool _bTopDown = false;
|
||||
|
||||
bool _bOwnPalette = false;
|
||||
bool _bReadOnly = false;
|
||||
bool _bInitialized = false;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
CBofBitmap();
|
||||
|
||||
/**
|
||||
* Constructs a CBofBitmap
|
||||
* @param dx Width of new bitmap
|
||||
* @param dy Height of new bitmap
|
||||
* @param pPalette Palette to use for this bitmap
|
||||
* @param bOwnPalette true if destructor should delete palette
|
||||
* @param pPrivateBuff
|
||||
*/
|
||||
CBofBitmap(int dx, int dy, CBofPalette *pPalette, bool bOwnPalette = false, byte *pPrivateBuff = nullptr);
|
||||
|
||||
/**
|
||||
* Constructs a CBofBitmap
|
||||
* @param pszFileName Path and Filename for Bitmap on disk
|
||||
* @param pPalette Palette to use for this bitmap
|
||||
* @param bOwnPalette true if destructor should delete palette
|
||||
*/
|
||||
CBofBitmap(const char *pszFileName, CBofPalette *pPalette = nullptr, bool bOwnPalette = false);
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~CBofBitmap();
|
||||
|
||||
/**
|
||||
* Allocates the structures needed for a CBofBitmap
|
||||
* @param pPalette Palette to be assigned into this bitmap
|
||||
*/
|
||||
ErrorCode buildBitmap(CBofPalette *pPalette);
|
||||
|
||||
/**
|
||||
* Loads the specified bitmap from disk
|
||||
* @param pszFileName Filename
|
||||
* @param pPalette Palette
|
||||
* @return Error return code
|
||||
*/
|
||||
ErrorCode loadBitmap(const char *pszFileName, CBofPalette *pPalette);
|
||||
|
||||
/**
|
||||
* Frees the data used by this bitmap
|
||||
*/
|
||||
void releaseBitmap();
|
||||
|
||||
//
|
||||
// Palette routines
|
||||
//
|
||||
|
||||
/**
|
||||
* Assigns specified palette to this bitmap
|
||||
* @param pPalette Pointer to CBofPalette to be assigned
|
||||
* @param bOwnPalette true if bitmap is to own this palette
|
||||
*/
|
||||
void setPalette(CBofPalette *pPalette, bool bOwnPalette = false);
|
||||
|
||||
CBofPalette *getPalette() {
|
||||
return _pPalette;
|
||||
}
|
||||
|
||||
void setIsOwnPalette(bool own) {
|
||||
_bOwnPalette = own;
|
||||
}
|
||||
|
||||
//
|
||||
// Misc routines
|
||||
//
|
||||
|
||||
/**
|
||||
* Returns the bit address of the (x, y) location in this bmp
|
||||
* @param x Column in _pBits
|
||||
* @param y Row in _pBits
|
||||
* @return Address of (x,y) in bitmap surface
|
||||
*/
|
||||
byte *getPixelAddress(int x, int y);
|
||||
byte *getPixelAddress(CBofPoint *pPoint) {
|
||||
return getPixelAddress(pPoint->x, pPoint->y);
|
||||
}
|
||||
|
||||
CBofSize getSize() {
|
||||
return CBofSize(_nDX, _nDY);
|
||||
}
|
||||
|
||||
CBofRect getRect() {
|
||||
return CBofRect(0, 0, _nDX - 1, _nDY - 1);
|
||||
}
|
||||
|
||||
void setReadOnly(bool bReadOnly) {
|
||||
_bReadOnly = bReadOnly;
|
||||
}
|
||||
|
||||
bool getReadOnly() {
|
||||
return _bReadOnly;
|
||||
}
|
||||
|
||||
bool isTopDown() {
|
||||
return _bTopDown;
|
||||
}
|
||||
|
||||
int width() {
|
||||
return _nDX;
|
||||
}
|
||||
|
||||
int widthBytes() {
|
||||
return _nScanDX;
|
||||
}
|
||||
|
||||
int height() {
|
||||
return _nDY;
|
||||
}
|
||||
|
||||
operator Graphics::ManagedSurface &() {
|
||||
return _bitmap;
|
||||
}
|
||||
|
||||
Graphics::ManagedSurface getSurface();
|
||||
|
||||
/**
|
||||
* Returns current bitmap's filename (if any)
|
||||
* @return Pointer to bitmap's filename
|
||||
*/
|
||||
const char *getFileName();
|
||||
|
||||
//
|
||||
// Drawing routines
|
||||
//
|
||||
/**
|
||||
* Paints some or all of the bitmap directly to the screen
|
||||
* @param pWnd Destination device for painting
|
||||
* @param x Destination column
|
||||
* @param y Destination row
|
||||
* @param pSrcRect Source rectangle from bitmap
|
||||
* @param nMaskColor Transparency color
|
||||
* @return error return code
|
||||
*/
|
||||
ErrorCode paint(CBofWindow *pWnd, int x, int y, CBofRect *pSrcRect = nullptr, int nMaskColor = NOT_TRANSPARENT);
|
||||
|
||||
/**
|
||||
* Paints some or all of the bitmap directly to the screen
|
||||
* @param pWnd Destination Device to paint to
|
||||
* @param pDstRect Destination rectangle (for stretching)
|
||||
* @param pSrcRect Source rectangle from bitmap
|
||||
* @param nMaskColor transparency color
|
||||
* @return Error return code
|
||||
*/
|
||||
ErrorCode paint(CBofWindow *pWnd, CBofRect *pDstRect = nullptr, CBofRect *pSrcRect = nullptr, int nMaskColor = NOT_TRANSPARENT);
|
||||
|
||||
/**
|
||||
* Paints some or all of the bitmap directly to the screen
|
||||
* @param pWnd Destination Device to paint to
|
||||
* @param pDstRect Destination rectangle (for stretching)
|
||||
* @param pSrcRect Source rectangle from bitmap
|
||||
* @param nMaskColor Transparency color
|
||||
* @return Error return code
|
||||
*/
|
||||
ErrorCode paintMaskBackdrop(CBofWindow *pWnd, CBofRect *pDstRect = nullptr, CBofRect *pSrcRect = nullptr, int nMaskColor = NOT_TRANSPARENT);
|
||||
|
||||
/**
|
||||
* Paints some or all of the bitmap directly to the screen
|
||||
* @param pBmp Destination bitmap to paint to
|
||||
* @param x Destination column
|
||||
* @param y Destination row
|
||||
* @param pSrcRect Source rectangle from bitmap
|
||||
* @param nMaskColor Transparency color
|
||||
* @return Error return code
|
||||
*/
|
||||
ErrorCode paint(CBofBitmap *pBmp, int x, int y, CBofRect *pSrcRect = nullptr, int nMaskColor = NOT_TRANSPARENT);
|
||||
|
||||
/**
|
||||
* Paints some or all of the bitmap directly to the screen
|
||||
* @param pBmp Destination bitmap to paint to
|
||||
* @param pDstRect Destination rectangle (for stretching)
|
||||
* @param pSrcRect Source rectangle from bitmap
|
||||
* @param nMaskColor Transparency color
|
||||
* @return Error return code.
|
||||
*/
|
||||
ErrorCode paint(CBofBitmap *pBmp, CBofRect *pDstRect = nullptr, CBofRect *pSrcRect = nullptr, int nMaskColor = NOT_TRANSPARENT);
|
||||
|
||||
//
|
||||
// Special Paint routines Optimized for specific tasks
|
||||
//
|
||||
|
||||
// Stretches 4 pixel wide
|
||||
/**
|
||||
* Stretches 4 pixel wide strips from source to destination
|
||||
* @brief The Destination rectangle MUST be divisible by 4.
|
||||
* Both bitmaps must be Bottom-Up. The Source must be smaller than the Destination.
|
||||
*
|
||||
* @param pBmp Destination bitmap to paint to
|
||||
* @param pDstRect Destination rectangle (for stretching)
|
||||
* @param pSrcRect Source rectangle from bitmap
|
||||
* @return Error return code
|
||||
*/
|
||||
ErrorCode paintStretch4(CBofBitmap *pBmp, CBofRect *pDstRect, CBofRect *pSrcRect);
|
||||
|
||||
/**
|
||||
* Stretches a multiple of 4 pixel wide strips from source to destination
|
||||
* @param pBmp Destination bitmap to paint to
|
||||
* @param pDstRect Destination rectangle (for stretching)
|
||||
* @param pSrcRect Source rectangle from bitmap
|
||||
* @param nOptSize
|
||||
* @return Error return code
|
||||
*/
|
||||
ErrorCode paintStretchOpt(CBofBitmap *pBmp, CBofRect *pDstRect, CBofRect *pSrcRect, int nOptSize);
|
||||
|
||||
/**
|
||||
* Paints some or all of the bitmap directly to the screen
|
||||
* @param pBmp Destination bitmap to paint to
|
||||
* @return Error return code
|
||||
*/
|
||||
ErrorCode paint1To1(CBofBitmap *pBmp);
|
||||
|
||||
/** Copy specified section of screen (or window) to bitmap.
|
||||
* @param pWnd Window to capture
|
||||
* @param pSrcRect Source rectangle in window
|
||||
* @param pDstRect Destination area to copy image to
|
||||
* @return Error return code
|
||||
*/
|
||||
ErrorCode captureScreen(CBofWindow *pWnd, CBofRect *pSrcRect, CBofRect *pDstRect = nullptr);
|
||||
|
||||
/**
|
||||
* Performs a "Fade" onto the specified window
|
||||
* @param pWnd Pointer to window to fade into
|
||||
* @param x Fade upper left X
|
||||
* @param y Fade upper left Y
|
||||
* @param nMaskColor Transparency color (if any)
|
||||
* @param nBlockSize Size of Fade Blocks
|
||||
* @param nSpeed Speed for fade (not implemented yet)
|
||||
* @return Error return code
|
||||
*/
|
||||
ErrorCode fadeIn(CBofWindow *pWnd, int x = 0, int y = 0, int nMaskColor = NOT_TRANSPARENT, int nBlockSize = CBMP_FADE_SIZE, int nSpeed = CBMP_FADE_SPEED);
|
||||
|
||||
ErrorCode curtain(CBofWindow *pWnd, int nSpeed = CBMP_CURT_SPEED, int nMaskColor = NOT_TRANSPARENT);
|
||||
ErrorCode fadeLines(CBofWindow *pWnd, int nSpeed = CBMP_LINE_SPEED, int nMaskColor = NOT_TRANSPARENT);
|
||||
|
||||
/**
|
||||
* Returns the color at the (x, y) location in this bmp
|
||||
* @param x X position
|
||||
* @param y Y position
|
||||
* @return Color Index of specified (x,y) location in _pBits
|
||||
*/
|
||||
byte readPixel(int x, int y);
|
||||
|
||||
/**
|
||||
* Assigns the specified color to the (x, y) location
|
||||
* @param x X position
|
||||
* @param y Y position
|
||||
* @param iColor Pixel value
|
||||
*/
|
||||
void writePixel(int x, int y, byte iColor);
|
||||
|
||||
/**
|
||||
* Writes a circle into this bitmap
|
||||
* @param x X center position
|
||||
* @param y Y center position
|
||||
* @param nRadius Radius of circle
|
||||
* @param iColor Pixel value
|
||||
*/
|
||||
void circle(int x, int y, uint16 nRadius, byte iColor);
|
||||
|
||||
/**
|
||||
* Writes a line into this bitmap
|
||||
* @param nSrcX Endpoint 1 x
|
||||
* @param nSrcY Endpoint 1 y
|
||||
* @param nDstX Endpoint 2 x
|
||||
* @param nDstY Endpoint 2 y
|
||||
* @param iColor Pixel value
|
||||
*/
|
||||
void line(int nSrcX, int nSrcY, int nDstX, int nDstY, byte iColor);
|
||||
|
||||
/**
|
||||
* Writes a line into this bitmap
|
||||
* @param pSrc Endpoint 1
|
||||
* @param pDest Endpoint 2
|
||||
* @param iColor Pixel value
|
||||
*/
|
||||
void line(CBofPoint *pSrc, CBofPoint *pDest, byte iColor);
|
||||
|
||||
/**
|
||||
* Writes a Rectangle into this bitmap
|
||||
* @param cRect Pointer to rectangle Coordinates
|
||||
* @param iColor Color of rectangle
|
||||
*/
|
||||
void drawRect(CBofRect *cRect, byte iColor);
|
||||
|
||||
/**
|
||||
* Writes a filled in Rectangle to this bitmap
|
||||
* @param cRect Pointer to rectangle Coordinates
|
||||
* @param iColor Color of rectangle
|
||||
*/
|
||||
void fillRect(CBofRect *cRect, byte iColor);
|
||||
|
||||
/**
|
||||
* Scrolls current bitmap horizontally
|
||||
* @param nPixels Number of pixels to scroll by
|
||||
* @param pRect Section of bitmap to scroll
|
||||
* @return Error return code
|
||||
*/
|
||||
ErrorCode scrollRight(int nPixels, CBofRect *pRect = nullptr);
|
||||
|
||||
|
||||
ErrorCode scrollLeft(int nPixels, CBofRect *pRect = nullptr) {
|
||||
return scrollRight(-nPixels, pRect);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scrolls current bitmap vertically
|
||||
* @param nPixels Number of pixels to scroll by
|
||||
* @return Error return code
|
||||
*/
|
||||
ErrorCode scrollUp(int nPixels);
|
||||
|
||||
static void setUseBackdrop(bool b) {
|
||||
_bUseBackdrop = b;
|
||||
}
|
||||
static bool getUseBackdrop() {
|
||||
return _bUseBackdrop;
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Misc graphics routines
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Loads specified bitmap (and possibly re-maps to palette)
|
||||
* @param pszFileName Bitmap to open
|
||||
* @param pPalette Palette for re-mapping
|
||||
* @param bSharedPal Shared palette flag
|
||||
* @return Pointer to bitmap
|
||||
*/
|
||||
extern CBofBitmap *loadBitmap(const char *pszFileName, CBofPalette *pPalette = nullptr, bool bSharedPal = false);
|
||||
|
||||
/**
|
||||
* Paints specified bitmap to specified window
|
||||
* @param pWindow Window to paint to
|
||||
* @param pszFileName Bitmap filename
|
||||
* @param pDstRect Destination area to paint to
|
||||
* @param pSrcRect Source area to paint from
|
||||
* @param pPalette Optional palette to re-map with
|
||||
* @param nMaskColor Optional transparent color
|
||||
* @return Error return code
|
||||
*/
|
||||
extern ErrorCode paintBitmap(CBofWindow *pWindow, const char *pszFileName, CBofRect *pDstRect = nullptr,
|
||||
CBofRect *pSrcRect = nullptr, CBofPalette *pPalette = nullptr, int nMaskColor = NOT_TRANSPARENT);
|
||||
|
||||
} // namespace SpaceBar
|
||||
} // namespace Bagel
|
||||
|
||||
#endif
|
||||
72
engines/bagel/spacebar/boflib/gfx/cursor.cpp
Normal file
72
engines/bagel/spacebar/boflib/gfx/cursor.cpp
Normal file
@@ -0,0 +1,72 @@
|
||||
/* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "graphics/cursorman.h"
|
||||
#include "bagel/spacebar/boflib/gfx/cursor.h"
|
||||
#include "bagel/boflib/stdinc.h"
|
||||
|
||||
namespace Bagel {
|
||||
namespace SpaceBar {
|
||||
|
||||
void CBofCursor::initialize() {
|
||||
show();
|
||||
}
|
||||
|
||||
CBofCursor::~CBofCursor() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
unLoad();
|
||||
}
|
||||
|
||||
ErrorCode CBofCursor::load() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
// kill any previous cursor
|
||||
unLoad();
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
ErrorCode CBofCursor::unLoad() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
ErrorCode CBofCursor::set() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
// TODO: This controlled the "Windows cursor" in the original game
|
||||
// ScummVM doesn't have one, so just show the arrow cursor or
|
||||
// use CursorMan accordingly
|
||||
void CBofCursor::hide() {
|
||||
//CursorMan.showMouse(false);
|
||||
}
|
||||
|
||||
void CBofCursor::show() {
|
||||
CursorMan.showMouse(true);
|
||||
}
|
||||
|
||||
} // namespace SpaceBar
|
||||
} // namespace Bagel
|
||||
51
engines/bagel/spacebar/boflib/gfx/cursor.h
Normal file
51
engines/bagel/spacebar/boflib/gfx/cursor.h
Normal file
@@ -0,0 +1,51 @@
|
||||
|
||||
/* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BAGEL_BOFLIB_GFX_CURSOR_H
|
||||
#define BAGEL_BOFLIB_GFX_CURSOR_H
|
||||
|
||||
#include "bagel/boflib/error.h"
|
||||
#include "bagel/boflib/object.h"
|
||||
|
||||
namespace Bagel {
|
||||
namespace SpaceBar {
|
||||
|
||||
class CBofCursor : public CBofObject, public CBofError {
|
||||
public:
|
||||
CBofCursor() {
|
||||
}
|
||||
~CBofCursor();
|
||||
static void initialize();
|
||||
|
||||
ErrorCode load();
|
||||
ErrorCode unLoad();
|
||||
|
||||
ErrorCode set();
|
||||
|
||||
static void show();
|
||||
static void hide();
|
||||
};
|
||||
|
||||
} // namespace SpaceBar
|
||||
} // namespace Bagel
|
||||
|
||||
#endif
|
||||
729
engines/bagel/spacebar/boflib/gfx/sprite.cpp
Normal file
729
engines/bagel/spacebar/boflib/gfx/sprite.cpp
Normal file
@@ -0,0 +1,729 @@
|
||||
/* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "bagel/spacebar/boflib/gfx/sprite.h"
|
||||
#include "bagel/boflib/misc.h"
|
||||
|
||||
namespace Bagel {
|
||||
namespace SpaceBar {
|
||||
|
||||
CBofRect *CBofSprite::_cDirtyRect;
|
||||
CBofSprite *CBofSprite::_pSpriteChain = nullptr; // Pointer to chain of linked sprites
|
||||
CBofSprite *CBofSprite::_pTouchedSprite = nullptr; // Pointer to sprite overlapped during painting
|
||||
CBofBitmap *CBofSprite::_pWorkBmp = nullptr; // Offscreen work area
|
||||
CBofPalette *CBofSprite::_pSharedPalette = nullptr; // Shared palette for ALL sprites
|
||||
int CBofSprite::_nWorkDX = 0;
|
||||
int CBofSprite::_nWorkDY = 0;
|
||||
|
||||
void CBofSprite::initialize() {
|
||||
_cDirtyRect = new CBofRect();
|
||||
_pSpriteChain = nullptr;
|
||||
_pTouchedSprite = nullptr;
|
||||
_pWorkBmp = nullptr;
|
||||
_pSharedPalette = nullptr;
|
||||
_nWorkDX = 0;
|
||||
_nWorkDY = 0;
|
||||
}
|
||||
|
||||
void CBofSprite::shutdown() {
|
||||
delete _cDirtyRect;
|
||||
}
|
||||
|
||||
void CBofSprite::openLibrary(CBofPalette *pPal) {
|
||||
// Must have a valid palette to do any sprite related stuff
|
||||
assert(pPal != nullptr);
|
||||
|
||||
clearDirtyRect();
|
||||
setSharedPalette(pPal);
|
||||
|
||||
// Set up a default work area
|
||||
setupWorkArea(200, 200);
|
||||
}
|
||||
|
||||
|
||||
void CBofSprite::closeLibrary() {
|
||||
flushSpriteChain();
|
||||
tearDownWorkArea();
|
||||
|
||||
_pSharedPalette = nullptr;
|
||||
}
|
||||
|
||||
|
||||
CBofSprite::CBofSprite() {
|
||||
_pImage = nullptr; // No initial bitmap image for the sprite
|
||||
|
||||
_cSize = CBofSize(0, 0); // There is no size to the sprite image
|
||||
_cRect.setRectEmpty(); // Rectangular bounds not yet defined
|
||||
|
||||
_cImageRect = _cRect; // Image rectangle starts same as display bounds
|
||||
_cPosition = CBofPoint(0, 0); // Default position to upper left corner of display
|
||||
_bPositioned = false; // Not yet positioned
|
||||
_bDuplicated = false; // Not sharing resources with other sprites
|
||||
_nZOrder = SPRITE_TOPMOST; // Default to top most in fore/back ground order
|
||||
_nCelCount = 1; // Number of frames in animated cel strip
|
||||
_nCelID = _nCelCount - 1; // Cel identifier not pointing at a cel
|
||||
_bAnimated = false; // Not initially animated
|
||||
_bLinked = false; // Not initially linked into the sprite chain
|
||||
|
||||
_nMaskColor = NOT_TRANSPARENT; // Default to NO transparency
|
||||
_bReadOnly = true;
|
||||
|
||||
setBlockAdvance(false); // Default always advance next sprite
|
||||
}
|
||||
|
||||
|
||||
CBofSprite::~CBofSprite() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
unlinkSprite();
|
||||
clearImage(); // Clear the sprite image bitmap and context
|
||||
}
|
||||
|
||||
|
||||
void CBofSprite::linkSprite() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
if (!_bLinked) {
|
||||
// Set for linked into chain
|
||||
_bLinked = true;
|
||||
|
||||
if (_pSpriteChain != nullptr) {
|
||||
switch (_nZOrder) {
|
||||
case SPRITE_TOPMOST:
|
||||
_pSpriteChain->addToTail(this);
|
||||
break;
|
||||
|
||||
case SPRITE_HINDMOST:
|
||||
_pSpriteChain->addToHead(this);
|
||||
_pSpriteChain = this;
|
||||
break;
|
||||
|
||||
default: {
|
||||
CBofSprite *pSprite;
|
||||
CBofSprite *pLastSprite = pSprite = _pSpriteChain;
|
||||
while (pSprite != nullptr && pSprite->_nZOrder > _nZOrder) {
|
||||
pLastSprite = pSprite;
|
||||
pSprite = (CBofSprite *)pSprite->_pNext;
|
||||
}
|
||||
pLastSprite->Insert(this);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
_pSpriteChain = this;
|
||||
}
|
||||
|
||||
// _pSpriteChain must always point to the head of the linked list
|
||||
assert(_pSpriteChain == (CBofSprite *)_pSpriteChain->getHead());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CBofSprite::unlinkSprite() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
if (_bLinked) {
|
||||
// Set for not linked into chain
|
||||
_bLinked = false;
|
||||
|
||||
if (_pSpriteChain == this)
|
||||
_pSpriteChain = (CBofSprite *)_pNext;
|
||||
|
||||
Delete();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CBofSprite::flushSpriteChain() {
|
||||
CBofSprite *pSprite = getSpriteChain();
|
||||
|
||||
// Cycle getting head of chain, un-linking it and then deleting it
|
||||
while (pSprite != nullptr) {
|
||||
pSprite->unlinkSprite();
|
||||
delete pSprite;
|
||||
pSprite = getSpriteChain();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CBofSprite::setupWorkArea(int dx, int dy) {
|
||||
// Do we already have a work area?
|
||||
if (_pWorkBmp != nullptr) {
|
||||
// Yes, so lets tear it down before we start a new one
|
||||
tearDownWorkArea();
|
||||
}
|
||||
|
||||
// Create an offscreen bitmap where we do all the work;
|
||||
_pWorkBmp = new CBofBitmap(dx, dy, _pSharedPalette);
|
||||
_nWorkDX = dx;
|
||||
_nWorkDY = dy;
|
||||
}
|
||||
|
||||
|
||||
void CBofSprite::tearDownWorkArea() {
|
||||
delete _pWorkBmp;
|
||||
_pWorkBmp = nullptr;
|
||||
}
|
||||
|
||||
|
||||
CBofSprite *CBofSprite::duplicateSprite() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
// Create an object for the sprite
|
||||
CBofSprite *pSprite = new CBofSprite;
|
||||
duplicateSprite(pSprite);
|
||||
|
||||
return pSprite;
|
||||
}
|
||||
|
||||
|
||||
void CBofSprite::duplicateSprite(CBofSprite *pSprite) {
|
||||
if (!isValidObject(this) || (pSprite == nullptr))
|
||||
error("duplicateSprite - Invalid source or destination sprite");
|
||||
|
||||
pSprite->_pImage = _pImage;
|
||||
pSprite->_cRect = _cRect;
|
||||
pSprite->_cImageRect = _cImageRect;
|
||||
pSprite->_cSize = _cSize;
|
||||
pSprite->_cPosition = _cPosition;
|
||||
pSprite->_nZOrder = _nZOrder;
|
||||
pSprite->_nCelID = _nCelID;
|
||||
pSprite->_nCelCount = _nCelCount;
|
||||
pSprite->_bAnimated = _bAnimated;
|
||||
pSprite->_nMaskColor = _nMaskColor;
|
||||
|
||||
pSprite->_bDuplicated = true; // Mark it as a sprite with shared resources
|
||||
}
|
||||
|
||||
|
||||
bool CBofSprite::loadSprite(const char *pszPathName, int nCels) {
|
||||
assert(isValidObject(this));
|
||||
assert(pszPathName != nullptr);
|
||||
assert(nCels >= 1);
|
||||
|
||||
// Create an object for the sprite's image
|
||||
CBofBitmap *pBitmap = new CBofBitmap(pszPathName, _pSharedPalette);
|
||||
return loadSprite(pBitmap, nCels);
|
||||
}
|
||||
|
||||
|
||||
bool CBofSprite::loadSprite(CBofBitmap *pBitmap, int nCels) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
// Can't load an invalid bitmap
|
||||
assert(pBitmap != nullptr);
|
||||
assert(nCels >= 1);
|
||||
|
||||
clearImage(); // Clear out any/all existing bitmaps, palettes,
|
||||
|
||||
_pImage = pBitmap; // Save pointer to bitmap
|
||||
|
||||
pBitmap->setReadOnly(_bReadOnly);
|
||||
|
||||
_cSize = pBitmap->getSize();
|
||||
|
||||
_cRect.setRect(0, 0, _cSize.cx - 1, _cSize.cy - 1);
|
||||
_cImageRect.setRect(0, 0, _cSize.cx - 1, _cSize.cy - 1);
|
||||
_nCelCount = 1;
|
||||
_nCelID = _nCelCount - 1;
|
||||
|
||||
if (nCels != 1) {
|
||||
setupCels(nCels);
|
||||
|
||||
// Assume it's animated
|
||||
_bAnimated = true;
|
||||
}
|
||||
|
||||
return true; // Return success
|
||||
}
|
||||
|
||||
|
||||
bool CBofSprite::setupCels(const int nCels) {
|
||||
assert(isValidObject(this));
|
||||
assert(nCels > 0);
|
||||
|
||||
_nCelCount = nCels; // Set cel count
|
||||
_nCelID = _nCelCount - 1; // No current cel
|
||||
int nStripWidth = _cSize.cx; // Temp place toRetain cell strip pixel length
|
||||
_cSize.cx /= nCels; // Calculate width of a cel
|
||||
|
||||
if (_cSize.cx * nCels == nStripWidth) { // Verify we have an even multiple
|
||||
_cRect.right = _cRect.left + _cSize.cx; // Reset sprite rectangular bounds
|
||||
_cRect.bottom = _cRect.top + _cSize.cy; // ... based on cel dimensions
|
||||
_cImageRect.setRect(0, 0, _cSize.cx - 1, _cSize.cy - 1); // Set bounds for first cel in strip
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void CBofSprite::nextCel() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
// verify old cel id
|
||||
assert(_nCelID >= 0 && _nCelID < _nCelCount);
|
||||
|
||||
if (getBlockAdvance() == false) {
|
||||
if (++_nCelID >= _nCelCount)
|
||||
_nCelID = 0;
|
||||
|
||||
setCel(_nCelID);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CBofSprite::prevCel() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
// verify old cel id
|
||||
assert(_nCelID >= 0 && _nCelID < _nCelCount);
|
||||
|
||||
if (--_nCelID < 0)
|
||||
_nCelID = _nCelCount - 1;
|
||||
|
||||
setCel(_nCelID);
|
||||
}
|
||||
|
||||
|
||||
bool CBofSprite::paintSprite(CBofWindow *pWnd, const int x, const int y) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
// Can't paint to a non-existent window
|
||||
assert(pWnd != nullptr);
|
||||
|
||||
// The window MUST have a backdrop
|
||||
assert(pWnd->getBackdrop() != nullptr);
|
||||
|
||||
batchPaint(x, y);
|
||||
|
||||
updateDirtyRect(pWnd, this);
|
||||
|
||||
return !errorOccurred();
|
||||
}
|
||||
|
||||
|
||||
bool CBofSprite::paintSprite(CBofBitmap *pBmp, const int x, const int y) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
// Can't paint to a non-existent window
|
||||
assert(pBmp != nullptr);
|
||||
|
||||
batchPaint(x, y);
|
||||
updateDirtyRect(pBmp, this);
|
||||
|
||||
return !errorOccurred();
|
||||
}
|
||||
|
||||
|
||||
bool CBofSprite::paintCel(CBofWindow *pWnd, int nCelId, const int x, const int y) {
|
||||
setCel(nCelId - 1);
|
||||
return paintSprite(pWnd, x, y);
|
||||
}
|
||||
|
||||
|
||||
bool CBofSprite::paintCel(CBofBitmap *pBmp, int nCelId, const int x, const int y) {
|
||||
setCel(nCelId - 1);
|
||||
return paintSprite(pBmp, x, y);
|
||||
}
|
||||
|
||||
|
||||
void CBofSprite::batchPaint(const int x, const int y) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
CBofRect cDstRect;
|
||||
|
||||
// Default to no sprite being overlapped by this painting operation
|
||||
_pTouchedSprite = nullptr;
|
||||
|
||||
// Calculate destination rectangle
|
||||
cDstRect.setRect(x, y, x + _cSize.cx - 1, y + _cSize.cy - 1);
|
||||
|
||||
// Add the destination position to the dirty rectangle list
|
||||
addToDirtyRect(&cDstRect);
|
||||
|
||||
// If the sprite is already on screen, then we must also add it's old
|
||||
// current location to the dirty rect list so that it is erase properly
|
||||
if (_bPositioned) {
|
||||
addToDirtyRect(&_cRect);
|
||||
}
|
||||
|
||||
// Now establish the sprite's new position
|
||||
setPosition(x, y);
|
||||
|
||||
if (_bAnimated && (_nCelCount > 1))
|
||||
// Advance to the next cel in the strip
|
||||
nextCel();
|
||||
}
|
||||
|
||||
bool CBofSprite::updateDirtyRect(CBofWindow *pWnd, CBofSprite *pPrimarySprite) {
|
||||
assert(pWnd != nullptr);
|
||||
|
||||
// The window MUST have a backdrop associated with it. If that's not feasible, then
|
||||
// use CSprites instead of CBofSprites
|
||||
assert(pWnd->getBackdrop() != nullptr);
|
||||
|
||||
//
|
||||
// Repaint the contents of the specified rectangle
|
||||
//
|
||||
|
||||
CBofBitmap *pBackdrop = pWnd->getBackdrop();
|
||||
if (pBackdrop != nullptr) {
|
||||
|
||||
CBofRect *pRect = _cDirtyRect;
|
||||
if (pRect->width() != 0 && pRect->height() != 0) {
|
||||
// Need a work area
|
||||
CBofBitmap *pWork = _pWorkBmp;
|
||||
int dx = pRect->width();
|
||||
int dy = pRect->height();
|
||||
|
||||
bool bTempWorkArea = false;
|
||||
if ((pWork == nullptr) || (dx > _nWorkDX) || (dy > _nWorkDY)) {
|
||||
|
||||
bTempWorkArea = true;
|
||||
pWork = new CBofBitmap(dx, dy, _pSharedPalette);
|
||||
}
|
||||
pWork->lock();
|
||||
|
||||
// Paint the background into the work area
|
||||
pBackdrop->paint(pWork, 0, 0, pRect);
|
||||
|
||||
// Only need to search the sprite list if current sprite is linked
|
||||
CBofSprite *pSprite = pPrimarySprite;
|
||||
if (pPrimarySprite == nullptr || pPrimarySprite->_bLinked) {
|
||||
pSprite = _pSpriteChain;
|
||||
}
|
||||
|
||||
CBofRect cRect, cSrcRect;
|
||||
// Run through the sprite list
|
||||
while (pSprite != nullptr) {
|
||||
// and paint each partial sprite overlap to the work area
|
||||
if (pSprite->_bPositioned && cRect.intersectRect(&pSprite->_cRect, pRect)) {
|
||||
if (pPrimarySprite != pSprite)
|
||||
_pTouchedSprite = pSprite;
|
||||
|
||||
cSrcRect = cRect - pSprite->_cRect.topLeft();
|
||||
cSrcRect += pSprite->_cImageRect.topLeft();
|
||||
cRect -= pRect->topLeft();
|
||||
|
||||
pSprite->_pImage->paint(pWork, &cRect, &cSrcRect, pSprite->_nMaskColor);
|
||||
}
|
||||
pSprite = (CBofSprite *)pSprite->_pNext;
|
||||
}
|
||||
|
||||
// Paint final outcome to the screen
|
||||
cSrcRect.setRect(0, 0, pRect->width() - 1, pRect->height() - 1);
|
||||
pWork->paint(pWnd, pRect, &cSrcRect);
|
||||
|
||||
pWork->unlock();
|
||||
|
||||
if (bTempWorkArea) {
|
||||
delete pWork;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clearDirtyRect();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CBofSprite::updateDirtyRect(CBofBitmap *pBmp, CBofSprite *pPrimarySprite) {
|
||||
assert(pBmp != nullptr);
|
||||
|
||||
//
|
||||
// Repaint the contents of the specified rectangle
|
||||
//
|
||||
CBofRect *pRect = getDirtyRect();
|
||||
|
||||
// Only need to search the sprite list if current sprite is linked
|
||||
CBofSprite *pSprite = pPrimarySprite;
|
||||
if (pPrimarySprite == nullptr || pPrimarySprite->_bLinked) {
|
||||
pSprite = _pSpriteChain;
|
||||
}
|
||||
|
||||
CBofRect cRect;
|
||||
// Run through the sprite list
|
||||
while (pSprite != nullptr) {
|
||||
// and paint each partial sprite overlap to the work area
|
||||
if (pSprite->_bPositioned && cRect.intersectRect(&pSprite->_cRect, pRect)) {
|
||||
|
||||
if (pPrimarySprite != pSprite)
|
||||
_pTouchedSprite = pSprite;
|
||||
|
||||
CBofRect cSrcRect = cRect - pSprite->_cRect.topLeft();
|
||||
cSrcRect += pSprite->_cImageRect.topLeft();
|
||||
|
||||
pSprite->_pImage->paint(pBmp, &cRect, &cSrcRect, pSprite->_nMaskColor);
|
||||
}
|
||||
pSprite = (CBofSprite *)pSprite->_pNext;
|
||||
}
|
||||
|
||||
clearDirtyRect();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void CBofSprite::addToDirtyRect(CBofRect *pRect) {
|
||||
assert(pRect != nullptr);
|
||||
|
||||
CBofRect cRect;
|
||||
|
||||
if (_cDirtyRect->isRectEmpty()) {
|
||||
cRect = *pRect;
|
||||
} else {
|
||||
cRect.unionRect(_cDirtyRect, pRect);
|
||||
}
|
||||
*_cDirtyRect = cRect;
|
||||
}
|
||||
|
||||
|
||||
void CBofSprite::setCel(const int nCelID) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
// All sprites must have at least 1 frame
|
||||
assert(_nCelCount > 0);
|
||||
|
||||
if (_nCelID != nCelID) {
|
||||
_nCelID = nCelID % _nCelCount;
|
||||
if ((_nCelID != 0) && (nCelID < 0)) {
|
||||
_nCelID = _nCelCount + _nCelID;
|
||||
}
|
||||
}
|
||||
|
||||
// Verify new cel id
|
||||
assert(_nCelID >= 0 && _nCelID < _nCelCount);
|
||||
|
||||
_cImageRect.left = _nCelID * _cSize.cx;
|
||||
_cImageRect.right = _cImageRect.left + _cSize.cx;
|
||||
}
|
||||
|
||||
bool CBofSprite::eraseSprite(CBofWindow *pWnd) {
|
||||
assert(isValidObject(this));
|
||||
assert(pWnd != nullptr);
|
||||
|
||||
batchErase();
|
||||
updateDirtyRect(pWnd);
|
||||
|
||||
return !errorOccurred();
|
||||
}
|
||||
|
||||
|
||||
void CBofSprite::batchErase() {
|
||||
if (_bPositioned) {
|
||||
_bPositioned = false;
|
||||
|
||||
addToDirtyRect(&_cRect);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool CBofSprite::testInterception(CBofSprite *pTestSprite, CBofPoint *pPoint) {
|
||||
assert(isValidObject(this));
|
||||
assert(pTestSprite != nullptr);
|
||||
|
||||
// Punt if no interception allowed
|
||||
if (pTestSprite != nullptr) {
|
||||
// be sure to not test against ourself
|
||||
if (this != pTestSprite) {
|
||||
|
||||
CBofRect overlapRect; // Area of overlap between rectangles
|
||||
// Use simple rectangle screening first
|
||||
if (overlapRect.intersectRect(&_cRect, &pTestSprite->_cRect)) {
|
||||
// ... and if that succeeds, see if we
|
||||
// ... have image masks that overlap
|
||||
if ((_nMaskColor == NOT_TRANSPARENT) || (pTestSprite->_nMaskColor == NOT_TRANSPARENT) || spritesOverlap(pTestSprite, pPoint)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
CBofSprite *CBofSprite::interception(CBofRect *pNewRect, CBofSprite *pTestSprite) {
|
||||
assert(isValidObject(this));
|
||||
assert(pNewRect != nullptr);
|
||||
|
||||
// Get first sprite to be tested
|
||||
CBofSprite *pSprite = pTestSprite;
|
||||
|
||||
// Thumb through the sprite chain
|
||||
while (pSprite != nullptr) {
|
||||
// be sure to not test against ourself
|
||||
// ... and only test against overlapping sprites
|
||||
if (this != pSprite) {
|
||||
CBofRect overlapRect; // Area of overlap between rectangles
|
||||
// Sprites touch if their rectangles intersect.
|
||||
// does our sprite overlap another?
|
||||
if (overlapRect.intersectRect(pNewRect, &pSprite->_cRect))
|
||||
// ... if so return a pointer to it
|
||||
return pSprite;
|
||||
}
|
||||
|
||||
// Fetch next sprite in chain for testing
|
||||
pSprite = (CBofSprite *)pSprite->_pNext;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
CBofSprite *CBofSprite::interception(CBofSprite *pTestSprite) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
CBofSprite *pSprite = pTestSprite; // Get first sprite to be tested
|
||||
|
||||
while (pSprite != nullptr) { // Thumb through the entire sprite collection
|
||||
|
||||
if (testInterception(pSprite, nullptr)) // ... testing against each sprite in turn
|
||||
return pSprite; // found an interception
|
||||
|
||||
pSprite = (CBofSprite *)pSprite->_pNext; // fetch next sprite in chain for testing
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
bool CBofSprite::spritesOverlap(CBofSprite *pSprite, CBofPoint *pPoint) {
|
||||
assert(isValidObject(this));
|
||||
assert(pSprite != nullptr);
|
||||
|
||||
// Assume no overlap
|
||||
bool bHit = false;
|
||||
|
||||
// If the sprite's rectangles overlap
|
||||
CBofRect overlapRect;
|
||||
if (overlapRect.intersectRect(&_cRect, &pSprite->_cRect)) {
|
||||
int32 dx = overlapRect.width();
|
||||
int32 dy = overlapRect.height();
|
||||
|
||||
int32 x1 = overlapRect.left - _cRect.left + _cImageRect.left;
|
||||
int32 y1 = overlapRect.top - _cRect.top + _cImageRect.top;
|
||||
|
||||
int32 x2 = overlapRect.left - pSprite->_cRect.left + pSprite->_cImageRect.left;
|
||||
int32 y2 = overlapRect.top - pSprite->_cRect.top + pSprite->_cImageRect.top;
|
||||
|
||||
int32 dx1 = _pImage->widthBytes();
|
||||
int32 dx2 = pSprite->_pImage->widthBytes();
|
||||
|
||||
byte m1 = (byte)_nMaskColor;
|
||||
byte m2 = (byte)pSprite->_nMaskColor;
|
||||
|
||||
// Lock down these bitmaps
|
||||
_pImage->lock();
|
||||
pSprite->_pImage->lock();
|
||||
|
||||
byte *pDib1 = (byte *)_pImage->getPixelAddress((int)x1, (int)y1);
|
||||
byte *pDib2 = (byte *)pSprite->_pImage->getPixelAddress((int)x2, (int)y2);
|
||||
|
||||
if (!_pImage->isTopDown()) {
|
||||
dx1 = -dx1;
|
||||
}
|
||||
|
||||
if (!pSprite->_pImage->isTopDown()) {
|
||||
dx2 = -dx2;
|
||||
}
|
||||
|
||||
for (int32 y = 0; y < dy; y++) {
|
||||
byte *pPtr1 = pDib1;
|
||||
byte *pPtr2 = pDib2;
|
||||
|
||||
for (int32 x = 0; x < dx; x++) {
|
||||
if ((*pPtr1 != m1) && (*pPtr2 != m2)) {
|
||||
if (pPoint != nullptr) {
|
||||
pPoint->x = (int)x;
|
||||
pPoint->y = (int)y;
|
||||
}
|
||||
|
||||
bHit = true;
|
||||
goto endroutine;
|
||||
}
|
||||
|
||||
pPtr1++;
|
||||
pPtr2++;
|
||||
}
|
||||
|
||||
pDib1 += dx1;
|
||||
pDib2 += dx2;
|
||||
}
|
||||
}
|
||||
|
||||
endroutine:
|
||||
// Don't need access to these bitmaps any more
|
||||
pSprite->_pImage->unlock();
|
||||
_pImage->unlock();
|
||||
|
||||
return bHit;
|
||||
}
|
||||
|
||||
|
||||
void CBofSprite::setPosition(int x, int y) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
// Now have a real location establish the new location of the sprite
|
||||
// and setup the bitmap's bounding rectangle
|
||||
_bPositioned = true;
|
||||
_cPosition.x = x;
|
||||
_cPosition.y = y;
|
||||
_cRect.setRect(_cPosition.x, _cPosition.y, _cPosition.x + _cSize.cx - 1, _cPosition.y + _cSize.cy - 1);
|
||||
}
|
||||
|
||||
|
||||
void CBofSprite::clearImage() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
if (!_bDuplicated && (_pImage != nullptr)) {
|
||||
delete _pImage;
|
||||
}
|
||||
|
||||
_pImage = nullptr;
|
||||
}
|
||||
|
||||
|
||||
void CBofSprite::setSharedPalette(CBofPalette *pPal) {
|
||||
assert(pPal != nullptr);
|
||||
|
||||
_pSharedPalette = pPal;
|
||||
}
|
||||
|
||||
void CBofSprite::setZOrder(int nValue) {
|
||||
assert(isValidObject(this));
|
||||
assert(nValue >= SPRITE_TOPMOST && nValue <= SPRITE_HINDMOST);
|
||||
|
||||
_nZOrder = nValue;
|
||||
|
||||
// Relinking this sprite after setting it's new Z-Order will
|
||||
// add the sprite to the correct Z-Order sorted location (Insertion Sort)
|
||||
if (_bLinked) {
|
||||
unlinkSprite();
|
||||
linkSprite();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace SpaceBar
|
||||
} // namespace Bagel
|
||||
237
engines/bagel/spacebar/boflib/gfx/sprite.h
Normal file
237
engines/bagel/spacebar/boflib/gfx/sprite.h
Normal file
@@ -0,0 +1,237 @@
|
||||
/* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BAGEL_BOFLIB_GFX_SPRITE_H
|
||||
#define BAGEL_BOFLIB_GFX_SPRITE_H
|
||||
|
||||
#include "bagel/spacebar/boflib/gfx/bitmap.h"
|
||||
#include "bagel/boflib/object.h"
|
||||
#include "bagel/boflib/palette.h"
|
||||
#include "bagel/spacebar/boflib/gui/window.h"
|
||||
|
||||
namespace Bagel {
|
||||
namespace SpaceBar {
|
||||
|
||||
#define SPRITE_TOPMOST 0
|
||||
#define SPRITE_FOREGROUND 64
|
||||
#define SPRITE_MIDDLE 128
|
||||
#define SPRITE_BACKGROUND 192
|
||||
#define SPRITE_HINDMOST 255
|
||||
|
||||
class CBofSprite : public CBofError, public CBofObject, public CLList {
|
||||
public:
|
||||
static void initialize();
|
||||
static void shutdown();
|
||||
|
||||
// Constructors
|
||||
CBofSprite();
|
||||
|
||||
// Destructors
|
||||
virtual ~CBofSprite();
|
||||
|
||||
//////////////////////////////////////////
|
||||
|
||||
// Implementation
|
||||
CBofSprite *duplicateSprite();
|
||||
void duplicateSprite(CBofSprite *pSprite);
|
||||
|
||||
bool loadSprite(const char *pszPathName, int nCels = 1);
|
||||
bool loadSprite(CBofBitmap *pBitmap, int nCels = 1);
|
||||
|
||||
bool paintSprite(CBofBitmap *pBmp, int x, int y);
|
||||
bool paintSprite(CBofBitmap *pBmp, CBofPoint point) {
|
||||
return paintSprite(pBmp, point.x, point.y);
|
||||
}
|
||||
|
||||
bool paintSprite(CBofWindow *pWnd, int x, int y);
|
||||
bool paintSprite(CBofWindow *pWnd, CBofPoint point) {
|
||||
return paintSprite(pWnd, point.x, point.y);
|
||||
}
|
||||
|
||||
bool paintCel(CBofWindow *pWnd, int nCelId, int x, int y);
|
||||
bool paintCel(CBofBitmap *pBmp, int nCelId, int x, int y);
|
||||
|
||||
void batchPaint(int, int y);
|
||||
void batchErase();
|
||||
|
||||
bool setupCels(int nCels);
|
||||
void setCel(int nCelID);
|
||||
|
||||
void nextCel();
|
||||
void prevCel();
|
||||
|
||||
bool refreshSprite(CBofBitmap *pBmp) {
|
||||
return paintSprite(pBmp, _cPosition.x, _cPosition.y);
|
||||
}
|
||||
|
||||
bool refreshSprite(CBofWindow *pWnd) {
|
||||
return paintSprite(pWnd, _cPosition.x, _cPosition.y);
|
||||
}
|
||||
|
||||
bool eraseSprite(CBofWindow *pWnd);
|
||||
|
||||
// Notice how there is no eraseSprite for a CBofBitmap - that's because
|
||||
// sprites no longer retain their background, so there would be no way
|
||||
// to restore the background, and that's all eraseSprite does.
|
||||
|
||||
CBofSprite *interception(CBofRect *newRect, CBofSprite *pTestSprite);
|
||||
CBofSprite *interception(CBofSprite *pTestSprite);
|
||||
|
||||
CBofSprite *interception() {
|
||||
return interception(_pSpriteChain);
|
||||
}
|
||||
|
||||
CBofSprite *interception(CBofRect *newRect) {
|
||||
return interception(newRect, _pSpriteChain);
|
||||
}
|
||||
|
||||
bool testInterception(CBofSprite *pTestSprite, CBofPoint *pPoint = nullptr);
|
||||
|
||||
void setPosition(int x, int y);
|
||||
|
||||
CBofPoint getPosition() const {
|
||||
return _cPosition;
|
||||
}
|
||||
|
||||
CBofSize getSize() const {
|
||||
return _cSize;
|
||||
}
|
||||
|
||||
CBofRect getRect() const {
|
||||
return _cRect;
|
||||
}
|
||||
|
||||
int height() const {
|
||||
return _cRect.height();
|
||||
}
|
||||
|
||||
int width() const {
|
||||
return _cRect.width();
|
||||
}
|
||||
|
||||
void setMaskColor(int nColor) {
|
||||
_nMaskColor = nColor;
|
||||
}
|
||||
|
||||
int getMaskColor() const {
|
||||
return _nMaskColor;
|
||||
}
|
||||
|
||||
byte readPixel(int x, int y) const {
|
||||
return _pImage->readPixel(x, y);
|
||||
}
|
||||
|
||||
void setZOrder(int nValue);
|
||||
|
||||
int getCelCount() const {
|
||||
return _nCelCount;
|
||||
}
|
||||
int getCelIndex() const {
|
||||
return _nCelID;
|
||||
}
|
||||
|
||||
void setAnimated(bool bAnimated) {
|
||||
_bAnimated = bAnimated;
|
||||
}
|
||||
bool getAnimated() const {
|
||||
return _bAnimated;
|
||||
}
|
||||
|
||||
void linkSprite();
|
||||
void unlinkSprite();
|
||||
|
||||
const char *getFileName() const {
|
||||
return _pImage->getFileName();
|
||||
}
|
||||
|
||||
static void openLibrary(CBofPalette *pPal);
|
||||
static void closeLibrary();
|
||||
|
||||
static void setSharedPalette(CBofPalette *pPalette);
|
||||
|
||||
static CBofSprite *getSpriteChain() {
|
||||
return _pSpriteChain;
|
||||
}
|
||||
|
||||
static bool updateDirtyRect(CBofWindow *pWnd, CBofSprite *pPrimarySprite = nullptr);
|
||||
static bool updateDirtyRect(CBofBitmap *pBmp, CBofSprite *pPrimarySprite = nullptr);
|
||||
static void addToDirtyRect(CBofRect *pRect);
|
||||
static void clearDirtyRect() {
|
||||
_cDirtyRect->setRectEmpty();
|
||||
}
|
||||
|
||||
static CBofRect *getDirtyRect() {
|
||||
return _cDirtyRect;
|
||||
}
|
||||
|
||||
static void flushSpriteChain();
|
||||
|
||||
static void setupWorkArea(int dx, int dy);
|
||||
static void tearDownWorkArea();
|
||||
|
||||
// Add a method for allowing callers of this object to block
|
||||
// next cell advancement
|
||||
|
||||
void setBlockAdvance(bool b = true) {
|
||||
_bBlockAdvance = b;
|
||||
}
|
||||
bool getBlockAdvance() const {
|
||||
return _bBlockAdvance;
|
||||
}
|
||||
|
||||
private:
|
||||
void clearImage();
|
||||
|
||||
bool spritesOverlap(CBofSprite *pSprite, CBofPoint *pPoint = nullptr);
|
||||
bool _bBlockAdvance; // Allow block next cell.
|
||||
public:
|
||||
CBofBitmap *_pImage; // Bitmap for the sprite
|
||||
|
||||
protected:
|
||||
CBofPoint _cPosition; // Upper left corner of sprite on display
|
||||
CBofSize _cSize; // dx/dy size of the sprite bitmap
|
||||
CBofRect _cRect; // Bounding rectangle on display
|
||||
CBofRect _cImageRect; // Bounding rectangle within image bitmap
|
||||
|
||||
int _nMaskColor; // Transparent color index for this sprite
|
||||
int _nZOrder; // Foreground / background order
|
||||
int _nCelID; // Index of current cel image
|
||||
int _nCelCount; // Number of cels in the animation strip
|
||||
|
||||
bool _bDuplicated : 1; // Shares bitmaps with some other sprite
|
||||
bool _bPositioned : 1; // Whether sprite has been positioned yet
|
||||
bool _bAnimated : 1; // Whether cel advance occurs when painting
|
||||
bool _bLinked : 1; // Whether sprite is linked into the chain
|
||||
bool _bReadOnly : 1; // Whether image is read only or not
|
||||
|
||||
static CBofRect *_cDirtyRect;
|
||||
static CBofSprite *_pSpriteChain; // Pointer to linked chain of sprites
|
||||
static CBofSprite *_pTouchedSprite; // Sprite touched during painting operation
|
||||
static CBofBitmap *_pWorkBmp; // Offscreen work area
|
||||
static CBofPalette *_pSharedPalette; // Shared palette for ALL sprites
|
||||
static int _nWorkDX;
|
||||
static int _nWorkDY;
|
||||
};
|
||||
|
||||
} // namespace SpaceBar
|
||||
} // namespace Bagel
|
||||
|
||||
#endif
|
||||
476
engines/bagel/spacebar/boflib/gfx/text.cpp
Normal file
476
engines/bagel/spacebar/boflib/gfx/text.cpp
Normal file
@@ -0,0 +1,476 @@
|
||||
/* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "graphics/fonts/ttf.h"
|
||||
#include "bagel/spacebar/boflib/app.h"
|
||||
#include "bagel/spacebar/boflib/gfx/text.h"
|
||||
|
||||
namespace Bagel {
|
||||
namespace SpaceBar {
|
||||
|
||||
#define START_SIZE 8
|
||||
#define MONO_FONT "LiberationMono-Regular.ttf"
|
||||
#define SERIF_FONT_REGULAR "LiberationSans-Regular.ttf"
|
||||
#define SERIF_FONT_BOLD "LiberationSans-Bold.ttf"
|
||||
#define TAB_SIZE 50
|
||||
|
||||
int CBofText::_tabStop;
|
||||
bool CBofText::_initialized;
|
||||
Graphics::Font *CBofText::_defaultFonts[NUM_POINT_SIZES];
|
||||
Graphics::Font *CBofText::_fixedFonts[NUM_POINT_SIZES];
|
||||
|
||||
|
||||
ErrorCode CBofText::initialize() {
|
||||
_initialized = true;
|
||||
_tabStop = 20; // tabstops every 20 pixels
|
||||
Common::fill(_defaultFonts, _defaultFonts + NUM_POINT_SIZES,
|
||||
(Graphics::Font *)nullptr);
|
||||
Common::fill(_fixedFonts, _fixedFonts + NUM_POINT_SIZES,
|
||||
(Graphics::Font *)nullptr);
|
||||
|
||||
return ERR_NONE;
|
||||
}
|
||||
|
||||
ErrorCode CBofText::shutdown() {
|
||||
for (int i = 0; i < NUM_POINT_SIZES; i++) {
|
||||
delete _defaultFonts[i];
|
||||
delete _fixedFonts[i];
|
||||
}
|
||||
|
||||
_initialized = false;
|
||||
|
||||
return ERR_NONE;
|
||||
}
|
||||
|
||||
CBofText::CBofText() {
|
||||
initializeFields(); // Initialize stuff
|
||||
}
|
||||
|
||||
CBofText::CBofText(const CBofRect *pRect, int nJustify, uint32 nFormatFlags) {
|
||||
// Can't access null pointers
|
||||
assert(pRect != nullptr);
|
||||
|
||||
// Initialize stuff
|
||||
initializeFields();
|
||||
|
||||
// Build the work areas
|
||||
setupText(pRect, nJustify, nFormatFlags);
|
||||
}
|
||||
|
||||
CBofText::~CBofText() {
|
||||
delete _pWork;
|
||||
_pWork = nullptr;
|
||||
|
||||
delete _pBackground;
|
||||
_pBackground = nullptr;
|
||||
}
|
||||
|
||||
void CBofText::initializeFields() {
|
||||
_pBackground = nullptr;
|
||||
_pWork = nullptr;
|
||||
_bSaved = false;
|
||||
|
||||
_cPosition = CBofPoint(0, 0);
|
||||
_cSize = CBofSize(0, 0);
|
||||
_cRect.setRect(0, 0, 0, 0);
|
||||
|
||||
_cShadowColor = RGB(0, 0, 0);
|
||||
_nShadow_DX = 0;
|
||||
_nShadow_DY = 0;
|
||||
|
||||
_nJustify = JUSTIFY_LEFT;
|
||||
|
||||
_nFormatFlags = FORMAT_DEFAULT;
|
||||
_bMultiLine = false;
|
||||
|
||||
_nCurSize = 10;
|
||||
_nCurWeight = TEXT_DONTCARE;
|
||||
_cTextColor = CTEXT_COLOR;
|
||||
}
|
||||
|
||||
ErrorCode CBofText::setupText(const CBofRect *pRect, int nJustify, uint32 nFormatFlags) {
|
||||
// Can't access null pointers
|
||||
assert(pRect != nullptr);
|
||||
|
||||
_nJustify = nJustify;
|
||||
|
||||
// Setup the fields for location and size of the text area
|
||||
_cRect = *pRect;
|
||||
_cSize.cx = _cRect.width();
|
||||
_cSize.cy = _cRect.height();
|
||||
|
||||
delete _pWork;
|
||||
_pWork = nullptr;
|
||||
|
||||
delete _pBackground;
|
||||
_pBackground = nullptr;
|
||||
|
||||
CBofPalette *pPalette = CBofApp::getApp()->getPalette();
|
||||
|
||||
// Create a bitmap to serve as our work area as we output text
|
||||
_pWork = new CBofBitmap(_cSize.cx, _cSize.cy, pPalette);
|
||||
|
||||
// Create a bitmap to hold the background we overwrite
|
||||
_pBackground = new CBofBitmap(_cSize.cx, _cSize.cy, pPalette);
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
ErrorCode CBofText::setupTextOpt(const CBofRect *pRect, int nJustify, uint32 nFormatFlags) {
|
||||
// Can't access null pointers
|
||||
assert(pRect != nullptr);
|
||||
|
||||
_nJustify = nJustify;
|
||||
_nFormatFlags = nFormatFlags;
|
||||
|
||||
// Setup the fields for location and size of the text area
|
||||
_cRect = *pRect;
|
||||
_cSize.cx = _cRect.width();
|
||||
_cSize.cy = _cRect.height();
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
ErrorCode CBofText::erase(CBofWindow *pWnd) {
|
||||
// Can't access null pointers
|
||||
assert(pWnd != nullptr);
|
||||
|
||||
if (_pBackground != nullptr && _bSaved) {
|
||||
// Simply splat the background art back where it came from
|
||||
_errCode = _pBackground->paint(pWnd, &_cRect);
|
||||
}
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
ErrorCode CBofText::erase(CBofBitmap *pBmp) {
|
||||
// Can't access null pointers
|
||||
assert(pBmp != nullptr);
|
||||
|
||||
if (_pBackground != nullptr && _bSaved) {
|
||||
// Simply splat the background art back where it came from
|
||||
_errCode = _pBackground->paint(pBmp, &_cRect);
|
||||
}
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
ErrorCode CBofText::display(CBofWindow *pWnd, const char *pszText, const int nSize, const int nWeight, const COLORREF cColor, int nFont) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
// Can't access null pointers
|
||||
assert(pWnd != nullptr);
|
||||
|
||||
_cTextColor = cColor;
|
||||
|
||||
return displayText(pWnd, pszText, &_cRect, nSize, nWeight, false, nFont);
|
||||
}
|
||||
|
||||
ErrorCode CBofText::display(CBofWindow *pWnd) {
|
||||
assert(isValidObject(this));
|
||||
assert(pWnd != nullptr);
|
||||
|
||||
return display(pWnd, _cCurString, _nCurSize, _nCurWeight, _cTextColor);
|
||||
}
|
||||
|
||||
ErrorCode CBofText::display(CBofBitmap *pBmp) {
|
||||
assert(isValidObject(this));
|
||||
assert(pBmp != nullptr);
|
||||
|
||||
return display(pBmp, _cCurString, _nCurSize, _nCurWeight, _cTextColor);
|
||||
}
|
||||
|
||||
ErrorCode CBofText::display(CBofBitmap *pBmp, const char *pszText, const int nSize, const int nWeight, const COLORREF cColor, int nFont) {
|
||||
// Can't access null pointers
|
||||
assert(pBmp != nullptr);
|
||||
|
||||
_cTextColor = cColor;
|
||||
|
||||
return displayText(pBmp, pszText, &_cRect, nSize, nWeight, false, nFont);
|
||||
}
|
||||
|
||||
ErrorCode CBofText::displayShadowed(CBofWindow *pWnd, const char *pszText, const int nSize, const int nWeight, const COLORREF cColor, const COLORREF cShadow, const int nDX, const int nDY, int nFont) {
|
||||
// Can't access null pointers
|
||||
assert(pWnd != nullptr);
|
||||
|
||||
_cTextColor = cColor;
|
||||
_cShadowColor = cShadow;
|
||||
_nShadow_DX = nDX;
|
||||
_nShadow_DY = nDY;
|
||||
|
||||
return displayText(pWnd, pszText, &_cRect, nSize, nWeight, true, nFont);
|
||||
}
|
||||
|
||||
ErrorCode CBofText::displayText(CBofWindow *pWnd, const char *pszText, CBofRect *pRect, const int nSize, const int nWeight, const bool bShadowed, int nFont) {
|
||||
assert(isValidObject(this));
|
||||
assert(pWnd != nullptr);
|
||||
assert(pszText != nullptr);
|
||||
assert(pRect != nullptr);
|
||||
|
||||
CBofRect cRect(0, 0, pRect->width() - 1, pRect->height() - 1);
|
||||
|
||||
assert(_pBackground != nullptr);
|
||||
assert(_pWork != nullptr);
|
||||
|
||||
if (!_bSaved) {
|
||||
CBofBitmap::setUseBackdrop(true);
|
||||
_pBackground->captureScreen(pWnd, pRect);
|
||||
CBofBitmap::setUseBackdrop(false);
|
||||
_bSaved = true;
|
||||
}
|
||||
|
||||
_pBackground->paint(_pWork, 0, 0);
|
||||
|
||||
displayTextEx(_pWork, pszText, &cRect, nSize, nWeight, bShadowed, nFont);
|
||||
|
||||
_pWork->paint(pWnd, pRect);
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
ErrorCode CBofText::displayText(CBofBitmap *pBmp, const char *pszText, CBofRect *pRect, const int nSize, const int nWeight, const bool bShadowed, int nFont) {
|
||||
assert(isValidObject(this));
|
||||
assert(pBmp != nullptr);
|
||||
assert(pszText != nullptr);
|
||||
assert(pRect != nullptr);
|
||||
|
||||
CBofRect cRect(0, 0, pRect->width() - 1, pRect->height() - 1);
|
||||
|
||||
assert(_pWork != nullptr);
|
||||
|
||||
assert(_pBackground != nullptr);
|
||||
|
||||
if (!_bSaved) {
|
||||
CBofRect r = _pBackground->getRect();
|
||||
pBmp->paint(_pBackground, &r, pRect);
|
||||
_bSaved = true;
|
||||
}
|
||||
|
||||
_pBackground->paint(_pWork, 0, 0);
|
||||
|
||||
displayTextEx(_pWork, pszText, &cRect, nSize, nWeight, bShadowed, nFont);
|
||||
|
||||
_pWork->paint(pBmp, pRect);
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
Graphics::Font *CBofText::getFont(int nFont, int nSize, int nWeight) {
|
||||
Graphics::Font *font;
|
||||
|
||||
// Attempt to use one of the fonts that we pre-allocated
|
||||
if (nFont != FONT_MONO) {
|
||||
font = _defaultFonts[nSize - START_SIZE];
|
||||
} else {
|
||||
font = _fixedFonts[nSize - START_SIZE];
|
||||
}
|
||||
|
||||
// Last resort - create the font now
|
||||
if (font == nullptr) {
|
||||
if (nFont != FONT_MONO) {
|
||||
font = Graphics::loadTTFFontFromArchive(SERIF_FONT_REGULAR, nSize, Graphics::kTTFSizeModeCell);
|
||||
_defaultFonts[nSize - START_SIZE] = font;
|
||||
} else {
|
||||
font = Graphics::loadTTFFontFromArchive(MONO_FONT, nSize, Graphics::kTTFSizeModeCell);
|
||||
_fixedFonts[nSize - START_SIZE] = font;
|
||||
}
|
||||
}
|
||||
|
||||
return font;
|
||||
}
|
||||
|
||||
ErrorCode CBofText::displayTextEx(CBofBitmap *pBmp, const char *pszText, CBofRect *pRect, const int nSize, const int nWeight, const bool bShadowed, int nFont) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
// can't access null pointers
|
||||
assert(pBmp != nullptr);
|
||||
assert(pszText != nullptr);
|
||||
assert(pRect != nullptr);
|
||||
|
||||
Graphics::ManagedSurface surface = pBmp->getSurface();
|
||||
Graphics::Font *font = getFont(nFont, nSize, nWeight);
|
||||
int color;
|
||||
|
||||
// Split lines
|
||||
Common::U32StringArray lines;
|
||||
font->wordWrapText(Common::U32String(pszText, Common::kWindows1252), pRect->width(), lines);
|
||||
|
||||
// Iterate the lines to get the maximum width
|
||||
int maxWidth = 0;
|
||||
for (uint i = 0; i < lines.size(); ++i)
|
||||
maxWidth = MAX(maxWidth, font->getStringWidth(lines[i]));
|
||||
Common::Point textInfo(maxWidth, (int)lines.size() * font->getFontHeight());
|
||||
|
||||
_cPosition.y = (_cSize.cy - textInfo.y) >> 1;
|
||||
|
||||
Graphics::TextAlign align = Graphics::kTextAlignLeft;
|
||||
switch (_nJustify) {
|
||||
case JUSTIFY_CENTER:
|
||||
_cPosition.x = (_cSize.cx - textInfo.x) >> 1;
|
||||
align = Graphics::kTextAlignCenter;
|
||||
break;
|
||||
|
||||
case JUSTIFY_LEFT:
|
||||
// align left
|
||||
_cPosition.x = 0;
|
||||
break;
|
||||
|
||||
case JUSTIFY_RIGHT:
|
||||
_cPosition.x = _cSize.cx - textInfo.x;
|
||||
align = Graphics::kTextAlignRight;
|
||||
break;
|
||||
|
||||
case JUSTIFY_WRAP:
|
||||
// Align left
|
||||
_bMultiLine = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// text starts relative to area for painting
|
||||
_cPosition += pRect->topLeft();
|
||||
|
||||
// Note: Under ScummVM, even single line drawing uses the multiLine code
|
||||
Common::Rect newRect = *pRect;
|
||||
|
||||
if ((_nFormatFlags & FORMAT_TOP_CENTER) == FORMAT_TOP_CENTER) {
|
||||
int h = lines.size() * font->getFontHeight();
|
||||
newRect.top = (newRect.top + newRect.bottom) / 2 - h / 2;
|
||||
newRect.bottom = newRect.top + h;
|
||||
}
|
||||
|
||||
Common::Rect shadowRect = newRect;
|
||||
shadowRect.translate(_nShadow_DX, _nShadow_DY);
|
||||
|
||||
for (uint i = 0; i < lines.size(); ++i) {
|
||||
const Common::U32String &line = lines[i];
|
||||
|
||||
if (bShadowed) {
|
||||
color = CBofApp::getApp()->getPalette()->getNearestIndex(_cShadowColor);
|
||||
displayLine(font, surface, line, shadowRect.left, shadowRect.top,
|
||||
shadowRect.width(), color, align);
|
||||
}
|
||||
|
||||
color = CBofApp::getApp()->getPalette()->getNearestIndex(_cTextColor);
|
||||
displayLine(font, surface, line, newRect.left, newRect.top,
|
||||
newRect.width(), color, align);
|
||||
|
||||
newRect.top += font->getFontHeight();
|
||||
shadowRect.top += font->getFontHeight();
|
||||
}
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
void CBofText::displayLine(Graphics::Font *font, Graphics::ManagedSurface &surface,
|
||||
const Common::U32String &line, int left, int top, int width, int color, Graphics::TextAlign align) {
|
||||
if (!line.contains('\t')) {
|
||||
font->drawString(&surface, line, left, top, width, color, align);
|
||||
|
||||
} else {
|
||||
// Special rendering of tabbed text
|
||||
Common::U32String str = line;
|
||||
|
||||
while (!str.empty()) {
|
||||
if (str[0] == '\t') {
|
||||
// Move to next tab stop
|
||||
left = (left + TAB_SIZE) / TAB_SIZE * TAB_SIZE;
|
||||
str.deleteChar(0);
|
||||
|
||||
} else {
|
||||
Common::U32String fragment;
|
||||
size_t tab = str.findFirstOf('\t');
|
||||
if (tab == Common::U32String::npos) {
|
||||
fragment = str;
|
||||
str.clear();
|
||||
} else {
|
||||
fragment = Common::U32String(str.c_str(), str.c_str() + tab);
|
||||
str = Common::U32String(str.c_str() + tab);
|
||||
}
|
||||
|
||||
int fragmentWidth = font->getStringWidth(fragment);
|
||||
font->drawString(&surface, fragment, left, top, width, color, align);
|
||||
|
||||
left += fragmentWidth;
|
||||
width -= fragmentWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ErrorCode paintText(CBofWindow *pWnd, CBofRect *pRect, const char *pszString, const int nSize, const int nWeight, const COLORREF cColor, int nJustify, uint32 nFormatFlags, int nFont) {
|
||||
assert(pWnd != nullptr);
|
||||
assert(pRect != nullptr);
|
||||
|
||||
CBofText cText(pRect, nJustify, nFormatFlags);
|
||||
return cText.display(pWnd, pszString, nSize, nWeight, cColor, nFont);
|
||||
}
|
||||
|
||||
ErrorCode paintText(CBofBitmap *pBmp, CBofRect *pRect, const char *pszString, const int nSize, const int nWeight, const COLORREF cColor, int nJustify, uint32 nFormatFlags, int nFont) {
|
||||
assert(pBmp != nullptr);
|
||||
assert(pRect != nullptr);
|
||||
|
||||
CBofText cText;
|
||||
cText.setupTextOpt(pRect, nJustify, nFormatFlags);
|
||||
|
||||
cText.setColor(cColor);
|
||||
|
||||
return cText.displayTextEx(pBmp, pszString, pRect, nSize, nWeight, false, nFont);
|
||||
}
|
||||
|
||||
ErrorCode paintShadowedText(CBofBitmap *pBmp, CBofRect *pRect, const char *pszString, const int nSize, const int nWeight, const COLORREF cColor, int nJustify, uint32 nFormatFlags, int nFont) {
|
||||
assert(pBmp != nullptr);
|
||||
assert(pRect != nullptr);
|
||||
|
||||
CBofText cText;
|
||||
cText.setupTextOpt(pRect, nJustify, nFormatFlags);
|
||||
|
||||
cText.setColor(cColor);
|
||||
cText.setShadowColor(CTEXT_SHADOW_COLOR);
|
||||
cText.setShadowSize(CTEXT_SHADOW_DX, CTEXT_SHADOW_DY);
|
||||
|
||||
return cText.displayTextEx(pBmp, pszString, pRect, nSize, nWeight, true, nFont);
|
||||
}
|
||||
|
||||
CBofRect calculateTextRect(CBofWindow *pWnd, const CBofString *pStr, int nSize, int nFont) {
|
||||
return calculateTextRect(pWnd->getRect(), pStr, nSize, nFont);
|
||||
}
|
||||
|
||||
CBofRect calculateTextRect(CBofRect rect, const CBofString *pStr, int nSize, int nFont) {
|
||||
// Get the font to use
|
||||
Graphics::Font *font = CBofText::getFont(nFont, nSize, TEXT_NORMAL);
|
||||
|
||||
// Wrap the text as necessary
|
||||
Common::U32StringArray lines;
|
||||
font->wordWrapText(Common::U32String(pStr->getBuffer(), Common::kWindows1252), rect.width(), lines);
|
||||
|
||||
// Iterate the lines to get the maximum width
|
||||
int maxWidth = 0;
|
||||
for (uint i = 0; i < lines.size(); ++i)
|
||||
maxWidth = MAX(maxWidth, font->getStringWidth(lines[i]));
|
||||
|
||||
return CBofRect(0, 0, maxWidth, (int)lines.size() * font->getFontHeight());
|
||||
}
|
||||
|
||||
} // namespace SpaceBar
|
||||
} // namespace Bagel
|
||||
340
engines/bagel/spacebar/boflib/gfx/text.h
Normal file
340
engines/bagel/spacebar/boflib/gfx/text.h
Normal file
@@ -0,0 +1,340 @@
|
||||
/* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BAGEL_BOFLIB_GFX_TEXT_H
|
||||
#define BAGEL_BOFLIB_GFX_TEXT_H
|
||||
|
||||
#include "graphics/font.h"
|
||||
#include "bagel/boflib/object.h"
|
||||
#include "bagel/spacebar/boflib/gfx/bitmap.h"
|
||||
#include "bagel/boflib/error.h"
|
||||
#include "bagel/boflib/string.h"
|
||||
|
||||
namespace Bagel {
|
||||
namespace SpaceBar {
|
||||
|
||||
#define NUM_POINT_SIZES 32
|
||||
|
||||
// Text color and offset definitions
|
||||
#define CTEXT_COLOR RGB(0,0,0)
|
||||
#define CTEXT_SHADOW_COLOR RGB(0,0,0)
|
||||
#define CTEXT_YELLOW RGB(255, 255, 0)
|
||||
#define CTEXT_WHITE RGB(255, 255, 255)
|
||||
|
||||
#define CTEXT_SHADOW_DX 2
|
||||
#define CTEXT_SHADOW_DY 2
|
||||
|
||||
// Text justification definitions
|
||||
enum {
|
||||
JUSTIFY_CENTER = 0,
|
||||
JUSTIFY_LEFT = 1,
|
||||
JUSTIFY_RIGHT = 2,
|
||||
JUSTIFY_WRAP = 3
|
||||
};
|
||||
|
||||
// Text weight definitions
|
||||
//
|
||||
|
||||
/*
|
||||
* DrawText Format Flags
|
||||
*/
|
||||
#define DT_TOP 0x00000000
|
||||
#define DT_LEFT 0x00000000
|
||||
#define DT_CENTER 0x00000001
|
||||
#define DT_RIGHT 0x00000002
|
||||
#define DT_VCENTER 0x00000004
|
||||
#define DT_BOTTOM 0x00000008
|
||||
#define DT_WORDBREAK 0x00000010
|
||||
#define DT_SINGLELINE 0x00000020
|
||||
#define DT_EXPANDTABS 0x00000040
|
||||
#define DT_TABSTOP 0x00000080
|
||||
#define DT_NOCLIP 0x00000100
|
||||
#define DT_EXTERNALLEADING 0x00000200
|
||||
#define DT_CALCRECT 0x00000400
|
||||
#define DT_NOPREFIX 0x00000800
|
||||
#define DT_intERNAL 0x00001000
|
||||
|
||||
|
||||
enum {
|
||||
FW_NORMAL,
|
||||
FW_BOLD,
|
||||
FW_MEDIUM,
|
||||
};
|
||||
|
||||
#define FONT_DEFAULT 0
|
||||
#define FONT_MONO 1
|
||||
|
||||
#define TEXT_DONTCARE 0
|
||||
#define TEXT_THIN FW_THIN
|
||||
#define TEXT_EXTRALIGHT FW_EXTRALIGHT
|
||||
#define TEXT_ULTRALIGHT FW_ULTRALIGHT
|
||||
#define TEXT_LIGHT FW_LIGHT
|
||||
#define TEXT_NORMAL FW_NORMAL
|
||||
#define TEXT_REGULAR FW_REGULAR
|
||||
#define TEXT_MEDIUM FW_MEDIUM
|
||||
#define TEXT_SEMIBOLD FW_SEMIBOLD
|
||||
#define TEXT_DEMIBOLD FW_DEMIBOLD
|
||||
#define TEXT_BOLD FW_BOLD
|
||||
#define TEXT_EXTRABOLD FW_EXTRABOLD
|
||||
#define TEXT_ULTRABOLD FW_ULTRABOLD
|
||||
#define TEXT_BLACK FW_BLACK
|
||||
#define TEXT_HEAVY FW_HEAVY
|
||||
|
||||
#define FORMAT_TOP_LEFT ( DT_TOP | DT_LEFT )
|
||||
#define FORMAT_TOP_RIGHT ( DT_TOP | DT_RIGHT )
|
||||
#define FORMAT_TOP_CENTER ( DT_TOP | DT_CENTER )
|
||||
#define FORMAT_BOT_LEFT ( DT_BOTTOM | DT_LEFT )
|
||||
#define FORMAT_BOT_RIGHT ( DT_BOTTOM | DT_RIGHT )
|
||||
#define FORMAT_BOT_CENTER ( DT_BOTTOM | DT_CENTER )
|
||||
#define FORMAT_CENTER_LEFT ( DT_VCENTER | DT_LEFT )
|
||||
#define FORMAT_CENTER_RIGHT ( DT_VCENTER | DT_RIGHT )
|
||||
#define FORMAT_CENTER_CENTER ( DT_VCENTER | DT_CENTER )
|
||||
#define FORMAT_SINGLE_LINE DT_SINGLELINE
|
||||
#define FORMAT_MULTI_LINE DT_WORDBREAK
|
||||
#define FORMAT_DEFAULT ( FORMAT_TOP_LEFT | FORMAT_MULTI_LINE )
|
||||
|
||||
#define FONT_DEFAULT_SIZE (-14)
|
||||
#define FONT_8POINT 8
|
||||
#define FONT_10POINT 10
|
||||
#define FONT_12POINT 12
|
||||
#define FONT_14POINT 14
|
||||
#define FONT_15POINT 15
|
||||
#define FONT_18POINT 18
|
||||
#define FONT_20POINT 20
|
||||
#define TEXT_DEFAULT_FACE TEXT_BOLD
|
||||
|
||||
|
||||
class CBofText : public CBofObject, public CBofError {
|
||||
public:
|
||||
// Constructors
|
||||
CBofText();
|
||||
CBofText(const CBofRect *pRect, int nJustify = JUSTIFY_CENTER, uint32 nFormatFlags = FORMAT_DEFAULT);
|
||||
virtual ~CBofText();
|
||||
|
||||
// Implementation
|
||||
//
|
||||
|
||||
/**
|
||||
* Build primary data objects and work areas; text will be displayed
|
||||
* centered within the defined rectangular area, hence it is up to
|
||||
* the caller to ensure that the text fits (excess is cropped).
|
||||
* @param pRect Rectangular area encompassed by the text object
|
||||
* @param nJustify Alignment of text in the rectangle
|
||||
* @param nFormatFlags Format flag
|
||||
*/
|
||||
ErrorCode setupText(const CBofRect *pRect, int nJustify = JUSTIFY_CENTER, uint32 nFormatFlags = FORMAT_DEFAULT);
|
||||
ErrorCode setupTextOpt(const CBofRect *pRect, int nJustify = JUSTIFY_CENTER, uint32 nFormatFlags = FORMAT_DEFAULT);
|
||||
|
||||
void setText(const CBofString &cString) {
|
||||
_cCurString = cString;
|
||||
}
|
||||
void setColor(const COLORREF cColor) {
|
||||
_cTextColor = cColor;
|
||||
}
|
||||
void SetSize(const int nSize) {
|
||||
_nCurSize = nSize;
|
||||
}
|
||||
void setWeight(const int nWeight) {
|
||||
_nCurWeight = nWeight;
|
||||
}
|
||||
|
||||
void setShadowColor(const COLORREF cColor) {
|
||||
_cShadowColor = cColor;
|
||||
}
|
||||
void setShadowSize(int nDX, int nDY) {
|
||||
_nShadow_DX = nDX;
|
||||
_nShadow_DY = nDY;
|
||||
}
|
||||
|
||||
CBofString getText() const {
|
||||
return _cCurString;
|
||||
}
|
||||
COLORREF getColor() const {
|
||||
return _cTextColor;
|
||||
}
|
||||
int getSize() const {
|
||||
return _nCurSize;
|
||||
}
|
||||
int getWeight() const {
|
||||
return _nCurWeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores the background behind current text on screen
|
||||
* @param pWnd Window to erase text from
|
||||
* @return Error return Code
|
||||
*/
|
||||
ErrorCode erase(CBofWindow *pWnd);
|
||||
|
||||
/**
|
||||
* Restores the background behind current text offscreen
|
||||
* @param pBmp Offscreen bitmap to erase text from
|
||||
* @return Error return Code
|
||||
*/
|
||||
ErrorCode erase(CBofBitmap *pBmp);
|
||||
|
||||
/**
|
||||
* Re-displays current text, formatted with current attribs
|
||||
* @param pWnd Window to paint into
|
||||
* @return Error return Code
|
||||
*/
|
||||
ErrorCode display(CBofWindow *pWnd);
|
||||
|
||||
/**
|
||||
* Re-displays current text, formatted with current attribs
|
||||
* @param pBmp Bitmap to paint into
|
||||
* @return Error return Code
|
||||
*/
|
||||
ErrorCode display(CBofBitmap *pBmp);
|
||||
|
||||
/**
|
||||
* Display a text string, formatted in the current text area
|
||||
* @param pWnd Window to paint into
|
||||
* @param pszText Point to text string to be displayed
|
||||
* @param nSize Point size of the text to be used
|
||||
* @param nWeight Weighting of the font (FW_ identifier)
|
||||
* @param cColor Color that the text will be
|
||||
* @param nFont Font used (default or mono)
|
||||
* @return Error return Code
|
||||
*/
|
||||
ErrorCode display(CBofWindow *pWnd, const char *pszText, int nSize, int nWeight, COLORREF cColor = CTEXT_COLOR, int nFont = FONT_DEFAULT);
|
||||
|
||||
/**
|
||||
* Display a text string, formatted in the current text area
|
||||
* @param pBmp Bitmap to paint into
|
||||
* @param pszText Point to text string to be displayed
|
||||
* @param nSize Point size of the text to be used
|
||||
* @param nWeight Weighting of the font (FW_ identifier)
|
||||
* @param cColor Color that the text will be
|
||||
* @param nFont Font used (default or mono)
|
||||
* @return Error return Code
|
||||
*/
|
||||
ErrorCode display(CBofBitmap *pBmp, const char *pszText, int nSize, int nWeight, COLORREF cColor = CTEXT_COLOR, int nFont = FONT_DEFAULT);
|
||||
|
||||
/**
|
||||
* Display a shadowed text string into the current text area
|
||||
* @param pWnd Window to paint into
|
||||
* @param pszText Point to text string to be displayed
|
||||
* @param nSize Point size of the text to be used
|
||||
* @param nWeight Weighting of the font (FW_ identifier)
|
||||
* @param cColor Color that the text will be
|
||||
* @param cShadow Color that the text's shadow will be
|
||||
* @param nDX Shadow DX
|
||||
* @param nDY Shadow DY
|
||||
* @param nFont Font used (default or mono)
|
||||
* @return Error return Code
|
||||
*/
|
||||
ErrorCode displayShadowed(CBofWindow *pWnd, const char *pszText, int nSize,
|
||||
int nWeight, COLORREF cColor, COLORREF cShadow = CTEXT_SHADOW_COLOR,
|
||||
int nDX = CTEXT_SHADOW_DX, int nDY = CTEXT_SHADOW_DY, int nFont = FONT_DEFAULT);
|
||||
|
||||
|
||||
void flushBackground() {
|
||||
_bSaved = false;
|
||||
}
|
||||
|
||||
static ErrorCode initialize();
|
||||
static ErrorCode shutdown();
|
||||
|
||||
/**
|
||||
* Displays specified text onto specified bitmap
|
||||
* @param pBmp Bitmap to paint text onto
|
||||
* @param pszText Pointer to text string to be displayed
|
||||
* @param pRect Area to paint text to
|
||||
* @param nSize Point size of the text to be used
|
||||
* @param nWeight Weighting of the font (FW_ identifier)
|
||||
* @param bShadowed Whether the text is shadowed
|
||||
* @param nFont Font used (default or mono)
|
||||
* @return Error return Code
|
||||
*/
|
||||
ErrorCode displayTextEx(CBofBitmap *pBmp, const char *pszText, CBofRect *pRect, int nSize, int nWeight, bool bShadowed, int nFont = FONT_DEFAULT);
|
||||
|
||||
static Graphics::Font *getFont(int nFont, int nSize, int nWeight);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Initializes key fields to zero or nullptr states.
|
||||
*/
|
||||
void initializeFields();
|
||||
|
||||
/**
|
||||
* Displays specified text onto specified bitmap
|
||||
* @param pWnd Window to paint text onto
|
||||
* @param pszText Pointer to text string to be displayed
|
||||
* @param pRect Area to paint text to
|
||||
* @param nSize Point size of the text to be used
|
||||
* @param nWeight Weighting of the font (FW_ identifier)
|
||||
* @param bShadowed Whether the text is shadowed
|
||||
* @param nFont Font used (default or mono)
|
||||
* @return Error return Code
|
||||
*/
|
||||
ErrorCode displayText(CBofWindow *pWnd, const char *pszText, CBofRect *pRect, int nSize, int nWeight, bool bShadowed, int nFont = FONT_DEFAULT);
|
||||
ErrorCode displayText(CBofBitmap *pBmp, const char *pszText, CBofRect *pRect, int nSize, int nWeight, bool bShadowed, int nFont = FONT_DEFAULT);
|
||||
|
||||
void displayLine(Graphics::Font *font, Graphics::ManagedSurface &surface, const Common::U32String &line,
|
||||
int left, int top, int width, int color, Graphics::TextAlign align);
|
||||
|
||||
protected:
|
||||
CBofString _cCurString; // text to be displayed
|
||||
CBofRect _cRect; // bounding rectangle of text area
|
||||
CBofPoint _cPosition; // upper left corner of text displayed
|
||||
CBofSize _cSize; // dx/dy size of the text bitmap
|
||||
COLORREF _cTextColor; // color to use for the text itself
|
||||
COLORREF _cShadowColor; // color to use for the text's shadow
|
||||
CBofBitmap *_pBackground; // bitmap for the text's background
|
||||
CBofBitmap *_pWork; // bitmap for the work area
|
||||
|
||||
int _nCurSize; // point size of current text
|
||||
int _nCurWeight; // style of current text
|
||||
|
||||
int _nJustify; // positioning within the rectangle
|
||||
int _nShadow_DX; // horizontal offset for shadow
|
||||
int _nShadow_DY; // vertical offset for shadow
|
||||
uint32 _nFormatFlags; // multi line formatting flags
|
||||
bool _bMultiLine; // multi vs single line formatting
|
||||
bool _bSaved;
|
||||
|
||||
static Graphics::Font *_defaultFonts[NUM_POINT_SIZES];
|
||||
static Graphics::Font *_fixedFonts[NUM_POINT_SIZES];
|
||||
|
||||
static bool _initialized;
|
||||
|
||||
static int _tabStop; // tabstop table
|
||||
};
|
||||
|
||||
// Global text functions
|
||||
//
|
||||
ErrorCode paintText(CBofWindow *pWnd, CBofRect *pRect, const char *, int nSize, int nWeight, COLORREF cColor = CTEXT_COLOR, int nJustify = JUSTIFY_CENTER, uint32 nFormat = FORMAT_DEFAULT, int nFont = FONT_DEFAULT);
|
||||
ErrorCode paintText(CBofBitmap *pBmp, CBofRect *pRect, const char *, int nSize, int nWeight, COLORREF cColor = CTEXT_COLOR, int nJustify = JUSTIFY_CENTER, uint32 nFormat = FORMAT_DEFAULT, int nFont = FONT_DEFAULT);
|
||||
|
||||
ErrorCode paintShadowedText(CBofBitmap *, CBofRect *pRect, const char *, int nSize, int nWeight, COLORREF cColor = CTEXT_COLOR, int nJustify = JUSTIFY_CENTER, uint32 n = FORMAT_DEFAULT, int nFont = FONT_DEFAULT);
|
||||
|
||||
/**
|
||||
* Utility routine that will calculate the rectangle that a text string
|
||||
* will fit in, given point size and font.
|
||||
*/
|
||||
CBofRect calculateTextRect(CBofWindow *pWnd, const CBofString *pStr, int nSize, int nFont);
|
||||
CBofRect calculateTextRect(CBofRect rect, const CBofString *pStr, int nSize, int nFont);
|
||||
|
||||
} // namespace SpaceBar
|
||||
} // namespace Bagel
|
||||
|
||||
#endif
|
||||
621
engines/bagel/spacebar/boflib/gui/button.cpp
Normal file
621
engines/bagel/spacebar/boflib/gui/button.cpp
Normal file
@@ -0,0 +1,621 @@
|
||||
/* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "bagel/spacebar/boflib/gui/button.h"
|
||||
#include "bagel/spacebar/boflib/app.h"
|
||||
#include "bagel/spacebar/boflib/gfx/text.h"
|
||||
|
||||
namespace Bagel {
|
||||
namespace SpaceBar {
|
||||
|
||||
#define SELECTED_TEXT_OFFSET_DX 1
|
||||
#define SELECTED_TEXT_OFFSET_DY 1
|
||||
|
||||
#define BUTTON_TEXT_SIZE 10
|
||||
|
||||
#define CHECK_BOX_SIZE 14
|
||||
#define CHECK_BOX_OFFSET_DX 4
|
||||
#define CHECK_BOX_OFFSET_DY 4
|
||||
#define CHECK_BOX_TEXT_SIZE 10
|
||||
|
||||
#define RADIO_BOX_SIZE 13
|
||||
#define RADIO_BOX_OFFSET_DX 3
|
||||
#define RADIO_BOX_OFFSET_DY 3
|
||||
#define RADIO_BOX_TEXT_SIZE 10
|
||||
|
||||
|
||||
static ST_COLORSCHEME g_stDefaultColors = {
|
||||
|
||||
RGB(171, 151, 127),
|
||||
RGB(207, 199, 183),
|
||||
RGB(131, 111, 91),
|
||||
RGB(0, 0, 0),
|
||||
RGB(0, 0, 0),
|
||||
RGB(0, 0, 0)
|
||||
};
|
||||
|
||||
CBofButton::CBofButton() {
|
||||
// Inits
|
||||
_nState = BUTTON_UP;
|
||||
|
||||
// Load a default color scheme until another is loaded
|
||||
loadColorScheme(&g_stDefaultColors);
|
||||
}
|
||||
|
||||
|
||||
CBofButton::CBofButton(ST_COLORSCHEME *pColorScheme) {
|
||||
assert(pColorScheme != nullptr);
|
||||
|
||||
// Inits
|
||||
_nState = BUTTON_UP;
|
||||
|
||||
loadColorScheme(pColorScheme);
|
||||
}
|
||||
|
||||
|
||||
CBofButton::~CBofButton() {
|
||||
assert(isValidObject(this));
|
||||
}
|
||||
|
||||
|
||||
ErrorCode CBofButton::paint(CBofRect *) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
// Only continue if this button is visible
|
||||
if (isVisible() && (_parent != nullptr) && _parent->isVisible()) {
|
||||
CBofPalette *pPalette = CBofApp::getApp()->getPalette();
|
||||
|
||||
int nWidth = _cRect.width();
|
||||
int nHeight = _cRect.height();
|
||||
|
||||
// Create our off-screen buffer
|
||||
CBofBitmap cBmp(nWidth, nHeight, pPalette);
|
||||
|
||||
cBmp.fillRect(&_cRect, pPalette->getNearestIndex(_cFaceColor));
|
||||
|
||||
int left = _cRect.left;
|
||||
int right = _cRect.right;
|
||||
int top = _cRect.top;
|
||||
int bottom = _cRect.bottom;
|
||||
|
||||
byte iShadow = pPalette->getNearestIndex(_cShadowColor);
|
||||
byte iHighlight = pPalette->getNearestIndex(_cHighlightColor);
|
||||
|
||||
if (_nState == BUTTON_DOWN) {
|
||||
byte iTemp = iShadow;
|
||||
iShadow = iHighlight;
|
||||
iHighlight = iTemp;
|
||||
}
|
||||
|
||||
byte c1 = iShadow;
|
||||
byte c2 = iHighlight;
|
||||
|
||||
int i;
|
||||
for (i = 1; i <= 3; i++) {
|
||||
cBmp.line(left + i, bottom - i, right - i, bottom - i, c1);
|
||||
cBmp.line(right - i, bottom - i, right - i, top + i - 1, c1);
|
||||
}
|
||||
|
||||
for (i = 1; i <= 3; i++) {
|
||||
cBmp.line(left + i, bottom - i, left + i, top + i - 1, c2);
|
||||
cBmp.line(left + i, top + i - 1, right - i, top + i - 1, c2);
|
||||
}
|
||||
|
||||
cBmp.drawRect(&_cRect, pPalette->getNearestIndex(_cOutlineColor));
|
||||
|
||||
// Create a temporary text object
|
||||
CBofRect cTempRect(3, 3, _cRect.right - 3, _cRect.bottom - 3);
|
||||
|
||||
if (_nState == BUTTON_DOWN) {
|
||||
cTempRect += CBofPoint(1, 1);
|
||||
}
|
||||
|
||||
CBofText cText(&cTempRect);
|
||||
|
||||
// Print text into button
|
||||
COLORREF cTextColor = _cTextColor;
|
||||
if (_nState == BUTTON_DISABLED)
|
||||
cTextColor = _cTextDisabledColor;
|
||||
|
||||
cText.display(&cBmp, _szTitle, BUTTON_TEXT_SIZE, TEXT_NORMAL, cTextColor);
|
||||
|
||||
if (_nState == BUTTON_FOCUS) {
|
||||
cBmp.drawRect(&cTempRect, pPalette->getNearestIndex(_cOutlineColor));
|
||||
}
|
||||
|
||||
// Now we can update the window
|
||||
cBmp.paint(this, 0, 0);
|
||||
}
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
|
||||
void CBofButton::loadColorScheme(ST_COLORSCHEME *pColorScheme) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
assert(pColorScheme != nullptr);
|
||||
|
||||
// Save all of the color info we need to build a button
|
||||
_cFaceColor = pColorScheme->_cFace;
|
||||
_cHighlightColor = pColorScheme->_cHighlight;
|
||||
_cShadowColor = pColorScheme->_cShadow;
|
||||
_cTextColor = pColorScheme->_cText;
|
||||
_cTextDisabledColor = pColorScheme->_cTextDisabled;
|
||||
_cOutlineColor = pColorScheme->_cOutline;
|
||||
}
|
||||
|
||||
|
||||
void CBofButton::enable() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
CBofWindow::enable();
|
||||
|
||||
setState(BUTTON_UP);
|
||||
}
|
||||
|
||||
|
||||
void CBofButton::disable() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
setState(BUTTON_DISABLED);
|
||||
|
||||
CBofWindow::disable();
|
||||
}
|
||||
|
||||
|
||||
ErrorCode CBofButton::setState(int nNewState, bool bRepaintNow) {
|
||||
assert(isValidObject(this));
|
||||
assert(nNewState >= BUTTON_UP && nNewState <= BUTTON_DISABLED);
|
||||
|
||||
// Remember last button state
|
||||
int nOldState = _nState;
|
||||
|
||||
_nState = nNewState;
|
||||
|
||||
// Update the window if forced to or if button state has changed
|
||||
if (bRepaintNow || (nOldState != nNewState)) {
|
||||
paint();
|
||||
}
|
||||
|
||||
// I must have a valid parent
|
||||
assert(_parent != nullptr);
|
||||
|
||||
// Tell parent the new state of this button
|
||||
if (_parent != nullptr) {
|
||||
_parent->onBofButton(this, _nState);
|
||||
}
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
|
||||
void CBofButton::onPaint(CBofRect *pRect) {
|
||||
assert(isValidObject(this));
|
||||
assert(pRect != nullptr);
|
||||
|
||||
paint(pRect);
|
||||
}
|
||||
|
||||
|
||||
void CBofButton::onLButtonDown(uint32, CBofPoint *pPoint, void *) {
|
||||
assert(isValidObject(this));
|
||||
assert(pPoint != nullptr);
|
||||
|
||||
if (!_bCaptured && _nState != BUTTON_DISABLED) {
|
||||
setCapture();
|
||||
setState(BUTTON_DOWN, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CBofButton::onLButtonUp(uint32, CBofPoint *pPoint, void *) {
|
||||
assert(isValidObject(this));
|
||||
assert(pPoint != nullptr);
|
||||
|
||||
if (_bCaptured) {
|
||||
releaseCapture();
|
||||
setState(BUTTON_UP, true);
|
||||
|
||||
if (_cRect.ptInRect(*pPoint) && (_parent != nullptr)) {
|
||||
_parent->onBofButton(this, BUTTON_CLICKED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* CBofRadioButton */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
void CBofRadioButton::onLButtonDown(uint32, CBofPoint *pPoint, void *) {
|
||||
assert(isValidObject(this));
|
||||
assert(pPoint != nullptr);
|
||||
|
||||
if (_nState == BUTTON_UP) {
|
||||
setState(BUTTON_DOWN, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CBofRadioButton::onLButtonUp(uint32, CBofPoint *pPoint, void *) {
|
||||
assert(isValidObject(this));
|
||||
assert(pPoint != nullptr);
|
||||
}
|
||||
|
||||
|
||||
ErrorCode CBofRadioButton::paint(CBofRect *) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
// Only continue if this button is visible
|
||||
if (isVisible() && (_parent != nullptr) && _parent->isVisible()) {
|
||||
|
||||
CBofPalette *pPalette = CBofApp::getApp()->getPalette();
|
||||
|
||||
int nWidth = _cRect.width();
|
||||
int nHeight = _cRect.height();
|
||||
|
||||
// Create a temporary off-screen buffer
|
||||
CBofBitmap cBmp(nWidth, nHeight, pPalette);
|
||||
|
||||
// Fill in the background color
|
||||
cBmp.fillRect(&_cRect, pPalette->getNearestIndex(_cFaceColor));
|
||||
|
||||
COLORREF cTextColor = _cTextColor;
|
||||
if (_nState == BUTTON_DISABLED)
|
||||
cTextColor = _cTextDisabledColor;
|
||||
|
||||
byte iShadow = pPalette->getNearestIndex(cTextColor);
|
||||
byte iHighlight = pPalette->getNearestIndex(cTextColor);
|
||||
|
||||
// Paint the radio button circle
|
||||
int nRadius = 7;
|
||||
int x = nRadius + RADIO_BOX_OFFSET_DX;
|
||||
int y = nHeight / 2;
|
||||
cBmp.circle(x, y, (uint16)nRadius, iShadow);
|
||||
nRadius--;
|
||||
cBmp.circle(x, y, (uint16)nRadius, iShadow);
|
||||
|
||||
// Create a temporary text object
|
||||
CBofRect cTempRect(20, RADIO_BOX_OFFSET_DY, _cRect.right, _cRect.bottom - RADIO_BOX_OFFSET_DY);
|
||||
if (_nState == BUTTON_DOWN) {
|
||||
nRadius = 1;
|
||||
cBmp.circle(x, y, (uint16)nRadius, iHighlight);
|
||||
nRadius = 2;
|
||||
cBmp.circle(x, y, (uint16)nRadius, iHighlight);
|
||||
nRadius = 3;
|
||||
cBmp.circle(x, y, (uint16)nRadius, iHighlight);
|
||||
nRadius = 4;
|
||||
cBmp.circle(x, y, (uint16)nRadius, iHighlight);
|
||||
}
|
||||
CBofText cText(&cTempRect, JUSTIFY_LEFT);
|
||||
|
||||
// Put a box around the whole button
|
||||
cBmp.drawRect(&_cRect, pPalette->getNearestIndex(_cOutlineColor));
|
||||
|
||||
// Show text disabled if button is disabled
|
||||
|
||||
// Print text into button
|
||||
cText.display(&cBmp, _szTitle, RADIO_BOX_TEXT_SIZE, TEXT_NORMAL, cTextColor);
|
||||
|
||||
// If button has focus, then put a box around the text
|
||||
if (_nState == BUTTON_FOCUS) {
|
||||
cBmp.drawRect(&cTempRect, pPalette->getNearestIndex(_cOutlineColor));
|
||||
}
|
||||
|
||||
// Now we can update the window
|
||||
cBmp.paint(this, 0, 0);
|
||||
}
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* CBofCheckButton */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
void CBofCheckButton::onLButtonDown(uint32, CBofPoint *pPoint, void *) {
|
||||
assert(isValidObject(this));
|
||||
assert(pPoint != nullptr);
|
||||
|
||||
if (_nState == BUTTON_DISABLED)
|
||||
return;
|
||||
|
||||
if (_nState == BUTTON_UP) {
|
||||
setState(BUTTON_DOWN, true);
|
||||
} else if (_nState == BUTTON_DOWN) {
|
||||
setState(BUTTON_UP, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CBofCheckButton::onLButtonUp(uint32, CBofPoint *pPoint, void *) {
|
||||
assert(isValidObject(this));
|
||||
assert(pPoint != nullptr);
|
||||
|
||||
// Do nothing, and don't call the base class version of this function
|
||||
}
|
||||
|
||||
|
||||
ErrorCode CBofCheckButton::paint(CBofRect *) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
// Only continue if this button is visible
|
||||
if (isVisible() && (_parent != nullptr) && _parent->isVisible()) {
|
||||
|
||||
CBofPalette *pPalette = CBofApp::getApp()->getPalette();
|
||||
|
||||
int nWidth = _cRect.width();
|
||||
int nHeight = _cRect.height();
|
||||
|
||||
// Create a temporary off-screen buffer
|
||||
CBofBitmap cBmp(nWidth, nHeight, pPalette);
|
||||
|
||||
// Fill in the background color
|
||||
cBmp.fillRect(&_cRect, pPalette->getNearestIndex(_cFaceColor));
|
||||
|
||||
// Show text disabled if button is disabled
|
||||
COLORREF cTextColor = _cTextColor;
|
||||
if (_nState == BUTTON_DISABLED)
|
||||
cTextColor = _cTextDisabledColor;
|
||||
|
||||
byte iShadow = pPalette->getNearestIndex(cTextColor);
|
||||
|
||||
// Draw the check box (centered vertically)
|
||||
int y = ((nHeight - CHECK_BOX_SIZE) / 2);
|
||||
CBofRect cTempRect(CHECK_BOX_OFFSET_DX, y, CHECK_BOX_SIZE + CHECK_BOX_OFFSET_DX - 1, y + CHECK_BOX_SIZE - 1);
|
||||
cBmp.drawRect(&cTempRect, iShadow);
|
||||
|
||||
// if button is in DOWN/ON state, then put an X in the box
|
||||
//
|
||||
if (_nState == BUTTON_DOWN) {
|
||||
cBmp.line(cTempRect.left, cTempRect.top, cTempRect.right, cTempRect.bottom, iShadow);
|
||||
cBmp.line(cTempRect.left, cTempRect.bottom, cTempRect.right, cTempRect.top, iShadow);
|
||||
}
|
||||
|
||||
// Create a temporary text object
|
||||
cTempRect.setRect(CHECK_BOX_SIZE + CHECK_BOX_OFFSET_DX, CHECK_BOX_OFFSET_DX, _cRect.right, _cRect.bottom - CHECK_BOX_OFFSET_DX);
|
||||
CBofText cText(&cTempRect, JUSTIFY_LEFT);
|
||||
|
||||
// Put a box around the whole button
|
||||
cBmp.drawRect(&_cRect, pPalette->getNearestIndex(_cOutlineColor));
|
||||
|
||||
// Print text into button
|
||||
//
|
||||
cText.display(&cBmp, _szTitle, CHECK_BOX_TEXT_SIZE, TEXT_NORMAL, cTextColor);
|
||||
|
||||
// If button has focus, then put a box around the text
|
||||
if (_nState == BUTTON_FOCUS) {
|
||||
cBmp.drawRect(&cTempRect, pPalette->getNearestIndex(_cOutlineColor));
|
||||
}
|
||||
|
||||
// Now we can update the window
|
||||
cBmp.paint(this, 0, 0);
|
||||
}
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
|
||||
ErrorCode CBofCheckButton::SetCheck(bool bChecked) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
setState(bChecked ? BUTTON_CHECKED : BUTTON_UNCHECKED, false);
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* CBofBmpButton */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
CBofBmpButton::CBofBmpButton() {
|
||||
_pButtonUp = nullptr;
|
||||
_pButtonDown = nullptr;
|
||||
_pButtonFocus = nullptr;
|
||||
_pButtonDisabled = nullptr;
|
||||
_pBackground = nullptr;
|
||||
_nState = BUTTON_UP;
|
||||
_nMaskColor = NOT_TRANSPARENT;
|
||||
}
|
||||
|
||||
|
||||
CBofBmpButton::~CBofBmpButton() {
|
||||
delete _pButtonUp;
|
||||
_pButtonUp = nullptr;
|
||||
|
||||
delete _pButtonDown;
|
||||
_pButtonDown = nullptr;
|
||||
|
||||
delete _pButtonDisabled;
|
||||
_pButtonDisabled = nullptr;
|
||||
|
||||
delete _pButtonFocus;
|
||||
_pButtonFocus = nullptr;
|
||||
|
||||
delete _pBackground;
|
||||
_pBackground = nullptr;
|
||||
}
|
||||
|
||||
|
||||
ErrorCode CBofBmpButton::paint(CBofRect *) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
// loadBitmaps must be called before the button can be painted
|
||||
assert(_pButtonUp != nullptr);
|
||||
assert(_pButtonDown != nullptr);
|
||||
assert(_pButtonFocus != nullptr);
|
||||
assert(_pButtonDisabled != nullptr);
|
||||
|
||||
// Only continue if this button is visible
|
||||
if (isVisible() && (_parent != nullptr) && _parent->isVisible()) {
|
||||
CBofPalette *pPalette = _pButtonUp->getPalette();
|
||||
|
||||
int nWidth = _cRect.width();
|
||||
int nHeight = _cRect.height();
|
||||
|
||||
// Do all painting off-screen
|
||||
CBofBitmap cOffScreen(nWidth, nHeight, pPalette);
|
||||
|
||||
if (_pBackground == nullptr) {
|
||||
_pBackground = new CBofBitmap(nWidth, nHeight, pPalette);
|
||||
} else {
|
||||
_pBackground->paint(&cOffScreen, 0, 0);
|
||||
}
|
||||
|
||||
// Assume UP state
|
||||
CBofBitmap *pBitmap = _pButtonUp;
|
||||
|
||||
// Display the correct bitmap based on state
|
||||
if (_nState == BUTTON_DOWN) {
|
||||
pBitmap = _pButtonDown;
|
||||
|
||||
} else if (_nState == BUTTON_FOCUS) {
|
||||
pBitmap = _pButtonFocus;
|
||||
|
||||
} else if (_nState == BUTTON_DISABLED) {
|
||||
pBitmap = _pButtonDisabled;
|
||||
}
|
||||
|
||||
// Paint button offscreen
|
||||
pBitmap->paint(&cOffScreen, 0, 0, nullptr, _nMaskColor);
|
||||
|
||||
// Now we can update the window
|
||||
cOffScreen.paint(this, 0, 0);
|
||||
}
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
|
||||
ErrorCode CBofBmpButton::loadBitmaps(CBofBitmap *pUp, CBofBitmap *pDown, CBofBitmap *pFocus, CBofBitmap *pDisabled, int nMaskColor) {
|
||||
assert(isValidObject(this));
|
||||
assert(pUp != nullptr);
|
||||
assert(pDown != nullptr);
|
||||
|
||||
// Use the bitmaps passed in
|
||||
_pButtonUp = pUp;
|
||||
_pButtonDown = pDown;
|
||||
_pButtonFocus = pFocus;
|
||||
_pButtonDisabled = pDisabled;
|
||||
|
||||
// Remember the transparent color for these bitmaps
|
||||
_nMaskColor = nMaskColor;
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
|
||||
ErrorCode CBofBmpButton::loadBitmaps(CBofPalette *pPalette, const char *pszUp, const char *pszDown, const char *pszFocus, const char *pszDisabled, int nMaskColor) {
|
||||
assert(isValidObject(this));
|
||||
assert(pPalette != nullptr);
|
||||
assert(pszUp != nullptr);
|
||||
assert(pszDown != nullptr);
|
||||
assert(pszFocus != nullptr);
|
||||
assert(pszDisabled != nullptr);
|
||||
|
||||
// Remember the button transparent color
|
||||
_nMaskColor = nMaskColor;
|
||||
|
||||
// Load each of the bitmaps that represent the button state
|
||||
_pButtonUp = new CBofBitmap(pszUp, pPalette);
|
||||
_pButtonUp->setReadOnly(true);
|
||||
|
||||
_pButtonDown = new CBofBitmap(pszDown, pPalette);
|
||||
_pButtonDown->setReadOnly(true);
|
||||
|
||||
_pButtonFocus = new CBofBitmap(pszFocus, pPalette);
|
||||
_pButtonFocus->setReadOnly(true);
|
||||
|
||||
_pButtonDisabled = new CBofBitmap(pszDisabled, pPalette);
|
||||
_pButtonDisabled->setReadOnly(true);
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
|
||||
ErrorCode CBofBmpButton::setState(int nNewState, bool bRepaintNow) {
|
||||
assert(isValidObject(this));
|
||||
assert(nNewState >= BUTTON_UP && nNewState <= BUTTON_DISABLED);
|
||||
|
||||
// Remember last button state
|
||||
int nOldState = _nState;
|
||||
|
||||
_nState = nNewState;
|
||||
|
||||
// Update the window if forced to or if button state has changed
|
||||
if (bRepaintNow || (nOldState != nNewState)) {
|
||||
paint();
|
||||
}
|
||||
|
||||
// I MUST have a valid parent
|
||||
assert(_parent != nullptr);
|
||||
|
||||
// Tell parent the new state of this button
|
||||
if (_parent != nullptr) {
|
||||
_parent->onBofButton(this, _nState);
|
||||
}
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
|
||||
void CBofBmpButton::onPaint(CBofRect *pRect) {
|
||||
assert(isValidObject(this));
|
||||
assert(pRect != nullptr);
|
||||
|
||||
paint(pRect);
|
||||
}
|
||||
|
||||
|
||||
void CBofBmpButton::onLButtonDown(uint32, CBofPoint *pPoint, void *) {
|
||||
assert(isValidObject(this));
|
||||
assert(pPoint != nullptr);
|
||||
|
||||
if (!_bCaptured && _nState != BUTTON_DISABLED) {
|
||||
setCapture();
|
||||
|
||||
setState(BUTTON_DOWN, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CBofBmpButton::onLButtonUp(uint32, CBofPoint *pPoint, void *) {
|
||||
assert(isValidObject(this));
|
||||
assert(pPoint != nullptr);
|
||||
|
||||
if (_bCaptured) {
|
||||
releaseCapture();
|
||||
|
||||
setState(BUTTON_UP, true);
|
||||
|
||||
if (_cRect.ptInRect(*pPoint) && (_parent != nullptr)) {
|
||||
_parent->onBofButton(this, BUTTON_CLICKED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace SpaceBar
|
||||
} // namespace Bagel
|
||||
151
engines/bagel/spacebar/boflib/gui/button.h
Normal file
151
engines/bagel/spacebar/boflib/gui/button.h
Normal file
@@ -0,0 +1,151 @@
|
||||
|
||||
/* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BAGEL_BOFLIB_GUI_BUTTON_H
|
||||
#define BAGEL_BOFLIB_GUI_BUTTON_H
|
||||
|
||||
#include "bagel/spacebar/boflib/gui/window.h"
|
||||
#include "bagel/boflib/palette.h"
|
||||
|
||||
namespace Bagel {
|
||||
namespace SpaceBar {
|
||||
|
||||
// Button states
|
||||
//
|
||||
#define BUTTON_UP 0
|
||||
#define BUTTON_DOWN 1
|
||||
#define BUTTON_FOCUS 2
|
||||
#define BUTTON_DISABLED 3
|
||||
#define BUTTON_CLICKED 4
|
||||
#define BUTTON_ON BUTTON_DOWN
|
||||
#define BUTTON_OFF BUTTON_UP
|
||||
|
||||
#define BUTTON_CHECKED BUTTON_ON
|
||||
#define BUTTON_UNCHECKED BUTTON_OFF
|
||||
|
||||
struct ST_COLORSCHEME {
|
||||
COLORREF _cFace;
|
||||
COLORREF _cHighlight;
|
||||
COLORREF _cShadow;
|
||||
COLORREF _cText;
|
||||
COLORREF _cTextDisabled;
|
||||
COLORREF _cOutline;
|
||||
};
|
||||
|
||||
class CBofButton : public CBofWindow {
|
||||
public:
|
||||
CBofButton();
|
||||
CBofButton(ST_COLORSCHEME *pColorScheme);
|
||||
virtual ~CBofButton();
|
||||
|
||||
void loadColorScheme(ST_COLORSCHEME *pColorScheme);
|
||||
|
||||
virtual ErrorCode paint(CBofRect *pRect = nullptr);
|
||||
|
||||
void enable() override;
|
||||
void disable() override;
|
||||
|
||||
ErrorCode setState(int nNewState, bool bRepaintNow = true);
|
||||
int getState() {
|
||||
return _nState;
|
||||
}
|
||||
|
||||
protected:
|
||||
void onPaint(CBofRect *pRect) override;
|
||||
void onLButtonDown(uint32 nFlags, CBofPoint *pPoint, void * = nullptr) override;
|
||||
void onLButtonUp(uint32 nFlags, CBofPoint *pPoint, void * = nullptr) override;
|
||||
|
||||
COLORREF _cFaceColor;
|
||||
COLORREF _cHighlightColor;
|
||||
COLORREF _cShadowColor;
|
||||
COLORREF _cTextColor;
|
||||
COLORREF _cTextDisabledColor;
|
||||
COLORREF _cOutlineColor;
|
||||
|
||||
int _nState;
|
||||
};
|
||||
|
||||
class CBofRadioButton : public CBofButton {
|
||||
public:
|
||||
virtual ErrorCode paint(CBofRect *pRect = nullptr);
|
||||
|
||||
protected:
|
||||
virtual void onLButtonDown(uint32 nFlags, CBofPoint *pPoint, void * = nullptr);
|
||||
virtual void onLButtonUp(uint32 nFlags, CBofPoint *pPoint, void * = nullptr);
|
||||
};
|
||||
|
||||
class CBofCheckButton : public CBofButton {
|
||||
public:
|
||||
ErrorCode SetCheck(bool bChecked);
|
||||
bool GetCheck() {
|
||||
return (_nState == BUTTON_CHECKED);
|
||||
}
|
||||
|
||||
ErrorCode paint(CBofRect *pRect = nullptr) override;
|
||||
|
||||
protected:
|
||||
void onLButtonDown(uint32 nFlags, CBofPoint *pPoint, void * = nullptr) override;
|
||||
void onLButtonUp(uint32 nFlags, CBofPoint *pPoint, void * = nullptr) override;
|
||||
};
|
||||
|
||||
class CBofBmpButton : public CBofWindow {
|
||||
public:
|
||||
// Constructors
|
||||
CBofBmpButton();
|
||||
|
||||
virtual ~CBofBmpButton();
|
||||
|
||||
// NOTE: CBofBmpButton takes control of these bitmaps, so there's
|
||||
// no need for the callers to free them afterwards
|
||||
ErrorCode loadBitmaps(CBofBitmap *pUp, CBofBitmap *pDown, CBofBitmap *pFocus, CBofBitmap *pDisabled, int nMaskColor = NOT_TRANSPARENT);
|
||||
ErrorCode loadBitmaps(CBofPalette *pPalette, const char *pszUp, const char *pszDown = nullptr, const char *pszFocus = nullptr, const char *pszDisabled = nullptr, int nMaskColor = NOT_TRANSPARENT);
|
||||
|
||||
ErrorCode paint(CBofRect *pRect = nullptr);
|
||||
|
||||
ErrorCode setState(int nNewState, bool bRepaintNow = true);
|
||||
int getState() {
|
||||
return _nState;
|
||||
}
|
||||
|
||||
CBofBitmap *getButtonBmp() {
|
||||
return _pButtonUp;
|
||||
}
|
||||
|
||||
protected:
|
||||
void onPaint(CBofRect *pRect) override;
|
||||
void onLButtonDown(uint32 nFlags, CBofPoint *pPoint, void * = nullptr) override;
|
||||
void onLButtonUp(uint32 nFlags, CBofPoint *pPoint, void * = nullptr) override;
|
||||
|
||||
CBofBitmap *_pButtonUp;
|
||||
CBofBitmap *_pButtonDown;
|
||||
CBofBitmap *_pButtonFocus;
|
||||
CBofBitmap *_pButtonDisabled;
|
||||
|
||||
CBofBitmap *_pBackground;
|
||||
int _nState;
|
||||
int _nMaskColor;
|
||||
};
|
||||
|
||||
} // namespace SpaceBar
|
||||
} // namespace Bagel
|
||||
|
||||
#endif
|
||||
294
engines/bagel/spacebar/boflib/gui/dialog.cpp
Normal file
294
engines/bagel/spacebar/boflib/gui/dialog.cpp
Normal file
@@ -0,0 +1,294 @@
|
||||
/* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/system.h"
|
||||
#include "common/events.h"
|
||||
#include "graphics/framelimiter.h"
|
||||
#include "bagel/spacebar/boflib/gui/dialog.h"
|
||||
#include "bagel/spacebar/boflib/app.h"
|
||||
#include "bagel/spacebar/boflib/timer.h"
|
||||
#include "bagel/boflib/sound.h"
|
||||
#include "bagel/bagel.h"
|
||||
|
||||
namespace Bagel {
|
||||
namespace SpaceBar {
|
||||
|
||||
CBofDialog::CBofDialog() {
|
||||
// Inits
|
||||
_pDlgBackground = nullptr;
|
||||
_bFirstTime = true;
|
||||
_bTempBitmap = false;
|
||||
_lFlags = BOFDLG_DEFAULT;
|
||||
_bEndDialog = false;
|
||||
_bHavePainted = false;
|
||||
}
|
||||
|
||||
|
||||
CBofDialog::CBofDialog(const char *pszFileName, CBofWindow *pParent, const uint32 nID, const uint32 lFlags) {
|
||||
assert(pszFileName != nullptr);
|
||||
assert(pParent != nullptr);
|
||||
|
||||
// Inits
|
||||
_pDlgBackground = nullptr;
|
||||
_bFirstTime = true;
|
||||
_bTempBitmap = false;
|
||||
_lFlags = lFlags;
|
||||
_bEndDialog = false;
|
||||
_bHavePainted = false;
|
||||
|
||||
CBofBitmap *pBmp = loadBitmap(pszFileName);
|
||||
|
||||
if (pBmp != nullptr) {
|
||||
// Use specified bitmap as this dialog's image
|
||||
setBackdrop(pBmp);
|
||||
}
|
||||
|
||||
assert(_pBackdrop != nullptr);
|
||||
CBofRect cRect = _pBackdrop->getRect();
|
||||
|
||||
// Create the dialog box
|
||||
create("DialogBox", cRect.left, cRect.top, cRect.width(), cRect.height(), pParent, nID);
|
||||
}
|
||||
|
||||
CBofDialog::~CBofDialog() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
delete _pDlgBackground;
|
||||
_pDlgBackground = nullptr;
|
||||
}
|
||||
|
||||
|
||||
ErrorCode CBofDialog::create(const char *pszName, int x, int y, int nWidth, int nHeight, CBofWindow *pParent, uint32 nControlID) {
|
||||
assert(isValidObject(this));
|
||||
assert(pszName != nullptr);
|
||||
|
||||
// Dialog boxes must have parent windows
|
||||
assert(pParent != nullptr);
|
||||
|
||||
// Inits
|
||||
_parent = pParent;
|
||||
_nID = nControlID;
|
||||
|
||||
// Remember the name of this window
|
||||
Common::strlcpy(_szTitle, pszName, MAX_TITLE);
|
||||
|
||||
// Calculate effective bounds
|
||||
Common::Rect stRect(x, y, x + nWidth, y + nHeight);
|
||||
if (pParent != nullptr)
|
||||
stRect.translate(pParent->getWindowRect().left, pParent->getWindowRect().top);
|
||||
|
||||
_cRect = stRect;
|
||||
|
||||
delete _surface;
|
||||
_surface = new Graphics::ManagedSurface(*g_engine->getScreen(), stRect);
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
|
||||
ErrorCode CBofDialog::create(const char *pszName, CBofRect *pRect, CBofWindow *pParent, uint32 nControlID) {
|
||||
assert(isValidObject(this));
|
||||
assert(pszName != nullptr);
|
||||
|
||||
CBofRect cRect;
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int nWidth = USE_DEFAULT;
|
||||
int nHeight = USE_DEFAULT;
|
||||
|
||||
if ((pRect == nullptr) && (_pBackdrop != nullptr)) {
|
||||
cRect = _pBackdrop->getRect();
|
||||
pRect = &cRect;
|
||||
}
|
||||
|
||||
if (pRect != nullptr) {
|
||||
x = pRect->left;
|
||||
y = pRect->top;
|
||||
nWidth = pRect->width();
|
||||
nHeight = pRect->height();
|
||||
}
|
||||
|
||||
return create(pszName, x, y, nWidth, nHeight, pParent, nControlID);
|
||||
}
|
||||
|
||||
|
||||
void CBofDialog::onClose() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
// Release any capture/focus that was active
|
||||
CBofApp *app = CBofApp::getApp();
|
||||
app->setCaptureControl(nullptr);
|
||||
app->setFocusControl(nullptr);
|
||||
|
||||
if (_parent != nullptr) {
|
||||
CBofWindow *pParent = _parent;
|
||||
pParent->enable();
|
||||
|
||||
// The parent window MUST now be enabled
|
||||
assert(pParent->isEnabled());
|
||||
}
|
||||
|
||||
// If we saved the background, then paint it
|
||||
if (_lFlags & BOFDLG_SAVEBACKGND) {
|
||||
paintBackground();
|
||||
|
||||
} else if (_parent != nullptr) {
|
||||
// Need to validate the portion of the parent window that we obscured
|
||||
// (but that we also have already repainted)
|
||||
// Otherwise, we need to cause the parent to repaint itself
|
||||
_parent->invalidateRect(nullptr);
|
||||
}
|
||||
|
||||
CBofWindow::onClose();
|
||||
|
||||
// Stop our personal message loop
|
||||
_bEndDialog = true;
|
||||
}
|
||||
|
||||
|
||||
ErrorCode CBofDialog::paint(CBofRect *pRect) {
|
||||
assert(isValidObject(this));
|
||||
assert(pRect != nullptr);
|
||||
|
||||
// Repaint the background behind the dialog
|
||||
if (!_bFirstTime) {
|
||||
paintBackground();
|
||||
}
|
||||
_bFirstTime = false;
|
||||
|
||||
// Paint the dialog (uses bitmap instead of standard windows dialog)
|
||||
if (hasBackdrop()) {
|
||||
paintBackdrop(pRect, COLOR_WHITE);
|
||||
}
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
|
||||
ErrorCode CBofDialog::paintBackground() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
// Paint back the background
|
||||
if (_pDlgBackground != nullptr) {
|
||||
_errCode = _pDlgBackground->paint(this, 0, 0);
|
||||
}
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
|
||||
ErrorCode CBofDialog::saveBackground() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
if (_lFlags & BOFDLG_SAVEBACKGND) {
|
||||
CBofPalette *pPalette = CBofApp::getApp()->getPalette();
|
||||
|
||||
// Remove any previous background
|
||||
delete _pDlgBackground;
|
||||
// Save a copy of the background
|
||||
_pDlgBackground = new CBofBitmap(width(), height(), pPalette);
|
||||
|
||||
_pDlgBackground->captureScreen(this, &_cRect);
|
||||
_pDlgBackground->setReadOnly(true);
|
||||
}
|
||||
|
||||
_bFirstTime = false;
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
|
||||
ErrorCode CBofDialog::killBackground() {
|
||||
delete _pDlgBackground;
|
||||
_pDlgBackground = nullptr;
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
|
||||
void CBofDialog::onPaint(CBofRect *pRect) {
|
||||
assert(isValidObject(this));
|
||||
assert(pRect != nullptr);
|
||||
|
||||
if (_bFirstTime) {
|
||||
saveBackground();
|
||||
}
|
||||
|
||||
paint(pRect);
|
||||
|
||||
_bHavePainted = true;
|
||||
}
|
||||
|
||||
|
||||
int CBofDialog::doModal() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
// The dialog box must have been successfully created first
|
||||
assert(isCreated());
|
||||
|
||||
CBofWindow *pLastActive = getActiveWindow();
|
||||
setActive();
|
||||
onInitDialog();
|
||||
|
||||
// Display the window
|
||||
show();
|
||||
|
||||
updateWindow();
|
||||
|
||||
// Start our own message loop (simulate Modal)
|
||||
_bEndDialog = false;
|
||||
|
||||
// Acquire and dispatch messages until quit message is received,
|
||||
// or until there are too many errors.
|
||||
Graphics::FrameLimiter limiter(g_system, 60, false);
|
||||
|
||||
while (!_bEndDialog && !g_engine->shouldQuit() && (CBofError::getErrorCount() < MAX_ERRORS)) {
|
||||
CBofSound::audioTask();
|
||||
CBofTimer::handleTimers();
|
||||
|
||||
if (isCreated()) {
|
||||
onMainLoop();
|
||||
}
|
||||
|
||||
handleEvents();
|
||||
|
||||
limiter.delayBeforeSwap();
|
||||
g_engine->getScreen()->update();
|
||||
limiter.startFrame();
|
||||
}
|
||||
|
||||
if (pLastActive != nullptr) {
|
||||
pLastActive->setActive();
|
||||
} else {
|
||||
_pActiveWindow = nullptr;
|
||||
}
|
||||
|
||||
return _nReturnValue;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// Virtual functions that the user can override if they want to
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
void CBofDialog::onInitDialog() {}
|
||||
|
||||
} // namespace SpaceBar
|
||||
} // namespace Bagel
|
||||
144
engines/bagel/spacebar/boflib/gui/dialog.h
Normal file
144
engines/bagel/spacebar/boflib/gui/dialog.h
Normal file
@@ -0,0 +1,144 @@
|
||||
/* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/".
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BAGEL_BOFLIB_GUI_DIALOG_H
|
||||
#define BAGEL_BOFLIB_GUI_DIALOG_H
|
||||
|
||||
#include "bagel/spacebar/boflib/gui/window.h"
|
||||
#include "bagel/spacebar/boflib/gfx/bitmap.h"
|
||||
|
||||
namespace Bagel {
|
||||
namespace SpaceBar {
|
||||
|
||||
#define IDOK 1
|
||||
#define IDCANCEL 2
|
||||
|
||||
#define BOFDLG_TRANSPARENT 0x00000001
|
||||
#define BOFDLG_SAVEBACKGND 0x00000002
|
||||
|
||||
#define BOFDLG_DEFAULT (BOFDLG_TRANSPARENT /* | BOFDLG_SAVEBACKGND*/)
|
||||
|
||||
class CBofDialog : public CBofWindow {
|
||||
protected:
|
||||
CBofBitmap *_pDlgBackground = nullptr;
|
||||
uint32 _lFlags = 0;
|
||||
int _nReturnValue = 0;
|
||||
|
||||
bool _bFirstTime = false;
|
||||
bool _bTempBitmap = false;
|
||||
bool _bEndDialog = false;
|
||||
bool _bHavePainted = false;
|
||||
|
||||
protected:
|
||||
virtual ErrorCode paint(CBofRect *pRect);
|
||||
virtual ErrorCode paintBackground();
|
||||
virtual ErrorCode saveBackground();
|
||||
virtual ErrorCode killBackground();
|
||||
|
||||
void onPaint(CBofRect *pRect) override;
|
||||
void onClose() override;
|
||||
virtual void onInitDialog();
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
CBofDialog();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
CBofDialog(const char *pszFileName, CBofWindow *pParent, uint32 nID = 0, uint32 lFlags = BOFDLG_DEFAULT);
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~CBofDialog();
|
||||
|
||||
/**
|
||||
* Creates the dialog
|
||||
* @param pszName Dialog name
|
||||
* @param x Top-left X position
|
||||
* @param y Top-left Y position
|
||||
* @param nWidth Width
|
||||
* @param nHeight Height
|
||||
* @param pParent Parent window
|
||||
* @param nControlID Control Id
|
||||
* @return Error return code
|
||||
*/
|
||||
ErrorCode create(const char *pszName, int x, int y, int nWidth, int nHeight, CBofWindow *pParent, uint32 nControlID = 0) override;
|
||||
|
||||
/**
|
||||
* Creates the dialog
|
||||
* @param pszName Dialog name
|
||||
* @param pRect Dialog bounds
|
||||
* @param pParent Parent window
|
||||
* @param nControlID Control Id
|
||||
* @return Error return code
|
||||
*/
|
||||
ErrorCode create(const char *pszName, CBofRect *pRect, CBofWindow *pParent, uint32 nControlID = 0) override;
|
||||
|
||||
/**
|
||||
* Set the dialog flags
|
||||
*/
|
||||
void setFlags(uint32 lFlags) {
|
||||
_lFlags = lFlags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the dialog's flags
|
||||
*/
|
||||
uint32 getFlags() const {
|
||||
return _lFlags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the dialog as a modal
|
||||
*/
|
||||
int doModal();
|
||||
|
||||
/**
|
||||
* End the dialog modal display
|
||||
*/
|
||||
void endModal() {
|
||||
_bEndDialog = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the dialog's return value
|
||||
*/
|
||||
void setReturnValue(int nValue) {
|
||||
_nReturnValue = nValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the dialog's return value
|
||||
* @return
|
||||
*/
|
||||
int getReturnValue() const {
|
||||
return _nReturnValue;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace SpaceBar
|
||||
} // namespace Bagel
|
||||
|
||||
#endif
|
||||
141
engines/bagel/spacebar/boflib/gui/edit_text.cpp
Normal file
141
engines/bagel/spacebar/boflib/gui/edit_text.cpp
Normal file
@@ -0,0 +1,141 @@
|
||||
/* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "bagel/spacebar/boflib/app.h"
|
||||
#include "bagel/spacebar/boflib/gui/edit_text.h"
|
||||
#include "bagel/spacebar/boflib/gfx/text.h"
|
||||
#include "bagel/spacebar/boflib/std_keys.h"
|
||||
|
||||
namespace Bagel {
|
||||
namespace SpaceBar {
|
||||
|
||||
CBofEditText::CBofEditText(const char *pszName, int x, int y, int nWidth,
|
||||
int nHeight, CBofWindow *pParent)
|
||||
: CBofWindow(pszName, x, y, nWidth, nHeight, pParent) {
|
||||
create(pszName, x, y, nWidth, nHeight, pParent);
|
||||
}
|
||||
|
||||
|
||||
ErrorCode CBofEditText::create(const char *pszName, CBofRect *pRect,
|
||||
CBofWindow *pParent, uint32 nControlID) {
|
||||
assert(isValidObject(this));
|
||||
assert(pszName != nullptr);
|
||||
|
||||
// Remember who our parent is
|
||||
_parent = pParent;
|
||||
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int nWidth = USE_DEFAULT;
|
||||
int nHeight = USE_DEFAULT;
|
||||
|
||||
if (pRect != nullptr) {
|
||||
x = pRect->left;
|
||||
y = pRect->top;
|
||||
nWidth = pRect->width();
|
||||
nHeight = pRect->height();
|
||||
}
|
||||
|
||||
return create(pszName, x, y, nWidth, nHeight, pParent, nControlID);
|
||||
}
|
||||
|
||||
|
||||
ErrorCode CBofEditText::create(const char *pszName, int x, int y,
|
||||
int nWidth, int nHeight, CBofWindow *pParent, uint32 nControlID) {
|
||||
assert(isValidObject(this));
|
||||
assert(pszName != nullptr);
|
||||
|
||||
// Remember who our parent is
|
||||
_parent = pParent;
|
||||
_nID = nControlID;
|
||||
|
||||
// Remember the name of this window
|
||||
Common::strcpy_s(_szTitle, pszName);
|
||||
|
||||
// Retain screen coordinates for this window
|
||||
_cWindowRect.setRect(x, y, x + nWidth - 1, y + nHeight - 1);
|
||||
|
||||
CBofPalette *pPalette = CBofApp::getApp()->getPalette();
|
||||
if (pPalette != nullptr) {
|
||||
selectPalette(pPalette);
|
||||
}
|
||||
|
||||
// Retain local coordinates (based on own window)
|
||||
_cRect.setRect(0, 0, _cWindowRect.width() - 1, _cWindowRect.height() - 1);
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
void CBofEditText::setText(const char *pszString) {
|
||||
assert(isValidObject(this));
|
||||
assert(isCreated());
|
||||
assert(pszString != nullptr);
|
||||
|
||||
_text = pszString;
|
||||
|
||||
updateWindow();
|
||||
}
|
||||
|
||||
|
||||
void CBofEditText::onPaint(CBofRect *pRect) {
|
||||
assert(isValidObject(this));
|
||||
assert(pRect != nullptr);
|
||||
|
||||
if (hasFocus())
|
||||
fillRect(nullptr, 255);
|
||||
|
||||
// Draw the text, if any
|
||||
if (!_text.isEmpty()) {
|
||||
CBofString tmp = _text + "|";
|
||||
|
||||
paintText(this, &_cRect, tmp.getBuffer(),
|
||||
12, 0, CTEXT_COLOR,
|
||||
JUSTIFY_LEFT,
|
||||
FORMAT_TOP_LEFT | FORMAT_SINGLE_LINE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void CBofEditText::onLButtonDown(uint32 nFlags, CBofPoint *pPoint, void *) {
|
||||
// First click focuses text input
|
||||
setFocus();
|
||||
_cursorPos = _text.getBufferSize();
|
||||
|
||||
updateWindow();
|
||||
}
|
||||
|
||||
void CBofEditText::onKeyHit(uint32 lKey, uint32 lRepCount) {
|
||||
if (lKey >= 32 && lKey <= 127) {
|
||||
CBofString tmp = _text + lKey;
|
||||
CBofRect rect = calculateTextRect(this, &tmp, 12, 0);
|
||||
|
||||
if ((_cRect.width() - rect.width()) > 10) {
|
||||
setText(tmp);
|
||||
}
|
||||
|
||||
} else if (lKey == BKEY_BACK && !_text.isEmpty()) {
|
||||
_text.deleteLastChar();
|
||||
updateWindow();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace SpaceBar
|
||||
} // namespace Bagel
|
||||
62
engines/bagel/spacebar/boflib/gui/edit_text.h
Normal file
62
engines/bagel/spacebar/boflib/gui/edit_text.h
Normal file
@@ -0,0 +1,62 @@
|
||||
|
||||
/* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BAGEL_BOFLIB_GUI_EDIT_TEXT_H
|
||||
#define BAGEL_BOFLIB_GUI_EDIT_TEXT_H
|
||||
|
||||
#include "bagel/spacebar/boflib/gui/window.h"
|
||||
#include "bagel/boflib/string.h"
|
||||
|
||||
namespace Bagel {
|
||||
namespace SpaceBar {
|
||||
|
||||
class CBofEditText : public CBofWindow {
|
||||
private:
|
||||
CBofString _text;
|
||||
size_t _cursorPos = 0;
|
||||
|
||||
protected:
|
||||
void onLButtonDown(uint32 nFlags, CBofPoint *pPoint, void * = nullptr) override;
|
||||
void onKeyHit(uint32 lKey, uint32 lRepCount) override;
|
||||
|
||||
public:
|
||||
CBofEditText() {
|
||||
}
|
||||
|
||||
CBofEditText(const char *pszName, int x, int y, int nWidth, int nHeight, CBofWindow *pParent);
|
||||
|
||||
ErrorCode create(const char *pszName, int x, int y, int nWidth, int nHeight, CBofWindow *pParent, uint32 nControlID = 0) override;
|
||||
ErrorCode create(const char *pszName, CBofRect *pRect, CBofWindow *pParent, uint32 nControlID = 0) override;
|
||||
|
||||
CBofString getText() const {
|
||||
return _text;
|
||||
}
|
||||
|
||||
void setText(const char *pszString);
|
||||
|
||||
void onPaint(CBofRect *pRect) override;
|
||||
};
|
||||
|
||||
} // namespace SpaceBar
|
||||
} // namespace Bagel
|
||||
|
||||
#endif
|
||||
549
engines/bagel/spacebar/boflib/gui/list_box.cpp
Normal file
549
engines/bagel/spacebar/boflib/gui/list_box.cpp
Normal file
@@ -0,0 +1,549 @@
|
||||
/* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "bagel/spacebar/boflib/app.h"
|
||||
#include "bagel/spacebar/boflib/gfx/text.h"
|
||||
#include "bagel/spacebar/boflib/gui/list_box.h"
|
||||
|
||||
#include "bagel/spacebar/boflib/std_keys.h"
|
||||
|
||||
namespace Bagel {
|
||||
namespace SpaceBar {
|
||||
|
||||
#define TEXT_ITEM_HEIGHT 24
|
||||
|
||||
|
||||
CBofListBox::CBofListBox() {
|
||||
_cTextColor = CTEXT_COLOR;
|
||||
_cHighColor = CTEXT_COLOR;
|
||||
_nTextSize = 10;
|
||||
_nTextWeight = TEXT_NORMAL;
|
||||
_nNumItems = 0;
|
||||
_n1stVisible = 0;
|
||||
_nPageSize = 0;
|
||||
_pWork = nullptr;
|
||||
_nItemHeight = TEXT_ITEM_HEIGHT;
|
||||
_nState = LISTBOX_NORMAL;
|
||||
_nTextFont = FONT_DEFAULT;
|
||||
|
||||
// Initialized the selected item
|
||||
CBofListBox::clearSelection();
|
||||
}
|
||||
|
||||
|
||||
CBofListBox::~CBofListBox() {
|
||||
// Kill the temporary work area
|
||||
delete _pWork;
|
||||
_pWork = nullptr;
|
||||
|
||||
deleteAll(false);
|
||||
}
|
||||
|
||||
void CBofListBox::clearSelection() {
|
||||
_nSelectedItem = -1;
|
||||
}
|
||||
|
||||
void CBofListBox::insertBefore(int nIndex, const CBofString &cString, bool bRepaint) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
ListBoxItem lbi;
|
||||
lbi._pTextStr = new CBofString(cString);
|
||||
lbi._nTextLineColor = COLOR_USE_DEFAULT;
|
||||
|
||||
_cTextItems.insertBefore(nIndex, lbi);
|
||||
|
||||
// One more item
|
||||
_nNumItems++;
|
||||
|
||||
clearSelection();
|
||||
|
||||
if (bRepaint && isCreated() && isVisible()) {
|
||||
repaintAll();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CBofListBox::insertAfter(int nIndex, const CBofString &cString, bool bRepaint) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
ListBoxItem lbi;
|
||||
lbi._pTextStr = new CBofString(cString);
|
||||
lbi._nTextLineColor = COLOR_USE_DEFAULT;
|
||||
|
||||
_cTextItems.insertAfter(nIndex, lbi);
|
||||
|
||||
// One more item
|
||||
_nNumItems++;
|
||||
|
||||
if (bRepaint && isCreated() && isVisible()) {
|
||||
repaintAll();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CBofListBox::addToHead(const CBofString &cString, bool bRepaint) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
ListBoxItem lbi;
|
||||
lbi._pTextStr = new CBofString(cString);
|
||||
lbi._nTextLineColor = COLOR_USE_DEFAULT;
|
||||
|
||||
_cTextItems.addToHead(lbi);
|
||||
|
||||
// One more item
|
||||
_nNumItems++;
|
||||
|
||||
clearSelection();
|
||||
|
||||
if (bRepaint && isCreated() && isVisible()) {
|
||||
repaintAll();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CBofListBox::addToTail(const CBofString &cString, bool bRepaint) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
ListBoxItem lbi;
|
||||
lbi._pTextStr = new CBofString(cString);
|
||||
lbi._nTextLineColor = COLOR_USE_DEFAULT;
|
||||
|
||||
_cTextItems.addToTail(lbi);
|
||||
|
||||
// One more item
|
||||
_nNumItems++;
|
||||
|
||||
clearSelection();
|
||||
|
||||
if (bRepaint && isCreated() && isVisible()) {
|
||||
repaintAll();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ErrorCode CBofListBox::delItem(int nIndex, bool bRepaint) {
|
||||
assert(isValidObject(this));
|
||||
assert(nIndex >= 0 && nIndex < _nNumItems);
|
||||
|
||||
_cTextItems.remove(nIndex);
|
||||
|
||||
// One less item
|
||||
_nNumItems--;
|
||||
|
||||
if (_n1stVisible >= _nNumItems) {
|
||||
_n1stVisible = _nNumItems - 1;
|
||||
if (_n1stVisible < 0)
|
||||
_n1stVisible = 0;
|
||||
}
|
||||
|
||||
clearSelection();
|
||||
|
||||
|
||||
if (bRepaint && isCreated() && isVisible()) {
|
||||
repaintAll();
|
||||
}
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
ErrorCode CBofListBox::deleteAll(bool bRepaint) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
// Switch item to be pointer to cbofstring instead of the item itself
|
||||
int nCount = _cTextItems.getCount();
|
||||
|
||||
for (int i = 0; i < nCount; i++) {
|
||||
ListBoxItem lbi = _cTextItems.getNodeItem(i);
|
||||
delete lbi._pTextStr;
|
||||
}
|
||||
|
||||
_cTextItems.removeAll();
|
||||
_nNumItems = 0;
|
||||
_n1stVisible = 0;
|
||||
|
||||
clearSelection();
|
||||
|
||||
if (bRepaint && isCreated() && isVisible()) {
|
||||
repaintAll();
|
||||
}
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
|
||||
void CBofListBox::onLButtonDown(uint32 /*nFlags*/, CBofPoint *pPoint, void *) {
|
||||
assert(isValidObject(this));
|
||||
assert(pPoint != nullptr);
|
||||
|
||||
int nIndex = (pPoint->y / _nItemHeight) + _n1stVisible;
|
||||
if (nIndex < _nNumItems) {
|
||||
|
||||
_nSelectedItem = nIndex; // Set the selected item
|
||||
_nState = LISTBOX_SELECT;
|
||||
|
||||
if (_parent != nullptr) {
|
||||
_parent->setPrevMouseDown(*pPoint);
|
||||
_parent->onBofListBox(this, nIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CBofListBox::onLButtonDblClk(uint32 /*nFlags*/, CBofPoint *pPoint) {
|
||||
assert(isValidObject(this));
|
||||
assert(pPoint != nullptr);
|
||||
|
||||
int nIndex = (pPoint->y / _nItemHeight) + _n1stVisible;
|
||||
|
||||
if (nIndex < _nNumItems) {
|
||||
_nSelectedItem = nIndex; // Set the selected item
|
||||
_nState = LISTBOX_USENOW;
|
||||
|
||||
if (_parent != nullptr) {
|
||||
_parent->setPrevMouseDown(*pPoint);
|
||||
_parent->onBofListBox(this, nIndex);
|
||||
}
|
||||
}
|
||||
|
||||
setFocus();
|
||||
}
|
||||
|
||||
|
||||
void CBofListBox::onKeyHit(uint32 lKey, uint32 lRepCount) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
switch (lKey) {
|
||||
case BKEY_HOME:
|
||||
scrollTo(0);
|
||||
break;
|
||||
|
||||
case BKEY_END:
|
||||
scrollTo(_nNumItems);
|
||||
break;
|
||||
|
||||
case BKEY_UP:
|
||||
lineUp();
|
||||
break;
|
||||
|
||||
case BKEY_DOWN:
|
||||
lineDown();
|
||||
break;
|
||||
|
||||
case BKEY_PAGEUP:
|
||||
pageUp();
|
||||
break;
|
||||
|
||||
case BKEY_PAGEDOWN:
|
||||
pageDown();
|
||||
break;
|
||||
|
||||
default:
|
||||
// Call the previous windows onkeyhit
|
||||
CBofWindow *pParent = getParent();
|
||||
if (pParent && pParent != this) {
|
||||
pParent->onKeyHit(lKey, lRepCount);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ErrorCode CBofListBox::scrollUp(const int nLines) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
// If all the items fit on a single page, make this operation a no-op.
|
||||
if (_nNumItems <= _nPageSize) {
|
||||
return scrollTo(_n1stVisible);
|
||||
}
|
||||
|
||||
int nNewLine = _n1stVisible - nLines;
|
||||
|
||||
if (nNewLine < 0) {
|
||||
nNewLine = 0;
|
||||
|
||||
} else if (nNewLine > (_nNumItems - _nPageSize)) {
|
||||
// If the line requested to be the top of the page
|
||||
// would cause fewer than _nPageSize lines to be displayed,
|
||||
// snap nNewLine to be equal to the top of the last full page.
|
||||
nNewLine = (_nNumItems - _nPageSize);
|
||||
}
|
||||
|
||||
return scrollTo(nNewLine);
|
||||
}
|
||||
|
||||
ErrorCode CBofListBox::scrollTo(const int nLine) {
|
||||
assert(isValidObject(this));
|
||||
assert(nLine >= 0 && nLine <= _nNumItems);
|
||||
|
||||
// Only update the screen if the list actually moved
|
||||
if (_n1stVisible != nLine) {
|
||||
_n1stVisible = nLine;
|
||||
|
||||
if (nLine >= _nNumItems) {
|
||||
assert(_nNumItems > 0);
|
||||
_n1stVisible--;
|
||||
}
|
||||
|
||||
// Show the text box
|
||||
repaintAll();
|
||||
}
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
|
||||
void CBofListBox::onPaint(CBofRect * /*pRect*/) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
_nPageSize = height() / _nItemHeight;
|
||||
|
||||
if (_pBackdrop == nullptr) {
|
||||
saveBackground();
|
||||
}
|
||||
|
||||
repaintAll();
|
||||
}
|
||||
|
||||
|
||||
void CBofListBox::killBackground() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
delete _pBackdrop;
|
||||
_pBackdrop = nullptr;
|
||||
}
|
||||
|
||||
|
||||
ErrorCode CBofListBox::saveBackground() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
killBackground();
|
||||
_pBackdrop = new CBofBitmap(width(), height(), CBofApp::getApp()->getPalette());
|
||||
|
||||
if ((_parent != nullptr) && (_parent->getBackdrop() != nullptr)) {
|
||||
CBofRect cRect = _pBackdrop->getRect();
|
||||
_parent->getBackdrop()->paint(_pBackdrop, &cRect, &_cWindowRect);
|
||||
} else {
|
||||
_pBackdrop->captureScreen(this, &_cRect);
|
||||
}
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
ErrorCode CBofListBox::createWorkArea() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
if (_pBackdrop == nullptr) {
|
||||
saveBackground();
|
||||
}
|
||||
|
||||
if (_pWork == nullptr) {
|
||||
assert(_pBackdrop != nullptr);
|
||||
_pWork = new CBofBitmap(width(), height(), _pBackdrop->getPalette());
|
||||
}
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
|
||||
ErrorCode CBofListBox::repaintAll() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
if (!errorOccurred()) {
|
||||
assert(isCreated());
|
||||
|
||||
int nCurFont = getFont();
|
||||
setFont(_nTextFont);
|
||||
|
||||
createWorkArea();
|
||||
|
||||
if (_pWork != nullptr) {
|
||||
_pWork->lock();
|
||||
|
||||
int nIndexedColor = _pWork->getPalette()->getNearestIndex(_cTextColor);
|
||||
|
||||
// prepare the background
|
||||
//
|
||||
assert(_pBackdrop != nullptr);
|
||||
_pBackdrop->paint(_pWork);
|
||||
|
||||
for (int i = 0; i < _nPageSize; i++) {
|
||||
CBofRect cRect;
|
||||
cRect.setRect(0, i * _nItemHeight, width() - 1, (i + 1) * _nItemHeight - 1);
|
||||
|
||||
if (i + _n1stVisible < _nNumItems) {
|
||||
// If this item is currently selected and we have a high color
|
||||
if ((i + _n1stVisible == _nSelectedItem) && (_cHighColor != _cTextColor)) {
|
||||
// display text highlighted
|
||||
paintText(_pWork,
|
||||
&cRect,
|
||||
*(_cTextItems.getNodeItem(i + _n1stVisible)._pTextStr),
|
||||
_nTextSize,
|
||||
_nTextWeight,
|
||||
_cHighColor,
|
||||
JUSTIFY_LEFT,
|
||||
FORMAT_TOP_LEFT | FORMAT_SINGLE_LINE,
|
||||
getFont());
|
||||
} else {
|
||||
// Display text
|
||||
// Allow list items of different colors.
|
||||
COLORREF rgbTextColor = _cTextColor;
|
||||
if (_cTextItems.getNodeItem(i + _n1stVisible)._nTextLineColor != COLOR_USE_DEFAULT) {
|
||||
rgbTextColor = _cTextItems.getNodeItem(i + _n1stVisible)._nTextLineColor;
|
||||
}
|
||||
|
||||
paintText(_pWork,
|
||||
&cRect,
|
||||
*(_cTextItems.getNodeItem(i + _n1stVisible)._pTextStr),
|
||||
_nTextSize,
|
||||
_nTextWeight,
|
||||
rgbTextColor,
|
||||
JUSTIFY_LEFT,
|
||||
FORMAT_TOP_LEFT | FORMAT_SINGLE_LINE,
|
||||
getFont());
|
||||
}
|
||||
|
||||
CBofPoint bl(cRect.bottomLeft()), br(cRect.bottomRight());
|
||||
_pWork->line(&bl, &br, (byte)nIndexedColor);
|
||||
}
|
||||
}
|
||||
|
||||
// Show final image on screen
|
||||
_pWork->paint(this);
|
||||
|
||||
_pWork->unlock();
|
||||
}
|
||||
|
||||
// Reset the font
|
||||
setFont(nCurFont);
|
||||
}
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
|
||||
ErrorCode CBofListBox::repaintItem(int nIndex) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
if (!errorOccurred()) {
|
||||
assert(nIndex >= 0 && nIndex < _nNumItems);
|
||||
int nCurFont = getFont();
|
||||
setFont(_nTextFont); // Set the proper font
|
||||
|
||||
// If this item is visible, then repaint it.
|
||||
if (nIndex >= _n1stVisible && nIndex <= _n1stVisible + _nPageSize) {
|
||||
int i = nIndex - _n1stVisible;
|
||||
|
||||
createWorkArea();
|
||||
int nIndexedColor = _pWork->getPalette()->getNearestIndex(_cTextColor);
|
||||
|
||||
_pWork->lock();
|
||||
|
||||
// Calculate area for this text item
|
||||
CBofRect cRect;
|
||||
cRect.setRect(0, i * _nItemHeight, width() - 1, (i + 1) * _nItemHeight - 1);
|
||||
|
||||
// Prepare the background
|
||||
assert(_pBackdrop != nullptr);
|
||||
_pBackdrop->paint(_pWork, &cRect, &cRect);
|
||||
|
||||
// If this item is currently selected and we have a high color
|
||||
if ((nIndex == _nSelectedItem) && (_cHighColor != _cTextColor)) {
|
||||
// Display text highlighted
|
||||
paintText(_pWork,
|
||||
&cRect,
|
||||
*(_cTextItems.getNodeItem(nIndex)._pTextStr),
|
||||
_nTextSize,
|
||||
_nTextWeight,
|
||||
_cHighColor,
|
||||
JUSTIFY_LEFT,
|
||||
FORMAT_TOP_LEFT | FORMAT_SINGLE_LINE,
|
||||
getFont());
|
||||
|
||||
} else {
|
||||
// Display text
|
||||
// Allow list items of different colors.
|
||||
COLORREF rgbTextColor = _cTextColor;
|
||||
if (_cTextItems.getNodeItem(i + _n1stVisible)._nTextLineColor != COLOR_USE_DEFAULT) {
|
||||
rgbTextColor = _cTextItems.getNodeItem(i + _n1stVisible)._nTextLineColor;
|
||||
}
|
||||
paintText(_pWork,
|
||||
&cRect,
|
||||
*(_cTextItems.getNodeItem(nIndex)._pTextStr),
|
||||
_nTextSize,
|
||||
_nTextWeight,
|
||||
rgbTextColor,
|
||||
JUSTIFY_LEFT,
|
||||
FORMAT_TOP_LEFT | FORMAT_SINGLE_LINE,
|
||||
getFont());
|
||||
}
|
||||
CBofPoint bl(cRect.bottomLeft()), br(cRect.bottomRight());
|
||||
_pWork->line(&bl, &br, (byte)nIndexedColor);
|
||||
|
||||
// Show final image on screen
|
||||
_pWork->paint(this, &cRect, &cRect);
|
||||
|
||||
_pWork->unlock();
|
||||
}
|
||||
|
||||
// Reset the font
|
||||
setFont(nCurFont);
|
||||
}
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
|
||||
void CBofListBox::setSelectedItem(int nItem, bool bRepaint) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
// Set highlighted item
|
||||
_nSelectedItem = nItem;
|
||||
|
||||
if (bRepaint) {
|
||||
repaintAll();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CBofString CBofListBox::getText(int nIndex) {
|
||||
return *(_cTextItems.getNodeItem(nIndex)._pTextStr);
|
||||
}
|
||||
|
||||
|
||||
void CBofListBox::setText(int nIndex, const CBofString &cStr) {
|
||||
|
||||
ListBoxItem lbi = _cTextItems.getNodeItem(nIndex);
|
||||
*lbi._pTextStr = cStr;
|
||||
|
||||
_cTextItems.setNodeItem(nIndex, lbi);
|
||||
}
|
||||
|
||||
|
||||
void CBofListBox::setTextLineColor(int nIndex, COLORREF rgbColor) {
|
||||
|
||||
ListBoxItem lbi = _cTextItems.getNodeItem(nIndex);
|
||||
lbi._nTextLineColor = rgbColor;
|
||||
|
||||
_cTextItems.setNodeItem(nIndex, lbi);
|
||||
}
|
||||
|
||||
} // namespace SpaceBar
|
||||
} // namespace Bagel
|
||||
179
engines/bagel/spacebar/boflib/gui/list_box.h
Normal file
179
engines/bagel/spacebar/boflib/gui/list_box.h
Normal file
@@ -0,0 +1,179 @@
|
||||
|
||||
/* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BAGEL_BOFLIB_GUI_LIST_BOX_H
|
||||
#define BAGEL_BOFLIB_GUI_LIST_BOX_H
|
||||
|
||||
#include "bagel/spacebar/boflib/gui/window.h"
|
||||
#include "bagel/spacebar/boflib/list.h"
|
||||
#include "bagel/boflib/string.h"
|
||||
|
||||
namespace Bagel {
|
||||
namespace SpaceBar {
|
||||
|
||||
#define LISTBOX_NORMAL 0
|
||||
#define LISTBOX_SELECT 1
|
||||
#define LISTBOX_USENOW 2
|
||||
#define COLOR_USE_DEFAULT 0xFFFFFFFF
|
||||
|
||||
class ListBoxItem {
|
||||
public:
|
||||
ListBoxItem() {
|
||||
_pTextStr = nullptr;
|
||||
_nTextLineColor = COLOR_USE_DEFAULT;
|
||||
}
|
||||
|
||||
|
||||
CBofString *_pTextStr;
|
||||
COLORREF _nTextLineColor;
|
||||
};
|
||||
|
||||
class CBofListBox : public CBofWindow {
|
||||
public:
|
||||
CBofListBox();
|
||||
~CBofListBox();
|
||||
|
||||
void setSelectedItem(int nItem, bool bRepaint = true);
|
||||
|
||||
void insertBefore(int nIndex, const CBofString &cString, bool bRepaint = true);
|
||||
void insertAfter(int nIndex, const CBofString &cString, bool bRepaint = true);
|
||||
|
||||
void addToHead(const CBofString &cString, bool bRepaint = true);
|
||||
void addToTail(const CBofString &cString, bool bRepaint = true);
|
||||
|
||||
ErrorCode delItem(int nIndex, bool bRepaint = true);
|
||||
ErrorCode deleteAll(bool bRepaint = true);
|
||||
|
||||
int getNumItems() {
|
||||
return _nNumItems;
|
||||
}
|
||||
CBofString getText(int nIndex);
|
||||
void setText(int nIndex, const CBofString &cStr);
|
||||
|
||||
void setTextLineColor(int nIndex, COLORREF rgbColor);
|
||||
|
||||
ErrorCode lineUp() {
|
||||
return scrollUp(1);
|
||||
}
|
||||
ErrorCode lineDown() {
|
||||
return scrollDown(1);
|
||||
}
|
||||
|
||||
ErrorCode pageUp() {
|
||||
return scrollUp(_nPageSize);
|
||||
}
|
||||
ErrorCode pageDown() {
|
||||
return scrollDown(_nPageSize);
|
||||
}
|
||||
|
||||
ErrorCode scrollUp(int nLines);
|
||||
ErrorCode scrollDown(const int nLines) {
|
||||
return scrollUp(-nLines);
|
||||
}
|
||||
|
||||
ErrorCode scrollTo(int nLine);
|
||||
|
||||
ErrorCode createWorkArea();
|
||||
ErrorCode saveBackground();
|
||||
void killBackground();
|
||||
|
||||
void setHighlightColor(COLORREF cHighColor) {
|
||||
_cHighColor = cHighColor;
|
||||
}
|
||||
COLORREF getHighlightColor() {
|
||||
return _cHighColor;
|
||||
}
|
||||
|
||||
void setTextColor(COLORREF cColor) {
|
||||
_cTextColor = cColor;
|
||||
}
|
||||
COLORREF getTextColor() {
|
||||
return _cTextColor;
|
||||
}
|
||||
|
||||
void setPointSize(int nSize) {
|
||||
_nTextSize = nSize;
|
||||
}
|
||||
int getPointSize() {
|
||||
return _nTextSize;
|
||||
}
|
||||
|
||||
void setWeight(int nWeight) {
|
||||
_nTextWeight = nWeight;
|
||||
}
|
||||
int getWeight() {
|
||||
return _nTextWeight;
|
||||
}
|
||||
|
||||
void setItemHeight(int nHeight) {
|
||||
_nItemHeight = nHeight;
|
||||
}
|
||||
int getItemHeight() {
|
||||
return _nItemHeight;
|
||||
}
|
||||
|
||||
void setFont(int nFont) {
|
||||
_nTextFont = nFont;
|
||||
}
|
||||
int getFont() {
|
||||
return _nTextFont;
|
||||
}
|
||||
|
||||
int getState() {
|
||||
return _nState;
|
||||
}
|
||||
|
||||
virtual ErrorCode repaintItem(int nIndex);
|
||||
virtual ErrorCode repaintAll();
|
||||
|
||||
protected:
|
||||
virtual void onLButtonDown(uint32 nFlags, CBofPoint *pPoint, void * = nullptr);
|
||||
virtual void onLButtonDblClk(uint32 nFlags, CBofPoint *pPoint);
|
||||
virtual void onKeyHit(uint32 lKey, uint32 lRepCount);
|
||||
virtual void onPaint(CBofRect *pRect);
|
||||
|
||||
/**
|
||||
* Clears the currently selected item
|
||||
*/
|
||||
virtual void clearSelection();
|
||||
|
||||
CBofList<ListBoxItem> _cTextItems;
|
||||
CBofBitmap *_pWork;
|
||||
int _nNumItems;
|
||||
int _n1stVisible;
|
||||
|
||||
int _nPageSize;
|
||||
|
||||
int _nTextSize;
|
||||
int _nTextWeight;
|
||||
COLORREF _cTextColor;
|
||||
COLORREF _cHighColor;
|
||||
int _nSelectedItem;
|
||||
int _nItemHeight;
|
||||
int _nTextFont;
|
||||
int _nState;
|
||||
};
|
||||
|
||||
} // namespace SpaceBar
|
||||
} // namespace Bagel
|
||||
|
||||
#endif
|
||||
376
engines/bagel/spacebar/boflib/gui/movie.cpp
Normal file
376
engines/bagel/spacebar/boflib/gui/movie.cpp
Normal file
@@ -0,0 +1,376 @@
|
||||
/* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/".
|
||||
*
|
||||
*/
|
||||
|
||||
#include "graphics/cursorman.h"
|
||||
|
||||
#include "bagel/boflib/string.h"
|
||||
#include "bagel/spacebar/boflib/gui/movie.h"
|
||||
#include "bagel/spacebar/boflib/gfx/cursor.h"
|
||||
#include "bagel/spacebar/boflib/std_keys.h"
|
||||
|
||||
namespace Bagel {
|
||||
namespace SpaceBar {
|
||||
|
||||
CBofMovie::CBofMovie(CBofWindow *pParent, const char *pszFilename, CBofRect *pBounds, bool bStretch, bool bUseNewPalette, bool bBlackOutWindow) {
|
||||
_bStretch = bStretch;
|
||||
|
||||
// Allow movie to not shift to new palette.
|
||||
_bUseNewPalette = bUseNewPalette;
|
||||
|
||||
// Black out first and last frame of flythroughs and examine movies
|
||||
_bBlackOutWindow = bBlackOutWindow;
|
||||
|
||||
initialize(pParent);
|
||||
open(pszFilename, pBounds);
|
||||
}
|
||||
|
||||
CBofMovie::~CBofMovie() {
|
||||
closeMovie();
|
||||
}
|
||||
|
||||
ErrorCode CBofMovie::initialize(CBofWindow *pParent) {
|
||||
// Movie Stuff
|
||||
_eMovStatus = STOPPED;
|
||||
_bEscCanStop = true;
|
||||
|
||||
// Smacker Stuff
|
||||
_pSbuf = nullptr;
|
||||
_pSmk = nullptr;
|
||||
_bLoop = false;
|
||||
|
||||
// Call dialog box creates
|
||||
if (create("MovieWin", 0, 0, 1, 1, pParent, 1) == ERR_NONE) {
|
||||
setCapture();
|
||||
}
|
||||
|
||||
return ERR_NONE;
|
||||
|
||||
}
|
||||
|
||||
bool CBofMovie::open(const char *sFilename, CBofRect *pBounds) {
|
||||
if (sFilename == nullptr) {
|
||||
assert(sFilename);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pBounds != nullptr) {
|
||||
_cRect = *pBounds;
|
||||
}
|
||||
|
||||
if (openMovie(sFilename)) {
|
||||
// We were given specific rect for movie
|
||||
if (pBounds)
|
||||
reSize(pBounds, true);
|
||||
else
|
||||
// Center the movie to the parent window
|
||||
centerRect();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CBofMovie::openMovie(const char *sFilename) {
|
||||
assert(sFilename[0] != '\0');
|
||||
|
||||
if (_pSmk) {
|
||||
closeMovie();
|
||||
}
|
||||
_pSmk = new Video::SmackerDecoder();
|
||||
_pSmk->setSoundType(Audio::Mixer::kSFXSoundType);
|
||||
|
||||
if (!_pSmk->loadFile(sFilename)) {
|
||||
// Opened failed
|
||||
error("Movie not found=%s", sFilename);
|
||||
}
|
||||
|
||||
// If supposed to stretch into specified window
|
||||
if (_bStretch) {
|
||||
_pSbuf = new Graphics::ManagedSurface(width(), height(), _pSmk->getPixelFormat());
|
||||
} else {
|
||||
_pSbuf = new Graphics::ManagedSurface(_pSmk->getWidth(), _pSmk->getHeight(), _pSmk->getPixelFormat());
|
||||
}
|
||||
|
||||
_srcRect = Common::Rect(_pSmk->getWidth(), _pSmk->getHeight());
|
||||
_dstRect = Common::Rect(_pSbuf->w, _pSbuf->h);
|
||||
|
||||
if (!_bStretch) {
|
||||
_dstRect.moveTo((_pSbuf->w - _pSmk->getWidth()) / 2, (_pSbuf->h - _pSmk->getHeight()) / 2);
|
||||
}
|
||||
|
||||
CBofRect MovieBounds(0, 0, (uint16)_pSbuf->w - 1, (uint16)_pSbuf->h - 1);
|
||||
reSize(&MovieBounds, true);
|
||||
|
||||
// If we have a window that is going to cause a single frame
|
||||
// palette shift, then black it out here.
|
||||
if (_bBlackOutWindow) {
|
||||
fillWindow(COLOR_BLACK);
|
||||
}
|
||||
|
||||
// Smack the current frame into the buffer
|
||||
const Graphics::Surface *frame = _pSmk->decodeNextFrame();
|
||||
if (frame) {
|
||||
_pSbuf->setPalette(_pSmk->getPalette(), 0, 256);
|
||||
_pSbuf->blitFrom(*frame, _srcRect, _dstRect);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CBofMovie::onKeyHit(uint32 lKey, uint32 /*lRepCount*/) {
|
||||
if (_bEscCanStop && lKey == BKEY_ESC) {
|
||||
// Clean up and exit
|
||||
_bLoop = false;
|
||||
stop();
|
||||
onMovieDone();
|
||||
}
|
||||
}
|
||||
|
||||
void CBofMovie::onMainLoop() {
|
||||
if (!_pSmk->needsUpdate() || _eMovStatus == STOPPED)
|
||||
return;
|
||||
|
||||
// Smack the current frame into the buffer
|
||||
const Graphics::Surface *frame = _pSmk->decodeNextFrame();
|
||||
if (_pSmk->hasDirtyPalette()) {
|
||||
_pSbuf->setPalette(_pSmk->getPalette(), 0, 256);
|
||||
}
|
||||
if (frame) {
|
||||
_pSbuf->blitFrom(*frame, _srcRect, _dstRect);
|
||||
updateWindow();
|
||||
}
|
||||
|
||||
if (_eMovStatus == FORWARD) {
|
||||
if (_pSmk->getCurFrame() == (int)_pSmk->getFrameCount() - 1) {
|
||||
if (_bLoop == false) {
|
||||
onMovieDone();
|
||||
} else {
|
||||
seekToStart();
|
||||
_pSmk->start();
|
||||
}
|
||||
}
|
||||
} else if (_eMovStatus == REVERSE) {
|
||||
if ((_pSmk->getCurFrame() == 0) || (_pSmk->getCurFrame() == 1)) {
|
||||
if (_bLoop == false) {
|
||||
onMovieDone();
|
||||
} else {
|
||||
seekToEnd();
|
||||
}
|
||||
} else {
|
||||
setFrame(_pSmk->getCurFrame() - 2); // HACK: Reverse playback
|
||||
}
|
||||
}// MOVIE_REVERSE
|
||||
}
|
||||
|
||||
void CBofMovie::onPaint(CBofRect *) {
|
||||
if (_pSbuf) {
|
||||
getSurface()->blitFrom(*_pSbuf);
|
||||
}
|
||||
}
|
||||
|
||||
void CBofMovie::closeMovie() {
|
||||
delete _pSbuf;
|
||||
_pSbuf = nullptr;
|
||||
|
||||
delete _pSmk;
|
||||
_pSmk = nullptr;
|
||||
}
|
||||
|
||||
void CBofMovie::onClose() {
|
||||
closeMovie();
|
||||
CBofDialog::onClose();
|
||||
}
|
||||
|
||||
void CBofMovie::onMovieDone() {
|
||||
if (!_bLoop) {
|
||||
if (_bCaptured)
|
||||
releaseCapture();
|
||||
|
||||
getParent()->enable();
|
||||
_bEndDialog = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool CBofMovie::play(bool bLoop, bool bEscCanStop) {
|
||||
|
||||
_bEscCanStop = bEscCanStop;
|
||||
_bLoop = bLoop;
|
||||
|
||||
bool bSuccess = play();
|
||||
|
||||
getParent()->disable();
|
||||
getParent()->flushAllMessages();
|
||||
|
||||
CursorMan.showMouse(false);
|
||||
|
||||
doModal();
|
||||
|
||||
CursorMan.showMouse(true);
|
||||
|
||||
return bSuccess;
|
||||
}
|
||||
|
||||
|
||||
bool CBofMovie::play() {
|
||||
if (_pSmk) {
|
||||
_pSmk->pauseVideo(false);
|
||||
//_pSmk->setReverse(false); // TODO: Not supported by SMK
|
||||
_pSmk->start();
|
||||
_eMovStatus = FORWARD;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
bool CBofMovie::reverse(bool bLoop, bool bEscCanStop) {
|
||||
_bEscCanStop = bEscCanStop;
|
||||
_bLoop = bLoop;
|
||||
|
||||
bool bSuccess = reverse();
|
||||
|
||||
getParent()->disable();
|
||||
getParent()->flushAllMessages();
|
||||
doModal();
|
||||
|
||||
return bSuccess;
|
||||
|
||||
}
|
||||
|
||||
bool CBofMovie::reverse() {
|
||||
|
||||
if (_pSmk) {
|
||||
_pSmk->pauseVideo(false);
|
||||
//_smk->setReverse(true); // TODO: Not supported by SMK
|
||||
_pSmk->start();
|
||||
_eMovStatus = REVERSE;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
bool CBofMovie::stop() {
|
||||
if (_pSmk) {
|
||||
_pSmk->stop();
|
||||
_eMovStatus = STOPPED;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
bool CBofMovie::pause() {
|
||||
if (_pSmk) {
|
||||
_pSmk->pauseVideo(true);
|
||||
_eMovStatus = PAUSED;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
bool CBofMovie::seekToStart() {
|
||||
if (_pSmk) {
|
||||
_pSmk->rewind();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CBofMovie::seekToEnd() {
|
||||
if (_pSmk) {
|
||||
setFrame(_pSmk->getFrameCount() - 2); // HACK: Reverse rewind
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 CBofMovie::getFrame() {
|
||||
if (_pSmk) {
|
||||
return _pSmk->getCurFrame();
|
||||
}
|
||||
|
||||
return (uint32) -1;
|
||||
}
|
||||
|
||||
|
||||
bool CBofMovie::setFrame(uint32 dwFrameNum) {
|
||||
if (_pSmk) {
|
||||
dwFrameNum = CLIP<uint32>(dwFrameNum, 0, _pSmk->getFrameCount() - 1);
|
||||
_pSmk->forceSeekToFrame(dwFrameNum);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CBofMovie::onReSize(CBofSize *pSize) {
|
||||
}
|
||||
|
||||
bool CBofMovie::centerRect() {
|
||||
CBofRect cBofRect = getParent()->getClientRect();
|
||||
RECT rcParentRect = cBofRect.getWinRect();
|
||||
int ClientWidth = rcParentRect.right - rcParentRect.left;
|
||||
int ClientHeight = rcParentRect.bottom - rcParentRect.top;
|
||||
|
||||
// Get Movies width and height
|
||||
int MovieWidth = _pSmk->getWidth();
|
||||
int MovieHeight = _pSmk->getHeight();
|
||||
|
||||
RECT rcMovieBounds;
|
||||
rcMovieBounds.left = (ClientWidth - MovieWidth) / 2;
|
||||
rcMovieBounds.top = (ClientHeight - MovieHeight) / 2;
|
||||
rcMovieBounds.right = rcMovieBounds.left + MovieWidth;
|
||||
rcMovieBounds.bottom = rcMovieBounds.top + MovieHeight;
|
||||
|
||||
// Reposition the playback window
|
||||
cBofRect = rcMovieBounds;
|
||||
reSize(&cBofRect, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CBofMovie::onButtonUp(uint32 /*nFlags*/, CBofPoint */*pPoint*/) {
|
||||
}
|
||||
|
||||
|
||||
ErrorCode bofPlayMovie(CBofWindow *pParent, const char *pszMovieFile, CBofRect *pRect) {
|
||||
assert(pParent != nullptr);
|
||||
assert(pszMovieFile != nullptr);
|
||||
|
||||
CBofMovie cMovie(pParent, pszMovieFile, pRect);
|
||||
if (!cMovie.errorOccurred()) {
|
||||
cMovie.play(false, true);
|
||||
}
|
||||
|
||||
return cMovie.getErrorCode();
|
||||
}
|
||||
|
||||
} // namespace SpaceBar
|
||||
} // namespace Bagel
|
||||
111
engines/bagel/spacebar/boflib/gui/movie.h
Normal file
111
engines/bagel/spacebar/boflib/gui/movie.h
Normal file
@@ -0,0 +1,111 @@
|
||||
|
||||
/* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/".
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BAGEL_BOFLIB_GUI_MOVIE_H
|
||||
#define BAGEL_BOFLIB_GUI_MOVIE_H
|
||||
|
||||
#include "graphics/managed_surface.h"
|
||||
#include "video/smk_decoder.h"
|
||||
#include "bagel/boflib/error.h"
|
||||
#include "bagel/spacebar/boflib/gui/dialog.h"
|
||||
#include "bagel/boflib/rect.h"
|
||||
|
||||
namespace Bagel {
|
||||
namespace SpaceBar {
|
||||
|
||||
class CBofMovie : public CBofDialog {
|
||||
public:
|
||||
enum MVSTATUS {
|
||||
STOPPED, PAUSED, FORWARD, REVERSE
|
||||
};
|
||||
protected:
|
||||
Graphics::ManagedSurface *_pSbuf;
|
||||
Video::SmackerDecoder *_pSmk;
|
||||
bool _bEscCanStop;
|
||||
bool _bLoop;
|
||||
bool _bStretch;
|
||||
bool _bUseNewPalette;
|
||||
bool _bBlackOutWindow;
|
||||
MVSTATUS _eMovStatus;
|
||||
Common::Rect _srcRect, _dstRect;
|
||||
|
||||
virtual ErrorCode initialize(CBofWindow *pParent);
|
||||
|
||||
virtual bool openMovie(const char *sFilename);
|
||||
virtual void closeMovie();
|
||||
|
||||
virtual void onReSize(CBofSize *pSize);
|
||||
|
||||
virtual bool play();
|
||||
virtual bool reverse();
|
||||
|
||||
virtual void onLButtonUp(uint32 nFlags, CBofPoint *pPoint, void * = nullptr) {
|
||||
onButtonUp(nFlags, pPoint);
|
||||
}
|
||||
virtual void onRButtonUp(uint32 nFlags, CBofPoint *pPoint) {
|
||||
onButtonUp(nFlags, pPoint);
|
||||
}
|
||||
virtual void onButtonUp(uint32 nFlags, CBofPoint *pPoint);
|
||||
virtual void onPaint(CBofRect *pRect);
|
||||
virtual void onMovieDone();
|
||||
virtual void onClose();
|
||||
virtual void onMainLoop();
|
||||
virtual void onKeyHit(uint32 lKey, uint32 lRepCount);
|
||||
|
||||
public:
|
||||
|
||||
CBofMovie(CBofWindow *pParent = nullptr, const char *pszFilename = nullptr, CBofRect *pBounds = nullptr, bool bStretch = false, bool bUseNewPalette = true, bool bBlackOutWindow = false);
|
||||
~CBofMovie();
|
||||
|
||||
virtual bool open(const char *sFilename = nullptr, CBofRect *pBounds = nullptr);
|
||||
|
||||
virtual bool play(bool bLoop, bool bEscCanStop = true);
|
||||
virtual bool reverse(bool bLoop, bool bEscCanStop = true);
|
||||
virtual bool pause();
|
||||
virtual bool stop();
|
||||
|
||||
virtual MVSTATUS status() {
|
||||
return _eMovStatus;
|
||||
}
|
||||
|
||||
virtual bool seekToStart();
|
||||
virtual bool seekToEnd();
|
||||
|
||||
virtual uint32 getFrame();
|
||||
virtual bool setFrame(uint32 dwFrameNum);
|
||||
|
||||
virtual bool centerRect();
|
||||
|
||||
Graphics::ManagedSurface *getSmackBuffer() {
|
||||
return _pSbuf;
|
||||
}
|
||||
Video::SmackerDecoder *getSmackMovie() {
|
||||
return _pSmk;
|
||||
}
|
||||
};
|
||||
|
||||
ErrorCode bofPlayMovie(CBofWindow *pParent, const char *pszMovieFile, CBofRect *pRect = nullptr);
|
||||
|
||||
} // namespace SpaceBar
|
||||
} // namespace Bagel
|
||||
|
||||
#endif
|
||||
489
engines/bagel/spacebar/boflib/gui/scroll_bar.cpp
Normal file
489
engines/bagel/spacebar/boflib/gui/scroll_bar.cpp
Normal file
@@ -0,0 +1,489 @@
|
||||
/* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "bagel/spacebar/boflib/app.h"
|
||||
#include "bagel/spacebar/boflib/gui/scroll_bar.h"
|
||||
|
||||
namespace Bagel {
|
||||
namespace SpaceBar {
|
||||
|
||||
#define BMP_SCROLL_TIMER 9999
|
||||
#define DEF_TIMER_INTERVAL 100
|
||||
|
||||
|
||||
CBofScrollBar::CBofScrollBar() {
|
||||
_pLeftBtnUp = nullptr;
|
||||
_pRightBtnUp = nullptr;
|
||||
_pLeftBtnDn = nullptr;
|
||||
_pRightBtnDn = nullptr;
|
||||
_pThumb = nullptr;
|
||||
_nMin = 0;
|
||||
_nMax = 10;
|
||||
_nPos = 0;
|
||||
_nLineDelta = 1;
|
||||
_nPageDelta = 1;
|
||||
|
||||
_pScrollText = nullptr;
|
||||
_szScrollText[0] = '\0';
|
||||
|
||||
_cThumbSize.cx = 0;
|
||||
_cThumbSize.cy = 0;
|
||||
_cBkSize.cx = 0;
|
||||
_cBkSize.cy = 0;
|
||||
_cCurPoint.x = 0;
|
||||
_cCurPoint.y = 0;
|
||||
_cThumbPos.x = 0;
|
||||
_cThumbPos.y = 0;
|
||||
|
||||
_nOffset = 0;
|
||||
_nScrollWidth = 0;
|
||||
_nRange = 0;
|
||||
_bMouseCaptured = false;
|
||||
_nScrollState = 0;
|
||||
|
||||
_nTimerCount = DEF_TIMER_INTERVAL;
|
||||
}
|
||||
|
||||
|
||||
CBofScrollBar::~CBofScrollBar() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
_szScrollText[0] = '\0';
|
||||
|
||||
delete _pScrollText;
|
||||
_pScrollText = nullptr;
|
||||
|
||||
delete _pThumb;
|
||||
_pThumb = nullptr;
|
||||
|
||||
delete _pLeftBtnUp;
|
||||
_pLeftBtnUp = nullptr;
|
||||
|
||||
delete _pRightBtnUp;
|
||||
_pRightBtnUp = nullptr;
|
||||
|
||||
delete _pLeftBtnDn;
|
||||
_pLeftBtnDn = nullptr;
|
||||
|
||||
delete _pRightBtnDn;
|
||||
_pRightBtnDn = nullptr;
|
||||
}
|
||||
|
||||
|
||||
void CBofScrollBar::onPaint(CBofRect *pDirtyRect) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
paint(pDirtyRect);
|
||||
}
|
||||
|
||||
|
||||
ErrorCode CBofScrollBar::setText(const char *pszText, int nJustify) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
_szScrollText[0] = '\0';
|
||||
|
||||
if ((pszText != nullptr) && (_parent != nullptr)) {
|
||||
Common::strlcpy(_szScrollText, pszText, MAX_TEXT);
|
||||
|
||||
if (_pScrollText == nullptr) {
|
||||
|
||||
CBofPoint cPoint = _parent->getWindowRect().topLeft();
|
||||
CBofRect cTempRect = _cWindowRect - cPoint;
|
||||
|
||||
cTempRect -= CBofPoint(0, 20);
|
||||
cTempRect.right += 20;
|
||||
|
||||
_pScrollText = new CBofText(&cTempRect, nJustify);
|
||||
}
|
||||
|
||||
if (_pScrollText != nullptr) {
|
||||
_pScrollText->display(_parent, _szScrollText, FONT_DEFAULT_SIZE, TEXT_DEFAULT_FACE);
|
||||
}
|
||||
}
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
|
||||
ErrorCode CBofScrollBar::setPos(const int nPos, bool bRepaint, bool isInitial) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
// Save old position
|
||||
int nOriginalPos = _nPos;
|
||||
|
||||
_nPos = nPos;
|
||||
if (nPos < _nMin)
|
||||
_nPos = _nMin;
|
||||
if (nPos > _nMax)
|
||||
_nPos = _nMax;
|
||||
|
||||
assert(_nRange != 0);
|
||||
|
||||
_cThumbPos.x = (int)(((int32)(_nScrollWidth - _cThumbSize.cx) * _nPos) / (_nRange - 1)) + _nOffset;
|
||||
_cThumbPos.y = (int)(_cBkSize.cy / 2) - (int)(_cThumbSize.cy / 2);
|
||||
|
||||
if (_cThumbPos.x < 0)
|
||||
_cThumbPos.x = 0;
|
||||
if (_cThumbPos.x > (_nScrollWidth - _cThumbSize.cx + _nOffset))
|
||||
_cThumbPos.x = _nScrollWidth - _cThumbSize.cx + _nOffset;
|
||||
|
||||
// If forced to repaint
|
||||
if (bRepaint) {
|
||||
|
||||
paint();
|
||||
|
||||
} else if (_nPos != nOriginalPos) {
|
||||
// Otherwise, only paint the thumb if it's position changed
|
||||
if (_pThumb != nullptr) {
|
||||
if (_pThumb->paintSprite(this, _cThumbPos) == false) {
|
||||
reportError(ERR_UNKNOWN, "_pThumb->paintSprite() failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the thumb actually moved, then tell our parent about it
|
||||
if (_nPos != nOriginalPos && !isInitial) {
|
||||
_parent->onBofScrollBar(this, _nPos);
|
||||
}
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
|
||||
void CBofScrollBar::getScrollRange(int &nMin, int &nMax) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
nMin = _nMin;
|
||||
nMax = _nMax;
|
||||
}
|
||||
|
||||
|
||||
void CBofScrollBar::setScrollRange(int nMin, int nMax, bool bRepaint) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
_nMin = nMin;
|
||||
_nMax = nMax;
|
||||
|
||||
_nRange = _nMax - _nMin + 1;
|
||||
|
||||
// Should we repaint the scroll bar now?
|
||||
if (bRepaint) {
|
||||
paint();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ErrorCode CBofScrollBar::loadBitmaps(const char *pszBack, const char *pszThumb, const char *pszLeftBtnUp, const char *pszRightBtnUp, const char *pszLeftBtnDn, const char *pszRightBtnDn) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
if ((pszBack == nullptr) || (pszThumb == nullptr))
|
||||
return _errCode;
|
||||
|
||||
_cLeftBtnRect.setRect(0, 0, 0, 0);
|
||||
_cRightBtnRect.setRect(0, 0, 0, 0);
|
||||
|
||||
if (_pThumb != nullptr) {
|
||||
_pThumb->eraseSprite(this);
|
||||
delete _pThumb;
|
||||
_pThumb = nullptr;
|
||||
}
|
||||
|
||||
killBackdrop();
|
||||
setBackdrop(pszBack);
|
||||
|
||||
CBofPalette *pPalette = CBofApp::getApp()->getPalette();
|
||||
|
||||
_cBkSize = _pBackdrop->getSize();
|
||||
_nScrollWidth = _cBkSize.cx;
|
||||
|
||||
_pThumb = new CBofSprite;
|
||||
|
||||
if (_pThumb->loadSprite(pszThumb) != false) {
|
||||
_pThumb->setMaskColor(COLOR_WHITE);
|
||||
_cThumbSize = _pThumb->getSize();
|
||||
}
|
||||
|
||||
delete _pLeftBtnUp;
|
||||
_pLeftBtnUp = nullptr;
|
||||
|
||||
CBofPoint cPoint;
|
||||
if (pszLeftBtnUp != nullptr) {
|
||||
_pLeftBtnUp = new CBofBitmap(pszLeftBtnUp, pPalette);
|
||||
|
||||
cPoint.x = 0;
|
||||
cPoint.y = (_pBackdrop->height() / 2) - (_pLeftBtnUp->height() / 2);
|
||||
|
||||
_cLeftBtnRect = _pLeftBtnUp->getRect() + cPoint;
|
||||
|
||||
_nOffset = _pLeftBtnUp->width();
|
||||
_nScrollWidth -= _nOffset;
|
||||
}
|
||||
|
||||
delete _pRightBtnUp;
|
||||
_pRightBtnUp = nullptr;
|
||||
|
||||
if (pszRightBtnUp != nullptr) {
|
||||
_pRightBtnUp = new CBofBitmap(pszRightBtnUp, pPalette);
|
||||
|
||||
cPoint.x = _pBackdrop->width() - _pRightBtnUp->width();
|
||||
cPoint.y = (_pBackdrop->height() / 2) - (_pRightBtnUp->height() / 2);
|
||||
_cRightBtnRect = _pLeftBtnUp->getRect() + cPoint;
|
||||
|
||||
_nScrollWidth -= _cRightBtnRect.width();
|
||||
}
|
||||
|
||||
delete _pLeftBtnDn;
|
||||
_pLeftBtnDn = nullptr;
|
||||
|
||||
if (pszLeftBtnDn != nullptr) {
|
||||
_pLeftBtnDn = new CBofBitmap(pszLeftBtnDn, pPalette);
|
||||
}
|
||||
|
||||
delete _pRightBtnDn;
|
||||
_pRightBtnDn = nullptr;
|
||||
|
||||
if (pszRightBtnDn != nullptr) {
|
||||
_pRightBtnDn = new CBofBitmap(pszRightBtnDn, pPalette);
|
||||
}
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
|
||||
ErrorCode CBofScrollBar::paint(CBofRect *pDirtyRect) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
if (!errorOccurred()) {
|
||||
CBofPalette *pPalette = CBofApp::getApp()->getPalette();
|
||||
|
||||
//
|
||||
// This function needs to be optimized to paint only the section that is
|
||||
// invalidated. Right now it just repaints the entire scroll bar each time.
|
||||
//
|
||||
|
||||
if ((_pBackdrop != nullptr) && (_pThumb != nullptr)) {
|
||||
// Do all painting offscreen
|
||||
CBofBitmap *pBmp = new CBofBitmap(_cBkSize.cx, _cBkSize.cy, pPalette);
|
||||
_pBackdrop->paint(pBmp, 0, 0, nullptr, COLOR_WHITE);
|
||||
|
||||
if ((_nScrollState == 1) && (_pLeftBtnDn != nullptr)) {
|
||||
CBofPoint cPoint = _cLeftBtnRect.topLeft();
|
||||
_pLeftBtnDn->paint(pBmp, cPoint.x, cPoint.y, nullptr, COLOR_WHITE);
|
||||
|
||||
} else if (_pLeftBtnUp != nullptr) {
|
||||
CBofPoint cPoint = _cLeftBtnRect.topLeft();
|
||||
_pLeftBtnUp->paint(pBmp, cPoint.x, cPoint.y, nullptr, COLOR_WHITE);
|
||||
}
|
||||
|
||||
if ((_nScrollState == 4) && (_pRightBtnDn != nullptr)) {
|
||||
CBofPoint cPoint = _cRightBtnRect.topLeft();
|
||||
_pRightBtnDn->paint(pBmp, cPoint.x, cPoint.y, nullptr, COLOR_WHITE);
|
||||
|
||||
} else if (_pRightBtnUp != nullptr) {
|
||||
CBofPoint cPoint = _cRightBtnRect.topLeft();
|
||||
_pRightBtnUp->paint(pBmp, cPoint.x, cPoint.y, nullptr, COLOR_WHITE);
|
||||
}
|
||||
|
||||
_cThumbPos.x = (int)(((int32)(_nScrollWidth - _cThumbSize.cx) * _nPos) / (_nRange - 1)) + _nOffset;
|
||||
_cThumbPos.y = (int)(_cBkSize.cy / 2) - (int)(_cThumbSize.cy / 2);
|
||||
|
||||
if (_cThumbPos.x < 0)
|
||||
_cThumbPos.x = 0;
|
||||
if (_cThumbPos.x > (_nScrollWidth - _cThumbSize.cx + _nOffset))
|
||||
_cThumbPos.x = _nScrollWidth - _cThumbSize.cx + _nOffset;
|
||||
|
||||
_pThumb->paintSprite(pBmp, _cThumbPos);
|
||||
|
||||
// now we can paint the offscreen buffer to the screen
|
||||
pBmp->paint(this, 0, 0);
|
||||
|
||||
delete pBmp;
|
||||
}
|
||||
|
||||
if ((_pScrollText != nullptr) && (_parent != nullptr)) {
|
||||
_pScrollText->display(_parent, _szScrollText, FONT_DEFAULT_SIZE, TEXT_DEFAULT_FACE);
|
||||
}
|
||||
}
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
|
||||
void CBofScrollBar::onLButtonDown(uint32 nFlags, CBofPoint *pPoint, void *) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
CBofRect cLeftPageRect, cRightPageRect;
|
||||
|
||||
bool bDoNothing = false;
|
||||
|
||||
cLeftPageRect.setRect(_nOffset, 0, (_nScrollWidth / _nRange) * _nPos + _nOffset - 1, _cBkSize.cy - 1);
|
||||
cRightPageRect.setRect(((_nScrollWidth / _nRange) * _nPos) + _nOffset + _cThumbSize.cx, 0, _nOffset + _nScrollWidth - 1, _cBkSize.cy - 1);
|
||||
|
||||
_cCurPoint = *pPoint;
|
||||
|
||||
if (_pLeftBtnUp != nullptr && _cLeftBtnRect.ptInRect(*pPoint)) {
|
||||
// Let timer know what happened
|
||||
_nScrollState = 1;
|
||||
|
||||
// Set new thumb position
|
||||
setPos(_nPos - _nLineDelta, true);
|
||||
|
||||
} else if (_pThumb->getRect().ptInRect(*pPoint)) {
|
||||
_nScrollState = 5;
|
||||
|
||||
} else if (cLeftPageRect.ptInRect(*pPoint)) {
|
||||
_nScrollState = 2;
|
||||
|
||||
// Set new thumb position
|
||||
setPos(_nPos - _nPageDelta, true);
|
||||
|
||||
} else if (cRightPageRect.ptInRect(*pPoint)) {
|
||||
_nScrollState = 3;
|
||||
|
||||
// Set new thumb position
|
||||
setPos(_nPos + _nPageDelta, true);
|
||||
|
||||
} else if (_pRightBtnUp != nullptr && _cRightBtnRect.ptInRect(*pPoint)) {
|
||||
// Let timer know what happened
|
||||
_nScrollState = 4;
|
||||
|
||||
// Set new thumb position
|
||||
setPos(_nPos + _nLineDelta, true);
|
||||
|
||||
} else {
|
||||
bDoNothing = true;
|
||||
}
|
||||
|
||||
if (!bDoNothing) {
|
||||
_bMouseCaptured = true;
|
||||
setCapture();
|
||||
if (_nScrollState != 5)
|
||||
setTimer(BMP_SCROLL_TIMER, _nTimerCount);
|
||||
}
|
||||
|
||||
CBofWindow::onLButtonDown(nFlags, pPoint);
|
||||
}
|
||||
|
||||
|
||||
int CBofScrollBar::pointToPos(CBofPoint *pPoint) {
|
||||
assert(isValidObject(this));
|
||||
assert(pPoint != nullptr);
|
||||
|
||||
int nPos = _nPos;
|
||||
|
||||
if (_cRect.ptInRect(*pPoint)) {
|
||||
nPos = (pPoint->x - _nOffset) / (int)(_nScrollWidth / _nRange);
|
||||
}
|
||||
|
||||
return nPos;
|
||||
}
|
||||
|
||||
|
||||
void CBofScrollBar::onLButtonUp(uint32 nFlags, CBofPoint *pPoint, void *) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
if (_bMouseCaptured) {
|
||||
killTimer(BMP_SCROLL_TIMER);
|
||||
_bMouseCaptured = false;
|
||||
releaseCapture();
|
||||
|
||||
int x, y;
|
||||
|
||||
switch (_nScrollState) {
|
||||
case 5:
|
||||
setPos(pointToPos(pPoint));
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if (_pLeftBtnUp != nullptr) {
|
||||
x = 0;
|
||||
y = (int)(_cBkSize.cy / 2) - (int)(_cLeftBtnRect.height() / 2);
|
||||
_pLeftBtnUp->paint(this, x, y, nullptr, COLOR_WHITE);
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
if (_pRightBtnUp != nullptr) {
|
||||
x = _cBkSize.cx - _cRightBtnRect.width();
|
||||
y = (int)(_cBkSize.cy / 2) - (int)(_cRightBtnRect.height() / 2);
|
||||
_pRightBtnUp->paint(this, x, y, nullptr, COLOR_WHITE);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
_nScrollState = 0;
|
||||
}
|
||||
|
||||
CBofWindow::onLButtonUp(nFlags, pPoint);
|
||||
}
|
||||
|
||||
|
||||
void CBofScrollBar::onMouseMove(uint32 nFlags, CBofPoint *pPoint, void *) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
if (_bMouseCaptured) {
|
||||
_cCurPoint = *pPoint;
|
||||
|
||||
if (_nScrollState == 5) {
|
||||
setPos(pointToPos(pPoint));
|
||||
}
|
||||
}
|
||||
|
||||
CBofWindow::onMouseMove(nFlags, pPoint);
|
||||
}
|
||||
|
||||
|
||||
void CBofScrollBar::setRepeatTimer(uint32 nTimerInt) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
_nTimerCount = nTimerInt;
|
||||
}
|
||||
|
||||
|
||||
void CBofScrollBar::onTimer(uint32 nWhichTimer) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
CBofRect cLeftPageRect, cRightPageRect;
|
||||
|
||||
cLeftPageRect.setRect(_nOffset, 0, (_nScrollWidth / _nRange) * _nPos + _nOffset - 1, _cBkSize.cy - 1);
|
||||
cRightPageRect.setRect(((_nScrollWidth / _nRange) * _nPos) + _nOffset + _cThumbSize.cx, 0, _nOffset + _nScrollWidth - 1, _cBkSize.cy - 1);
|
||||
|
||||
if (nWhichTimer == BMP_SCROLL_TIMER) {
|
||||
if ((_nScrollState == 1) && _cLeftBtnRect.ptInRect(_cCurPoint)) {
|
||||
lineLeft();
|
||||
|
||||
} else if ((_nScrollState == 2) && cLeftPageRect.ptInRect(_cCurPoint)) {
|
||||
pageLeft();
|
||||
|
||||
} else if ((_nScrollState == 3) && cRightPageRect.ptInRect(_cCurPoint)) {
|
||||
pageRight();
|
||||
|
||||
} else if ((_nScrollState == 4) && _cRightBtnRect.ptInRect(_cCurPoint)) {
|
||||
lineRight();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace SpaceBar
|
||||
} // namespace Bagel
|
||||
155
engines/bagel/spacebar/boflib/gui/scroll_bar.h
Normal file
155
engines/bagel/spacebar/boflib/gui/scroll_bar.h
Normal file
@@ -0,0 +1,155 @@
|
||||
|
||||
/* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BAGEL_BOFLIB_GUI_SCROLL_BAR_H
|
||||
#define BAGEL_BOFLIB_GUI_SCROLL_BAR_H
|
||||
|
||||
#include "bagel/spacebar/boflib/gui/window.h"
|
||||
#include "bagel/spacebar/boflib/gfx/sprite.h"
|
||||
#include "bagel/spacebar/boflib/gfx/text.h"
|
||||
|
||||
namespace Bagel {
|
||||
namespace SpaceBar {
|
||||
|
||||
#define BSB_LEFT 800
|
||||
#define BSB_RIGHT 801
|
||||
#define BSB_LINE_LEFT 802
|
||||
#define BSB_LINE_RIGHT 803
|
||||
#define BSB_PAGE_LEFT 804
|
||||
#define BSB_PAGE_RIGHT 805
|
||||
#define BSB_THUMB_POS 806
|
||||
#define BSB_THUMB_TRACK 807
|
||||
|
||||
#define MAX_TEXT 128
|
||||
|
||||
class CBofScrollBar : public CBofWindow {
|
||||
public:
|
||||
CBofScrollBar();
|
||||
|
||||
virtual ~CBofScrollBar();
|
||||
|
||||
// Implementation
|
||||
//
|
||||
|
||||
ErrorCode loadBitmaps(const char *pszBack, const char *pszThumb, const char *pszLeftUp = nullptr, const char *pszRightUp = nullptr, const char *pszLeftDown = nullptr, const char *pszRightDown = nullptr);
|
||||
|
||||
ErrorCode setPos(int nPos, bool bRepaint = true, bool isInitial = false);
|
||||
int getPos() const {
|
||||
return _nPos;
|
||||
}
|
||||
|
||||
ErrorCode lineLeft() {
|
||||
return setPos(_nPos - _nLineDelta);
|
||||
}
|
||||
ErrorCode lineRight() {
|
||||
return setPos(_nPos + _nLineDelta);
|
||||
}
|
||||
ErrorCode pageLeft() {
|
||||
return setPos(_nPos - _nPageDelta);
|
||||
}
|
||||
ErrorCode pageRight() {
|
||||
return setPos(_nPos + _nPageDelta);
|
||||
}
|
||||
|
||||
ErrorCode home() {
|
||||
return setPos(_nMin);
|
||||
}
|
||||
ErrorCode end() {
|
||||
return setPos(_nMax);
|
||||
}
|
||||
|
||||
int getScrollMin() const {
|
||||
return _nMin;
|
||||
}
|
||||
int getScrollMax() const {
|
||||
return _nMax;
|
||||
}
|
||||
|
||||
void setLineDelta(const int nDelta) {
|
||||
_nLineDelta = nDelta;
|
||||
}
|
||||
int getLineDelta() const {
|
||||
return _nLineDelta;
|
||||
}
|
||||
|
||||
void setPageDelta(const int nDelta) {
|
||||
_nPageDelta = nDelta;
|
||||
}
|
||||
int getPageDelta() const {
|
||||
return _nPageDelta;
|
||||
}
|
||||
|
||||
void getScrollRange(int &nMin, int &nMax);
|
||||
void setScrollRange(int nMin, int nMax, bool bRepaint = true);
|
||||
|
||||
ErrorCode setText(const char *pszText, int nFlags = JUSTIFY_CENTER);
|
||||
|
||||
void setRepeatTimer(uint32 nMilliSeconds);
|
||||
ErrorCode paint(CBofRect *pRect = nullptr);
|
||||
|
||||
protected:
|
||||
int pointToPos(CBofPoint *pPoint);
|
||||
|
||||
void onPaint(CBofRect *pDirtyRect) override;
|
||||
void onLButtonDown(uint32 nFlags, CBofPoint *pPoint, void * = nullptr) override;
|
||||
void onLButtonUp(uint32 nFlags, CBofPoint *pPoint, void * = nullptr) override;
|
||||
void onMouseMove(uint32 nFlags, CBofPoint *pPoint, void * = nullptr) override;
|
||||
void onTimer(uint32) override;
|
||||
|
||||
//
|
||||
// Data members
|
||||
//
|
||||
CBofBitmap *_pLeftBtnUp;
|
||||
CBofBitmap *_pRightBtnUp;
|
||||
CBofBitmap *_pLeftBtnDn;
|
||||
CBofBitmap *_pRightBtnDn;
|
||||
CBofSprite *_pThumb;
|
||||
|
||||
CBofRect _cLeftBtnRect;
|
||||
CBofRect _cRightBtnRect;
|
||||
|
||||
int _nMin;
|
||||
int _nMax;
|
||||
int _nPos;
|
||||
int _nLineDelta;
|
||||
int _nPageDelta;
|
||||
|
||||
CBofText *_pScrollText;
|
||||
char _szScrollText[MAX_TEXT];
|
||||
|
||||
CBofSize _cThumbSize;
|
||||
CBofSize _cBkSize;
|
||||
|
||||
int _nOffset;
|
||||
int _nScrollWidth;
|
||||
int _nRange;
|
||||
bool _bMouseCaptured;
|
||||
CBofPoint _cCurPoint;
|
||||
CBofPoint _cThumbPos;
|
||||
int _nScrollState;
|
||||
uint32 _nTimerCount;
|
||||
};
|
||||
|
||||
} // namespace SpaceBar
|
||||
} // namespace Bagel
|
||||
|
||||
#endif
|
||||
273
engines/bagel/spacebar/boflib/gui/text_box.cpp
Normal file
273
engines/bagel/spacebar/boflib/gui/text_box.cpp
Normal file
@@ -0,0 +1,273 @@
|
||||
/* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "bagel/spacebar/boflib/gui/text_box.h"
|
||||
|
||||
namespace Bagel {
|
||||
namespace SpaceBar {
|
||||
|
||||
#define DEFAULT_PAGE_SIZE 10
|
||||
#define DEFAULT_WEIGHT TEXT_NORMAL
|
||||
#define DEFAULT_POINT_SIZE FONT_12POINT
|
||||
#define DEFAULT_COLOR CTEXT_COLOR
|
||||
|
||||
|
||||
CBofTextBox::CBofTextBox() {
|
||||
// Inits
|
||||
_pDestWindow = nullptr;
|
||||
_pDestBitmap = nullptr;
|
||||
_pTextField = nullptr;
|
||||
_nWeight = DEFAULT_WEIGHT;
|
||||
_nPointSize = DEFAULT_POINT_SIZE;
|
||||
_cTextColor = DEFAULT_COLOR;
|
||||
_nTextFont = FONT_DEFAULT;
|
||||
_nPageSize = DEFAULT_PAGE_SIZE;
|
||||
_nCurrentLine = 0;
|
||||
_nCurrentIndex = 0;
|
||||
_nNumLines = 0;
|
||||
}
|
||||
|
||||
|
||||
CBofTextBox::CBofTextBox(CBofWindow *pWindow, const CBofRect *pRect, const CBofString &cText) {
|
||||
assert(pWindow != nullptr);
|
||||
assert(pRect != nullptr);
|
||||
|
||||
// Inits
|
||||
_pDestWindow = nullptr;
|
||||
_pDestBitmap = nullptr;
|
||||
_pTextField = nullptr;
|
||||
_nWeight = DEFAULT_WEIGHT;
|
||||
_nPointSize = DEFAULT_POINT_SIZE;
|
||||
_cTextColor = DEFAULT_COLOR;
|
||||
_nPageSize = DEFAULT_PAGE_SIZE;
|
||||
_nCurrentLine = 0;
|
||||
_nCurrentIndex = 0;
|
||||
_nNumLines = 0;
|
||||
_nTextFont = FONT_DEFAULT;
|
||||
|
||||
setText(cText);
|
||||
setBox(pRect);
|
||||
setDisplay(pWindow);
|
||||
}
|
||||
|
||||
|
||||
CBofTextBox::CBofTextBox(CBofBitmap *pBitmap, const CBofRect *pRect, const CBofString &cText) {
|
||||
assert(pBitmap != nullptr);
|
||||
assert(pRect != nullptr);
|
||||
|
||||
// Inits
|
||||
_pDestWindow = nullptr;
|
||||
_pDestBitmap = nullptr;
|
||||
_pTextField = nullptr;
|
||||
_nWeight = DEFAULT_WEIGHT;
|
||||
_nPointSize = DEFAULT_POINT_SIZE;
|
||||
_cTextColor = DEFAULT_COLOR;
|
||||
_nPageSize = DEFAULT_PAGE_SIZE;
|
||||
_nCurrentLine = 0;
|
||||
_nCurrentIndex = 0;
|
||||
_nNumLines = 0;
|
||||
_nTextFont = FONT_DEFAULT;
|
||||
|
||||
setText(cText);
|
||||
setBox(pRect);
|
||||
setDisplay(pBitmap);
|
||||
}
|
||||
|
||||
|
||||
CBofTextBox::~CBofTextBox() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
if (_pTextField != nullptr) {
|
||||
delete _pTextField;
|
||||
_pTextField = nullptr;
|
||||
}
|
||||
_pDestWindow = nullptr;
|
||||
_pDestBitmap = nullptr;
|
||||
}
|
||||
|
||||
|
||||
ErrorCode CBofTextBox::setBox(const CBofRect *pRect) {
|
||||
assert(isValidObject(this));
|
||||
assert(pRect != nullptr);
|
||||
|
||||
// Remove previous text field (if any)
|
||||
delete _pTextField;
|
||||
_pTextField = nullptr;
|
||||
|
||||
// Create a new text field the size of the box we want
|
||||
_pTextField = new CBofText(pRect, JUSTIFY_WRAP);
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
|
||||
void CBofTextBox::setDisplay(CBofWindow *pWindow) {
|
||||
assert(isValidObject(this));
|
||||
assert(pWindow != nullptr);
|
||||
|
||||
_pDestWindow = pWindow;
|
||||
_pDestBitmap = nullptr;
|
||||
}
|
||||
|
||||
|
||||
void CBofTextBox::setDisplay(CBofBitmap *pBitmap) {
|
||||
assert(isValidObject(this));
|
||||
assert(pBitmap != nullptr);
|
||||
|
||||
_pDestBitmap = pBitmap;
|
||||
_pDestWindow = nullptr;
|
||||
}
|
||||
|
||||
|
||||
void CBofTextBox::setTextAttribs(const int nSize, const int nWeight, const COLORREF cColor, const int nFont) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
_nPointSize = nSize;
|
||||
_nWeight = nWeight;
|
||||
_cTextColor = cColor;
|
||||
_nTextFont = nFont;
|
||||
}
|
||||
|
||||
|
||||
void CBofTextBox::setText(const CBofString &cString) {
|
||||
_cBuffer = cString;
|
||||
assert(_cBuffer.getLength() != 0);
|
||||
|
||||
_cBuffer.replaceStr("\r\n", "\n");
|
||||
_cBuffer.replaceStr("\r", "\n");
|
||||
|
||||
_nCurrentLine = 0;
|
||||
_nCurrentIndex = 0;
|
||||
_nNumLines = _cBuffer.findNumOccurrences("\n");
|
||||
}
|
||||
|
||||
int CBofTextBox::getIndex(const int nLine) {
|
||||
assert(nLine >= 0 && nLine <= _nNumLines);
|
||||
|
||||
// Find the index into our buffer that represents the top left of the
|
||||
// buffer that is nLine from current the beginning of the buffer.
|
||||
const char *pszCur, *pszBuffer;
|
||||
const char *pszLast = pszCur = pszBuffer = _cBuffer;
|
||||
for (int i = 0; i < nLine; i++) {
|
||||
pszLast = pszCur;
|
||||
pszCur = strstr(pszCur, "\n");
|
||||
|
||||
// Make sure we don't go too far (nLines is invalid)
|
||||
assert(pszCur != nullptr);
|
||||
|
||||
pszCur++;
|
||||
}
|
||||
int nChars = pszCur - pszBuffer;
|
||||
if (nLine == _nNumLines) {
|
||||
nChars = pszLast - pszBuffer;
|
||||
_nCurrentLine--;
|
||||
}
|
||||
|
||||
return nChars;
|
||||
}
|
||||
|
||||
|
||||
ErrorCode CBofTextBox::scrollUp(const int nLines) {
|
||||
// Make scroll a no-op if all the lines in the box appear on one screen.
|
||||
if (_nNumLines <= _nPageSize) {
|
||||
return scrollTo(_nCurrentLine);
|
||||
}
|
||||
|
||||
int nNewLine = _nCurrentLine - nLines;
|
||||
|
||||
if (nNewLine < 0) {
|
||||
nNewLine = 0;
|
||||
} else if (nNewLine > (_nNumLines - _nPageSize)) {
|
||||
// If the line requested to be the top of the page
|
||||
// would cause fewer than _nPageSize lines to be displayed,
|
||||
// snap nNewLine to be the top of the last full page.
|
||||
//
|
||||
nNewLine = (_nNumLines - _nPageSize);
|
||||
}
|
||||
return scrollTo(nNewLine);
|
||||
}
|
||||
|
||||
|
||||
ErrorCode CBofTextBox::scrollTo(const int nLine) {
|
||||
assert(isValidObject(this));
|
||||
assert(nLine >= 0 && nLine <= _nNumLines);
|
||||
|
||||
_nCurrentIndex = getIndex(nLine);
|
||||
_nCurrentLine = nLine;
|
||||
|
||||
// Show the text box
|
||||
display();
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
|
||||
ErrorCode CBofTextBox::display() {
|
||||
assert(isValidObject(this));
|
||||
assert(_nCurrentLine >= 0 && _nCurrentLine <= _nNumLines);
|
||||
assert(_nCurrentIndex >= 0 && _nCurrentIndex < _cBuffer.getLength());
|
||||
|
||||
// The actual text box must have been created before it can be displayed
|
||||
assert(_pTextField != nullptr);
|
||||
|
||||
// If painting to a window
|
||||
if (_pDestWindow != nullptr) {
|
||||
_pTextField->display(_pDestWindow, _cBuffer.mid(_nCurrentIndex), _nPointSize, _nWeight, _cTextColor, _nTextFont);
|
||||
|
||||
} else {
|
||||
// Otherwise, must be painting to a bitmap
|
||||
assert(_pDestBitmap != nullptr);
|
||||
|
||||
_pTextField->display(_pDestBitmap, _cBuffer.mid(_nCurrentIndex), _nPointSize, _nWeight, _cTextColor, _nTextFont);
|
||||
}
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
|
||||
ErrorCode CBofTextBox::erase() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
// The actual text box must have been created before it can be displayed
|
||||
assert(_pTextField != nullptr);
|
||||
|
||||
if (_pDestWindow != nullptr) {
|
||||
_errCode = _pTextField->erase(_pDestWindow);
|
||||
|
||||
} else {
|
||||
assert(_pDestBitmap != nullptr);
|
||||
_errCode = _pTextField->erase(_pDestBitmap);
|
||||
}
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
|
||||
void CBofTextBox::flushBackground() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
if (_pTextField != nullptr) {
|
||||
_pTextField->flushBackground();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace SpaceBar
|
||||
} // namespace Bagel
|
||||
140
engines/bagel/spacebar/boflib/gui/text_box.h
Normal file
140
engines/bagel/spacebar/boflib/gui/text_box.h
Normal file
@@ -0,0 +1,140 @@
|
||||
|
||||
/* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BAGEL_BOFLIB_GUI_TEXT_BOX_H
|
||||
#define BAGEL_BOFLIB_GUI_TEXT_BOX_H
|
||||
|
||||
#include "bagel/spacebar/boflib/gfx/bitmap.h"
|
||||
#include "bagel/boflib/error.h"
|
||||
#include "bagel/boflib/string.h"
|
||||
#include "bagel/spacebar/boflib/gfx/text.h"
|
||||
#include "bagel/spacebar/boflib/gui/window.h"
|
||||
|
||||
namespace Bagel {
|
||||
namespace SpaceBar {
|
||||
|
||||
class CBofTextBox : public CBofObject, public CBofError {
|
||||
public:
|
||||
CBofTextBox();
|
||||
CBofTextBox(CBofWindow *pWindow, const CBofRect *pRect, const CBofString &cText);
|
||||
CBofTextBox(CBofBitmap *pBitmap, const CBofRect *pRect, const CBofString &cText);
|
||||
virtual ~CBofTextBox();
|
||||
|
||||
void setText(const CBofString &cText);
|
||||
ErrorCode setBox(const CBofRect *pRect);
|
||||
void setDisplay(CBofWindow *pWindow);
|
||||
void setDisplay(CBofBitmap *pBitmap);
|
||||
|
||||
void setTextAttribs(int nSize, int nWeight, COLORREF cColor = CTEXT_COLOR, int nFont = FONT_DEFAULT);
|
||||
|
||||
void setPointSize(const int nSize) {
|
||||
_nPointSize = nSize;
|
||||
}
|
||||
int getPointSize() const {
|
||||
return _nPointSize;
|
||||
}
|
||||
|
||||
void setWeight(const int nWeight) {
|
||||
_nWeight = nWeight;
|
||||
}
|
||||
int getWeight() const {
|
||||
return _nWeight;
|
||||
}
|
||||
|
||||
void setPageLength(const int nSize) {
|
||||
_nPageSize = nSize;
|
||||
}
|
||||
int getPageLength() const {
|
||||
return _nPageSize;
|
||||
}
|
||||
|
||||
void setColor(const COLORREF cColor) {
|
||||
_cTextColor = cColor;
|
||||
}
|
||||
COLORREF getColor() const {
|
||||
return _cTextColor;
|
||||
}
|
||||
|
||||
void setFont(int nFont) {
|
||||
_nTextFont = nFont;
|
||||
}
|
||||
int getFont() const {
|
||||
return _nTextFont;
|
||||
}
|
||||
|
||||
ErrorCode lineUp() {
|
||||
return scrollUp(1);
|
||||
}
|
||||
ErrorCode lineDown() {
|
||||
return scrollDown(1);
|
||||
}
|
||||
|
||||
ErrorCode pageUp() {
|
||||
return scrollUp(_nPageSize);
|
||||
}
|
||||
ErrorCode pageDown() {
|
||||
return scrollDown(_nPageSize);
|
||||
}
|
||||
|
||||
ErrorCode scrollUp(int nLines);
|
||||
ErrorCode scrollDown(const int nLines) {
|
||||
return scrollUp(-nLines);
|
||||
}
|
||||
|
||||
ErrorCode scrollTo(int nLine);
|
||||
|
||||
ErrorCode display();
|
||||
ErrorCode erase();
|
||||
|
||||
void flushBackground();
|
||||
|
||||
int getCurrLine() {
|
||||
return _nCurrentLine;
|
||||
}
|
||||
ErrorCode setCurrLine(const int nLine) {
|
||||
return scrollTo(nLine);
|
||||
}
|
||||
|
||||
protected:
|
||||
int getIndex(int nLines);
|
||||
|
||||
// Data
|
||||
CBofString _cBuffer;
|
||||
CBofText *_pTextField;
|
||||
CBofWindow *_pDestWindow;
|
||||
CBofBitmap *_pDestBitmap;
|
||||
|
||||
int _nCurrentLine;
|
||||
int _nCurrentIndex;
|
||||
int _nNumLines;
|
||||
int _nPageSize;
|
||||
|
||||
COLORREF _cTextColor;
|
||||
int _nPointSize;
|
||||
int _nWeight;
|
||||
int _nTextFont;
|
||||
};
|
||||
|
||||
} // namespace SpaceBar
|
||||
} // namespace Bagel
|
||||
|
||||
#endif
|
||||
859
engines/bagel/spacebar/boflib/gui/window.cpp
Normal file
859
engines/bagel/spacebar/boflib/gui/window.cpp
Normal file
@@ -0,0 +1,859 @@
|
||||
/* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "bagel/spacebar/boflib/gui/window.h"
|
||||
#include "bagel/spacebar/boflib/app.h"
|
||||
#include "bagel/spacebar/boflib/events.h"
|
||||
#include "bagel/boflib/sound.h"
|
||||
#include "bagel/spacebar/boflib/std_keys.h"
|
||||
#include "bagel/metaengine.h"
|
||||
#include "bagel/bagel.h"
|
||||
|
||||
namespace Bagel {
|
||||
namespace SpaceBar {
|
||||
|
||||
#define DOUBLE_CLICK_TIME 250
|
||||
|
||||
// Static members defined here
|
||||
CBofWindow *CBofWindow::_pWindowList = nullptr;
|
||||
CBofWindow *CBofWindow::_pActiveWindow = nullptr;
|
||||
CBofTimerPacket *CBofWindow::_pTimerList = nullptr;
|
||||
int CBofWindow::_mouseX = 0;
|
||||
int CBofWindow::_mouseY = 0;
|
||||
|
||||
CBofWindow::CBofWindow() {
|
||||
if (_pActiveWindow == nullptr)
|
||||
_pActiveWindow = this;
|
||||
|
||||
if (_pWindowList == nullptr) {
|
||||
_pWindowList = this;
|
||||
} else {
|
||||
_pWindowList->Insert(this);
|
||||
}
|
||||
}
|
||||
|
||||
CBofWindow::CBofWindow(const char *pszName, int x, int y, int nWidth, int nHeight, CBofWindow *pParent) {
|
||||
if (_pWindowList == nullptr) {
|
||||
_pWindowList = this;
|
||||
} else {
|
||||
_pWindowList->Insert(this);
|
||||
}
|
||||
|
||||
create(pszName, x, y, nWidth, nHeight, pParent);
|
||||
}
|
||||
|
||||
CBofWindow::~CBofWindow() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
delete _surface;
|
||||
_surface = nullptr;
|
||||
|
||||
killMyTimers();
|
||||
|
||||
// Remove it from any parent
|
||||
if (_parent != nullptr)
|
||||
setParent(nullptr);
|
||||
|
||||
// Remove this window from the list
|
||||
if (_pWindowList == this) {
|
||||
_pWindowList = (CBofWindow *)getNext();
|
||||
}
|
||||
|
||||
killBackdrop();
|
||||
|
||||
CBofWindow::destroy();
|
||||
}
|
||||
|
||||
ErrorCode CBofWindow::initialize() {
|
||||
_pWindowList = nullptr;
|
||||
_pActiveWindow = nullptr;
|
||||
_pTimerList = nullptr;
|
||||
|
||||
return ERR_NONE;
|
||||
}
|
||||
|
||||
ErrorCode CBofWindow::shutdown() {
|
||||
return ERR_NONE;
|
||||
}
|
||||
|
||||
Common::Point CBofWindow::getMousePos() {
|
||||
return Common::Point(_mouseX, _mouseY);
|
||||
}
|
||||
|
||||
void CBofWindow::destroy() {
|
||||
releaseCapture();
|
||||
|
||||
delete _surface;
|
||||
_surface = nullptr;
|
||||
|
||||
// When gui elements are destroyed, remove them
|
||||
// from the _children array of their parent
|
||||
setParent(nullptr);
|
||||
}
|
||||
|
||||
void CBofWindow::validateAnscestors(CBofRect *pRect) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
// Validate all anscestors
|
||||
CBofWindow *pParent = _parent;
|
||||
while (pParent != nullptr) {
|
||||
pParent->validateRect(pRect);
|
||||
pParent = pParent->getParent();
|
||||
}
|
||||
}
|
||||
|
||||
ErrorCode CBofWindow::create(const char *pszName, int x, int y, int nWidth, int nHeight, CBofWindow *pParent, uint32 nControlID) {
|
||||
assert(isValidObject(this));
|
||||
assert(pszName != nullptr);
|
||||
assert(pParent != this);
|
||||
|
||||
// Remember who our parent is
|
||||
if (pParent != nullptr)
|
||||
setParent(pParent);
|
||||
|
||||
_nID = nControlID;
|
||||
|
||||
// Remember the name of this window
|
||||
Common::strlcpy(_szTitle, pszName, MAX_TITLE);
|
||||
|
||||
// Retain screen coordinates for this window
|
||||
_cWindowRect.setRect(x, y, x + nWidth - 1, y + nHeight - 1);
|
||||
|
||||
// Calculate effective bounds
|
||||
Common::Rect stRect(x, y, x + nWidth, y + nHeight);
|
||||
if (pParent != nullptr)
|
||||
stRect.translate(pParent->getWindowRect().left,
|
||||
pParent->getWindowRect().top);
|
||||
|
||||
delete _surface;
|
||||
_surface = new Graphics::ManagedSurface(*g_engine->getScreen(), stRect);
|
||||
|
||||
if (!errorOccurred()) {
|
||||
CBofPalette *pPalette = CBofApp::getApp()->getPalette();
|
||||
if (pPalette != nullptr) {
|
||||
selectPalette(pPalette);
|
||||
}
|
||||
|
||||
// Retain local coordinates (based on own window)
|
||||
_cRect.setRect(0, 0, _cWindowRect.width() - 1, _cWindowRect.height() - 1);
|
||||
}
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
void CBofWindow::updateWindow() {
|
||||
if (_visible) {
|
||||
if (isVisible())
|
||||
onPaint(&_cRect);
|
||||
|
||||
for (uint i = 0; i < _children.size(); ++i)
|
||||
_children[i]->updateWindow();
|
||||
}
|
||||
}
|
||||
|
||||
void CBofWindow::setParent(CBofWindow *parent) {
|
||||
if (_parent != nullptr)
|
||||
_parent->_children.remove(this);
|
||||
|
||||
_parent = parent;
|
||||
if (parent)
|
||||
parent->_children.push_back(this);
|
||||
}
|
||||
|
||||
|
||||
ErrorCode CBofWindow::create(const char *pszName, CBofRect *pRect, CBofWindow *pParent, uint32 nControlID) {
|
||||
assert(isValidObject(this));
|
||||
assert(pszName != nullptr);
|
||||
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
|
||||
int nWidth = USE_DEFAULT;
|
||||
int nHeight = USE_DEFAULT;
|
||||
|
||||
if (pRect != nullptr) {
|
||||
x = pRect->left;
|
||||
y = pRect->top;
|
||||
nWidth = pRect->width();
|
||||
nHeight = pRect->height();
|
||||
}
|
||||
|
||||
return create(pszName, x, y, nWidth, nHeight, pParent, nControlID);
|
||||
}
|
||||
|
||||
void CBofWindow::releaseCapture() {
|
||||
_bCaptured = false;
|
||||
if (hasCapture())
|
||||
CBofApp::getApp()->setCaptureControl(nullptr);
|
||||
}
|
||||
|
||||
void CBofWindow::setCapture() {
|
||||
_bCaptured = true;
|
||||
CBofApp::getApp()->setCaptureControl(this);
|
||||
}
|
||||
|
||||
bool CBofWindow::hasCapture() const {
|
||||
return CBofApp::getApp()->getCaptureControl() == this;
|
||||
}
|
||||
|
||||
void CBofWindow::releaseFocus() {
|
||||
CBofApp::getApp()->setFocusControl(nullptr);
|
||||
}
|
||||
|
||||
void CBofWindow::setFocus() {
|
||||
CBofApp::getApp()->setFocusControl(this);
|
||||
}
|
||||
|
||||
bool CBofWindow::hasFocus() const {
|
||||
return CBofApp::getApp()->getFocusControl() == this;
|
||||
}
|
||||
|
||||
void CBofWindow::center() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
CBofWindow *pParent = _parent;
|
||||
int x, y;
|
||||
|
||||
if (pParent != nullptr) {
|
||||
CBofRect cWindowRect = pParent->getWindowRect();
|
||||
x = cWindowRect.left + (pParent->width() - width()) / 2;
|
||||
y = cWindowRect.top + (pParent->height() - height()) / 2;
|
||||
|
||||
} else {
|
||||
x = (CBofApp::getApp()->screenWidth() - width()) / 2;
|
||||
y = (CBofApp::getApp()->screenHeight() - height()) / 2;
|
||||
}
|
||||
|
||||
move(x, y);
|
||||
}
|
||||
|
||||
void CBofWindow::move(const int x, const int y, bool bRepaint) {
|
||||
assert(isValidObject(this));
|
||||
assert(isCreated());
|
||||
|
||||
// We now have a new position (in screen coordinates)
|
||||
_cWindowRect.setRect(x, y, x + _cRect.width() - 1, y + _cRect.height() - 1);
|
||||
|
||||
// Recreate the surface at the new screen position
|
||||
delete _surface;
|
||||
_surface = new Graphics::ManagedSurface(*g_engine->getScreen(), _cWindowRect);
|
||||
}
|
||||
|
||||
void CBofWindow::reSize(CBofRect *pRect, bool bRepaint) {
|
||||
assert(isValidObject(this));
|
||||
assert(isCreated());
|
||||
assert(pRect != nullptr);
|
||||
|
||||
// We now have a new position (in screen coordinates)
|
||||
_cWindowRect = *pRect;
|
||||
_cRect.setRect(0, 0, _cWindowRect.width() - 1, _cWindowRect.height() - 1);
|
||||
|
||||
// Recreate the surface at the new screen position
|
||||
delete _surface;
|
||||
_surface = new Graphics::ManagedSurface(*g_engine->getScreen(), _cWindowRect);
|
||||
}
|
||||
|
||||
void CBofWindow::select() {
|
||||
// No implementation in ScummVM
|
||||
}
|
||||
|
||||
void CBofWindow::show() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
if (!errorOccurred()) {
|
||||
assert(isCreated());
|
||||
|
||||
if (isCreated()) {
|
||||
_visible = true;
|
||||
invalidateRect(&_cRect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CBofWindow::hide() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
if (!errorOccurred()) {
|
||||
assert(isCreated());
|
||||
|
||||
_visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
void CBofWindow::postMessage(uint32 nMessage, uint32 lParam1, uint32 lParam2) {
|
||||
assert(isValidObject(this));
|
||||
assert(isCreated());
|
||||
}
|
||||
|
||||
void CBofWindow::setTimer(uint32 nID, uint32 nInterval, BofCallback pCallBack) {
|
||||
assert(isValidObject(this));
|
||||
assert(isCreated());
|
||||
|
||||
// Don't add it if there's already a timer there with the same id.
|
||||
CBofTimerPacket *pPacket = _pTimerList;
|
||||
|
||||
while (pPacket != nullptr) {
|
||||
if (pPacket->_nID == nID)
|
||||
return;
|
||||
|
||||
pPacket = (CBofTimerPacket *)pPacket->getNext();
|
||||
}
|
||||
|
||||
pPacket = new CBofTimerPacket;
|
||||
pPacket->_nID = nID;
|
||||
pPacket->_nInterval = nInterval;
|
||||
pPacket->_pCallBack = pCallBack;
|
||||
pPacket->_pOwnerWindow = this;
|
||||
|
||||
// Add this timer to the list of current timers
|
||||
if (_pTimerList != nullptr) {
|
||||
_pTimerList->addToHead(pPacket);
|
||||
}
|
||||
|
||||
_pTimerList = pPacket;
|
||||
|
||||
// Add the timer to the window
|
||||
_timers.push_back(WindowTimer(nInterval, nID, pCallBack));
|
||||
}
|
||||
|
||||
void CBofWindow::killTimer(uint32 nID) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
// Remove the timer from the window timer list
|
||||
for (Common::List<WindowTimer>::iterator it = _timers.begin(); it != _timers.end(); ++it) {
|
||||
if (it->_id == nID) {
|
||||
_timers.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Find and remove the timer packet for this timer
|
||||
CBofTimerPacket *pPacket = _pTimerList;
|
||||
|
||||
while (pPacket != nullptr) {
|
||||
if (pPacket->_nID == nID) {
|
||||
if (pPacket == _pTimerList) {
|
||||
_pTimerList = (CBofTimerPacket *)_pTimerList->getNext();
|
||||
}
|
||||
|
||||
delete pPacket;
|
||||
break;
|
||||
}
|
||||
|
||||
pPacket = (CBofTimerPacket *)pPacket->getNext();
|
||||
}
|
||||
}
|
||||
|
||||
void CBofWindow::killMyTimers() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
CBofTimerPacket *pTimer = _pTimerList;
|
||||
while (pTimer != nullptr) {
|
||||
CBofTimerPacket *pNextTimer = (CBofTimerPacket *)pTimer->getNext();
|
||||
|
||||
if (pTimer->_pOwnerWindow == this) {
|
||||
killTimer(pTimer->_nID);
|
||||
}
|
||||
|
||||
pTimer = pNextTimer;
|
||||
}
|
||||
}
|
||||
|
||||
void CBofWindow::checkTimers() {
|
||||
for (uint i = 0; i < _children.size(); ++i)
|
||||
_children[i]->checkTimers();
|
||||
|
||||
for (bool timersChanged = true; timersChanged;) {
|
||||
timersChanged = false;
|
||||
uint32 currTime = g_system->getMillis();
|
||||
|
||||
// Iterate over the timers looking for any that have expired
|
||||
for (auto &timer : _timers) {
|
||||
if (currTime >= (timer._lastExpiryTime + timer._interval)) {
|
||||
// Timer has expired
|
||||
timer._lastExpiryTime = currTime;
|
||||
|
||||
if (timer._callback) {
|
||||
(timer._callback)(timer._id, this);
|
||||
} else {
|
||||
onTimer(timer._id);
|
||||
}
|
||||
|
||||
// Flag to restart scanning through the timer list
|
||||
// for any other expired timers, since the timer call
|
||||
// may have modified the existing list
|
||||
timersChanged = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CBofWindow::screenToClient(CBofPoint *pPoint) {
|
||||
// Not needed in ScummVM
|
||||
}
|
||||
|
||||
CBofRect CBofWindow::getClientRect() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
CBofRect cRect(0, 0, _cRect.width() - 1, _cRect.height() - 1);
|
||||
return cRect;
|
||||
}
|
||||
|
||||
void CBofWindow::postUserMessage(uint32 lMessage, uint32 lExtraInfo) {
|
||||
Common::Event e;
|
||||
e.type = (Common::EventType)EVENT_USER;
|
||||
e.mouse.x = lMessage;
|
||||
e.mouse.y = lExtraInfo;
|
||||
|
||||
g_system->getEventManager()->pushEvent(e);
|
||||
}
|
||||
|
||||
void CBofWindow::flushAllMessages() {
|
||||
// Make sure this is a valid window
|
||||
assert(isValidObject(this));
|
||||
assert(isCreated());
|
||||
}
|
||||
|
||||
void CBofWindow::validateRect(const CBofRect *pRect) {
|
||||
// No implementation in ScummVM
|
||||
}
|
||||
|
||||
void CBofWindow::invalidateRect(const CBofRect *pRect) {
|
||||
}
|
||||
|
||||
ErrorCode CBofWindow::setBackdrop(CBofBitmap *pNewBitmap, bool bRefresh) {
|
||||
assert(isValidObject(this));
|
||||
assert(pNewBitmap != nullptr);
|
||||
|
||||
// Destroy old backdrop (if any)
|
||||
killBackdrop();
|
||||
|
||||
// We take ownership of this bitmap!
|
||||
_pBackdrop = pNewBitmap;
|
||||
|
||||
if (bRefresh) {
|
||||
_pBackdrop->paint(this, 0, 0);
|
||||
}
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
ErrorCode CBofWindow::setBackdrop(const char *pszFileName, bool bRefresh) {
|
||||
assert(isValidObject(this));
|
||||
assert(pszFileName != nullptr);
|
||||
|
||||
// Use Application's palette if none supplied
|
||||
CBofPalette *pPalette = CBofApp::getApp()->getPalette();
|
||||
CBofBitmap *pBmp = new CBofBitmap(pszFileName, pPalette);
|
||||
|
||||
return setBackdrop(pBmp, bRefresh);
|
||||
}
|
||||
|
||||
void CBofWindow::killBackdrop() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
delete _pBackdrop;
|
||||
_pBackdrop = nullptr;
|
||||
}
|
||||
|
||||
ErrorCode CBofWindow::paintBackdrop(CBofRect *pRect, int nTransparentColor) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
if (_pBackdrop != nullptr) {
|
||||
if (pRect == nullptr) {
|
||||
_errCode = _pBackdrop->paint(this, &_cRect, nullptr, nTransparentColor);
|
||||
} else {
|
||||
_errCode = _pBackdrop->paint(this, pRect, pRect, nTransparentColor);
|
||||
}
|
||||
}
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
void CBofWindow::selectPalette(CBofPalette *pPal) {
|
||||
assert(isValidObject(this));
|
||||
assert(isCreated());
|
||||
}
|
||||
|
||||
Graphics::ManagedSurface *CBofWindow::getSurface() {
|
||||
return _surface;
|
||||
}
|
||||
|
||||
|
||||
// Default version of these virtual functions don't do anything
|
||||
//
|
||||
void CBofWindow::onMouseMove(uint32, CBofPoint *, void *) {
|
||||
}
|
||||
|
||||
void CBofWindow::onLButtonDown(uint32, CBofPoint *, void *) {
|
||||
}
|
||||
void CBofWindow::onLButtonUp(uint32, CBofPoint *, void *) {
|
||||
}
|
||||
void CBofWindow::onLButtonDblClk(uint32, CBofPoint *) {
|
||||
}
|
||||
|
||||
void CBofWindow::onRButtonDown(uint32, CBofPoint *) {
|
||||
}
|
||||
void CBofWindow::onRButtonUp(uint32, CBofPoint *) {
|
||||
}
|
||||
void CBofWindow::onRButtonDblClk(uint32, CBofPoint *) {
|
||||
}
|
||||
|
||||
void CBofWindow::onKeyHit(uint32, uint32) {
|
||||
}
|
||||
|
||||
void CBofWindow::onReSize(CBofSize *) {
|
||||
}
|
||||
void CBofWindow::onPaint(CBofRect *) {
|
||||
}
|
||||
void CBofWindow::onTimer(uint32) {
|
||||
}
|
||||
|
||||
void CBofWindow::onClose() {
|
||||
}
|
||||
|
||||
void CBofWindow::onBofButton(CBofObject *, int) {
|
||||
}
|
||||
void CBofWindow::onBofScrollBar(CBofObject *, int) {
|
||||
}
|
||||
void CBofWindow::onBofListBox(CBofObject *, int) {
|
||||
}
|
||||
void CBofWindow::onUserMessage(uint32, uint32) {
|
||||
}
|
||||
void CBofWindow::onMainLoop() {
|
||||
}
|
||||
|
||||
void CBofWindow::onSoundNotify(CBofObject *, uint32) {
|
||||
}
|
||||
void CBofWindow::onMovieNotify(uint32, uint32) {
|
||||
}
|
||||
|
||||
void CBofWindow::onActivate() {
|
||||
}
|
||||
void CBofWindow::onDeActivate() {
|
||||
}
|
||||
|
||||
void CBofWindow::onMCINotify(uint32 wParam, uint32 lParam) {
|
||||
assert(isValidObject(this));
|
||||
}
|
||||
|
||||
void CBofWindow::handleEvents() {
|
||||
Common::Event e;
|
||||
CBofWindow *capture = CBofApp::getApp()->getCaptureControl();
|
||||
CBofWindow *focus = CBofApp::getApp()->getFocusControl();
|
||||
bool eventsPresent = false;
|
||||
|
||||
while (g_system->getEventManager()->pollEvent(e)) {
|
||||
if (capture)
|
||||
capture->handleEvent(e);
|
||||
else if (e.type == Common::EVENT_KEYDOWN && focus)
|
||||
focus->handleEvent(e);
|
||||
else
|
||||
handleEvent(e);
|
||||
|
||||
if (e.type >= Common::EVENT_MOUSEMOVE && e.type <= Common::EVENT_MBUTTONUP) {
|
||||
_mouseX = e.mouse.x;
|
||||
_mouseY = e.mouse.y;
|
||||
}
|
||||
|
||||
if (e.type != Common::EVENT_MOUSEMOVE) {
|
||||
eventsPresent = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Only do timer checks when not processing other pending events.
|
||||
// This simulates Windows behaviour, where the WM_TIMER events
|
||||
// would be added at the end of the event queue
|
||||
if (!eventsPresent)
|
||||
// Check for expired timers
|
||||
checkTimers();
|
||||
|
||||
|
||||
}
|
||||
|
||||
void CBofWindow::handleEvent(const Common::Event &event) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
if (!_enabled || !_visible)
|
||||
// Window is disabled or hidden
|
||||
return;
|
||||
|
||||
CBofPoint mousePos(event.mouse.x - _cWindowRect.left,
|
||||
event.mouse.y - _cWindowRect.top);
|
||||
for (auto parent = _parent; parent; parent = parent->_parent) {
|
||||
mousePos.x -= parent->_cWindowRect.left;
|
||||
mousePos.y -= parent->_cWindowRect.top;
|
||||
}
|
||||
|
||||
switch (event.type) {
|
||||
case Common::EVENT_MOUSEMOVE:
|
||||
case Common::EVENT_LBUTTONDOWN:
|
||||
case Common::EVENT_LBUTTONUP:
|
||||
case Common::EVENT_RBUTTONDOWN:
|
||||
case Common::EVENT_RBUTTONUP: {
|
||||
// Check if the mouse is within the area of a child control
|
||||
for (uint i = 0; i < _children.size(); ++i) {
|
||||
auto &child = *_children[i];
|
||||
if (child.isVisible() && child.isEnabled() &&
|
||||
child.getWindowRect().ptInRect(mousePos)) {
|
||||
child.handleEvent(event);
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
uint32 currTime = g_system->getMillis();
|
||||
|
||||
switch ((int)event.type) {
|
||||
case Common::EVENT_MOUSEMOVE:
|
||||
onMouseMove(0, &mousePos);
|
||||
break;
|
||||
|
||||
case Common::EVENT_LBUTTONDOWN:
|
||||
if ((currTime - _lastLButtonTime) <= DOUBLE_CLICK_TIME) {
|
||||
_lastLButtonTime = 0;
|
||||
onLButtonDblClk(1, &mousePos);
|
||||
} else {
|
||||
onLButtonDown(1, &mousePos);
|
||||
_lastLButtonTime = currTime;
|
||||
}
|
||||
break;
|
||||
|
||||
case Common::EVENT_LBUTTONUP:
|
||||
onLButtonUp(0, &mousePos);
|
||||
break;
|
||||
|
||||
case Common::EVENT_RBUTTONDOWN:
|
||||
if ((currTime - _lastRButtonTime) <= DOUBLE_CLICK_TIME) {
|
||||
_lastRButtonTime = 0;
|
||||
onRButtonDblClk(2, &mousePos);
|
||||
} else {
|
||||
onRButtonDown(2, &mousePos);
|
||||
_lastRButtonTime = currTime;
|
||||
}
|
||||
break;
|
||||
|
||||
case Common::EVENT_RBUTTONUP:
|
||||
onRButtonUp(0, &mousePos);
|
||||
break;
|
||||
|
||||
case Common::EVENT_KEYDOWN:
|
||||
uint32 lNewKey;
|
||||
|
||||
if ((lNewKey = translateKey(event)) != BKEY_UNKNOWN) {
|
||||
onKeyHit(lNewKey, event.kbdRepeat ? 1 : 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case Common::EVENT_CUSTOM_ENGINE_ACTION_START:
|
||||
if (event.customType != KEYBIND_NONE)
|
||||
onKeyHit((event.customType == KEYBIND_WAIT)
|
||||
? BKEY_SPACE : BKEY_SCRL_LOCK, 0);
|
||||
break;
|
||||
|
||||
case EVENT_USER:
|
||||
// Message type and param are stored in mouse x/y
|
||||
onUserMessage(event.mouse.x, event.mouse.y);
|
||||
break;
|
||||
|
||||
case Common::EVENT_QUIT:
|
||||
onClose();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32 CBofWindow::translateKey(const Common::Event &event) const {
|
||||
uint32 nCode = BKEY_UNKNOWN;
|
||||
|
||||
switch (event.kbd.keycode) {
|
||||
case Common::KEYCODE_F1:
|
||||
nCode = BKEY_F1;
|
||||
break;
|
||||
case Common::KEYCODE_F2:
|
||||
nCode = BKEY_SAVE;
|
||||
break;
|
||||
case Common::KEYCODE_F3:
|
||||
nCode = BKEY_RESTORE;
|
||||
break;
|
||||
case Common::KEYCODE_F4:
|
||||
nCode = BKEY_F4;
|
||||
break;
|
||||
case Common::KEYCODE_F5:
|
||||
nCode = BKEY_SAVE;
|
||||
break;
|
||||
case Common::KEYCODE_F6:
|
||||
nCode = BKEY_F6;
|
||||
break;
|
||||
case Common::KEYCODE_F7:
|
||||
nCode = BKEY_RESTORE;
|
||||
break;
|
||||
case Common::KEYCODE_F8:
|
||||
nCode = BKEY_F8;
|
||||
break;
|
||||
case Common::KEYCODE_F9:
|
||||
nCode = BKEY_F9;
|
||||
break;
|
||||
case Common::KEYCODE_F10:
|
||||
nCode = BKEY_F10;
|
||||
break;
|
||||
case Common::KEYCODE_F11:
|
||||
nCode = BKEY_F11;
|
||||
break;
|
||||
case Common::KEYCODE_F12:
|
||||
nCode = BKEY_F12;
|
||||
break;
|
||||
|
||||
case Common::KEYCODE_END:
|
||||
nCode = BKEY_END;
|
||||
break;
|
||||
case Common::KEYCODE_HOME:
|
||||
nCode = BKEY_HOME;
|
||||
break;
|
||||
case Common::KEYCODE_LEFT:
|
||||
nCode = BKEY_LEFT;
|
||||
break;
|
||||
case Common::KEYCODE_RIGHT:
|
||||
nCode = BKEY_RIGHT;
|
||||
break;
|
||||
case Common::KEYCODE_UP:
|
||||
nCode = BKEY_UP;
|
||||
break;
|
||||
case Common::KEYCODE_DOWN:
|
||||
nCode = BKEY_DOWN;
|
||||
break;
|
||||
case Common::KEYCODE_RETURN:
|
||||
nCode = BKEY_ENTER;
|
||||
break;
|
||||
case Common::KEYCODE_INSERT:
|
||||
nCode = BKEY_INS;
|
||||
break;
|
||||
case Common::KEYCODE_BACKSPACE:
|
||||
nCode = BKEY_BACK;
|
||||
break;
|
||||
case Common::KEYCODE_DELETE:
|
||||
nCode = BKEY_DEL;
|
||||
break;
|
||||
case Common::KEYCODE_SCROLLOCK:
|
||||
nCode = BKEY_SCRL_LOCK;
|
||||
break;
|
||||
case Common::KEYCODE_PAGEUP:
|
||||
nCode = BKEY_PAGEUP;
|
||||
break;
|
||||
case Common::KEYCODE_PAGEDOWN:
|
||||
nCode = BKEY_PAGEDOWN;
|
||||
break;
|
||||
case Common::KEYCODE_ESCAPE:
|
||||
nCode = BKEY_ESC;
|
||||
break;
|
||||
|
||||
default:
|
||||
// No translation for this key
|
||||
if (event.kbd.ascii >= 32 && event.kbd.ascii <= 127)
|
||||
nCode = event.kbd.ascii;
|
||||
break;
|
||||
}
|
||||
|
||||
if (nCode != BKEY_UNKNOWN) {
|
||||
if (event.kbd.flags & Common::KBD_ALT) {
|
||||
nCode = tolower(nCode) | BKF_ALT;
|
||||
}
|
||||
}
|
||||
|
||||
return nCode;
|
||||
}
|
||||
|
||||
void CBofWindow::fillWindow(byte iColor) {
|
||||
fillRect(nullptr, iColor);
|
||||
}
|
||||
|
||||
void CBofWindow::fillRect(CBofRect *pRect, byte iColor) {
|
||||
CBofBitmap cBmp(width(), height(), CBofApp::getApp()->getPalette());
|
||||
cBmp.fillRect(pRect, iColor);
|
||||
cBmp.paint(this, 0, 0);
|
||||
}
|
||||
|
||||
ErrorCode CBofWindow::paintBeveledText(CBofRect *rect, const CBofString &cString, const int size, const int weight, const COLORREF color, int justify, uint32 format) {
|
||||
assert(rect != nullptr);
|
||||
|
||||
CBofBitmap bmp(rect->width(), rect->height(), nullptr, false);
|
||||
|
||||
// Assume no error
|
||||
ErrorCode errorCode = ERR_NONE;
|
||||
|
||||
CBofRect r = bmp.getRect();
|
||||
CBofPalette *palette = nullptr;
|
||||
CBofApp *app = CBofApp::getApp();
|
||||
if (app != nullptr) {
|
||||
palette = app->getPalette();
|
||||
}
|
||||
|
||||
if (palette != nullptr) {
|
||||
bmp.fillRect(nullptr, palette->getNearestIndex(RGB(92, 92, 92)));
|
||||
|
||||
bmp.drawRect(&r, palette->getNearestIndex(RGB(0, 0, 0)));
|
||||
} else {
|
||||
bmp.fillRect(nullptr, COLOR_BLACK);
|
||||
}
|
||||
|
||||
byte c1 = 3;
|
||||
byte c2 = 9;
|
||||
CBofRect cBevel = r;
|
||||
|
||||
int left = cBevel.left;
|
||||
int top = cBevel.top;
|
||||
int right = cBevel.right;
|
||||
int bottom = cBevel.bottom;
|
||||
|
||||
r.left += 6;
|
||||
r.top += 3;
|
||||
r.right -= 5;
|
||||
r.bottom -= 5;
|
||||
|
||||
for (int i = 1; i <= 3; i++) {
|
||||
bmp.line(left + i, bottom - i, right - i, bottom - i, c1);
|
||||
bmp.line(right - i, bottom - i, right - i, top + i - 1, c1);
|
||||
}
|
||||
|
||||
for (int i = 1; i <= 3; i++) {
|
||||
bmp.line(left + i, bottom - i, left + i, top + i - 1, c2);
|
||||
bmp.line(left + i, top + i - 1, right - i, top + i - 1, c2);
|
||||
}
|
||||
|
||||
paintText(&bmp, &r, cString, size, weight, color, justify, format, FONT_DEFAULT);
|
||||
|
||||
bmp.paint(this, rect);
|
||||
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
} // namespace SpaceBar
|
||||
} // namespace Bagel
|
||||
480
engines/bagel/spacebar/boflib/gui/window.h
Normal file
480
engines/bagel/spacebar/boflib/gui/window.h
Normal file
@@ -0,0 +1,480 @@
|
||||
|
||||
/* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BAGEL_BOFLIB_GUI_WINDOW_H
|
||||
#define BAGEL_BOFLIB_GUI_WINDOW_H
|
||||
|
||||
#include "common/list.h"
|
||||
#include "common/events.h"
|
||||
#include "bagel/spacebar/boflib/array.h"
|
||||
#include "bagel/boflib/stdinc.h"
|
||||
#include "bagel/boflib/error.h"
|
||||
#include "bagel/boflib/object.h"
|
||||
#include "bagel/boflib/point.h"
|
||||
#include "bagel/boflib/rect.h"
|
||||
#include "bagel/boflib/size.h"
|
||||
#include "bagel/spacebar/boflib/timer.h"
|
||||
#include "bagel/boflib/llist.h"
|
||||
#include "bagel/spacebar/boflib/gfx/bitmap.h"
|
||||
#include "bagel/boflib/palette.h"
|
||||
#include "bagel/spacebar/boflib/gfx/text.h"
|
||||
|
||||
namespace Bagel {
|
||||
|
||||
class CBofString;
|
||||
|
||||
namespace SpaceBar {
|
||||
|
||||
#define MAX_TITLE 64
|
||||
#define USE_DEFAULT (-1)
|
||||
|
||||
class CBofBitmap;
|
||||
class CBofTimerPacket;
|
||||
|
||||
class CBofWindow : public CLList, public CBofObject, public CBofError {
|
||||
private:
|
||||
bool _visible = true;
|
||||
bool _enabled = true;
|
||||
Common::List<WindowTimer> _timers;
|
||||
uint32 _lastLButtonTime = 0, _lastRButtonTime = 0;
|
||||
|
||||
/**
|
||||
* Handles translating from a ScummVM event structure to
|
||||
* a code used by the game engine
|
||||
*/
|
||||
uint32 translateKey(const Common::Event &event) const;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Checks window timers for expiry
|
||||
*/
|
||||
void checkTimers();
|
||||
|
||||
public:
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
CBofWindow();
|
||||
|
||||
/**
|
||||
* Constructor for CBofWindow
|
||||
* @param pszName Name of window
|
||||
* @param x X position
|
||||
* @param y Y position
|
||||
* @param nWidth Width of window to create (optional)
|
||||
* @param nHeight Height of window to create (optional)
|
||||
* @param pParent Parent of this window (optional)
|
||||
*/
|
||||
CBofWindow(const char *pszName, int x, int y, int nWidth, int nHeight, CBofWindow *pParent);
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~CBofWindow();
|
||||
|
||||
static ErrorCode initialize();
|
||||
static ErrorCode shutdown();
|
||||
static Common::Point getMousePos();
|
||||
|
||||
/**
|
||||
* Creates a window
|
||||
* @param pszName Name of window
|
||||
* @param x X position of upper-left corner
|
||||
* @param y Y position of upper-left corner
|
||||
* @param nWidth Width of window to create (optional)
|
||||
* @param nHeight Height of window to create (optional)
|
||||
* @param pParent Parent of this window (optional)
|
||||
* @param nControlID User defined ID of this window
|
||||
* @return Error return code
|
||||
*/
|
||||
virtual ErrorCode create(const char *pszName, int x, int y, int nWidth, int nHeight, CBofWindow *pParent, uint32 nControlID = 0);
|
||||
|
||||
/**
|
||||
* Creates a window
|
||||
* @param pszName Name of window
|
||||
* @param pRect Rectangle for window placement
|
||||
* @param pParent Parent of this window (optional)
|
||||
* @param nControlID User defined ID of this window
|
||||
* @return Error return code
|
||||
*/
|
||||
virtual ErrorCode create(const char *pszName, CBofRect *pRect, CBofWindow *pParent, uint32 nControlID = 0);
|
||||
|
||||
/**
|
||||
* Destroys the Window attached to this CBofWindow (if any)
|
||||
*/
|
||||
virtual void destroy();
|
||||
virtual void destroyWindow() {
|
||||
destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows current window (if hidden)
|
||||
*/
|
||||
void show();
|
||||
|
||||
void select();
|
||||
|
||||
/**
|
||||
* Hides current window (if shown)
|
||||
*/
|
||||
void hide();
|
||||
|
||||
/**
|
||||
* Centers current window in parent window or in screen
|
||||
*/
|
||||
void center();
|
||||
|
||||
/**
|
||||
* Moves current window to specified location in parent
|
||||
* @param x New upper left corner X position
|
||||
* @param y New upper left corner Y position
|
||||
* @param bRepaint true if should update the window
|
||||
*/
|
||||
void move(int x, int y, bool bRepaint = false);
|
||||
|
||||
/**
|
||||
* Resizes current window to specified area
|
||||
* @param pRect New area for window
|
||||
* @param bRepaint Optional repaint after resize
|
||||
*/
|
||||
void reSize(CBofRect *pRect, bool bRepaint = false);
|
||||
|
||||
virtual ErrorCode close() {
|
||||
onClose();
|
||||
|
||||
return ERR_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Posts a message
|
||||
* @param nMessage Message to post
|
||||
* @param lParam1 User info
|
||||
* @param lParam2 More user info
|
||||
*/
|
||||
void postMessage(uint32 nMessage, uint32 lParam1, uint32 lParam2);
|
||||
|
||||
/**
|
||||
* Posts a user defined message
|
||||
*/
|
||||
void postUserMessage(uint32 lMessage, uint32 lExtraInfo);
|
||||
|
||||
/**
|
||||
* Sets a timer which calls specified callback (or onTimer)
|
||||
* @param nID ID of timer to set
|
||||
* @param nInterval Number of milliseconds till event
|
||||
* @param pCallBack Function to call when time is up
|
||||
*/
|
||||
void setTimer(uint32 nID, uint32 nInterval, BofCallback pCallBack = nullptr);
|
||||
|
||||
/**
|
||||
* Stops specified timer
|
||||
* @param nID ID of timer to stop
|
||||
*/
|
||||
void killTimer(uint32 nID);
|
||||
|
||||
/**
|
||||
* Stops all timers associated with current window
|
||||
*/
|
||||
void killMyTimers();
|
||||
|
||||
/**
|
||||
* Returns the parent window element, if any
|
||||
*/
|
||||
CBofWindow *getParent() const {
|
||||
return _parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Causes all parent windows to have valid paint regions
|
||||
* @param pRect Area to validate
|
||||
*/
|
||||
void validateAnscestors(CBofRect *pRect = nullptr);
|
||||
|
||||
static CBofWindow *getActiveWindow() {
|
||||
return _pActiveWindow;
|
||||
}
|
||||
|
||||
void setActive() {
|
||||
_pActiveWindow = this;
|
||||
}
|
||||
|
||||
static CBofWindow *getWindowList() {
|
||||
return _pWindowList;
|
||||
}
|
||||
|
||||
CBofRect getWindowRect() const {
|
||||
return _cWindowRect;
|
||||
}
|
||||
CBofRect getClientRect();
|
||||
|
||||
CBofRect getRect() const {
|
||||
return _cRect;
|
||||
}
|
||||
|
||||
int width() const {
|
||||
return _cRect.width();
|
||||
}
|
||||
int height() const {
|
||||
return _cRect.height();
|
||||
}
|
||||
|
||||
void screenToClient(CBofPoint *pPoint);
|
||||
|
||||
/**
|
||||
* Selects and Realizes specified palette into current DC
|
||||
* @param pPal Palette to select
|
||||
*/
|
||||
void selectPalette(CBofPalette *pPal);
|
||||
|
||||
/**
|
||||
* Associates a new background bitmap to this window
|
||||
* @param pNewBitmap New background bitmap
|
||||
* @param bRefresh true if should repaint now
|
||||
* @return Error return code
|
||||
*/
|
||||
ErrorCode setBackdrop(CBofBitmap *pNewBitmap, bool bRefresh = false);
|
||||
|
||||
/**
|
||||
* Associates a new background bitmap to this window
|
||||
* @param pszFileName new background bitmap from file
|
||||
* @param bRefresh true if should repaint now
|
||||
* @return Error return code
|
||||
*/
|
||||
ErrorCode setBackdrop(const char *pszFileName, bool bRefresh = false);
|
||||
|
||||
void clearBackdrop() {
|
||||
_pBackdrop = nullptr;
|
||||
}
|
||||
|
||||
CBofBitmap *getBackdrop() const {
|
||||
return _pBackdrop;
|
||||
}
|
||||
|
||||
bool hasBackdrop() const {
|
||||
return _pBackdrop != nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the background bitmap associated with this window
|
||||
*/
|
||||
void killBackdrop();
|
||||
|
||||
/**
|
||||
* Updates the specified section of the background bitmap
|
||||
* @param pRect Area of bitmap to update on screen
|
||||
* @param nTransparentColor Color index used for transparency (-1 = none)
|
||||
* @return Error return code
|
||||
*/
|
||||
ErrorCode paintBackdrop(CBofRect *pRect = nullptr, int nTransparentColor = -1);
|
||||
|
||||
void setControlID(uint32 nID) {
|
||||
_nID = nID;
|
||||
}
|
||||
uint32 getControlID() const {
|
||||
return _nID;
|
||||
}
|
||||
|
||||
void setBkColor(COLORREF cColor) {
|
||||
_cBkColor = cColor;
|
||||
}
|
||||
COLORREF getBkColor() const {
|
||||
return _cBkColor;
|
||||
}
|
||||
|
||||
void setFgColor(COLORREF cColor) {
|
||||
_cFgColor = cColor;
|
||||
}
|
||||
COLORREF getFgColor() const {
|
||||
return _cFgColor;
|
||||
}
|
||||
|
||||
void setPrevMouseDown(CBofPoint p) {
|
||||
_cPrevMouseDown = p;
|
||||
}
|
||||
CBofPoint getPrevMouseDown() const {
|
||||
return _cPrevMouseDown;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets mouse capture for this window
|
||||
*/
|
||||
void setCapture();
|
||||
|
||||
/**
|
||||
* Release mouse capture for this window
|
||||
*/
|
||||
void releaseCapture();
|
||||
|
||||
/**
|
||||
* Returns true if the control is capturing mouse events
|
||||
*/
|
||||
bool hasCapture() const;
|
||||
|
||||
/**
|
||||
* Sets the focus on a control for keyboard input
|
||||
*/
|
||||
void setFocus();
|
||||
|
||||
/**
|
||||
* Releases focus from an edit control
|
||||
*/
|
||||
void releaseFocus();
|
||||
|
||||
/**
|
||||
* Returns true if the control has focus
|
||||
*/
|
||||
bool hasFocus() const;
|
||||
|
||||
void flushAllMessages();
|
||||
|
||||
/**
|
||||
* Adds specified rectangle to dirty rect list for this window
|
||||
* @param pRect Rectangle to add to dirty list
|
||||
*/
|
||||
void validateRect(const CBofRect *pRect);
|
||||
|
||||
/**
|
||||
* Removes specified rectangle from dirty rect for this window
|
||||
* @param pRect Rectangle to remove from dirty list
|
||||
*/
|
||||
void invalidateRect(const CBofRect *pRect);
|
||||
|
||||
virtual void onBofButton(CBofObject *pButton, int nExtraInfo);
|
||||
virtual void onBofScrollBar(CBofObject *pButton, int nNewPos);
|
||||
virtual void onBofListBox(CBofObject *pListBox, int nItemIndex);
|
||||
virtual void onMainLoop();
|
||||
|
||||
virtual void onSoundNotify(CBofObject *pObject, uint32 lParam2);
|
||||
virtual void onMovieNotify(uint32 lParam1, uint32 lParam2);
|
||||
|
||||
virtual void onMCINotify(uint32 wParam, uint32 lParam);
|
||||
|
||||
virtual void onTimer(uint32 nTimerId);
|
||||
|
||||
/**
|
||||
* Handles a pending ScummVM event
|
||||
* @param event Event to process
|
||||
*/
|
||||
virtual void handleEvent(const Common::Event &event);
|
||||
|
||||
Graphics::ManagedSurface *getSurface();
|
||||
|
||||
bool isCreated() const {
|
||||
return _surface != nullptr;
|
||||
}
|
||||
|
||||
virtual void enable() {
|
||||
_enabled = true;
|
||||
updateWindow();
|
||||
}
|
||||
virtual void disable() {
|
||||
_enabled = false;
|
||||
updateWindow();
|
||||
}
|
||||
bool isVisible() const {
|
||||
return _visible;
|
||||
}
|
||||
bool isEnabled() const {
|
||||
return _enabled;
|
||||
}
|
||||
|
||||
void updateWindow();
|
||||
|
||||
void setParent(CBofWindow *parent);
|
||||
|
||||
/**
|
||||
* Handle all pending ScummVM events
|
||||
*/
|
||||
void handleEvents();
|
||||
|
||||
virtual void onKeyHit(uint32 lKey, uint32 lRepCount);
|
||||
void fillWindow(byte iColor);
|
||||
void fillRect(CBofRect *pRect, byte iColor);
|
||||
|
||||
ErrorCode paintBeveledText(CBofRect *rect, const CBofString &string, int size, int weight, COLORREF color, int justify, uint32 format);
|
||||
|
||||
|
||||
protected:
|
||||
CBofWindow *_parent = nullptr; // Pointer to parent window
|
||||
Array<CBofWindow *> _children; // Child element pointers
|
||||
|
||||
virtual void onMouseMove(uint32 nFlags, CBofPoint *pPoint, void * = nullptr);
|
||||
virtual void onLButtonDown(uint32 nFlags, CBofPoint *pPoint, void * = nullptr);
|
||||
virtual void onLButtonUp(uint32 nFlags, CBofPoint *pPoint, void * = nullptr);
|
||||
virtual void onLButtonDblClk(uint32 nFlags, CBofPoint *pPoint);
|
||||
|
||||
virtual void onRButtonDown(uint32 nFlags, CBofPoint *pPoint);
|
||||
virtual void onRButtonUp(uint32 nFlags, CBofPoint *pPoint);
|
||||
virtual void onRButtonDblClk(uint32 nFlags, CBofPoint *pPoint);
|
||||
|
||||
virtual void onReSize(CBofSize *pSize);
|
||||
virtual void onPaint(CBofRect *pRect);
|
||||
virtual void onClose();
|
||||
|
||||
virtual void onUserMessage(uint32 nMessage, uint32 lParam);
|
||||
|
||||
virtual void onActivate();
|
||||
virtual void onDeActivate();
|
||||
|
||||
// Window Data
|
||||
char _szTitle[MAX_TITLE] = { 0 }; // Title of window
|
||||
CBofRect _cWindowRect; // Screen based area of this window
|
||||
CBofRect _cRect; // Window-based area of this window
|
||||
CBofBitmap *_pBackdrop = nullptr; // Backdrop bitmap
|
||||
uint32 _nID = 0; // ID of this window
|
||||
|
||||
COLORREF _cBkColor = RGB(255, 255, 255);
|
||||
COLORREF _cFgColor = RGB(0, 0, 0);
|
||||
|
||||
bool _bCaptured = false;
|
||||
Graphics::ManagedSurface *_surface = nullptr;
|
||||
|
||||
static CBofWindow *_pWindowList;
|
||||
static CBofWindow *_pActiveWindow;
|
||||
static CBofTimerPacket *_pTimerList;
|
||||
CBofPoint _cPrevMouseDown;
|
||||
static int _mouseX;
|
||||
static int _mouseY;
|
||||
};
|
||||
|
||||
class CBofMessage : public CBofObject {
|
||||
public:
|
||||
CBofWindow *_pWindow; // destination window for message
|
||||
uint32 _nMessage; // message to send (usually WM_USER)
|
||||
uint32 _lParam1; // user defined info
|
||||
uint32 _lParam2; // more user defined info
|
||||
};
|
||||
|
||||
class CBofTimerPacket : public CBofObject, public CLList {
|
||||
public:
|
||||
CBofWindow *_pOwnerWindow;
|
||||
BofCallback _pCallBack;
|
||||
uint32 _nID;
|
||||
uint32 _nInterval;
|
||||
};
|
||||
|
||||
extern CBofWindow *g_hackWindow;
|
||||
|
||||
} // namespace SpaceBar
|
||||
} // namespace Bagel
|
||||
|
||||
#endif
|
||||
496
engines/bagel/spacebar/boflib/list.h
Normal file
496
engines/bagel/spacebar/boflib/list.h
Normal file
@@ -0,0 +1,496 @@
|
||||
|
||||
/* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BAGEL_BOFLIB_LIST_H
|
||||
#define BAGEL_BOFLIB_LIST_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "bagel/boflib/misc.h"
|
||||
|
||||
namespace Bagel {
|
||||
namespace SpaceBar {
|
||||
|
||||
#define MIN_NODES 5 // Minimum # of pre-allocated nodes in node array
|
||||
|
||||
template<class T>
|
||||
class CBofListNode {
|
||||
protected:
|
||||
T _cItem; // Data contained at this node
|
||||
|
||||
public:
|
||||
CBofListNode() {
|
||||
_pNext = _pPrev = nullptr;
|
||||
}
|
||||
CBofListNode(T cItem) {
|
||||
_pNext = _pPrev = nullptr;
|
||||
_cItem = cItem;
|
||||
}
|
||||
|
||||
T getNodeItem() {
|
||||
return _cItem;
|
||||
}
|
||||
void setNodeItem(T cItem) {
|
||||
_cItem = cItem;
|
||||
}
|
||||
|
||||
CBofListNode *_pNext; // Next node in list
|
||||
CBofListNode *_pPrev; // Previous node in list
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class CBofList {
|
||||
private:
|
||||
void newItemList() {
|
||||
if (_pItemList != nullptr) {
|
||||
bofFree(_pItemList);
|
||||
_pItemList = nullptr;
|
||||
}
|
||||
|
||||
if (_nNumItems != 0) {
|
||||
_pItemList = (void **)bofAlloc(_nNumItems * sizeof(void *));
|
||||
}
|
||||
}
|
||||
|
||||
void killItemList() {
|
||||
if (_pItemList != nullptr) {
|
||||
bofFree(_pItemList);
|
||||
_pItemList = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void recalcItemList() {
|
||||
// We only want to recalc if we're about to overflow what we have
|
||||
if (_nNumItems >= _nItemsAllocated) {
|
||||
if (_pItemList != nullptr) {
|
||||
bofFree(_pItemList);
|
||||
_pItemList = nullptr;
|
||||
}
|
||||
|
||||
if (_nNumItems != 0) {
|
||||
assert(_nItemsAllocated < 0x8000);
|
||||
_nItemsAllocated *= 2;
|
||||
if (_nItemsAllocated == 0)
|
||||
_nItemsAllocated = MIN_NODES;
|
||||
|
||||
_pItemList = (void **)bofAlloc(_nItemsAllocated * sizeof(void *));
|
||||
}
|
||||
}
|
||||
|
||||
if (_nNumItems != 0) {
|
||||
assert(_pItemList != nullptr);
|
||||
|
||||
int i = 0;
|
||||
CBofListNode<T> *pNode = _pHead;
|
||||
|
||||
while (pNode != nullptr) {
|
||||
*(_pItemList + i++) = pNode;
|
||||
pNode = pNode->_pNext;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates a new CBofListNode with specified data
|
||||
* @param cItem Data to store in new node
|
||||
* @returns Pointer to new node
|
||||
*/
|
||||
CBofListNode<T> *newNode(T cItem) {
|
||||
CBofListNode<T> *pNewNode = new CBofListNode<T>(cItem);
|
||||
return pNewNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the actual head of this linked list
|
||||
* @remarks This function is used for debugging to verify that _pHead
|
||||
* is still pointing to the 1st node in the list.
|
||||
* @returns Pointer to head of list
|
||||
*/
|
||||
CBofListNode<T> *getActualHead() {
|
||||
CBofListNode<T> *pNode;
|
||||
CBofListNode<T> *pLast = pNode = _pHead;
|
||||
|
||||
while (pNode != nullptr) {
|
||||
pLast = pNode;
|
||||
pNode = pNode->_pPrev;
|
||||
}
|
||||
|
||||
return pLast;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the actual tail of this linked list
|
||||
* @remarks This function is used for debugging to verify that _pTail
|
||||
* is still pointing to the last node in the list.
|
||||
* @returns Pointer to tail of list
|
||||
*/
|
||||
CBofListNode<T> *getActualTail() {
|
||||
CBofListNode<T> *pNode;
|
||||
CBofListNode<T> *pLast = pNode = _pTail;
|
||||
|
||||
while (pNode != nullptr) {
|
||||
pLast = pNode;
|
||||
pNode = pLast->_pNext;
|
||||
}
|
||||
|
||||
return pLast;
|
||||
}
|
||||
|
||||
protected:
|
||||
uint32 _nNumItems;
|
||||
uint32 _nItemsAllocated;
|
||||
CBofListNode<T> *_pHead; // pointer to head of list
|
||||
CBofListNode<T> *_pTail; // pointer to tail of list
|
||||
|
||||
void **_pItemList; // pointer to secondary node list
|
||||
|
||||
public:
|
||||
/*
|
||||
* Constructor
|
||||
*/
|
||||
CBofList() {
|
||||
_nNumItems = 0;
|
||||
_nItemsAllocated = 0;
|
||||
_pHead = _pTail = nullptr;
|
||||
_pItemList = nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~CBofList() {
|
||||
removeAll();
|
||||
killItemList();
|
||||
assert(_nNumItems == 0);
|
||||
}
|
||||
|
||||
int getCount() const {
|
||||
return _nNumItems;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the number of items in this list
|
||||
* @returns Returns the number of linked items in this linked list.
|
||||
*/
|
||||
int getActualCount() const {
|
||||
uint32 nCount = 0;
|
||||
CBofListNode<T> *pNode = _pHead;
|
||||
while (pNode != nullptr) {
|
||||
nCount++;
|
||||
pNode = pNode->_pNext;
|
||||
}
|
||||
|
||||
// There should be no discrepancy
|
||||
assert(_nNumItems == nCount);
|
||||
|
||||
return _nNumItems;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the list is empty
|
||||
* @return
|
||||
*/
|
||||
bool isEmpty() const {
|
||||
return _pHead == nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the item at the specified location
|
||||
* @returns Returns the item located at the node with given index.
|
||||
* @param nNodeIndex Index of node to retrieve
|
||||
*/
|
||||
inline T getNodeItem(int nNodeIndex) {
|
||||
CBofListNode<T> *pNode = getNode(nNodeIndex);
|
||||
|
||||
assert(pNode != nullptr);
|
||||
|
||||
return pNode->getNodeItem();
|
||||
}
|
||||
|
||||
void setNodeItem(int nNodeIndex, T tNewItem) {
|
||||
CBofListNode<T> *pNode = getNode(nNodeIndex);
|
||||
|
||||
assert(pNode != nullptr);
|
||||
|
||||
pNode->setNodeItem(tNewItem);
|
||||
}
|
||||
|
||||
T operator[](int nIndex) {
|
||||
return getNodeItem(nIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the node at the specified location
|
||||
* @returns Returns the node located at the given index.
|
||||
* @param nNodeIndex Index of node to retrieve
|
||||
*/
|
||||
CBofListNode<T> *getNode(int nNodeIndex) {
|
||||
assert(nNodeIndex >= 0 && nNodeIndex < getCount());
|
||||
|
||||
CBofListNode<T> *pNode;
|
||||
|
||||
if (_pItemList == nullptr) {
|
||||
|
||||
pNode = _pHead;
|
||||
while (pNode != nullptr) {
|
||||
if (nNodeIndex-- == 0)
|
||||
break;
|
||||
pNode = pNode->_pNext;
|
||||
}
|
||||
|
||||
} else {
|
||||
pNode = (CBofListNode<T> *)(*(_pItemList + nNodeIndex));
|
||||
}
|
||||
|
||||
return pNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a new node as the previous node to the one specified
|
||||
* @param nNodeIndex Index of node to insert before
|
||||
* @param cNewItem Data to store at new node
|
||||
*/
|
||||
void insertBefore(int nNodeIndex, T cNewItem) {
|
||||
assert(!isEmpty());
|
||||
insertBefore(getNode(nNodeIndex), cNewItem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a new node as the previous node to the one specified
|
||||
* @param pNode Node to insert before
|
||||
* @param cNewItem Data to store at new node
|
||||
*/
|
||||
void insertBefore(CBofListNode<T> *pNode, T cNewItem) {
|
||||
assert(pNode != nullptr);
|
||||
assert(!isEmpty());
|
||||
|
||||
if (pNode == _pHead) {
|
||||
addToHead(cNewItem);
|
||||
} else {
|
||||
|
||||
CBofListNode<T> *pNewNode = newNode(cNewItem);
|
||||
|
||||
pNewNode->_pPrev = pNode->_pPrev;
|
||||
pNewNode->_pNext = pNode;
|
||||
|
||||
if (pNode->_pPrev != nullptr)
|
||||
pNode->_pPrev->_pNext = pNewNode;
|
||||
|
||||
pNode->_pPrev = pNewNode;
|
||||
}
|
||||
|
||||
// one more item in list
|
||||
assert(_nNumItems != 0xFFFF);
|
||||
_nNumItems++;
|
||||
|
||||
recalcItemList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a new node as the next node to the one specified
|
||||
* @param nNodeIndex Index of node to insert after
|
||||
* @param cNewItem Data to store at new node
|
||||
*/
|
||||
void insertAfter(int nNodeIndex, T cNewItem) {
|
||||
assert(!isEmpty());
|
||||
insertAfter(getNode(nNodeIndex), cNewItem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a new node as the next node to the one specified
|
||||
* @param pNode Node to insert after
|
||||
* @param cNewItem Data to store at new node
|
||||
*/
|
||||
void insertAfter(CBofListNode<T> *pNode, T cNewItem) {
|
||||
assert(pNode != nullptr);
|
||||
assert(!isEmpty());
|
||||
|
||||
if (pNode == _pTail) {
|
||||
addToTail(cNewItem);
|
||||
} else {
|
||||
|
||||
CBofListNode<T> *pNewNode = newNode(cNewItem);
|
||||
pNewNode->_pPrev = pNode;
|
||||
pNewNode->_pNext = pNode->_pNext;
|
||||
|
||||
if (pNode->_pNext != nullptr)
|
||||
pNode->_pNext->_pPrev = pNewNode;
|
||||
|
||||
pNode->_pNext = pNewNode;
|
||||
}
|
||||
|
||||
// one more item in list
|
||||
assert(_nNumItems != 0xFFFF);
|
||||
_nNumItems++;
|
||||
|
||||
recalcItemList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes specified node from the list
|
||||
* @param pNode Node to remove
|
||||
* @returns Item stored at specified location
|
||||
*/
|
||||
T remove(CBofListNode<T> *pNode) {
|
||||
assert(pNode != nullptr);
|
||||
|
||||
// One less item in list
|
||||
_nNumItems--;
|
||||
|
||||
//assert(_nNumItems >= 0);
|
||||
|
||||
if (pNode != nullptr) {
|
||||
|
||||
T retVal = pNode->getNodeItem();
|
||||
|
||||
if (_pHead == pNode)
|
||||
_pHead = _pHead->_pNext;
|
||||
|
||||
if (_pTail == pNode)
|
||||
_pTail = _pTail->_pPrev;
|
||||
|
||||
if (pNode->_pPrev != nullptr)
|
||||
pNode->_pPrev->_pNext = pNode->_pNext;
|
||||
|
||||
if (pNode->_pNext != nullptr)
|
||||
pNode->_pNext->_pPrev = pNode->_pPrev;
|
||||
|
||||
delete pNode;
|
||||
|
||||
recalcItemList();
|
||||
return retVal;
|
||||
} else {
|
||||
return T();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes specified node (by index) from the list
|
||||
* @param nNodeIndex Index of node to remove
|
||||
* @returns Item stored at specified location
|
||||
*/
|
||||
T remove(int nNodeIndex) {
|
||||
return remove(getNode(nNodeIndex));
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all nodes from this list
|
||||
* @remarks Deletes all memory used by the nodes in this list
|
||||
*/
|
||||
void removeAll() {
|
||||
int i = getCount();
|
||||
|
||||
while (i-- != 0)
|
||||
remove(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes specified node (by index) from the list
|
||||
* @returns Item stored at specified location
|
||||
*/
|
||||
inline T removeHead() {
|
||||
assert(_pHead != nullptr);
|
||||
|
||||
return remove(_pHead);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes specified node (by index) from the list
|
||||
* @returns Item stored at specified location
|
||||
*/
|
||||
inline T removeTail() {
|
||||
assert(_pTail != nullptr);
|
||||
return remove(_pTail);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds specified node as the new head of this list
|
||||
* @param pNewNode Pointer to node to add to the list
|
||||
*/
|
||||
inline void addToHead(CBofListNode<T> *pNewNode) {
|
||||
assert(pNewNode != nullptr);
|
||||
|
||||
pNewNode->_pNext = _pHead;
|
||||
pNewNode->_pPrev = nullptr;
|
||||
if (_pHead != nullptr)
|
||||
_pHead->_pPrev = pNewNode;
|
||||
_pHead = pNewNode;
|
||||
|
||||
if (_pTail == nullptr)
|
||||
_pTail = _pHead;
|
||||
|
||||
// one less item in list
|
||||
assert(_nNumItems != 0xFFFF);
|
||||
_nNumItems++;
|
||||
|
||||
recalcItemList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds specified item as the new head of this list
|
||||
* @param cItem Item to add to the list
|
||||
*/
|
||||
inline void addToHead(T cItem) {
|
||||
addToHead(newNode(cItem));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds specified node as the new tail of this list
|
||||
* @param pNewNode Pointer to node to add to the list
|
||||
*/
|
||||
void addToTail(CBofListNode<T> *pNewNode) {
|
||||
assert(pNewNode != nullptr);
|
||||
|
||||
pNewNode->_pPrev = _pTail;
|
||||
pNewNode->_pNext = nullptr;
|
||||
if (_pTail != nullptr)
|
||||
_pTail->_pNext = pNewNode;
|
||||
_pTail = pNewNode;
|
||||
|
||||
if (_pHead == nullptr)
|
||||
_pHead = _pTail;
|
||||
|
||||
// One more item in list
|
||||
assert(_nNumItems != 0xFFFF);
|
||||
_nNumItems++;
|
||||
recalcItemList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds specified item as the new tail of this list
|
||||
* @param cItem Item to add to the list
|
||||
*/
|
||||
void addToTail(T cItem) {
|
||||
addToTail(newNode(cItem));
|
||||
}
|
||||
|
||||
CBofListNode<T> *getHead() const {
|
||||
return _pHead;
|
||||
}
|
||||
CBofListNode<T> *getTail() const {
|
||||
return _pTail;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace SpaceBar
|
||||
} // namespace Bagel
|
||||
|
||||
#endif
|
||||
361
engines/bagel/spacebar/boflib/options.cpp
Normal file
361
engines/bagel/spacebar/boflib/options.cpp
Normal file
@@ -0,0 +1,361 @@
|
||||
/* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/config-manager.h"
|
||||
#include "common/file.h"
|
||||
#include "bagel/spacebar/boflib/options.h"
|
||||
#include "bagel/boflib/misc.h"
|
||||
#include "bagel/boflib/log.h"
|
||||
#include "bagel/boflib/string_functions.h"
|
||||
|
||||
namespace Bagel {
|
||||
namespace SpaceBar {
|
||||
|
||||
COption::COption(const char *pszInit) {
|
||||
_szBuf[0] = '\0';
|
||||
|
||||
if (pszInit != nullptr) {
|
||||
assert(strlen(pszInit) < MAX_OPTION_LEN);
|
||||
Common::strcpy_s(_szBuf, pszInit);
|
||||
}
|
||||
}
|
||||
|
||||
CBofOptions::CBofOptions(const char *pszOptionFile) {
|
||||
_szFileName[0] = '\0';
|
||||
_pOptionList = nullptr;
|
||||
_bDirty = false;
|
||||
|
||||
if (pszOptionFile != nullptr) {
|
||||
loadOptionFile(pszOptionFile);
|
||||
}
|
||||
}
|
||||
|
||||
CBofOptions::~CBofOptions() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
release();
|
||||
|
||||
_szFileName[0] = '\0';
|
||||
}
|
||||
|
||||
ErrorCode CBofOptions::loadOptionFile(const char *pszOptionFile) {
|
||||
assert(isValidObject(this));
|
||||
assert(pszOptionFile != nullptr);
|
||||
assert(*pszOptionFile != '\0');
|
||||
assert(strlen(pszOptionFile) < MAX_FNAME);
|
||||
|
||||
release();
|
||||
|
||||
Common::strcpy_s(_szFileName, pszOptionFile);
|
||||
|
||||
return load();
|
||||
}
|
||||
|
||||
ErrorCode CBofOptions::load() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
// Assume no error
|
||||
ErrorCode errorCode = ERR_NONE;
|
||||
|
||||
// Free any previous option info
|
||||
release();
|
||||
|
||||
Common::File f;
|
||||
if (Common::File::exists(_szFileName) && f.open(_szFileName)) {
|
||||
char szBuf[MAX_OPTION_LEN];
|
||||
|
||||
assert(_pOptionList == nullptr);
|
||||
|
||||
while (readLine(&f, szBuf)) {
|
||||
COption *pNewOption = new COption(szBuf);
|
||||
if (_pOptionList != nullptr) {
|
||||
_pOptionList->addToTail(pNewOption);
|
||||
} else {
|
||||
_pOptionList = pNewOption;
|
||||
}
|
||||
}
|
||||
|
||||
if (_pOptionList != nullptr) {
|
||||
// _pOptionList must always be the head of the list!
|
||||
assert(_pOptionList == _pOptionList->getHead());
|
||||
}
|
||||
|
||||
f.close();
|
||||
|
||||
} else {
|
||||
errorCode = ERR_FOPEN;
|
||||
}
|
||||
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
void CBofOptions::release() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
commit();
|
||||
|
||||
// Release each item in the list
|
||||
while (_pOptionList != nullptr) {
|
||||
COption *pNextItem = (COption *)_pOptionList->getNext();
|
||||
|
||||
delete _pOptionList;
|
||||
_pOptionList = pNextItem;
|
||||
}
|
||||
}
|
||||
|
||||
ErrorCode CBofOptions::commit() {
|
||||
assert(isValidObject(this));
|
||||
ErrorCode errorCode = ERR_NONE;
|
||||
|
||||
if ((_pOptionList != nullptr) && _bDirty) {
|
||||
// _pOptionList must always be the head of the list!
|
||||
assert(_pOptionList == _pOptionList->getHead());
|
||||
|
||||
warning("TODO: Look into refactoring options to ConfMan if needed");
|
||||
}
|
||||
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
ErrorCode CBofOptions::writeSetting(const char *pszSection, const char *pszVar, const char *pszNewValue) {
|
||||
// Can't access nullptr pointers
|
||||
assert(pszSection != nullptr);
|
||||
assert(pszVar != nullptr);
|
||||
assert(pszNewValue != nullptr);
|
||||
|
||||
char szValueBuf[MAX_OPTION_LEN];
|
||||
|
||||
// Assume no error
|
||||
ErrorCode errorCode = ERR_NONE;
|
||||
|
||||
// Indicate that the options file needs to be updated
|
||||
_bDirty = true;
|
||||
|
||||
Common::sprintf_s(szValueBuf, "%s=%s", pszVar, pszNewValue);
|
||||
|
||||
// Find this option based on it's section
|
||||
COption *pOption = findOption(pszSection, pszVar);
|
||||
if (pOption != nullptr) {
|
||||
// Update option with new value
|
||||
Common::strcpy_s(pOption->_szBuf, szValueBuf);
|
||||
|
||||
} else {
|
||||
// Did not find option (or possibly also did not find section)
|
||||
|
||||
// If this section is not in the file
|
||||
COption *pSection = findSection(pszSection);
|
||||
if (pSection == nullptr) {
|
||||
char szSectionBuf[MAX_OPTION_LEN];
|
||||
// Then create a new section
|
||||
Common::sprintf_s(szSectionBuf, "[%s]", pszSection);
|
||||
|
||||
pSection = new COption(szSectionBuf);
|
||||
|
||||
if (_pOptionList != nullptr) {
|
||||
_pOptionList->addToTail(pSection);
|
||||
} else {
|
||||
_pOptionList = pSection;
|
||||
}
|
||||
}
|
||||
|
||||
// Add this option to the specified section
|
||||
pOption = new COption(szValueBuf);
|
||||
pSection->Insert(pOption);
|
||||
}
|
||||
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
ErrorCode CBofOptions::writeSetting(const char *pszSection, const char *pszVar, int nNewValue) {
|
||||
// Can't access nullptr pointers
|
||||
assert(pszSection != nullptr);
|
||||
assert(pszVar != nullptr);
|
||||
|
||||
char szBuf[20];
|
||||
|
||||
Common::sprintf_s(szBuf, "%d", nNewValue);
|
||||
ErrorCode errorCode = writeSetting(pszSection, pszVar, szBuf);
|
||||
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
ErrorCode CBofOptions::readSetting(const char *section, const char *option, char *stringValue, const char *defaultValue, uint32 maxLen) {
|
||||
// Can't access nullptr pointers
|
||||
assert(section != nullptr);
|
||||
assert(option != nullptr);
|
||||
assert(stringValue != nullptr);
|
||||
assert(defaultValue != nullptr);
|
||||
|
||||
// If ConfMan has a key of a given name, no matter the section,
|
||||
// than it takes precedence over any INI file value
|
||||
if (ConfMan.hasKey(option)) {
|
||||
Common::String str = ConfMan.get(option);
|
||||
Common::strcpy_s(stringValue, maxLen, str.c_str());
|
||||
return ERR_NONE;
|
||||
}
|
||||
|
||||
char szBuf[MAX_OPTION_LEN];
|
||||
|
||||
// Assume no error
|
||||
ErrorCode errorCode = ERR_NONE;
|
||||
|
||||
// Assume we will need to use the default setting
|
||||
Common::strcpy_s(stringValue, maxLen, defaultValue);
|
||||
|
||||
// Try to find this option
|
||||
COption *pOption = findOption(section, option);
|
||||
if (pOption != nullptr) {
|
||||
assert(strlen(pOption->_szBuf) < MAX_OPTION_LEN);
|
||||
|
||||
Common::strcpy_s(szBuf, pOption->_szBuf);
|
||||
|
||||
// Strip out any comments
|
||||
strreplaceChar(szBuf, ';', '\0');
|
||||
|
||||
// Find 1st equal sign
|
||||
char *p = strchr(szBuf, '=');
|
||||
|
||||
// Error in .INI file if we can't find the equal sign
|
||||
if (p != nullptr) {
|
||||
p++;
|
||||
|
||||
if (strlen(p) > 0)
|
||||
Common::strcpy_s(stringValue, maxLen, p);
|
||||
|
||||
} else {
|
||||
logError(buildString("Error in %s, section: %s, entry: %s", _szFileName, section, option));
|
||||
errorCode = ERR_FTYPE;
|
||||
}
|
||||
}
|
||||
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
ErrorCode CBofOptions::readSetting(const char *section, const char *option, int *intValue, int defaultValue) {
|
||||
assert(section != nullptr);
|
||||
assert(option != nullptr);
|
||||
assert(intValue != nullptr);
|
||||
|
||||
// If ConfMan has a key of a given name, no matter the section,
|
||||
// than it takes precedence over any INI file value
|
||||
if (ConfMan.hasKey(option)) {
|
||||
*intValue = ConfMan.getInt(option);
|
||||
return ERR_NONE;
|
||||
}
|
||||
|
||||
char szDefault[20], szBuf[20];
|
||||
|
||||
Common::sprintf_s(szDefault, "%d", defaultValue);
|
||||
ErrorCode errorCode = readSetting(section, option, szBuf, szDefault, 20);
|
||||
*intValue = atoi(szBuf);
|
||||
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
ErrorCode CBofOptions::readSetting(const char *section, const char *option, bool *boolValue, bool defaultValue) {
|
||||
assert(section != nullptr);
|
||||
assert(option != nullptr);
|
||||
assert(boolValue != nullptr);
|
||||
|
||||
// If ConfMan has a key of a given name, no matter the section,
|
||||
// than it takes precedence over any INI file value
|
||||
if (ConfMan.hasKey(option)) {
|
||||
*boolValue = ConfMan.getBool(option);
|
||||
return ERR_NONE;
|
||||
}
|
||||
|
||||
int v;
|
||||
ErrorCode errorCode = readSetting(section, option, &v, defaultValue);
|
||||
*boolValue = v != 0;
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
COption *CBofOptions::findSection(const char *pszSection) {
|
||||
assert(isValidObject(this));
|
||||
assert(pszSection != nullptr);
|
||||
assert(*pszSection != '\0');
|
||||
|
||||
char szSectionBuf[MAX_OPTION_LEN];
|
||||
|
||||
Common::sprintf_s(szSectionBuf, "[%s]", pszSection);
|
||||
int nLength = strlen(szSectionBuf);
|
||||
|
||||
COption *pOption = _pOptionList;
|
||||
while (pOption != nullptr) {
|
||||
if (!scumm_strnicmp(pOption->_szBuf, szSectionBuf, nLength)) {
|
||||
break;
|
||||
}
|
||||
|
||||
pOption = (COption *)pOption->getNext();
|
||||
}
|
||||
|
||||
return pOption;
|
||||
}
|
||||
|
||||
COption *CBofOptions::findOption(const char *pszSection, const char *pszVar) {
|
||||
assert(isValidObject(this));
|
||||
assert(pszSection != nullptr);
|
||||
assert(pszVar != nullptr);
|
||||
assert(*pszSection != '\0');
|
||||
assert(*pszVar != '\0');
|
||||
|
||||
// Assume we won't find the option
|
||||
COption *pFound = nullptr;
|
||||
|
||||
int nLength = strlen(pszVar);
|
||||
COption *pStart = findSection(pszSection);
|
||||
|
||||
if (pStart != nullptr) {
|
||||
COption *pOption = (COption *)pStart->getNext();
|
||||
while (pOption != nullptr) {
|
||||
if (pOption->_szBuf[0] == '[') {
|
||||
// this option was not found
|
||||
pFound = nullptr;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!scumm_strnicmp(pOption->_szBuf, pszVar, nLength)) {
|
||||
pFound = pOption;
|
||||
break;
|
||||
}
|
||||
|
||||
pOption = (COption *)pOption->getNext();
|
||||
}
|
||||
}
|
||||
|
||||
return pFound;
|
||||
}
|
||||
|
||||
bool CBofOptions::readLine(Common::SeekableReadStream *pFile, char *pszBuf) {
|
||||
assert(pFile != nullptr);
|
||||
assert(pszBuf != nullptr);
|
||||
|
||||
if (pFile->eos())
|
||||
return false;
|
||||
|
||||
Common::String line = pFile->readLine();
|
||||
Common::strcpy_s(pszBuf, 256, line.c_str());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace SpaceBar
|
||||
} // namespace Bagel
|
||||
169
engines/bagel/spacebar/boflib/options.h
Normal file
169
engines/bagel/spacebar/boflib/options.h
Normal file
@@ -0,0 +1,169 @@
|
||||
|
||||
/* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BAGEL_BOFLIB_OPTIONS_H
|
||||
#define BAGEL_BOFLIB_OPTIONS_H
|
||||
|
||||
#include "common/stream.h"
|
||||
|
||||
#include "bagel/boflib/stdinc.h"
|
||||
#include "bagel/boflib/llist.h"
|
||||
#include "bagel/boflib/object.h"
|
||||
#include "bagel/boflib/error.h"
|
||||
|
||||
namespace Bagel {
|
||||
namespace SpaceBar {
|
||||
|
||||
#define MAX_OPTION_LEN 100
|
||||
|
||||
class COption : public CLList, public CBofObject {
|
||||
public:
|
||||
COption(const char *pszInit = nullptr);
|
||||
|
||||
char _szBuf[MAX_OPTION_LEN];
|
||||
};
|
||||
|
||||
class CBofOptions : public CBofObject { // CCache
|
||||
private:
|
||||
/**
|
||||
* Finds the specified INI section in current file
|
||||
* @param pszSection INI section
|
||||
* @return Pointer to option where this section starts
|
||||
*/
|
||||
COption *findSection(const char *pszSection);
|
||||
|
||||
/**
|
||||
* Finds the variable (option) in specified section
|
||||
* @param pszSection INI section
|
||||
* @param pszVar Variable name for this option
|
||||
* @return Pointer to option containing this variable
|
||||
*/
|
||||
COption *findOption(const char *pszSection, const char *pszVar);
|
||||
|
||||
/**
|
||||
* Reads one line of text from specified file
|
||||
* @param pFile Pointer to open file for reading
|
||||
* @param pszBuf Buffer to fill with text read
|
||||
*/
|
||||
bool readLine(Common::SeekableReadStream *pFile, char *pszBuf);
|
||||
|
||||
protected:
|
||||
char _szFileName[MAX_FNAME];
|
||||
COption *_pOptionList;
|
||||
bool _bDirty;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
* @brief Loads specified .INI file which contains user options.
|
||||
* @param pszOptionsFile Name of .INI settings file
|
||||
**/
|
||||
CBofOptions(const char *pszOptionsFile = nullptr);
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~CBofOptions();
|
||||
|
||||
/**
|
||||
* Updates current option list file
|
||||
* @return Error return code
|
||||
*/
|
||||
ErrorCode commit();
|
||||
|
||||
/**
|
||||
* Loads specified .INI options file
|
||||
* @brief Loads and builds Option list
|
||||
* @param pszFile Name of .INI file to load
|
||||
* @return Error return code
|
||||
**/
|
||||
ErrorCode loadOptionFile(const char *pszFile);
|
||||
|
||||
const char *getFileName() const {
|
||||
return ((const char *)_szFileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds or modifies 1 option in list
|
||||
* @param pszSection Section in .INI file
|
||||
* @param pszOption Option to update
|
||||
* @param pszValue New value
|
||||
* @return Error return code
|
||||
*/
|
||||
ErrorCode writeSetting(const char *pszSection, const char *pszOption, const char *pszValue);
|
||||
|
||||
/**
|
||||
* Adds or modifies 1 option in list
|
||||
* @param pszSection Section in .INI file
|
||||
* @param pszOption Option to update
|
||||
* @param nValue New value
|
||||
* @return Error return code
|
||||
*/
|
||||
ErrorCode writeSetting(const char *pszSection, const char *pszOption, int nValue);
|
||||
|
||||
/**
|
||||
* Reads value for the specified option
|
||||
* @param section Section in .INI file
|
||||
* @param option Option to update
|
||||
* @param stringValue Destination buffer for read value
|
||||
* @param defaultValue Default value if not exists
|
||||
* @param nSize Max length of stringValue buffer
|
||||
* @return Error return code
|
||||
*/
|
||||
ErrorCode readSetting(const char *section, const char *option, char *stringValue, const char *defaultValue, uint32 nSize);
|
||||
|
||||
/**
|
||||
* Reads value for the specified option
|
||||
* @param section Section in .INI file
|
||||
* @param option Option to update
|
||||
* @param nValue Pointer to write value to
|
||||
* @param defaultValue Default value if not exists
|
||||
* @return Error return code
|
||||
*/
|
||||
ErrorCode readSetting(const char *section, const char *option, int *nValue, int defaultValue);
|
||||
|
||||
/**
|
||||
* Reads value for the specified option
|
||||
* @param section Section in .INI file
|
||||
* @param option Option to update
|
||||
* @param boolValue Pointer to write value to
|
||||
* @param defaultValue Default value if not exists
|
||||
* @return Error return code
|
||||
*/
|
||||
ErrorCode readSetting(const char *section, const char *option, bool *boolValue, bool defaultValue);
|
||||
|
||||
/**
|
||||
* Loads current .INI options file
|
||||
* @return Error return code
|
||||
*/
|
||||
ErrorCode load();
|
||||
|
||||
/**
|
||||
* Updates and Releases current option list
|
||||
*/
|
||||
void release();
|
||||
};
|
||||
|
||||
} // namespace SpaceBar
|
||||
} // namespace Bagel
|
||||
|
||||
#endif
|
||||
163
engines/bagel/spacebar/boflib/res.cpp
Normal file
163
engines/bagel/spacebar/boflib/res.cpp
Normal file
@@ -0,0 +1,163 @@
|
||||
/* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "bagel/spacebar/boflib/res.h"
|
||||
#include "bagel/spacebar/boflib/debug.h"
|
||||
#include "bagel/boflib/misc.h"
|
||||
#include "bagel/boflib/string_functions.h"
|
||||
#include "bagel/boflib/log.h"
|
||||
|
||||
namespace Bagel {
|
||||
namespace SpaceBar {
|
||||
|
||||
CBofStringTable::CBofStringTable(const char *pszFileName) : CBofFile(nullptr) {
|
||||
assert(pszFileName != nullptr);
|
||||
|
||||
load(pszFileName);
|
||||
}
|
||||
|
||||
CBofStringTable::~CBofStringTable() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
release();
|
||||
}
|
||||
|
||||
ErrorCode CBofStringTable::load(const char *pszFileName) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
// Deallocate any previous data
|
||||
release();
|
||||
|
||||
// Open this string file
|
||||
open(pszFileName);
|
||||
|
||||
_lBufSize = getLength();
|
||||
|
||||
assert(_lBufSize > 0);
|
||||
|
||||
// Allocate a buffer to hold entire file and fill it with 0s
|
||||
_pBuf = (byte *)bofCleanAlloc(_lBufSize + 1);
|
||||
|
||||
// Read in entire file
|
||||
read(_pBuf, _lBufSize);
|
||||
buildTable();
|
||||
|
||||
// Don't need this file open anymore
|
||||
close();
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
void CBofStringTable::release() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
killTable();
|
||||
|
||||
if (_pBuf != nullptr) {
|
||||
bofFree(_pBuf);
|
||||
_pBuf = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void CBofStringTable::killTable() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
CResString *pString = _pStringTable;
|
||||
while (pString != nullptr) {
|
||||
CResString *pNextString = (CResString *)pString->getNext();
|
||||
delete pString;
|
||||
|
||||
pString = pNextString;
|
||||
}
|
||||
|
||||
_pStringTable = nullptr;
|
||||
}
|
||||
|
||||
ErrorCode CBofStringTable::buildTable() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
// Deallocate any previous table
|
||||
killTable();
|
||||
|
||||
assert(_pStringTable == nullptr);
|
||||
assert(_pBuf != nullptr);
|
||||
|
||||
memreplaceChar(_pBuf, '\r', '\0', _lBufSize);
|
||||
memreplaceChar(_pBuf, '\n', '\0', _lBufSize);
|
||||
const byte *pBuf = _pBuf;
|
||||
|
||||
while (pBuf < _pBuf + _lBufSize) {
|
||||
int nId = atoi((const char *)pBuf);
|
||||
pBuf = (const byte *)strchr((const char *)pBuf, '=');
|
||||
if (pBuf == nullptr) {
|
||||
reportError(ERR_NONE, "Parsing error in buildTable()");
|
||||
break;
|
||||
}
|
||||
pBuf++;
|
||||
|
||||
CResString *pString = new CResString(nId, (const char *)pBuf);
|
||||
|
||||
// Add this string to the table
|
||||
if (_pStringTable == nullptr) {
|
||||
_pStringTable = pString;
|
||||
} else {
|
||||
_pStringTable->addToTail(pString);
|
||||
}
|
||||
|
||||
while (*pBuf++ != '\0') {
|
||||
if (pBuf > _pBuf + _lBufSize)
|
||||
break;
|
||||
}
|
||||
|
||||
while (*pBuf == '\0') {
|
||||
pBuf++;
|
||||
if (pBuf > _pBuf + _lBufSize)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return _errCode;
|
||||
}
|
||||
|
||||
const char *CBofStringTable::getString(int nId) {
|
||||
assert(isValidObject(this));
|
||||
|
||||
CResString *pCurString = _pStringTable;
|
||||
const char *pszString = nullptr;
|
||||
|
||||
while (pCurString != nullptr) {
|
||||
if (pCurString->_nId == nId) {
|
||||
pszString = (const char *)pCurString->_pszString;
|
||||
break;
|
||||
}
|
||||
|
||||
pCurString = (CResString *)pCurString->getNext();
|
||||
}
|
||||
|
||||
if (pCurString == nullptr) {
|
||||
logWarning(buildString("Resource String %d not found in %s", nId, _szFileName));
|
||||
}
|
||||
|
||||
return pszString;
|
||||
}
|
||||
|
||||
} // namespace SpaceBar
|
||||
} // namespace Bagel
|
||||
96
engines/bagel/spacebar/boflib/res.h
Normal file
96
engines/bagel/spacebar/boflib/res.h
Normal file
@@ -0,0 +1,96 @@
|
||||
|
||||
/* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BAGEL_BOFLIB_RES_H
|
||||
#define BAGEL_BOFLIB_RES_H
|
||||
|
||||
#include "bagel/spacebar/boflib/file.h"
|
||||
#include "bagel/boflib/llist.h"
|
||||
#include "bagel/boflib/object.h"
|
||||
|
||||
namespace Bagel {
|
||||
namespace SpaceBar {
|
||||
|
||||
class CResString : public CLList, public CBofObject {
|
||||
public:
|
||||
CResString(int nId, const char *pszString) {
|
||||
_nId = nId;
|
||||
_pszString = pszString;
|
||||
}
|
||||
|
||||
int _nId;
|
||||
const char *_pszString;
|
||||
};
|
||||
|
||||
class CBofStringTable : public CBofFile {
|
||||
private:
|
||||
CResString *_pStringTable = nullptr;
|
||||
byte *_pBuf = nullptr;
|
||||
uint32 _lBufSize = 0;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Loads string table from specified res file
|
||||
* @param pszFileName Name of file containing resources
|
||||
* @return Error return code
|
||||
*/
|
||||
ErrorCode load(const char *pszFileName);
|
||||
|
||||
/**
|
||||
* De-allocates the current Resource String Table
|
||||
*/
|
||||
void release();
|
||||
|
||||
/**
|
||||
* Allocates the current Resource String Table
|
||||
* @return Error return code
|
||||
*/
|
||||
ErrorCode buildTable();
|
||||
|
||||
/**
|
||||
* De-allocates the current Resource String Table
|
||||
*/
|
||||
void killTable();
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor for Boffo Resource String Table
|
||||
* @param pszFileName Name of file containing resources
|
||||
**/
|
||||
CBofStringTable(const char *pszFileName);
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~CBofStringTable();
|
||||
|
||||
/**
|
||||
* Retrieves the specified resource string
|
||||
* @param nId Res ID for string to be retrieved
|
||||
*/
|
||||
const char *getString(int nId);
|
||||
};
|
||||
|
||||
} // namespace SpaceBar
|
||||
} // namespace Bagel
|
||||
|
||||
#endif
|
||||
167
engines/bagel/spacebar/boflib/std_keys.h
Normal file
167
engines/bagel/spacebar/boflib/std_keys.h
Normal file
@@ -0,0 +1,167 @@
|
||||
|
||||
/* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BAGEL_BOFLIB_STD_KEYS_H
|
||||
#define BAGEL_BOFLIB_STD_KEYS_H
|
||||
|
||||
#include "bagel/boflib/stdinc.h"
|
||||
|
||||
namespace Bagel {
|
||||
namespace SpaceBar {
|
||||
|
||||
// Boffo Key defs
|
||||
//
|
||||
#define BKEY_UNKNOWN 0x00000000
|
||||
|
||||
#define BKF_ALT 0x10000000
|
||||
#define BKF_CMD 0x10000000 // Mac's Flower/Clover/Command key
|
||||
|
||||
#define BKF_CTRL 0x20000000
|
||||
#define BKF_SHIFT 0x40000000
|
||||
|
||||
#define BKEY_0 '0'
|
||||
#define BKEY_1 '1'
|
||||
#define BKEY_2 '2'
|
||||
#define BKEY_3 '3'
|
||||
#define BKEY_4 '4'
|
||||
#define BKEY_5 '5'
|
||||
#define BKEY_6 '6'
|
||||
#define BKEY_7 '7'
|
||||
#define BKEY_8 '8'
|
||||
#define BKEY_9 '9'
|
||||
|
||||
#define BKEY_a (uint32)'a'
|
||||
#define BKEY_b (uint32)'b'
|
||||
#define BKEY_c (uint32)'c'
|
||||
#define BKEY_d (uint32)'d'
|
||||
#define BKEY_e (uint32)'e'
|
||||
#define BKEY_f (uint32)'f'
|
||||
#define BKEY_g (uint32)'g'
|
||||
#define BKEY_h (uint32)'h'
|
||||
#define BKEY_i (uint32)'i'
|
||||
#define BKEY_j (uint32)'j'
|
||||
#define BKEY_k (uint32)'k'
|
||||
#define BKEY_l (uint32)'l'
|
||||
#define BKEY_m (uint32)'m'
|
||||
#define BKEY_n (uint32)'n'
|
||||
#define BKEY_o (uint32)'o'
|
||||
#define BKEY_p (uint32)'p'
|
||||
#define BKEY_q (uint32)'q'
|
||||
#define BKEY_r (uint32)'r'
|
||||
#define BKEY_s (uint32)'s'
|
||||
#define BKEY_t (uint32)'t'
|
||||
#define BKEY_u (uint32)'u'
|
||||
#define BKEY_v (uint32)'v'
|
||||
#define BKEY_w (uint32)'w'
|
||||
#define BKEY_x (uint32)'x'
|
||||
#define BKEY_y (uint32)'y'
|
||||
#define BKEY_z (uint32)'z'
|
||||
|
||||
#define BKEY_PLUS (uint32)'+'
|
||||
#define BKEY_MINUS (uint32)'-'
|
||||
#define BKEY_PERIOD (uint32)'.'
|
||||
|
||||
#define BKEY_ALT_a (BKEY_a | BKF_ALT)
|
||||
#define BKEY_ALT_b (BKEY_b | BKF_ALT)
|
||||
#define BKEY_ALT_c (BKEY_c | BKF_ALT)
|
||||
#define BKEY_ALT_d (BKEY_d | BKF_ALT)
|
||||
#define BKEY_ALT_e (BKEY_e | BKF_ALT)
|
||||
#define BKEY_ALT_f (BKEY_f | BKF_ALT)
|
||||
#define BKEY_ALT_g (BKEY_g | BKF_ALT)
|
||||
#define BKEY_ALT_h (BKEY_h | BKF_ALT)
|
||||
#define BKEY_ALT_i (BKEY_i | BKF_ALT)
|
||||
#define BKEY_ALT_j (BKEY_j | BKF_ALT)
|
||||
#define BKEY_ALT_k (BKEY_k | BKF_ALT)
|
||||
#define BKEY_ALT_l (BKEY_l | BKF_ALT)
|
||||
#define BKEY_ALT_m (BKEY_m | BKF_ALT)
|
||||
#define BKEY_ALT_n (BKEY_n | BKF_ALT)
|
||||
#define BKEY_ALT_o (BKEY_o | BKF_ALT)
|
||||
#define BKEY_ALT_p (BKEY_p | BKF_ALT)
|
||||
#define BKEY_ALT_q (BKEY_q | BKF_ALT)
|
||||
#define BKEY_ALT_r (BKEY_r | BKF_ALT)
|
||||
#define BKEY_ALT_s (BKEY_s | BKF_ALT)
|
||||
#define BKEY_ALT_t (BKEY_t | BKF_ALT)
|
||||
#define BKEY_ALT_u (BKEY_u | BKF_ALT)
|
||||
#define BKEY_ALT_v (BKEY_v | BKF_ALT)
|
||||
#define BKEY_ALT_w (BKEY_w | BKF_ALT)
|
||||
#define BKEY_ALT_x (BKEY_x | BKF_ALT)
|
||||
#define BKEY_ALT_y (BKEY_y | BKF_ALT)
|
||||
#define BKEY_ALT_z (BKEY_z | BKF_ALT)
|
||||
|
||||
#define BKEY_BASE 0x00000100
|
||||
#define BKEY_F1 (BKEY_BASE + 1)
|
||||
#define BKEY_F2 (BKEY_BASE + 2)
|
||||
#define BKEY_F3 (BKEY_BASE + 3)
|
||||
#define BKEY_F4 (BKEY_BASE + 4)
|
||||
#define BKEY_SAVE (BKEY_BASE + 5)
|
||||
#define BKEY_F6 (BKEY_BASE + 6)
|
||||
#define BKEY_RESTORE (BKEY_BASE + 7)
|
||||
#define BKEY_F8 (BKEY_BASE + 8)
|
||||
#define BKEY_F9 (BKEY_BASE + 9)
|
||||
#define BKEY_F10 (BKEY_BASE + 10)
|
||||
#define BKEY_F11 (BKEY_BASE + 11)
|
||||
#define BKEY_F12 (BKEY_BASE + 12)
|
||||
|
||||
#define BKEY_ALT_F1 (BKEY_F1 | BKF_ALT)
|
||||
#define BKEY_ALT_F2 (BKEY_F2 | BKF_ALT)
|
||||
#define BKEY_ALT_F3 (BKEY_F3 | BKF_ALT)
|
||||
#define BKEY_ALT_F4 (BKEY_F4 | BKF_ALT)
|
||||
#define BKEY_ALT_F5 (BKEY_F5 | BKF_ALT)
|
||||
#define BKEY_ALT_F6 (BKEY_F6 | BKF_ALT)
|
||||
#define BKEY_ALT_F7 (BKEY_F7 | BKF_ALT)
|
||||
#define BKEY_ALT_F8 (BKEY_F8 | BKF_ALT)
|
||||
#define BKEY_ALT_F9 (BKEY_F9 | BKF_ALT)
|
||||
#define BKEY_ALT_F10 (BKEY_F10 | BKF_ALT)
|
||||
#define BKEY_ALT_F11 (BKEY_F11 | BKF_ALT)
|
||||
#define BKEY_ALT_F12 (BKEY_F12 | BKF_ALT)
|
||||
|
||||
#define BKEY_ESC (uint32)0x1B
|
||||
#define BKEY_BACK (uint32)0x08
|
||||
#define BKEY_ENTER (uint32)0x0D
|
||||
#define BKEY_SPACE (uint32)' '
|
||||
#define BKEY_PERIOD (uint32)'.'
|
||||
|
||||
#define BKEY_END (BKEY_BASE + 14)
|
||||
#define BKEY_HOME (BKEY_BASE + 15)
|
||||
#define BKEY_LEFT (BKEY_BASE + 16)
|
||||
#define BKEY_RIGHT (BKEY_BASE + 17)
|
||||
#define BKEY_UP (BKEY_BASE + 18)
|
||||
#define BKEY_DOWN (BKEY_BASE + 19)
|
||||
#define BKEY_INS (BKEY_BASE + 20)
|
||||
#define BKEY_DEL (BKEY_BASE + 21)
|
||||
|
||||
#define BKEY_ALT_UP (BKEY_UP | BKF_ALT)
|
||||
#define BKEY_ALT_DOWN (BKEY_DOWN | BKF_ALT)
|
||||
|
||||
#define BKEY_PAGEUP (BKEY_BASE + 22)
|
||||
#define BKEY_PAGEDOWN (BKEY_BASE + 23)
|
||||
|
||||
#define BKEY_SCRL_LOCK (BKEY_BASE + 24)
|
||||
|
||||
#define BKEY_SHIFT BKF_SHIFT
|
||||
#define BKEY_CTRL BKF_CTRL
|
||||
#define BKEY_ALT BKF_ALT
|
||||
|
||||
} // namespace SpaceBar
|
||||
} // namespace Bagel
|
||||
|
||||
#endif
|
||||
126
engines/bagel/spacebar/boflib/timer.cpp
Normal file
126
engines/bagel/spacebar/boflib/timer.cpp
Normal file
@@ -0,0 +1,126 @@
|
||||
|
||||
/* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/system.h"
|
||||
#include "bagel/spacebar/boflib/timer.h"
|
||||
#include "bagel/bagel.h"
|
||||
#include "bagel/boflib/log.h"
|
||||
|
||||
namespace Bagel {
|
||||
namespace SpaceBar {
|
||||
|
||||
bool CBofTimer::_bModified = false;
|
||||
CBofTimer *CBofTimer::_pTimerList = nullptr;
|
||||
|
||||
WindowTimer::WindowTimer(uint32 interval, uint32 id, BofCallback callback) :
|
||||
_interval(interval), _id(id), _callback(callback) {
|
||||
_lastExpiryTime = g_system->getMillis();
|
||||
}
|
||||
|
||||
|
||||
CBofTimer::CBofTimer() {
|
||||
_lLastTime = 0;
|
||||
_nID = 0;
|
||||
_nInterval = 0;
|
||||
_pCallBack = nullptr;
|
||||
_lUserInfo = 0;
|
||||
_bActive = false;
|
||||
|
||||
// Another item for the list
|
||||
if (_pTimerList == nullptr) {
|
||||
_pTimerList = this;
|
||||
|
||||
} else {
|
||||
_pTimerList->addToTail(this);
|
||||
}
|
||||
|
||||
// Creating a new timer object modifies the timer list
|
||||
_bModified = true;
|
||||
}
|
||||
|
||||
|
||||
CBofTimer::CBofTimer(uint32 nID, uint32 nInterval, void *lUserInfo, BofCallback pCallBack) {
|
||||
_lLastTime = 0;
|
||||
_nID = nID;
|
||||
_nInterval = nInterval;
|
||||
_pCallBack = pCallBack;
|
||||
_lUserInfo = lUserInfo;
|
||||
_bActive = false;
|
||||
|
||||
// Another item for the list
|
||||
if (_pTimerList == nullptr) {
|
||||
_pTimerList = this;
|
||||
|
||||
} else {
|
||||
_pTimerList->addToTail(this);
|
||||
}
|
||||
|
||||
// Creating a new timer object modifies the timer list
|
||||
_bModified = true;
|
||||
}
|
||||
|
||||
|
||||
CBofTimer::~CBofTimer() {
|
||||
assert(isValidObject(this));
|
||||
|
||||
if (_pTimerList == this) {
|
||||
_pTimerList = (CBofTimer *)_pTimerList->getNext();
|
||||
}
|
||||
|
||||
// Removing a timer object modifies the timer list
|
||||
_bModified = true;
|
||||
}
|
||||
|
||||
|
||||
void CBofTimer::handleTimers() {
|
||||
CBofTimer *pTimer = _pTimerList;
|
||||
while (pTimer != nullptr) {
|
||||
if (pTimer->isActive()) {
|
||||
uint32 lCurrentTime = g_system->getMillis();
|
||||
|
||||
if ((uint32)(lCurrentTime - pTimer->_lLastTime) >= pTimer->_nInterval) {
|
||||
// Remember for next time
|
||||
pTimer->_lLastTime = lCurrentTime;
|
||||
|
||||
if (pTimer->_pCallBack != nullptr) {
|
||||
// Execute call back
|
||||
(*pTimer->_pCallBack)(pTimer->_nID, pTimer->_lUserInfo);
|
||||
|
||||
// If callback modifies the timer list, then we must start over
|
||||
if (_bModified) {
|
||||
pTimer = _pTimerList;
|
||||
continue;
|
||||
}
|
||||
|
||||
} else {
|
||||
// Otherwise, something is wrong
|
||||
logWarning(buildString("Timer without a callback: %d", pTimer->_nID));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pTimer = (CBofTimer *)pTimer->getNext();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace SpaceBar
|
||||
} // namespace Bagel
|
||||
112
engines/bagel/spacebar/boflib/timer.h
Normal file
112
engines/bagel/spacebar/boflib/timer.h
Normal file
@@ -0,0 +1,112 @@
|
||||
/* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/".
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BAGEL_BOFLIB_TIMER_H
|
||||
#define BAGEL_BOFLIB_TIMER_H
|
||||
|
||||
#include "bagel/spacebar/boflib/timer.h"
|
||||
#include "bagel/boflib/llist.h"
|
||||
#include "bagel/boflib/palette.h"
|
||||
|
||||
namespace Bagel {
|
||||
namespace SpaceBar {
|
||||
|
||||
struct WindowTimer {
|
||||
uint32 _interval = 0;
|
||||
uint32 _lastExpiryTime = 0;
|
||||
uint32 _id = 0;
|
||||
BofCallback _callback = nullptr;
|
||||
|
||||
WindowTimer() { }
|
||||
WindowTimer(uint32 interval, uint32 id, BofCallback callback);
|
||||
};
|
||||
|
||||
|
||||
class CBofTimer: public CBofObject, public CLList {
|
||||
public:
|
||||
CBofTimer();
|
||||
CBofTimer(uint32 nID, uint32 nInterval, void *lUserInfo, BofCallback pCallBack);
|
||||
~CBofTimer();
|
||||
|
||||
void start() {
|
||||
_bActive = true;
|
||||
}
|
||||
void stop() {
|
||||
_bActive = false;
|
||||
}
|
||||
|
||||
bool isActive() {
|
||||
return _bActive;
|
||||
}
|
||||
|
||||
void setID(uint32 nID) {
|
||||
_nID = nID;
|
||||
}
|
||||
uint32 getID() {
|
||||
return _nID;
|
||||
}
|
||||
|
||||
void setInterval(uint32 nInterval) {
|
||||
_nInterval = nInterval;
|
||||
}
|
||||
uint32 getInterval() {
|
||||
return _nInterval;
|
||||
}
|
||||
|
||||
void setUserInfo(void *lUserInfo) {
|
||||
_lUserInfo = lUserInfo;
|
||||
}
|
||||
void *getUserInfo() {
|
||||
return _lUserInfo;
|
||||
}
|
||||
|
||||
void setCallBack(BofCallback pCallBack) {
|
||||
_pCallBack = pCallBack;
|
||||
}
|
||||
BofCallback getCallBack() {
|
||||
return _pCallBack;
|
||||
}
|
||||
|
||||
static void handleTimers();
|
||||
|
||||
//
|
||||
// members
|
||||
//
|
||||
|
||||
protected:
|
||||
|
||||
static CBofTimer *_pTimerList;
|
||||
static bool _bModified;
|
||||
|
||||
public:
|
||||
|
||||
uint32 _lLastTime;
|
||||
uint32 _nID;
|
||||
uint32 _nInterval;
|
||||
BofCallback _pCallBack;
|
||||
void *_lUserInfo;
|
||||
bool _bActive;
|
||||
};
|
||||
|
||||
} // namespace SpaceBar
|
||||
} // namespace Bagel
|
||||
|
||||
#endif
|
||||
230
engines/bagel/spacebar/boflib/vector.cpp
Normal file
230
engines/bagel/spacebar/boflib/vector.cpp
Normal file
@@ -0,0 +1,230 @@
|
||||
/* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "bagel/spacebar/boflib/vector.h"
|
||||
|
||||
namespace Bagel {
|
||||
namespace SpaceBar {
|
||||
|
||||
CVector::CVector() {
|
||||
this->x = 0;
|
||||
this->y = 0;
|
||||
this->z = 0;
|
||||
}
|
||||
|
||||
CVector::CVector(const Vector &stVector) {
|
||||
x = stVector.x;
|
||||
y = stVector.y;
|
||||
z = stVector.z;
|
||||
}
|
||||
|
||||
CVector::CVector(double xx, double yy, double zz) {
|
||||
x = xx;
|
||||
y = yy;
|
||||
z = zz;
|
||||
}
|
||||
|
||||
double CVector::length() {
|
||||
// Make sure this object is not used after it is destructed
|
||||
assert(isValidObject(this));
|
||||
|
||||
return sqrt(x * x + y * y);
|
||||
}
|
||||
|
||||
double CVector::angleBetween(const Vector &vector) {
|
||||
// Make sure this object is not used after it is destructed
|
||||
assert(isValidObject(this));
|
||||
|
||||
CVector vTmp(vector);
|
||||
|
||||
// Get the angle by getting the arc-cosine of the cosine of the
|
||||
// angle between the 2 vectors.
|
||||
double fCos = this->dotProduct(vTmp) / (this->length() * vTmp.length());
|
||||
|
||||
if (fCos > 1.0) {
|
||||
fCos = 1.0;
|
||||
} else if (fCos < -1.0) {
|
||||
fCos = -1.0;
|
||||
}
|
||||
|
||||
double angle = acos(fCos);
|
||||
return angle;
|
||||
}
|
||||
|
||||
double CVector::dotProduct(const Vector &vector) {
|
||||
// Make sure this object is not used after it is destructed
|
||||
assert(isValidObject(this));
|
||||
|
||||
return (this->x * vector.x) + (this->y * vector.y);
|
||||
}
|
||||
|
||||
void CVector::rotate(double angle) {
|
||||
// Make sure this object is not used after it is destructed
|
||||
assert(isValidObject(this));
|
||||
|
||||
// Get the sine and cosine of the angle
|
||||
double co = cos(angle);
|
||||
double si = sin(angle);
|
||||
|
||||
double xx = this->x * co - this->y * si;
|
||||
double yy = this->y * co + this->x * si;
|
||||
|
||||
this->x = xx;
|
||||
this->y = yy;
|
||||
}
|
||||
|
||||
double CVector::realAngle(const Vector &vector) {
|
||||
// Make sure this object is not used after it is destructed
|
||||
assert(isValidObject(this));
|
||||
|
||||
CVector vTmp = *this;
|
||||
double angle = vTmp.angleBetween(vector);
|
||||
|
||||
if (angle != (double)0.0) {
|
||||
vTmp.rotate(angle);
|
||||
|
||||
// Determine if the angle is greater then 180 degrees
|
||||
if (((int)(vTmp.angleBetween(vector) * 1000) == 0)) {
|
||||
angle = 2 * PI - angle;
|
||||
}
|
||||
}
|
||||
|
||||
return angle;
|
||||
}
|
||||
|
||||
CVector CVector::operator+(Vector vector) {
|
||||
// Make sure this object is not used after it is destructed
|
||||
assert(isValidObject(this));
|
||||
|
||||
CVector vSum(this->x + vector.x, this->y + vector.y, this->z + vector.z);
|
||||
|
||||
return vSum;
|
||||
}
|
||||
|
||||
CVector CVector::operator+(double offset) {
|
||||
// Make sure this object is not used after it is destructed
|
||||
assert(isValidObject(this));
|
||||
|
||||
CVector vSum(this->x + offset, this->y + offset, this->z + offset);
|
||||
|
||||
return vSum;
|
||||
}
|
||||
|
||||
CVector CVector::operator-(Vector vector) {
|
||||
// Make sure this object is not used after it is destructed
|
||||
assert(isValidObject(this));
|
||||
|
||||
CVector vDif(this->x - vector.x, this->y - vector.y, this->z - vector.z);
|
||||
|
||||
return vDif;
|
||||
}
|
||||
|
||||
CVector CVector::operator-(double offset) {
|
||||
// Make sure this object is not used after it is destructed
|
||||
assert(isValidObject(this));
|
||||
|
||||
CVector vDif(this->x - offset, this->y - offset, this->z - offset);
|
||||
|
||||
return vDif;
|
||||
}
|
||||
|
||||
void CVector::operator+=(Vector vector) {
|
||||
// Make sure this object is not used after it is destructed
|
||||
assert(isValidObject(this));
|
||||
|
||||
this->x += vector.x;
|
||||
this->y += vector.y;
|
||||
this->z += vector.z;
|
||||
}
|
||||
|
||||
void CVector::operator-=(Vector vector) {
|
||||
// Make sure this object is not used after it is destructed
|
||||
assert(isValidObject(this));
|
||||
|
||||
this->x -= vector.x;
|
||||
this->y -= vector.y;
|
||||
this->z -= vector.z;
|
||||
}
|
||||
|
||||
CVector CVector::operator*(double scalar) {
|
||||
// Make sure this object is not used after it is destructed
|
||||
assert(isValidObject(this));
|
||||
|
||||
CVector vProduct(this->x * scalar, this->y * scalar, this->z * scalar);
|
||||
|
||||
return vProduct;
|
||||
}
|
||||
|
||||
CVector CVector::operator/(double scalar) {
|
||||
// Make sure this object is not used after it is destructed
|
||||
assert(isValidObject(this));
|
||||
|
||||
// Can't divide by 0
|
||||
assert(scalar != (double)0.0);
|
||||
|
||||
CVector vDividend;
|
||||
|
||||
if (scalar != (double)0.0) {
|
||||
vDividend.x = this->x / scalar;
|
||||
vDividend.y = this->y / scalar;
|
||||
vDividend.z = this->z / scalar;
|
||||
}
|
||||
|
||||
return vDividend;
|
||||
}
|
||||
|
||||
void CVector::operator*=(double scalar) {
|
||||
// Make sure this object is not used after it is destructed
|
||||
assert(isValidObject(this));
|
||||
|
||||
this->x *= scalar;
|
||||
this->y *= scalar;
|
||||
this->z *= scalar;
|
||||
}
|
||||
|
||||
void CVector::operator/=(double scalar) {
|
||||
// Make sure this object is not used after it is destructed
|
||||
assert(isValidObject(this));
|
||||
|
||||
// can't divide by 0
|
||||
assert(scalar != (double)0.0);
|
||||
|
||||
if (scalar != (double)0.0) {
|
||||
this->x /= scalar;
|
||||
this->y /= scalar;
|
||||
this->z /= scalar;
|
||||
}
|
||||
}
|
||||
|
||||
bool CVector::operator==(Vector v) {
|
||||
// Make sure this object is not used after it is destructed
|
||||
assert(isValidObject(this));
|
||||
|
||||
bool bReturn = false;
|
||||
|
||||
if ((this->x == v.x) && (this->y == v.y))
|
||||
bReturn = true;
|
||||
|
||||
return bReturn;
|
||||
}
|
||||
|
||||
} // namespace SpaceBar
|
||||
} // namespace Bagel
|
||||
105
engines/bagel/spacebar/boflib/vector.h
Normal file
105
engines/bagel/spacebar/boflib/vector.h
Normal file
@@ -0,0 +1,105 @@
|
||||
|
||||
/* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BAGEL_BOFLIB_VECTOR_H
|
||||
#define BAGEL_BOFLIB_VECTOR_H
|
||||
|
||||
#include "bagel/boflib/stdinc.h"
|
||||
#include "bagel/boflib/object.h"
|
||||
|
||||
namespace Bagel {
|
||||
namespace SpaceBar {
|
||||
|
||||
#define PI (double)3.141592653
|
||||
#define RADCNVT ((double)180 / PI) // PI is 180 degrees
|
||||
|
||||
#define Deg2Rad(d) ((d) / RADCNVT) // Converts degrees to radians
|
||||
#define Rad2Deg(r) ((r) * RADCNVT) // Converts radians to degrees
|
||||
|
||||
class CVector : public CBofObject, public Vector {
|
||||
public:
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
CVector();
|
||||
|
||||
/**
|
||||
* Copy constructor
|
||||
*/
|
||||
CVector(const Vector &stVector);
|
||||
|
||||
/**
|
||||
* Constructor based on passed figures
|
||||
*/
|
||||
CVector(double xx, double yy, double zz = 0);
|
||||
|
||||
/**
|
||||
* Calculates the dot-product of the 2 specified vectors
|
||||
* @param vector Second vector
|
||||
* @return Dot-product
|
||||
*/
|
||||
double dotProduct(const Vector &vector);
|
||||
|
||||
/**
|
||||
* Rotates this vector the specified number of degrees
|
||||
* @param fAngle Rotation angle
|
||||
*/
|
||||
void rotate(double fAngle);
|
||||
|
||||
/**
|
||||
* Gets the angle between this vector and specified vector
|
||||
* @param vector Second vector
|
||||
* @return Angle
|
||||
*/
|
||||
double angleBetween(const Vector &vector);
|
||||
|
||||
/**
|
||||
* Calculates the positive or negative angle between 2 vectors
|
||||
* @param vector Second vector
|
||||
* @return Angle
|
||||
*/
|
||||
double realAngle(const Vector &vector);
|
||||
|
||||
/**
|
||||
* Gets the length of this vector
|
||||
* @return Vector length
|
||||
*/
|
||||
double length();
|
||||
|
||||
// Generic operations
|
||||
CVector operator+(Vector);
|
||||
CVector operator+(double);
|
||||
CVector operator-(Vector);
|
||||
CVector operator-(double);
|
||||
CVector operator*(double);
|
||||
CVector operator/(double);
|
||||
void operator+=(Vector);
|
||||
void operator-=(Vector);
|
||||
void operator*=(double);
|
||||
void operator/=(double);
|
||||
bool operator==(Vector);
|
||||
};
|
||||
|
||||
} // namespace SpaceBar
|
||||
} // namespace Bagel
|
||||
|
||||
#endif
|
||||
125
engines/bagel/spacebar/boflib/vhash_table.h
Normal file
125
engines/bagel/spacebar/boflib/vhash_table.h
Normal file
@@ -0,0 +1,125 @@
|
||||
|
||||
/* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BAGEL_BOFLIB_VHASH_TABLE_H
|
||||
#define BAGEL_BOFLIB_VHASH_TABLE_H
|
||||
|
||||
#include "bagel/spacebar/boflib/list.h"
|
||||
|
||||
namespace Bagel {
|
||||
namespace SpaceBar {
|
||||
|
||||
template<class T, int S>
|
||||
class CBofVHashTable {
|
||||
public:
|
||||
CBofVHashTable(unsigned(*hashFun)(const T &));
|
||||
virtual ~CBofVHashTable();
|
||||
bool contains(const T &val);
|
||||
void insert(const T &val);
|
||||
|
||||
private:
|
||||
// Default constructor is not allowed. A declaration is provided,
|
||||
// but an implementation is not. A link error will result if an
|
||||
// attempt is made to use this constructor. The location which
|
||||
// is attempting to reference the default constructor should be changed
|
||||
// so that it calls the class constructor which takes a pointer to a
|
||||
// function and a table size.
|
||||
CBofVHashTable();
|
||||
|
||||
// Member which holds the hash table itself.
|
||||
CBofList<T *> _xHashTable[S];
|
||||
|
||||
// Member which holds a pointer to the table's hashing
|
||||
// function.
|
||||
unsigned(*_pHashFunction)(const T &);
|
||||
|
||||
// Member which holds the count of buckets in the hash table.
|
||||
int _nHashTableSize;
|
||||
|
||||
// Boolean which affords a light-weight test of whether the hash
|
||||
// table is empty.
|
||||
//
|
||||
bool _bisEmpty;
|
||||
};
|
||||
|
||||
// CBofVHashTable::CBofVHashTable - class constructor.
|
||||
//
|
||||
template<class T, int S>
|
||||
CBofVHashTable<T, S>::CBofVHashTable(unsigned(*hashFun)(const T &)) : _nHashTableSize(S),
|
||||
_pHashFunction(hashFun), _bisEmpty(true) {
|
||||
}
|
||||
|
||||
// CBofVHashTable::~CBofVHashTable - class destructor.
|
||||
template<class T, int S>
|
||||
CBofVHashTable<T, S>::~CBofVHashTable() {
|
||||
for (int x = 0; x < _nHashTableSize; x++) {
|
||||
CBofList<T *> *pHashBucket = &_xHashTable[x];
|
||||
int nListEntries = pHashBucket->getActualCount();
|
||||
|
||||
for (int i = 0; i < nListEntries; i++) {
|
||||
T *pListItem = pHashBucket->getNodeItem(i);
|
||||
delete pListItem;
|
||||
pHashBucket->setNodeItem(i, (T *)nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CBofVHashTable<T, S>::insert - add a value to the hash table.
|
||||
template<class T, int S>
|
||||
void CBofVHashTable<T, S>::insert(const T &val) {
|
||||
T *pNodeValue = new T(val);
|
||||
CBofListNode<T *> *pNode = new CBofListNode<T *>(pNodeValue);
|
||||
assert(pNode != nullptr);
|
||||
|
||||
int nHashBucketIndex = ((*_pHashFunction)(val)) % _nHashTableSize;
|
||||
assert(nHashBucketIndex < _nHashTableSize);
|
||||
|
||||
CBofList<T *> *pHashBucket = &_xHashTable[nHashBucketIndex];
|
||||
assert(pHashBucket != nullptr);
|
||||
pHashBucket->addToTail(pNode);
|
||||
}
|
||||
|
||||
// CBofVHashTable<T, S>contains - predicate to test whether a value is stored in the hash table.
|
||||
template<class T, int S>
|
||||
bool CBofVHashTable<T, S>::contains(const T &val) {
|
||||
bool returnValue = false;
|
||||
int nHashBucketIndex = ((*_pHashFunction)(val)) % _nHashTableSize;
|
||||
assert(nHashBucketIndex < _nHashTableSize);
|
||||
|
||||
CBofVHashTable<T, S> *const fakeThis = (CBofVHashTable<T, S> *const)this;
|
||||
CBofList<T *> *pHashBucket = &(fakeThis->_xHashTable[nHashBucketIndex]);
|
||||
assert(pHashBucket != nullptr);
|
||||
int nItemsInBucket = pHashBucket->getCount();
|
||||
for (int i = 0; i < nItemsInBucket; i++) {
|
||||
T *TableEntry = pHashBucket->getNodeItem(i);
|
||||
if (TableEntry->compareNoCase((const char *)val) == 0) {
|
||||
returnValue = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
} // namespace SpaceBar
|
||||
} // namespace Bagel
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user