Files
scummvm-cursorfix/engines/bagel/spacebar/baglib/button_object.cpp
2026-02-02 04:50:13 +01:00

505 lines
12 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "bagel/spacebar/baglib/button_object.h"
#include "bagel/spacebar/baglib/bagel.h"
#include "bagel/spacebar/baglib/master_win.h"
#include "bagel/spacebar/baglib/pan_window.h"
namespace Bagel {
namespace SpaceBar {
CBagButtonObject::CBagButtonObject() {
_xObjType = BUTTON_OBJ;
_buttonType = BTN_PUSH;
// Set to first cel
CBagObject::setState(0);
_active = false;
_activeDown = false;
_activeUp = false;
_numPos = 0;
_dragging = false;
setCallBack(nullptr, nullptr);
setAlwaysUpdate(true);
setTimeless(true);
}
CBagButtonObject::~CBagButtonObject() {
CBagButtonObject::detach();
}
ErrorCode CBagButtonObject::attach() {
const ErrorCode errorCode = CBagSpriteObject::attach();
CBofSprite *curSprite = getSprite();
if (curSprite) {
curSprite->setAnimated(false);
}
if (_buttonType == BTN_VLEVER || _buttonType == BTN_HLEVER) {
_midPoint.x = getRect().topLeft().x + (getRect().width() / 2);
_midPoint.y = getRect().topLeft().y + (getRect().height() / 2);
}
if (curSprite && curSprite->getCelCount() == 1 && _buttonType != BTN_SLIDER) {
// Only given down state
setVisible(false);
}
// If this is a slider button make sure it is in the correct position
if (_buttonType == BTN_SLIDER) {
CBofPoint NewPoint = getPosition();
const int xIncrement = _slideRect.width() / (_numPos - 1);
NewPoint.x = _slideRect.left + (getState() * xIncrement);
setPosition(NewPoint);
}
return errorCode;
}
ErrorCode CBagButtonObject::detach() {
return CBagSpriteObject::detach();
}
extern bool g_noMenuFl;
bool CBagButtonObject::runObject() {
// Reset wield
g_noMenuFl = false;
if (_buttonType == BTN_PUSH) {
if (_active && !_activeUp) {
_activeUp = true;
}
if (getSprite() && (getSprite()->getCelCount() == 1)) {
// Only given down state
setVisible(false);
}
// Set to first cel
setState(0);
}
runCallBack();
return CBagObject::runObject();
}
void CBagButtonObject::onLButtonDown(uint32 /*nFlags*/, CBofPoint *point, void *) {
if (_buttonType == BTN_PUSH) {
if (!_active && !_activeDown) {
_activeDown = true;
_active = true;
}
if (getSprite() && (getSprite()->getCelCount() == 1)) {
// Only given down state
setVisible();
}
// Set to clicked down
setState(1);
} else if (_buttonType == BTN_HLEVER || _buttonType == BTN_VLEVER) {
if (!_activeDown && !_activeUp) {
if ((_buttonType == BTN_HLEVER && point->x > _midPoint.x) || // right of midpoint
(_buttonType == BTN_VLEVER && point->y > _midPoint.y)) { // below midpoint
_activeDown = true;
} else {
_activeUp = true;
}
}
} else if (_buttonType == BTN_SLIDER) {
_dragging = true;
}
setDirty();
}
void CBagButtonObject::onLButtonUp(uint32 flags, CBofPoint *point, void *extraInfo) {
CBagStorageDevWnd *pMainWin = (CBagel::getBagApp()->getMasterWnd()->getCurrentStorageDev());
if (pMainWin != nullptr) {
pMainWin->setPreFilterPan(true);
}
if ((_buttonType == BTN_SLIDER) && _dragging) {
// Snap to place
CBofPoint NewPoint = getPosition();
// Get the mouse point relative to the pan window
CBagPanWindow *pWnd = (CBagPanWindow *)extraInfo;
const CBofRect r = pWnd->getSlideBitmap()->getCurrView();
const int mLocX = point->x + r.left - pWnd->getViewPortPos().x;
const int xIncrement = _slideRect.width() / (_numPos - 1);
int slidePos = _slideRect.left;
int i;
for (i = 0; (i < _numPos) && (slidePos < mLocX); i++)
slidePos = _slideRect.left + (i * xIncrement);
// We Went too far
i--;
// Find the previous position was closer to the mouse
if ((i > 0) && (slidePos - mLocX > mLocX - (slidePos - xIncrement)))
i--; // Go back one
NewPoint.x = _slideRect.left + (i * xIncrement);
if (NewPoint.x < _slideRect.left) {
NewPoint.x = _slideRect.left;
} else if (NewPoint.x > _slideRect.right) {
NewPoint.x = _slideRect.right;
}
setPosition(NewPoint);
if (i < 0) {
i = 0;
} else if (i >= _numPos) {
i = _numPos - 1;
}
setState(i);
_dragging = false;
} else if (_buttonType == BTN_CHECKBOX) {
if (!_active) {
_active = true;
_activeDown = !_activeDown;
if (getSprite() && (getSprite()->getCelCount() == 1)) {
// Only given down state
setVisible(_activeDown);
_active = false;
}
if (_activeDown)
setState(1);
else
setState(0);
}
}
setDirty();
CBagSpriteObject::onLButtonUp(flags, point, extraInfo);
}
bool CBagButtonObject::onMouseMove(uint32 /*nFlags*/, CBofPoint point, void *extraInfo) {
CBagStorageDevWnd *pMainWin = (CBagel::getBagApp()->getMasterWnd()->getCurrentStorageDev());
if (_buttonType == BTN_SLIDER && _dragging) {
if (!_slideRect.isRectEmpty()) {
if (pMainWin != nullptr) {
pMainWin->setPreFilterPan(true);
}
setDirty();
CBofPoint NewPoint = getPosition();
CBagPanWindow *pWnd = (CBagPanWindow *)extraInfo;
const CBofRect r = pWnd->getSlideBitmap()->getCurrView();
const int mLocX = point.x + r.left - pWnd->getViewPortPos().x;
int NewXPos = mLocX;
// Constrict Dragging to width of slidebar
if (NewXPos > _slideRect.right)
NewXPos = _slideRect.right;
if (NewXPos < _slideRect.left)
NewXPos = _slideRect.left;
NewPoint.x = NewXPos;
setPosition(NewPoint);
// We need to set the state here as well as LButtonUP
// because there is a chance we won't get it
const int xIncrement = _slideRect.width() / (_numPos - 1);
const int i = (NewPoint.x - _slideRect.left) / xIncrement;
setState(i);
}
}
if (_buttonType == BTN_PUSH) {
if (getSprite() && (getSprite()->getCelCount() > 1)) {
if (!this->getRect().ptInRect(point) && _active && !_activeUp) {
_activeUp = true;
}
}
if (getSprite() && (getSprite()->getCelCount() == 1)) { // Only given down state
setVisible(false);
}
setState(0); // Set to first cel
}
return true;
}
ErrorCode CBagButtonObject::update(CBofBitmap *bmp, CBofPoint pt, CBofRect *srcRect, int maskColor) {
bool bDirty = false;
if (_buttonType == BTN_PUSH) {
if (getSprite() && (getSprite()->getCelCount() > 1)) {
if (_active) { // If the button is doing something
if (_activeDown) {
getSprite()->nextCel(); // Increment frame
// If this is animated, the bring it back up immediately
if (getSprite()->getCelIndex() == getSprite()->getCelCount() - 1 || getSprite()->getAnimated()) {
_activeDown = false;
}
} else if (_activeUp) { // else (going back up)
getSprite()->prevCel(); // decrement frame
// If this is animated, the let it go immediately
if (getSprite()->getCelIndex() == 0 || getSprite()->getAnimated()) {
_activeUp = false;
_active = false;
}
}
}
}
} else if (_buttonType == BTN_CHECKBOX) {
if (getSprite() && (getSprite()->getCelCount() > 1) && _active) {
if (_activeDown) {
getSprite()->nextCel(); // Increment frame
if (getSprite()->getCelIndex() == getSprite()->getCelCount() - 1) {
_active = false;
}
} else { // else (going back up)
getSprite()->prevCel(); // decrement frame
if (getSprite()->getCelIndex() == 0) {
_active = false;
}
}
}
// For checkboxes, we have to make sure that they are always
// redrawn as they will otherwise return to their state on the pan (in the
// background of the closeup).
bDirty = true;
} else if (_buttonType == BTN_HLEVER || _buttonType == BTN_VLEVER) {
if (getSprite() && (getSprite()->getCelCount() > 1)) {
if (_activeDown) {
if (getSprite()->getCelIndex() < (getSprite()->getCelCount() - 1))
getSprite()->nextCel();
_activeDown = false;
} else if (_activeUp) {
if (getSprite()->getCelIndex() > 0)
getSprite()->prevCel();
_activeUp = false;
}
setState(getSprite()->getCelIndex());
}
}
if (getSprite() && ((getSprite()->getCelCount() > 1) || isVisible())) {
const ErrorCode errorCode = CBagSpriteObject::update(bmp, pt, srcRect, maskColor);
setDirty(bDirty);
return errorCode;
}
return _errCode;
}
void CBagButtonObject::setSize(const CBofSize &size) {
if (_buttonType == BTN_SLIDER)
_slideRect = CBofRect(getPosition(), size);
CBagSpriteObject::setSize(size);
}
ParseCodes CBagButtonObject::setInfo(CBagIfstream &istr) {
bool nObjectUpdated = false;
while (!istr.eof()) {
const char ch = (char)istr.peek();
switch (ch) {
//
// +n - n number of slides in sprite
//
case '+': {
int cels;
istr.getCh();
getIntFromStream(istr, cels);
if (_buttonType == BTN_SLIDER)
_numPos = cels;
else
setCels(cels);
nObjectUpdated = true;
break;
}
// Handle a maximum framerate...
case 'F': {
char szLocalStr[256];
szLocalStr[0] = 0;
CBofString sStr(szLocalStr, 256);
getAlphaNumFromStream(istr, sStr);
if (!sStr.find("FRAMERATE")) {
int nFrameRate;
istr.eatWhite();
getIntFromStream(istr, nFrameRate);
// The framerate is expressed in frames/second, so do some division
// here to store the number of milliseconds.
setFrameRate(1000 / nFrameRate);
nObjectUpdated = true;
} else {
putbackStringOnStream(istr, sStr);
}
break;
}
//
// AS [LINK|CLOSEUP] - how to run the link
//
case 'A': {
char szLocalStr[256];
szLocalStr[0] = 0;
CBofString sStr(szLocalStr, 256);
getAlphaNumFromStream(istr, sStr);
if (!sStr.find("AS")) {
istr.eatWhite();
getAlphaNumFromStream(istr, sStr);
if (!sStr.find("PUSH")) {
_buttonType = BTN_PUSH;
nObjectUpdated = true;
} else if (!sStr.find("CHECKBOX")) {
_buttonType = BTN_CHECKBOX;
nObjectUpdated = true;
} else if (!sStr.find("HLEVER")) {
_buttonType = BTN_HLEVER;
nObjectUpdated = true;
} else if (!sStr.find("VLEVER")) {
_buttonType = BTN_VLEVER;
nObjectUpdated = true;
} else if (!sStr.find("DIAL")) {
_buttonType = BTN_DIAL;
nObjectUpdated = true;
} else if (!sStr.find("SLIDER")) {
_buttonType = BTN_SLIDER;
nObjectUpdated = true;
} else {
putbackStringOnStream(istr, sStr);
putbackStringOnStream(istr, "AS ");
}
} else {
putbackStringOnStream(istr, sStr);
}
break;
}
//
// No match return from function
//
default: {
const ParseCodes parseCode = CBagObject::setInfo(istr);
if (parseCode == PARSING_DONE) {
return PARSING_DONE;
}
if (parseCode == UPDATED_OBJECT) {
nObjectUpdated = true;
} else { // rc==UNKNOWN_TOKEN
if (nObjectUpdated)
return UPDATED_OBJECT;
return UNKNOWN_TOKEN;
}
break;
}
} // end switch
} // end while
return PARSING_DONE;
}
void CBagButtonObject::setProperty(const CBofString &prop, int val) {
if (!prop.find("STATE")) {
if (getSprite()) {
if (_buttonType == BTN_CHECKBOX) {
_active = true;
if (val == 0)
_activeDown = false;
else
_activeDown = true;
if (getSprite()->getCelCount() == 1) { // Only given down state
setVisible(_activeDown);
_active = false;
}
if (val == 0)
setState(0);
else
setState(1);
} else {
if (_buttonType == BTN_SLIDER) {
CBofPoint cPos = getPosition();
cPos.x = _slideRect.left + (val * (_slideRect.width() / (_numPos - 1)));
setPosition(cPos);
setDirty(true);
}
setState(val);
getSprite()->setCel(val);
}
}
} else if (!prop.find("CURR_CEL")) {
setState(val);
if (getSprite())
getSprite()->setCel(val);
} else
CBagObject::setProperty(prop, val);
}
int CBagButtonObject::getProperty(const CBofString &prop) {
if (!prop.find("CURR_CEL")) {
if (getSprite()) {
return getSprite()->getCelIndex();
}
return 0;
}
return CBagObject::getProperty(prop);
}
} // namespace SpaceBar
} // namespace Bagel