mirror of
https://github.com/scummvm/scummvm.git
synced 2026-06-20 05:45:29 +00:00
505 lines
12 KiB
C++
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/baglib/button_object.h"
|
|
#include "bagel/baglib/bagel.h"
|
|
#include "bagel/baglib/pan_window.h"
|
|
|
|
namespace Bagel {
|
|
|
|
CBagButtonObject::CBagButtonObject() {
|
|
m_xObjType = BUTTONOBJ;
|
|
m_xButtonType = PUSH;
|
|
|
|
SetState(0); // Set to first cel
|
|
|
|
m_bActive = false;
|
|
m_bActiveDown = false;
|
|
m_bActiveUp = false;
|
|
|
|
m_nNumPos = 0;
|
|
m_bDragging = false;
|
|
SetCallBack(nullptr, nullptr);
|
|
SetAlwaysUpdate(true);
|
|
|
|
SetTimeless(true);
|
|
}
|
|
|
|
CBagButtonObject::~CBagButtonObject() {
|
|
Detach();
|
|
}
|
|
|
|
ErrorCode CBagButtonObject::Attach() {
|
|
ErrorCode rc = CBagSpriteObject::Attach();
|
|
|
|
if (GetSprite()) {
|
|
GetSprite()->SetAnimated(false);
|
|
}
|
|
|
|
if (m_xButtonType == VLEVER || m_xButtonType == HLEVER) {
|
|
m_MidPoint.x = GetRect().TopLeft().x + (GetRect().Width() / 2);
|
|
m_MidPoint.y = GetRect().TopLeft().y + (GetRect().Height() / 2);
|
|
}
|
|
|
|
if (GetSprite()->GetCelCount() == 1 && m_xButtonType != SLIDER) {
|
|
// Only given down state
|
|
SetVisible(false);
|
|
}
|
|
|
|
// If this is a slider button make sure it is in the correct position
|
|
if (m_xButtonType == SLIDER) {
|
|
CBofPoint NewPoint = GetPosition();
|
|
int xIncrement = m_SlideRect.Width() / (m_nNumPos - 1);
|
|
NewPoint.x = m_SlideRect.left + (GetState() * xIncrement);
|
|
SetPosition(NewPoint);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
ErrorCode CBagButtonObject::Detach() {
|
|
return CBagSpriteObject::Detach();
|
|
}
|
|
|
|
extern bool g_bNoMenu;
|
|
|
|
bool CBagButtonObject::RunObject() {
|
|
// Reset wield
|
|
g_bNoMenu = false;
|
|
|
|
if (m_xButtonType == PUSH) {
|
|
|
|
if (m_bActive && !m_bActiveUp) {
|
|
m_bActiveUp = true;
|
|
}
|
|
if (GetSprite() && (GetSprite()->GetCelCount() == 1)) {
|
|
// Only given down state
|
|
SetVisible(false);
|
|
}
|
|
|
|
SetState(0); // Set to first cel
|
|
}
|
|
|
|
RunCallBack();
|
|
|
|
return CBagObject::RunObject();
|
|
}
|
|
|
|
void CBagButtonObject::OnLButtonDown(uint32 /*nFlags*/, CBofPoint *xPoint, void *) {
|
|
if (m_xButtonType == PUSH) {
|
|
if (!m_bActive && !m_bActiveDown) {
|
|
m_bActiveDown = true;
|
|
m_bActive = true;
|
|
}
|
|
if (GetSprite() && (GetSprite()->GetCelCount() == 1)) {
|
|
// Only given down state
|
|
SetVisible();
|
|
}
|
|
|
|
SetState(1); // Set to clicked down
|
|
|
|
} else if (m_xButtonType == HLEVER || m_xButtonType == VLEVER) {
|
|
if (!m_bActiveDown && !m_bActiveUp) {
|
|
if ((m_xButtonType == HLEVER && xPoint->x > m_MidPoint.x) || // right of midpoint
|
|
(m_xButtonType == VLEVER && xPoint->y > m_MidPoint.y)) { // below midpoint
|
|
m_bActiveDown = true;
|
|
} else {
|
|
m_bActiveUp = true;
|
|
}
|
|
}
|
|
|
|
} else if (m_xButtonType == SLIDER) {
|
|
m_bDragging = true;
|
|
}
|
|
|
|
SetDirty();
|
|
}
|
|
|
|
void CBagButtonObject::OnLButtonUp(uint32 nFlags, CBofPoint *xPoint, void *info) {
|
|
CBagStorageDevWnd *pMainWin = (CBagel::GetBagApp()->GetMasterWnd()->GetCurrentStorageDev());
|
|
|
|
if (pMainWin != nullptr) {
|
|
pMainWin->SetPreFilterPan(true);
|
|
}
|
|
|
|
if ((m_xButtonType == SLIDER) && m_bDragging) {
|
|
|
|
// Snap to place
|
|
CBofPoint mLoc;
|
|
CBofPoint NewPoint = GetPosition();
|
|
|
|
// Get the mouse point relative to the pan window
|
|
CBagPanWindow *pWnd = (CBagPanWindow *)info;
|
|
CBofRect r = pWnd->GetSlideBitmap()->GetCurrView();
|
|
|
|
mLoc.x = xPoint->x + r.left - pWnd->GetViewPortPos().x;
|
|
mLoc.y = xPoint->y + r.top - pWnd->GetViewPortPos().y;
|
|
|
|
int xIncrement = m_SlideRect.Width() / (m_nNumPos - 1);
|
|
|
|
int slidePos = m_SlideRect.left;
|
|
int i;
|
|
for (i = 0; (i < m_nNumPos) && (slidePos < mLoc.x); i++)
|
|
slidePos = m_SlideRect.left + (i * xIncrement);
|
|
|
|
// We Went too far
|
|
i--;
|
|
|
|
// Find the previous position was closer to the mouse
|
|
if ((i > 0) && (slidePos - mLoc.x > mLoc.x - (slidePos - xIncrement)))
|
|
i--; // Go back one
|
|
|
|
NewPoint.x = m_SlideRect.left + (i * xIncrement);
|
|
if (NewPoint.x < m_SlideRect.left) {
|
|
NewPoint.x = m_SlideRect.left;
|
|
} else if (NewPoint.x > m_SlideRect.right) {
|
|
NewPoint.x = m_SlideRect.right;
|
|
}
|
|
|
|
SetPosition(NewPoint);
|
|
if (i < 0) {
|
|
i = 0;
|
|
} else if (i >= m_nNumPos) {
|
|
i = m_nNumPos - 1;
|
|
}
|
|
|
|
SetState(i);
|
|
m_bDragging = false;
|
|
|
|
} else if (m_xButtonType == CHECKBOX) {
|
|
|
|
if (!m_bActive) {
|
|
m_bActive = true;
|
|
m_bActiveDown = !m_bActiveDown;
|
|
|
|
if (GetSprite() && (GetSprite()->GetCelCount() == 1)) {
|
|
// Only given down state
|
|
SetVisible(m_bActiveDown);
|
|
m_bActive = false;
|
|
}
|
|
|
|
if (m_bActiveDown)
|
|
SetState(1);
|
|
else
|
|
SetState(0);
|
|
}
|
|
}
|
|
|
|
SetDirty();
|
|
|
|
CBagSpriteObject::OnLButtonUp(nFlags, xPoint, info);
|
|
}
|
|
|
|
bool CBagButtonObject::OnMouseMove(uint32 /*nFlags*/, CBofPoint xPoint, void *info) {
|
|
CBagStorageDevWnd *pMainWin = (CBagel::GetBagApp()->GetMasterWnd()->GetCurrentStorageDev());
|
|
|
|
if (m_xButtonType == SLIDER && m_bDragging) {
|
|
if (!m_SlideRect.IsRectEmpty()) {
|
|
if (pMainWin != nullptr) {
|
|
pMainWin->SetPreFilterPan(true);
|
|
}
|
|
SetDirty();
|
|
|
|
CBofPoint mLoc;
|
|
CBofPoint NewPoint = GetPosition();
|
|
CBagPanWindow *pWnd = (CBagPanWindow *)info;
|
|
CBofRect r = pWnd->GetSlideBitmap()->GetCurrView();
|
|
|
|
mLoc.x = xPoint.x + r.left - pWnd->GetViewPortPos().x;
|
|
mLoc.y = xPoint.y + r.top - pWnd->GetViewPortPos().y;
|
|
|
|
int NewXPos = mLoc.x;
|
|
|
|
// Constrict Dragging to width of slidebar
|
|
if (NewXPos > m_SlideRect.right)
|
|
NewXPos = m_SlideRect.right;
|
|
if (NewXPos < m_SlideRect.left)
|
|
NewXPos = m_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
|
|
int xIncrement = m_SlideRect.Width() / (m_nNumPos - 1);
|
|
int i = (NewPoint.x - m_SlideRect.left) / xIncrement;
|
|
SetState(i);
|
|
}
|
|
}
|
|
|
|
if (m_xButtonType == PUSH) {
|
|
if (GetSprite() && (GetSprite()->GetCelCount() > 1)) {
|
|
if (!this->GetRect().PtInRect(xPoint) &&
|
|
m_bActive && !m_bActiveUp) {
|
|
m_bActiveUp = true;
|
|
}
|
|
}
|
|
if (GetSprite() && (GetSprite()->GetCelCount() == 1)) { // Only given down state
|
|
SetVisible(false);
|
|
}
|
|
|
|
SetState(0); // Set to first cel
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
ErrorCode CBagButtonObject::Update(CBofBitmap *pBmp, CBofPoint pt, CBofRect *pSrcRect, int nMaskColor) {
|
|
bool bDirty = false;
|
|
|
|
if (m_xButtonType == PUSH) {
|
|
|
|
if (GetSprite() && (GetSprite()->GetCelCount() > 1)) {
|
|
|
|
if (m_bActive) { // If the button is doing something
|
|
if (m_bActiveDown) {
|
|
GetSprite()->NextCel(); // Increment frame
|
|
// If this is animated, the bring it back up immediately
|
|
if (GetSprite()->GetCelIndex() == GetSprite()->GetCelCount() - 1 || GetSprite()->GetAnimated()) {
|
|
m_bActiveDown = false;
|
|
}
|
|
} else if (m_bActiveUp) { // else (going back up)
|
|
GetSprite()->PrevCel(); // decrement frame
|
|
// If this is animated, the let it go immediately
|
|
if (GetSprite()->GetCelIndex() == 0 || GetSprite()->GetAnimated()) {
|
|
m_bActiveUp = false;
|
|
m_bActive = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
} else if (m_xButtonType == CHECKBOX) {
|
|
if (GetSprite() && (GetSprite()->GetCelCount() > 1) && m_bActive) {
|
|
if (m_bActiveDown) {
|
|
GetSprite()->NextCel(); // Increment frame
|
|
if (GetSprite()->GetCelIndex() == GetSprite()->GetCelCount() - 1) {
|
|
m_bActive = false;
|
|
}
|
|
} else { // else (going back up)
|
|
GetSprite()->PrevCel(); // decrement frame
|
|
if (GetSprite()->GetCelIndex() == 0) {
|
|
m_bActive = 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 (m_xButtonType == HLEVER || m_xButtonType == VLEVER) {
|
|
|
|
if (GetSprite() && (GetSprite()->GetCelCount() > 1)) {
|
|
if (m_bActiveDown) {
|
|
if (GetSprite()->GetCelIndex() < (GetSprite()->GetCelCount() - 1))
|
|
GetSprite()->NextCel();
|
|
m_bActiveDown = false;
|
|
} else if (m_bActiveUp) {
|
|
if (GetSprite()->GetCelIndex() > 0)
|
|
GetSprite()->PrevCel();
|
|
m_bActiveUp = false;
|
|
}
|
|
|
|
SetState(GetSprite()->GetCelIndex());
|
|
}
|
|
}
|
|
|
|
if (GetSprite() && ((GetSprite()->GetCelCount() > 1) || IsVisible())) {
|
|
ErrorCode err = CBagSpriteObject::Update(pBmp, pt, pSrcRect, nMaskColor);
|
|
SetDirty(bDirty);
|
|
return err;
|
|
}
|
|
|
|
return m_errCode;
|
|
}
|
|
|
|
void CBagButtonObject::SetSize(const CBofSize &xSize) {
|
|
if (m_xButtonType == SLIDER)
|
|
m_SlideRect = CBofRect(GetPosition(), xSize);
|
|
|
|
CBagSpriteObject::SetSize(xSize);
|
|
}
|
|
|
|
PARSE_CODES CBagButtonObject::SetInfo(bof_ifstream &istr) {
|
|
bool nObjectUpdated = false;
|
|
|
|
while (!istr.eof()) {
|
|
char ch = (char)istr.peek();
|
|
switch (ch) {
|
|
//
|
|
// +n - n number of slides in sprite
|
|
//
|
|
case '+': {
|
|
int cels;
|
|
istr.Get();
|
|
GetIntFromStream(istr, cels);
|
|
|
|
if (m_xButtonType == SLIDER)
|
|
m_nNumPos = 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")) {
|
|
m_xButtonType = PUSH;
|
|
nObjectUpdated = true;
|
|
} else if (!sStr.Find("CHECKBOX")) {
|
|
m_xButtonType = CHECKBOX;
|
|
nObjectUpdated = true;
|
|
} else if (!sStr.Find("HLEVER")) {
|
|
m_xButtonType = HLEVER;
|
|
nObjectUpdated = true;
|
|
} else if (!sStr.Find("VLEVER")) {
|
|
m_xButtonType = VLEVER;
|
|
nObjectUpdated = true;
|
|
} else if (!sStr.Find("DIAL")) {
|
|
m_xButtonType = DIAL;
|
|
nObjectUpdated = true;
|
|
} else if (!sStr.Find("SLIDER")) {
|
|
m_xButtonType = SLIDER;
|
|
nObjectUpdated = true;
|
|
} else {
|
|
PutbackStringOnStream(istr, sStr);
|
|
PutbackStringOnStream(istr, "AS ");
|
|
}
|
|
} else {
|
|
PutbackStringOnStream(istr, sStr);
|
|
}
|
|
break;
|
|
}
|
|
|
|
//
|
|
// No match return from function
|
|
//
|
|
default: {
|
|
PARSE_CODES rc = CBagObject::SetInfo(istr);
|
|
if (rc == PARSING_DONE) {
|
|
return PARSING_DONE;
|
|
}
|
|
|
|
if (rc == 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 &sProp, int nVal) {
|
|
if (!sProp.Find("STATE")) {
|
|
if (GetSprite()) {
|
|
if (m_xButtonType == CHECKBOX) {
|
|
m_bActive = true;
|
|
if (nVal == 0)
|
|
m_bActiveDown = false;
|
|
else
|
|
m_bActiveDown = true;
|
|
|
|
if (GetSprite() && (GetSprite()->GetCelCount() == 1)) { // Only given down state
|
|
SetVisible(m_bActiveDown);
|
|
m_bActive = false;
|
|
}
|
|
|
|
if (nVal == 0)
|
|
SetState(0);
|
|
else
|
|
SetState(1);
|
|
} else {
|
|
if (m_xButtonType == SLIDER) {
|
|
CBofPoint cPos = GetPosition();
|
|
|
|
cPos.x = m_SlideRect.left + (nVal * (m_SlideRect.Width() / (m_nNumPos - 1)));
|
|
SetPosition(cPos);
|
|
SetDirty(true);
|
|
}
|
|
SetState(nVal);
|
|
GetSprite()->SetCel(nVal);
|
|
}
|
|
}
|
|
} else if (!sProp.Find("CURR_CEL")) {
|
|
SetState(nVal);
|
|
if (GetSprite())
|
|
GetSprite()->SetCel(nVal);
|
|
} else
|
|
CBagObject::SetProperty(sProp, nVal);
|
|
}
|
|
|
|
int CBagButtonObject::GetProperty(const CBofString &sProp) {
|
|
if (!sProp.Find("CURR_CEL")) {
|
|
if (GetSprite()) {
|
|
return GetSprite()->GetCelIndex();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
return CBagObject::GetProperty(sProp);
|
|
}
|
|
|
|
} // namespace Bagel
|