1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
21
22 #include "common/array.h"
23 #include "common/list.h"
24 #include "common/system.h"
25 #include "common/timer.h"
26
27 #include "graphics/cursorman.h"
28 #include "graphics/managed_surface.h"
29 #include "graphics/palette.h"
30 #include "graphics/primitives.h"
31 #include "graphics/macgui/macwindowmanager.h"
32 #include "graphics/macgui/macfontmanager.h"
33 #include "graphics/macgui/macwindow.h"
34 #include "graphics/macgui/mactextwindow.h"
35 #include "graphics/macgui/macmenu.h"
36
37 #include "image/bmp.h"
38
39 namespace Graphics {
40
41 static const byte palette[] = {
42 0, 0, 0, // Black
43 0x80, 0x80, 0x80, // Gray80
44 0x88, 0x88, 0x88, // Gray88
45 0xee, 0xee, 0xee, // GrayEE
46 0xff, 0xff, 0xff, // White
47 0x00, 0xff, 0x00, // Green
48 0x00, 0xcf, 0x00 // Green2
49 };
50
51 static byte fillPatterns[][8] = { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, // kPatternSolid
52 { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 }, // kPatternStripes
53 { 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 }, // kPatternCheckers
54 { 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa }, // kPatternCheckers2
55 { 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22 }, // kPatternLightGray
56 { 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd } // kPatternDarkGray
57 };
58
59 static const byte cursorPalette[] = {
60 0, 0, 0,
61 0xff, 0xff, 0xff
62 };
63
64 static const byte macCursorArrow[] = {
65 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3,
66 1, 0, 1, 3, 3, 3, 3, 3, 3, 3, 3,
67 1, 0, 0, 1, 3, 3, 3, 3, 3, 3, 3,
68 1, 0, 0, 0, 1, 3, 3, 3, 3, 3, 3,
69 1, 0, 0, 0, 0, 1, 3, 3, 3, 3, 3,
70 1, 0, 0, 0, 0, 0, 1, 3, 3, 3, 3,
71 1, 0, 0, 0, 0, 0, 0, 1, 3, 3, 3,
72 1, 0, 0, 0, 0, 0, 0, 0, 1, 3, 3,
73 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3,
74 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
75 1, 0, 0, 1, 0, 0, 1, 3, 3, 3, 3,
76 1, 0, 1, 3, 1, 0, 0, 1, 3, 3, 3,
77 1, 1, 3, 3, 1, 0, 0, 1, 3, 3, 3,
78 1, 3, 3, 3, 3, 1, 0, 0, 1, 3, 3,
79 3, 3, 3, 3, 3, 1, 0, 0, 1, 3, 3,
80 3, 3, 3, 3, 3, 3, 1, 1, 1, 3, 3
81 };
82
83 static const byte macCursorBeam[] = {
84 0, 0, 3, 3, 3, 0, 0, 3, 3, 3, 3,
85 3, 3, 0, 3, 0, 3, 3, 3, 3, 3, 3,
86 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
87 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
88 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
89 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
90 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
91 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
92 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
93 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
94 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
95 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
96 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
97 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
98 3, 3, 0, 3, 0, 3, 3, 3, 3, 3, 3,
99 0, 0, 3, 3, 3, 0, 0, 3, 3, 3, 3,
100 };
101 static const byte macCursorCrossHair[] = {
102 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3,
103 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3,
104 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3,
105 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3,
106 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3,
107 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
108 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3,
109 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3,
110 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3,
111 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3,
112 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3,
113 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
114 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
115 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
116 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
117 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
118 };
119 static const byte macCursorWatch[] = {
120 3, 3, 0, 0, 0, 0, 0, 0, 3, 3, 3,
121 3, 3, 0, 0, 0, 0, 0, 0, 3, 3, 3,
122 3, 3, 0, 0, 0, 0, 0, 0, 3, 3, 3,
123 3, 3, 0, 0, 0, 0, 0, 0, 3, 3, 3,
124 3, 0, 1, 1, 1, 1, 1, 1, 0, 1, 3,
125 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 3,
126 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 3,
127 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,
128 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0,
129 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 3,
130 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 3,
131 3, 0, 1, 1, 1, 1, 1, 1, 0, 1, 3,
132 3, 3, 0, 0, 0, 0, 0, 0, 3, 3, 3,
133 3, 3, 0, 0, 0, 0, 0, 0, 3, 3, 3,
134 3, 3, 0, 0, 0, 0, 0, 0, 3, 3, 3,
135 3, 3, 0, 0, 0, 0, 0, 0, 3, 3, 3,
136 };
137 static const byte macCursorCrossBar[] = {
138 3, 3, 3, 0, 0, 0, 0, 3, 3, 3, 3,
139 3, 3, 3, 0, 1, 1, 0, 0, 3, 3, 3,
140 3, 3, 3, 0, 1, 1, 0, 0, 3, 3, 3,
141 3, 3, 3, 0, 1, 1, 0, 0, 3, 3, 3,
142 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 3,
143 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0,
144 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0,
145 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0,
146 3, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0,
147 3, 3, 3, 0, 1, 1, 0, 0, 3, 3, 3,
148 3, 3, 3, 0, 1, 1, 0, 0, 3, 3, 3,
149 3, 3, 3, 0, 0, 0, 0, 0, 3, 3, 3,
150 3, 3, 3, 3, 0, 0, 0, 0, 3, 3, 3,
151 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
152 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
153 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
154 };
155
156 static void menuTimerHandler(void *refCon);
157
MacWindowManager(uint32 mode,MacPatterns * patterns,Common::Language language)158 MacWindowManager::MacWindowManager(uint32 mode, MacPatterns *patterns, Common::Language language) {
159 _screen = nullptr;
160 _screenCopy = nullptr;
161 _desktopBmp = nullptr;
162 _desktop = nullptr;
163 _lastId = 0;
164 _activeWindow = -1;
165 _needsRemoval = false;
166
167 _activeWidget = nullptr;
168 _mouseDown = false;
169 _hoveredWidget = nullptr;
170
171 _mode = mode;
172 _language = language;
173
174 _menu = 0;
175 _menuDelay = 0;
176 _menuTimerActive = false;
177
178 _engineP = nullptr;
179 _engineR = nullptr;
180 _redrawEngineCallback = nullptr;
181 _screenCopyPauseToken = nullptr;
182
183 _colorBlack = kColorBlack;
184 _colorGray80 = kColorGray80;
185 _colorGray88 = kColorGray88;
186 _colorGrayEE = kColorGrayEE;
187 _colorWhite = kColorWhite;
188 _colorGreen = kColorGreen;
189 _colorGreen2 = kColorGreen2;
190
191 _fullRefresh = true;
192 _inEditableArea = false;
193
194 _hilitingWidget = false;
195
196 if (mode & kWMMode32bpp)
197 _pixelformat = Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0);
198 else
199 _pixelformat = PixelFormat::createFormatCLUT8();
200
201 if (patterns) {
202 _patterns = *patterns;
203 } else {
204 for (int i = 0; i < ARRAYSIZE(fillPatterns); i++)
205 _patterns.push_back(fillPatterns[i]);
206 }
207
208 // builtin pattern
209 for (int i = 0; i < ARRAYSIZE(fillPatterns); i++)
210 _builtinPatterns.push_back(fillPatterns[i]);
211
212 g_system->getPaletteManager()->setPalette(palette, 0, ARRAYSIZE(palette) / 3);
213
214 _paletteSize = ARRAYSIZE(palette) / 3;
215 if (_paletteSize) {
216 _palette = (byte *)malloc(_paletteSize * 3);
217 memcpy(_palette, palette, _paletteSize * 3);
218 }
219
220 _fontMan = new MacFontManager(mode, language);
221
222 _cursor = nullptr;
223 _tempType = kMacCursorArrow;
224 replaceCursor(kMacCursorArrow);
225 CursorMan.showMouse(true);
226
227 loadDataBundle();
228 if (!(_mode & Graphics::kWMNoScummVMWallpaper)) {
229 loadDesktop();
230 }
231 }
232
~MacWindowManager()233 MacWindowManager::~MacWindowManager() {
234 for (Common::HashMap<uint, BaseMacWindow *>::iterator it = _windows.begin(); it != _windows.end(); it++)
235 delete it->_value;
236
237 if (_palette)
238 free(_palette);
239
240 delete _fontMan;
241 delete _screenCopy;
242
243 if (_desktopBmp) {
244 _desktopBmp->free();
245 delete _desktopBmp;
246 }
247 delete _desktop;
248
249 cleanupDataBundle();
250
251 g_system->getTimerManager()->removeTimerProc(&menuTimerHandler);
252 }
253
setScreen(ManagedSurface * screen)254 void MacWindowManager::setScreen(ManagedSurface *screen) {
255 _screen = screen;
256 delete _screenCopy;
257 _screenCopy = nullptr;
258
259 if (_desktop)
260 _desktop->free();
261 else
262 _desktop = new ManagedSurface();
263
264 _desktop->create(_screen->w, _screen->h, _pixelformat);
265 drawDesktop();
266 }
267
setScreen(int w,int h)268 void MacWindowManager::setScreen(int w, int h) {
269 if (_desktop)
270 _desktop->free();
271 else
272 _desktop = new ManagedSurface();
273
274 _screenDims = Common::Rect(w, h);
275 _desktop->create(w, h, _pixelformat);
276 drawDesktop();
277 }
278
resizeScreen(int w,int h)279 void MacWindowManager::resizeScreen(int w, int h) {
280 if (!_screen)
281 error("MacWindowManager::resizeScreen(): Trying to creating surface on non-existing screen");
282 _screenDims = Common::Rect(w, h);
283 _screen->free();
284 _screen->create(w, h, _pixelformat);
285 }
286
setMode(uint32 mode)287 void MacWindowManager::setMode(uint32 mode) {
288 _mode = mode;
289
290 if (mode & kWMModeForceBuiltinFonts)
291 _fontMan->forceBuiltinFonts();
292 }
293
clearHandlingWidgets()294 void MacWindowManager::clearHandlingWidgets() {
295 // pass a LBUTTONUP event to those widgets should clear those state
296 Common::Event event;
297 event.type = Common::EVENT_LBUTTONUP;
298 event.mouse = _lastClickPos;
299 processEvent(event);
300
301 setActiveWidget(nullptr);
302 _hoveredWidget = nullptr;
303 }
304
setActiveWidget(MacWidget * widget)305 void MacWindowManager::setActiveWidget(MacWidget *widget) {
306 if (_activeWidget == widget)
307 return;
308
309 if (_activeWidget)
310 _activeWidget->setActive(false);
311
312 _activeWidget = widget;
313
314 if (_activeWidget)
315 _activeWidget->setActive(true);
316 }
317
clearWidgetRefs(MacWidget * widget)318 void MacWindowManager::clearWidgetRefs(MacWidget *widget) {
319 if (widget == _hoveredWidget)
320 _hoveredWidget = nullptr;
321
322 if (widget == _activeWidget)
323 _activeWidget = nullptr;
324 }
325
addWindow(bool scrollable,bool resizable,bool editable)326 MacWindow *MacWindowManager::addWindow(bool scrollable, bool resizable, bool editable) {
327 MacWindow *w = new MacWindow(_lastId, scrollable, resizable, editable, this);
328
329 addWindowInitialized(w);
330
331 setActiveWindow(getNextId());
332
333 return w;
334 }
335
addTextWindow(const MacFont * font,int fgcolor,int bgcolor,int maxWidth,TextAlign textAlignment,MacMenu * menu,bool cursorHandler)336 MacTextWindow *MacWindowManager::addTextWindow(const MacFont *font, int fgcolor, int bgcolor, int maxWidth, TextAlign textAlignment, MacMenu *menu, bool cursorHandler) {
337 MacTextWindow *w = new MacTextWindow(this, font, fgcolor, bgcolor, maxWidth, textAlignment, menu, cursorHandler);
338
339 addWindowInitialized(w);
340
341 setActiveWindow(getNextId());
342
343 return w;
344 }
345
addTextWindow(const Font * font,int fgcolor,int bgcolor,int maxWidth,TextAlign textAlignment,MacMenu * menu,bool cursorHandler)346 MacTextWindow *MacWindowManager::addTextWindow(const Font *font, int fgcolor, int bgcolor, int maxWidth, TextAlign textAlignment, MacMenu *menu, bool cursorHandler) {
347 MacTextWindow *w = new MacTextWindow(this, font, fgcolor, bgcolor, maxWidth, textAlignment, menu, cursorHandler);
348
349 addWindowInitialized(w);
350
351 setActiveWindow(getNextId());
352
353 return w;
354 }
355
356
addWindowInitialized(MacWindow * macwindow)357 void MacWindowManager::addWindowInitialized(MacWindow *macwindow) {
358 _windows[macwindow->getId()] = macwindow;
359 _windowStack.push_back(macwindow);
360 }
361
addMenu()362 MacMenu *MacWindowManager::addMenu() {
363 if (_menu) {
364 _windows[_menu->getId()] = nullptr;
365 delete _menu;
366 }
367
368 _menu = new MacMenu(getNextId(), getScreenBounds(), this);
369
370 _windows[_menu->getId()] = _menu;
371
372 return _menu;
373 }
374
removeMenu()375 void MacWindowManager::removeMenu() {
376 if (_menu) {
377 _windows[_menu->getId()] = nullptr;
378 delete _menu;
379 _menu = nullptr;
380 }
381 }
382
activateMenu()383 void MacWindowManager::activateMenu() {
384 if (!_menu || ((_mode & kWMModeAutohideMenu) && _menu->isVisible()))
385 return;
386
387 if (_mode & kWMModalMenuMode) {
388 activateScreenCopy();
389 }
390
391 _menu->setVisible(true);
392 }
393
activateScreenCopy()394 void MacWindowManager::activateScreenCopy() {
395 if (_screen) {
396 if (!_screenCopy)
397 _screenCopy = new ManagedSurface(*_screen); // Create a copy
398 else
399 *_screenCopy = *_screen;
400 } else {
401 Surface *surface = g_system->lockScreen();
402
403 if (!_screenCopy) {
404 _screenCopy = new ManagedSurface(_screenDims.width(), _screenDims.height());
405 }
406
407 _screenCopy->blitFrom(*surface);
408 g_system->unlockScreen();
409 }
410
411 _screenCopyPauseToken = new PauseToken(pauseEngine());
412 }
413
disableScreenCopy()414 void MacWindowManager::disableScreenCopy() {
415 if (_screenCopyPauseToken) {
416 _screenCopyPauseToken->clear();
417 delete _screenCopyPauseToken;
418 _screenCopyPauseToken = nullptr;
419 }
420
421 // add a check, we may not get the _screenCopy because we may not activate the menu
422 if (!_screenCopy)
423 return;
424
425 if (_screen)
426 *_screen = *_screenCopy; // restore screen
427
428 g_system->copyRectToScreen(_screenCopy->getBasePtr(0, 0), _screenCopy->pitch, 0, 0, _screenCopy->w, _screenCopy->h);
429 }
430
setMenuItemCheckMark(const Common::String & menuId,const Common::String & itemId,bool checkMark)431 void MacWindowManager::setMenuItemCheckMark(const Common::String &menuId, const Common::String &itemId, bool checkMark) {
432 if (_menu) {
433 _menu->setCheckMark(menuId, itemId, checkMark);
434 } else {
435 warning("MacWindowManager::setMenuItemCheckMark: wm doesn't have menu");
436 }
437 }
438
setMenuItemEnabled(const Common::String & menuId,const Common::String & itemId,bool enabled)439 void MacWindowManager::setMenuItemEnabled(const Common::String &menuId, const Common::String &itemId, bool enabled) {
440 if (_menu) {
441 _menu->setEnabled(menuId, itemId, enabled);
442 } else {
443 warning("MacWindowManager::setMenuItemEnabled: wm doesn't have menu");
444 }
445 }
446
setMenuItemName(const Common::String & menuId,const Common::String & itemId,const Common::String & name)447 void MacWindowManager::setMenuItemName(const Common::String &menuId, const Common::String &itemId, const Common::String &name) {
448 if (_menu) {
449 _menu->setName(menuId, itemId, name);
450 } else {
451 warning("MacWindowManager::setMenuItemName: wm doesn't have menu");
452 }
453 }
454
setMenuItemCheckMark(int menuId,int itemId,bool checkMark)455 void MacWindowManager::setMenuItemCheckMark(int menuId, int itemId, bool checkMark) {
456 if (_menu) {
457 _menu->setCheckMark(menuId, itemId, checkMark);
458 } else {
459 warning("MacWindowManager::setMenuItemCheckMark: wm doesn't have menu");
460 }
461 }
462
setMenuItemEnabled(int menuId,int itemId,bool enabled)463 void MacWindowManager::setMenuItemEnabled(int menuId, int itemId, bool enabled) {
464 if (_menu) {
465 _menu->setEnabled(menuId, itemId, enabled);
466 } else {
467 warning("MacWindowManager::setMenuItemEnabled: wm doesn't have menu");
468 }
469 }
470
setMenuItemName(int menuId,int itemId,const Common::String & name)471 void MacWindowManager::setMenuItemName(int menuId, int itemId, const Common::String &name) {
472 if (_menu) {
473 _menu->setName(menuId, itemId, name);
474 } else {
475 warning("MacWindowManager::setMenuItemName: wm doesn't have menu");
476 }
477 }
478
setMenuItemAction(const Common::String & menuId,const Common::String & itemId,int actionId)479 void MacWindowManager::setMenuItemAction(const Common::String &menuId, const Common::String &itemId, int actionId) {
480 if (_menu) {
481 _menu->setAction(menuId, itemId, actionId);
482 } else {
483 warning("MacWindowManager::setMenuItemAction: wm doesn't have menu");
484 }
485 }
486
setMenuItemAction(int menuId,int itemId,int actionId)487 void MacWindowManager::setMenuItemAction(int menuId, int itemId, int actionId) {
488 if (_menu) {
489 _menu->setAction(menuId, itemId, actionId);
490 } else {
491 warning("MacWindowManager::setMenuItemAction: wm doesn't have menu");
492 }
493 }
494
getMenuItemCheckMark(const Common::String & menuId,const Common::String & itemId)495 bool MacWindowManager::getMenuItemCheckMark(const Common::String &menuId, const Common::String &itemId) {
496 if (_menu) {
497 return _menu->getCheckMark(menuId, itemId);
498 } else {
499 warning("MacWindowManager::getMenuItemCheckMark: wm doesn't have menu");
500 return false;
501 }
502 }
503
getMenuItemCheckMark(int menuId,int itemId)504 bool MacWindowManager::getMenuItemCheckMark(int menuId, int itemId) {
505 if (_menu) {
506 return _menu->getCheckMark(menuId, itemId);
507 } else {
508 warning("MacWindowManager::getMenuItemCheckMark: wm doesn't have menu");
509 return false;
510 }
511 }
512
getMenuItemEnabled(const Common::String & menuId,const Common::String & itemId)513 bool MacWindowManager::getMenuItemEnabled(const Common::String &menuId, const Common::String &itemId) {
514 if (_menu) {
515 return _menu->getEnabled(menuId, itemId);
516 } else {
517 warning("MacWindowManager::getMenuItemEnabled: wm doesn't have menu");
518 return false;
519 }
520 }
521
getMenuItemEnabled(int menuId,int itemId)522 bool MacWindowManager::getMenuItemEnabled(int menuId, int itemId) {
523 if (_menu) {
524 return _menu->getEnabled(menuId, itemId);
525 } else {
526 warning("MacWindowManager::getMenuItemEnabled: wm doesn't have menu");
527 return false;
528 }
529 }
530
getMenuItemName(const Common::String & menuId,const Common::String & itemId)531 Common::String MacWindowManager::getMenuItemName(const Common::String &menuId, const Common::String &itemId) {
532 if (_menu) {
533 return _menu->getName(menuId, itemId);
534 } else {
535 warning("MacWindowManager::getMenuItemName: wm doesn't have menu");
536 return Common::String();
537 }
538 }
539
getMenuItemName(int menuId,int itemId)540 Common::String MacWindowManager::getMenuItemName(int menuId, int itemId) {
541 if (_menu) {
542 return _menu->getName(menuId, itemId);
543 } else {
544 warning("MacWindowManager::getMenuItemName: wm doesn't have menu");
545 return Common::String();
546 }
547 }
548
getMenuItemAction(const Common::String & menuId,const Common::String & itemId)549 int MacWindowManager::getMenuItemAction(const Common::String &menuId, const Common::String &itemId) {
550 if (_menu) {
551 return _menu->getAction(menuId, itemId);
552 } else {
553 warning("MacWindowManager::getMenuItemAction: wm doesn't have menu");
554 return 0;
555 }
556 }
557
getMenuItemAction(int menuId,int itemId)558 int MacWindowManager::getMenuItemAction(int menuId, int itemId) {
559 if (_menu) {
560 return _menu->getAction(menuId, itemId);
561 } else {
562 warning("MacWindowManager::getMenuItemAction: wm doesn't have menu");
563 return 0;
564 }
565 }
566
567 // this is refer to how we deal U32String in splitString in mactext
568 // maybe we can optimize this specifically
stripFormat(const Common::U32String & str)569 Common::U32String stripFormat(const Common::U32String &str) {
570 Common::U32String res, paragraph, tmp;
571 // calc the size of str
572 const Common::U32String::value_type *l = str.c_str();
573 while (*l) {
574 // split paragraph first
575 paragraph.clear();
576 while (*l) {
577 if (*l == '\r') {
578 l++;
579 if (*l == '\n')
580 l++;
581 break;
582 }
583 if (*l == '\n') {
584 l++;
585 break;
586 }
587 paragraph += *l++;
588 }
589 const Common::U32String::value_type *s = paragraph.c_str();
590 tmp.clear();
591 while (*s) {
592 if (*s == '\001') {
593 s++;
594 // if there are two \001, then we regard it as one character
595 if (*s == '\001') {
596 tmp += *s++;
597 }
598 } else if (*s == '\015') { // binary format
599 // we are skipping the formatting stuffs
600 // this number 12, and the number 23, is the size of our format
601 s += 12;
602 } else if (*s == '\016') { // human-readable format
603 s += 23;
604 } else {
605 tmp += *s++;
606 }
607 }
608 res += tmp;
609 if (*l)
610 res += '\n';
611 }
612 return res;
613 }
614
setTextInClipboard(const Common::U32String & str)615 void MacWindowManager::setTextInClipboard(const Common::U32String &str) {
616 _clipboard = str;
617 g_system->setTextInClipboard(stripFormat(str));
618 }
619
620 // get the text size ignoring \n
getPureTextSize(const Common::U32String & str,bool global)621 int getPureTextSize(const Common::U32String &str, bool global) {
622 const Common::U32String::value_type *l = str.c_str();
623 int res = 0;
624 if (global) {
625 // if we are in global, then we have no format in str. thus, we ignore all \r \n
626 while (*l) {
627 if (*l != '\n' && *l != '\r')
628 res++;
629 l++;
630 }
631 } else {
632 // if we are not in global, then we are using the wm clipboard, which use \n for new line
633 // i think that if statement can be optimized to, like if (*l != '\n' && (!global || *l != '\r'))
634 // but for the sake of readability, we keep codes here
635 while (*l) {
636 if (*l != '\n')
637 res++;
638 l++;
639 }
640 }
641 return res;
642 }
643
getTextFromClipboard(const Common::U32String & format,int * size)644 Common::U32String MacWindowManager::getTextFromClipboard(const Common::U32String &format, int *size) {
645 Common::U32String global_str = g_system->getTextFromClipboard();
646 // str is what we need
647 Common::U32String str;
648 if (_clipboard.empty()) {
649 // if wm clipboard is empty, then we use the global clipboard, which won't contain the format
650 str = format + global_str;
651 if (size)
652 *size = getPureTextSize(global_str, true);
653 } else {
654 Common::U32String tmp = stripFormat(_clipboard);
655 if (tmp == global_str) {
656 // if the text is equal, then we use wm one which contains the format
657 str = _clipboard;
658 if (size)
659 *size = getPureTextSize(tmp, false);
660 } else {
661 // otherwise, we prefer the global one
662 str = format + global_str;
663 if (size)
664 *size = getPureTextSize(global_str, true);
665 }
666 }
667 return str;
668 }
669
isMenuActive()670 bool MacWindowManager::isMenuActive() {
671 if (!_menu)
672 return false;
673
674 return _menu->isVisible();
675 }
676
setActiveWindow(int id)677 void MacWindowManager::setActiveWindow(int id) {
678 if (_activeWindow == id)
679 return;
680
681 if (_activeWindow != -1)
682 _windows[_activeWindow]->setActive(false);
683
684 _activeWindow = id;
685
686 _windows[id]->setActive(true);
687
688 _windowStack.remove(_windows[id]);
689 _windowStack.push_back(_windows[id]);
690
691 _fullRefresh = true;
692 }
693
removeWindow(MacWindow * target)694 void MacWindowManager::removeWindow(MacWindow *target) {
695 _windowsToRemove.push_back(target);
696 _needsRemoval = true;
697 _hoveredWidget = nullptr;
698
699 if (target->getId() == _activeWindow)
700 _activeWindow = -1;
701 }
702
703 template<typename T>
macDrawPixel(int x,int y,int color,void * data)704 void macDrawPixel(int x, int y, int color, void *data) {
705 MacPlotData *p = (MacPlotData *)data;
706
707 if (p->fillType > p->patterns->size() || !p->fillType)
708 return;
709
710 byte *pat = p->patterns->operator[](p->fillType - 1);
711
712 if (p->thickness == 1) {
713 if (x >= 0 && x < p->surface->w && y >= 0 && y < p->surface->h) {
714 uint xu = (uint)x; // for letting compiler optimize it
715 uint yu = (uint)y;
716
717 *((T)p->surface->getBasePtr(xu, yu)) = p->invert ? ~(*((T)p->surface->getBasePtr(xu, yu))) :
718 (pat[(yu - p->fillOriginY) % 8] & (1 << (7 - (xu - p->fillOriginX) % 8))) ? color : p->bgColor;
719
720 if (p->mask)
721 *((T)p->mask->getBasePtr(xu, yu)) = 0xff;
722 }
723 } else {
724 int x1 = x;
725 int x2 = x1 + p->thickness;
726 int y1 = y;
727 int y2 = y1 + p->thickness;
728
729 for (y = y1; y < y2; y++)
730 for (x = x1; x < x2; x++)
731 if (x >= 0 && x < p->surface->w && y >= 0 && y < p->surface->h) {
732 uint xu = (uint)x; // for letting compiler optimize it
733 uint yu = (uint)y;
734 *((T)p->surface->getBasePtr(xu, yu)) = p->invert ? ~(*((T)p->surface->getBasePtr(xu, yu))) :
735 (pat[(yu - p->fillOriginY) % 8] & (1 << (7 - (xu - p->fillOriginX) % 8))) ? color : p->bgColor;
736
737 if (p->mask)
738 *((T)p->mask->getBasePtr(xu, yu)) = 0xff;
739 }
740 }
741 }
742
macDrawInvertPixel(int x,int y,int color,void * data)743 void macDrawInvertPixel(int x, int y, int color, void *data) {
744 MacPlotData *p = (MacPlotData *)data;
745
746 if (p->fillType > p->patterns->size() || !p->fillType)
747 return;
748
749 if (x >= 0 && x < p->surface->w && y >= 0 && y < p->surface->h) {
750 uint xu = (uint)x; // for letting compiler optimize it
751 uint yu = (uint)y;
752
753 byte cur_color = *((byte *)p->surface->getBasePtr(xu, yu));
754 // 0 represent black in default palette, and 4 represent white
755 // if color is black, we invert it to white, otherwise, we invert it to black
756 byte invert_color = 0;
757 if (cur_color == 0) {
758 invert_color = 4;
759 }
760 *((byte *)p->surface->getBasePtr(xu, yu)) = invert_color;
761
762 if (p->mask)
763 *((byte *)p->mask->getBasePtr(xu, yu)) = 0xff;
764 }
765 }
766
getDrawPixel()767 MacDrawPixPtr MacWindowManager::getDrawPixel() {
768 if (_pixelformat.bytesPerPixel == 1)
769 return &macDrawPixel<byte *>;
770 else
771 return &macDrawPixel<uint32 *>;
772 }
773
774 // get the function of drawing invert pixel for default palette
getDrawInvertPixel()775 MacDrawPixPtr MacWindowManager::getDrawInvertPixel() {
776 if (_pixelformat.bytesPerPixel == 1)
777 return &macDrawInvertPixel;
778 warning("function of drawing invert pixel for default palette has not implemented yet");
779 return nullptr;
780 }
781
loadDesktop()782 void MacWindowManager::loadDesktop() {
783 Common::SeekableReadStream *file = getFile("scummvm_background.bmp");
784 if (!file)
785 return;
786
787 Image::BitmapDecoder bmpDecoder;
788 Graphics::Surface *source;
789 _desktopBmp = new Graphics::TransparentSurface();
790
791 bmpDecoder.loadStream(*file);
792 source = bmpDecoder.getSurface()->convertTo(_desktopBmp->getSupportedPixelFormat(), bmpDecoder.getPalette());
793
794 _desktopBmp->copyFrom(*source);
795
796 delete file;
797 source->free();
798 delete source;
799 }
800
drawDesktop()801 void MacWindowManager::drawDesktop() {
802 if (_desktopBmp) {
803 for (int i = 0; i < _desktop->w; ++i) {
804 for (int j = 0; j < _desktop->h; ++j) {
805 uint32 color = *(uint32 *)_desktopBmp->getBasePtr(i % _desktopBmp->w, j % _desktopBmp->h);
806 if (_pixelformat.bytesPerPixel == 1) {
807 byte r, g, b;
808 _desktopBmp->format.colorToRGB(color, r, g, b);
809 if (color > 0) {
810 *((byte *)_desktop->getBasePtr(i, j)) = findBestColor(r, g, b);
811 }
812 } else {
813 *((uint32 *)_desktop->getBasePtr(i, j)) = color;
814 }
815 }
816 }
817 } else {
818 Common::Rect r(_desktop->getBounds());
819
820 MacPlotData pd(_desktop, nullptr, &_patterns, kPatternCheckers, 0, 0, 1, _colorWhite);
821
822 Graphics::drawRoundRect(r, kDesktopArc, _colorBlack, true, getDrawPixel(), &pd);
823 }
824 }
825
draw()826 void MacWindowManager::draw() {
827 removeMarked();
828
829 Common::Rect bounds = getScreenBounds();
830
831 if (_fullRefresh) {
832 if (!(_mode & kWMModeNoDesktop)) {
833 Common::Rect screen = getScreenBounds();
834 if (_desktop->w != screen.width() || _desktop->h != screen.height()) {
835 _desktop->free();
836 _desktop->create(screen.width(), screen.height(), _pixelformat);
837 drawDesktop();
838 }
839
840 if (_screen) {
841 _screen->blitFrom(*_desktop, Common::Point(0, 0));
842 g_system->copyRectToScreen(_screen->getPixels(), _screen->pitch, 0, 0, _screen->w, _screen->h);
843 } else {
844 _screenCopyPauseToken = new PauseToken(pauseEngine());
845 g_system->copyRectToScreen(_desktop->getPixels(), _desktop->pitch, 0, 0, _desktop->w, _desktop->h);
846 }
847 }
848 if (_redrawEngineCallback != nullptr)
849 _redrawEngineCallback(_engineR);
850 }
851
852 Common::Array<Common::Rect> dirtyRects;
853 for (Common::List<BaseMacWindow *>::const_iterator it = _windowStack.begin(); it != _windowStack.end(); it++) {
854 BaseMacWindow *w = *it;
855 if (!w->isVisible())
856 continue;
857
858 Common::Rect clip = w->getInnerDimensions();
859 clip.clip(bounds);
860
861 if (clip.isEmpty())
862 continue;
863
864 clip = w->getDimensions();
865 clip.clip(bounds);
866
867 if (clip.isEmpty())
868 continue;
869
870 bool forceRedraw = _fullRefresh;
871 if (!forceRedraw && dirtyRects.size()) {
872 for (Common::Array<Common::Rect>::iterator dirty = dirtyRects.begin(); dirty != dirtyRects.end(); dirty++) {
873 if (clip.intersects(*dirty)) {
874 forceRedraw = true;
875 break;
876 }
877 }
878 }
879
880 if (!_screen) {
881 if (w->isDirty() || forceRedraw) {
882 w->draw(forceRedraw);
883
884 Common::Rect outerDims = w->getDimensions();
885 Common::Rect innerDims = w->getInnerDimensions();
886 int adjWidth, adjHeight;
887
888 if (w->isDirty() || forceRedraw) {
889 w->draw(forceRedraw);
890
891 adjustDimensions(clip, outerDims, adjWidth, adjHeight);
892
893 if (_pixelformat.bytesPerPixel == 1) {
894 Surface *surface = g_system->lockScreen();
895 ManagedSurface *border = w->getBorderSurface();
896
897 for (int y = 0; y < adjHeight; y++) {
898 const byte *src = (const byte *)border->getBasePtr(clip.left - outerDims.left, y);
899 byte *dst = (byte *)surface->getBasePtr(clip.left, y + clip.top);
900 for (int x = 0; x < adjWidth; x++, src++, dst++)
901 if (*src != _colorGreen2 && *src != _colorGreen)
902 *dst = *src;
903 }
904
905 g_system->unlockScreen();
906 } else {
907 g_system->copyRectToScreen(w->getBorderSurface()->getBasePtr(MAX(clip.left - outerDims.left, 0), MAX(clip.top - outerDims.top, 0)), w->getBorderSurface()->pitch, clip.left, clip.top, adjWidth, adjHeight);
908 }
909 }
910
911 adjustDimensions(clip, innerDims, adjWidth, adjHeight);
912 g_system->copyRectToScreen(w->getWindowSurface()->getBasePtr(MAX(clip.left - innerDims.left, 0), MAX(clip.top - innerDims.top, 0)), w->getWindowSurface()->pitch,MAX(innerDims.left, (int16)0), MAX(innerDims.top, (int16)0), adjWidth, adjHeight);
913
914 dirtyRects.push_back(clip);
915 }
916
917 if (_screenCopyPauseToken) {
918 _screenCopyPauseToken->clear();
919 delete _screenCopyPauseToken;
920 _screenCopyPauseToken = nullptr;
921 }
922 } else if (w->draw(_screen, forceRedraw)) {
923 w->setDirty(false);
924 g_system->copyRectToScreen(_screen->getBasePtr(clip.left, clip.top), _screen->pitch, clip.left, clip.top, clip.width(), clip.height());
925 dirtyRects.push_back(clip);
926 }
927 }
928
929 // Menu is drawn on top of everything and always
930 if (_menu && !(_mode & kWMModeFullscreen)) {
931 if (_fullRefresh)
932 _menu->draw(_screen, _fullRefresh);
933 else {
934 // add intersection check with menu
935 bool menuRedraw = false;
936 for (Common::Array<Common::Rect>::iterator dirty = dirtyRects.begin(); dirty != dirtyRects.end(); dirty++) {
937 if (_menu->checkIntersects(*dirty)) {
938 menuRedraw = true;
939 break;
940 }
941 }
942 _menu->draw(_screen, menuRedraw);
943 }
944 }
945
946 _fullRefresh = false;
947 }
948
menuTimerHandler(void * refCon)949 static void menuTimerHandler(void *refCon) {
950 MacWindowManager *wm = (MacWindowManager *)refCon;
951
952 if (wm->_menuHotzone.contains(wm->_lastMousePos)) {
953 wm->activateMenu();
954 }
955
956 wm->_menuTimerActive = false;
957
958 g_system->getTimerManager()->removeTimerProc(&menuTimerHandler);
959 }
960
processEvent(Common::Event & event)961 bool MacWindowManager::processEvent(Common::Event &event) {
962 switch (event.type) {
963 case Common::EVENT_MOUSEMOVE:
964 _lastMousePos = event.mouse;
965 break;
966 case Common::EVENT_LBUTTONDOWN:
967 _mouseDown = true;
968 _lastClickPos = event.mouse;
969 break;
970 case Common::EVENT_LBUTTONUP:
971 _mouseDown = false;
972 break;
973 default:
974 break;
975 }
976
977 if (_menu && !_menu->isVisible()) {
978 if ((_mode & kWMModeAutohideMenu) && event.type == Common::EVENT_MOUSEMOVE) {
979 if (!_menuTimerActive && _menuHotzone.contains(event.mouse)) {
980 _menuTimerActive = true;
981
982 g_system->getTimerManager()->installTimerProc(&menuTimerHandler, _menuDelay, this, "menuWindowCursor");
983 }
984 }
985 }
986
987 // Menu gets events first for shortcuts and menu bar
988 if (_menu && _menu->processEvent(event))
989 return true;
990
991 if (_activeWindow != -1) {
992 if ((_windows[_activeWindow]->isEditable() && _windows[_activeWindow]->getType() == kWindowWindow &&
993 ((MacWindow *)_windows[_activeWindow])->getInnerDimensions().contains(event.mouse.x, event.mouse.y)) ||
994 (_activeWidget && _activeWidget->isEditable() &&
995 _activeWidget->getDimensions().contains(event.mouse.x, event.mouse.y))) {
996 if (getCursorType() != kMacCursorBeam) {
997 _tempType = getCursorType();
998 _inEditableArea = true;
999 replaceCursor(kMacCursorBeam);
1000 }
1001 } else {
1002 // here, we use _inEditableArea is distinguish whether the current Beam cursor is set by director or ourself
1003 // if we are not in the editable area but we are drawing the Beam cursor, then the cursor is set by director, thus we don't replace it
1004 if (getCursorType() == kMacCursorBeam && _inEditableArea) {
1005 replaceCursor(_tempType, _cursor);
1006 _inEditableArea = false;
1007 }
1008 }
1009 }
1010
1011 for (Common::List<BaseMacWindow *>::const_iterator it = _windowStack.end(); it != _windowStack.begin();) {
1012 it--;
1013 BaseMacWindow *w = *it;
1014
1015 if (w->hasAllFocus() || (w->isEditable() && event.type == Common::EVENT_KEYDOWN) ||
1016 w->getDimensions().contains(event.mouse.x, event.mouse.y)) {
1017 if (event.type == Common::EVENT_LBUTTONDOWN || event.type == Common::EVENT_LBUTTONUP)
1018 setActiveWindow(w->getId());
1019
1020 return w->processEvent(event);
1021 }
1022 }
1023
1024 return false;
1025 }
1026
adjustDimensions(const Common::Rect & clip,const Common::Rect & dims,int & adjWidth,int & adjHeight)1027 void MacWindowManager::adjustDimensions(const Common::Rect &clip, const Common::Rect &dims, int &adjWidth, int &adjHeight) {
1028 int wOffset, hOffset;
1029
1030 wOffset = clip.left - dims.left;
1031 adjWidth = dims.width();
1032 if (wOffset > 0) {
1033 adjWidth -= wOffset;
1034 } else if (dims.right > getScreenBounds().right) {
1035 adjWidth -= (dims.right - getScreenBounds().right);
1036 }
1037
1038 hOffset = clip.top - dims.top;
1039 adjHeight = dims.height();
1040 if (hOffset > 0) {
1041 adjHeight -= hOffset;
1042 } else if (dims.bottom > getScreenBounds().bottom) {
1043 adjHeight -= (dims.bottom - getScreenBounds().bottom);
1044 }
1045 }
1046
removeMarked()1047 void MacWindowManager::removeMarked() {
1048 if (!_needsRemoval) return;
1049
1050 Common::List<BaseMacWindow *>::const_iterator it;
1051 for (it = _windowsToRemove.begin(); it != _windowsToRemove.end(); it++) {
1052 removeFromStack(*it);
1053 removeFromWindowList(*it);
1054 delete *it;
1055 _activeWindow = -1;
1056 _fullRefresh = true;
1057 }
1058 _windowsToRemove.clear();
1059 _needsRemoval = false;
1060
1061 // Do we need compact lastid?
1062 _lastId = 0;
1063 for (Common::HashMap<uint, BaseMacWindow *>::iterator lit = _windows.begin(); lit != _windows.end(); lit++) {
1064 if (lit->_key >= (uint)_lastId)
1065 _lastId = lit->_key + 1;
1066 }
1067 }
1068
removeFromStack(BaseMacWindow * target)1069 void MacWindowManager::removeFromStack(BaseMacWindow *target) {
1070 Common::List<BaseMacWindow *>::iterator stackIt;
1071 for (stackIt = _windowStack.begin(); stackIt != _windowStack.end(); stackIt++) {
1072 if (*stackIt == target) {
1073 stackIt = _windowStack.erase(stackIt);
1074 stackIt--;
1075 }
1076 }
1077 }
1078
removeFromWindowList(BaseMacWindow * target)1079 void MacWindowManager::removeFromWindowList(BaseMacWindow *target) {
1080 // _windows.erase(target->getId()); // Is applicable?
1081 for (Common::HashMap<uint, BaseMacWindow *>::iterator it = _windows.begin(); it != _windows.end(); it++) {
1082 if (it->_value == target) {
1083 _windows.erase(it);
1084 break;
1085 }
1086 }
1087 }
1088
1089
addZoomBox(ZoomBox * box)1090 void MacWindowManager::addZoomBox(ZoomBox *box) {
1091 _zoomBoxes.push_back(box);
1092 }
1093
renderZoomBox(bool redraw)1094 void MacWindowManager::renderZoomBox(bool redraw) {
1095 if (!_zoomBoxes.size())
1096 return;
1097
1098 ZoomBox *box = _zoomBoxes.front();
1099 uint32 t = g_system->getMillis();
1100
1101 MacPlotData pd(_screen, nullptr, &getPatterns(), Graphics::kPatternCheckers, 0, 0, 1, 0, true);
1102
1103 // Undraw the previous boxes
1104 if (box->last.size() != 0) {
1105 for (uint i = 0; i < box->last.size(); i++) {
1106 Common::Rect r = box->last.remove_at(i);
1107 zoomBoxInner(r, pd);
1108 }
1109 }
1110
1111 if (box->nextTime > t)
1112 return;
1113
1114 const int numSteps = 14;
1115 // We have 15 steps in total, and we have flying rectange
1116 // from switching 3/4 frames
1117
1118 int start, end;
1119 // Determine, how many rectangles and what are their numbers
1120 if (box->step <= 5) {
1121 start = 1;
1122 end = box->step - 1;
1123 } else {
1124 start = box->step - 4;
1125 end = MIN(start + 3 - box->step % 2, 7);
1126 }
1127
1128 for (int i = start; i <= end; i++) {
1129 Common::Rect r(box->start.left + (box->end.left - box->start.left) * i / 8,
1130 box->start.top + (box->end.top - box->start.top) * i / 8,
1131 box->start.right + (box->end.right - box->start.right) * i / 8,
1132 box->start.bottom + (box->end.bottom - box->start.bottom) * i / 8);
1133
1134 zoomBoxInner(r, pd);
1135 box->last.push_back(r);
1136 }
1137
1138 box->step++;
1139 box->nextTime = box->startTime + 1000 * box->step * box->delay / 60;
1140
1141 if (redraw) {
1142 g_system->copyRectToScreen(_screen->getPixels(), _screen->pitch, 0, 0, _screen->getBounds().width(), _screen->getBounds().height()); // zoomBox
1143 }
1144
1145 if (box->step >= numSteps) {
1146 delete _zoomBoxes[0];
1147 _zoomBoxes.remove_at(0);
1148 }
1149 }
1150
zoomBoxInner(Common::Rect & r,Graphics::MacPlotData & pd)1151 void MacWindowManager::zoomBoxInner(Common::Rect &r, Graphics::MacPlotData &pd) {
1152 Graphics::drawLine(r.left, r.top, r.right, r.top, 0xff, getDrawPixel(), &pd);
1153 Graphics::drawLine(r.right, r.top, r.right, r.bottom, 0xff, getDrawPixel(), &pd);
1154 Graphics::drawLine(r.left, r.bottom, r.right, r.bottom, 0xff, getDrawPixel(), &pd);
1155 Graphics::drawLine(r.left, r.top, r.left, r.bottom, 0xff, getDrawPixel(), &pd);
1156 }
1157
1158 /////////////////
1159 // Cursor stuff
1160 /////////////////
replaceCursorType(MacCursorType type)1161 void MacWindowManager::replaceCursorType(MacCursorType type) {
1162 if (_cursorTypeStack.empty())
1163 _cursorTypeStack.push(type);
1164 else
1165 _cursorTypeStack.top() = type;
1166 }
1167
getCursorType() const1168 MacCursorType MacWindowManager::getCursorType() const {
1169 if (_cursorTypeStack.empty())
1170 return kMacCursorOff;
1171
1172 return _cursorTypeStack.top();
1173 }
1174
pushCursor(MacCursorType type,Cursor * cursor)1175 void MacWindowManager::pushCursor(MacCursorType type, Cursor *cursor) {
1176 switch (type) {
1177 case kMacCursorOff:
1178 CursorMan.pushCursor(nullptr, 0, 0, 0, 0, 0);
1179 CursorMan.pushCursorPalette(cursorPalette, 0, 2);
1180 break;
1181 case kMacCursorArrow:
1182 CursorMan.pushCursor(macCursorArrow, 11, 16, 1, 1, 3);
1183 CursorMan.pushCursorPalette(cursorPalette, 0, 2);
1184 break;
1185 case kMacCursorBeam:
1186 CursorMan.pushCursor(macCursorBeam, 11, 16, 1, 1, 3);
1187 CursorMan.pushCursorPalette(cursorPalette, 0, 2);
1188 break;
1189 case kMacCursorCrossHair:
1190 CursorMan.pushCursor(macCursorCrossHair, 11, 16, 1, 1, 3);
1191 CursorMan.pushCursorPalette(cursorPalette, 0, 2);
1192 break;
1193 case kMacCursorCrossBar:
1194 CursorMan.pushCursor(macCursorCrossBar, 11, 16, 1, 1, 3);
1195 CursorMan.pushCursorPalette(cursorPalette, 0, 2);
1196 break;
1197 case kMacCursorWatch:
1198 CursorMan.pushCursor(macCursorWatch, 11, 16, 1, 1, 3);
1199 CursorMan.pushCursorPalette(cursorPalette, 0, 2);
1200 break;
1201 case kMacCursorCustom:
1202 if (!cursor) {
1203 warning("MacWindowManager::pushCursor(): Custom cursor signified but not provided");
1204 return;
1205 }
1206
1207 pushCustomCursor(cursor);
1208 }
1209
1210 _cursorTypeStack.push(type);
1211 }
1212
replaceCursor(MacCursorType type,Cursor * cursor)1213 void MacWindowManager::replaceCursor(MacCursorType type, Cursor *cursor) {
1214 switch (type) {
1215 case kMacCursorOff:
1216 CursorMan.replaceCursor(nullptr, 0, 0, 0, 0, 0);
1217 CursorMan.replaceCursorPalette(cursorPalette, 0, 2);
1218 break;
1219 case kMacCursorArrow:
1220 CursorMan.replaceCursor(macCursorArrow, 11, 16, 1, 1, 3);
1221 CursorMan.replaceCursorPalette(cursorPalette, 0, 2);
1222 break;
1223 case kMacCursorBeam:
1224 CursorMan.replaceCursor(macCursorBeam, 11, 16, 1, 1, 3);
1225 CursorMan.replaceCursorPalette(cursorPalette, 0, 2);
1226 break;
1227 case kMacCursorCrossHair:
1228 CursorMan.replaceCursor(macCursorCrossHair, 11, 16, 1, 1, 3);
1229 CursorMan.replaceCursorPalette(cursorPalette, 0, 2);
1230 break;
1231 case kMacCursorCrossBar:
1232 CursorMan.replaceCursor(macCursorCrossBar, 11, 16, 1, 1, 3);
1233 CursorMan.replaceCursorPalette(cursorPalette, 0, 2);
1234 break;
1235 case kMacCursorWatch:
1236 CursorMan.replaceCursor(macCursorWatch, 11, 16, 1, 1, 3);
1237 CursorMan.replaceCursorPalette(cursorPalette, 0, 2);
1238 break;
1239 case kMacCursorCustom:
1240 if (!cursor) {
1241 warning("MacWindowManager::replaceCursor(): Custom cursor signified but not provided");
1242 return;
1243 }
1244
1245 CursorMan.replaceCursor(cursor);
1246 break;
1247 }
1248
1249 replaceCursorType(type);
1250 }
1251
pushCustomCursor(const byte * data,int w,int h,int hx,int hy,int transcolor)1252 void MacWindowManager::pushCustomCursor(const byte *data, int w, int h, int hx, int hy, int transcolor) {
1253 CursorMan.pushCursor(data, w, h, hx, hy, transcolor);
1254 CursorMan.pushCursorPalette(cursorPalette, 0, 2);
1255 _cursorTypeStack.push(kMacCursorCustom);
1256 }
1257
replaceCustomCursor(const byte * data,int w,int h,int hx,int hy,int transcolor)1258 void MacWindowManager::replaceCustomCursor(const byte *data, int w, int h, int hx, int hy, int transcolor) {
1259 CursorMan.replaceCursor(data, w, h, hx, hy, transcolor);
1260 CursorMan.replaceCursorPalette(cursorPalette, 0, 2);
1261 replaceCursorType(kMacCursorCustom);
1262 }
1263
pushCustomCursor(const Graphics::Cursor * cursor)1264 void MacWindowManager::pushCustomCursor(const Graphics::Cursor *cursor) {
1265 CursorMan.pushCursor(cursor->getSurface(), cursor->getWidth(), cursor->getHeight(), cursor->getHotspotX(),
1266 cursor->getHotspotY(), cursor->getKeyColor());
1267
1268 if (cursor->getPalette())
1269 CursorMan.pushCursorPalette(cursor->getPalette(), cursor->getPaletteStartIndex(), cursor->getPaletteCount());
1270 else
1271 CursorMan.pushCursorPalette(cursorPalette, 0, 2);
1272
1273 _cursorTypeStack.push(kMacCursorCustom);
1274 }
1275
popCursor()1276 void MacWindowManager::popCursor() {
1277 CursorMan.popCursor();
1278 CursorMan.popCursorPalette();
1279 _cursorTypeStack.pop();
1280 }
1281
1282 ///////////////////
1283 // Palette stuff
1284 ///////////////////
1285 #define LOOKUPCOLOR(x) _color ## x = findBestColor(palette[kColor ## x * 3], palette[kColor ## x * 3 + 1], palette[kColor ## x * 3 + 2]);
1286
passPalette(const byte * pal,uint size)1287 void MacWindowManager::passPalette(const byte *pal, uint size) {
1288 if (_palette)
1289 free(_palette);
1290
1291 if (size) {
1292 _palette = (byte *)malloc(size * 3);
1293 memcpy(_palette, pal, size * 3);
1294 }
1295 _paletteSize = size;
1296
1297 _colorHash.clear();
1298 _invertColorHash.clear();
1299
1300 LOOKUPCOLOR(White);
1301 LOOKUPCOLOR(Gray80);
1302 LOOKUPCOLOR(Gray88);
1303 LOOKUPCOLOR(GrayEE);
1304 LOOKUPCOLOR(Black);
1305 LOOKUPCOLOR(Green);
1306 LOOKUPCOLOR(Green2);
1307
1308 drawDesktop();
1309 setFullRefresh(true);
1310 }
1311
findBestColor(uint32 color)1312 uint MacWindowManager::findBestColor(uint32 color) {
1313 byte r, g, b;
1314 decomposeColor(color, r, g, b);
1315 return findBestColor(r, g, b);
1316 }
1317
findBestColor(byte cr,byte cg,byte cb)1318 uint MacWindowManager::findBestColor(byte cr, byte cg, byte cb) {
1319 if (_pixelformat.bytesPerPixel == 4)
1320 return _pixelformat.RGBToColor(cr, cg, cb);
1321
1322 uint bestColor = 0;
1323 double min = 0xFFFFFFFF;
1324
1325 uint32 color = cr << 16 | cg << 8 | cb;
1326
1327 if (_colorHash.contains(color))
1328 return _colorHash[color];
1329
1330 for (uint i = 0; i < _paletteSize; ++i) {
1331 int rmean = (*(_palette + 3 * i + 0) + cr) / 2;
1332 int r = *(_palette + 3 * i + 0) - cr;
1333 int g = *(_palette + 3 * i + 1) - cg;
1334 int b = *(_palette + 3 * i + 2) - cb;
1335
1336 double dist = sqrt((((512 + rmean) * r * r) >> 8) + 4 * g * g + (((767 - rmean) * b * b) >> 8));
1337 if (min > dist) {
1338 bestColor = i;
1339 min = dist;
1340 }
1341 }
1342
1343 _colorHash[color] = bestColor;
1344
1345 return bestColor;
1346 }
1347
decomposeColor(uint32 color,byte & r,byte & g,byte & b)1348 void MacWindowManager::decomposeColor(uint32 color, byte &r, byte &g, byte &b) {
1349 if (_pixelformat.bytesPerPixel == 1 || color <= 0xff) {
1350 r = *(_palette + 3 * color + 0);
1351 g = *(_palette + 3 * color + 1);
1352 b = *(_palette + 3 * color + 2);
1353 } else {
1354 _pixelformat.colorToRGB(color, r, g, b);
1355 }
1356 }
1357
inverter(uint src)1358 uint MacWindowManager::inverter(uint src) {
1359 if (_invertColorHash.contains(src))
1360 return _invertColorHash[src];
1361
1362 if (_pixelformat.bytesPerPixel == 1) {
1363 byte r, g, b;
1364 decomposeColor(src, r, g, b);
1365 r = ~r;
1366 g = ~g;
1367 b = ~b;
1368 _invertColorHash[src] = findBestColor(r, g, b);
1369 } else {
1370 uint32 alpha = _pixelformat.ARGBToColor(255, 0, 0, 0);
1371 _invertColorHash[src] = ~(src & ~alpha) | alpha;
1372 }
1373 return _invertColorHash[src];
1374 }
1375
pauseEngine()1376 PauseToken MacWindowManager::pauseEngine() {
1377 return _engineP->pauseEngine();
1378 }
1379
setEngine(Engine * engine)1380 void MacWindowManager::setEngine(Engine *engine) {
1381 _engineP = engine;
1382 }
1383
setEngineRedrawCallback(void * engine,void (* redrawCallback)(void *))1384 void MacWindowManager::setEngineRedrawCallback(void *engine, void (*redrawCallback)(void *)) {
1385 _engineR = engine;
1386 _redrawEngineCallback = redrawCallback;
1387 }
1388
1389 } // End of namespace Graphics
1390