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 	if (buf) {
69 		g_system->setMouseCursor(cur->_data, w, h, hotspotX, hotspotY, keycolor, dontScale, format);
70 	}
71 }
72 
popCursor()73 void CursorManager::popCursor() {
74 	if (_cursorStack.empty())
75 		return;
76 
77 	Cursor *cur = _cursorStack.pop();
78 	delete cur;
79 
80 	if (!_cursorStack.empty()) {
81 		cur = _cursorStack.top();
82 		g_system->setMouseCursor(cur->_data, cur->_width, cur->_height, cur->_hotspotX, cur->_hotspotY, cur->_keycolor, cur->_dontScale, &cur->_format);
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->showMouse(isVisible());
103 }
104 
replaceCursor(const void * buf,uint w,uint h,int hotspotX,int hotspotY,uint32 keycolor,bool dontScale,const Graphics::PixelFormat * format)105 void CursorManager::replaceCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format) {
106 
107 	if (_cursorStack.empty()) {
108 		pushCursor(buf, w, h, hotspotX, hotspotY, keycolor, dontScale, format);
109 		return;
110 	}
111 
112 	Cursor *cur = _cursorStack.top();
113 
114 #ifdef USE_RGB_COLOR
115 	uint size;
116 	if (!format)
117 		size = w * h;
118 	else
119 		size = w * h * format->bytesPerPixel;
120 #else
121 	uint size = w * h;
122 #endif
123 
124 	if (cur->_size < size) {
125 		delete[] cur->_data;
126 		cur->_data = new byte[size];
127 		cur->_size = size;
128 	}
129 
130 	if (buf && cur->_data)
131 		memcpy(cur->_data, buf, size);
132 
133 	cur->_width = w;
134 	cur->_height = h;
135 	cur->_hotspotX = hotspotX;
136 	cur->_hotspotY = hotspotY;
137 	cur->_keycolor = keycolor;
138 	cur->_dontScale = dontScale;
139 #ifdef USE_RGB_COLOR
140 	if (format)
141 		cur->_format = *format;
142 	else
143 		cur->_format = Graphics::PixelFormat::createFormatCLUT8();
144 #endif
145 
146 	g_system->setMouseCursor(cur->_data, w, h, hotspotX, hotspotY, keycolor, dontScale, format);
147 }
148 
supportsCursorPalettes()149 bool CursorManager::supportsCursorPalettes() {
150 	return g_system->hasFeature(OSystem::kFeatureCursorPalette);
151 }
152 
disableCursorPalette(bool disable)153 void CursorManager::disableCursorPalette(bool disable) {
154 	if (!g_system->hasFeature(OSystem::kFeatureCursorPalette))
155 		return;
156 
157 	if (_cursorPaletteStack.empty())
158 		return;
159 
160 	Palette *pal = _cursorPaletteStack.top();
161 	pal->_disabled = disable;
162 
163 	g_system->setFeatureState(OSystem::kFeatureCursorPalette, !disable);
164 }
165 
pushCursorPalette(const byte * colors,uint start,uint num)166 void CursorManager::pushCursorPalette(const byte *colors, uint start, uint num) {
167 	if (!g_system->hasFeature(OSystem::kFeatureCursorPalette))
168 		return;
169 
170 	Palette *pal = new Palette(colors, start, num);
171 	_cursorPaletteStack.push(pal);
172 
173 	if (num)
174 		g_system->setCursorPalette(colors, start, num);
175 	else
176 		g_system->setFeatureState(OSystem::kFeatureCursorPalette, false);
177 }
178 
popCursorPalette()179 void CursorManager::popCursorPalette() {
180 	if (!g_system->hasFeature(OSystem::kFeatureCursorPalette))
181 		return;
182 
183 	if (_cursorPaletteStack.empty())
184 		return;
185 
186 	Palette *pal = _cursorPaletteStack.pop();
187 	delete pal;
188 
189 	if (_cursorPaletteStack.empty()) {
190 		g_system->setFeatureState(OSystem::kFeatureCursorPalette, false);
191 		return;
192 	}
193 
194 	pal = _cursorPaletteStack.top();
195 
196 	if (pal->_num && !pal->_disabled)
197 		g_system->setCursorPalette(pal->_data, pal->_start, pal->_num);
198 	else
199 		g_system->setFeatureState(OSystem::kFeatureCursorPalette, false);
200 }
201 
replaceCursorPalette(const byte * colors,uint start,uint num)202 void CursorManager::replaceCursorPalette(const byte *colors, uint start, uint num) {
203 	if (!g_system->hasFeature(OSystem::kFeatureCursorPalette))
204 		return;
205 
206 	if (_cursorPaletteStack.empty()) {
207 		pushCursorPalette(colors, start, num);
208 		return;
209 	}
210 
211 	Palette *pal = _cursorPaletteStack.top();
212 	uint size = 3 * num;
213 
214 	if (pal->_size < size) {
215 		// Could not re-use the old buffer. Create a new one.
216 		delete[] pal->_data;
217 		pal->_data = new byte[size];
218 		pal->_size = size;
219 	}
220 
221 	pal->_start = start;
222 	pal->_num = num;
223 
224 	if (num) {
225 		memcpy(pal->_data, colors, size);
226 		g_system->setCursorPalette(pal->_data, pal->_start, pal->_num);
227 	} else {
228 		g_system->setFeatureState(OSystem::kFeatureCursorPalette, false);
229 	}
230 }
231 
lock(bool locked)232 void CursorManager::lock(bool locked) {
233 	_locked = locked;
234 }
235 
Cursor(const void * data,uint w,uint h,int hotspotX,int hotspotY,uint32 keycolor,bool dontScale,const Graphics::PixelFormat * format)236 CursorManager::Cursor::Cursor(const void *data, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format) {
237 #ifdef USE_RGB_COLOR
238 	if (!format)
239 		_format = Graphics::PixelFormat::createFormatCLUT8();
240 	 else
241 		_format = *format;
242 	_size = w * h * _format.bytesPerPixel;
243 	_keycolor = keycolor & ((1 << (_format.bytesPerPixel << 3)) - 1);
244 #else
245 	_format = Graphics::PixelFormat::createFormatCLUT8();
246 	_size = w * h;
247 	_keycolor = keycolor & 0xFF;
248 #endif
249 	_data = new byte[_size];
250 	if (data && _data)
251 		memcpy(_data, data, _size);
252 	_width = w;
253 	_height = h;
254 	_hotspotX = hotspotX;
255 	_hotspotY = hotspotY;
256 	_dontScale = dontScale;
257 	_visible = false;
258 }
259 
~Cursor()260 CursorManager::Cursor::~Cursor() {
261 	delete[] _data;
262 }
263 
Palette(const byte * colors,uint start,uint num)264 CursorManager::Palette::Palette(const byte *colors, uint start, uint num) {
265 	_start = start;
266 	_num = num;
267 	_size = 3 * num;
268 
269 	if (num) {
270 		_data = new byte[_size];
271 		memcpy(_data, colors, _size);
272 	} else {
273 		_data = NULL;
274 	}
275 
276 	_disabled = false;
277 }
278 
~Palette()279 CursorManager::Palette::~Palette() {
280 	delete[] _data;
281 }
282 
283 } // End of namespace Graphics
284