Files
scummvm-cursorfix/engines/bagel/mfc/gfx/dialog_template.cpp
2026-02-02 04:50:13 +01:00

277 lines
6.8 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 "common/memstream.h"
#include "bagel/mfc/gfx/dialog_template.h"
#include "bagel/mfc/afxwin.h"
namespace Bagel {
namespace MFC {
namespace Gfx {
CDialogTemplate::CDialogTemplate(LPCDLGTEMPLATE pTemplate) {
setTemplate(pTemplate);
}
CDialogTemplate::CDialogTemplate(HGLOBAL hGlobal) {
LPDLGTEMPLATE dlgTemplate = (LPDLGTEMPLATE)GlobalLock(hGlobal);
setTemplate(dlgTemplate);
GlobalUnlock(hGlobal);
}
bool CDialogTemplate::setTemplate(LPCDLGTEMPLATE pTemplate) {
Common::MemoryReadStream src((const byte *)pTemplate, 99999);
_header.load(src);
_items.clear();
_items.resize(_header._itemCount);
for (auto &item : _items)
item.load(src);
return true;
}
bool CDialogTemplate::HasFont() const {
return false;
}
bool CDialogTemplate::SetFont(const char *lpFaceName, uint16 nFontSize) {
return false;
}
bool CDialogTemplate::SetSystemFont(uint16 nFontSize) {
return false;
}
bool CDialogTemplate::GetFont(CString &strFaceName, uint16 &nFontSize) const {
return false;
}
void CDialogTemplate::GetSizeInDialogUnits(SIZE *pSize) const {
}
void CDialogTemplate::GetSizeInPixels(SIZE *pSize) const {
}
bool CDialogTemplate::GetFont(LPCDLGTEMPLATE pTemplate,
CString &strFaceName, uint16 &nFontSize) {
return false;
}
/*--------------------------------------------*/
void CDialogTemplate::Header::load(Common::SeekableReadStream &src) {
byte bTerm;
_style = src.readUint32LE();
_itemCount = src.readByte();
_x = src.readSint16LE();
_y = src.readSint16LE();
_w = src.readSint16LE();
_h = src.readSint16LE();
bTerm = src.readByte();
switch (bTerm) {
case 0:
_menuName.clear();
break;
case 0xff:
// Int resource Id
src.skip(2);
break;
default:
src.seek(-1, SEEK_CUR);
_menuName = src.readString();
break;
}
_className = src.readString();
_caption = src.readString();
if (_style & DS_SETFONT) {
_fontInfo._pointSize = src.readUint16LE();
_fontInfo._fontName = src.readString();
} else {
_fontInfo._pointSize = 0;
_fontInfo._fontName.clear();
}
}
/*--------------------------------------------*/
void CDialogTemplate::Item::load(Common::SeekableReadStream &src) {
byte bTerm;
_x = src.readSint16LE();
_y = src.readSint16LE();
_w = src.readSint16LE();
_h = src.readSint16LE();
_id = src.readUint16LE();
_style = src.readUint32LE();
bTerm = src.readByte();
if (bTerm & 0x80) {
switch (bTerm) {
case 0x80: _className = "BUTTON"; break;
case 0x81: _className = "EDIT"; break;
case 0x82: _className = "STATIC"; break;
case 0x83: _className = "LISTBOX"; break;
case 0x84: _className = "SCROLLBAR"; break;
case 0x85: _className = "COMBOBOX"; break;
default:
_className.clear();
break;
}
} else {
src.seek(-1, SEEK_CUR);
_className = src.readString();
}
bTerm = src.readByte();
if (bTerm == 0xff) {
// Integer id, not documented
src.skip(2);
} else {
src.seek(-1, SEEK_CUR);
_title = src.readString();
}
_data.resize(src.readByte());
if (!_data.empty())
src.read(&_data[0], _data.size());
}
LOGFONT CDialogTemplate::ParseFontFromTemplate() {
LOGFONT lf;
memset(&lf, 0, sizeof(LOGFONT));
Common::strcpy_s(lf.lfFaceName,
_header._fontInfo._fontName.c_str());
lf.lfHeight = _header._fontInfo._pointSize;
return lf;
}
void CDialogTemplate::getBaseUnits(int &x, int &y) {
// Step 1: Get the font
LOGFONT lf = ParseFontFromTemplate();
HFONT hFont = CreateFontIndirect(&lf);
// Step 2: Create a temporary DC and select the font
HDC hdc = CreateCompatibleDC(nullptr);
HGDIOBJ hOldFont = SelectObject(hdc, hFont);
// Step 3: Get metrics
TEXTMETRIC tm;
GetTextMetrics(hdc, &tm);
// Calculate DLU conversion
x = tm.tmAveCharWidth;
y = tm.tmHeight;
// Clean up
SelectObject(hdc, hOldFont);
DeleteDC(hdc);
DeleteObject(hFont);
}
void CDialogTemplate::loadTemplate(CDialog *dialog) {
int base_unit_x, base_unit_y;
getBaseUnits(base_unit_x, base_unit_y);
// Set up the overall window
RECT bounds = RectToRECT(
SafeMulDiv(_header._x, base_unit_x, 4),
SafeMulDiv(_header._y, base_unit_y, 8),
SafeMulDiv(_header._x + _header._w, base_unit_x, 4),
SafeMulDiv(_header._y + _header._h, base_unit_y, 8)
);
// WORKAROUND: For Hodj n Podj Boardgame dialog
bounds.right = MIN<long>(bounds.right, 640);
bounds.bottom = MIN<long>(bounds.bottom, 480);
CWnd *wndDialog = static_cast<CWnd *>(dialog);
wndDialog->Create(_header._className.c_str(),
_header._caption.c_str(),
_header._style | WS_POPUP | WS_VISIBLE,
bounds,
dialog->m_pParentWnd,
0
);
// Iterate through the controls
for (const auto &item : _items) {
CWnd *ctl;
if (item._className == "BUTTON")
ctl = new CButton();
else if (item._className == "EDIT")
ctl = new CEdit();
else if (item._className == "STATIC")
ctl = new CStatic();
else if (item._className == "LISTBOX")
ctl = new CListBox();
else if (item._className == "SCROLLBAR")
ctl = new CScrollBar();
else
error("Unhandle dialog item - %s",
item._className.c_str());
// Convert dialog DLU to actual pixels
int x1 = SafeMulDiv(item._x, base_unit_x, 4);
int y1 = SafeMulDiv(item._y, base_unit_y, 8);
int x2 = SafeMulDiv(item._x + item._w, base_unit_x, 4);
int y2 = SafeMulDiv(item._y + item._h, base_unit_y, 8);
// Set up control
bounds = RectToRECT(x1, y1, x2, y2);
ctl->Create(item._className.c_str(),
item._title.c_str(),
item._style | WS_VISIBLE | WS_TABSTOP,
bounds,
dialog,
item._id
);
// Register the control as needing to be
// freed when the dialog is closed
dialog->_ownedControls.push_back(ctl);
if (item._style & BS_DEFPUSHBUTTON)
dialog->_defaultId = item._id;
}
// Apply the font to the window and all child controls
LOGFONT lf = ParseFontFromTemplate();
dialog->_dialogFont.CreateFontIndirect(&lf);
dialog->SendMessageToDescendants(WM_SETFONT,
(WPARAM)dialog->_dialogFont.m_hObject, 0);
// Allow the dialog to set up replacement controls
CDataExchange exchange = { false };
dialog->DoDataExchange(&exchange);
}
} // namespace Gfx
} // namespace MFC
} // namespace Bagel