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
23 #include "graphics/cursorman.h"
24
25 #include "common/system.h"
26 #include "common/stack.h"
27
28 namespace Common {
29 DECLARE_SINGLETON(Graphics::CursorManager);
30 }
31
32 namespace Graphics {
33
~CursorManager()34 CursorManager::~CursorManager() {
35 for (Common::Stack<Cursor *>::size_type i = 0; i < _cursorStack.size(); ++i)
36 delete _cursorStack[i];
37 _cursorStack.clear();
38 for (Common::Stack<Palette *>::size_type i = 0; i < _cursorPaletteStack.size(); ++i)
39 delete _cursorPaletteStack[i];
40 _cursorPaletteStack.clear();
41 }
42
isVisible()43 bool CursorManager::isVisible() {
44 if (_cursorStack.empty())
45 return false;
46 return _cursorStack.top()->_visible;
47 }
48
showMouse(bool visible)49 bool CursorManager::showMouse(bool visible) {
50 if (_cursorStack.empty())
51 return false;
52 if (_locked) {
53 return false;
54 }
55
56 _cursorStack.top()->_visible = visible;
57
58 // Should work, even if there's just a dummy cursor on the stack.
59 return g_system->showMouse(visible);
60 }
61
pushCursor(const void * buf,uint w,uint h,int hotspotX,int hotspotY,uint32 keycolor,bool dontScale,const Graphics::PixelFormat * format)62 void CursorManager::pushCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format) {
63 Cursor *cur = new Cursor(buf, w, h, hotspotX, hotspotY, keycolor, dontScale, format);
64
65 cur->_visible = isVisible();
66 _cursorStack.push(cur);
67
68 g_system->setMouseCursor(cur->_data, w, h, hotspotX, hotspotY, keycolor, dontScale, format);
69 }
70
popCursor()71 void CursorManager::popCursor() {
72 if (_cursorStack.empty())
73 return;
74
75 Cursor *cur = _cursorStack.pop();
76 delete cur;
77
78 if (!_cursorStack.empty()) {
79 cur = _cursorStack.top();
80 g_system->setMouseCursor(cur->_data, cur->_width, cur->_height, cur->_hotspotX, cur->_hotspotY, cur->_keycolor, cur->_dontScale, &cur->_format);
81 } else {
82 g_system->setMouseCursor(nullptr, 0, 0, 0, 0, 0);
83 }
84
85 g_system->showMouse(isVisible());
86 }
87
88
popAllCursors()89 void CursorManager::popAllCursors() {
90 while (!_cursorStack.empty()) {
91 Cursor *cur = _cursorStack.pop();
92 delete cur;
93 }
94
95 if (g_system->hasFeature(OSystem::kFeatureCursorPalette)) {
96 while (!_cursorPaletteStack.empty()) {
97 Palette *pal = _cursorPaletteStack.pop();
98 delete pal;
99 }
100 }
101
102 g_system->setMouseCursor(nullptr, 0, 0, 0, 0, 0);
103 g_system->showMouse(isVisible());
104 }
105
replaceCursor(const void * buf,uint w,uint h,int hotspotX,int hotspotY,uint32 keycolor,bool dontScale,const Graphics::PixelFormat * format)106 void CursorManager::replaceCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format) {
107
108 if (_cursorStack.empty()) {
109 pushCursor(buf, w, h, hotspotX, hotspotY, keycolor, dontScale, format);
110 return;
111 }
112
113 Cursor *cur = _cursorStack.top();
114
115 #ifdef USE_RGB_COLOR
116 uint size;
117 if (!format)
118 size = w * h;
119 else
120 size = w * h * format->bytesPerPixel;
121 #else
122 uint size = w * h;
123 #endif
124
125 if (cur->_size < size) {
126 delete[] cur->_data;
127 cur->_data = new byte[size];
128 cur->_size = size;
129 }
130
131 if (buf && cur->_data)
132 memcpy(cur->_data, buf, size);
133
134 cur->_width = w;
135 cur->_height = h;
136 cur->_hotspotX = hotspotX;
137 cur->_hotspotY = hotspotY;
138 cur->_keycolor = keycolor;
139 cur->_dontScale = dontScale;
140 #ifdef USE_RGB_COLOR
141 if (format)
142 cur->_format = *format;
143 else
144 cur->_format = Graphics::PixelFormat::createFormatCLUT8();
145 #endif
146
147 g_system->setMouseCursor(cur->_data, w, h, hotspotX, hotspotY, keycolor, dontScale, format);
148 }
149
replaceCursor(const Graphics::Cursor * cursor)150 void CursorManager::replaceCursor(const Graphics::Cursor *cursor) {
151 replaceCursor(cursor->getSurface(), cursor->getWidth(), cursor->getHeight(), cursor->getHotspotX(),
152 cursor->getHotspotY(), cursor->getKeyColor());
153
154 if (cursor->getPalette())
155 replaceCursorPalette(cursor->getPalette(), cursor->getPaletteStartIndex(), cursor->getPaletteCount());
156 }
157
supportsCursorPalettes()158 bool CursorManager::supportsCursorPalettes() {
159 return g_system->hasFeature(OSystem::kFeatureCursorPalette);
160 }
161
disableCursorPalette(bool disable)162 void CursorManager::disableCursorPalette(bool disable) {
163 if (!g_system->hasFeature(OSystem::kFeatureCursorPalette))
164 return;
165
166 if (_cursorPaletteStack.empty())
167 return;
168
169 Palette *pal = _cursorPaletteStack.top();
170 pal->_disabled = disable;
171
172 g_system->setFeatureState(OSystem::kFeatureCursorPalette, !disable);
173 }
174
pushCursorPalette(const byte * colors,uint start,uint num)175 void CursorManager::pushCursorPalette(const byte *colors, uint start, uint num) {
176 if (!g_system->hasFeature(OSystem::kFeatureCursorPalette))
177 return;
178
179 Palette *pal = new Palette(colors, start, num);
180 _cursorPaletteStack.push(pal);
181
182 if (num)
183 g_system->setCursorPalette(colors, start, num);
184 else
185 g_system->setFeatureState(OSystem::kFeatureCursorPalette, false);
186 }
187
popCursorPalette()188 void CursorManager::popCursorPalette() {
189 if (!g_system->hasFeature(OSystem::kFeatureCursorPalette))
190 return;
191
192 if (_cursorPaletteStack.empty())
193 return;
194
195 Palette *pal = _cursorPaletteStack.pop();
196 delete pal;
197
198 if (_cursorPaletteStack.empty()) {
199 g_system->setFeatureState(OSystem::kFeatureCursorPalette, false);
200 return;
201 }
202
203 pal = _cursorPaletteStack.top();
204
205 if (pal->_num && !pal->_disabled)
206 g_system->setCursorPalette(pal->_data, pal->_start, pal->_num);
207 else
208 g_system->setFeatureState(OSystem::kFeatureCursorPalette, false);
209 }
210
replaceCursorPalette(const byte * colors,uint start,uint num)211 void CursorManager::replaceCursorPalette(const byte *colors, uint start, uint num) {
212 if (!g_system->hasFeature(OSystem::kFeatureCursorPalette))
213 return;
214
215 if (_cursorPaletteStack.empty()) {
216 pushCursorPalette(colors, start, num);
217 return;
218 }
219
220 Palette *pal = _cursorPaletteStack.top();
221 uint size = 3 * num;
222
223 if (pal->_size < size) {
224 // Could not re-use the old buffer. Create a new one.
225 delete[] pal->_data;
226 pal->_data = new byte[size];
227 pal->_size = size;
228 }
229
230 pal->_start = start;
231 pal->_num = num;
232
233 if (num) {
234 memcpy(pal->_data, colors, size);
235 g_system->setCursorPalette(pal->_data, pal->_start, pal->_num);
236 } else {
237 g_system->setFeatureState(OSystem::kFeatureCursorPalette, false);
238 }
239 }
240
lock(bool locked)241 void CursorManager::lock(bool locked) {
242 _locked = locked;
243 }
244
Cursor(const void * data,uint w,uint h,int hotspotX,int hotspotY,uint32 keycolor,bool dontScale,const Graphics::PixelFormat * format)245 CursorManager::Cursor::Cursor(const void *data, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format) {
246 #ifdef USE_RGB_COLOR
247 if (!format)
248 _format = Graphics::PixelFormat::createFormatCLUT8();
249 else
250 _format = *format;
251 _size = w * h * _format.bytesPerPixel;
252 _keycolor = keycolor & ((1 << (_format.bytesPerPixel << 3)) - 1);
253 #else
254 _format = Graphics::PixelFormat::createFormatCLUT8();
255 _size = w * h;
256 _keycolor = keycolor & 0xFF;
257 #endif
258 _data = new byte[_size];
259 if (data && _data)
260 memcpy(_data, data, _size);
261 _width = w;
262 _height = h;
263 _hotspotX = hotspotX;
264 _hotspotY = hotspotY;
265 _dontScale = dontScale;
266 _visible = false;
267 }
268
~Cursor()269 CursorManager::Cursor::~Cursor() {
270 delete[] _data;
271 }
272
Palette(const byte * colors,uint start,uint num)273 CursorManager::Palette::Palette(const byte *colors, uint start, uint num) {
274 _start = start;
275 _num = num;
276 _size = 3 * num;
277
278 if (num) {
279 _data = new byte[_size];
280 memcpy(_data, colors, _size);
281 } else {
282 _data = NULL;
283 }
284
285 _disabled = false;
286 }
287
~Palette()288 CursorManager::Palette::~Palette() {
289 delete[] _data;
290 }
291
292 } // End of namespace Graphics
293