Skip to content

Commit 8f9b2be

Browse files
author
Torbjörn Andersson
committed
SCUMM: Improve Mac "beam" cursor handling
The beam cursor should be drawn inverted. ScummVM does not have support for such cursors as far as I know (except maybe in the OpenGL backend?) so we draw it manually. I still need to deal gracefully with colors other than black and white, because it's possible to drag the cursor outside the dialog window while pressing the mouse button to select text.
1 parent 82ddb70 commit 8f9b2be

File tree

2 files changed

+138
-24
lines changed

2 files changed

+138
-24
lines changed

engines/scumm/gfx_mac.cpp

Lines changed: 124 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -561,16 +561,6 @@ MacGui::MacEditText::MacEditText(MacGui::MacDialogWindow *window, Common::Rect b
561561
_textSurface = _window->innerSurface()->getSubArea(textBounds);
562562
}
563563

564-
Graphics::MacGUIConstants::MacCursorType MacGui::MacEditText::getCursorType() const {
565-
// If the widget is found, that implies that it's active.
566-
567-
// Note: The text widget in the Indy 3 save dialog does not change the
568-
// cursor in the original. But since we're not going to emulate it
569-
// that closely, I don't think we need to mark this as an enhancement.
570-
571-
return Graphics::MacGUIConstants::kMacCursorBeam;
572-
}
573-
574564
bool MacGui::MacEditText::findWidget(int x, int y) const {
575565
if (!_visible || !_enabled)
576566
return false;
@@ -786,8 +776,6 @@ bool MacGui::MacEditText::handleKeyDown(Common::Event &event) {
786776
if (event.kbd.flags & (Common::KBD_CTRL | Common::KBD_ALT | Common::KBD_META))
787777
return false;
788778

789-
CursorMan.showMouse(false);
790-
791779
switch (event.kbd.keycode) {
792780
case Common::KEYCODE_LEFT:
793781
if (_selectLen < 0) {
@@ -1033,8 +1021,8 @@ MacGui::MacDialogWindow::~MacDialogWindow() {
10331021
if (!CursorMan.isVisible())
10341022
CursorMan.showMouse(true);
10351023

1036-
if (_gui->_windowManager->getCursorType() != Graphics::MacGUIConstants::kMacCursorArrow)
1037-
_gui->_windowManager->replaceCursor(Graphics::MacGUIConstants::kMacCursorArrow);
1024+
CursorMan.showMouse(true);
1025+
_gui->_windowManager->replaceCursor(Graphics::MacGUIConstants::kMacCursorArrow);
10381026

10391027
copyToScreen(_backup);
10401028
_backup->free();
@@ -1123,6 +1111,72 @@ void MacGui::MacDialogWindow::markRectAsDirty(Common::Rect r) {
11231111
_dirtyRects.push_back(r);
11241112
}
11251113

1114+
void MacGui::MacDialogWindow::drawBeamCursor() {
1115+
int x0 = _beamCursorPos.x - _beamCursorHotspotX;
1116+
int y0 = _beamCursorPos.y - _beamCursorHotspotY;
1117+
int x1 = x0 + _beamCursor->w;
1118+
int y1 = y0 + _beamCursor->h;
1119+
1120+
_beamCursor->copyRectToSurface(*(_gui->surface()), 0, 0, Common::Rect(x0, y0, x1, y1));
1121+
1122+
const Common::Point beam[] = {
1123+
Common::Point(0, 0), Common::Point(1, 0), Common::Point(5, 0),
1124+
Common::Point(6, 0), Common::Point(2, 1), Common::Point(4, 1),
1125+
Common::Point(3, 2), Common::Point(3, 3), Common::Point(3, 4),
1126+
Common::Point(3, 5), Common::Point(3, 6), Common::Point(3, 7),
1127+
Common::Point(3, 8), Common::Point(3, 9), Common::Point(3, 10),
1128+
Common::Point(3, 11), Common::Point(3, 12), Common::Point(3, 13),
1129+
Common::Point(2, 14), Common::Point(4, 14), Common::Point(0, 15),
1130+
Common::Point(1, 15), Common::Point(5, 15), Common::Point(6, 15)
1131+
};
1132+
1133+
for (int i = 0; i < ARRAYSIZE(beam); i++) {
1134+
uint32 color = _beamCursor->getPixel(beam[i].x, beam[i].y);
1135+
1136+
if (color == kBlack)
1137+
color = kWhite;
1138+
else
1139+
color = kBlack;
1140+
1141+
_beamCursor->setPixel(beam[i].x, beam[i].y, color);
1142+
}
1143+
1144+
int srcX = 0;
1145+
int srcY = 0;
1146+
1147+
if (x0 < 0) {
1148+
srcX = -x0;
1149+
x0 = 0;
1150+
}
1151+
1152+
x1 = MIN(x1, 640);
1153+
1154+
if (y0 < 0) {
1155+
srcY = -y0;
1156+
y0 = 0;
1157+
}
1158+
1159+
y1 = MIN(y1, 400);
1160+
1161+
_system->copyRectToScreen(_beamCursor->getBasePtr(srcX, srcY), _beamCursor->pitch, x0, y0, x1 - x0, y1 - y0);
1162+
}
1163+
1164+
void MacGui::MacDialogWindow::undrawBeamCursor() {
1165+
int x0 = _beamCursorPos.x - _beamCursorHotspotX;
1166+
int y0 = _beamCursorPos.y - _beamCursorHotspotY;
1167+
int x1 = x0 + _beamCursor->w;
1168+
int y1 = y0 + _beamCursor->h;
1169+
1170+
x0 = MAX(x0, 0);
1171+
x1 = MIN(x1, 640);
1172+
y0 = MAX(y0, 0);
1173+
y1 = MIN(y1, 400);
1174+
1175+
Graphics::Surface *screen = _gui->surface();
1176+
1177+
_system->copyRectToScreen(screen->getBasePtr(x0, y0), screen->pitch, x0, y0, x1 - x0, y1 - y0);
1178+
}
1179+
11261180
void MacGui::MacDialogWindow::update(bool fullRedraw) {
11271181
for (uint i = 0; i < _widgets.size(); i++)
11281182
_widgets[i]->draw();
@@ -1141,6 +1195,12 @@ void MacGui::MacDialogWindow::update(bool fullRedraw) {
11411195
}
11421196

11431197
_dirtyRects.clear();
1198+
1199+
if (_beamCursor) {
1200+
undrawBeamCursor();
1201+
_beamCursorPos = _realMousePos;
1202+
drawBeamCursor();
1203+
}
11441204
}
11451205

11461206
void MacGui::MacDialogWindow::fillPattern(Common::Rect r, uint16 pattern) {
@@ -1180,6 +1240,9 @@ int MacGui::MacDialogWindow::runDialog() {
11801240

11811241
while (_system->getEventManager()->pollEvent(event)) {
11821242
if (Common::isMouseEvent(event)) {
1243+
_realMousePos.x = event.mouse.x;
1244+
_realMousePos.y = event.mouse.y;
1245+
11831246
event.mouse.x -= (_bounds.left + _margin);
11841247
event.mouse.y -= (_bounds.top + _margin);
11851248

@@ -1212,8 +1275,8 @@ int MacGui::MacDialogWindow::runDialog() {
12121275
break;
12131276

12141277
case Common::EVENT_MOUSEMOVE:
1215-
if (!CursorMan.isVisible())
1216-
CursorMan.showMouse(true);
1278+
if (_beamCursor && !_beamCursorVisible)
1279+
_beamCursorVisible = true;
12171280

12181281
if (_focusedWidget) {
12191282
if (_focusedWidget->findWidget(_oldMousePos.x, _oldMousePos.y) != _focusedWidget->findWidget(_mousePos.x, _mousePos.y)) {
@@ -1223,12 +1286,24 @@ int MacGui::MacDialogWindow::runDialog() {
12231286
_focusedWidget->handleMouseMove(event);
12241287
} else {
12251288
int mouseOverWidget = findWidget(_mousePos.x, _mousePos.y);
1226-
Graphics::MacGUIConstants::MacCursorType cursorType = (mouseOverWidget >= 0) ? _widgets[mouseOverWidget]->getCursorType() : Graphics::MacGUIConstants::kMacCursorArrow;
12271289

1228-
if (_gui->_windowManager->getCursorType() != cursorType)
1229-
_gui->_windowManager->replaceCursor(cursorType);
1290+
bool useBeamCursor = (mouseOverWidget >= 0 && _widgets[mouseOverWidget]->useBeamCursor());
1291+
1292+
if (useBeamCursor && !_beamCursor) {
1293+
CursorMan.showMouse(false);
1294+
_beamCursor = new Graphics::Surface();
1295+
_beamCursor->create(7, 16, Graphics::PixelFormat::createFormatCLUT8());
1296+
_beamCursorVisible = true;
1297+
_beamCursorPos = _realMousePos;
1298+
} else if (!useBeamCursor && _beamCursor) {
1299+
CursorMan.showMouse(true);
1300+
undrawBeamCursor();
1301+
_beamCursor->free();
1302+
delete _beamCursor;
1303+
_beamCursor = nullptr;
1304+
_beamCursorVisible = false;
1305+
}
12301306
}
1231-
12321307
break;
12331308

12341309
case Common::EVENT_KEYDOWN:
@@ -1259,6 +1334,8 @@ int MacGui::MacDialogWindow::runDialog() {
12591334
// to key presses.
12601335
for (uint i = 0; i < _widgets.size(); i++) {
12611336
if (_widgets[i]->handleKeyDown(event)) {
1337+
if (_beamCursor)
1338+
_beamCursorVisible = true;
12621339
_widgets[i]->setRedraw();
12631340
break;
12641341
}
@@ -1593,13 +1670,39 @@ Graphics::Surface *MacGui::loadPict(int id) {
15931670
// The palette doesn't match the game's palette at all, so remap
15941671
// the colors to the custom area of the palette. It's assumed that
15951672
// only one such picture will be loaded at a time.
1673+
//
1674+
// But we still match black and white to 0 and 15 to make sure they
1675+
// mach exactly.
1676+
1677+
int black = -1;
1678+
int white = -1;
1679+
1680+
for (int i = 0; i < pict.getPaletteColorCount(); i++) {
1681+
int r = palette[3 * i];
1682+
int g = palette[3 * i + 1];
1683+
int b = palette[3 * i + 2];
1684+
1685+
if (r == 0 && g == 0 && b == 0)
1686+
black = i;
1687+
else if (r == 255 && g == 255 && b == 255)
1688+
white = i;
1689+
}
15961690

15971691
if (palette) {
15981692
_system->getPaletteManager()->setPalette(palette, kCustomColor, pict.getPaletteColorCount());
15991693

16001694
for (int y = 0; y < s->h; y++) {
16011695
for (int x = 0; x < s->w; x++) {
1602-
s->setPixel(x, y, kCustomColor + s1->getPixel(x, y));
1696+
int color = s1->getPixel(x, y);
1697+
1698+
if (color == black)
1699+
color = kBlack;
1700+
else if (color == white)
1701+
color = kWhite;
1702+
else
1703+
color = kCustomColor + color;
1704+
1705+
s->setPixel(x, y, color);
16031706
}
16041707
}
16051708
} else

engines/scumm/gfx_mac.h

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
#define SCUMM_GFX_MAC_H
2424

2525
#include "graphics/font.h"
26-
#include "graphics/macgui/macwindowmanager.h"
2726

2827
class OSystem;
2928

@@ -181,7 +180,7 @@ class MacGui {
181180
virtual void setValue(int value);
182181
int getValue() const { return _value; }
183182

184-
virtual Graphics::MacGUIConstants::MacCursorType getCursorType() const { return Graphics::MacGUIConstants::kMacCursorArrow; }
183+
virtual bool useBeamCursor() { return false; }
185184
virtual bool findWidget(int x, int y) const;
186185

187186
virtual void draw(bool drawFocused = false) = 0;
@@ -257,7 +256,7 @@ class MacGui {
257256
public:
258257
MacEditText(MacGui::MacDialogWindow *window, Common::Rect bounds, Common::String text, bool enabled);
259258

260-
Graphics::MacGUIConstants::MacCursorType getCursorType() const;
259+
bool useBeamCursor() { return true; }
261260
bool findWidget(int x, int y) const;
262261

263262
void draw(bool drawFocused = false);
@@ -317,6 +316,15 @@ class MacGui {
317316

318317
bool _visible = false;
319318

319+
Graphics::Surface *_beamCursor = nullptr;
320+
Common::Point _beamCursorPos;
321+
bool _beamCursorVisible = false;
322+
int _beamCursorHotspotX = 3;
323+
int _beamCursorHotspotY = 4;
324+
325+
void drawBeamCursor();
326+
void undrawBeamCursor();
327+
320328
PauseToken _pauseToken;
321329

322330
Graphics::Surface *_from = nullptr;
@@ -333,6 +341,7 @@ class MacGui {
333341
Common::Point _focusClick;
334342
Common::Point _oldMousePos;
335343
Common::Point _mousePos;
344+
Common::Point _realMousePos;
336345

337346
Common::StringArray _substitutions;
338347
Common::Array<Common::Rect> _dirtyRects;
@@ -401,6 +410,8 @@ class MacGui {
401410
MacGui(ScummEngine *vm, Common::String resourceFile);
402411
virtual ~MacGui();
403412

413+
Graphics::Surface *surface() { return _surface; }
414+
404415
virtual const Common::String name() const = 0;
405416

406417
virtual bool handleEvent(Common::Event &event);

0 commit comments

Comments
 (0)