Files
scummvm-cursorfix/engines/hpl1/engine/gui/Widget.cpp
2026-02-02 04:50:13 +01:00

559 lines
14 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/>.
*
*/
/*
* Copyright (C) 2006-2010 - Frictional Games
*
* This file is part of HPL1 Engine.
*/
#include "hpl1/engine/gui/Widget.h"
#include "hpl1/engine/system/low_level_system.h"
#include "hpl1/engine/gui/GuiGfxElement.h"
#include "hpl1/engine/gui/GuiSet.h"
#include "hpl1/engine/gui/GuiSkin.h"
namespace hpl {
//////////////////////////////////////////////////////////////////////////
// CONSTRUCTORS
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
iWidget::iWidget(eWidgetType aType, cGuiSet *apSet, cGuiSkin *apSkin) {
mpSet = apSet;
mpSkin = apSkin;
mpGui = mpSet->GetGui();
mType = aType;
mvCallbackLists.resize(eGuiMessage_LastEnum);
mpParent = NULL;
mvPosition = 0;
mvSize = 0;
mbEnabled = true;
mbVisible = true;
mbClipsGraphics = false;
mbMouseIsOver = false;
msText = _W("");
mbPositionIsUpdated = true;
mlPositionCount = 0;
mbConnectedToChildren = true;
if (mpSkin)
mpPointerGfx = mpSkin->GetGfx(eGuiSkinGfx_PointerNormal);
else
mpPointerGfx = NULL;
}
//-----------------------------------------------------------------------
iWidget::~iWidget() {
////////////////////////
// Remove all children
tWidgetListIt it = mlstChildren.begin();
while (it != mlstChildren.end()) {
RemoveChild(*it);
it = mlstChildren.begin();
}
////////////////////////////
// Remove from parent
if (mpParent)
mpParent->RemoveChild(this);
}
//-----------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////
// PUBLIC METHODS
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
void iWidget::Update(float afTimeStep) {
OnUpdate(afTimeStep);
}
//-----------------------------------------------------------------------
void iWidget::Draw(float afTimeStep, cGuiClipRegion *apClipRegion) {
if (mbVisible == false)
return;
OnDraw(afTimeStep, apClipRegion);
cGuiClipRegion *pChildRegion = apClipRegion;
if (mbClipsGraphics) {
pChildRegion = apClipRegion->CreateChild(GetGlobalPosition(), mvSize);
mpSet->SetCurrentClipRegion(pChildRegion);
}
OnDrawAfterClip(afTimeStep, apClipRegion);
/////////////////////////////////
// Draw callbacks
cGuiMessageData data;
data.mfVal = afTimeStep;
data.mpData = apClipRegion;
ProcessMessage(eGuiMessage_OnDraw, data);
/////////////////////////////////
// Draw children
tWidgetListIt it = mlstChildren.begin();
for (; it != mlstChildren.end(); ++it) {
iWidget *pChild = *it;
pChild->Draw(afTimeStep, pChildRegion);
}
if (mbClipsGraphics)
mpSet->SetCurrentClipRegion(apClipRegion);
}
//-----------------------------------------------------------------------
void iWidget::Init() {
OnInit();
LoadGraphics();
}
//-----------------------------------------------------------------------
bool iWidget::ProcessMessage(eGuiMessage aMessage, cGuiMessageData &aData) {
if (IsEnabled() == false)
return false;
aData.mMessage = aMessage;
bool bRet = false;
bRet = OnMessage(aMessage, aData); // This can override any message.
/////////////////////////////////////////
// Call the correct virtual function
if (bRet == false) {
switch (aMessage) {
case eGuiMessage_MouseMove:
bRet = OnMouseMove(aData);
break;
case eGuiMessage_MouseDown:
bRet = OnMouseDown(aData);
break;
case eGuiMessage_MouseUp:
bRet = OnMouseUp(aData);
break;
case eGuiMessage_MouseDoubleClick:
bRet = OnMouseDoubleClick(aData);
break;
case eGuiMessage_MouseEnter:
bRet = OnMouseEnter(aData);
break;
case eGuiMessage_MouseLeave:
bRet = OnMouseLeave(aData);
break;
case eGuiMessage_KeyPress:
bRet = OnKeyPress(aData);
break;
case eGuiMessage_GotFocus:
bRet = OnGotFocus(aData);
break;
case eGuiMessage_LostFocus:
bRet = OnLostFocus(aData);
break;
default:
break;
}
}
/////////////////////////////////////////
// Process user callbacks for the event.
if (ProcessCallbacks(aMessage, aData))
bRet = true;
return bRet;
}
//-----------------------------------------------------------------------
void iWidget::AddCallback(eGuiMessage aMessage, void *apObject, tGuiCallbackFunc apFunc) {
mvCallbackLists[aMessage].push_back(cWidgetCallback(apObject, apFunc));
}
//-----------------------------------------------------------------------
bool iWidget::PointIsInside(const cVector2f &avPoint, bool abOnlyClipped) {
if (mpParent && mpParent->ClipsGraphics()) {
if (mpParent->PointIsInside(avPoint, true) == false) {
return false;
}
}
if (abOnlyClipped && mbClipsGraphics == false)
return true;
cVector3f vGlobalPos = GetGlobalPosition();
if (avPoint.x < vGlobalPos.x || avPoint.x > vGlobalPos.x + mvSize.x ||
avPoint.y < vGlobalPos.y || avPoint.y > vGlobalPos.y + mvSize.y) {
return false;
} else {
return true;
}
}
//-----------------------------------------------------------------------
void iWidget::AttachChild(iWidget *apChild) {
if (apChild->mpParent) {
iWidget *pParent = apChild->mpParent;
pParent->RemoveChild(apChild);
apChild->SetPosition(apChild->mvPosition + pParent->GetGlobalPosition());
apChild->SetPosition(apChild->mvPosition - GetGlobalPosition());
}
apChild->mpParent = this;
apChild->SetPositionUpdated();
mlstChildren.push_back(apChild);
}
void iWidget::RemoveChild(iWidget *apChild) {
tWidgetListIt it = mlstChildren.begin();
for (; it != mlstChildren.end(); ++it) {
iWidget *pChild = *it;
if (pChild == apChild) {
mlstChildren.erase(it);
pChild->mpParent = NULL;
pChild->SetPositionUpdated();
pChild->SetPosition(pChild->mvPosition + GetGlobalPosition());
break;
}
}
}
//-----------------------------------------------------------------------
void iWidget::SetEnabled(bool abX) {
if (mbEnabled == abX)
return;
mbEnabled = abX;
}
bool iWidget::IsEnabled() {
if (mpParent) {
if (mpParent->IsEnabled())
return mbEnabled;
else
return false;
}
return mbEnabled;
}
//-----------------------------------------------------------------------
void iWidget::SetVisible(bool abX) {
if (mbVisible == abX)
return;
mbVisible = abX;
}
bool iWidget::IsVisible() {
if (mpParent) {
if (mpParent->IsVisible())
return mbVisible;
else
return false;
}
return mbVisible;
}
//-----------------------------------------------------------------------
bool iWidget::HasFocus() {
return mpSet->GetFocusedWidget() == this;
}
//-----------------------------------------------------------------------
void iWidget::SetText(const tWString &asText) {
if (asText == msText)
return;
msText = asText;
OnChangeText();
cGuiMessageData data = cGuiMessageData();
ProcessMessage(eGuiMessage_TextChange, data);
}
//-----------------------------------------------------------------------
void iWidget::SetPosition(const cVector3f &avPos) {
mvPosition = avPos;
SetPositionUpdated();
}
void iWidget::SetGlobalPosition(const cVector3f &avPos) {
SetPosition(avPos - mpParent->GetGlobalPosition());
}
const cVector3f &iWidget::GetLocalPosition() {
return mvPosition;
}
const cVector3f &iWidget::GetGlobalPosition() {
if (mpParent) {
if (mbPositionIsUpdated) {
mbPositionIsUpdated = false;
mvGlobalPosition = mpParent->GetGlobalPosition() + mvPosition;
}
return mvGlobalPosition;
} else {
return mvPosition;
}
}
//-----------------------------------------------------------------------
void iWidget::SetSize(const cVector2f &avSize) {
mvSize = avSize;
OnChangeSize();
}
//-----------------------------------------------------------------------
bool iWidget::ClipsGraphics() {
if (mpParent && mpParent->ClipsGraphics())
return true;
return mbClipsGraphics;
}
//-----------------------------------------------------------------------
bool iWidget::IsConnectedTo(iWidget *apWidget, bool abIsStartWidget) {
if (abIsStartWidget == false && mbConnectedToChildren == false)
return false;
if (apWidget == NULL)
return false;
if (apWidget == this)
return true;
if (mpParent)
return mpParent->IsConnectedTo(apWidget, false);
return false;
}
//-----------------------------------------------------------------------
cGuiGfxElement *iWidget::GetPointerGfx() {
return mpPointerGfx;
}
//-----------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////
// PROTECTED METHODS
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
bool iWidget::OnGotFocus(cGuiMessageData &aData) {
return mbEnabled;
}
//-----------------------------------------------------------------------
cVector3f iWidget::WorldToLocalPosition(const cVector3f &avPos) {
return avPos - GetGlobalPosition();
}
//-----------------------------------------------------------------------
cVector2f iWidget::GetPosRelativeToMouse(cGuiMessageData &aData) {
cVector3f vTemp = GetGlobalPosition() - aData.mvPos;
return cVector2f(vTemp.x, vTemp.y);
}
//-----------------------------------------------------------------------
void iWidget::DrawBordersAndCorners(cGuiGfxElement *apBackground,
cGuiGfxElement **apBorderVec, cGuiGfxElement **apCornerVec,
const cVector3f &avPosition, const cVector2f &avSize) {
mpSet->SetDrawOffset(avPosition);
///////////////////////
// Background
if (apBackground) {
mpSet->DrawGfx(apBackground, cVector3f(apCornerVec[0]->GetActiveSize().x, apCornerVec[0]->GetActiveSize().y, 0),
avSize - apCornerVec[2]->GetActiveSize() - apCornerVec[0]->GetActiveSize(),
cColor(1, 1));
}
///////////////////////
// Borders
// Right
mpSet->DrawGfx(apBorderVec[0],
cVector3f(avSize.x - apBorderVec[0]->GetActiveSize().x,
apCornerVec[1]->GetActiveSize().y, 0),
cVector2f(apBorderVec[0]->GetImageSize().x,
avSize.y - (apCornerVec[2]->GetActiveSize().y +
apCornerVec[1]->GetActiveSize().y)));
// Left
mpSet->DrawGfx(apBorderVec[1],
cVector3f(0, apCornerVec[0]->GetActiveSize().y, 0),
cVector2f(apBorderVec[1]->GetImageSize().x,
avSize.y - (apCornerVec[3]->GetActiveSize().y +
apCornerVec[0]->GetActiveSize().y)));
// Up
mpSet->DrawGfx(apBorderVec[2],
cVector3f(apCornerVec[0]->GetActiveSize().x, 0, 0),
cVector2f(avSize.x - (apCornerVec[0]->GetActiveSize().x +
apCornerVec[1]->GetActiveSize().x),
apBorderVec[2]->GetImageSize().y));
// Down
mpSet->DrawGfx(apBorderVec[3],
cVector3f(apCornerVec[3]->GetActiveSize().x,
avSize.y - apBorderVec[3]->GetActiveSize().y, 0),
cVector2f(avSize.x - (apCornerVec[2]->GetActiveSize().x +
apCornerVec[3]->GetActiveSize().x),
apBorderVec[3]->GetImageSize().y));
///////////////////////
// Corners
// Left Up
mpSet->DrawGfx(apCornerVec[0], cVector3f(0, 0, 0));
// Right Up
mpSet->DrawGfx(apCornerVec[1], cVector3f(avSize.x - apCornerVec[1]->GetActiveSize().x, 0, 0));
// Right Down
mpSet->DrawGfx(apCornerVec[2], cVector3f(avSize.x - apCornerVec[2]->GetActiveSize().x,
avSize.y - apCornerVec[2]->GetActiveSize().y, 0));
// Left Down
mpSet->DrawGfx(apCornerVec[3], cVector3f(0, avSize.y - apCornerVec[3]->GetActiveSize().y, 0));
mpSet->SetDrawOffset(0);
}
//-----------------------------------------------------------------------
void iWidget::DrawSkinText(const tWString &asText, eGuiSkinFont aFont,
const cVector3f &avPosition, eFontAlign aAlign) {
cGuiSkinFont *pFont = mpSkin->GetFont(aFont);
mpSet->DrawFont(asText, pFont->mpFont, avPosition, pFont->mvSize, pFont->mColor,
aAlign);
}
//-----------------------------------------------------------------------
void iWidget::DrawDefaultText(const tWString &asText,
const cVector3f &avPosition, eFontAlign aAlign) {
if (mpDefaultFontType == NULL)
return;
mpSet->DrawFont(asText, mpDefaultFontType, avPosition, mvDefaultFontSize,
mDefaultFontColor, aAlign);
}
//-----------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////
// PRIVATE METHODS
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
bool iWidget::ProcessCallbacks(eGuiMessage aMessage, cGuiMessageData &aData) {
tWidgetCallbackList &lstCallbacks = mvCallbackLists[aMessage];
if (lstCallbacks.empty())
return false;
bool bRet = false;
tWidgetCallbackListIt it = lstCallbacks.begin();
for (; it != lstCallbacks.end(); ++it) {
cWidgetCallback &callback = *it;
bool bX = (callback.mpFunc)(callback.mpObject, this, aData);
if (bX)
bRet = true;
}
return bRet;
}
//-----------------------------------------------------------------------
void iWidget::LoadGraphics() {
if (mpSkin) {
mpDefaultFont = mpSkin->GetFont(eGuiSkinFont_Default);
mpDefaultFontType = mpDefaultFont->mpFont;
mDefaultFontColor = mpDefaultFont->mColor;
mvDefaultFontSize = mpDefaultFont->mvSize;
} else {
mpDefaultFont = NULL;
}
OnLoadGraphics();
}
//-----------------------------------------------------------------------
void iWidget::SetPositionUpdated() {
mbPositionIsUpdated = true;
mlPositionCount++;
OnChangePosition();
tWidgetListIt it = mlstChildren.begin();
for (; it != mlstChildren.end(); ++it) {
iWidget *pChild = *it;
pChild->SetPositionUpdated();
}
}
//-----------------------------------------------------------------------
} // namespace hpl