aboutsummaryrefslogtreecommitdiff
path: root/graphics
diff options
context:
space:
mode:
authorEugene Sandulenko2016-08-03 14:37:38 +0200
committerGitHub2016-08-03 14:37:38 +0200
commita00272c62c012ed4f6ee98ada7415064e8faac5a (patch)
tree1ad50f4d2c7307b1b6cb26f92bafcec406cdd00b /graphics
parent08c881e8eb72072816ab6539dc603f27963cbc65 (diff)
parentff9b1ccb57fad47b9bb32bb77c83a06c6fd75958 (diff)
downloadscummvm-rg350-a00272c62c012ed4f6ee98ada7415064e8faac5a.tar.gz
scummvm-rg350-a00272c62c012ed4f6ee98ada7415064e8faac5a.tar.bz2
scummvm-rg350-a00272c62c012ed4f6ee98ada7415064e8faac5a.zip
Merge pull request #796 from blorente/move-macgui
GRAPHICS/WAGE: Extract Mac GUI system.
Diffstat (limited to 'graphics')
-rw-r--r--graphics/macgui/macmenu.cpp583
-rw-r--r--graphics/macgui/macmenu.h123
-rw-r--r--graphics/macgui/macwindow.cpp496
-rw-r--r--graphics/macgui/macwindow.h350
-rw-r--r--graphics/macgui/macwindowborder.cpp117
-rw-r--r--graphics/macgui/macwindowborder.h149
-rw-r--r--graphics/macgui/macwindowmanager.cpp423
-rw-r--r--graphics/macgui/macwindowmanager.h218
-rw-r--r--graphics/module.mk4
-rw-r--r--graphics/nine_patch.cpp88
-rw-r--r--graphics/nine_patch.h18
11 files changed, 2564 insertions, 5 deletions
diff --git a/graphics/macgui/macmenu.cpp b/graphics/macgui/macmenu.cpp
new file mode 100644
index 0000000000..6169b3e3cd
--- /dev/null
+++ b/graphics/macgui/macmenu.cpp
@@ -0,0 +1,583 @@
+/* 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * 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/system.h"
+#include "common/keyboard.h"
+
+#include "graphics/primitives.h"
+#include "graphics/font.h"
+#include "graphics/macgui/macwindowmanager.h"
+#include "graphics/macgui/macwindow.h"
+#include "graphics/macgui/macmenu.h"
+
+namespace Graphics {
+
+enum {
+ kMenuHeight = 20,
+ kMenuLeftMargin = 7,
+ kMenuSpacing = 13,
+ kMenuPadding = 16,
+ kMenuDropdownPadding = 14,
+ kMenuDropdownItemHeight = 16,
+ kMenuItemHeight = 20
+};
+
+enum {
+ kMenuHighLevel = -1
+};
+
+enum {
+ kFontStyleBold = 1,
+ kFontStyleItalic = 2,
+ kFontStyleUnderline = 4,
+ kFontStyleOutline = 8,
+ kFontStyleShadow = 16,
+ kFontStyleCondensed = 32,
+ kFontStyleExtended = 64
+};
+
+enum {
+ kMenuActionCommand
+};
+
+
+struct MenuSubItem {
+ Common::String text;
+ int action;
+ int style;
+ char shortcut;
+ bool enabled;
+ Common::Rect bbox;
+
+ MenuSubItem(const char *t, int a, int s = 0, char sh = 0, bool e = true) : text(t), action(a), style(s), shortcut(sh), enabled(e) {}
+};
+
+typedef Common::Array<MenuSubItem *> SubItemArray;
+
+struct MenuItem {
+ Common::String name;
+ SubItemArray subitems;
+ Common::Rect bbox;
+ Common::Rect subbbox;
+
+ MenuItem(const char *n) : name(n) {}
+};
+
+Menu::Menu(int id, const Common::Rect &bounds, MacWindowManager *wm)
+ : BaseMacWindow(id, false, wm) {
+ _font = getMenuFont();
+
+ _screen.create(bounds.width(), bounds.height(), PixelFormat::createFormatCLUT8());
+
+ _bbox.left = 0;
+ _bbox.top = 0;
+ _bbox.right = _screen.w;
+ _bbox.bottom = kMenuHeight;
+
+ _menuActivated = false;
+ _activeItem = -1;
+ _activeSubItem = -1;
+
+ _ccallback = NULL;
+ _cdata = NULL;
+
+ _tempSurface.create(_screen.w, _font->getFontHeight(), PixelFormat::createFormatCLUT8());
+}
+
+Menu::~Menu() {
+ for (uint i = 0; i < _items.size(); i++) {
+ for (uint j = 0; j < _items[i]->subitems.size(); j++)
+ delete _items[i]->subitems[j];
+ delete _items[i];
+ }
+}
+
+void Menu::addStaticMenus(const MenuData *data) {
+ MenuItem *about = new MenuItem(_wm->hasBuiltInFonts() ? "\xa9" : "\xf0"); // (c) Symbol as the most resembling apple
+ _items.push_back(about);
+
+ for (int i = 0; data[i].menunum; i++) {
+ const MenuData *m = &data[i];
+
+ if (m->menunum == kMenuHighLevel) {
+ MenuItem *item = new MenuItem(m->title);
+ _items.push_back(item);
+
+ continue;
+ }
+
+ _items[m->menunum]->subitems.push_back(new MenuSubItem(m->title, m->action, 0, m->shortcut, m->enabled));
+ }
+}
+
+int Menu::addMenuItem(const char *name) {
+ MenuItem *i = new MenuItem(name);
+ _items.push_back(i);
+
+ return _items.size() - 1;
+}
+
+void Menu::addMenuSubItem(int id, const char *text, int action, int style, char shortcut, bool enabled) {
+ _items[id]->subitems.push_back(new MenuSubItem(text, action, style, shortcut, enabled));
+
+ calcMenuBounds(_items[id]);
+}
+
+void Menu::calcDimensions() {
+ // Calculate menu dimensions
+ int y = 1;
+ int x = 18;
+
+ for (uint i = 0; i < _items.size(); i++) {
+ int w = _font->getStringWidth(_items[i]->name);
+
+ if (_items[i]->bbox.bottom == 0) {
+ _items[i]->bbox.left = x - kMenuLeftMargin;
+ _items[i]->bbox.top = y;
+ _items[i]->bbox.right = x + w + kMenuSpacing - kMenuLeftMargin;
+ _items[i]->bbox.bottom = y + _font->getFontHeight() + (_wm->hasBuiltInFonts() ? 3 : 2);
+ }
+
+ calcMenuBounds(_items[i]);
+
+ x += w + kMenuSpacing;
+ }
+}
+
+void Menu::clearSubMenu(int id) {
+ MenuItem *menu = _items[id];
+
+ for (uint j = 0; j < menu->subitems.size(); j++)
+ delete menu->subitems[j];
+
+ menu->subitems.clear();
+}
+
+void Menu::createSubMenuFromString(int id, const char *str) {
+ clearSubMenu(id);
+
+ MenuItem *menu = _items[id];
+ Common::String string(str);
+
+ Common::String item;
+
+ for (uint i = 0; i < string.size(); i++) {
+ while(i < string.size() && string[i] != ';') // Read token
+ item += string[i++];
+
+ if (item == "(-") {
+ menu->subitems.push_back(new MenuSubItem(NULL, 0));
+ } else {
+ bool enabled = true;
+ int style = 0;
+ char shortcut = 0;
+ const char *shortPtr = strrchr(item.c_str(), '/');
+ if (shortPtr != NULL) {
+ if (strlen(shortPtr) >= 2) {
+ shortcut = shortPtr[1];
+ item.deleteChar(shortPtr - item.c_str());
+ item.deleteChar(shortPtr - item.c_str());
+ } else {
+ error("Unexpected shortcut: '%s', item '%s' in menu '%s'", shortPtr, item.c_str(), string.c_str());
+ }
+ }
+
+ while (item.size() >= 2 && item[item.size() - 2] == '<') {
+ char c = item.lastChar();
+ if (c == 'B') {
+ style |= kFontStyleBold;
+ } else if (c == 'I') {
+ style |= kFontStyleItalic;
+ } else if (c == 'U') {
+ style |= kFontStyleUnderline;
+ } else if (c == 'O') {
+ style |= kFontStyleOutline;
+ } else if (c == 'S') {
+ style |= kFontStyleShadow;
+ } else if (c == 'C') {
+ style |= kFontStyleCondensed;
+ } else if (c == 'E') {
+ style |= kFontStyleExtended;
+ }
+ item.deleteLastChar();
+ item.deleteLastChar();
+ }
+
+ Common::String tmpitem(item);
+ tmpitem.trim();
+ if (tmpitem[0] == '(') {
+ enabled = false;
+
+ for (uint j = 0; j < item.size(); j++)
+ if (item[j] == '(') {
+ item.deleteChar(j);
+ break;
+ }
+ }
+
+ menu->subitems.push_back(new MenuSubItem(item.c_str(), kMenuActionCommand, style, shortcut, enabled));
+ }
+
+ item.clear();
+ }
+
+ calcMenuBounds(menu);
+}
+
+const Font *Menu::getMenuFont() {
+ return _wm->getFont("Chicago-12", FontManager::kBigGUIFont);
+}
+
+const char *Menu::getAcceleratorString(MenuSubItem *item, const char *prefix) {
+ static char res[20];
+ *res = 0;
+
+ if (item->shortcut != 0)
+ sprintf(res, "%s%c%c", prefix, (_wm->hasBuiltInFonts() ? '^' : '\x11'), item->shortcut);
+
+ return res;
+}
+
+int Menu::calculateMenuWidth(MenuItem *menu) {
+ int maxWidth = 0;
+ for (uint i = 0; i < menu->subitems.size(); i++) {
+ MenuSubItem *item = menu->subitems[i];
+ if (!item->text.empty()) {
+ Common::String text(item->text);
+ Common::String acceleratorText(getAcceleratorString(item, " "));
+ if (!acceleratorText.empty()) {
+ text += acceleratorText;
+ }
+
+ int width = _font->getStringWidth(text);
+ if (width > maxWidth) {
+ maxWidth = width;
+ }
+ }
+ }
+ return maxWidth;
+}
+
+void Menu::calcMenuBounds(MenuItem *menu) {
+ // TODO: cache maxWidth
+ int maxWidth = calculateMenuWidth(menu);
+ int x1 = menu->bbox.left - 1;
+ int y1 = menu->bbox.bottom + 1;
+ int x2 = x1 + maxWidth + kMenuDropdownPadding * 2 - 4;
+ int y2 = y1 + menu->subitems.size() * kMenuDropdownItemHeight + 2;
+
+ menu->subbbox.left = x1;
+ menu->subbbox.top = y1;
+ menu->subbbox.right = x2;
+ menu->subbbox.bottom = y2;
+}
+
+static void drawPixelPlain(int x, int y, int color, void *data) {
+ ManagedSurface *surface = (ManagedSurface *)data;
+
+ if (x >= 0 && x < surface->w && y >= 0 && y < surface->h)
+ *((byte *)surface->getBasePtr(x, y)) = (byte)color;
+}
+
+static void drawFilledRoundRect(ManagedSurface *surface, Common::Rect &rect, int arc, int color) {
+ drawRoundRect(rect, arc, color, true, drawPixelPlain, surface);
+}
+
+bool Menu::draw(ManagedSurface *g, bool forceRedraw) {
+ Common::Rect r(_bbox);
+
+ if (!_contentIsDirty && !forceRedraw)
+ return false;
+
+ _contentIsDirty = false;
+
+ _screen.clear(kColorGreen);
+
+ drawFilledRoundRect(&_screen, r, kDesktopArc, kColorWhite);
+ r.top = 7;
+ _screen.fillRect(r, kColorWhite);
+ r.top = kMenuHeight - 1;
+ r.bottom++;
+ _screen.fillRect(r, kColorGreen);
+ r.bottom--;
+ _screen.fillRect(r, kColorBlack);
+
+ for (uint i = 0; i < _items.size(); i++) {
+ int color = kColorBlack;
+ MenuItem *it = _items[i];
+
+ if ((uint)_activeItem == i) {
+ Common::Rect hbox = it->bbox;
+
+ hbox.left -= 1;
+ hbox.right += 3;
+ hbox.bottom += 1;
+
+ _screen.fillRect(hbox, kColorBlack);
+ color = kColorWhite;
+
+ if (!it->subitems.empty())
+ renderSubmenu(it);
+ }
+
+ _font->drawString(&_screen, it->name, it->bbox.left + kMenuLeftMargin, it->bbox.top + (_wm->hasBuiltInFonts() ? 2 : 1), it->bbox.width(), color);
+ }
+
+ g->transBlitFrom(_screen, kColorGreen);
+
+ g_system->copyRectToScreen(g->getPixels(), g->pitch, 0, 0, g->w, g->h);
+
+ return true;
+}
+
+void Menu::renderSubmenu(MenuItem *menu) {
+ Common::Rect *r = &menu->subbbox;
+
+ if (r->width() == 0 || r->height() == 0)
+ return;
+
+ _screen.fillRect(*r, kColorWhite);
+ _screen.frameRect(*r, kColorBlack);
+ _screen.vLine(r->right, r->top + 3, r->bottom + 1, kColorBlack);
+ _screen.vLine(r->right + 1, r->top + 3, r->bottom + 1, kColorBlack);
+ _screen.hLine(r->left + 3, r->bottom, r->right + 1, kColorBlack);
+ _screen.hLine(r->left + 3, r->bottom + 1, r->right + 1, kColorBlack);
+
+ int x = r->left + kMenuDropdownPadding;
+ int y = r->top + 1;
+ for (uint i = 0; i < menu->subitems.size(); i++) {
+ Common::String text(menu->subitems[i]->text);
+ Common::String acceleratorText(getAcceleratorString(menu->subitems[i], ""));
+ int accelX = r->right - 25;
+
+ int color = kColorBlack;
+ if (i == (uint)_activeSubItem && !text.empty() && menu->subitems[i]->enabled) {
+ color = kColorWhite;
+ Common::Rect trect(r->left, y - (_wm->hasBuiltInFonts() ? 1 : 0), r->right, y + _font->getFontHeight());
+
+ _screen.fillRect(trect, kColorBlack);
+ }
+
+ if (!text.empty()) {
+ ManagedSurface *s = &_screen;
+ int tx = x, ty = y;
+
+ if (!menu->subitems[i]->enabled) {
+ s = &_tempSurface;
+ tx = 0;
+ ty = 0;
+ accelX -= x;
+
+ _tempSurface.clear(kColorGreen);
+ }
+
+ _font->drawString(s, text, tx, ty, r->width(), color);
+
+ if (!acceleratorText.empty())
+ _font->drawString(s, acceleratorText, accelX, ty, r->width(), color);
+
+ if (!menu->subitems[i]->enabled) {
+ // I am lazy to extend drawString() with plotProc as a parameter, so
+ // fake it here
+ for (int ii = 0; ii < _tempSurface.h; ii++) {
+ const byte *src = (const byte *)_tempSurface.getBasePtr(0, ii);
+ byte *dst = (byte *)_screen.getBasePtr(x, y+ii);
+ byte pat = _wm->getPatterns()[kPatternCheckers2 - 1][ii % 8];
+ for (int j = 0; j < r->width(); j++) {
+ if (*src != kColorGreen && (pat & (1 << (7 - (x + j) % 8))))
+ *dst = *src;
+ src++;
+ dst++;
+ }
+ }
+ }
+ } else { // Delimiter
+ bool flip = r->left & 2;
+ byte *ptr = (byte *)_screen.getBasePtr(r->left + 1, y + kMenuDropdownItemHeight / 2);
+ for (int xx = r->left + 1; xx <= r->right - 1; xx++, ptr++) {
+ *ptr = flip ? kColorBlack : kColorWhite;
+ flip = !flip;
+ }
+ }
+
+ y += kMenuDropdownItemHeight;
+ }
+
+ _contentIsDirty = true;
+ //g_system->copyRectToScreen(_screen.getBasePtr(r->left, r->top), _screen.pitch, r->left, r->top, r->width() + 2, r->height() + 2);
+}
+
+bool Menu::processEvent(Common::Event &event) {
+ switch (event.type) {
+ case Common::EVENT_KEYDOWN:
+ return keyEvent(event);
+ case Common::EVENT_LBUTTONDOWN:
+ return mouseClick(event.mouse.x, event.mouse.y);
+ case Common::EVENT_LBUTTONUP:
+ return mouseRelease(event.mouse.x, event.mouse.y);
+ case Common::EVENT_MOUSEMOVE:
+ return mouseMove(event.mouse.x, event.mouse.y);
+ default:
+ return false;
+ }
+}
+
+bool Menu::keyEvent(Common::Event &event) {
+ if (event.type != Common::EVENT_KEYDOWN)
+ return false;
+
+ if (event.kbd.flags & (Common::KBD_ALT | Common::KBD_CTRL | Common::KBD_META)) {
+ if (event.kbd.ascii >= 0x20 && event.kbd.ascii <= 0x7f) {
+ return processMenuShortCut(event.kbd.flags, event.kbd.ascii);
+ }
+ }
+
+ return false;
+}
+
+bool Menu::mouseClick(int x, int y) {
+ if (_bbox.contains(x, y)) {
+ for (uint i = 0; i < _items.size(); i++)
+ if (_items[i]->bbox.contains(x, y)) {
+ if ((uint)_activeItem == i)
+ return false;
+
+ if (_activeItem != -1) { // Restore background
+ Common::Rect r(_items[_activeItem]->subbbox);
+ r.right += 3;
+ r.bottom += 3;
+
+ _wm->setFullRefresh(true);
+ }
+
+ _activeItem = i;
+ _activeSubItem = -1;
+ _menuActivated = true;
+
+ _contentIsDirty = true;
+
+ return true;
+ }
+ } else if (_menuActivated && _items[_activeItem]->subbbox.contains(x, y)) {
+ MenuItem *it = _items[_activeItem];
+ int numSubItem = (y - it->subbbox.top) / kMenuDropdownItemHeight;
+
+ if (numSubItem != _activeSubItem) {
+ _activeSubItem = numSubItem;
+
+ renderSubmenu(_items[_activeItem]);
+ _contentIsDirty = true;
+ }
+ } else if (_menuActivated && _activeItem != -1) {
+ _activeSubItem = -1;
+
+ renderSubmenu(_items[_activeItem]);
+ _contentIsDirty = true;
+ }
+
+ return false;
+}
+
+bool Menu::mouseMove(int x, int y) {
+ if (_menuActivated)
+ if (mouseClick(x, y))
+ return true;
+
+ return false;
+}
+
+bool Menu::mouseRelease(int x, int y) {
+ if (_menuActivated) {
+ _menuActivated = false;
+
+ if (_activeItem != -1 && _activeSubItem != -1 && _items[_activeItem]->subitems[_activeSubItem]->enabled)
+ (*_ccallback)(_items[_activeItem]->subitems[_activeSubItem]->action,
+ _items[_activeItem]->subitems[_activeSubItem]->text, _cdata);
+
+ _activeItem = -1;
+ _activeSubItem = -1;
+
+ _wm->setFullRefresh(true);
+
+ return true;
+ }
+
+ return false;
+}
+
+bool Menu::processMenuShortCut(byte flags, uint16 ascii) {
+ ascii = tolower(ascii);
+
+ if (flags & (Common::KBD_CTRL | Common::KBD_META)) {
+ for (uint i = 0; i < _items.size(); i++)
+ for (uint j = 0; j < _items[i]->subitems.size(); j++)
+ if (_items[i]->subitems[j]->enabled && tolower(_items[i]->subitems[j]->shortcut) == ascii) {
+ (*_ccallback)(_items[i]->subitems[j]->action, _items[i]->subitems[j]->text, _cdata);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void Menu::enableCommand(int menunum, int action, bool state) {
+ for (uint i = 0; i < _items[menunum]->subitems.size(); i++)
+ if (_items[menunum]->subitems[i]->action == action)
+ _items[menunum]->subitems[i]->enabled = state;
+
+ _contentIsDirty = true;
+}
+
+void Menu::disableAllMenus() {
+ for (uint i = 1; i < _items.size(); i++) // Leave About menu on
+ for (uint j = 0; j < _items[i]->subitems.size(); j++)
+ _items[i]->subitems[j]->enabled = false;
+
+ _contentIsDirty = true;
+}
+
+} // End of namespace Wage
diff --git a/graphics/macgui/macmenu.h b/graphics/macgui/macmenu.h
new file mode 100644
index 0000000000..7114066ae6
--- /dev/null
+++ b/graphics/macgui/macmenu.h
@@ -0,0 +1,123 @@
+/* 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * 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_MACMENU_H
+#define GRAPHICS_MACGUI_MACMENU_H
+
+namespace Graphics {
+
+struct MenuItem;
+struct MenuSubItem;
+
+struct MenuData {
+ int menunum;
+ const char *title;
+ int action;
+ byte shortcut;
+ bool enabled;
+};
+
+class Menu : public BaseMacWindow {
+public:
+ Menu(int id, const Common::Rect &bounds, MacWindowManager *wm);
+ ~Menu();
+
+ void setCommandsCallback(void (*callback)(int, Common::String &, void *), void *data) { _ccallback = callback; _cdata = data; }
+
+ void addStaticMenus(const MenuData *data);
+ void calcDimensions();
+
+ int addMenuItem(const char *name);
+ void addMenuSubItem(int id, const char *text, int action, int style = 0, char shortcut = 0, bool enabled = true);
+ void createSubMenuFromString(int id, const char *string);
+ void clearSubMenu(int id);
+
+ bool draw(ManagedSurface *g, bool forceRedraw = false);
+ bool processEvent(Common::Event &event);
+
+ void enableCommand(int menunum, int action, bool state);
+ void disableAllMenus();
+
+ void setActive(bool active) { _menuActivated = active; }
+ bool hasAllFocus() { return _menuActivated; }
+
+ Common::Rect _bbox;
+
+private:
+ ManagedSurface _screen;
+ ManagedSurface _tempSurface;
+
+private:
+ const Font *getMenuFont();
+ const char *getAcceleratorString(MenuSubItem *item, const char *prefix);
+ int calculateMenuWidth(MenuItem *menu);
+ void calcMenuBounds(MenuItem *menu);
+ void renderSubmenu(MenuItem *menu);
+
+ bool keyEvent(Common::Event &event);
+ bool mouseClick(int x, int y);
+ bool mouseRelease(int x, int y);
+ bool mouseMove(int x, int y);
+
+ bool processMenuShortCut(byte flags, uint16 ascii);
+
+ Common::Array<MenuItem *> _items;
+
+ const Font *_font;
+
+ bool _menuActivated;
+
+ int _activeItem;
+ int _activeSubItem;
+
+ void (*_ccallback)(int action, Common::String &text, void *data);
+ void *_cdata;
+};
+
+} // End of namespace Graphics
+
+#endif
diff --git a/graphics/macgui/macwindow.cpp b/graphics/macgui/macwindow.cpp
new file mode 100644
index 0000000000..dbb600ba82
--- /dev/null
+++ b/graphics/macgui/macwindow.cpp
@@ -0,0 +1,496 @@
+/* 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * 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 "graphics/font.h"
+#include "graphics/primitives.h"
+#include "common/events.h"
+#include "graphics/macgui/macwindowmanager.h"
+#include "graphics/macgui/macwindow.h"
+#include "image/bmp.h"
+
+namespace Graphics {
+
+BaseMacWindow::BaseMacWindow(int id, bool editable, MacWindowManager *wm) :
+ _id(id), _editable(editable), _wm(wm) {
+ _callback = 0;
+ _dataPtr = 0;
+
+ _contentIsDirty = true;
+
+ _type = kWindowUnknown;
+}
+
+MacWindow::MacWindow(int id, bool scrollable, bool resizable, bool editable, MacWindowManager *wm) :
+ BaseMacWindow(id, editable, wm), _scrollable(scrollable), _resizable(resizable) {
+ _active = false;
+ _borderIsDirty = true;
+
+ _highlightedPart = kBorderNone;
+
+ _scrollPos = _scrollSize = 0.0;
+
+ _beingDragged = false;
+ _beingResized = false;
+
+ _draggedX = _draggedY = 0;
+
+ _type = kWindowWindow;
+
+ _closeable = false;
+
+ _borderWidth = kBorderWidth;
+}
+
+MacWindow::~MacWindow() {
+}
+
+const Font *MacWindow::getTitleFont() {
+ return _wm->getFont("Chicago-12", FontManager::kBigGUIFont);
+}
+
+void MacWindow::setActive(bool active) {
+ if (active == _active)
+ return;
+
+ _active = active;
+ _borderIsDirty = true;
+}
+
+bool MacWindow::isActive() { return _active; }
+
+void MacWindow::resize(int w, int h) {
+ if (_surface.w == w && _surface.h == h)
+ return;
+
+ _surface.free();
+ _surface.create(w, h, PixelFormat::createFormatCLUT8());
+ _borderSurface.free();
+ _borderSurface.create(w, h, PixelFormat::createFormatCLUT8());
+ _composeSurface.free();
+ _composeSurface.create(w, h, PixelFormat::createFormatCLUT8());
+
+ _dims.setWidth(w);
+ _dims.setHeight(h);
+
+ updateInnerDims();
+
+ _contentIsDirty = true;
+ _borderIsDirty = true;
+}
+
+void MacWindow::move(int x, int y) {
+ if (_dims.left == x && _dims.top == y)
+ return;
+
+ _dims.moveTo(x, y);
+ updateInnerDims();
+
+ _contentIsDirty = true;
+}
+
+void MacWindow::setDimensions(const Common::Rect &r) {
+ resize(r.width(), r.height());
+ _dims.moveTo(r.left, r.top);
+ updateInnerDims();
+
+ _contentIsDirty = true;
+}
+
+bool MacWindow::draw(ManagedSurface *g, bool forceRedraw) {
+ if (!_borderIsDirty && !_contentIsDirty && !forceRedraw)
+ return false;
+
+ if (_borderIsDirty || forceRedraw)
+ drawBorder();
+
+ _contentIsDirty = false;
+
+ // Compose
+ _composeSurface.blitFrom(_surface, Common::Rect(0, 0, _surface.w - 2, _surface.h - 2), Common::Point(2, 2));
+ _composeSurface.transBlitFrom(_borderSurface, kColorGreen);
+
+ g->transBlitFrom(_composeSurface, _composeSurface.getBounds(), Common::Point(_dims.left - 2, _dims.top - 2), kColorGreen2);
+
+ return true;
+}
+
+
+#define ARROW_W 12
+#define ARROW_H 6
+const int arrowPixels[ARROW_H][ARROW_W] = {
+ {0,0,0,0,0,1,1,0,0,0,0,0},
+ {0,0,0,0,1,1,1,1,0,0,0,0},
+ {0,0,0,1,1,1,1,1,1,0,0,0},
+ {0,0,1,1,1,1,1,1,1,1,0,0},
+ {0,1,1,1,1,1,1,1,1,1,1,0},
+ {1,1,1,1,1,1,1,1,1,1,1,1}};
+
+static void drawPixelInverted(int x, int y, int color, void *data) {
+ ManagedSurface *surface = (ManagedSurface *)data;
+
+ if (x >= 0 && x < surface->w && y >= 0 && y < surface->h) {
+ byte *p = (byte *)surface->getBasePtr(x, y);
+
+ *p = *p == kColorWhite ? kColorBlack : kColorWhite;
+ }
+}
+
+void MacWindow::updateInnerDims() {
+ if (_macBorder.hasBorder(_active) && _macBorder.hasOffsets()) {
+ _innerDims = Common::Rect(
+ _dims.left + _macBorder.getOffset(kBorderOffsetLeft),
+ _dims.top + _macBorder.getOffset(kBorderOffsetTop),
+ _dims.right - _macBorder.getOffset(kBorderOffsetRight),
+ _dims.bottom - _macBorder.getOffset(kBorderOffsetBottom));
+ } else {
+ _innerDims = _dims;
+ _innerDims.grow(-kBorderWidth);
+ }
+}
+
+void MacWindow::drawBorder() {
+ _borderIsDirty = false;
+
+ ManagedSurface *g = &_borderSurface;
+
+ if (_macBorder.hasBorder(_active)) {
+ drawBorderFromSurface(g);
+ } else {
+ drawSimpleBorder(g);
+ }
+}
+
+void MacWindow::prepareBorderSurface(ManagedSurface *g) {
+ // We draw rect with outer kColorGreen2 and inner kColorGreen, so on 2 passes we cut out
+ // scene by external shape of the border
+ int sz = kBorderWidth / 2;
+ int width = g->w;
+ int height = g->h;
+ g->clear(kColorGreen2);
+ g->fillRect(Common::Rect(sz, sz, width - sz, height - sz), kColorGreen);
+}
+
+void MacWindow::drawBorderFromSurface(ManagedSurface *g) {
+ g->clear(kColorGreen2);
+ Common::Rect inside = _innerDims;
+ inside.moveTo(_macBorder.getOffset(kBorderOffsetLeft), _macBorder.getOffset(kBorderOffsetTop));
+ g->fillRect(inside, kColorGreen);
+
+ _macBorder.blitBorderInto(_borderSurface, _active);
+}
+
+void MacWindow::drawSimpleBorder(ManagedSurface *g) {
+
+ bool active = _active, scrollable = _scrollable, closeable = _active, drawTitle = !_title.empty();
+ const int size = kBorderWidth;
+ int x = 0;
+ int y = 0;
+ int width = _borderSurface.w;
+ int height = _borderSurface.h;
+
+ prepareBorderSurface(g);
+
+ drawBox(g, x, y, size, size);
+ drawBox(g, x + width - size - 1, y, size, size);
+ drawBox(g, x + width - size - 1, y + height - size - 1, size, size);
+ drawBox(g, x, y + height - size - 1, size, size);
+ drawBox(g, x + size, y + 2, width - 2 * size - 1, size - 4);
+ drawBox(g, x + size, y + height - size + 1, width - 2 * size - 1, size - 4);
+ drawBox(g, x + 2, y + size, size - 4, height - 2 * size - 1);
+ drawBox(g, x + width - size + 1, y + size, size - 4, height - 2 * size - 1);
+
+ if (active) {
+ fillRect(g, x + size, y + 5, width - 2 * size - 1, 8, kColorBlack);
+ fillRect(g, x + size, y + height - 13, width - 2 * size - 1, 8, kColorBlack);
+ fillRect(g, x + 5, y + size, 8, height - 2 * size - 1, kColorBlack);
+ if (!scrollable) {
+ fillRect(g, x + width - 13, y + size, 8, height - 2 * size - 1, kColorBlack);
+ } else {
+ int x1 = x + width - 15;
+ int y1 = y + size + 1;
+
+ for (int yy = 0; yy < ARROW_H; yy++) {
+ for (int xx = 0; xx < ARROW_W; xx++)
+ g->hLine(x1 + xx, y1 + yy, x1 + xx, (arrowPixels[yy][xx] != 0 ? kColorBlack : kColorWhite));
+ }
+
+ fillRect(g, x + width - 13, y + size + ARROW_H, 8, height - 2 * size - 1 - ARROW_H * 2, kColorBlack);
+
+ y1 += height - 2 * size - ARROW_H - 2;
+ for (int yy = 0; yy < ARROW_H; yy++) {
+ for (int xx = 0; xx < ARROW_W; xx++)
+ g->hLine(x1 + xx, y1 + yy, x1 + xx, (arrowPixels[ARROW_H - yy - 1][xx] != 0 ? kColorBlack : kColorWhite));
+ }
+
+ if (_highlightedPart == kBorderScrollUp || _highlightedPart == kBorderScrollDown) {
+ int rx1 = x + width - kBorderWidth + 2;
+ int ry1 = y + size + _dims.height() * _scrollPos;
+ int rx2 = rx1 + size - 4;
+ int ry2 = ry1 + _dims.height() * _scrollSize;
+ Common::Rect rr(rx1, ry1, rx2, ry2);
+
+ Graphics::drawFilledRect(rr, kColorBlack, drawPixelInverted, g);
+ }
+ }
+ if (closeable) {
+ if (_highlightedPart == kBorderCloseButton) {
+ fillRect(g, x + 6, y + 6, 6, 6, kColorBlack);
+ } else {
+ drawBox(g, x + 5, y + 5, 7, 7);
+ }
+ }
+ }
+
+ if (drawTitle) {
+ const Graphics::Font *font = getTitleFont();
+ int yOff = _wm->hasBuiltInFonts() ? 3 : 1;
+
+ int w = font->getStringWidth(_title) + 10;
+ int maxWidth = width - size * 2 - 7;
+ if (w > maxWidth)
+ w = maxWidth;
+ drawBox(g, x + (width - w) / 2, y, w, size);
+ font->drawString(g, _title, x + (width - w) / 2 + 5, y + yOff, w, kColorBlack);
+ }
+}
+
+void MacWindow::setHighlight(WindowClick highlightedPart) {
+ if (_highlightedPart == highlightedPart)
+ return;
+
+ _highlightedPart = highlightedPart;
+ _borderIsDirty = true;
+}
+
+void MacWindow::setScroll(float scrollPos, float scrollSize) {
+ if (_scrollPos == scrollPos && _scrollSize == scrollSize)
+ return;
+
+ _scrollPos = scrollPos;
+ _scrollSize = scrollSize;
+ _borderIsDirty = true;
+}
+
+void MacWindow::loadBorder(Common::SeekableReadStream &file, bool active, int lo, int ro, int to, int bo) {
+ Image::BitmapDecoder bmpDecoder;
+ Graphics::Surface source;
+ Graphics::TransparentSurface *surface = new Graphics::TransparentSurface();
+
+ bmpDecoder.loadStream(file);
+ source = *(bmpDecoder.getSurface());
+
+ source.convertToInPlace(surface->getSupportedPixelFormat(), bmpDecoder.getPalette());
+ surface->create(source.w, source.h, source.format);
+ surface->copyFrom(source);
+ surface->applyColorKey(255, 0, 255, false);
+
+ if (active)
+ _macBorder.addActiveBorder(*surface);
+ else
+ _macBorder.addInactiveBorder(*surface);
+
+ if (!_macBorder.hasOffsets())
+ _macBorder.setOffsets(lo, ro, to, bo);
+
+ updateInnerDims();
+}
+
+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, kColorWhite);
+ g->frameRect(r, kColorBlack);
+}
+
+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) {
+ 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) {
+ int bLeft = kBorderWidth;
+ int bTop = kBorderWidth;
+ if (_macBorder.hasOffsets()) {
+ bLeft = _macBorder.getOffset(kBorderOffsetLeft);
+ bTop = _macBorder.getOffset(kBorderOffsetTop);
+ }
+ return (x >= _innerDims.left - bLeft && x < _innerDims.left && y >= _innerDims.top - bTop && y < _innerDims.top);
+}
+
+bool MacWindow::isInResizeButton(int x, int y) {
+ int bRight = kBorderWidth;
+ int bBottom = kBorderWidth;
+ if (_macBorder.hasOffsets()) {
+ bRight = _macBorder.getOffset(kBorderOffsetRight);
+ bBottom = _macBorder.getOffset(kBorderOffsetBottom);
+ }
+ return (x >= _innerDims.right && x < _innerDims.right + bRight && y >= _innerDims.bottom && y < _innerDims.bottom + bBottom);
+}
+
+WindowClick MacWindow::isInScroll(int x, int y) {
+ int bTop = kBorderWidth;
+ int bRight = kBorderWidth;
+ int bBottom = kBorderWidth;
+ if (_macBorder.hasOffsets()) {
+ bTop = _macBorder.getOffset(kBorderOffsetTop);
+ bRight = _macBorder.getOffset(kBorderOffsetRight);
+ bBottom = _macBorder.getOffset(kBorderOffsetBottom);
+ }
+
+ 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);
+
+ switch (event.type) {
+ case Common::EVENT_MOUSEMOVE:
+ if (_beingDragged) {
+ _dims.translate(event.mouse.x - _draggedX, event.mouse.y - _draggedY);
+ updateInnerDims();
+
+ _draggedX = event.mouse.x;
+ _draggedY = event.mouse.y;
+
+ _wm->setFullRefresh(true);
+ }
+
+ if (_beingResized) {
+ resize(MAX(_borderWidth * 4, _dims.width() + event.mouse.x - _draggedX),
+ MAX(_borderWidth * 4, _dims.height() + event.mouse.y - _draggedY));
+
+ _draggedX = event.mouse.x;
+ _draggedY = event.mouse.y;
+
+ _wm->setFullRefresh(true);
+ (*_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:
+ _beingDragged = false;
+ _beingResized = false;
+
+ setHighlight(kBorderNone);
+ break;
+ default:
+ return false;
+ }
+
+ return (*_callback)(click, event, _dataPtr);
+}
+
+} // End of namespace Wage
diff --git a/graphics/macgui/macwindow.h b/graphics/macgui/macwindow.h
new file mode 100644
index 0000000000..c40c1a4a38
--- /dev/null
+++ b/graphics/macgui/macwindow.h
@@ -0,0 +1,350 @@
+/* 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * 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_MACWINDOW_H
+#define GRAPHICS_MACGUI_MACWINDOW_H
+
+#include "graphics/managed_surface.h"
+#include "graphics/transparent_surface.h"
+#include "graphics/nine_patch.h"
+#include "graphics/palette.h"
+
+#include "graphics/macgui/macwindowborder.h"
+
+namespace Graphics {
+
+class MacWindowManager;
+class MacWindowBorder;
+
+namespace MacWindowConstants {
+enum WindowType {
+ kWindowUnknown,
+ kWindowWindow,
+ kWindowMenu
+};
+
+enum {
+ kBorderWidth = 17
+};
+
+enum WindowClick {
+ kBorderNone = 0,
+ kBorderScrollUp,
+ kBorderScrollDown,
+ kBorderScrollLeft,
+ kBorderScrollRight,
+ kBorderCloseButton,
+ kBorderInner,
+ kBorderBorder,
+ kBorderResizeButton
+};
+}
+using namespace MacWindowConstants;
+
+/**
+ * Abstract class that defines common functionality for all window classes.
+ * It supports event callbacks and drawing.
+ */
+class BaseMacWindow {
+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 for the complete dimensions of the window.
+ * @return Dimensions of the window (including border) relative to the WM's screen.
+ */
+ const Common::Rect &getDimensions() { return _dims; }
+
+ /**
+ * 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; }
+
+ /**
+ * Method to access the entire surface of the window (e.g. to draw an image).
+ * @return A pointer to the entire surface of the window.
+ */
+ ManagedSurface *getSurface() { return &_surface; }
+
+ /**
+ * Abstract method for indicating whether the window is active or inactive.
+ * Used by the WM to handle focus on windows, etc.
+ * @param active Desired state of the window.
+ */
+ virtual void setActive(bool active) = 0;
+
+ /**
+ * Method for marking the window for redraw.
+ * @param dirty True if the window needs to be redrawn.
+ */
+ void setDirty(bool dirty) { _contentIsDirty = dirty; }
+
+ /**
+ * 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;
+
+ virtual bool hasAllFocus() = 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; }
+
+protected:
+ int _id;
+ WindowType _type;
+
+ bool _editable;
+
+ ManagedSurface _surface;
+ bool _contentIsDirty;
+
+ Common::Rect _dims;
+
+ bool (*_callback)(WindowClick, Common::Event &, void *);
+ void *_dataPtr;
+
+ MacWindowManager *_wm;
+};
+
+/**
+ * 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);
+ 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.
+ * @param w New width of the window.
+ * @param h New height of the window.
+ */
+ void resize(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);
+
+ /**
+ * 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.
+ */
+ const Common::Rect &getInnerDimensions() { return _innerDims; }
+
+ /**
+ * 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);
+
+ /**
+ * Mutator to change the active state of the window.
+ * Most often called from the WM.
+ * @param active Target state.
+ */
+ void setActive(bool active);
+ /**
+ * Accessor to determine whether a window is active.
+ * @return True if the window is active.
+ */
+ bool isActive();
+
+ /**
+ * Mutator to change the title of the window.
+ * @param title Target title of the window.
+ */
+ void setTitle(Common::String &title) { _title = 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);
+ bool hasAllFocus() { 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, bool active, int lo, int ro, int to, int bo);
+ //void setBorder(TransparentSurface &border, bool active);
+
+ /**
+ * Indicate whether the window can be closed (false by default).
+ * @param closeable True if the window can be closed.
+ */
+ void setCloseable(bool closeable);
+
+private:
+ void drawBorder();
+ void prepareBorderSurface(ManagedSurface *g);
+ void drawSimpleBorder(ManagedSurface *g);
+ void drawBorderFromSurface(ManagedSurface *g);
+ 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 updateInnerDims();
+ WindowClick isInBorder(int x, int y);
+
+ bool isInCloseButton(int x, int y);
+ bool isInResizeButton(int x, int y);
+ WindowClick isInScroll(int x, int y);
+
+private:
+ ManagedSurface _borderSurface;
+ ManagedSurface _composeSurface;
+
+ MacWindowBorder _macBorder;
+
+ bool _scrollable;
+ bool _resizable;
+ bool _active;
+ bool _borderIsDirty;
+
+ bool _closeable;
+
+ int _borderWidth;
+
+ bool _beingDragged, _beingResized;
+ int _draggedX, _draggedY;
+
+ WindowClick _highlightedPart;
+ float _scrollPos, _scrollSize;
+
+ Common::Rect _innerDims;
+
+ Common::String _title;
+};
+
+
+
+} // End of namespace Graphics
+
+#endif
diff --git a/graphics/macgui/macwindowborder.cpp b/graphics/macgui/macwindowborder.cpp
new file mode 100644
index 0000000000..b77fa35603
--- /dev/null
+++ b/graphics/macgui/macwindowborder.cpp
@@ -0,0 +1,117 @@
+/* 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 2
+* 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, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* MIT License:
+*
+* Copyright (c) 2016 Borja Lorente
+*
+* 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/system.h"
+
+#include "graphics/macgui/macwindowborder.h"
+#include "graphics/macgui/macwindowmanager.h"
+
+namespace Graphics {
+
+using namespace Graphics::MacGUIConstants;
+
+MacWindowBorder::MacWindowBorder() : _activeInitialized(false), _inactiveInitialized(false) {
+ _activeBorder = nullptr;
+ _inactiveBorder = nullptr;
+ _hasOffsets = false;
+}
+
+MacWindowBorder::~MacWindowBorder() {
+ if (_activeBorder)
+ delete _activeBorder;
+ if (_inactiveBorder)
+ delete _inactiveBorder;
+}
+
+bool MacWindowBorder::hasBorder(bool active) {
+ return active ? _activeInitialized : _inactiveInitialized;
+}
+
+void MacWindowBorder::addActiveBorder(TransparentSurface &source) {
+ assert(!_activeBorder);
+ _activeBorder = new NinePatchBitmap(&source, false);
+ _activeInitialized = true;
+}
+
+void MacWindowBorder::addInactiveBorder(TransparentSurface &source) {
+ assert(!_inactiveBorder);
+ _inactiveBorder = new NinePatchBitmap(&source, false);
+ _inactiveInitialized = true;
+}
+
+bool MacWindowBorder::hasOffsets() {
+ return _hasOffsets;
+}
+
+void MacWindowBorder::setOffsets(int left, int right, int top, int bottom) {
+ _borderOffsets[0] = left;
+ _borderOffsets[1] = right;
+ _borderOffsets[2] = top;
+ _borderOffsets[3] = bottom;
+ _hasOffsets = true;
+}
+
+int MacWindowBorder::getOffset(MacBorderOffset offset) {
+ return _borderOffsets[offset];
+}
+
+void MacWindowBorder::blitBorderInto(ManagedSurface &destination, bool active) {
+
+ TransparentSurface srf;
+ NinePatchBitmap *src = active ? _activeBorder : _inactiveBorder;
+
+ srf.create(destination.w, destination.h, destination.format);
+ srf.fillRect(Common::Rect(0, 0, srf.w, srf.h), kColorGreen2);
+
+ byte palette[kColorCount];
+ g_system->getPaletteManager()->grabPalette(palette, 0, kColorCount);
+
+ src->blit(srf, 0, 0, srf.w, srf.h, palette, kColorCount);
+ destination.transBlitFrom(srf, kColorGreen2);
+}
+
+} // End of namespace Graphics
diff --git a/graphics/macgui/macwindowborder.h b/graphics/macgui/macwindowborder.h
new file mode 100644
index 0000000000..54938e5143
--- /dev/null
+++ b/graphics/macgui/macwindowborder.h
@@ -0,0 +1,149 @@
+/* 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 2
+* 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, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* MIT License:
+*
+* Copyright (c) 2016 Borja Lorente
+*
+* 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_MACWINDOWBORDER_H
+#define GRAPHICS_MACGUI_MACWINDOWBORDER_H
+
+#include "common/str.h"
+#include "common/list.h"
+
+#include "graphics/nine_patch.h"
+#include "graphics/managed_surface.h"
+#include "graphics/transparent_surface.h"
+
+namespace Graphics {
+
+enum MacBorderOffset {
+ kBorderOffsetLeft = 0,
+ kBorderOffsetRight = 1,
+ kBorderOffsetTop = 2,
+ kBorderOffsetBottom = 3
+};
+
+/**
+ * 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 active State that we want to check. If true it checks for active border, if false it checks for inactive.
+ * @return True if the checked state has a border loaded, false otherwise.
+ */
+ bool hasBorder(bool active);
+
+ /**
+ * Add the given surface as the display of the border in the active state.
+ * Will fail if there is already an active border.
+ * @param The surface that will be displayed.
+ */
+ void addActiveBorder(TransparentSurface &source);
+
+ /**
+ * Add the given surface as the display of the border in the inactive state.
+ * Will fail if there is already an inactive border.
+ * @param The surface that will be displayed.
+ */
+ void addInactiveBorder(TransparentSurface &source);
+
+ /**
+ * Accessor function for the custom offsets.
+ * @return True if custom offsets have been indicated (setOffsets has been called previously).
+ */
+ bool hasOffsets();
+
+ /**
+ * 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);
+
+ /**
+ * 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.
+ */
+ int getOffset(MacBorderOffset offset);
+
+ /**
+ * 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 active True if we want to blit the active border, false otherwise.
+ */
+ void blitBorderInto(ManagedSurface &destination, bool active);
+
+private:
+
+ NinePatchBitmap *_activeBorder;
+ NinePatchBitmap *_inactiveBorder;
+
+ bool _activeInitialized;
+ bool _inactiveInitialized;
+
+ bool _hasOffsets;
+ int _borderOffsets[4];
+
+};
+
+} // End of namespace Graphics
+#endif
diff --git a/graphics/macgui/macwindowmanager.cpp b/graphics/macgui/macwindowmanager.cpp
new file mode 100644
index 0000000000..9d3b729661
--- /dev/null
+++ b/graphics/macgui/macwindowmanager.cpp
@@ -0,0 +1,423 @@
+/* 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * 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/array.h"
+#include "common/events.h"
+#include "common/list.h"
+#include "common/unzip.h"
+#include "common/system.h"
+#include "common/stream.h"
+
+#include "graphics/cursorman.h"
+#include "graphics/fonts/bdf.h"
+#include "graphics/managed_surface.h"
+#include "graphics/palette.h"
+#include "graphics/primitives.h"
+#include "graphics/macgui/macwindowmanager.h"
+#include "graphics/macgui/macwindow.h"
+#include "graphics/macgui/macmenu.h"
+
+namespace Graphics {
+
+static const byte palette[] = {
+ 0, 0, 0, // Black
+ 0x80, 0x80, 0x80, // Gray
+ 0xff, 0xff, 0xff, // White
+ 0x00, 0xff, 0x00, // Green
+ 0x00, 0xcf, 0x00 // Green2
+};
+
+static byte fillPatterns[][8] = { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, // kPatternSolid
+ { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 }, // kPatternStripes
+ { 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 }, // kPatternCheckers
+ { 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa } // kPatternCheckers2
+};
+
+static const byte macCursorArrow[] = {
+ 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 2, 0, 2, 3, 3, 3, 3, 3, 3, 3, 3,
+ 2, 0, 0, 2, 3, 3, 3, 3, 3, 3, 3,
+ 2, 0, 0, 0, 2, 3, 3, 3, 3, 3, 3,
+ 2, 0, 0, 0, 0, 2, 3, 3, 3, 3, 3,
+ 2, 0, 0, 0, 0, 0, 2, 3, 3, 3, 3,
+ 2, 0, 0, 0, 0, 0, 0, 2, 3, 3, 3,
+ 2, 0, 0, 0, 0, 0, 0, 0, 2, 3, 3,
+ 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3,
+ 2, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2,
+ 2, 0, 0, 2, 0, 0, 2, 3, 3, 3, 3,
+ 2, 0, 2, 3, 2, 0, 0, 2, 3, 3, 3,
+ 2, 2, 3, 3, 2, 0, 0, 2, 3, 3, 3,
+ 2, 3, 3, 3, 3, 2, 0, 0, 2, 3, 3,
+ 3, 3, 3, 3, 3, 2, 0, 0, 2, 3, 3,
+ 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 3
+};
+
+static const byte macCursorBeam[] = {
+ 0, 0, 3, 3, 3, 0, 0, 3, 3, 3, 3,
+ 3, 3, 0, 3, 0, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 0, 3, 0, 3, 3, 3, 3, 3, 3,
+ 0, 0, 3, 3, 3, 0, 0, 3, 3, 3, 3,
+};
+
+MacWindowManager::MacWindowManager() {
+ _screen = 0;
+ _lastId = 0;
+ _activeWindow = -1;
+
+ _menu = 0;
+
+ _fullRefresh = true;
+
+ _builtInFonts = true;
+
+ for (int i = 0; i < ARRAYSIZE(fillPatterns); i++)
+ _patterns.push_back(fillPatterns[i]);
+
+ loadFonts();
+
+ g_system->getPaletteManager()->setPalette(palette, 0, ARRAYSIZE(palette) / 3);
+
+ CursorMan.replaceCursorPalette(palette, 0, ARRAYSIZE(palette) / 3);
+ CursorMan.replaceCursor(macCursorArrow, 11, 16, 1, 1, 3);
+ _cursorIsArrow = true;
+ CursorMan.showMouse(true);
+}
+
+MacWindowManager::~MacWindowManager() {
+ for (int i = 0; i < _lastId; i++)
+ delete _windows[i];
+}
+
+MacWindow *MacWindowManager::addWindow(bool scrollable, bool resizable, bool editable) {
+ MacWindow *w = new MacWindow(_lastId, scrollable, resizable, editable, this);
+
+ _windows.push_back(w);
+ _windowStack.push_back(w);
+
+ setActive(_lastId);
+
+ _lastId++;
+
+ return w;
+}
+
+Menu *MacWindowManager::addMenu() {
+ _menu = new Menu(_lastId, _screen->getBounds(), this);
+
+ _windows.push_back(_menu);
+
+ _lastId++;
+
+ return _menu;
+}
+
+void MacWindowManager::setActive(int id) {
+ if (_activeWindow == id)
+ return;
+
+ if (_activeWindow != -1)
+ _windows[_activeWindow]->setActive(false);
+
+ _activeWindow = id;
+
+ _windows[id]->setActive(true);
+
+ _windowStack.remove(_windows[id]);
+ _windowStack.push_back(_windows[id]);
+
+ _fullRefresh = true;
+}
+
+void MacWindowManager::removeWindow(MacWindow *target) {
+ _windowsToRemove.push_back(target);
+ _needsRemoval = true;
+}
+
+struct PlotData {
+ Graphics::ManagedSurface *surface;
+ MacPatterns *patterns;
+ uint fillType;
+ int thickness;
+
+ PlotData(Graphics::ManagedSurface *s, MacPatterns *p, int f, int t) :
+ surface(s), patterns(p), fillType(f), thickness(t) {}
+};
+
+static void drawPixel(int x, int y, int color, void *data) {
+ PlotData *p = (PlotData *)data;
+
+ if (p->fillType > p->patterns->size())
+ return;
+
+ byte *pat = p->patterns->operator[](p->fillType - 1);
+
+ if (p->thickness == 1) {
+ if (x >= 0 && x < p->surface->w && y >= 0 && y < p->surface->h) {
+ uint xu = (uint)x; // for letting compiler optimize it
+ uint yu = (uint)y;
+
+ *((byte *)p->surface->getBasePtr(xu, yu)) =
+ (pat[yu % 8] & (1 << (7 - xu % 8))) ?
+ color : kColorWhite;
+ }
+ } else {
+ int x1 = x;
+ int x2 = x1 + p->thickness;
+ int y1 = y;
+ int y2 = y1 + p->thickness;
+
+ for (y = y1; y < y2; y++)
+ for (x = x1; x < x2; x++)
+ if (x >= 0 && x < p->surface->w && y >= 0 && y < p->surface->h) {
+ uint xu = (uint)x; // for letting compiler optimize it
+ uint yu = (uint)y;
+ *((byte *)p->surface->getBasePtr(xu, yu)) =
+ (pat[yu % 8] & (1 << (7 - xu % 8))) ?
+ color : kColorWhite;
+ }
+ }
+}
+
+void MacWindowManager::drawDesktop() {
+ Common::Rect r(_screen->getBounds());
+
+ PlotData pd(_screen, &_patterns, kPatternCheckers, 1);
+
+ Graphics::drawRoundRect(r, kDesktopArc, kColorBlack, true, drawPixel, &pd);
+
+ g_system->copyRectToScreen(_screen->getPixels(), _screen->pitch, 0, 0, _screen->w, _screen->h);
+}
+
+void MacWindowManager::draw() {
+ assert(_screen);
+
+ removeMarked();
+
+ if (_fullRefresh)
+ drawDesktop();
+
+ for (Common::List<BaseMacWindow *>::const_iterator it = _windowStack.begin(); it != _windowStack.end(); it++) {
+ BaseMacWindow *w = *it;
+ if (w->draw(_screen, _fullRefresh)) {
+ w->setDirty(false);
+
+ Common::Rect clip(w->getDimensions().left - 2, w->getDimensions().top - 2, w->getDimensions().right - 2, w->getDimensions().bottom - 2);
+ clip.clip(_screen->getBounds());
+
+ g_system->copyRectToScreen(_screen->getBasePtr(clip.left, clip.top), _screen->pitch, clip.left, clip.top, clip.width(), clip.height());
+ }
+ }
+
+ // Menu is drawn on top of everything and always
+ if (_menu)
+ _menu->draw(_screen, _fullRefresh);
+
+ _fullRefresh = false;
+}
+
+bool MacWindowManager::processEvent(Common::Event &event) {
+ // Menu gets events first fir shortcuts and menu bar
+ if (_menu && _menu->processEvent(event))
+ return true;
+
+ if (event.type != Common::EVENT_MOUSEMOVE && event.type != Common::EVENT_LBUTTONDOWN &&
+ event.type != Common::EVENT_LBUTTONUP)
+ return false;
+
+ if (_windows[_activeWindow]->isEditable() && _windows[_activeWindow]->getType() == kWindowWindow &&
+ ((MacWindow *)_windows[_activeWindow])->getInnerDimensions().contains(event.mouse.x, event.mouse.y)) {
+ if (_cursorIsArrow) {
+ CursorMan.replaceCursor(macCursorBeam, 11, 16, 3, 8, 3);
+ _cursorIsArrow = false;
+ }
+ } else {
+ if (_cursorIsArrow == false) {
+ CursorMan.replaceCursor(macCursorArrow, 11, 16, 1, 1, 3);
+ _cursorIsArrow = true;
+ }
+ }
+
+ for (Common::List<BaseMacWindow *>::const_iterator it = _windowStack.end(); it != _windowStack.begin();) {
+ it--;
+ BaseMacWindow *w = *it;
+
+
+ if (w->hasAllFocus() || w->getDimensions().contains(event.mouse.x, event.mouse.y)) {
+ if (event.type == Common::EVENT_LBUTTONDOWN || event.type == Common::EVENT_LBUTTONUP)
+ setActive(w->getId());
+
+ return w->processEvent(event);
+ }
+ }
+
+ return false;
+}
+
+void MacWindowManager::removeMarked() {
+ if (!_needsRemoval) return;
+
+ Common::List<BaseMacWindow *>::const_iterator it;
+ for (it = _windowsToRemove.begin(); it != _windowsToRemove.end(); it++) {
+ removeFromStack(*it);
+ removeFromWindowList(*it);
+ delete *it;
+ _activeWindow = 0;
+ _fullRefresh = true;
+ }
+ _windowsToRemove.clear();
+ _needsRemoval = false;
+}
+
+void MacWindowManager::removeFromStack(BaseMacWindow *target) {
+ Common::List<BaseMacWindow *>::iterator stackIt;
+ for (stackIt = _windowStack.begin(); stackIt != _windowStack.end(); stackIt++) {
+ if (*stackIt == target) {
+ stackIt = _windowStack.erase(stackIt);
+ stackIt--;
+ }
+ }
+}
+
+void MacWindowManager::removeFromWindowList(BaseMacWindow *target) {
+ int size = _windows.size();
+ int ndx = 0;
+ for (int i = 0; i < size; i++) {
+ if (_windows[i] == target) {
+ ndx = i;
+ }
+ }
+ _windows.remove_at(ndx);
+}
+
+//////////////////////
+// Font stuff
+//////////////////////
+void MacWindowManager::loadFonts() {
+ Common::Archive *dat;
+
+ dat = Common::makeZipArchive("classicmacfonts.dat");
+
+ if (!dat) {
+ warning("Could not find classicmacfonts.dat. Falling back to built-in fonts");
+ _builtInFonts = true;
+
+ return;
+ }
+
+ Common::ArchiveMemberList list;
+ dat->listMembers(list);
+
+ for (Common::ArchiveMemberList::iterator it = list.begin(); it != list.end(); ++it) {
+ Common::SeekableReadStream *stream = dat->createReadStreamForMember((*it)->getName());
+
+ Graphics::BdfFont *font = Graphics::BdfFont::loadFont(*stream);
+
+ delete stream;
+
+ Common::String fontName = (*it)->getName();
+
+ // Trim the .bdf extension
+ for (int i = fontName.size() - 1; i >= 0; --i) {
+ if (fontName[i] == '.') {
+ while ((uint)i < fontName.size()) {
+ fontName.deleteLastChar();
+ }
+ break;
+ }
+ }
+
+ FontMan.assignFontToName(fontName, font);
+
+ debug(2, " %s", fontName.c_str());
+ }
+
+ _builtInFonts = false;
+
+ delete dat;
+}
+
+const Graphics::Font *MacWindowManager::getFont(const char *name, Graphics::FontManager::FontUsage fallback) {
+ const Graphics::Font *font = 0;
+
+ if (!_builtInFonts) {
+ font = FontMan.getFontByName(name);
+
+ if (!font)
+ warning("Cannot load font %s", name);
+ }
+
+ if (_builtInFonts || !font)
+ font = FontMan.getFontByUsage(fallback);
+
+ return font;
+}
+
+/////////////////
+// Cursor stuff
+/////////////////
+void MacWindowManager::pushArrowCursor() {
+ CursorMan.pushCursor(macCursorArrow, 11, 16, 1, 1, 3);
+}
+
+void MacWindowManager::popCursor() {
+ CursorMan.popCursor();
+}
+
+
+} // End of namespace Graphics
diff --git a/graphics/macgui/macwindowmanager.h b/graphics/macgui/macwindowmanager.h
new file mode 100644
index 0000000000..22731a142e
--- /dev/null
+++ b/graphics/macgui/macwindowmanager.h
@@ -0,0 +1,218 @@
+/* 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * 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_MACWINDOWMANAGER_H
+#define GRAPHICS_MACGUI_MACWINDOWMANAGER_H
+
+#include "common/array.h"
+#include "common/list.h"
+#include "common/events.h"
+#include "common/archive.h"
+
+#include "graphics/fontman.h"
+#include "graphics/macgui/macwindow.h"
+
+namespace Graphics {
+
+namespace MacGUIConstants {
+enum {
+ kDesktopArc = 7
+};
+
+enum {
+ kColorBlack = 0,
+ kColorGray = 1,
+ kColorWhite = 2,
+ kColorGreen = 3,
+ kColorGreen2 = 4,
+ kColorCount
+};
+
+enum {
+ kPatternSolid = 1,
+ kPatternStripes = 2,
+ kPatternCheckers = 3,
+ kPatternCheckers2 = 4
+};
+}
+using namespace MacGUIConstants;
+
+class ManagedSurface;
+
+class Menu;
+
+typedef Common::Array<byte *> MacPatterns;
+
+/**
+ * A manager class to handle window creation, destruction,
+ * drawing, moving and event handling.
+ */
+class MacWindowManager {
+public:
+ MacWindowManager();
+ ~MacWindowManager();
+
+ /**
+ * 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) { _screen = screen; }
+ /**
+ * 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(const char *name, FontManager::FontUsage fallback);
+
+ /**
+ * 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);
+ /**
+ * 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.
+ */
+ Menu *addMenu();
+ /**
+ * Set the desired window state to active.
+ * @param id ID of the window that has to be set to active.
+ */
+ void setActive(int id);
+ /**
+ * 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 = true; }
+
+ /**
+ * 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) { return _windows[id]; }
+
+ /**
+ * Retrieve the patterns used to fill surfaces.
+ * @return A MacPatterns object reference with the patterns.
+ */
+ MacPatterns &getPatterns() { return _patterns; }
+ void drawFilledRoundRect(ManagedSurface *surface, Common::Rect &rect, int arc, int color);
+
+ void pushArrowCursor();
+ void popCursor();
+
+private:
+ void drawDesktop();
+ void loadFonts();
+
+ void removeMarked();
+ void removeFromStack(BaseMacWindow *target);
+ void removeFromWindowList(BaseMacWindow *target);
+
+private:
+ ManagedSurface *_screen;
+
+ Common::List<BaseMacWindow *> _windowStack;
+ Common::Array<BaseMacWindow *> _windows;
+
+ Common::List<BaseMacWindow *> _windowsToRemove;
+ bool _needsRemoval;
+
+ int _lastId;
+ int _activeWindow;
+
+ bool _fullRefresh;
+
+ MacPatterns _patterns;
+
+ Menu *_menu;
+
+ bool _builtInFonts;
+ bool _cursorIsArrow;
+};
+
+} // End of namespace Graphics
+
+#endif
diff --git a/graphics/module.mk b/graphics/module.mk
index 7331a56c93..f0f5af6c00 100644
--- a/graphics/module.mk
+++ b/graphics/module.mk
@@ -12,6 +12,10 @@ MODULE_OBJS := \
fonts/ttf.o \
fonts/winfont.o \
maccursor.o \
+ macgui/macmenu.o \
+ macgui/macwindow.o \
+ macgui/macwindowborder.o \
+ macgui/macwindowmanager.o\
managed_surface.o \
nine_patch.o \
pixelformat.o \
diff --git a/graphics/nine_patch.cpp b/graphics/nine_patch.cpp
index 8ac6977eed..fa2ef20a6e 100644
--- a/graphics/nine_patch.cpp
+++ b/graphics/nine_patch.cpp
@@ -48,6 +48,8 @@
#include "graphics/transparent_surface.h"
#include "graphics/nine_patch.h"
+#include "graphics/managed_surface.h"
+
namespace Graphics {
NinePatchSide::~NinePatchSide() {
@@ -201,7 +203,7 @@ bad_bitmap:
}
}
-void NinePatchBitmap::blit(Graphics::Surface &target, int dx, int dy, int dw, int dh) {
+void NinePatchBitmap::blit(Graphics::Surface &target, int dx, int dy, int dw, int dh, byte *palette, byte numColors) {
/* don't draw bitmaps that are smaller than the fixed area */
if (dw < _h._fix || dh < _v._fix)
return;
@@ -223,6 +225,43 @@ void NinePatchBitmap::blit(Graphics::Surface &target, int dx, int dy, int dw, in
_cached_dh = dh;
}
+ /* Handle CLUT8 */
+ if (target.format.bytesPerPixel == 1) {
+ if (!palette)
+ warning("Trying to blit into a surface with 1bpp, you need the palette.");
+
+ Surface srf;
+ srf.create(target.w, target.h, _bmp->format);
+
+ drawRegions(srf, dx, dy, dw, dh);
+
+ //TODO: This can be further optimized by keeping the data between draws,
+ // and using a unique identifier for each palette, so that it only gets
+ // recalculated when the palette changes.
+ _cached_colors.clear();
+
+ for (uint i = 0; i < srf.w; ++i) {
+ for (uint j = 0; j < srf.h; ++j) {
+ uint32 color = *(uint32*)srf.getBasePtr(i, j);
+ if (color > 0) {
+ *((byte *)target.getBasePtr(i, j)) = closestGrayscale(color, palette, numColors);
+ }
+ }
+ }
+
+ return;
+ }
+
+ /* Else, draw regions normally */
+ drawRegions(target, dx, dy, dw, dh);
+}
+
+NinePatchBitmap::~NinePatchBitmap() {
+ if (_destroy_bmp)
+ delete _bmp;
+}
+
+void NinePatchBitmap::drawRegions(Graphics::Surface &target, int dx, int dy, int dw, int dh) {
/* draw each region */
for (uint i = 0; i < _v._m.size(); ++i) {
for (uint j = 0; j < _h._m.size(); ++j) {
@@ -271,9 +310,50 @@ void NinePatchBitmap::blitClip(Graphics::Surface &target, Common::Rect clip, int
}
}
-NinePatchBitmap::~NinePatchBitmap() {
- if (_destroy_bmp)
- delete _bmp;
+byte NinePatchBitmap::getColorIndex(uint32 target, byte* palette) {
+ byte *pal = palette;
+ uint i = 0;
+ uint32 color = TS_RGB(pal[0], pal[1], pal[2]);
+ while (color != target) {
+ i += 3;
+ color = TS_RGB(pal[i], pal[i + 1], pal[i + 2]);
+ }
+ return (i / 3);
+}
+
+uint32 NinePatchBitmap::grayscale(uint32 color) {
+ byte r, g, b;
+ _bmp->format.colorToRGB(color, r, g, b);
+ return grayscale(r, g, b);
+}
+
+uint32 NinePatchBitmap::grayscale(byte r, byte g, byte b) {
+ return (0.29 * r + 0.58 * g + 0.11 * b) / 3;
+}
+
+static inline uint32 dist(uint32 a, uint32 b) {
+ if (a > b)
+ return (a - b);
+
+ return b - a;
+}
+
+byte NinePatchBitmap::closestGrayscale(uint32 color, byte* palette, byte paletteLength) {
+ if (!_cached_colors.contains(color)) {
+ byte target = grayscale(color);
+ byte bestNdx = 0;
+ byte bestColor = grayscale(palette[0], palette[1], palette[2]);
+ for (byte i = 1; i < paletteLength; ++i) {
+ byte current = grayscale(palette[i * 3], palette[(i * 3) + 1], palette[(i * 3) + 2]);
+ if (dist(target, bestColor) >= dist(target, current)) {
+ bestColor = current;
+ bestNdx = i;
+ }
+ }
+ _cached_colors[color] = bestNdx;
+ }
+
+ return _cached_colors[color];
}
} // end of namespace Graphics
diff --git a/graphics/nine_patch.h b/graphics/nine_patch.h
index 45e4e0918a..aa81a2fc1f 100644
--- a/graphics/nine_patch.h
+++ b/graphics/nine_patch.h
@@ -47,9 +47,14 @@
#define GRAPHICS_NINE_PATCH_H
#include "common/array.h"
+#include "common/rect.h"
+#include "common/hashmap.h"
namespace Graphics {
+class TransparentSurface;
+class Surface;
+
struct NinePatchMark {
int offset;
int length;
@@ -77,12 +82,13 @@ class NinePatchBitmap {
bool _destroy_bmp;
int _width, _height;
int _cached_dw, _cached_dh;
+ Common::HashMap<uint32, int> _cached_colors;
public:
NinePatchBitmap(Graphics::TransparentSurface *bmp, bool owns_bitmap);
~NinePatchBitmap();
- void blit(Graphics::Surface &target, int dx, int dy, int dw, int dh);
+ void blit(Graphics::Surface &target, int dx, int dy, int dw, int dh, byte *palette = NULL, byte numColors = 0);
void blitClip(Graphics::Surface &target, Common::Rect clip, int dx, int dy, int dw, int dh);
int getWidth() { return _width; }
@@ -91,6 +97,16 @@ public:
int getMinHeight() { return _v._fix; }
Graphics::TransparentSurface *getSource() { return _bmp; }
Common::Rect &getPadding() { return _padding; }
+
+private:
+
+ void drawRegions(Graphics::Surface &target, int dx, int dy, int dw, int dh);
+
+ // Assumes color is in the palette
+ byte getColorIndex(uint32 target, byte *palette);
+ uint32 grayscale(uint32 color);
+ uint32 grayscale(byte r, byte g, byte b);
+ byte closestGrayscale(uint32 color, byte* palette, byte paletteLength);
};
} // end of namespace Graphics