Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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