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,130 @@
/* 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/>.
*
*/
/*
* Based on MacVenture engine, based on
* WebVenture (c) 2010, Sean Kasun
* https://github.com/mrkite/webventure, https://seancode.com/webventure/
*
* Used with explicit permission from the author
*/
#include "graphics/macgui/macwindowmanager.h"
#include "common/archive.h"
#include "common/compression/unzip.h"
namespace Graphics {
static const char * const MACGUI_DATA_BUNDLE = "macgui.dat";
struct BorderName {
uint32 type;
const char *name;
BorderOffsets offsets;
};
static const BorderName borders[] = {
{0x00, "StandardClose", { 1, 2, 19, 2, 2, 2, false, 25, 15, 8, 11, -1, 0, 0, 0, 0}},
{0x01, "ThickNoTitle", { 5, 5, 5, 5, -1, -1, false, 0, -1, -1, 0, -1, 0, 0, 0, 0}},
{0x02, "ThinNoTitle", { 1, 1, 1, 1, -1, -1, false, 0, -1, -1, 0, -1, 0, 0, 0, 0}},
{0x03, "ThinNoTitleShadow", { 1, 3, 1, 3, -1, -1, false, 0, -1, -1, 0, -1, 0, 0, 0, 0}},
{0x04, "StandardClose", { 1, 2, 19, 2, 2, 2, false, 25, 15, 8, 11, -1, 0, 0, 0, 0}},
{0x05, "Thick", { 5, 5, 20, 5, 2, 3, false, 13, -1, -1, 0, -1, 0, 0, 0, 0}},
{0x06, "ThinNoTitle", { 1, 1, 1, 1, -1, -1, false, 0, -1, -1, 0, -1, 0, 0, 0, 0}},
{0x07, "ThinNoTitleShadow", { 1, 3, 1, 3, -1, -1, false, 0, -1, -1, 0, -1, 0, 0, 0, 0}},
{0x08, "StandardCloseZoom", { 1, 2, 19, 2, 2, 2, false, 25, 15, 8, 11, -1, 0, 0, 0, 0}},
{0x09, "ThickZoom", { 5, 5, 20, 5, 2, 3, false, 13, -1, -1, 0, -1, 0, 0, 0, 0}},
{0x0A, "ThinNoTitle", { 1, 1, 1, 1, -1, -1, false, 0, -1, -1, 0, -1, 0, 0, 0, 0}},
{0x0B, "ThinNoTitleShadow", { 1, 3, 1, 3, -1, -1, false, 0, -1, -1, 0, -1, 0, 0, 0, 0}},
{0x0C, "StandardCloseZoom", { 1, 2, 19, 2, 2, 2, false, 25, 15, 8, 11, -1, 0, 0, 0, 0}},
{0x0D, "ThickZoom", { 5, 5, 20, 5, 2, 3, false, 13, -1, -1, 0, -1, 0, 0, 0, 0}},
{0x0E, "ThinNoTitle", { 1, 1, 1, 1, -1, -1, false, 0, -1, -1, 0, -1, 0, 0, 0, 0}},
{0x0F, "ThinNoTitleShadow", { 1, 3, 1, 3, -1, -1, false, 0, -1, -1, 0, -1, 0, 0, 0, 0}},
{0x10, "RoundClose", { 1, 1, 19, 6, 1, 1, true, 25, 15, 8, 11, -1, 0, 0, 0, 0}},
{kBorderScroll + 0x00, "Win95BorderScrollbar", { 1, 17, 1, 1, 1, 1, true, 25, -1, -1, 0, -1, 0, 15, 17, 8}},
{kBorderScroll + 0x01, "Win95NoBorderScrollbar", { 1, 17, 1, 1, 1, 1, true, 25, -1, -1, 0, -1, 0, 15, 17, 8}},
{kBorderScroll + 0x02, "MacOSNoBorderScrollbar", { 1, 17, 1, 1, 1, 1, true, 25, -1, -1, 0, -1, 0, 17, 17, 8}},
{0xFF, "No type", {-1, -1, -1, -1, -1, -1, false, 0, -1, -1, 0, -1, 0, 0, 0, 0}}
};
Common::String windowTypeName(uint32 windowType) {
int i = 0;
while (borders[i].type != 0xFF) {
if (borders[i].type == windowType) {
return borders[i].name;
}
i++;
}
return "ThinNoTitle";
}
void MacWindowManager::loadDataBundle() {
_dataBundle = Common::makeZipArchive(MACGUI_DATA_BUNDLE);
if (!_dataBundle) {
warning("MACGUI: Couldn't load data bundle '%s'.", MACGUI_DATA_BUNDLE);
}
}
void MacWindowManager::cleanupDataBundle() {
delete _dataBundle;
}
const BorderOffsets &MacWindowManager::getBorderOffsets(uint32 windowType) {
int i = 0;
while (borders[i].type != 0xFF) {
if (borders[i].type == windowType)
break;
i++;
}
return borders[i].offsets;
}
Common::SeekableReadStream *MacWindowManager::getBorderFile(uint32 windowType, uint32 flags) {
if (!_dataBundle)
return NULL;
Common::String filename = windowTypeName(windowType);
filename += (flags & kWindowBorderActive) ? "_act" : "_inac";
filename += (flags & kWindowBorderTitle) ? "_title" : "";
filename += ".bmp";
Common::Path path(filename, Common::Path::kNoSeparator);
if (!_dataBundle->hasFile(path)) {
warning("Missing border file '%s' in data bundle", filename.c_str());
return NULL;
}
return _dataBundle->createReadStreamForMember(path);
}
Common::SeekableReadStream *MacWindowManager::getFile(const Common::Path &filename) {
if (!_dataBundle)
return NULL;
if (!_dataBundle->hasFile(filename)) {
warning("Missing file '%s' in data bundle", filename.toString().c_str());
return NULL;
}
return _dataBundle->createReadStreamForMember(filename);
}
} // End of namespace Graphics

View File

@@ -0,0 +1,245 @@
/* 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/timer.h"
#include "common/system.h"
#include "graphics/primitives.h"
#include "graphics/macgui/macwindowmanager.h"
#include "graphics/macgui/macfontmanager.h"
#include "graphics/macgui/macmenu.h"
#include "graphics/macgui/macbutton.h"
#include "graphics/macgui/macwidget.h"
#include "graphics/macgui/macwindow.h"
namespace Graphics {
MacButton::MacButton(MacButtonType buttonType, TextAlign textAlignment, MacWidget *parent, int x, int y, int w, int h, MacWindowManager *wm, const Common::U32String &s, const MacFont *macFont, int fgcolor, int bgcolor) :
MacText(parent, x, y, w, h, wm, s, macFont, fgcolor, bgcolor, w, textAlignment), _pd(Graphics::MacPlotData(_composeSurface, nullptr, &_wm->getPatterns(), 1, 0, 0, 1, bgcolor, true)) {
_buttonType = buttonType;
init();
}
void MacButton::init() {
_invertInner = false;
_checkBoxType = 0;
_checkBoxAccess = 0;
switch (_buttonType) {
case kCheckBox:
_dims.right += 16;
break;
case kRound:
_dims.right += 4;
_dims.bottom += 4;
break;
case kRadio:
_dims.right += 16;
break;
}
_composeSurface->create(_dims.width(), _dims.height(), _wm->_pixelformat);
_composeSurface->clear(_bgcolor);
}
void MacButton::setActive(bool active) {
if (active == _active)
return;
MacWidget::setActive(active);
if (_composeSurface)
_contentIsDirty = true;
}
// whether to use getDrawPrimitives or getDrawInvertPrimitives to draw invert pixel, maybe depends on the pattle we are using
void MacButton::invertOuter() {
Common::Rect r(_dims.width() - 1, _dims.height() - 1);
Primitives &primitives = _wm->getDrawPrimitives();
switch (_buttonType) {
case kCheckBox: {
Common::Rect c = Common::Rect(r.left + 1, r.top + 3, r.left + 9, r.top + 11);
primitives.drawRect1(c, _wm->_colorWhite, &_pd);
break;
}
case kRound:
primitives.drawRoundRect1(r, 4, _wm->_colorWhite, true, &_pd);
break;
case kRadio:
primitives.drawEllipse(r.left + 1, r.top + 3, r.left + 10, r.top + 12, _wm->_colorWhite, false, &_pd);
break;
}
}
void MacButton::setCheckBoxType(int type) {
if (_checkBoxType == type)
return;
_checkBoxType = type;
_contentIsDirty = true;
}
void MacButton::invertInner() {
Common::Rect r(_dims.width() - 1, _dims.height() - 1);
Common::Rect checkbox;
Primitives &primitives = _wm->getDrawPrimitives();
switch (_buttonType) {
case kCheckBox:
switch (_checkBoxType) {
case kCBNormal:
primitives.drawLine(r.left + 1, r.top + 3, r.left + 9, r.top + 11, _wm->_colorWhite, &_pd);
primitives.drawLine(r.left + 1, r.top + 11, r.left + 9, r.top + 3, _wm->_colorWhite, &_pd);
primitives.drawPoint(5, 7, _wm->_colorWhite, &_pd);
break;
case kCBInsetBlack:
checkbox = Common::Rect(r.left + 2, r.top + 4, r.left + 2 + 6, r.top + 4 + 6);
primitives.drawFilledRect1(checkbox, _wm->_colorWhite, &_pd);
break;
case kCBFilledBlack:
checkbox = Common::Rect(r.left + 1, r.top + 3, r.left + 1 + 8, r.top + 3 + 8);
primitives.drawFilledRect1(checkbox, _wm->_colorWhite, &_pd);
break;
}
break;
case kRound:
break;
case kRadio:
primitives.drawEllipse(r.left + 3, r.top + 5, r.left + 8, r.top + 10, 0, true, &_pd);
break;
}
}
void MacButton::setHilite(bool hilite) {
if (hilite == _invertInner)
return;
_invertInner = hilite;
_contentIsDirty = true;
}
bool MacButton::draw(bool forceRedraw) {
if (!_contentIsDirty && !forceRedraw)
return false;
MacText::draw();
Common::Rect r(_dims.width() - 1, _dims.height() - 1);
Graphics::MacPlotData pd(_composeSurface, nullptr, &_wm->getPatterns(), 1, 0, 0, 1, 0);
Primitives &primitives = _wm->getDrawPrimitives();
switch (_buttonType) {
case kCheckBox: {
Common::Rect c = Common::Rect(r.left, r.top + 2, r.left + 10, r.top + 2 + 10);
primitives.drawRect1(c, _wm->_colorBlack, &pd);
break;
}
case kRound:
primitives.drawRoundRect1(r, 4, _wm->_colorBlack, false, &pd);
break;
case kRadio:
primitives.drawEllipse(r.left, r.top + 2, r.left + 11, r.top + 13, _wm->_colorBlack, false, &pd);
break;
}
if (_active)
invertOuter();
if (_invertInner)
invertInner();
return true;
}
bool MacButton::draw(ManagedSurface *g, bool forceRedraw) {
if (!MacButton::draw(forceRedraw))
return false;
g->transBlitFrom(*_composeSurface, _composeSurface->getBounds(), Common::Point(_dims.left, _dims.top), _wm->_colorGreen2);
return true;
}
bool MacButton::processEvent(Common::Event &event) {
switch (event.type) {
case Common::EVENT_MOUSEMOVE:
if (_wm->_mouseDown) {
if (_wm->_mode & kWMModeButtonDialogStyle)
return true;
else if (!_wm->_hilitingWidget)
return true;
// hovered widget in macwindow will help us set the button status to non-active.
// so we only care about setting active here is ok.
setActive(true);
}
break;
case Common::EVENT_LBUTTONDOWN:
setActive(true);
_wm->_hilitingWidget = true;
break;
case Common::EVENT_LBUTTONUP:
setActive(false);
switch (_checkBoxAccess) {
case 0:
_invertInner = !_invertInner;
break;
case 1:
_invertInner = true;
break;
case 2:
// no op, type 2 will prevent user from setting checkboxes
break;
default:
warning("MacButton::processEvent can not handle checkBoxAccess with type %d", _checkBoxAccess);
break;
}
_wm->_hilitingWidget = false;
break;
default:
warning("MacButton:: processEvent: Event not handled");
}
return false;
}
// we won't have the text with _border and _gutter in macbutton now.
// so for the override of calculateOffset, we are passing the border and gutter which depends on buttonType
// maybe we can cache this for optimization
Common::Point MacButton::calculateOffset() {
int x = 0, y = 0;
switch (_buttonType) {
case kCheckBox:
x = 16;
break;
case kRound:
x = 2;
y = 2;
break;
case kRadio:
x = 16;
break;
}
return Common::Point(x, y);
}
} // End of namespace Graphics

View File

@@ -0,0 +1,78 @@
/* 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 GRAPHICS_MACGUI_MACBUTTON_H
#define GRAPHICS_MACGUI_MACBUTTON_H
#include "graphics/macgui/mactext.h"
#include "graphics/macgui/macwidget.h"
namespace Graphics {
class MacWidget;
class MacText;
struct MacPlotData;
enum MacButtonType {
kRound,
kCheckBox,
kRadio
};
// those name comes from Apartment
enum CheckBoxType {
kCBNormal,
kCBInsetBlack,
kCBFilledBlack
};
class MacButton : public MacText {
public:
MacButton(MacButtonType buttonType, TextAlign textAlignment, MacWidget *parent, int x, int y, int w, int h, MacWindowManager *wm, const Common::U32String &s, const MacFont *macFont, int fgcolor, int bgcolor);
void setActive(bool active) override;
void invertOuter();
void invertInner();
void setHilite(bool hilite);
void setCheckBoxType(int type);
void setCheckBoxAccess(int type) { _checkBoxAccess = type; }
bool draw(ManagedSurface *g, bool forceRedraw = false) override;
bool draw(bool forceRedraw = false) override;
bool processEvent(Common::Event &event) override;
Common::Point calculateOffset() override;
private:
void init();
private:
MacButtonType _buttonType;
MacPlotData _pd;
bool _invertInner;
int _checkBoxType;
int _checkBoxAccess;
};
} // End of namespace Graphics
#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/>.
*
* MIT License:
*
* Copyright (c) 2009 Alexei Svitkine, Eugene Sandulenko
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "common/events.h"
#include "common/system.h"
#include "graphics/font.h"
#include "graphics/managed_surface.h"
#include "graphics/primitives.h"
#include "graphics/macgui/mactext.h"
#include "graphics/macgui/macfontmanager.h"
#include "graphics/macgui/macwindowmanager.h"
#include "graphics/macgui/macdialog.h"
namespace Graphics {
enum {
kDialogHeight = 113,
kDialogBottomPadding = 15
};
MacDialog::MacDialog(ManagedSurface *screen, MacWindowManager *wm, int width, MacText *mactext, int maxTextWidth, MacDialogButtonArray *buttons, uint defaultButton) :
_screen(screen), _wm(wm), _mactext(mactext), _maxTextWidth(maxTextWidth), _buttons(buttons), _defaultButton(defaultButton) {
// if we have buttons the height of the dialog box should resize accordingly
int buttonBottomPos = 0;
if (_buttons) {
for (uint i = 0; i < _buttons->size(); i++) {
if ((*_buttons)[i]->bounds.bottom > buttonBottomPos)
buttonBottomPos = (*_buttons)[i]->bounds.bottom;
}
}
int height;
if (buttonBottomPos > 0)
height = buttonBottomPos + kDialogBottomPadding;
else
height = kDialogHeight + _mactext->getTextHeight();
_font = getDialogFont();
_tempSurface = new ManagedSurface();
_tempSurface->create(width + 1, height + 1, Graphics::PixelFormat::createFormatCLUT8());
_bbox.left = (_screen->w - width) / 2;
_bbox.top = (_screen->h - height) / 2;
_bbox.right = (_screen->w + width) / 2;
_bbox.bottom = (_screen->h + height) / 2;
_pressedButton = -1;
_mouseOverButton = -1;
_mouseOverPressedButton = false;
// Adjust button positions
for (uint i = 0; i < _buttons->size(); i++)
_buttons->operator[](i)->bounds.translate(_bbox.left, _bbox.top);
_needsRedraw = true;
}
MacDialog::~MacDialog() {
for (uint i = 0; i < _buttons->size(); i++)
delete _buttons->operator[](i);
delete _tempSurface;
}
const Graphics::Font *MacDialog::getDialogFont() {
return _wm->_fontMan->getFont(Graphics::MacFont(Graphics::kMacFontSystem, 12));
}
void MacDialog::paint() {
if (!_needsRedraw)
return;
Primitives &primitives = _wm->getDrawPrimitives();
MacPlotData pd(_screen, nullptr, &_wm->getPatterns(), 1, 0, 0, 1, _wm->_colorBlack, false);
primitives.drawFilledRect1(_bbox, kColorWhite, &pd);
_mactext->drawToPoint(_screen, Common::Point(_bbox.left + (_bbox.width() - _maxTextWidth)/2, _bbox.top + 16));
static int boxOutline[] = {1, 0, 0, 1, 1};
drawOutline(_bbox, boxOutline, ARRAYSIZE(boxOutline));
for (uint i = 0; i < _buttons->size(); i++) {
MacDialogButton *button = _buttons->operator[](i);
static int buttonOutline[] = {0, 0, 0, 0, 1};
if (i == _defaultButton) {
buttonOutline[0] = buttonOutline[1] = 1;
} else {
buttonOutline[0] = buttonOutline[1] = 0;
}
int color = kColorBlack;
if ((int)i == _pressedButton && _mouseOverPressedButton) {
Common::Rect bb(button->bounds.left + 5, button->bounds.top + 5,
button->bounds.right - 5, button->bounds.bottom - 5);
primitives.drawFilledRect1(bb, kColorBlack, &pd);
color = kColorWhite;
}
int w = _font->getStringWidth(button->text);
int x = button->bounds.left + (button->bounds.width() - w) / 2;
int y = button->bounds.top + 6;
_font->drawString(_screen, button->text, x, y, _bbox.width(), color);
drawOutline(button->bounds, buttonOutline, ARRAYSIZE(buttonOutline));
}
_needsRedraw = false;
}
void MacDialog::blit() {
paint();
g_system->copyRectToScreen(_screen->getBasePtr(_bbox.left, _bbox.top), _screen->pitch,
_bbox.left, _bbox.top, _bbox.width() + 1, _bbox.height() + 1);
}
void MacDialog::drawOutline(Common::Rect &bounds, int *spec, int speclen) {
Primitives &primitives = _wm->getDrawPrimitives();
MacPlotData pd(_screen, nullptr, &_wm->getPatterns(), 1, 0, 0, 1, _wm->_colorBlack, false);
for (int i = 0; i < speclen; i++)
if (spec[i] != 0) {
Common::Rect r(bounds.left + i, bounds.top + i, bounds.right - i, bounds.bottom - i);
primitives.drawRect1(r, kColorBlack, &pd);
}
}
int MacDialog::run() {
bool shouldQuitEngine = false;
bool shouldQuit = false;
Common::Rect r(_bbox);
// we set _fullRefresh to true inside closeMenu() but it does not update the screen
// to ensure we capture the background without the menu we must force a draw
// draw() checks _fullRefresh flag which is set to true by closeMenu()
// so draw() will draw the screen again without the menu pixels
// if we don't call draw() then the background captured in the next line has the pixels of the menu.
_wm->draw();
_tempSurface->copyRectToSurface(_screen->getBasePtr(_bbox.left, _bbox.top), _screen->pitch, 0, 0, _bbox.width() + 1, _bbox.height() + 1);
_wm->pushCursor(kMacCursorArrow, nullptr);
while (!shouldQuit) {
Common::Event event;
while (g_system->getEventManager()->pollEvent(event)) {
if (processEvent(event))
continue;
switch (event.type) {
case Common::EVENT_QUIT:
shouldQuitEngine = true;
shouldQuit = true;
break;
case Common::EVENT_MOUSEMOVE:
mouseMove(event.mouse.x, event.mouse.y);
break;
case Common::EVENT_LBUTTONDOWN:
mouseClick(event.mouse.x, event.mouse.y);
break;
case Common::EVENT_LBUTTONUP:
shouldQuit = mouseRaise(event.mouse.x, event.mouse.y);
break;
case Common::EVENT_KEYDOWN:
switch (event.kbd.keycode) {
case Common::KEYCODE_ESCAPE:
_pressedButton = -1;
shouldQuit = true;
default:
break;
}
break;
default:
break;
}
}
if (_needsRedraw)
blit();
g_system->updateScreen();
g_system->delayMillis(50);
}
_screen->copyRectToSurface(_tempSurface->getBasePtr(0, 0), _tempSurface->pitch, _bbox.left, _bbox.top, _bbox.width() + 1, _bbox.height() + 1);
g_system->copyRectToScreen(_screen->getBasePtr(r.left, r.top), _screen->pitch, r.left, r.top, r.width() + 1, r.height() + 1);
_wm->popCursor();
if (shouldQuitEngine)
return kMacDialogQuitRequested;
return _pressedButton;
}
int MacDialog::matchButton(int x, int y) {
for (uint i = 0; i < _buttons->size(); i++)
if (_buttons->operator[](i)->bounds.contains(x, y))
return i;
return -1;
}
void MacDialog::mouseMove(int x, int y) {
int match = matchButton(x, y);
if (_pressedButton != -1) {
if (_mouseOverPressedButton && match != _pressedButton) {
_mouseOverPressedButton = false;
_needsRedraw = true;
} else if (!_mouseOverPressedButton && match == _pressedButton) {
_mouseOverPressedButton = true;
_needsRedraw = true;
}
}
if (_mouseOverButton != match) {
_mouseOverButton = match;
if (match != -1) {
_wm->sayText(_buttons->operator[](match)->text);
}
}
}
void MacDialog::mouseClick(int x, int y) {
int match = matchButton(x, y);
if (match != -1) {
_pressedButton = match;
_mouseOverPressedButton = true;
_needsRedraw = true;
}
}
int MacDialog::mouseRaise(int x, int y) {
bool res = false;
if (_pressedButton != -1) {
if (matchButton(x, y) == _pressedButton)
res = true;
}
return res;
}
} // End of namespace Graphics

126
graphics/macgui/macdialog.h Normal file
View File

@@ -0,0 +1,126 @@
/* 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/>.
*
* MIT License:
*
* Copyright (c) 2009 Alexei Svitkine, Eugene Sandulenko
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef GRAPHICS_MACGUI_MACDIALOG_H
#define GRAPHICS_MACGUI_MACDIALOG_H
#include "common/str.h"
#include "common/rect.h"
namespace Common {
struct Event;
}
namespace Graphics {
class Font;
class ManagedSurface;
class MacText;
class MacWindowManager;
enum {
kMacDialogQuitRequested = -2
};
struct MacDialogButton {
Common::String text;
Common::Rect bounds;
MacDialogButton(const char *t, int x1, int y1, int w, int h) {
text = t;
bounds.left = x1;
bounds.top = y1;
bounds.right = x1 + w - 1;
bounds.bottom = y1 + h - 1;
}
};
typedef Common::Array<MacDialogButton *> MacDialogButtonArray;
class MacDialog {
public:
MacDialog(ManagedSurface *screen, MacWindowManager *wm, int width, MacText *mactext, int maxTextWidth, MacDialogButtonArray *buttons, uint defaultButton);
virtual ~MacDialog();
int run();
virtual bool processEvent(const Common::Event &event) { return false; }
protected:
ManagedSurface *_screen;
MacWindowManager *_wm;
ManagedSurface *_tempSurface;
Common::Rect _bbox;
Common::Rect _r;
MacText *_mactext;
int _maxTextWidth;
const Font *_font;
MacDialogButtonArray *_buttons;
uint _defaultButton;
bool _mouseOverPressedButton;
int _mouseOverButton;
public:
int _pressedButton;
bool _needsRedraw;
private:
const Font *getDialogFont();
void drawOutline(Common::Rect &bounds, int *spec, int speclen);
public:
virtual void paint();
void blit();
void mouseMove(int x, int y);
void mouseClick(int x, int y);
int mouseRaise(int x, int y);
int matchButton(int x, int y);
};
} // End of namespace Graphics
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,242 @@
/* 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 GRAPHICS_MACGUI_MACFONTMANAGER_H
#define GRAPHICS_MACGUI_MACFONTMANAGER_H
#include "common/language.h"
#include "graphics/fonts/bdf.h"
#include "graphics/fontman.h"
namespace Common {
class SeekableReadStream;
class MacResManager;
}
namespace Graphics {
struct TTFMap {
const char *ttfName;
uint16 slant;
};
class MacFONTFont;
class MacFontFamily;
enum {
kMacFontNonStandard = -1,
kMacFontSystem = 0,
kMacFontApplication = 1,
kMacFontNewYork = 2,
kMacFontGeneva = 3,
kMacFontMonaco = 4,
kMacFontVenice = 5,
kMacFontLondon = 6,
kMacFontAthens = 7,
kMacFontSanFrancisco = 8,
kMacFontToronto = 9,
kMacFontCairo = 11,
kMacFontLosAngeles = 12,
kMacFontZapfDingbats = 13,
kMacFontBookman = 14,
kMacFontHelveticaNarrow = 15,
kMacFontPalatino = 16,
kMacFontZapfChancery = 18,
kMacFontTimes = 20,
kMacFontHelvetica = 21,
kMacFontCourier = 22,
kMacFontSymbol = 23,
kMacFontTaliesin = 24,
kMacFontAvantGarde = 33,
kMacFontNewCenturySchoolbook = 34,
kMacFontChicago = 16383,
kMacFontOsaka = 16384,
kMacFontBookMinchoM = 16396,
kMacFontMonoGothic = 16433,
kMacFontMonoMing = 16435,
kMacFontOsakaMono = 16436,
kMacFontMediumGothic = 16640,
kMacFontMing = 16641,
kMacFontHeiseiMincho = 16700,
kMacFontHeiseiKakuGothic = 16701
};
enum {
kMacFontRegular,
kMacFontBold = 1,
kMacFontItalic = 2,
kMacFontUnderline = 4,
kMacFontOutline = 8,
kMacFontShadow = 16,
kMacFontCondense = 32,
kMacFontExtend = 64
};
class Font;
struct FontInfo {
Common::Language lang;
Common::CodePage encoding;
int aliasForId;
Common::String name;
FontInfo() : lang(Common::UNK_LANG), encoding(Common::kCodePageInvalid), aliasForId(-1) {}
};
class MacFont {
public:
MacFont(int id = kMacFontSystem, int size = 12, int slant = kMacFontRegular) {
_id = id;
_size = size ? size : 12;
_slant = slant;
_fallback = FontMan.getFontByUsage(Graphics::FontManager::kBigGUIFont);
_fallbackName = Common::String(((const BdfFont *)_fallback)->getFamilyName());
_generated = false;
_truetype = false;
_font = NULL;
}
int getId() const { return _id; };
void setId(int id) { _id = id; }
int getSize() const { return _size; }
int getSlant() const { return _slant; }
Common::String getName() const { return _name; }
void setName(Common::String &name) { setName(name.c_str()); }
void setName(const char *name);
const Graphics::Font *getFallback() const { return _fallback; }
bool isGenerated() const { return _generated; }
void setGenerated(bool gen) { _generated = gen; }
bool isTrueType() const { return _truetype; }
Font *getFont() const { return _font; }
void setFont(Font *font, bool truetype) { _font = font; _truetype = truetype; }
void setFallback(const Font *font, Common::String name = "");
Common::String getFallbackName() const { return _fallbackName; }
private:
int _id;
int _size;
int _slant;
bool _truetype;
Common::String _name;
const Graphics::Font *_fallback;
Common::String _fallbackName;
bool _generated;
Font *_font;
};
class MacFontManager {
public:
MacFontManager(uint32 mode, Common::Language language);
~MacFontManager();
void setLocalizedFonts();
/**
* Accessor method to check the presence of built-in fonts.
* @return True if there are bult-in fonts.
*/
bool hasBuiltInFonts() { return _builtInFonts; }
/**
* Retrieve a font from the available ones.
* @param name Name of the desired font.
* @param fallback Fallback policy in case the desired font isn't there.
* @return The requested font or the fallback.
*/
const Font *getFont(MacFont *macFont);
const Font *getFont(MacFont macFont);
/**
* Return font name from standard ID
* @param id ID of the font
* @param size size of the font
* @return the font name or NULL if ID goes beyond the mapping
*/
const Common::String getFontName(uint16 id, int size, int slant = kMacFontRegular, bool tryGen = false);
const Common::String getFontName(const MacFont &font);
int getFontIdByName(Common::String name);
Common::Language getFontLanguage(uint16 id);
Common::CodePage getFontEncoding(uint16 id);
int getFontAliasForId(uint16 id);
Common::String getFontName(uint16 id);
void loadFonts(Common::SeekableReadStream *stream);
void loadFonts(const Common::Path &fileName);
void loadFonts(Common::MacResManager *fontFile);
void loadWindowsFont(const Common::Path &fileName);
/**
* Register a font name if it doesn't already exist.
* @param name name of the font
* @return the font's ID
*/
int registerFontName(Common::String name, int preferredId = -1);
void forceBuiltinFonts() { _builtInFonts = true; }
int parseSlantFromName(const Common::String &name);
Common::String getNameFromSlant(int slantVal);
const Common::Array<MacFontFamily *> &getFontFamilies() { return _fontFamilies; }
void printFontRegistry(int debugLevel, uint32 channel);
int registerTTFFont(const Graphics::TTFMap ttfList[]);
int getFamilyId(int newId, int newSlant);
private:
void loadFontsBDF();
void loadFonts();
void loadJapaneseFonts();
void generateFontSubstitute(MacFont &macFont);
void generateFONTFont(MacFont &toFont, MacFont &fromFont);
#ifdef USE_FREETYPE2
void generateTTFFont(MacFont &toFront, Common::SeekableReadStream *stream);
#endif
private:
bool _builtInFonts;
bool _japaneseFontsLoaded;
uint32 _mode;
Common::Language _language;
Common::HashMap<Common::String, Graphics::Font *> _winFontRegistry;
Common::HashMap<Common::String, MacFont *> _fontRegistry;
Common::Array<MacFontFamily *> _fontFamilies;
Common::HashMap<int, FontInfo *> _fontInfo;
Common::HashMap<Common::String, int> _fontIds;
int parseFontSlant(Common::String slant);
/* Unicode font */
Common::HashMap<Common::String, const Graphics::Font *> _uniFontRegistry;
Common::HashMap<Common::String, Common::SeekableReadStream *> _ttfData;
};
} // End of namespace Graphics
#endif

1759
graphics/macgui/macmenu.cpp Normal file

File diff suppressed because it is too large Load Diff

246
graphics/macgui/macmenu.h Normal file
View File

@@ -0,0 +1,246 @@
/* 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 GRAPHICS_MACGUI_MACMENU_H
#define GRAPHICS_MACGUI_MACMENU_H
#include "common/str-array.h"
#include "graphics/macgui/macfontmanager.h"
#include "graphics/macgui/macwindow.h"
#include "graphics/font.h"
namespace Common {
class U32String;
class MacResManager;
class PEResources;
}
namespace Graphics {
struct MacMenuItem;
struct MacMenuSubMenu;
typedef Common::Array<MacMenuItem *> ItemArray;
struct MacMenuSubMenu {
ItemArray items;
Common::Rect bbox;
int highlight;
int visStart; // Visible start
int visEnd; // Visible end
int scroll;
MacMenuSubMenu() : highlight(-1), visStart(0), visEnd(0), scroll(0) {}
~MacMenuSubMenu();
void enableAllItems();
int ytoItem(int y, int itemHeight) { return MIN<int>((y - bbox.top) / itemHeight, items.size() - 1); }
};
struct MacMenuItem {
Common::String text;
Common::U32String unicodeText;
bool unicode;
int action;
int style;
char shortcut;
int shortcutPos;
bool enabled;
bool checked;
Common::Rect bbox;
MacMenuSubMenu *submenu;
MacMenuItem(const Common::String &t, int a = -1, int s = 0, char sh = 0, int sp = -1, bool e = true, bool c = false) :
text(t), unicode(false), action(a), style(s), shortcut(sh),
shortcutPos(sp), enabled(e), submenu(nullptr), checked(c) {}
MacMenuItem(const Common::U32String &t, int a = -1, int s = 0, char sh = 0, int sp = -1, bool e = true, bool c = false) :
unicodeText(t), unicode(true), action(a), style(s), shortcut(sh),
shortcutPos(sp), enabled(e), submenu(nullptr), checked(c) {}
~MacMenuItem() {
if (submenu)
delete submenu;
}
};
struct MacMenuData {
int menunum;
const char *title;
int action;
byte shortcut;
bool enabled;
};
class MacMenu : public BaseMacWindow {
public:
MacMenu(int id, const Common::Rect &bounds, MacWindowManager *wm);
~MacMenu();
ManagedSurface *getBorderSurface() override { return nullptr; }
const Common::Rect &getInnerDimensions() override { return _dims; }
bool isDirty() override { return _contentIsDirty || _dimensionsDirty; }
static Common::StringArray *readMenuFromResource(Common::SeekableReadStream *res);
static MacMenu *createMenuFromPEexe(Common::PEResources *exe, MacWindowManager *wm);
void setAlignment(Graphics::TextAlign align);
void setCommandsCallback(void (*callback)(int, Common::String &, void *), void *data) { _ccallback = callback; _cdata = data; }
void setCommandsCallback(void (*callback)(int, Common::U32String &, void *), void *data) { _unicodeccallback = callback; _cdata = data; }
void addStaticMenus(const MacMenuData *data);
void calcDimensions();
int numberOfMenus();
int numberOfMenuItems(MacMenuItem *menu);
MacMenuItem *getMenuItem(int menuId);
MacMenuItem *getMenuItem(const Common::String &menuId);
MacMenuItem *getSubMenuItem(MacMenuItem *menu, int itemId);
MacMenuItem *getSubMenuItem(MacMenuItem *menu, const Common::String &itemId);
MacMenuSubMenu *addSubMenu(MacMenuSubMenu *submenu, int index = -1);
int addMenuItem(MacMenuSubMenu *submenu, const Common::String &text, int action = -1, int style = 0, char shortcut = 0, bool enabled = true, bool checked = false);
int addMenuItem(MacMenuSubMenu *submenu, const Common::U32String &text, int action = 0, int style = 0, char shortcut = 0, bool enabled = true, bool checked = false);
void insertMenuItem(MacMenuSubMenu *submenu, const Common::String &text, uint pos, int action = -1, int style = 0, char shortcut = 0, bool enabled = true, bool checked = false);
void insertMenuItem(MacMenuSubMenu *submenu, const Common::U32String &text, uint pos, int action = 0, int style = 0, char shortcut = 0, bool enabled = true, bool checked = false);
void removeMenuItem(MacMenuSubMenu *submenu, uint pos);
void loadMenuResource(Common::MacResManager *resFork, uint16 id);
void loadMenuBarResource(Common::MacResManager *resFork, uint16 id);
void createSubMenuFromString(int id, const char *string, int commandId);
void clearSubMenu(int id);
MacMenuSubMenu *getSubmenu(MacMenuSubMenu *submenu, int index);
bool draw(ManagedSurface *g, bool forceRedraw = false) override;
void eventLoop();
bool mouseClick(int x, int y);
bool draw(bool forceRedraw = false) override { return false; }
void blit(ManagedSurface *g, Common::Rect &dest) override {}
bool processEvent(Common::Event &event) override;
void enableCommand(int menunum, int action, bool state);
void enableCommand(const char *menuitem, const char *menuaction, bool state);
void enableCommand(const Common::U32String &menuitem, const Common::U32String &menuaction, bool state);
void enableAllMenus();
void disableAllMenus();
bool isVisible() { return _isVisible; }
void setVisible(bool visible, bool silent = false) override { _isVisible = visible; _contentIsDirty = true; }
void printMenu(int level = 0, MacMenuSubMenu *submenu = nullptr);
virtual void closeMenu();
bool checkIntersects(Common::Rect &rect);
// macmenuItem operations
void setCheckMark(MacMenuItem *menuItem, bool checkMark);
bool getCheckMark(MacMenuItem *menuItem);
void setEnabled(MacMenuItem *menuItem, bool enabled);
bool getEnabled(MacMenuItem *menuItem);
void setName(MacMenuItem *menuItem, const Common::String &name);
Common::String getName(MacMenuItem *menuItem);
void setAction(MacMenuItem *menuItem, int actionId);
int getAction(MacMenuItem *menuItem);
int getLastSelectedMenuItem() { return _lastActiveItem; };
int getLastSelectedSubmenuItem() { return _lastActiveSubItem; };
void renderSubmenu(MacMenuSubMenu *menu, bool recursive = true);
int getScrollDirection() { return _scrollDirection; }
int getDropdownItemHeight() { return _menuDropdownItemHeight; }
Common::Array<MacMenuSubMenu *> _menustack;
protected:
Common::Rect _bbox;
ManagedSurface _screen;
ItemArray _items;
bool _isVisible;
bool _dimensionsDirty;
int _menuDropdownItemHeight;
int _activeItem;
int _activeSubItem;
bool _isModal;
void calcSubMenuBounds(MacMenuSubMenu *menu, int x, int y);
private:
ManagedSurface _tempSurface;
TextAlign _align;
int _menuLeftDropdownPadding;
int _menuRightDropdownPadding;
private:
bool checkCallback(bool unicode = false);
const Font *getMenuFont(int slant = kMacFontRegular);
Common::CodePage getMenuEncoding() const;
const Common::String getAcceleratorString(MacMenuItem *item, const char *prefix);
void processTabs();
void processSubmenuTabs(MacMenuSubMenu *submenu);
int calcSubMenuWidth(MacMenuSubMenu *menu);
bool keyEvent(Common::Event &event);
bool mouseRelease(int x, int y);
bool mouseMove(int x, int y);
bool processMenuShortCut(uint16 ascii);
void drawSubMenuArrow(ManagedSurface *dst, int x, int y, int color);
bool contains(int x, int y);
void drawScrollArrow(int arrowX, int arrowY, int direction);
MacMenuItem *findMenuItem(const Common::String &menuId, const Common::String &itemId);
MacMenuItem *findMenuItem(int menuId, int itemId);
const Font *_font;
Font *_loadedFont;
int _lastActiveItem;
int _lastActiveSubItem;
int _selectedItem;
bool _scrollTimerActive;
int _scrollDirection;
void (*_ccallback)(int action, Common::String &text, void *data);
void (*_unicodeccallback)(int action, Common::U32String &text, void *data);
void *_cdata;
};
} // End of namespace Graphics
#endif

View File

@@ -0,0 +1,168 @@
/* 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/macgui/macpopupmenu.h"
#include "graphics/macgui/macwindowmanager.h"
namespace Graphics {
MacPopUp::MacPopUp(int id, const Common::Rect &bounds, MacWindowManager *wm, const char *string) : MacMenu(id, bounds, wm) {
_menuItemId = addMenuItem(nullptr, "");
createSubMenuFromString(0, string, 0);
wm->addMenu(id, this);
_menuId = id;
}
bool MacPopUp::draw(ManagedSurface *g, bool forceRedraw) {
if (!_isVisible)
return false;
if (_dimensionsDirty)
calcSubMenuBounds(_items[0]->submenu, _mouseX, _mouseY + _offsetY);
if (!_contentIsDirty && !forceRedraw)
return false;
_contentIsDirty = false;
_screen.clear(_wm->_colorGreen);
renderSubmenu(_items[0]->submenu, false);
if (g)
g->transBlitFrom(_screen, _wm->_colorGreen);
if (!(_wm->_mode & kWMModalMenuMode) && g)
g_system->copyRectToScreen(g->getPixels(), g->pitch, 0, 0, g->w, g->h);
return true;
}
void MacPopUp::closeMenu() {
// Special handling of popup closing (for example when displaying closing animation)
int activeSubItem = getLastSelectedSubmenuItem(); // Find selected item
if (activeSubItem != -1) {
// Do the blinking animation
for (int i = 0; i < kNumBlinks; i++) {
_items[0]->submenu->highlight = -1; // No selection
draw(_wm->_screen, true);
g_system->updateScreen();
g_system->delayMillis(kBlinkDelay);
_items[0]->submenu->highlight = activeSubItem; // Selection
draw(_wm->_screen, true);
g_system->updateScreen();
g_system->delayMillis(kBlinkDelay);
}
}
if (_isSmart && activeSubItem != -1) {
// Smart menu, open menu at offset position (so selected item under cursor)
int yDisplace = -activeSubItem * _menuDropdownItemHeight;
_offsetY = _mouseY + yDisplace > 0 ? yDisplace : -_mouseY; // If offset sum gets out of window, then position menu to 0 (ie below top of window)
// Checkmark handling
setCheckMark(_items[0]->submenu->items[activeSubItem], true);
// // Uncheck previous item if checked
if (_prevCheckedItem != -1 && _prevCheckedItem != activeSubItem) {
setCheckMark(_items[0]->submenu->items[_prevCheckedItem], false);
}
_prevCheckedItem = activeSubItem;
}
_isModal = false;
// Close now
MacMenu::closeMenu();
}
uint32 MacPopUp::drawAndSelectMenu(int x, int y, int item) {
_mouseX = x;
_mouseY = y;
// If menu is not active, then activate it!
if (!_active)
_wm->activateMenu();
setActive(true);
_contentIsDirty = true; // Set true to force refresh menu open changes
_isModal = true;
// Push our submenu to stack
_menustack.clear();
_menustack.push_back(_items[0]->submenu);
_items[0]->submenu->visStart = 0;
_items[0]->submenu->visEnd = 0;
_items[0]->submenu->scroll = 0;
_offsetY = 0;
if (_isSmart) {
int activeSubItem = getLastSelectedSubmenuItem();
if (activeSubItem != -1)
_offsetY = -activeSubItem * _menuDropdownItemHeight;
else if (_prevCheckedItem != -1)
_offsetY = -_prevCheckedItem * _menuDropdownItemHeight;
while (_offsetY + _mouseY < 0) {
_offsetY += _menuDropdownItemHeight;
_items[0]->submenu->visStart++;
}
int itemsLeft = _items[0]->submenu->items.size() - _items[0]->submenu->visStart;
int spaceLeft = _screen.h - MIN(_mouseY + _offsetY, _mouseY);
_items[0]->submenu->visEnd = MAX(0, itemsLeft - spaceLeft / _menuDropdownItemHeight);
}
// Highlight previous item if smart menu
if (_isSmart && getLastSelectedSubmenuItem() != -1) {
_activeItem = 0;
_activeSubItem = getLastSelectedSubmenuItem();
// Also select the item
_items[0]->submenu->highlight = getLastSelectedSubmenuItem();
}
// Display menu and update according to events
this->draw(_wm->_screen);
eventLoop();
int activeSubItem = getLastSelectedSubmenuItem();
if (activeSubItem == -1)
return item;
// Return one indexed item!
return activeSubItem + 1;
}
Common::String MacPopUp::getItemText(int item) {
// Convert 1-indexed item to 0 indexed
item = item - 1;
MacMenuItem *menu = getMenuItem(_menuItemId);
MacMenuItem *submenu = getSubMenuItem(menu, item);
return getName(submenu);
}
} // end of namespace Graphics

View File

@@ -0,0 +1,61 @@
/* 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 GRAPHICS_MACGUI_MACPOPUPMENU_H
#define GRAPHICS_MACGUI_MACPOPUPMENU_H
#include "graphics/macgui/macmenu.h"
namespace Graphics {
class MacMenu;
class MacWindowManager;
class MacPopUp : public MacMenu {
public:
MacPopUp(int id, const Common::Rect &bounds, MacWindowManager *wm, const char *string);
uint32 drawAndSelectMenu(int x, int y, int item);
Common::String getItemText(int item);
bool draw(ManagedSurface *g, bool forceRedraw = false) override;
void closeMenu() override;
// Extra functions
void setSmart(bool smart) {
_isSmart = smart;
}
private:
int kBlinkDelay = 15; // Blink delay for closing animation
int kNumBlinks = 3; // Number of blinks
int _mouseX;
int _mouseY;
int _menuItemId;
int _menuId;
bool _isSmart = false;
int _offsetY = 0;
int _prevCheckedItem = -1;
bool mouseClicked(int x, int y);
};
} // End of namespace Graphics
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,211 @@
/* 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 GRAPHICS_MACGUI_MACTEXTCANVAS_H
#define GRAPHICS_MACGUI_MACTEXTCANVAS_H
#include "graphics/macgui/macwindowmanager.h"
#include "graphics/image-archive.h"
namespace Graphics {
class MacText;
struct MacFontRun {
Common::U32String text;
uint16 fontId;
byte textSlant;
uint16 fontSize;
uint16 palinfo1;
uint16 palinfo2;
uint16 palinfo3;
uint32 fgcolor;
const Font *font;
MacWindowManager *wm;
Common::String link; // Substitute to return when hover or click
MacFontRun() {
wm = nullptr;
fontId = textSlant = fontSize = 0;
palinfo1 = palinfo2 = palinfo3 = 0;
fgcolor = 0;
font = nullptr;
}
MacFontRun(MacWindowManager *wm_) {
wm = wm_;
fontId = textSlant = fontSize = 0;
palinfo1 = palinfo2 = palinfo3 = 0;
fgcolor = 0;
font = nullptr;
}
MacFontRun(MacWindowManager *wm_, uint16 fontId_, byte textSlant_, uint16 fontSize_,
uint16 palinfo1_, uint16 palinfo2_, uint16 palinfo3_) {
setValues(wm_, fontId_, textSlant_, fontSize_, palinfo1_, palinfo2_, palinfo3_);
}
MacFontRun(MacWindowManager *wm_, const Font *font_, byte textSlant_, uint16 fontSize_,
uint16 palinfo1_, uint16 palinfo2_, uint16 palinfo3_) {
setValues(wm_, 0, textSlant_, fontSize_, palinfo1_, palinfo2_, palinfo3_);
font = font_;
}
void setValues(MacWindowManager *wm_, uint16 fontId_, byte textSlant_, uint16 fontSize_,
uint16 palinfo1_, uint16 palinfo2_, uint16 palinfo3_) {
wm = wm_;
fontId = fontId_;
textSlant = textSlant_;
fontSize = fontSize_;
palinfo1 = palinfo1_;
palinfo2 = palinfo2_;
palinfo3 = palinfo3_;
fgcolor = wm_->findBestColor(palinfo1_ & 0xff, palinfo2_ & 0xff, palinfo3_ & 0xff);
font = nullptr;
}
const Font *getFont();
const Common::String toString();
bool equals(MacFontRun &to);
Common::CodePage getEncoding();
bool plainByteMode();
Common::String getEncodedText();
bool equals(const MacFontRun *y) {
return (fontId == y->fontId &&
textSlant == y->textSlant &&
fontSize == y->fontSize &&
palinfo1 == y->palinfo1 &&
palinfo2 == y->palinfo2 &&
palinfo3 == y->palinfo3 &&
fgcolor == y->fgcolor);
}
void debugPrint();
};
struct MacTextLine;
class MacTextCanvas {
public:
Common::Array<MacTextLine> _text;
ManagedSurface *_surface = nullptr, *_shadowSurface = nullptr;
int _maxWidth = 0;
int _textMaxWidth = 0;
int _textMaxHeight = 0;
TextAlign _textAlignment = kTextAlignLeft;
int _interLinear = 0;
int _textShadow = 0;
MacWindowManager *_wm = nullptr;
uint32 _tfgcolor = 0;
uint32 _tbgcolor = 0;
bool _macFontMode = true;
MacText *_macText;
MacFontRun _defaultFormatting;
ImageArchive _imageArchive;
public:
~MacTextCanvas();
void recalcDims();
void reallocSurface();
void render(int from, int to);
void render(int from, int to, int shadow);
int getAlignOffset(int row);
/**
* Returns line width in pixels. This takes into account chunks.
* The result is cached for faster subsequent calls.
*
* @param line Line number
* @param enforce Flag for indicating skipping the cache and computing the width,
* must be called when text gets changed
* @param col Compute line width up to specified column, including this column
* @return line width in pixels, or 0 for non-existent lines
*/
int getLineWidth(int line, bool enforce = false, int col = -1);
int getLineHeight(int line);
int getLineCharWidth(int line, bool enforce = false);
void splitString(const Common::U32String &str, int curLine, MacFontRun &defaultFormatting);
const Common::U32String::value_type *splitString(const Common::U32String::value_type *s, int curLine, MacFontRun &defaultFormatting);
void chopChunk(const Common::U32String &str, int *curLinePtr, int indent, int maxWidth);
Common::U32String getTextChunk(int startRow, int startCol, int endRow, int endCol, bool formatted = false, bool newlines = true);
/**
* Rewraps paragraph containing given text row.
* When text is modified, we redo whole thing again without touching
* other paragraphs. Also, cursor position is returned in the arguments
*/
void reshuffleParagraph(int *row, int *col, MacFontRun &defaultFormatting);
void setMaxWidth(int maxWidth, MacFontRun &defaultFormatting);
void debugPrint(const char *prefix = nullptr);
private:
void processTable(int line, int maxWidth);
void parsePicExt(const Common::U32String &ext, uint16 &w, uint16 &h, int defpercent);
};
struct MacTextTableRow {
Common::Array<MacTextCanvas> cells;
int heght = -1;
};
struct MacTextLine {
int width = -1;
int height = -1;
int minWidth = -1;
int y = 0;
int charwidth = -1;
bool paragraphEnd = false;
bool wordContinuation = false;
int indent = 0; // in units
int firstLineIndent = 0; // in pixels
Common::Path picfname;
Common::U32String picalt, pictitle, picext;
uint16 picpercent = 50;
Common::Array<MacTextTableRow> *table = nullptr;
ManagedSurface *tableSurface = nullptr;
Common::Array<MacFontRun> chunks;
MacFontRun &firstChunk() { return chunks[0]; }
MacFontRun &lastChunk() { return chunks[chunks.size() - 1]; }
/**
* Search for a chunk at given char column.
*
* @param col Requested column, gets modified with in-chunk column
* @returns Chunk number
*
* @note If requested column is too big, returns last character in the line
*/
uint getChunkNum(int *col);
};
} // End of namespace Graphics
#endif

View File

@@ -0,0 +1,382 @@
/* 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/formats/markdown.h"
#include "graphics/macgui/mactext.h"
namespace Graphics {
#define PR(x) ((x && x->data) ? Common::toPrintable(Common::String((const char *)(x)->data , (x)->size)).c_str() : "(null)")
struct MDState {
Common::List<int> listNum;
uint32 linkr = 0, linkg = 0, linkb = 0;
};
void render_blockcode(Common::SDDataBuffer *ob, const Common::SDDataBuffer *text, const Common::SDDataBuffer *lang, void *opaque) {
if (!text)
return;
Common::String res = Common::String::format("\n\001\016+0001" "\001\016t%04x" "%s" "\001\016tffff" "\n\001\016-0001",
kMacFontMonaco, Common::String((const char *)text->data , text->size).c_str());
sd_bufput(ob, res.c_str(), res.size());
debug(1, "render_blockcode(%s, %s)", PR(text), PR(lang));
}
void render_blockquote(Common::SDDataBuffer *ob, const Common::SDDataBuffer *text, void *opaque) {
if (!text)
return;
warning("STUB: render_blockquote(%s)", PR(text));
}
void render_blockhtml(Common::SDDataBuffer *ob, const Common::SDDataBuffer *text, void *opaque) {
if (!text)
return;
warning("STUB: render_blockhtml(%s)", PR(text));
}
void render_header(Common::SDDataBuffer *ob, const Common::SDDataBuffer *text, int level, void *opaque) {
if (!text)
return;
debug(1, "render_header(%s)", PR(text));
Common::String res = Common::String::format("\001\016+00%01x0" "%s" "\001\016-00f0\n", level, Common::String((const char *)text->data , text->size).c_str());
sd_bufput(ob, res.c_str(), res.size());
}
void render_hrule(Common::SDDataBuffer *ob, void *opaque) {
warning("STUB: render_hrule()");
}
void render_list_start(Common::SDDataBuffer *ob, const Common::SDDataBuffer *text, int flags, void *opaque) {
MDState *mdstate = (MDState *)opaque;
mdstate->listNum.push_back(flags & MKD_LIST_ORDERED ? 1 : -1);
sd_bufput(ob, "\001\016+0001", 7);
debug(1, "render_list_start(%s, %d)", PR(text), flags);
}
void render_list(Common::SDDataBuffer *ob, const Common::SDDataBuffer *text, int flags, void *opaque) {
MDState *mdstate = (MDState *)opaque;
mdstate->listNum.pop_back();
sd_bufput(ob, text->data, text->size);
sd_bufput(ob, "\n\001\016-0001", 8);
debug(1, "render_list(%s, %d)", PR(text), flags);
}
void render_listitem(Common::SDDataBuffer *ob, const Common::SDDataBuffer *text, int flags, void *opaque) {
MDState *mdstate = (MDState *)opaque;
int listNum = mdstate->listNum.back();
Common::String prefix;
if (flags & MKD_LIST_ORDERED) {
prefix = Common::String::format("%d. ", listNum);
mdstate->listNum.back()++;
} else {
prefix = "* ";
}
Common::String res = Common::String::format("\001\016*%02x%s", prefix.size(), prefix.c_str());
sd_bufput(ob, res.c_str(), res.size());
sd_bufput(ob, prefix.c_str(), prefix.size());
sd_bufput(ob, text->data, text->size);
debug(1, "render_listitem(%s, %d)", PR(text), flags);
}
void render_paragraph(Common::SDDataBuffer *ob, const Common::SDDataBuffer *text, void *opaque) {
if (!text)
return;
debug(1, "render_paragraph(%s)", PR(text));
sd_bufput(ob, text->data, text->size);
sd_bufput(ob, "\n\n", 2);
}
void render_table(Common::SDDataBuffer *ob, const Common::SDDataBuffer *header, const Common::SDDataBuffer *body, void *opaque) {
if (!body)
return;
Common::String res = Common::String::format("\001\016Th" "%s" "\001\016Tb" "%s" "\001\016TB",
Common::String((const char *)header->data , header->size).c_str(), Common::String((const char *)body->data , body->size).c_str());
sd_bufput(ob, res.c_str(), res.size());
debug(1, "render_table(%s, %s)", PR(header), PR(body));
}
void render_table_row(Common::SDDataBuffer *ob, const Common::SDDataBuffer *text, void *opaque) {
if (!text)
return;
Common::String res = Common::String::format("\001\016Tr" "%s\n", Common::String((const char *)text->data , text->size).c_str());
sd_bufput(ob, res.c_str(), res.size());
debug(1, "render_table_row(%s)", PR(text));
}
void render_table_cell(Common::SDDataBuffer *ob, const Common::SDDataBuffer *text, int flags, void *opaque) {
if (!text)
return;
TextAlign align;
switch (flags) {
case Common::MKD_TABLE_ALIGN_R:
align = kTextAlignRight;
break;
case Common::MKD_TABLE_ALIGN_CENTER:
align = kTextAlignCenter;
break;
case Common::MKD_TABLE_ALIGN_L:
default:
align = kTextAlignLeft;
}
Common::String res = Common::String((const char *)text->data, text->size);
if (flags & Common::MKD_TABLE_HEADER)
res = Common::String::format("\001\016+%02x00" "%s" "\001\016-%02x00", kMacFontBold, res.c_str(), kMacFontBold);
res = Common::String::format("\001\016Tc%02x" "%s" "\001\016TC", align, res.c_str());
sd_bufput(ob, res.c_str(), res.size());
debug(1, "render_table_cell(%s), flags: %d", PR(text), flags);
}
int render_autolink(Common::SDDataBuffer *ob, const Common::SDDataBuffer *link, Common::MKDAutolink type, void *opaque) {
if (!link)
return 0;
warning("STUB: render_autolink(%s)", PR(link));
return 1;
}
int render_codespan(Common::SDDataBuffer *ob, const Common::SDDataBuffer *text, void *opaque) {
if (!text)
return 0;
Common::String res = Common::String::format("\001\016t%04x" "%s" "\001\016tffff",
kMacFontMonaco, Common::String((const char *)text->data , text->size).c_str());
sd_bufput(ob, res.c_str(), res.size());
debug(1, "render_codespan(%s)", PR(text));
return 1;
}
int render_double_emphasis(Common::SDDataBuffer *ob, const Common::SDDataBuffer *text, void *opaque) {
if (!text || !text->size)
return 0;
debug(1, "render_double_emphasis(%s)", PR(text));
Common::String res = Common::String::format("\001\016+%02x00" "%s" "\001\016-%02x00", kMacFontBold, Common::String((const char *)text->data , text->size).c_str(), kMacFontBold);
sd_bufput(ob, res.c_str(), res.size());
return 1;
}
int render_emphasis(Common::SDDataBuffer *ob, const Common::SDDataBuffer *text, void *opaque) {
if (!text || !text->size)
return 0;
debug(1, "render_emphasis(%s)", PR(text));
Common::String res = Common::String::format("\001\016+%02x00" "%s" "\001\016-%02x00", kMacFontItalic, Common::String((const char *)text->data , text->size).c_str(), kMacFontItalic);
sd_bufput(ob, res.c_str(), res.size());
return 1;
}
int render_image(Common::SDDataBuffer *ob, const Common::SDDataBuffer *link, const Common::SDDataBuffer *title, const Common::SDDataBuffer *alt, const Common::SDDataBuffer *ext, void *opaque) {
if (!link)
return 0;
Common::String res = Common::String::format("\001" "\016i%02x" "%02x%s",
80, (uint)link->size, Common::String((const char *)link->data, link->size).c_str());
if (alt) {
uint32 len = Common::U32String((const char *)alt->data, alt->size).size();
res += Common::String::format("%02x%s", len, Common::String((const char *)alt->data, alt->size).c_str());
} else {
res += "00";
}
if (title) {
uint32 len = Common::U32String((const char *)title->data, title->size).size();
res += Common::String::format("%02x%s", len, Common::String((const char *)title->data, title->size).c_str());
} else {
res += "00";
}
if (ext) {
uint32 len = Common::U32String((const char *)ext->data, ext->size).size();
res += Common::String::format("%02x%s", len, Common::String((const char *)ext->data, ext->size).c_str());
} else {
res += "00";
}
res += "\n";
sd_bufput(ob, res.c_str(), res.size());
debug(1, "render_image(%s, %s, %s, %s)", PR(link), PR(title), PR(alt), PR(ext));
return 1;
}
int render_linebreak(Common::SDDataBuffer *ob, void *opaque) {
debug(1, "render_linebreak()");
sd_bufput(ob, "\n", 1);
return 1;
}
int render_link(Common::SDDataBuffer *ob, const Common::SDDataBuffer *link, const Common::SDDataBuffer *title, const Common::SDDataBuffer *content, void *opaque) {
if (!link)
return 0;
MDState *mdstate = (MDState *)opaque;
const Common::SDDataBuffer *text = content ? content : link;
uint32 linklen = Common::U32String((const char *)link->data, link->size).size();
Common::String res = Common::String::format("\001" "\016+%02x00" "\001\016[%04x%04x%04x"
"\001\016l%02x%s" "%s" "\001\016l00" "\001\016]" "\001\016-%02x00", kMacFontUnderline,
mdstate->linkr, mdstate->linkg, mdstate->linkb,
linklen, Common::String((const char *)link->data , link->size).c_str(),
Common::String((const char *)text->data , text->size).c_str(), kMacFontUnderline);
sd_bufput(ob, res.c_str(), res.size());
debug(1, "render_link(%s, %s, %s)", PR(link), PR(title), PR(content));
return 1;
}
int render_raw_html_tag(Common::SDDataBuffer *ob, const Common::SDDataBuffer *tag, void *opaque) {
if (!tag)
return 0;
sd_bufput(ob, tag->data, tag->size);
debug(1, "render_raw_html_tag(%s)", PR(tag));
return 1;
}
int render_triple_emphasis(Common::SDDataBuffer *ob, const Common::SDDataBuffer *text, void *opaque) {
if (!text)
return 0;
warning("STUB: render_triple_emphasis(%s)", PR(text));
return 1;
}
int render_strikethrough(Common::SDDataBuffer *ob, const Common::SDDataBuffer *text, void *opaque) {
if (!text)
return 0;
warning("STUB: render_strikethrough(%s)", PR(text));
return 1;
}
int render_superscript(Common::SDDataBuffer *ob, const Common::SDDataBuffer *text, void *opaque) {
if (!text)
return 0;
warning("STUB: render_superscript(%s)", PR(text));
return 1;
}
void MacText::setMarkdownText(const Common::U32String &str) {
const Common::SDCallbacks cb = {
/* block level callbacks - NULL skips the block */
render_blockcode,
render_blockquote,
render_blockhtml,
render_header,
render_hrule,
render_list_start,
render_list,
render_listitem,
render_paragraph,
render_table,
render_table_row,
render_table_cell,
/* span level callbacks - NULL or return 0 prints the span verbatim */
render_autolink,
render_codespan,
render_double_emphasis,
render_emphasis,
render_image,
render_linebreak,
render_link,
render_raw_html_tag,
render_triple_emphasis,
render_strikethrough,
render_superscript,
/* low level callbacks - NULL copies input directly into the output */
NULL,
NULL,
/* header and footer */
NULL,
NULL,
};
Common::String input = str.encode(); // Encode to UTF8
MDState mdState;
// Set link color to blue
mdState.linkr = 0;
mdState.linkg = 0;
mdState.linkb = 0xff;
Common::SDMarkdown md(Common::MKDEXT_TABLES, 16, &cb, &mdState);
Common::String rendered = md.render((const byte *)input.c_str(), input.size());
setText(rendered);
}
} // End of namespace Graphics

2191
graphics/macgui/mactext.cpp Normal file

File diff suppressed because it is too large Load Diff

265
graphics/macgui/mactext.h Normal file
View File

@@ -0,0 +1,265 @@
/* 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 GRAPHICS_MACGUI_MACTEXT_H
#define GRAPHICS_MACGUI_MACTEXT_H
#include "graphics/macgui/mactext-canvas.h"
namespace Graphics {
struct SelectedText {
int startX, startY;
int endX, endY;
int startRow, startCol;
int endRow, endCol;
SelectedText() {
startX = startY = -1;
endX = endY = -1;
startRow = startCol = -1;
endRow = endCol = -1;
}
bool needsRender() {
return startX != endX || startY != endY;
}
};
class MacText : public MacWidget {
public:
MacText(MacWidget *parent, int x, int y, int w, int h, MacWindowManager *wm, const Common::U32String &s, const MacFont *font, uint32 fgcolor, uint32 bgcolor, int maxWidth, TextAlign textAlignment = kTextAlignLeft, int interlinear = 0, uint16 border = 0, uint16 gutter = 0, uint16 boxShadow = 0, uint16 textShadow = 0, bool fixedDims = true, bool scrollBar = false);
// 0 pixels between the lines by default
MacText(const Common::U32String &s, MacWindowManager *wm, const MacFont *font, uint32 fgcolor, uint32 bgcolor, int maxWidth, TextAlign textAlignment, int interlinear = 0, bool fixedDims = true, bool scrollBar = false);
MacText(const Common::U32String &s, MacWindowManager *wm, const Font *font, uint32 fgcolor, uint32 bgcolor, int maxWidth, TextAlign textAlignment, int interlinear = 0, bool fixedDims = true, bool scrollBar = false);
virtual ~MacText();
virtual void resize(int w, int h);
bool processEvent(Common::Event &event) override;
bool needsRedraw() override { return _contentIsDirty || _cursorDirty; }
WindowClick isInScrollBar(int x, int y) const;
void setScrollBar(bool enable);
void resizeScrollBar(int w, int h);
void setAutoSelect(bool enable) { _autoSelect = enable; }
void render();
void undrawCursor();
void draw(ManagedSurface *g, int x, int y, int w, int h, int xoff, int yoff);
bool draw(ManagedSurface *g, bool forceRedraw = false) override;
bool draw(bool forceRedraw = false) override;
void drawToPoint(ManagedSurface *g, Common::Rect srcRect, Common::Point dstPoint);
void drawToPoint(ManagedSurface *g, Common::Point dstPoint);
ManagedSurface *getSurface() { return _canvas._surface; }
int getInterLinear() { return _canvas._interLinear; }
void setInterLinear(int interLinear);
void setMaxWidth(int maxWidth);
void setDefaultFormatting(uint16 fontId, byte textSlant, uint16 fontSize,
uint16 palinfo1, uint16 palinfo2, uint16 palinfo3);
const MacFontRun &getDefaultFormatting() { return _defaultFormatting; }
void setAlignOffset(TextAlign align);
TextAlign getAlign() { return _canvas._textAlignment; }
virtual Common::Point calculateOffset();
void setActive(bool active) override;
void setEditable(bool editable);
void setInputPadding(bool enable){ _addInputPadding = enable; }
void setColors(uint32 fg, uint32 bg) override;
// set fgcolor for line x
void setTextColor(uint32 color, uint32 line);
void setTextColor(uint32 color, uint32 start, uint32 end);
void appendText(const Common::U32String &str, int fontId = kMacFontSystem, int fontSize = 12, int fontSlant = kMacFontRegular, bool skipAdd = false);
void appendText(const Common::U32String &str, int fontId = kMacFontSystem, int fontSize = 12, int fontSlant = kMacFontRegular, uint16 r = 0, uint16 g = 0, uint16 b = 0, bool skipAdd = false);
void appendText(const Common::U32String &str, const Font *font, uint16 r = 0, uint16 g = 0, uint16 b = 0, bool skipAdd = false);
int getTextFont() { return _defaultFormatting.fontId; }
void enforceTextFont(uint16 fontId);
int getRowCount();
// because currently, we are counting linespacing as font height
int getTextSize() { return _defaultFormatting.fontSize; }
void setTextSize(int textSize);
int getTextSize(int start, int end);
void setTextSize(int textSize, int start, int end);
uint32 getTextColor() { return _defaultFormatting.fgcolor; }
uint32 getTextColor(int start, int end);
int getTextFont(int start, int end);
void setTextFont(int fontId, int start, int end);
int getTextSlant() { return _defaultFormatting.textSlant; }
int getTextSlant(int start, int end);
void setTextSlant(int textSlant, int start, int end);
void enforceTextSlant(int textSlant);
// director text related-functions
int getMouseChar(int x, int y);
int getMouseWord(int x, int y);
int getMouseItem(int x, int y);
int getMouseLine(int x, int y);
Common::U32String getMouseLink(int x, int y);
bool setImageArchive(const Common::Path &name) { return _canvas._imageArchive.setImageArchive(name); }
private:
MacFontRun getTextChunks(int start, int end);
void setTextChunks(int start, int end, int param, void (*callback)(MacFontRun &, int));
void appendText_(const Common::U32String &strWithFont, uint oldLen);
void deletePreviousCharInternal(int *row, int *col);
void insertTextFromClipboard();
MacFontRun getFgColor();
public:
void appendTextDefault(const Common::U32String &str, bool skipAdd = false);
void appendTextDefault(const Common::String &str, bool skipAdd = false);
void clearText();
void removeLastLine();
int getLineCount() { return _canvas._text.size(); }
int getLastLineWidth();
int getTextHeight() { return _canvas._textMaxHeight; }
int getLineHeight(int line);
int getTextMaxWidth() { return _canvas._textMaxWidth; }
void setText(const Common::U32String &str);
void setFixDims(bool fixed) { _fixedDims = fixed; }
bool getFixDims() { return _fixedDims; }
void deleteSelection();
void deletePreviousChar(int *row, int *col);
void addNewLine(int *row, int *col);
void insertChar(byte c, int *row, int *col);
void getChunkPosFromIndex(int index, uint &lineNum, uint &chunkNum, uint &offset);
void getRowCol(int x, int y, int *sx, int *sy, int *row, int *col, int *chunk_ = nullptr);
void getLineCharacter(int x, int y, int *sx, int *sy, int *line, int *character, int *chunk_ = nullptr);
Common::U32String getTextChunk(int startRow, int startCol, int endRow, int endCol, bool formatted = false, bool newlines = true);
Common::U32String getSelection(bool formatted = false, bool newlines = true);
uint getSelectionIndex(bool start);
void clearSelection();
Common::U32String cutSelection();
const SelectedText *getSelectedText() { return &_selectedText; }
bool hasSelection() { return _selectedText.endY != -1; }
int getLineSpacing() { return _canvas._interLinear; }
/**
* set the selection of mactext
* @param pos pos of selection, 0 represent first, -1 represent the end of text
* @param start selection start or selection end
*/
void setSelection(int pos, bool start);
Common::U32String getEditedString();
Common::U32String getText() { return _str; }
Common::U32String getPlainText();
void setSelRange(int selStart, int selEnd);
void scroll(int delta);
// Markdown
public:
void setMarkdownText(const Common::U32String &str);
private:
void init(uint32 fgcolor, uint32 bgcolor, int maxWidth, TextAlign textAlignment, int interlinear, uint16 textShadow, bool macFontMode);
bool isCutAllowed();
void recalcDims();
void drawSelection(int xoff, int yoff);
void updateCursorPos();
void startMarking(int x, int y);
void updateTextSelection(int x, int y);
/**
* Clears the text of the last chunk.
*/
void clearChunkInput();
public:
int _cursorX, _cursorY;
bool _cursorState;
int _cursorRow, _cursorCol;
bool _cursorDirty;
Common::Rect *_cursorRect;
bool _cursorOff;
bool _selectable;
int _scrollPos;
bool _fullRefresh;
protected:
Common::U32String _str;
const MacFont *_macFont;
bool _fixedDims;
bool _scrollBar;
MacWindowBorder _scrollBorder;
ManagedSurface _borderSurface;
int _selEnd;
int _selStart;
MacTextCanvas _canvas;
MacFontRun _defaultFormatting;
MacFontRun _currentFormatting;
private:
ManagedSurface *_cursorSurface;
ManagedSurface *_cursorSurface2;
int _editableRow;
bool _addInputPadding;
bool _inTextSelection;
SelectedText _selectedText;
bool _selectionIsDirty;
MacMenu *_menu;
bool _autoSelect;
};
int getStringWidth(MacFontRun &format, const Common::U32String &str);
} // End of namespace Graphics
#endif

View File

@@ -0,0 +1,618 @@
/* 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/timer.h"
#include "common/system.h"
#include "graphics/macgui/macwindowmanager.h"
#include "graphics/macgui/macfontmanager.h"
#include "graphics/macgui/mactextwindow.h"
#include "graphics/macgui/macmenu.h"
#define SCROLLBAR_DELAY 300
namespace Graphics {
enum {
kConWOverlap = 20,
kConHOverlap = 20,
kConWPadding = 3,
kConHPadding = 4,
kConOverscan = 3,
kConScrollStep = 12,
};
MacTextWindow::MacTextWindow(MacWindowManager *wm, const MacFont *font, int fgcolor, int bgcolor, int maxWidth, TextAlign textAlignment, MacMenu *menu, int padding) :
MacWindow(wm->getLastId(), true, true, true, wm), _bgcolor(bgcolor), _maxWidth(maxWidth), _menu(menu) {
_font = font;
_mactext = new MacText(this, 0, 0, 0, 0, _wm, Common::U32String(""), font, fgcolor, bgcolor, maxWidth, textAlignment, 0, padding);
_fontRef = wm->_fontMan->getFont(*font);
init();
}
MacTextWindow::MacTextWindow(MacWindowManager *wm, const Font *font, int fgcolor, int bgcolor, int maxWidth, TextAlign textAlignment, MacMenu *menu, int padding) :
MacWindow(wm->getLastId(), true, true, true, wm), _bgcolor(bgcolor), _maxWidth(maxWidth), _menu(menu) {
_font = nullptr;
_mactext = new MacText(Common::U32String(""), _wm, font, fgcolor, bgcolor, maxWidth, textAlignment, 0, true);
_fontRef = font;
init();
}
void MacTextWindow::init() {
_inputTextHeight = 0;
_inputIsDirty = true;
_editable = true;
_selectable = true;
_textColorRGB = 0;
_scrollDirection = kBorderNone;
_clickedScrollPart = kBorderNone;
_nextScrollTime = 0;
_nextWheelEventTime = 0;
_scrollDelay = 50;
_isDragging = false;
_dragStartY = 0;
_dragStartScrollPos = 0;
// Disable autoselect on activation
_mactext->setAutoSelect(false);
if (_wm->_mode & kWMModeWin95) {
// in win95 mode, we set scrollbar as default
_hasScrollBar = true;
setBorderType(kWinBorderWin95Scrollbar);
loadInternalBorder(kWindowBorderScrollbar | kWindowBorderActive);
}
}
void MacTextWindow::resize(int w, int h) {
if (_composeSurface->w == w && _composeSurface->h == h)
return;
undrawInput();
MacWindow::resize(w, h);
_maxWidth = getInnerDimensions().width();
_mactext->resize(_maxWidth, getInnerDimensions().height());
}
void MacTextWindow::setDimensions(const Common::Rect &r) {
resize(r.width(), r.height());
_dims.moveTo(r.left, r.top);
updateInnerDims();
_contentIsDirty = true;
_wm->setFullRefresh(true);
_mactext->setDimensions(Common::Rect(_innerDims.width(), _innerDims.height()));
}
void MacTextWindow::appendText(const Common::U32String &str, const MacFont *macFont, bool skipAdd) {
// the reason we put undrawInput here before appendText, is we don't want the appended text affect our input
// thus, we first delete all of out input, and we append new text, and we redraw the input
undrawInput();
// we calc the rgb though fgcolor
uint16 red = (_textColorRGB >> 16) & 0xFF;
uint16 green = (_textColorRGB >> 8) & 0xFF;
uint16 blue = (_textColorRGB) & 0xFF;
// Adding empty line at the bottom of the input text area if needed
_mactext->setInputPadding(true);
if (macFont)
_mactext->appendText(str, macFont->getId(), macFont->getSize(), macFont->getSlant(), red, green, blue, skipAdd);
else {
_mactext->appendText(str, _fontRef, red, green, blue, skipAdd);
}
_contentIsDirty = true;
_inputIsDirty = true; //force it to redraw input
if (_editable) {
// Add one line of bottom padding to ensure the last line is not covered
int padding = _mactext->getLineHeight(_mactext->getLineCount() - 1);
padding = MIN<int>(padding, getInnerDimensions().height());
int oldScroll = _mactext->_scrollPos;
_mactext->_scrollPos = MAX<int>(0, _mactext->getTextHeight() - getInnerDimensions().height() + padding);
if (_mactext->_scrollPos != oldScroll) {
_mactext->undrawCursor();
_mactext->_cursorY -= (_mactext->_scrollPos - oldScroll);
_mactext->_cursorDirty = true;
}
}
if (_wm->_mode & kWMModeWin95)
calcScrollBar();
// if we enable the dynamic scrollbar, and the text height is smaller than window height, then we disable the border
// if the window is editable, then we don't disable the border, because in editable window, the area you scroll is always bigger
// than the window
if (!_editable && (_mode & kWindowModeDynamicScrollbar) && _mactext->getTextHeight() < getInnerDimensions().height()) {
int w = getDimensions().width();
int h = getDimensions().height();
enableScrollbar(false);
disableBorder();
resize(w, h);
_mactext->_fullRefresh = true;
}
// if the text height is bigger than the window, then we enable the scrollbar again
if (!_editable && (_mode & kWindowModeDynamicScrollbar) && _mactext->getTextHeight() > getInnerDimensions().height()) {
enableScrollbar(true);
int w = getDimensions().width();
int h = getDimensions().height();
resize(w, h);
_mactext->_fullRefresh = true;
}
}
void MacTextWindow::appendText(const Common::String &str, const MacFont *macFont, bool skipAdd) {
appendText(Common::U32String(str), macFont, skipAdd);
}
void MacTextWindow::setMarkdownText(const Common::U32String &str) {
_mactext->setMarkdownText(str);
_contentIsDirty = true;
}
void MacTextWindow::clearText() {
_mactext->clearText();
_contentIsDirty = true;
_borderIsDirty = true;
}
MacTextWindow::~MacTextWindow() {
delete _mactext;
}
void MacTextWindow::setTextWindowFont(const MacFont *font) {
_font = font;
_fontRef = _wm->_fontMan->getFont(*font);
_mactext->setDefaultFormatting(font->getId(), font->getSlant(), font->getSize(), 0, 0, 0);
}
const MacFont *MacTextWindow::getTextWindowFont() {
return _font;
}
bool MacTextWindow::draw(bool forceRedraw) {
uint32 now = g_system->getMillis();
// check if we need to hide the scroll bar
if (!(_wm->_mode & kWMModeWin95)) {
if (_nextWheelEventTime != 0 && now >= _nextWheelEventTime) {
if (_scrollDirection == kBorderNone && _clickedScrollPart == kBorderNone) {
setScroll(0, 0); // hide the scrollbar
_nextWheelEventTime = 0; // reset timer
}
}
}
// handle mouse button scrolling
if (_scrollDirection != kBorderNone) {
Common::Point mousePos = g_system->getEventManager()->getMousePos();
if (isInBorder(mousePos.x, mousePos.y) != _clickedScrollPart) {
_scrollDirection = kBorderNone;
setHighlight(kBorderNone);
calcScrollBar();
if (!(_wm->_mode & kWMModeWin95)) {
setScroll(0, 0);
}
}
if (_scrollDirection != kBorderNone && now >= _nextScrollTime) {
if (_scrollDirection == kBorderScrollUp) {
_mactext->scroll(-1);
} else if (_scrollDirection == kBorderScrollDown) {
_mactext->scroll(1);
}
calcScrollBar();
_nextScrollTime = now + _scrollDelay;
}
}
bool needsContentRedraw = _contentIsDirty || _inputIsDirty || _mactext->needsRedraw() || forceRedraw;
if (!_borderIsDirty && !needsContentRedraw)
return false;
if (_borderIsDirty || forceRedraw)
drawBorder();
if (_inputIsDirty || forceRedraw) {
drawInput();
_inputIsDirty = false;
needsContentRedraw = true; // input update needs a redraw
}
if (needsContentRedraw) {
// only clear the surface if we are actually going to redraw the text
if (_wm->_mode & kWMModeWin95) {
_composeSurface->clear(_bgcolor);
} else {
_composeSurface->clear(_wm->_colorWhite);
}
_contentIsDirty = false;
_mactext->draw(_composeSurface, forceRedraw);
}
return true;
}
bool MacTextWindow::draw(ManagedSurface *g, bool forceRedraw) {
if (!draw(forceRedraw))
return false;
g->blitFrom(*_composeSurface, Common::Rect(0, 0, _composeSurface->w, _composeSurface->h), Common::Point(_innerDims.left, _innerDims.top));
uint32 transcolor = (_wm->_pixelformat.bytesPerPixel == 1) ? _wm->_colorGreen : 0;
g->transBlitFrom(_borderSurface, Common::Rect(0, 0, _borderSurface.w, _borderSurface.h), Common::Point(_dims.left, _dims.top), transcolor);
return true;
}
void MacTextWindow::blit(ManagedSurface *g, Common::Rect &dest) {
g->transBlitFrom(*_composeSurface, _composeSurface->getBounds(), dest, _wm->_colorGreen2);
}
Common::U32String MacTextWindow::getSelection(bool formatted, bool newlines) {
return _mactext->getSelection(formatted, newlines);
}
int MacTextWindow::getMouseLine(int x, int y) {
// TODO: Improve the algorithm here, since after long scrolling there is
// sometimes error of +2 rows
x -= getInnerDimensions().left;
y -= getInnerDimensions().top + kConScrollStep;
return _mactext->getMouseLine(x, y);
}
void MacTextWindow::calcScrollBar() {
// since this function only able for the window which has scroll bar
// thus, if it doesn't has scrollbar, then we don't have to calc it
if (!_hasScrollBar)
return;
int maxText = 0, maxScrollbar = 0, displayHeight = 0;
displayHeight = getInnerDimensions().height();
maxScrollbar = getDimensions().height() - getBorderOffsets().upperScrollHeight - getBorderOffsets().lowerScrollHeight;
maxText = _mactext->getTextHeight();
// if we enable the win95 mode but the text height is smaller than window height, then we don't draw the scrollbar
if (_wm->_mode & kWMModeWin95 && displayHeight > maxText && !_editable)
return;
int maxScroll = 0;
// identical to MacText scroll() logic
if (_editable)
maxScroll = maxText - kConScrollStep;
else
maxScroll = maxText - displayHeight;
float contentHeight = (float)(maxText + displayHeight);
float scrollSize = (float)(maxScrollbar * displayHeight) / contentHeight;
int range = maxScrollbar - (int)scrollSize - 1;
float ratio = CLIP<float>((float)_mactext->_scrollPos / (float)maxScroll, 0.0f, 1.0f);
float scrollPos = ratio * (float)range;
setScroll(scrollPos, scrollSize);
}
void MacTextWindow::calcWin95Scroll(int &scrollAreaTop, int &scrollAreaHeight, int &barY, int &barHeight) {
const BorderOffsets &offsets = getBorderOffsets();
scrollAreaTop = offsets.upperScrollHeight;
scrollAreaHeight = _dims.height() - offsets.upperScrollHeight - offsets.lowerScrollHeight;
int contentHeight = _mactext->getTextHeight();
int winHeight = getInnerDimensions().height();
// if content fits in the current window
if (contentHeight <= winHeight || contentHeight == 0) {
barHeight = scrollAreaHeight;
barY = scrollAreaTop;
return;
}
float winRatio = (float)winHeight / (float)contentHeight;
barHeight = MAX<int>(8, (int)(scrollAreaHeight * winRatio)); // 8 the min height of scrollBar
int maxTextScroll = contentHeight - winHeight;
int maxBarScroll = scrollAreaHeight - barHeight;
float scrollAmount = (float)_mactext->_scrollPos / (float)maxTextScroll;
barY = scrollAreaTop + (int)(maxBarScroll * scrollAmount);
}
bool MacTextWindow::processEvent(Common::Event &event) {
WindowClick click = isInBorder(event.mouse.x, event.mouse.y);
if (!(g_system->getEventManager()->getButtonState() & Common::EventManager::LBUTTON)) {
if (_isDragging) {
_isDragging = false;
}
if (_clickedScrollPart != kBorderNone || _scrollDirection != kBorderNone) {
_scrollDirection = kBorderNone;
_clickedScrollPart = kBorderNone;
setHighlight(kBorderNone);
if (!(_wm->_mode & kWMModeWin95)) {
setScroll(0, 0);
}
return true;
}
}
if (event.type == Common::EVENT_MOUSEMOVE) {
if (!(_wm->_mode & kWMModeWin95)) {
if (_clickedScrollPart == kBorderScrollUp || _clickedScrollPart == kBorderScrollDown) {
if (click == kBorderScrollUp) {
if (_scrollDirection != kBorderScrollUp) {
_scrollDirection = kBorderScrollUp;
_clickedScrollPart = kBorderScrollUp;
setHighlight(kBorderScrollUp);
calcScrollBar();
}
} else if (click == kBorderScrollDown) {
if (_scrollDirection != kBorderScrollDown) {
_scrollDirection = kBorderScrollDown;
_clickedScrollPart = kBorderScrollDown;
setHighlight(kBorderScrollDown);
calcScrollBar();
}
} else {
if (_scrollDirection != kBorderNone) {
_scrollDirection = kBorderNone;
setHighlight(kBorderNone);
calcScrollBar();
setScroll(0, 0);
}
}
return true;
}
} else if ((_wm->_mode & kWMModeWin95) && _isDragging) {
int scrollAreaTop, scrollAreaHeight, barY, barHeight;
calcWin95Scroll(scrollAreaTop, scrollAreaHeight, barY, barHeight);
int relMouseY = event.mouse.y - _dims.top;
int diffY = relMouseY - _dragStartY;
if (diffY != 0) {
int maxTextScroll = _mactext->getTextHeight() - getInnerDimensions().height();
int maxBarScroll = scrollAreaHeight - barHeight;
if (maxBarScroll > 0) {
float pixelsPerUnit = (float)maxTextScroll / (float)maxBarScroll;
int newScrollPos = _dragStartScrollPos + (int)(diffY * pixelsPerUnit);
newScrollPos = CLIP<int>(newScrollPos, 0, maxTextScroll);
if (newScrollPos != _mactext->_scrollPos) {
_mactext->_scrollPos = newScrollPos;
_mactext->setDirty(true);
_contentIsDirty = true;
_borderIsDirty = true;
calcScrollBar();
}
}
}
return true;
}
}
if (event.type == Common::EVENT_LBUTTONDOWN) {
if ((_wm->_mode & kWMModeWin95) && (click == kBorderScrollUp || click == kBorderScrollDown)) {
const BorderOffsets &offsets = getBorderOffsets();
int scrollBarWidth = offsets.right;
if (event.mouse.x >= _dims.right - scrollBarWidth && event.mouse.x < _dims.right) {
int scrollAreaTop, scrollAreaHeight, barY, barHeight;
calcWin95Scroll(scrollAreaTop, scrollAreaHeight, barY, barHeight);
int relMouseY = event.mouse.y - _dims.top;
if (relMouseY >= barY && relMouseY < barY + barHeight) {
_isDragging = true;
_dragStartY = relMouseY; // store window relative Y
_dragStartScrollPos = _mactext->_scrollPos;
return true;
}
}
}
}
if (event.type == Common::EVENT_LBUTTONUP) {
if (_isDragging) {
_isDragging = false;
return true;
}
}
if (event.type == Common::EVENT_KEYDOWN) {
if (!_editable)
return false;
_wm->setActiveWindow(getId());
if (event.kbd.flags & (Common::KBD_ALT | Common::KBD_CTRL | Common::KBD_META)) {
if (_mactext->processEvent(event))
return true;
}
switch (event.kbd.keycode) {
case Common::KEYCODE_BACKSPACE:
if (!_inputText.empty()) {
if (_mactext->hasSelection()) {
_mactext->cutSelection();
} else {
_inputText.deleteLastChar();
}
_inputIsDirty = true;
}
return true;
case Common::KEYCODE_RETURN:
undrawInput();
_inputIsDirty = true; // we force it to redraw input
return false; // Pass it to the higher level for processing
default:
if (event.kbd.ascii == '~')
return false;
if (event.kbd.ascii >= 0x20 && event.kbd.ascii <= 0x7f) {
if (_mactext->hasSelection())
_mactext->cutSelection();
_inputText += (char)event.kbd.ascii;
_inputIsDirty = true;
return true;
}
break;
}
}
if (hasAllFocus()) // We are being dragged or resized
return MacWindow::processEvent(event); // Pass it to upstream
if (event.type == Common::EVENT_WHEELUP) {
//setHighlight(kBorderScrollUp);
_mactext->scroll(-2);
_contentIsDirty = true;
calcScrollBar();
_nextWheelEventTime = g_system->getMillis() + SCROLLBAR_DELAY; // hide the bar after 300ms from now
return true;
}
if (event.type == Common::EVENT_WHEELDOWN) {
//setHighlight(kBorderScrollDown);
_mactext->scroll(2);
_contentIsDirty = true;
calcScrollBar();
_nextWheelEventTime = g_system->getMillis() + SCROLLBAR_DELAY; // hide the bar after 300ms from now
return true;
}
if (click == kBorderScrollUp || click == kBorderScrollDown) {
if (event.type == Common::EVENT_LBUTTONDOWN) {
setHighlight(click);
_scrollDirection = click;
_clickedScrollPart = click;
calcScrollBar();
return true;
} else if (event.type == Common::EVENT_LBUTTONUP) {
// reset scrolling state
_scrollDirection = kBorderNone;
_clickedScrollPart = kBorderNone;
setHighlight(kBorderNone);
// hide the scroll bar
if (!(_wm->_mode & kWMModeWin95)) {
setScroll(0, 0);
}
return true;
}
return false;
}
if (event.type == Common::EVENT_LBUTTONUP && _clickedScrollPart != kBorderNone) {
_scrollDirection = kBorderNone;
_clickedScrollPart = kBorderNone;
setHighlight(kBorderNone);
if (!(_wm->_mode & kWMModeWin95)) {
setScroll(0, 0);
}
return true;
}
if (click == kBorderInner) {
// Call callback for processing any events
if (_callback)
(*_callback)(click, event, _dataPtr);
if (!_selectable)
return false;
event.mouse.x -= _innerDims.left;
event.mouse.y -= _innerDims.top;
return _mactext->processEvent(event);
}
return MacWindow::processEvent(event);
}
void MacTextWindow::undrawInput() {
for (uint i = 0; i < _inputTextHeight; i++)
_mactext->removeLastLine();
_inputTextHeight = 0;
}
void MacTextWindow::drawInput() {
if (!_editable)
return;
int oldLen = _mactext->getLineCount() - _inputTextHeight;
// add new input line to the text
appendText(_inputText, _font, true);
// Now recalc new text height
int newLen = _mactext->getLineCount();
_inputTextHeight = newLen - oldLen;
_contentIsDirty = true;
}
void MacTextWindow::clearInput() {
_inputText.clear();
}
void MacTextWindow::appendInput(const Common::U32String &str) {
_inputText += str;
drawInput();
}
void MacTextWindow::appendInput(const Common::String &str) {
appendInput(Common::U32String(str));
}
} // End of namespace Graphics

View File

@@ -0,0 +1,142 @@
/* 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 GRAPHICS_MACGUI_MACTEXTWINDOW_H
#define GRAPHICS_MACGUI_MACTEXTWINDOW_H
#include "graphics/macgui/macfontmanager.h"
#include "graphics/macgui/mactext.h"
namespace Graphics {
class MacTextWindow : public MacWindow {
public:
MacTextWindow(MacWindowManager *wm, const MacFont *font, int fgcolor, int bgcolor, int maxWidth, TextAlign textAlignment, MacMenu *menu, int padding = 0);
MacTextWindow(MacWindowManager *wm, const Font *font, int fgcolor, int bgcolor, int maxWidth, TextAlign textAlignment, MacMenu *menu, int padding = 0);
virtual ~MacTextWindow();
virtual void resize(int w, int h) override;
void setDimensions(const Common::Rect &r) override;
virtual bool processEvent(Common::Event &event) override;
virtual bool draw(ManagedSurface *g, bool forceRedraw = false) override;
virtual bool draw(bool forceRedraw = false) override;
virtual void blit(ManagedSurface *g, Common::Rect &dest) override;
void setTextWindowFont(const MacFont *macFont);
const MacFont *getTextWindowFont();
void appendText(const Common::U32String &str, const MacFont *macFont = nullptr, bool skipAdd = false);
void appendText(const Common::String &str, const MacFont *macFont = nullptr, bool skipAdd = false);
void clearText();
void setMarkdownText(const Common::U32String &str);
void setEditable(bool editable) { _editable = editable; _mactext->setEditable(editable); }
void setActive(bool active) override { MacWindow::setActive(active); if (_editable) _mactext->setActive(active); }
void setSelectable(bool selectable) { _selectable = selectable; }
const Common::U32String &getInput() { return _inputText; }
void clearInput();
void appendInput(const Common::U32String &str);
void appendInput(const Common::String &str);
Common::U32String getSelection(bool formatted = false, bool newlines = true);
void clearSelection() { _mactext->clearSelection(); }
Common::U32String cutSelection() { return _mactext->cutSelection(); }
const SelectedText *getSelectedText() { return _mactext->getSelectedText(); }
uint32 getTextColor() { return _mactext->getTextColor(); }
uint32 getTextColor(int start, int end) { return _mactext->getTextColor(start, end); }
void setTextColor(uint32 color, int start, int end) { return _mactext->setTextColor(color, start, end); }
int getTextFont() { return _mactext->getTextFont(); }
int getTextFont(int start, int end) { return _mactext->getTextFont(start, end); }
int getTextSlant() { return _mactext->getTextSlant(); }
int getTextSlant(int start, int end) { return _mactext->getTextSlant(start, end); }
int getTextHeight() { return _mactext->getTextHeight(); }
int getLineHeight(int line) { return _mactext->getLineHeight(line); }
Common::U32String getTextChunk(int startRow, int startCol, int endRow, int endCol, bool formatted = false, bool newlines = true) { return _mactext->getTextChunk(startRow, startCol, endRow, endCol, formatted, newlines); }
Common::U32String getPlainText() { return _mactext->getPlainText(); }
Common::U32String getEditedString() { return _mactext->getEditedString(); };
void enforceTextFont(uint16 fontId) { return _mactext->enforceTextFont(fontId); }
void setTextFont(uint16 fontId, int start, int end) { return _mactext->setTextFont(fontId, start, end); }
void enforceTextSlant(int textSlant) { return _mactext->enforceTextSlant(textSlant); }
void setTextSlant(int textSlant, int start, int end) { return _mactext->setTextSlant(textSlant, start, end); }
int getRowCount() { return _mactext->getRowCount(); }
int getLineSpacing() { return _mactext->getLineSpacing(); }
int getTextSize() { return _mactext->getTextSize(); }
int getTextSize(int start, int end) { return _mactext->getTextSize(start, end); }
void setTextSize(int textSize) { return _mactext->setTextSize(textSize); }
void setTextSize(int textSize, int start, int end) { return _mactext->setTextSize(textSize, start, end); }
int getMouseLine(int x, int y);
virtual void setBorderColor(uint32 color) override { _mactext->setBorderColor(color); }
/**
* if we want to draw the text which color is not black, then we need to set _textColorRGB
* @param rgb text color you want to draw
*/
void setTextColorRGB (uint32 rgb) { _textColorRGB = rgb; }
private:
void init();
void calcScrollBar();
void undrawInput();
void drawInput();
void drawSelection();
void calcWin95Scroll(int &scrollAreaTop, int &scrollAreaHeight, int &barY, int &barHeight);
public:
bool _editable;
bool _selectable;
private:
MacText *_mactext;
const MacFont *_font;
const Font *_fontRef;
int _maxWidth;
Common::U32String _inputText;
uint _inputTextHeight;
bool _inputIsDirty;
WindowClick _scrollDirection;
uint32 _nextScrollTime;
uint32 _scrollDelay;
uint32 _nextWheelEventTime;
WindowClick _clickedScrollPart;
// dragging bar for win95
bool _isDragging;
int _dragStartY;
int _dragStartScrollPos;
MacMenu *_menu;
int _bgcolor;
int _textColorRGB;
};
} // End of namespace Graphics
#endif

View File

@@ -0,0 +1,176 @@
/* 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 "graphics/macgui/macwindowmanager.h"
#include "graphics/macgui/macwidget.h"
namespace Graphics {
MacWidget::MacWidget(MacWidget *parent, int x, int y, int w, int h, MacWindowManager *wm, bool focusable, uint16 border, uint16 gutter, uint16 shadow, uint32 fgcolor, uint32 bgcolor) :
_focusable(focusable), _parent(parent), _border(border), _gutter(gutter), _shadow(shadow), _wm(wm) {
_contentIsDirty = true;
_priority = 0;
_dims.left = x;
_dims.right = x + w + (2 * border) + (2 * gutter) + shadow;
_dims.top = y;
_dims.bottom = y + h + (2 * border) + gutter + shadow;
_fgcolor = fgcolor;
_bgcolor = bgcolor;
if (parent)
parent->_children.push_back(this);
_composeSurface = new ManagedSurface(_dims.width(), _dims.height(), _wm->_pixelformat);
_composeSurface->clear(_bgcolor);
_active = false;
_editable = false;
_borderColor = 0xff;
}
MacWidget::~MacWidget() {
if (_parent)
_parent->removeWidget(this, false);
if (_wm)
_wm->clearWidgetRefs(this);
if (_composeSurface) {
_composeSurface->free();
delete _composeSurface;
}
}
void MacWidget::setActive(bool active) {
if (!_focusable)
return;
if (active == _active)
return;
_active = active;
}
bool MacWidget::draw(bool forceRedraw) {
_contentIsDirty = false;
return false;
}
bool MacWidget::draw(ManagedSurface *g, bool forceRedraw) {
_contentIsDirty = false;
return false;
}
void MacWidget::blit(ManagedSurface *g, Common::Rect &dest) {
g->transBlitFrom(*_composeSurface, _composeSurface->getBounds(), dest, _wm->_colorGreen2);
}
void MacWidget::setColors(uint32 fg, uint32 bg) {
_fgcolor = fg;
_bgcolor = bg;
_contentIsDirty = true;
}
bool MacWidget::processEvent(Common::Event &event) {
return false;
}
void MacWidget::removeWidget(MacWidget *child, bool del) {
if (_children.size() == 0)
return;
for (uint i = 0; i < _children.size(); i++) {
if (_children[i] == child) {
if (del)
delete _children[i];
_children.remove_at(i);
}
}
}
MacWidget *MacWidget::findEventHandler(Common::Event &event, int dx, int dy) {
switch (event.type) {
case Common::EVENT_LBUTTONDOWN:
case Common::EVENT_LBUTTONUP:
case Common::EVENT_RBUTTONDOWN:
case Common::EVENT_RBUTTONUP:
case Common::EVENT_MOUSEMOVE:
{
Common::Point pos;
pos = g_system->getEventManager()->getMousePos();
if (_dims.contains(pos.x - dx, pos.y - dy)) {
uint priority = 0;
MacWidget *widget = nullptr;
for (uint i = 0; i < _children.size(); i++) {
MacWidget *res = _children[i]->findEventHandler(event, dx + _dims.left, dy + _dims.top);
if (res && res->_priority > priority) {
priority = res->_priority;
widget = res;
}
}
return widget ? widget : this;
}
break;
}
case Common::EVENT_KEYDOWN:
break;
default:
return nullptr;
}
return nullptr;
}
Common::Point MacWidget::getAbsolutePos() {
Common::Point absPoint = Common::Point(0, 0);
MacWidget *currentParent = _parent;
while (currentParent != nullptr) {
absPoint = Common::Point(currentParent->_dims.left, currentParent->_dims.top) + absPoint;
currentParent = currentParent->_parent;
}
return absPoint;
}
Common::Rect MacWidget::getAbsoluteDimensions() {
Common::Point absPos = getAbsolutePos();
Common::Rect dims = getDimensions();
dims.translate(absPos.x, absPos.y);
return dims;
}
} // End of namespace Graphics

118
graphics/macgui/macwidget.h Normal file
View File

@@ -0,0 +1,118 @@
/* 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 GRAPHICS_MACGUI_MACWIDGET_H
#define GRAPHICS_MACGUI_MACWIDGET_H
#include "common/array.h"
#include "common/events.h"
#include "common/rect.h"
#include "graphics/managed_surface.h"
namespace Common {
struct Event;
}
namespace Graphics {
class ManagedSurface;
class MacWindowManager;
class MacWidget {
public:
MacWidget(MacWidget *parent, int x, int y, int w, int h, MacWindowManager *wm, bool focusable, uint16 border = 0, uint16 gutter = 0, uint16 shadow = 0, uint32 fgcolor = 0, uint32 bgcolor= 0xff);
virtual ~MacWidget();
/**
* Accessor method for the complete dimensions of the widget.
* @return Dimensions of the widget relative to the parent's position.
*/
const Common::Rect &getDimensions() { return _dims; }
/**
* Method for indicating whether the widget is active or inactive.
* Used by the WM to handle focus on windows, etc.
* @param active Desired state of the widget.
*/
virtual void setActive(bool active);
/**
* Method for marking the widget for redraw.
* @param dirty True if the widget needs to be redrawn.
*/
void setDirty(bool dirty) { _contentIsDirty = dirty; }
virtual bool needsRedraw() { return _contentIsDirty; }
virtual bool draw(ManagedSurface *g, bool forceRedraw = false);
virtual bool draw(bool forceRedraw = false);
virtual void blit(ManagedSurface *g, Common::Rect &dest);
virtual bool processEvent(Common::Event &event);
virtual bool hasAllFocus() { return _active; }
virtual bool isEditable() { return _editable; }
virtual void setColors(uint32 fg, uint32 bg);
virtual void setBorderColor(uint32 color) {
_borderColor = color;
_contentIsDirty = true;
}
virtual void setDimensions(const Common::Rect &r) {
_dims = r;
}
Common::Point getAbsolutePos();
Common::Rect getAbsoluteDimensions();
MacWidget *findEventHandler(Common::Event &event, int dx, int dy);
void removeWidget(MacWidget *child, bool del = true);
Graphics::ManagedSurface *getSurface() { return _composeSurface; }
protected:
uint16 _border;
uint16 _gutter;
uint16 _shadow;
uint32 _borderColor;
uint32 _fgcolor, _bgcolor;
Graphics::ManagedSurface *_composeSurface;
bool _contentIsDirty;
public:
bool _focusable;
bool _active;
bool _editable;
uint _priority;
Common::Rect _dims;
MacWindowManager *_wm;
MacWidget *_parent;
Common::Array<MacWidget *> _children;
};
} // End of namespace Graphics
#endif

View File

@@ -0,0 +1,728 @@
/* 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/font.h"
#include "graphics/primitives.h"
#include "common/events.h"
#include "graphics/macgui/macfontmanager.h"
#include "graphics/macgui/macwindowmanager.h"
#include "graphics/macgui/macwindow.h"
#include "graphics/macgui/macwidget.h"
#include "image/bmp.h"
namespace Graphics {
BaseMacWindow::BaseMacWindow(int id, bool editable, MacWindowManager *wm) :
MacWidget(nullptr, 0, 0, 0, 0, wm, true), _id(id), _editable(editable) {
_callback = 0;
_dataPtr = 0;
_contentIsDirty = true;
_type = kWindowUnknown;
_visible = true;
_draggable = true;
}
void BaseMacWindow::setVisible(bool visible, bool silent) { _visible = visible; _wm->setFullRefresh(true); }
bool BaseMacWindow::isVisible() { return _visible; }
MacWindow::MacWindow(int id, bool scrollable, bool resizable, bool editable, MacWindowManager *wm) :
BaseMacWindow(id, editable, wm), _scrollable(scrollable), _resizable(resizable) {
_borderIsDirty = true;
_pattern = 0;
_hasPattern = false;
_highlightedPart = kBorderNone;
_beingDragged = false;
_beingResized = false;
_draggedX = _draggedY = 0;
_type = kWindowWindow;
_closeable = false;
_isTitleVisible = true;
_borderType = -1;
_borderWidth = kBorderWidth;
_macBorder.setWindow(this);
_macBorder.setWindowManager(wm);
_hasScrollBar = false;
_mode = 0;
}
MacWindow::MacWindow(const MacWindow &source) :
BaseMacWindow(source),
_borderIsDirty(source._borderIsDirty),
_innerDims(source._innerDims),
_dirtyRects(source._dirtyRects),
_hasScrollBar(source._hasScrollBar),
_mode(source._mode),
_macBorder(source._macBorder),
_pattern(source._pattern),
_hasPattern(source._hasPattern),
_scrollable(source._scrollable),
_resizable(source._resizable),
_closeable(source._closeable),
_isTitleVisible(source._isTitleVisible),
_borderWidth(source._borderWidth),
_beingDragged(source._beingDragged),
_beingResized(source._beingResized),
_draggedX(source._draggedX),
_draggedY(source._draggedY),
_highlightedPart(source._highlightedPart),
_title(source._title),
_shadowedTitle(source._shadowedTitle),
_borderType(source._borderType) {
// The copy constructor of ManagedSurface is deprecated
// Need to use copyFrom
_borderSurface.copyFrom(source._borderSurface);
}
void MacWindow::disableBorder() {
_macBorder.disableBorder();
}
const Font *MacWindow::getTitleFont() {
return _wm->_fontMan->getFont(Graphics::MacFont(kMacFontSystem, 12));
}
void MacWindow::setActive(bool active) {
bool changed = (active != _active);
MacWidget::setActive(active);
_borderIsDirty = true;
if (changed) {
WindowClick click = active ? kBorderActivate : kBorderDeactivate;
Common::Event event;
if (_callback)
_callback(click, event, _dataPtr);
}
}
bool MacWindow::isActive() const { return _active; }
void MacWindow::resize(int w, int h) {
w = MAX(w, (int)kWindowMinWidth);
h = MAX(h, (int)kWindowMinHeight);
if (_composeSurface->w == w && _composeSurface->h == h)
return;
_dims.setWidth(w);
_dims.setHeight(h);
updateInnerDims();
rebuildSurface();
}
void MacWindow::resizeInner(int w, int h) {
if (_composeSurface->w == w && _composeSurface->h == h)
return;
_innerDims.setWidth(w);
_innerDims.setHeight(h);
updateOuterDims();
rebuildSurface();
}
void MacWindow::rebuildSurface() {
_composeSurface->free();
_composeSurface->create(_innerDims.width(), _innerDims.height(), _wm->_pixelformat);
if (_hasPattern)
drawPattern();
_borderSurface.free();
_borderSurface.create(_dims.width(), _dims.height(), _wm->_pixelformat);
_contentIsDirty = true;
_borderIsDirty = true;
_wm->setFullRefresh(true);
}
void MacWindow::move(int x, int y) {
if (_dims.left == x && _dims.top == y)
return;
_dims.moveTo(x, y);
updateInnerDims();
_contentIsDirty = true;
_wm->setFullRefresh(true);
}
void MacWindow::setDimensions(const Common::Rect &r) {
resize(r.width(), r.height());
_dims.moveTo(r.left, r.top);
updateInnerDims();
_contentIsDirty = true;
_wm->setFullRefresh(true);
}
void MacWindow::setInnerDimensions(const Common::Rect &r) {
resizeInner(r.width(), r.height());
_innerDims.moveTo(r.left, r.top);
updateOuterDims();
_contentIsDirty = true;
_wm->setFullRefresh(true);
}
void MacWindow::setBackgroundPattern(int pattern) {
_pattern = pattern;
_hasPattern = true;
drawPattern();
_contentIsDirty = true;
}
bool MacWindow::draw(bool forceRedraw) {
if (!_borderIsDirty && !_contentIsDirty && !forceRedraw)
return false;
if (_borderIsDirty || forceRedraw)
drawBorder();
_contentIsDirty = false;
return true;
}
bool MacWindow::draw(ManagedSurface *g, bool forceRedraw) {
if (!draw(forceRedraw))
return false;
g->blitFrom(*_composeSurface, Common::Rect(0, 0, _composeSurface->w, _composeSurface->h), Common::Point(_innerDims.left, _innerDims.top));
uint32 transcolor = (_wm->_pixelformat.bytesPerPixel == 1) ? _wm->_colorGreen : 0;
g->transBlitFrom(_borderSurface, Common::Rect(0, 0, _borderSurface.w, _borderSurface.h), Common::Point(_dims.left, _dims.top), transcolor);
return true;
}
void MacWindow::blit(ManagedSurface *g, Common::Rect &dest) {
// Only the inner surface is blitted here
uint32 transcolor = (_wm->_pixelformat.bytesPerPixel == 1) ? _wm->_colorGreen2 : 0;
g->transBlitFrom(*_composeSurface, _composeSurface->getBounds(), dest, transcolor);
}
uint32 MacWindow::getBorderFlags() const {
uint32 flags = 0;
if (_active)
flags |= kWindowBorderActive;
if (!_title.empty() && _borderType != 0x02 && _borderType != 0x03 && _borderType != 0x0a && _borderType != 0x0b)
flags |= kWindowBorderTitle;
if (_hasScrollBar)
flags |= kWindowBorderScrollbar;
return flags;
}
void MacWindow::center(bool toCenter) {
if (!_wm)
return;
Common::Rect screen = _wm->getScreenBounds();
uint32 flags = getBorderFlags();
if (toCenter) {
move((screen.width() - _dims.width()) / 2, (screen.height() - _dims.height()) / 2);
} else if (_macBorder.hasBorder(flags) && _macBorder.hasOffsets()) {
move(_macBorder.getOffset().left, _macBorder.getOffset().top);
} else {
move(0, 0);
}
}
void MacWindow::updateInnerDims() {
if (_dims.isEmpty())
return;
uint32 flags = getBorderFlags();
if (_macBorder.hasBorder(flags) && _macBorder.hasOffsets()) {
_innerDims = Common::Rect(
_dims.left + _macBorder.getOffset().left,
_dims.top + _macBorder.getOffset().top,
_dims.right - _macBorder.getOffset().right,
_dims.bottom - _macBorder.getOffset().bottom);
} else {
_innerDims = _dims;
_innerDims.grow(-kBorderWidth);
}
// Prevent negative dimensions
_innerDims.right = MAX(_innerDims.left, _innerDims.right);
_innerDims.bottom = MAX(_innerDims.top, _innerDims.bottom);
}
void MacWindow::updateOuterDims() {
if (_innerDims.isEmpty())
return;
uint32 flags = getBorderFlags();
if (_macBorder.hasBorder(flags) && _macBorder.hasOffsets()) {
_dims = Common::Rect(
_innerDims.left - _macBorder.getOffset().left,
_innerDims.top - _macBorder.getOffset().top,
_innerDims.right + _macBorder.getOffset().right,
_innerDims.bottom + _macBorder.getOffset().bottom);
} else {
_dims = _innerDims;
_dims.grow(kBorderWidth);
}
}
void MacWindow::drawBorder() {
resizeBorderSurface();
_borderIsDirty = false;
ManagedSurface *g = &_borderSurface;
uint32 flags = getBorderFlags();
if (_macBorder.hasBorder(flags)) {
drawBorderFromSurface(g, flags);
} else {
warning("MacWindow: No Border Loaded");
setBorderType(0xff);
return;
}
if (_highlightedPart == kBorderScrollUp || _highlightedPart == kBorderScrollDown) {
_macBorder.drawScrollBar(g);
_highlightedPart = kBorderNone;
setHighlight(kBorderNone);
}
}
void MacWindow::drawBorderFromSurface(ManagedSurface *g, uint32 flags) {
if (_wm->_pixelformat.bytesPerPixel == 1) {
g->clear(_wm->_colorGreen);
}
_macBorder.blitBorderInto(*g, flags);
}
void MacWindow::setTitle(const Common::String &title) {
if (!_isTitleVisible) {
// Title hidden right now, so don't propagate the change but just cache it up for later
_shadowedTitle = title;
return;
}
_title = title;
_borderIsDirty = true;
_macBorder.setTitle(title, _borderSurface.w);
}
void MacWindow::setTitleVisible(bool visible) {
if (_isTitleVisible && !visible) {
_shadowedTitle = _title;
setTitle("");
_isTitleVisible = visible;
} else if (!_isTitleVisible && visible) {
_title = _shadowedTitle;
_isTitleVisible = visible;
setTitle(_title);
}
}
bool MacWindow::isTitleVisible() {
return _isTitleVisible;
}
void MacWindow::drawPattern() {
const byte *pat = _wm->getPatterns()[_pattern - 1];
for (int y = 0; y < _composeSurface->h; y++) {
for (int x = 0; x < _composeSurface->w; x++) {
if (_wm->_pixelformat.bytesPerPixel == 1) {
byte *dst = (byte *)_composeSurface->getBasePtr(x, y);
if (pat[y % 8] & (1 << (7 - (x % 8))))
*dst = _wm->_colorBlack;
else
*dst = _wm->_colorWhite;
} else {
uint32 *dst = (uint32 *)_composeSurface->getBasePtr(x, y);
if (pat[y % 8] & (1 << (7 - (x % 8))))
*dst = _wm->_colorBlack;
else
*dst = _wm->_colorWhite;
}
}
}
}
void MacWindow::setHighlight(WindowClick highlightedPart) {
if (_highlightedPart == highlightedPart)
return;
_highlightedPart = highlightedPart;
_borderIsDirty = true;
}
void MacWindow::setScroll(float scrollPos, float scrollSize) {
_macBorder.setScroll(scrollPos, scrollSize);
_borderIsDirty = true;
}
void MacWindow::loadBorder(Common::SeekableReadStream &file, uint32 flags, int lo, int ro, int to, int bo) {
_macBorder.loadBorder(file, flags, lo, ro, to, bo);
}
void MacWindow::loadBorder(Common::SeekableReadStream &file, uint32 flags, const BorderOffsets &offsets) {
_macBorder.loadBorder(file, flags, offsets);
}
void MacWindow::setBorder(Graphics::ManagedSurface *surface, uint32 flags, const BorderOffsets &offsets) {
_macBorder.setBorder(surface, flags, offsets);
}
void MacWindow::resizeBorderSurface() {
updateOuterDims();
if (_borderSurface.w != _dims.width() || _borderSurface.h != _dims.height()) {
_borderSurface.free();
_borderSurface.create(_dims.width(), _dims.height(), _wm->_pixelformat);
}
}
void MacWindow::setCloseable(bool closeable) {
_closeable = closeable;
}
void MacWindow::drawBox(ManagedSurface *g, int x, int y, int w, int h) {
Common::Rect r(x, y, x + w + 1, y + h + 1);
g->fillRect(r, _wm->_colorWhite);
g->frameRect(r, _wm->_colorBlack);
}
void MacWindow::fillRect(ManagedSurface *g, int x, int y, int w, int h, int color) {
Common::Rect r(x, y, x + w, y + h);
g->fillRect(r, color);
}
WindowClick MacWindow::isInBorder(int x, int y) const {
if (_innerDims.contains(x, y))
return kBorderInner;
if (isInCloseButton(x, y))
return kBorderCloseButton;
if (_resizable)
if (isInResizeButton(x, y))
return kBorderResizeButton;
if (_scrollable)
return isInScroll(x, y);
return kBorderBorder;
}
bool MacWindow::isInCloseButton(int x, int y) const {
int bLeft = kBorderWidth;
int bTop = kBorderWidth;
if (_macBorder.hasOffsets()) {
bLeft = _macBorder.getOffset().left;
bTop = _macBorder.getOffset().top;
}
if (_macBorder.getOffset().closeButtonTop > -1 && _macBorder.getOffset().closeButtonLeft > -1 &&
_macBorder.getOffset().closeButtonWidth > 0) {
int closeButtonTop = _macBorder.getOffset().closeButtonTop;
int closeButtonLeft = _macBorder.getOffset().closeButtonLeft;
int closeWidth = _macBorder.getOffset().closeButtonWidth;
return (x >= _innerDims.left + closeButtonLeft && x < _innerDims.left + closeButtonLeft + closeWidth && y >= _innerDims.top - closeButtonTop && y < _innerDims.top - closeButtonTop + closeWidth);
}
return (x >= _innerDims.left - bLeft && x < _innerDims.left && y >= _innerDims.top - bTop && y < _innerDims.top);
}
bool MacWindow::isInResizeButton(int x, int y) const {
int bRight = kBorderWidth;
int bBottom = kBorderWidth;
if (_macBorder.hasOffsets()) {
bRight = _macBorder.getOffset().right;
bBottom = _macBorder.getOffset().bottom;
}
if (_macBorder.getOffset().resizeButtonTop > -1 && _macBorder.getOffset().resizeButtonHeight > 0) {
int resizeButtonTop = _macBorder.getOffset().resizeButtonTop;
int resizeHeight = _macBorder.getOffset().resizeButtonHeight;
if (bBottom != resizeButtonTop) {
return (x >= _innerDims.right && x < _innerDims.right + bRight && y >= _innerDims.bottom - resizeHeight && y < _innerDims.bottom);
}
}
return (x >= _innerDims.right && x < _innerDims.right + bRight && y >= _innerDims.bottom && y < _innerDims.bottom + bBottom);
}
WindowClick MacWindow::isInScroll(int x, int y) const {
int bTop = kBorderWidth;
int bRight = kBorderWidth;
int bBottom = kBorderWidth;
if (_macBorder.hasOffsets()) {
bTop = _macBorder.getOffset().top;
bRight = _macBorder.getOffset().right;
bBottom = _macBorder.getOffset().bottom;
}
if (x >= _innerDims.right && x < _innerDims.right + bRight) {
if (y < _innerDims.top - bTop)
return kBorderBorder;
if (y >= _innerDims.bottom + bBottom)
return kBorderBorder;
if (y >= _innerDims.top + _innerDims.height() / 2)
return kBorderScrollDown;
return kBorderScrollUp;
}
if (y >= _innerDims.bottom && y < _innerDims.bottom + bBottom) {
if (x < _innerDims.left - bTop)
return kBorderBorder;
if (x >= _innerDims.right + bRight)
return kBorderBorder;
if (x >= _innerDims.left + _innerDims.width() / 2)
return kBorderScrollRight;
return kBorderScrollLeft;
}
return kBorderBorder;
}
bool MacWindow::processEvent(Common::Event &event) {
WindowClick click = isInBorder(event.mouse.x, event.mouse.y);
bool result = false;
switch (event.type) {
case Common::EVENT_MOUSEMOVE:
if (_wm->_mouseDown && _wm->_hoveredWidget && !_wm->_hoveredWidget->_dims.contains(event.mouse.x - _dims.left, event.mouse.y - _dims.top)) {
_wm->_hoveredWidget->setActive(false);
// since we de-active the hoveredWidget, so we need to check whether it's the activeWidget of wm
if (_wm->getActiveWidget() == _wm->_hoveredWidget)
_wm->setActiveWidget(nullptr);
_wm->_hoveredWidget = nullptr;
}
if (_beingDragged && _draggable) {
_dims.translate(event.mouse.x - _draggedX, event.mouse.y - _draggedY);
updateInnerDims();
_draggedX = event.mouse.x;
_draggedY = event.mouse.y;
_wm->setFullRefresh(true);
}
if (_beingResized) {
int minWidth = _borderWidth * 4;
int minHeight = minWidth;
uint32 flags = getBorderFlags();
if (_macBorder.hasBorder(flags) && _macBorder.hasOffsets()) {
minWidth = MAX(minWidth, _macBorder.getMinWidth(flags));
minHeight = MAX(minHeight, _macBorder.getMinHeight(flags));
}
resize(MAX(minWidth, _dims.width() + event.mouse.x - _draggedX),
MAX(minHeight, _dims.height() + event.mouse.y - _draggedY));
setTitle(_title);
_draggedX = event.mouse.x;
_draggedY = event.mouse.y;
_wm->setFullRefresh(true);
if (_callback)
(*_callback)(click, event, _dataPtr);
}
break;
case Common::EVENT_LBUTTONDOWN:
setHighlight(click);
if (click == kBorderBorder) {
_beingDragged = true;
_draggedX = event.mouse.x;
_draggedY = event.mouse.y;
}
if (click == kBorderResizeButton) {
_beingResized = true;
_draggedX = event.mouse.x;
_draggedY = event.mouse.y;
}
if (click == kBorderCloseButton && _closeable) {
_wm->removeWindow(this);
}
break;
case Common::EVENT_LBUTTONUP:
if (_beingDragged || _beingResized) {
WindowClick click1 = _beingDragged ? kBorderDragged : kBorderResized;
if (_callback)
_callback(click1, event, _dataPtr);
}
_beingDragged = false;
_beingResized = false;
setHighlight(kBorderNone);
break;
case Common::EVENT_KEYDOWN:
if (_callback)
result = _callback(kBorderNone, event, _dataPtr);
if (!_editable && !(_wm->getActiveWidget() && _wm->getActiveWidget()->isEditable()))
return result;
if (_wm->getActiveWidget())
return _wm->getActiveWidget()->processEvent(event) || result;
return result;
case Common::EVENT_WHEELUP:
case Common::EVENT_WHEELDOWN:
if (_callback)
result = _callback(kBorderNone, event, _dataPtr);
if (_wm->getActiveWidget() && _wm->getActiveWidget()->processEvent(event))
return true;
return result;
default:
if (_callback)
return _callback(kBorderNone, event, _dataPtr);
return false;
}
event.mouse.x -= _dims.left;
event.mouse.y -= _dims.top;
MacWidget *w = findEventHandler(event, -_dims.left + _innerDims.left, -_dims.top + _innerDims.top);
if (w && w != this) {
_wm->_hoveredWidget = w;
if (w->processEvent(event))
result = true;
}
if (_callback)
result = (*_callback)(click, event, _dataPtr) || result;
return result;
}
void MacWindow::setBorderType(int borderType) {
_borderType = borderType;
if (borderType < 0) {
_macBorder.disableBorder();
} else {
_macBorder.setBorderType(borderType);
}
}
void MacWindow::loadInternalBorder(uint32 flags) {
_macBorder.loadInternalBorder(flags);
}
void MacWindow::addDirtyRect(const Common::Rect &r) {
if (!r.isValidRect())
return;
Common::Rect bounds = r;
bounds.clip(Common::Rect(_innerDims.width(), _innerDims.height()));
if (bounds.width() > 0 && bounds.height() > 0)
_dirtyRects.push_back(bounds);
}
void MacWindow::markAllDirty() {
_dirtyRects.clear();
_dirtyRects.push_back(Common::Rect(_composeSurface->w, _composeSurface->h));
}
void MacWindow::mergeDirtyRects() {
Common::List<Common::Rect>::iterator rOuter, rInner;
// Process the dirty rect list to find any rects to merge
for (rOuter = _dirtyRects.begin(); rOuter != _dirtyRects.end(); ++rOuter) {
rInner = rOuter;
while (++rInner != _dirtyRects.end()) {
if ((*rOuter).intersects(*rInner)) {
// These two rectangles overlap, so merge them
rOuter->extend(*rInner);
// remove the inner rect from the list
_dirtyRects.erase(rInner);
// move back to beginning of list
rInner = rOuter;
}
}
}
}
Common::Rect MacWindow::getDirtyRectBounds() {
Common::Rect result;
if (_dirtyRects.size() == 0)
return result;
result = Common::Rect(_dirtyRects.front());
for (auto &r : _dirtyRects) {
result.extend(r);
}
return result;
}
} // End of namespace Graphics

461
graphics/macgui/macwindow.h Normal file
View File

@@ -0,0 +1,461 @@
/* 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 GRAPHICS_MACGUI_MACWINDOW_H
#define GRAPHICS_MACGUI_MACWINDOW_H
#include "common/stream.h"
#include "graphics/managed_surface.h"
#include "graphics/nine_patch.h"
#include "graphics/font.h"
#include "graphics/macgui/macwidget.h"
#include "graphics/macgui/macwindowborder.h"
namespace Graphics {
class MacWindowManager;
class MacWindowBorder;
class MacWidget;
namespace MacWindowConstants {
enum WindowType {
kWindowUnknown,
kWindowWindow,
kWindowMenu
};
enum {
kBorderWidth = 17,
kWindowMinWidth = 70,
kWindowMinHeight = 70
};
enum WindowClick {
kBorderNone = 0,
kBorderScrollUp,
kBorderScrollDown,
kBorderScrollLeft,
kBorderScrollRight,
kBorderCloseButton,
kBorderInner,
kBorderBorder,
kBorderResizeButton,
kBorderActivate,
kBorderDeactivate,
kBorderDragged,
kBorderResized,
kBorderMaximizeButton,
};
enum {
kWindowModeDynamicScrollbar = 1 << 0
};
}
using namespace MacWindowConstants;
/**
* Abstract class that defines common functionality for all window classes.
* It supports event callbacks and drawing.
*/
class BaseMacWindow : public MacWidget {
public:
/**
* Base constructor.
* @param id ID of the window.
* @param editable True if the window is editable.
* @param wm Pointer to the MacWindowManager that owns the window.
*/
BaseMacWindow(int id, bool editable, MacWindowManager *wm);
virtual ~BaseMacWindow() {}
/**
* Accessor method to the id of the window.
* @return The id set in the constructor.
*/
int getId() { return _id; }
/**
* Accessor method to the type of window.
* Each subclass must indicate it's type.
* @return The type of the window.
*/
WindowType getType() { return _type; }
/**
* Accessor method to check whether the window is editable (e.g. for resizing).
* @return True if the window is editable as indicated in the constructor.
*/
bool isEditable() { return _editable; }
/**
* Mutator to change the visible state of the window.
* @param visible Target state.
*/
virtual void setVisible(bool visible, bool silent = false);
/**
* Accessor to determine whether a window is active.
* @return True if the window is active.
*/
bool isVisible();
/**
* Method to access the entire interior surface of the window (e.g. to draw an image).
* @return A pointer to the entire interior surface of the window.
*/
ManagedSurface *getWindowSurface() { return _composeSurface; }
/**
* Method to access the border surface of the window.
* @return A pointer to the border surface of the window.
*/
virtual ManagedSurface *getBorderSurface() = 0;
/**
* Accessor to retrieve the dimensions of the inner surface of the window
* (i.e. without taking borders into account).
* Note that the returned dimensions' position is relative to the WM's
* screen, just like in getDimensions().
* @return The inner dimensions of the window.
*/
virtual const Common::Rect &getInnerDimensions() = 0;
/**
* Method called to internally draw the window. This relies on the window
* being marked as dirty unless otherwise specified.
* @param forceRedraw Its behavior depends on the subclass.
*/
virtual bool draw(bool forceRedraw = false) = 0;
/**
* Method called to draw the window into the target surface.
* This method is most often called by the WM, and relies on
* the window being marked as dirty unless otherwise specified.
* @param g Surface on which to draw the window.
* @param forceRedraw It's behavior depends on the subclass.
*/
virtual bool draw(ManagedSurface *g, bool forceRedraw = false) = 0;
/**
* Method called by the WM when there is an event concerning the window.
* Note that depending on the subclass of the window, it might not be called
* if the window is not active.
* @param event Event to be processed.
* @return true If the event was successfully consumed and processed.
*/
virtual bool processEvent(Common::Event &event) = 0;
/**
* Method that checks if the window is needs redrawing.
*/
virtual bool isDirty() = 0;
/**
* Set the callback that will be used when an event needs to be processed.
* @param callback A function pointer to a function that accepts:
* - A WindowClick, the pert of the window that was clicked.
* - The event to be processed.
* - Any additional required data (e.g. the engine's GUI).
*/
void setCallback(bool (*callback)(WindowClick, Common::Event &, void *), void *data) { _callback = callback; _dataPtr = data; }
/**
* Mutator to change the draggable state of the window.
* @param draggable Target state.
*/
void setDraggable(bool draggable) { _draggable = draggable; }
protected:
int _id;
WindowType _type;
bool _editable;
bool (*_callback)(WindowClick, Common::Event &, void *);
void *_dataPtr;
bool _visible;
bool _draggable;
};
/**
* An implementation of an ordinary window in the Mac interface.
* It supports custom resizing, scrolling, borders, etc.
*/
class MacWindow : public BaseMacWindow {
public:
/**
* Construct a simple window, with the default settings.
* Note that the scroll must be implemented in the event handling,
* even if the scrollable flag is set to true.
* @param id See BaseMacWindow.
* @param scrollable True if the window can be scrolled.
* @param resizable True if the window can be resized.
* @param editable See BaseMacWindow.
* @param wm See BaseMacWindow.
*/
MacWindow(int id, bool scrollable, bool resizable, bool editable, MacWindowManager *wm);
/**
* Copy constructor for MacWindow
* Needs defining because ManagedSurface has a deprecated default copy constructor
* @param source Source window to copy from
*/
MacWindow(const MacWindow &source);
virtual ~MacWindow() {}
/**
* Change the window's location to fixed coordinates (not delta).
* @param x New left position of the window relative to the WM's screen.
* @param y New top position of the window relative to the WM's screen.
*/
void move(int x, int y);
/*
* Change the width and the height of the window (outer dimensions).
* @param w New width of the window.
* @param h New height of the window.
*/
virtual void resize(int w, int h);
/*
* Change the width and the height of the inner window.
* @param w New width of the window.
* @param h New height of the window.
*/
virtual void resizeInner(int w, int h);
/**
* Change the dimensions of the window ([0, 0, 0, 0] by default).
* Note that this can be used to update both the position and the size
* of the window, although move() and resize() might be more comfortable.
* @param r The desired dimensions of the window.
*/
void setDimensions(const Common::Rect &r) override;
/**
* Change the inner dimension of the window.
* Note that this changes the window inner dimension and calculates
* outer dimension (ie with border, etc)
* @param r The desired dimensions of the window.
*/
void setInnerDimensions(const Common::Rect &r);
/**
* Set a background pattern for the window.
* @param pattern
*/
void setBackgroundPattern(int pattern);
/**
* Similar to that described in BaseMacWindow.
* @param g See BaseMacWindow.
* @param forceRedraw If true, the borders are guarranteed to redraw.
*/
bool draw(ManagedSurface *g, bool forceRedraw = false) override;
bool draw(bool forceRedraw = false) override;
void blit(ManagedSurface *g, Common::Rect &dest) override;
const Common::Rect &getInnerDimensions() override { return _innerDims; }
ManagedSurface *getBorderSurface() override { return &_borderSurface; }
/**
* Centers the window using the dimensions of the parent window manager, or undoes this; does
* nothing if WM is null.
*/
void center(bool toCenter = true);
/**
* Mutator to change the active state of the window.
* Most often called from the WM.
* @param active Target state.
*/
void setActive(bool active) override;
/**
* Accessor to determine whether a window is active.
* @return True if the window is active.
*/
bool isActive() const;
/**
* Mutator to change the title of the window.
* @param title Target title.
*/
void setTitle(const Common::String &title);
/**
* Set visibility of window title.
* @param visible visibility of window.
*/
virtual void setTitleVisible(bool visible);
/**
* Get visibility of window title.
*/
bool isTitleVisible();
/**
* Accessor to get the title of the window.
* @return Title.
*/
const Common::String &getTitle() const { return _title; };
/**
* Highlight the target part of the window.
* Used for the default borders.
* @param highlightedPart Part to be highlighted.
*/
void setHighlight(WindowClick highlightedPart);
/**
* Set the scroll poisition.
* @param scrollPos Target scroll position.
* @param scrollSize Size of the scrolling bar.
*/
void setScroll(float scrollPos, float scrollSize);
/**
* See BaseMacWindow.
*/
bool processEvent(Common::Event &event) override;
bool hasAllFocus() override { return _beingDragged || _beingResized; }
/**
* Set arbitrary border from a BMP data stream, with custom border offsets.
* Note that the BMP has to be 9patch compliant. For examples, go to:
* https://github.com/blorente/MacVenture-Extract-Guide/tree/master/borders
* @param file The BMP data stream with the desired border.
* @param active Whether the border corresponds with the active state of the window.
* @param lo Width of the left side of the border, in pixels.
* @param ro Width of the right side of the border, in pixels.
* @param to Width of the top side of the border, in pixels.
* @param bo Width of the bottom side of the border, in pixels.
*/
void loadBorder(Common::SeekableReadStream &file, uint32 flags, int lo = -1, int ro = -1, int to = -1, int bo = -1);
void loadBorder(Common::SeekableReadStream &file, uint32 flags, const BorderOffsets &offsets);
void setBorder(Graphics::ManagedSurface *surface, uint32 flags, const BorderOffsets &offsets);
void disableBorder();
void loadInternalBorder(uint32 flags);
/**
* we better set this before we load the border
* @param scrollbar state
*/
void enableScrollbar(bool active) { _hasScrollBar = active; }
/**
* Indicate whether the window can be closed (false by default).
* @param closeable True if the window can be closed.
*/
void setCloseable(bool closeable);
/**
* Mutator to change the border type.
* @param borderType Border type.
*/
void setBorderType(int borderType);
/**
* Accessor to get the border type.
* @return Border type.
*/
int getBorderType() const { return _borderType; };
/**
* We should call this method whenever we need border flags
* don't calc border flags yourself
* @return Border flags
*/
uint32 getBorderFlags() const;
void addDirtyRect(const Common::Rect &r);
void markAllDirty();
void mergeDirtyRects();
Common::Rect getDirtyRectBounds();
void clearDirtyRects() { _dirtyRects.clear(); }
Common::List<Common::Rect> &getDirtyRectList() { return _dirtyRects; }
bool isDirty() override { return _borderIsDirty || _contentIsDirty; }
void setBorderDirty(bool dirty) { _borderIsDirty = true; }
void setContentDirty(bool dirty) { _contentIsDirty = true; }
void resizeBorderSurface();
void setMode(uint32 mode) { _mode = mode; }
void setBorderOffsets(BorderOffsets &offsets) { _macBorder.setOffsets(offsets); }
const BorderOffsets &getBorderOffsets() const { return _macBorder.getOffset(); }
void updateInnerDims();
private:
void rebuildSurface(); // Propagate dimensions change and recreate patter/borders, etc.
void drawBorderFromSurface(ManagedSurface *g, uint32 flags);
void drawPattern();
void drawBox(ManagedSurface *g, int x, int y, int w, int h);
void fillRect(ManagedSurface *g, int x, int y, int w, int h, int color);
const Font *getTitleFont();
void updateOuterDims();
bool isInCloseButton(int x, int y) const;
bool isInResizeButton(int x, int y) const;
WindowClick isInScroll(int x, int y) const;
protected:
void drawBorder();
WindowClick isInBorder(int x, int y) const;
protected:
ManagedSurface _borderSurface;
bool _borderIsDirty;
Common::Rect _innerDims;
Common::List<Common::Rect> _dirtyRects;
bool _hasScrollBar;
uint32 _mode;
private:
MacWindowBorder _macBorder;
int _pattern;
bool _hasPattern;
bool _scrollable;
bool _resizable;
bool _closeable;
bool _isTitleVisible;
int _borderWidth;
bool _beingDragged, _beingResized;
int _draggedX, _draggedY;
WindowClick _highlightedPart;
Common::String _title;
Common::String _shadowedTitle;
int _borderType;
};
} // End of namespace Graphics
#endif

View File

@@ -0,0 +1,349 @@
/* 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 "graphics/macgui/macwindowborder.h"
#include "graphics/macgui/macwindowmanager.h"
#include "graphics/macgui/macfontmanager.h"
namespace Graphics {
using namespace Graphics::MacGUIConstants;
static const byte noborderData[3][3] = {
{ 0, 1, 0 },
{ 1, 0, 1 },
{ 0, 1, 0 },
};
MacWindowBorder::MacWindowBorder() {
_border = Common::Array<NinePatchBitmap *>(kWindowBorderMaxFlag);
_window = nullptr;
_wm = nullptr;
_useInternalBorder = false;
for (uint32 i = 0; i < kWindowBorderMaxFlag; i++)
_border[i] = nullptr;
_borderOffsets.left = -1;
_borderOffsets.right = -1;
_borderOffsets.top = -1;
_borderOffsets.bottom = -1;
_borderOffsets.titleTop = -1;
_borderOffsets.titleBottom = -1;
_borderOffsets.dark = false;
_borderOffsets.titlePos = 0;
_borderOffsets.closeButtonTop = -1;
_borderOffsets.closeButtonLeft = -1;
_borderOffsets.closeButtonWidth = 0;
_borderOffsets.resizeButtonTop = -1;
_borderOffsets.resizeButtonHeight = 0;
_borderOffsets.upperScrollHeight = 0;
_borderOffsets.lowerScrollHeight = 0;
_borderType = 0;
_scrollSize = -1;
_scrollPos = 0;
}
MacWindowBorder::~MacWindowBorder() {
for (uint32 i = 0; i < kWindowBorderMaxFlag; i++) {
if (_border[i])
delete _border[i];
}
}
bool MacWindowBorder::hasBorder(uint32 flags) {
if (flags >= kWindowBorderMaxFlag) {
warning("Accessing non-existed border type, %d", flags);
return false;
}
if (_useInternalBorder && !_border[flags]) {
loadInternalBorder(flags);
}
return _border[flags] != nullptr;
}
void MacWindowBorder::disableBorder() {
const byte palette[] = {
255, 0, 255,
0, 0, 0,
255, 255, 255,
};
Graphics::ManagedSurface *noborder = new Graphics::ManagedSurface();
noborder->create(3, 3, Graphics::PixelFormat::createFormatCLUT8());
noborder->setPalette(palette, 0, 3);
noborder->setTransparentColor(0);
for (int y = 0; y < 3; y++)
for (int x = 0; x < 3; x++)
*((byte *)noborder->getBasePtr(x, y)) = noborderData[y][x];
setBorder(noborder, kWindowBorderActive);
Graphics::ManagedSurface *noborder2 = new Graphics::ManagedSurface();
noborder2->copyFrom(*noborder);
setBorder(noborder2, 0);
}
void MacWindowBorder::addBorder(ManagedSurface *source, uint32 flags, int titlePos) {
if (flags >= kWindowBorderMaxFlag) {
warning("Accessing non-existed border type");
return;
}
if (_border[flags])
delete _border[flags];
_border[flags] = new NinePatchBitmap(source, true, titlePos);
if (_border[flags]->getPadding().isValidRect() && _border[flags]->getPadding().left > -1 && _border[flags]->getPadding().top > -1)
setOffsets(_border[flags]->getPadding());
}
bool MacWindowBorder::hasOffsets() const {
return _borderOffsets.left > -1 && _borderOffsets.right > -1
&& _borderOffsets.top > -1 && _borderOffsets.bottom > -1;
}
void MacWindowBorder::setOffsets(int left, int right, int top, int bottom) {
_borderOffsets.left = left;
_borderOffsets.right = right;
_borderOffsets.top = top;
_borderOffsets.bottom = bottom;
}
void MacWindowBorder::setOffsets(Common::Rect &rect) {
_borderOffsets.left = rect.left;
_borderOffsets.right = rect.right;
_borderOffsets.top = rect.top;
_borderOffsets.bottom = rect.bottom;
}
void MacWindowBorder::setOffsets(const BorderOffsets &offsets) {
_borderOffsets = offsets;
}
BorderOffsets &MacWindowBorder::getOffset() {
return _borderOffsets;
}
const BorderOffsets &MacWindowBorder::getOffset() const {
return _borderOffsets;
}
int MacWindowBorder::getMinWidth(uint32 flags) const {
return _border[flags]->getMinWidth();
}
int MacWindowBorder::getMinHeight(uint32 flags) const {
return _border[flags]->getMinHeight();
}
void MacWindowBorder::setTitle(const Common::String& title, int width) {
_title = title;
const Graphics::Font *font = _wm->_fontMan->getFont(Graphics::MacFont(kMacFontSystem, 12));
int titleWidth = font->getStringWidth(_title) + getOffset().titlePadding;
// if titleWidth is changed, then we modify it
// here, we change all the border that has title
for (uint32 i = 0; i < kWindowBorderMaxFlag; i++) {
if ((_border[i] != nullptr) && (i & kWindowBorderTitle)) {
int maxWidth = MAX<int>(width - _border[i]->getMinWidth() + getOffset().titlePadding, 0);
if (titleWidth > maxWidth)
titleWidth = maxWidth;
_border[i]->modifyTitleWidth(titleWidth);
}
}
}
void MacWindowBorder::drawScrollBar(ManagedSurface *g) {
// here, we first check the _scrollSize, and if it is negative, then we don't draw the scrollBar
if (_scrollSize < 0)
return;
int width = _borderOffsets.right;
int height = _borderOffsets.upperScrollHeight;
int rx1 = g->w - width + 2;
int ry1 = height + _scrollPos;
int rx2 = rx1 + width - 5;
int ry2 = ry1 + _scrollSize ;
Common::Rect rr(rx1, ry1, rx2, ry2);
MacPlotData pd(g, nullptr, &_wm->getPatterns(), 1, 0, 0, 1, _wm->_colorWhite, true);
Primitives &primitives = _wm->getDrawInvertPrimitives();
primitives.drawFilledRect1(rr, _wm->_colorWhite, &pd);
// after drawing, we set the _scrollSize negative, to indicate no more drawing is needed
// if win95 mode is enabled, then we keep on drawing the scrollbar
if (!(_wm->_mode & kWMModeWin95))
_scrollSize = -1;
}
void MacWindowBorder::drawTitle(ManagedSurface *g, int titleOffset, int minWidth) {
const Graphics::Font *font = _wm->_fontMan->getFont(Graphics::MacFont(kMacFontSystem, 12));
int width = g->w;
int titleColor = getOffset().dark ? _wm->_colorWhite: _wm->_colorBlack;
int titleY = getOffset().titleTop;
int titleWidth = font->getStringWidth(_title) + 8;
int yOff = _wm->_fontMan->hasBuiltInFonts() ? 3 : 1;
int maxWidth = MAX<int>(width - minWidth - 7 - 4, 0);
if (titleWidth > maxWidth)
titleWidth = maxWidth;
font->drawString(g, _title, titleOffset + 4, titleY + yOff, titleWidth, titleColor);
}
void MacWindowBorder::setBorderType(int type) {
if (_window)
setOffsets(_window->_wm->getBorderOffsets(type));
_useInternalBorder = true;
_borderType = type;
}
void MacWindowBorder::loadBorder(Common::SeekableReadStream &file, uint32 flags, int lo, int ro, int to, int bo) {
BorderOffsets offsets;
offsets.left = lo;
offsets.right = ro;
offsets.top = to;
offsets.bottom = bo;
offsets.titleTop = -1;
offsets.titleBottom = -1;
offsets.titlePos = 0;
offsets.dark = false;
offsets.closeButtonTop = -1;
offsets.closeButtonLeft = -1;
offsets.closeButtonWidth = 0;
offsets.resizeButtonTop = -1;
offsets.resizeButtonHeight = 0;
offsets.upperScrollHeight = 0;
offsets.lowerScrollHeight = 0;
loadBorder(file, flags, offsets);
}
void MacWindowBorder::loadBorder(Common::SeekableReadStream &file, uint32 flags, const BorderOffsets &offsets) {
Image::BitmapDecoder bmpDecoder;
bmpDecoder.loadStream(file);
Graphics::ManagedSurface *surface = new Graphics::ManagedSurface();
surface->copyFrom(*bmpDecoder.getSurface());
surface->setPalette(bmpDecoder.getPalette().data(), 0,
bmpDecoder.getPalette().size());
if (surface->format.isCLUT8()) {
const Graphics::Palette &palette = bmpDecoder.getPalette();
uint i = palette.find(255, 0, 255);
if (i < palette.size())
surface->setTransparentColor(i);
} else {
const Graphics::PixelFormat requiredFormat_4byte(4, 8, 8, 8, 8, 24, 16, 8, 0);
surface->convertToInPlace(requiredFormat_4byte);
surface->setTransparentColor(surface->format.RGBToColor(255, 0, 255));
}
setBorder(surface, flags, offsets);
}
void MacWindowBorder::setBorder(Graphics::ManagedSurface *surface, uint32 flags, int lo, int ro, int to, int bo) {
BorderOffsets offsets;
offsets.left = lo;
offsets.right = ro;
offsets.top = to;
offsets.bottom = bo;
offsets.titleTop = -1;
offsets.titleBottom = -1;
offsets.titlePos = 0;
offsets.dark = false;
offsets.closeButtonTop = -1;
offsets.closeButtonLeft = -1;
offsets.closeButtonWidth = 0;
offsets.resizeButtonTop = -1;
offsets.resizeButtonHeight = 0;
offsets.upperScrollHeight = 0;
offsets.lowerScrollHeight = 0;
setBorder(surface, flags, offsets);
}
void MacWindowBorder::setBorder(Graphics::ManagedSurface *surface, uint32 flags, const BorderOffsets &offsets) {
addBorder(surface, flags, offsets.titlePos);
if ((flags & kWindowBorderActive) && offsets.left + offsets.right + offsets.top + offsets.bottom > -4) { // Checking against default -1
setOffsets(offsets);
if (_window)
_window->resizeBorderSurface();
}
if (_window) {
_window->setBorderDirty(true);
_window->_wm->setFullRefresh(true);
}
}
void MacWindowBorder::loadInternalBorder(uint32 flags) {
if (_borderType < 0) {
warning("trying to load non-existing internal border type");
return;
}
const BorderOffsets &offsets = _wm->getBorderOffsets(_borderType);
Common::SeekableReadStream *file = _wm->getBorderFile(_borderType, flags);
if (file) {
loadBorder(*file, flags, offsets);
delete file;
}
}
void MacWindowBorder::blitBorderInto(ManagedSurface &destination, uint32 flags) {
if (flags >= kWindowBorderMaxFlag) {
warning("Accessing non-existed border type");
return;
}
NinePatchBitmap *src = _border[flags];
if (!src) {
warning("Attempt to blit uninitialized border");
return;
}
if (destination.w == 0 || destination.h == 0) {
warning("Attempt to draw %d x %d window", destination.w, destination.h);
return;
}
// we add a special check here, if we have title but the titleWidth is zero, then we try to recalc it
if ((flags & kWindowBorderTitle) && _border[flags]->getTitleWidth() == 0) {
setTitle(_title, destination.w);
}
src->blit(destination, 0, 0, destination.w, destination.h, _wm);
if (flags & kWindowBorderTitle)
drawTitle(&destination, src->getTitleOffset(), _border[flags]->getMinWidth());
if (flags & kWindowBorderScrollbar)
drawScrollBar(&destination);
}
} // End of namespace Graphics

View File

@@ -0,0 +1,184 @@
/* 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 GRAPHICS_MACGUI_MACWINDOWBORDER_H
#define GRAPHICS_MACGUI_MACWINDOWBORDER_H
#include "common/str.h"
#include "common/list.h"
#include "graphics/managed_surface.h"
#include "graphics/primitives.h"
#include "image/bmp.h"
namespace Graphics {
class MacWindow;
class MacWindowManager;
class NinePatchBitmap;
enum {
kWindowBorderActive = 1 << 0,
kWindowBorderTitle = 1 << 1,
kWindowBorderScrollbar = 1 << 2,
kWindowBorderMaxFlag = 1 << 3
};
enum {
kBorderScroll = 1000
};
enum {
kWinBorderWin95Scrollbar = kBorderScroll + 0x00,
kWindowBorderWin95NoBorderScrollbar,
kWindowBorderMacOSNoBorderScrollbar
};
struct BorderOffsets {
int left;
int right;
int top;
int bottom;
int titleTop;
int titleBottom;
bool dark;
int titlePos;
int closeButtonTop;
int closeButtonLeft;
int closeButtonWidth;
int resizeButtonTop;
int resizeButtonHeight;
int upperScrollHeight;
int lowerScrollHeight;
int titlePadding;
};
/**
* A representation of a custom border, which allows for arbitrary border offsets
* and nine-patch resizable displays for both active and inactive states.
* However, the border offsets are the same for both active and inactive states.
*/
class MacWindowBorder {
public:
MacWindowBorder();
~MacWindowBorder();
/**
* Accessor to check whether or not a border is loaded.
* @param check whether the border type we want has been initialized.
* @return True if the checked state has a border loaded, false otherwise.
*/
bool hasBorder(uint32 flags);
/**
* Add the given surface as the display of the border in the state that is instructed by flag.
* Will fail if there is already a border.
* @param The surface that will be displayed.
* @param The border type indicated by flag
* @param The title position of bmp image
*/
void addBorder(ManagedSurface *source, uint32 flags, int titlePos = 0);
/**
* Accessor function for the custom offsets.
* @return True if custom offsets have been indicated (setOffsets has been called previously).
*/
bool hasOffsets() const;
/**
* Mutator method to indicate the custom border offsets.
* These should be set to the desired thickness of each side of the border.
* e.g. For a border that is 10 pixels wide and 5 pixels tall, the call should be:
* setOffsets(10, 10, 5, 5)
* Note that this function does not check whether those borders form
* a valid rect when combined with the window dimensions.
* @param left Thickness (in pixels) of the left side of the border.
* @param right Thickness (in pixels) of the right side of the border.
* @param top Thickness (in pixels) of the top side of the border.
* @param bottom Thickness (in pixels) of the bottom side of the border.
*/
void setOffsets(int left, int right, int top, int bottom);
void setOffsets(Common::Rect &rect);
void setOffsets(const BorderOffsets &offsets);
/**
* Accessor method to retrieve a given border.
* Note that it does not check for validity, and thus if setOffsets
* was not called before it might return garbage.
* @param offset The identifier of the offset wanted.
* @return The desired offset in pixels.
*/
BorderOffsets &getOffset();
const BorderOffsets &getOffset() const;
int getMinWidth(uint32 flags) const;
int getMinHeight(uint32 flags) const;
/**
* Blit the desired border (active or inactive) into a destination surface.
* It automatically resizes the border to fit the given surface.
* @param destination The surface we want to blit into.
* @param border type that you want to draw
* @param wm The window manager.
*/
void blitBorderInto(ManagedSurface &destination, uint32 flags);
void setTitle(const Common::String& title, int width);
void setScroll(int scrollPos, int scrollSize) { _scrollPos = scrollPos, _scrollSize = scrollSize; }
void drawTitle(ManagedSurface *g, int titleOffset, int minWidth);
void drawScrollBar(ManagedSurface *g);
// we should call this method as soon as the macwindowborder is constructed
void setWindow(MacWindow *window) { _window = window; }
void setWindowManager(MacWindowManager *wm) { _wm = wm; }
void setBorderType(int type);
void disableBorder();
void loadBorder(Common::SeekableReadStream &file, uint32 flags, int lo = -1, int ro = -1, int to = -1, int bo = -1);
void loadBorder(Common::SeekableReadStream &file, uint32 flags, const BorderOffsets &offsets);
void loadInternalBorder(uint32 flags);
void setBorder(Graphics::ManagedSurface *surface, uint32 flags, int lo = -1, int ro = -1, int to = -1, int bo = -1);
void setBorder(Graphics::ManagedSurface *surface, uint32 flags, const BorderOffsets &offsets);
private:
int _scrollPos, _scrollSize;
Common::String _title;
Common::Array<NinePatchBitmap *> _border;
MacWindow *_window;
MacWindowManager *_wm;
BorderOffsets _borderOffsets;
bool _useInternalBorder;
int _borderType;
};
} // End of namespace Graphics
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,504 @@
/* 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 GRAPHICS_MACGUI_MACWINDOWMANAGER_H
#define GRAPHICS_MACGUI_MACWINDOWMANAGER_H
#include "common/hashmap.h"
#include "common/list.h"
#include "common/mutex.h"
#include "common/stack.h"
#include "common/events.h"
#include "graphics/font.h"
#include "graphics/fontman.h"
#include "graphics/palette.h"
#include "graphics/macgui/macwindow.h"
#include "graphics/macgui/macmenu.h"
#include "engines/engine.h"
namespace Common {
class Archive;
}
namespace Graphics {
namespace MacGUIConstants {
enum {
kDesktopArc = 7
};
enum {
kColorBlack = 0,
kColorGray80 = 1,
kColorGray88 = 2,
kColorGrayEE = 3,
kColorWhite = 4,
kColorGreen = 5,
kColorGreen2 = 6,
kColorCount
};
enum {
kPatternSolid = 1,
kPatternStripes = 2,
kPatternCheckers = 3,
kPatternCheckers2 = 4,
kPatternLightGray = 5,
kPatternDarkGray = 6
};
enum MacCursorType {
kMacCursorArrow,
kMacCursorBeam,
kMacCursorCrossHair,
kMacCursorCrossBar,
kMacCursorWatch,
kMacCursorCustom,
kMacCursorOff
};
enum {
kWMModeNone = 0,
kWMModeNoDesktop = (1 << 0),
kWMModeAutohideMenu = (1 << 1),
kWMModalMenuMode = (1 << 2),
kWMModeForceBuiltinFonts = (1 << 3),
kWMModeUnicode = (1 << 4),
kWMModeManualDrawWidgets = (1 << 5),
kWMModeFullscreen = (1 << 6),
kWMModeButtonDialogStyle = (1 << 7),
kWMMode32bpp = (1 << 8),
kWMNoScummVMWallpaper = (1 << 9),
kWMModeWin95 = (1 << 10),
kWMModeForceMacFontsInWin95 = (1 << 11), // Enforce Mac font for languages which don't have glyphs in ms_sans_serif.ttf
kWMModeNoCursorOverride = (1 << 12),
kWMModeForceMacBorder = (1 << 13),
kWMModeForceMacFonts = (1 << 14), // Enforce Mac fonts even when there are viable TTF substitutions
};
}
using namespace MacGUIConstants;
class Cursor;
class ManagedSurface;
class MacCursor;
class MacMenu;
class MacTextWindow;
class MacWidget;
class MacFont;
class MacFontManager;
typedef Common::Array<const byte *> MacPatterns;
struct MacPlotData {
Graphics::ManagedSurface *surface;
Graphics::ManagedSurface *mask;
MacPatterns *patterns;
uint fillType;
int fillOriginX;
int fillOriginY;
int thickness;
uint bgColor;
bool invert;
MacPlotData(Graphics::ManagedSurface *s, Graphics::ManagedSurface *m, MacPatterns *p, uint f, int fx, int fy, int t, uint bg, bool inv = false) :
surface(s), mask(m), patterns(p), fillType(f), fillOriginX(fx), fillOriginY(fy), thickness(t), bgColor(bg), invert(inv) {
}
};
struct ZoomBox {
Common::Rect start;
Common::Rect end;
Common::Array<Common::Rect> last;
int delay;
int step;
uint32 startTime;
uint32 nextTime;
};
/**
* A manager class to handle window creation, destruction,
* drawing, moving and event handling.
*/
class MacWindowManager {
public:
MacWindowManager(uint32 mode = 0, MacPatterns *patterns = nullptr, Common::Language language = Common::UNK_LANG);
~MacWindowManager();
Primitives &getDrawPrimitives() const { return *_macDrawPrimitives; }
Primitives &getDrawInvertPrimitives() const;
/**
* Mutator to indicate the surface onto which the desktop will be drawn.
* Note that this method should be called as soon as the WM is created.
* @param screen Surface on which the desktop will be drawn.
*/
void setScreen(ManagedSurface *screen);
/**
* Mutator to indicate the dimensions of the desktop, when a backing surface is not used.
* Note that this method should be called as soon as the WM is created.
* @param screen Surface on which the desktop will be drawn.
*/
void setScreen(int w, int h);
int getWidth();
int getHeight();
/**
* Create a window with the given parameters.
* Note that this method allocates the necessary memory for the window.
* @param scrollable True if the window has to be scrollable.
* @param resizable True if the window can be resized.
* @param editable True if the window can be edited.
* @return Pointer to the newly created window.
*/
MacWindow *addWindow(bool scrollable, bool resizable, bool editable);
MacTextWindow *addTextWindow(const MacFont *font, int fgcolor, int bgcolor, int maxWidth, TextAlign textAlignment, MacMenu *menu, int padding = 0);
MacTextWindow *addTextWindow(const Font *font, int fgcolor, int bgcolor, int maxWidth, TextAlign textAlignment, MacMenu *menu, int padding = 0);
void resizeScreen(int w, int h);
/**
* Adds a window that has already been initialized to the registry.
* Like addWindow, but this doesn't create/allocate the Window.
* @param macWindow the window to be added to the registry
*/
void addWindowInitialized(MacWindow *macwindow);
/**
* Returns the last allocated id
* @return last allocated window id
*/
int getLastId() { return _lastId; }
/**
* Returns the next available id and the increments the internal counter.
* @return next (new) window id that can be used
*/
int getNextId() { return _lastId++; }
/**
* Add the menu to the desktop.
* Note that the returned menu is empty, and therefore must be filled
* afterwards.
* @return Pointer to a new empty menu.
*/
MacMenu *addMenu();
void addMenu(int id, MacMenu *menu);
void removeMenu();
void activateMenu();
void activateScreenCopy();
void disableScreenCopy();
bool isMenuActive();
void setDesktopMode(uint32 mode);
/**
* Set hot zone where menu appears (works only with autohide menu)
*/
void setMenuHotzone(const Common::Rect &rect) { _menuHotzone = rect; }
/**
* Set delay in milliseconds when menu appears (works only with autohide menu)
*/
void setMenuDelay(int delay) { _menuDelay = delay; }
/**
* Set the desired window state to active.
* @param id ID of the window that has to be set to active.
*/
void setActiveWindow(int id);
int getActiveWindow() { return _activeWindow; }
/**
* Return Top Window containing a point
* @param x x coordinate of point
* @param y y coordiante of point
*/
MacWindow *findWindowAtPoint(int16 x, int16 y);
/**
* Return Top Window containing a point
* @param point Point
*/
MacWindow *findWindowAtPoint(Common::Point point);
/**
* Mark a window for removal.
* Note that the window data will be destroyed.
* @param target Window to be removed.
*/
void removeWindow(MacWindow *target);
/**
* Mutator to indicate that the entire desktop must be refreshed.
* @param redraw Currently unused.
*/
void setFullRefresh(bool redraw) { _fullRefresh = redraw; }
/**
* Method to draw the desktop into the screen,
* It will take into accout the contents set as dirty.
* Note that this method does not refresh the screen,
* g_system must be called separately.
*/
void draw();
/**
* Method to process the events from the engine.
* Most often this method will be called from the engine's GUI, and
* will send the event to the relevant windows for them to process.
* @param event The event to be processed.
* @return True if the event was processed.
*/
bool processEvent(Common::Event &event);
/**
* Accessor to retrieve an arbitrary window.
* @param id The id of the desired window.
* @return Pointer to the requested window, if it exists.
*/
BaseMacWindow *getWindow(int id) {
if (id >= 0 && id < (int)_windows.size())
return _windows[id];
return nullptr;
}
/**
* Retrieve the patterns used to fill surfaces.
* @return A MacPatterns object reference with the patterns.
*/
MacPatterns &getPatterns() { return _patterns; }
/**
* Sets an active widget, typically the one which steals the input
* It also sends deactivation message to the previous one
* @param widget Pointer to the widget to activate, nullptr for no widget
*/
void setActiveWidget(MacWidget *widget);
/**
* Similar to setActiveWidget but in this case no action including animation
* hover, etc can work until a window is locked.
* Anything outside this window will not respond to user.
* @param widget Pointer to the widget to lock, nullptr for no widget
*/
void setLockedWidget(MacWidget *widget);
/**
* Sets a background window, which is always active, this window cannot be
* deactivated by clicking outside it, ie it is always in background.
* @param window Pointer to the widget to background, nullptr for no widget
*/
void setBackgroundWindow(MacWindow *window);
MacPatterns &getBuiltinPatterns() { return _builtinPatterns; }
MacWidget *getActiveWidget() { return _activeWidget; }
MacWidget *getLockedWidget() { return _lockedWidget; }
Common::Rect getScreenBounds() { return _screen ? _screen->getBounds() : _screenDims; }
void clearWidgetRefs(MacWidget *widget);
void printWMMode(int debuglevel = 0);
private:
void replaceCursorType(MacCursorType type);
public:
MacCursorType getCursorType() const;
void pushCursor(MacCursorType type, Cursor *cursor = nullptr);
void replaceCursor(MacCursorType type, Cursor *cursor = nullptr);
void pushCustomCursor(const byte *data, int w, int h, int hx, int hy, int transcolor);
void replaceCustomCursor(const byte *data, int w, int h, int hx, int hy, int transcolor);
void pushCustomCursor(const Graphics::Cursor *cursor);
void popCursor();
PauseToken pauseEngine();
void setMode(uint32 mode);
void setEngine(Engine *engine);
void setEngineRedrawCallback(void *engine, void (*redrawCallback)(void *engine));
void setEngineActivateMenuCallback(void *engine, void (*redrawCallback)(void *engine));
void passPalette(const byte *palette, uint size);
template <typename T> void decomposeColor(uint32 color, byte &r, byte &g, byte &b);
uint32 findBestColor(byte cr, byte cg, byte cb);
uint32 findBestColor(uint32 color);
void setDesktopColor(byte, byte, byte);
byte inverter(byte src);
const byte *getPalette() { return _palette; }
uint getPaletteSize() { return _paletteSize; }
void renderZoomBox(bool redraw = false);
void addZoomBox(ZoomBox *box);
void removeMarked();
void loadDataBundle();
void cleanupDataBundle();
void cleanupDesktopBmp();
const BorderOffsets &getBorderOffsets(uint32 windowType);
Common::SeekableReadStream *getBorderFile(uint32 windowType, uint32 flags);
Common::SeekableReadStream *getFile(const Common::Path &filename);
void setTextInClipboard(const Common::U32String &str);
/**
* get text from WM clipboard or the global clipboard
* @param size will change to the length of real text in clipboard
* @return the text in clipboard, which may contained the format
*/
Common::U32String getTextFromClipboard(const Common::U32String &format = Common::U32String(), int *size = nullptr);
/**
* reset events for current widgets. i.e. we reset those variables which are used for handling events for macwidgets.
* e.g. we clear the active widget, set mouse down false, clear the hoveredWidget
* this function should be called when we are going to other level to handling events. thus wm may not handle events correctly.
*/
void clearHandlingWidgets();
void setMenuItemCheckMark(MacMenuItem *menuItem, bool checkMark);
void setMenuItemEnabled(MacMenuItem *menuItem, bool enabled);
void setMenuItemName(MacMenuItem *menuItem, const Common::String &name);
void setMenuItemAction(MacMenuItem *menuItem, int actionId);
bool getMenuItemCheckMark(MacMenuItem *menuItem);
bool getMenuItemEnabled(MacMenuItem *menuItem);
Common::String getMenuItemName(MacMenuItem *menuItem);
int getMenuItemAction(MacMenuItem *menuItem);
MacMenu *getMenu();
MacMenu *getMenu(int id);
void sayText(const Common::U32String &text) const;
void setTTSEnabled(bool enabled);
public:
MacFontManager *_fontMan;
uint32 _mode;
Common::Language _language;
Common::Point _lastClickPos;
Common::Point _lastMousePos;
Common::Rect _menuHotzone;
uint32 _menuTimer;
bool _mouseDown;
uint32 _colorBlack, _colorGray80, _colorGray88, _colorGrayEE, _colorWhite, _colorGreen, _colorGreen2;
MacWidget *_hoveredWidget;
// we use it to indicate whether we are clicking the hilite-able widget.
// In list style button mode, we will highlight the subsequent buttons only when we've clicked the hilite-able button initially
bool _hilitingWidget;
private:
void loadDesktop();
void drawDesktop();
void removeFromStack(BaseMacWindow *target);
void removeFromWindowList(BaseMacWindow *target);
void zoomBoxInner(Common::Rect &r, Graphics::MacPlotData &pd);
bool haveZoomBox() { return !_zoomBoxes.empty(); }
void adjustDimensions(const Common::Rect &clip, const Common::Rect &dims, int &adjWidth, int &adjHeight);
public:
Surface *_desktopBmp;
ManagedSurface *_desktop;
PixelFormat _pixelformat;
ManagedSurface *_screen;
ManagedSurface *_screenCopy;
Common::Rect _screenDims;
private:
Common::Mutex _mutex;
Common::List<BaseMacWindow *> _windowStack;
Common::HashMap<uint, BaseMacWindow *> _windows;
Common::List<BaseMacWindow *> _windowsToRemove;
bool _needsRemoval;
int _lastId;
int _activeWindow;
bool _fullRefresh;
bool _inEditableArea;
Primitives *_macDrawPrimitives;
Primitives *_macDrawInvertPrimitives;
MacPatterns _patterns;
MacPatterns _builtinPatterns;
byte *_palette;
uint _paletteSize;
MacMenu *_menu;
uint32 _menuDelay;
Engine *_engineP;
void *_engineR;
void (*_redrawEngineCallback)(void *engine);
void *_engineAM;
void (*_activateMenuCallback)(void *engine);
MacCursorType _tempType = kMacCursorArrow;
Common::Stack<MacCursorType> _cursorTypeStack;
Cursor *_cursor = nullptr;
MacWidget *_activeWidget;
MacWidget *_lockedWidget;
MacWindow *_backgroundWindow;
PauseToken *_screenCopyPauseToken;
Common::Array<ZoomBox *> _zoomBoxes;
Graphics::PaletteLookup _paletteLookup;
Common::HashMap<uint, uint> _invertColorHash;
Common::Archive *_dataBundle;
Common::U32String _clipboard;
bool _ttsEnabled;
};
const Common::U32String::value_type *readHex(uint16 *res, const Common::U32String::value_type *s, int len);
} // End of namespace Graphics
#endif