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  * Based on the original sources
23  *   Faery Tale II -- The Halls of the Dead
24  *   (c) 1993-1996 The Wyrmkeep Entertainment Co.
25  */
26 
27 #include "saga2/saga2.h"
28 #include "saga2/fta.h"
29 #include "saga2/hresmgr.h"
30 #include "saga2/button.h"
31 #include "saga2/objects.h"
32 #include "saga2/fontlib.h"
33 
34 namespace Saga2 {
35 
36 typedef void *pVOID;
37 typedef pVOID apVOID[];
38 
39 extern void playMemSound(uint32 s); // play click # s
40 
41 /* ======================================================================= *
42     Compressed image class
43  * ======================================================================= */
44 
init(void)45 void GfxCompImage::init(void) {
46 	_compImages      = NULL;
47 	_max             = 0;
48 	_min             = 0;
49 	_internalAlloc   = false;
50 	_currentImage    = 0;
51 	_numPtrAlloc     = 0;
52 	_textFont        = &Onyx10Font;  // default
53 }
54 
GfxCompImage(gPanelList & list,const Rect16 & box,void * image,uint16 ident,AppFunc * cmd)55 GfxCompImage::GfxCompImage(gPanelList &list, const Rect16 &box, void *image, uint16 ident,
56                        AppFunc *cmd) : gControl(list, box, NULL, ident, cmd) {
57 	// setup a single image configuration
58 
59 	init();
60 
61 	if (image) {
62 		_compImages = (void **)malloc(sizeof(pVOID) * 1); // allocate room for one pointer
63 		_compImages[0] = image;
64 		_internalAlloc   = false;
65 		_numPtrAlloc     = 1;
66 	}
67 }
68 
GfxCompImage(gPanelList & list,const Rect16 & box,uint32 contextID,char a,char b,char c,uint16 resNum,uint16 numImages,uint16 ident,AppFunc * cmd)69 GfxCompImage::GfxCompImage(gPanelList &list,
70                        const Rect16 &box,
71                        uint32 contextID,
72                        char a, char b, char c,
73                        uint16 resNum, uint16 numImages,
74                        uint16 ident,
75                        AppFunc *cmd) : gControl(list, box, NULL, ident, cmd) {
76 	uint16 i, rNum;
77 
78 	init();
79 
80 	// init the resource context handle
81 	hResContext *resContext = resFile->newContext(contextID, "container window resource");
82 
83 	// setup for a numImages image configuration
84 	_compImages = (void **)malloc(sizeof(void *)*numImages);  // allocate room for numImages pointers
85 
86 	for (i = 0, rNum = resNum; i < numImages; i++, rNum++) {
87 		_compImages[i] = LoadResource(resContext,
88 		                               MKTAG(a, b, c, rNum),
89 		                               " GfxCompImage ");
90 	}
91 
92 	_max             = numImages - 1;
93 	_internalAlloc   = true;
94 	_numPtrAlloc     = numImages;
95 
96 	// get rid of this context
97 	resFile->disposeContext(resContext);
98 	resContext = NULL;
99 }
100 
GfxCompImage(gPanelList & list,const Rect16 & box,void * image,const char * text,textPallete & pal,uint16 ident,AppFunc * cmd)101 GfxCompImage::GfxCompImage(gPanelList &list, const Rect16 &box, void *image, const char *text, textPallete &pal, uint16 ident,
102                        AppFunc *cmd) : gControl(list, box, text, ident, cmd) {
103 	// setup a single image configuration
104 	init();
105 
106 	if (!image)
107 		return;
108 
109 	_compImages = (void **)malloc(sizeof(void *) * 1); // allocate room for one pointer
110 
111 	_compImages[0] = image;
112 	_max             = 0;
113 	_numPtrAlloc     = 1;
114 	title           = text;
115 	_textFont        = &Onyx10Font;  // >>> this should be dynamic
116 	_textPal         = pal;
117 }
118 
GfxCompImage(gPanelList & list,const Rect16 & box,void ** images,int16 numRes,int16 initial,uint16 ident,AppFunc * cmd)119 GfxCompImage::GfxCompImage(gPanelList &list, const Rect16 &box, void **images,
120                        int16 numRes, int16 initial,
121                        uint16 ident, AppFunc *cmd) : gControl(list, box, NULL, ident, cmd) {
122 	init();
123 
124 	if (!images)
125 		return;
126 
127 	_compImages      = images;
128 
129 	// set up limits
130 	_max             = numRes - 1;
131 	_currentImage    = clamp(_min, initial, _max);
132 }
133 
GfxCompImage(gPanelList & list,const Rect16 & box,void ** images,int16 numRes,int16 initial,const char * text,textPallete & pal,uint16 ident,AppFunc * cmd)134 GfxCompImage::GfxCompImage(gPanelList &list, const Rect16 &box, void **images,
135                        int16 numRes, int16 initial, const char *text, textPallete &pal,
136                        uint16 ident, AppFunc *cmd) : gControl(list, box, text, ident, cmd) {
137 	init();
138 
139 	if (images) {
140 		_compImages      = images;
141 
142 		// set up limits
143 		_max             = numRes - 1;
144 		_currentImage    = clamp(_min, initial, _max);
145 	}
146 
147 	title       = text;
148 	_textFont    = &Onyx10Font;  // >>> this should be dynamic
149 	_textPal     = pal;
150 }
151 
GfxCompImage(gPanelList & list,const StaticRect & box,void ** images,int16 numRes,int16 initial,const char * text,textPallete & pal,uint16 ident,AppFunc * cmd)152 GfxCompImage::GfxCompImage(gPanelList &list, const StaticRect &box, void **images,
153                        int16 numRes, int16 initial, const char *text, textPallete &pal,
154                        uint16 ident, AppFunc *cmd) : gControl(list, box, text, ident, cmd) {
155 	init();
156 
157 	if (images) {
158 		_compImages = images;
159 
160 		// set up limits
161 		_max          = numRes - 1;
162 		_currentImage = clamp(_min, initial, _max);
163 	}
164 
165 	title    = text;
166 	_textFont = &Onyx10Font;  // >>> this should be dynamic
167 	_textPal  = pal;
168 }
169 
170 
~GfxCompImage(void)171 GfxCompImage::~GfxCompImage(void) {
172 	// delete any allocated image pointers
173 	// for JEFFL: I took out the winklude #ifdefs becuase I belive
174 	// I fixed the problem that was causing the crash under win32
175 	// 11-14-95, I should talk to you tommorow. This is note is
176 	// a precaution
177 
178 	// if we LoadRes'ed image internally RDispose those
179 	if (_internalAlloc) {
180 		for (int16 i = 0; i < _numPtrAlloc; i++) {
181 			free(_compImages[i]);
182 		}
183 	}
184 
185 	// delete any pointer arrays new'ed
186 	if (_numPtrAlloc > 0) {
187 		free(_compImages);
188 	}
189 }
190 
pointerMove(gPanelMessage & msg)191 void GfxCompImage::pointerMove(gPanelMessage &msg) {
192 	// call the superclass's pointerMove
193 	gControl::pointerMove(msg);
194 
195 	notify(gEventMouseMove, (msg.pointerEnter ? enter : 0) | (msg.pointerLeave ? leave : 0));
196 }
197 
enable(bool abled)198 void GfxCompImage::enable(bool abled) {
199 	gPanel::enable(abled);
200 }
201 
invalidate(Rect16 *)202 void GfxCompImage::invalidate(Rect16 *) {
203 	window.update(_extent);
204 }
205 
draw(void)206 void GfxCompImage::draw(void) {
207 	gPort   &port = window.windowPort;
208 	Rect16  rect = window.getExtent();
209 
210 	SAVE_GPORT_STATE(port);                  // save pen color, etc.
211 	g_vm->_pointer->hide(port, _extent);              // hide mouse pointer
212 	drawClipped(port,
213 	            Point16(0, 0),
214 	            Rect16(0, 0, rect.width, rect.height));
215 	g_vm->_pointer->show(port, _extent);              // show mouse pointer
216 }
217 
getCurrentCompImage(void)218 void *GfxCompImage::getCurrentCompImage(void) {
219 	if (_compImages) {
220 		return _compImages[_currentImage];  // return the image pointed to by compImage
221 	} else {
222 		return NULL;
223 	}
224 }
225 
226 // waring! : the number of images has has to be == to the inital number
setImages(void ** images)227 void GfxCompImage::setImages(void **images) {
228 	if (images) {
229 		_compImages = images;
230 	}
231 }
232 
setImage(void * image)233 void GfxCompImage::setImage(void *image) {
234 	if (image) {
235 		_compImages[0] = image;
236 		_max             = 0;
237 		_currentImage    = 0;
238 	}
239 }
240 
select(uint16 val)241 void GfxCompImage::select(uint16 val) {
242 	setCurrent(val);
243 
244 	if (getEnabled()) {
245 		window.update(_extent);
246 	}
247 }
248 
select(uint16 val,const Rect16 & rect)249 void GfxCompImage::select(uint16 val, const Rect16 &rect) {
250 	select(val);
251 	setExtent(rect);
252 }
253 
setExtent(const Rect16 & rect)254 void GfxCompImage::setExtent(const Rect16 &rect) {
255 	// set the new extent
256 	_extent = rect;
257 }
258 
259 // getCurrentCompImage() is virtual function that should return
260 // the current image to be displayed (to be used across all sub-classes)
drawClipped(gPort & port,const Point16 & offset,const Rect16 & r)261 void GfxCompImage::drawClipped(gPort &port,
262                              const Point16 &offset,
263                              const Rect16 &r) {
264 	if (!_extent.overlap(r))    return;
265 
266 	SAVE_GPORT_STATE(port);
267 
268 	// get the current image
269 	void *dispImage = getCurrentCompImage();
270 
271 	// make sure the image is valid
272 	if (dispImage) {
273 		// will part of this be drawn on screen?
274 		if (_extent.overlap(r)) {
275 			// offset the image?
276 			Point16 pos(_extent.x - offset.x,
277 			            _extent.y - offset.y
278 			           );
279 			// draw the compressed image
280 			if (isGhosted()) drawCompressedImageGhosted(port, pos, dispImage);
281 			else drawCompressedImage(port, pos, dispImage);
282 
283 			// this could be modified to get the current text coloring
284 			if (title) {
285 				Rect16 textRect = _extent;
286 				textRect.x -= offset.x;
287 				textRect.y -= offset.y;
288 
289 				writePlaqText(port, textRect, _textFont, 0, _textPal, selected, title);
290 			}
291 		}
292 	}
293 }
294 
295 /* ===================================================================== *
296    GfxSpriteImage class member functions
297  * ===================================================================== */
298 
GfxSpriteImage(gPanelList & list,const Rect16 & box,GameObject * object,char,uint16 ident,AppFunc * cmd)299 GfxSpriteImage::GfxSpriteImage(gPanelList &list, const Rect16 &box, GameObject *object, char,
300                            uint16 ident, AppFunc *cmd) : GfxCompImage(list, box, NULL, ident, cmd) {
301 	// get the prototype for the object
302 	ProtoObj *proto = object->proto();
303 
304 	// assign the sprites remapped colors
305 	object->getColorTranslation(_objColors);
306 
307 	// assing the sprite pointer
308 	_sprPtr = proto->getSprite(object, ProtoObj::objInContainerView).sp;
309 }
310 
311 // getCurrentCompImage() is virtual function that should return
312 // the current image to be displayed (to be used across all sub-classes)
drawClipped(gPort & port,const Point16 & offset,const Rect16 & r)313 void GfxSpriteImage::drawClipped(gPort &port,
314                                const Point16 &offset,
315                                const Rect16 &r) {
316 	if (!_extent.overlap(r))    return;
317 
318 	SAVE_GPORT_STATE(port);
319 
320 	// if there's a sprite present
321 	gPixelMap       map;
322 
323 	//map.size = Point16( extent.height, extent.width );
324 	map.size = _sprPtr->size;
325 
326 	map.data = (uint8 *)malloc(map.bytes() * sizeof(uint8));
327 	if (map.data == NULL) return;
328 
329 	memset(map.data, 0, map.bytes());
330 
331 	//  Render the sprite into the bitmap image sequence
332 	ExpandColorMappedSprite(map, _sprPtr, _objColors);
333 
334 	port.setMode(drawModeMatte);
335 	port.bltPixels(map, 0, 0,
336 	               _extent.x - offset.x, _extent.y - offset.y,
337 	               map.size.x, map.size.y);
338 
339 	free(map.data);
340 }
341 
342 /* ===================================================================== *
343    GfxCompButton class member functions
344  * ===================================================================== */
345 
loadImages(hResContext * con,hResID res1,hResID res2)346 void GfxCompButton::loadImages(hResContext *con, hResID res1, hResID res2) {
347 	if (con) {
348 		_forImage = LoadResource(con, res1, "CBtn fore image");
349 		_resImage = LoadResource(con, res2, "CBtn res image");
350 		_dimImage    = NULL;
351 	} else {
352 		_forImage    = NULL;
353 		_resImage    = NULL;
354 		_dimImage    = NULL;
355 	}
356 
357 	_internalAlloc   = true;
358 	_dimmed          = false;
359 }
360 
loadImages(hResID contextID,hResID res1,hResID res2)361 void GfxCompButton::loadImages(hResID contextID, hResID res1, hResID res2) {
362 	// init the resource context handle
363 	hResContext *con = resFile->newContext(contextID,
364 	                                       "container window resource");
365 
366 	loadImages(con, res1, res2);
367 	resFile->disposeContext(con);               // get rid of this context
368 }
369 
GfxCompButton(gPanelList & list,const Rect16 & box,hResContext * con,hResID resID1,hResID resID2,uint16 ident,AppFunc * cmd)370 GfxCompButton::GfxCompButton(gPanelList &list, const Rect16 &box, hResContext *con, hResID resID1, hResID resID2, uint16 ident,
371                          AppFunc *cmd) : GfxCompImage(list, box, NULL, ident, cmd), _extent(box) {
372 	loadImages(con, resID1, resID2);
373 }
374 
GfxCompButton(gPanelList & list,const Rect16 & box,hResID contextID,hResID resID1,hResID resID2,uint16 ident,AppFunc * cmd)375 GfxCompButton::GfxCompButton(gPanelList &list, const Rect16 &box, hResID contextID, hResID resID1, hResID resID2, uint16 ident,
376                          AppFunc *cmd) : GfxCompImage(list, box, NULL, ident, cmd), _extent(box) {
377 	loadImages(contextID, resID1, resID2);
378 }
379 
GfxCompButton(gPanelList & list,const Rect16 & box,hResContext * con,char a,char b,char c,int16 butNum_1,int16 butNum_2,uint16 ident,AppFunc * cmd)380 GfxCompButton::GfxCompButton(gPanelList &list, const Rect16 &box, hResContext *con, char a, char b, char c, int16 butNum_1, int16 butNum_2, uint16 ident,
381                          AppFunc *cmd) : GfxCompImage(list, box, NULL, ident, cmd), _extent(box) {
382 	loadImages(con, MKTAG(a, b, c, butNum_1), MKTAG(a, b, c, butNum_2));
383 }
384 
GfxCompButton(gPanelList & list,const Rect16 & box,hResID contextID,char a,char b,char c,int16 butNum_1,int16 butNum_2,uint16 ident,AppFunc * cmd)385 GfxCompButton::GfxCompButton(gPanelList &list, const Rect16 &box, hResID contextID, char a, char b, char c, int16 butNum_1, int16 butNum_2, uint16 ident,
386                          AppFunc *cmd) : GfxCompImage(list, box, NULL, ident, cmd), _extent(box) {
387 	loadImages(contextID, MKTAG(a, b, c, butNum_1), MKTAG(a, b, c, butNum_2));
388 }
389 
GfxCompButton(gPanelList & list,const Rect16 & box,hResContext * con,int16 butNum,uint16 ident,AppFunc * cmd)390 GfxCompButton::GfxCompButton(gPanelList &list, const Rect16 &box, hResContext *con, int16 butNum, uint16 ident,
391                          AppFunc *cmd) : GfxCompImage(list, box, NULL, ident, cmd), _extent(box) {
392 	loadImages(con, MKTAG('B', 'T', 'N', butNum), MKTAG('B', 'T', 'N', butNum + 1));
393 }
394 
GfxCompButton(gPanelList & list,const Rect16 & box,void ** images,int16 numRes,uint16 ident,AppFunc * cmd)395 GfxCompButton::GfxCompButton(gPanelList &list, const Rect16 &box, void **images, int16 numRes, uint16 ident,
396                          AppFunc *cmd) : GfxCompImage(list, box, NULL, ident, cmd) {
397 	if (images[0] && images[1] && numRes == 2) {
398 		_forImage    = images[0];
399 		_resImage    = images[1];
400 		_dimImage    = NULL;
401 	} else {
402 		_forImage    = NULL;
403 		_resImage    = NULL;
404 		_dimImage    = NULL;
405 	}
406 
407 	_internalAlloc   = false;
408 	_dimmed          = false;
409 	_extent          = box;
410 }
411 
GfxCompButton(gPanelList & list,const Rect16 & box,void ** images,int16 numRes,const char * text,textPallete & pal,uint16 ident,AppFunc * cmd)412 GfxCompButton::GfxCompButton(gPanelList &list, const Rect16 &box, void **images, int16 numRes, const char *text, textPallete &pal, uint16 ident,
413                          AppFunc *cmd) : GfxCompImage(list, box, NULL, 0, 0, text, pal, ident, cmd) {
414 	if (images[0] && images[1] && numRes == 2) {
415 		_forImage    = images[0];
416 		_resImage    = images[1];
417 		_dimImage    = NULL;
418 	} else {
419 		_forImage    = NULL;
420 		_resImage    = NULL;
421 		_dimImage    = NULL;
422 	}
423 
424 	_internalAlloc   = false;
425 	_dimmed          = false;
426 	_extent          = box;
427 }
428 
GfxCompButton(gPanelList & list,const Rect16 & box,void ** images,int16 numRes,void * newDimImage,bool dimNess,uint16 ident,AppFunc * cmd)429 GfxCompButton::GfxCompButton(gPanelList &list, const Rect16 &box, void **images, int16 numRes, void *newDimImage, bool dimNess, uint16 ident,
430                          AppFunc *cmd) : GfxCompImage(list, box, NULL, ident, cmd) {
431 	if (images[0] && images[1] && numRes == 2) {
432 		_forImage    = images[0];
433 		_resImage    = images[1];
434 	} else {
435 		_forImage    = NULL;
436 		_resImage    = NULL;
437 	}
438 
439 	if (newDimImage) {
440 		_dimImage = newDimImage;
441 	} else {
442 		_dimImage = NULL;
443 	}
444 
445 	_internalAlloc   = false;
446 	_dimmed          = dimNess;
447 	_extent          = box;
448 }
449 
450 
GfxCompButton(gPanelList & list,const Rect16 & box,void * image,uint16 ident,AppFunc * cmd)451 GfxCompButton::GfxCompButton(gPanelList &list, const Rect16 &box, void *image, uint16 ident,
452                          AppFunc *cmd) : GfxCompImage(list, box, NULL, ident, cmd)
453 
454 {
455 	if (image) {
456 		_forImage    = image;
457 		_resImage    = image;
458 		_dimImage    = NULL;
459 	} else {
460 		_forImage    = NULL;
461 		_resImage    = NULL;
462 		_dimImage    = NULL;
463 	}
464 
465 	_internalAlloc   = false;
466 	_dimmed          = false;
467 	_extent          = box;
468 }
469 
GfxCompButton(gPanelList & list,const StaticRect & box,void ** images,int16 numRes,const char * text,textPallete & pal,uint16 ident,AppFunc * cmd)470 GfxCompButton::GfxCompButton(gPanelList &list, const StaticRect &box, void **images, int16 numRes, const char *text, textPallete &pal, uint16 ident, AppFunc *cmd) : GfxCompImage(list, box, NULL, 0, 0, text, pal, ident, cmd) {
471 	if (images[0] && images[1] && numRes == 2) {
472 		_forImage = images[0];
473 		_resImage = images[1];
474 		_dimImage = nullptr;
475 	} else {
476 		_forImage = nullptr;
477 		_resImage = nullptr;
478 		_dimImage = nullptr;
479 	}
480 
481 	_internalAlloc = false;
482 	_dimmed        = false;
483 	_extent        = box;
484 }
485 
GfxCompButton(gPanelList & list,const Rect16 & box,AppFunc * cmd)486 GfxCompButton::GfxCompButton(gPanelList &list, const Rect16 &box, AppFunc *cmd) : GfxCompImage(list, box, NULL, 0, cmd) {
487 	_forImage    = NULL;
488 	_resImage    = NULL;
489 	_dimImage    = NULL;
490 
491 	_internalAlloc   = false;
492 	_dimmed          = false;
493 	_extent          = box;
494 }
495 
~GfxCompButton(void)496 GfxCompButton::~GfxCompButton(void) {
497 	if (_internalAlloc) {
498 		if (_forImage) {
499 			free(_forImage);
500 			_forImage = NULL;
501 		}
502 
503 		if (_resImage) {
504 			free(_resImage);
505 			_resImage = NULL;
506 		}
507 
508 		if (_dimImage) {
509 			free(_dimImage);
510 			_dimImage = NULL;
511 		}
512 	}
513 }
514 
dim(bool enableFlag)515 void GfxCompButton::dim(bool enableFlag) {
516 	if (enableFlag) {
517 		if (!_dimmed)
518 			_dimmed = true;
519 	} else {
520 		if (_dimmed)
521 			_dimmed = false;
522 	}
523 
524 	window.update(_extent);
525 }
526 
527 
deactivate(void)528 void GfxCompButton::deactivate(void) {
529 	selected = 0;
530 	window.update(_extent);
531 	gPanel::deactivate();
532 }
533 
activate(gEventType why)534 bool GfxCompButton::activate(gEventType why) {
535 	selected = 1;
536 	window.update(_extent);
537 
538 	if (why == gEventKeyDown) { // momentarily depress
539 		deactivate();
540 		notify(gEventNewValue, 1);       // notify App of successful hit
541 	}
542 	playMemSound(2);
543 	return false;
544 }
545 
pointerMove(gPanelMessage & msg)546 void GfxCompButton::pointerMove(gPanelMessage &msg) {
547 	if (_dimmed)
548 		return;
549 
550 	//notify( gEventMouseMove, (msg.pointerEnter ? enter : 0)|(msg.pointerLeave ? leave : 0));
551 	GfxCompImage::pointerMove(msg);
552 }
553 
pointerHit(gPanelMessage &)554 bool GfxCompButton::pointerHit(gPanelMessage &) {
555 	if (_dimmed)
556 		return false;
557 
558 	activate(gEventMouseDown);
559 	return true;
560 }
561 
pointerRelease(gPanelMessage &)562 void GfxCompButton::pointerRelease(gPanelMessage &) {
563 	//  We have to test selected first because deactivate clears it.
564 
565 	if (selected) {
566 		deactivate();                       // give back input focus
567 		notify(gEventNewValue, 1);       // notify App of successful hit
568 	} else deactivate();
569 }
570 
pointerDrag(gPanelMessage & msg)571 void GfxCompButton::pointerDrag(gPanelMessage &msg) {
572 	if (selected != msg.inPanel) {
573 		selected = msg.inPanel;
574 		window.update(_extent);
575 	}
576 }
577 
enable(bool abled)578 void GfxCompButton::enable(bool abled) {
579 	gPanel::enable(abled);
580 }
581 
invalidate(Rect16 *)582 void GfxCompButton::invalidate(Rect16 *) {
583 	window.update(_extent);
584 }
585 
586 
draw(void)587 void GfxCompButton::draw(void) {
588 	gPort   &port = window.windowPort;
589 	Rect16  rect = window.getExtent();
590 
591 	SAVE_GPORT_STATE(port);                  // save pen color, etc.
592 	g_vm->_pointer->hide(port, _extent);              // hide mouse pointer
593 	drawClipped(port, Point16(0, 0), Rect16(0, 0, rect.width, rect.height));
594 	g_vm->_pointer->show(port, _extent);              // show mouse pointer
595 }
596 
getCurrentCompImage(void)597 void *GfxCompButton::getCurrentCompImage(void) {
598 	if (_dimmed) {
599 		return _dimImage;
600 	} else if (selected) {
601 		return _resImage;
602 	} else {
603 		return _forImage;
604 	}
605 }
606 
607 /************************************************************************
608 * GfxOwnerSelCompButton -- like a GfxCompButton but does not chage the      *
609 * selector bit                                                          *
610 ************************************************************************/
611 
GfxOwnerSelCompButton(gPanelList & list,const Rect16 & box,void ** images,int16 butRes,uint16 ident,AppFunc * cmd)612 GfxOwnerSelCompButton::GfxOwnerSelCompButton(gPanelList &list, const Rect16 &box, void **images, int16 butRes, uint16 ident,
613         AppFunc *cmd) : GfxCompButton(list, box, images, butRes, ident, cmd) {
614 
615 }
616 
activate(gEventType why)617 bool GfxOwnerSelCompButton::activate(gEventType why) {
618 	if (why == gEventKeyDown || why == gEventMouseDown) {
619 //		selected = !selected;
620 //		window.update( extent );
621 		gPanel::deactivate();
622 		notify(gEventNewValue, selected);    // notify App of successful hit
623 		playMemSound(2);
624 	}
625 	return false;
626 }
627 
pointerHit(gPanelMessage &)628 bool GfxOwnerSelCompButton::pointerHit(gPanelMessage &) {
629 	return activate(gEventMouseDown);
630 }
631 
select(uint16 val)632 void GfxOwnerSelCompButton::select(uint16 val) {
633 	selected = val;
634 
635 	setCurrent(val);
636 
637 	if (getEnabled()) {
638 		window.update(_extent);
639 	}
640 }
641 
642 /************************************************************************
643 * GfxMultCompButton -- like GfxCompButton but does any number of images     *
644 ************************************************************************/
645 
GfxMultCompButton(gPanelList & list,const Rect16 & box,hResContext * con,char a,char b,char c,int16 resStart,int16 numRes,int16 initial,uint16 ident,AppFunc * cmd)646 GfxMultCompButton::GfxMultCompButton(gPanelList &list, const Rect16 &box, hResContext *con, char a, char b, char c, int16 resStart, int16 numRes, int16 initial, uint16 ident,
647                                  AppFunc *cmd) : GfxCompButton(list, box, (hResContext *)NULL, 0, ident, cmd) {
648 	int16   i, k;
649 
650 
651 	_images = (void **)malloc(sizeof(void *)*numRes);
652 
653 	for (i = 0, k = resStart; i < numRes; i++, k++) {
654 		_images[i] = LoadResource(con, MKTAG(a, b, c, k), "Multi btn image");
655 	}
656 
657 	_response = true;
658 	_internalAlloc = true;
659 	_max     = numRes - 1;
660 	_min     = 0;
661 	_current = clamp(_min, initial, _max);
662 
663 	_extent  = box;
664 }
665 
GfxMultCompButton(gPanelList & list,const Rect16 & box,void ** newImages,int16 numRes,int16 initial,uint16 ident,AppFunc * cmd)666 GfxMultCompButton::GfxMultCompButton(gPanelList &list, const Rect16 &box, void **newImages, int16 numRes, int16 initial, uint16 ident,
667                                  AppFunc *cmd) : GfxCompButton(list, box, (hResContext *)NULL, 0, ident, cmd) {
668 	if (!newImages) {
669 		_images  = NULL;
670 		_max     = 0;
671 		_min     = 0;
672 		_current = 0;
673 		_response = false;
674 		return;
675 	}
676 
677 	_images = newImages;
678 
679 	_response = true;
680 	_internalAlloc = false;
681 	_max     = numRes - 1;
682 	_min     = 0;
683 	_current = initial;
684 
685 	_extent  = box;
686 }
687 
GfxMultCompButton(gPanelList & list,const Rect16 & box,void ** newImages,int16 numRes,int16 initial,bool hitResponse,uint16 ident,AppFunc * cmd)688 GfxMultCompButton::GfxMultCompButton(gPanelList &list, const Rect16 &box, void **newImages,
689                                  int16 numRes, int16 initial, bool hitResponse, uint16 ident,
690                                  AppFunc *cmd) : GfxCompButton(list, box, (hResContext *)NULL, 0, ident, cmd) {
691 	if (!newImages) {
692 		_images  = NULL;
693 		_max     = 0;
694 		_min     = 0;
695 		_current = 0;
696 		_response = hitResponse;
697 		return;
698 	}
699 
700 	_images = newImages;
701 
702 	_response = hitResponse;
703 	_internalAlloc = false;
704 	_max     = numRes - 1;
705 	_min     = 0;
706 	_current = initial;
707 
708 	_extent  = box;
709 }
710 
~GfxMultCompButton(void)711 GfxMultCompButton::~GfxMultCompButton(void) {
712 	int16   i;
713 
714 	if (_images && _internalAlloc) {
715 		for (i = 0; i <= _max; i++) {
716 			if (_images[i]) {
717 				free(_images[i]);
718 			}
719 		}
720 
721 		free(_images);
722 		_images = NULL;
723 	}
724 }
725 
activate(gEventType why)726 bool GfxMultCompButton::activate(gEventType why) {
727 	if (why == gEventKeyDown || why == gEventMouseDown) {
728 		if (_response) {
729 			if (++_current > _max) {
730 				_current = 0;
731 			}
732 			window.update(_extent);
733 		}
734 
735 		gPanel::deactivate();
736 		notify(gEventNewValue, _current);     // notify App of successful hit
737 		playMemSound(1);
738 //		playSound( MKTAG('C','B','T',5) );
739 	}
740 	return false;
741 }
742 
pointerHit(gPanelMessage &)743 bool GfxMultCompButton::pointerHit(gPanelMessage &) {
744 	return activate(gEventMouseDown);
745 }
746 
getCurrentCompImage(void)747 void *GfxMultCompButton::getCurrentCompImage(void) {
748 	return _images[_current];
749 }
750 
751 /* ===================================================================== *
752    GfxSlider class
753  * ===================================================================== */
754 
GfxSlider(gPanelList & list,const Rect16 & box,const Rect16 & imageBox,int16 sliderStart,int16 sliderEnd,void ** newImages,int16 resStart,int16 initial,uint16 ident,AppFunc * cmd)755 GfxSlider::GfxSlider(gPanelList &list, const Rect16 &box, const Rect16 &imageBox,
756                  int16 sliderStart, int16 sliderEnd, void **newImages, int16 resStart,
757                  int16 initial, uint16 ident,
758                  AppFunc *cmd) : GfxMultCompButton(list, box, newImages, resStart, initial, ident, cmd) {
759 	int16   calcX;
760 
761 	_imageRect   = imageBox;
762 	_slValMin    = sliderStart;
763 	_slValMax    = sliderEnd;
764 	_slCurrent   = initial;
765 
766 	// find out the position of the slider
767 	calcX = (_slValMax * 100) / clamp(1, _slCurrent, _slCurrent);
768 	calcX = (_extent.width * 100) / clamp(1, calcX, calcX);
769 
770 	_imagePosX = clamp(_extent.x,
771 	                  calcX,
772 	                  _extent.width - _imageRect.x);
773 }
774 
getCurrentCompImage(void)775 void *GfxSlider::getCurrentCompImage(void) {
776 	int16   val;
777 	int32   index;
778 
779 	val = getSliderLenVal();
780 
781 	// max == number of images in array indexing;
782 
783 	index = val / clamp(1, _max + 1, _max + 1);
784 
785 	index = _slCurrent / clamp(1, index, index);
786 
787 	index = clamp(0, index, _max);
788 
789 	return _images[index];
790 }
791 
getSliderLenVal(void)792 int16 GfxSlider::getSliderLenVal(void) {
793 	int16   val = 0;
794 
795 	if (_slValMin < 0 && _slValMax < 0) {
796 		val = _slValMax - _slValMin;
797 	} else if (_slValMin < 0 && _slValMax >= 0) {
798 		val = ABS(_slValMin) + _slValMax;
799 	} else if (_slValMin >= 0 && _slValMax < 0) {
800 		val = ABS(_slValMax) - _slValMin;
801 	} else if (_slValMin >= 0 && _slValMax >= 0) {
802 		val = _slValMax - _slValMin;
803 	}
804 
805 	return val;
806 }
807 
draw(void)808 void GfxSlider::draw(void) {
809 	gPort   &port   = window.windowPort;
810 	Point16 offset  = Point16(0, 0);
811 
812 	SAVE_GPORT_STATE(port);                  // save pen color, etc.
813 	g_vm->_pointer->hide(port, _extent);              // hide mouse pointer
814 	drawClipped(port, offset, Rect16(0, 0, _imageRect.width, _imageRect.height));
815 	g_vm->_pointer->show(port, _extent);              // show mouse pointer
816 }
817 
818 
quantizedVolume(uint16 trueVolume)819 inline int16 quantizedVolume(uint16 trueVolume) {
820 	int16 quantized = trueVolume & 0xFFF8;
821 	quantized += (quantized / 16);
822 	return quantized;
823 }
824 
drawClipped(gPort & port,const Point16 & offset,const Rect16 & r)825 void GfxSlider::drawClipped(gPort &port,
826                           const Point16 &offset,
827                           const Rect16 &r) {
828 	void *dispImage = getCurrentCompImage();
829 	if (dispImage) {
830 		if (_extent.overlap(r)) {
831 			Point16 pos(_imagePosX - offset.x,
832 			            _extent.y - offset.y
833 			           );
834 			if (isGhosted()) drawCompressedImageGhosted(port, pos, dispImage);
835 			else drawCompressedImage(port, pos, dispImage);
836 		}
837 	}
838 }
839 
activate(gEventType why)840 bool GfxSlider::activate(gEventType why) {
841 	if (why == gEventKeyDown || why == gEventMouseDown) {
842 		selected = 1;
843 		window.update(_extent);
844 		gPanel::deactivate();
845 		notify(gEventNewValue, _slCurrent);   // notify App of successful hit
846 	}
847 	return false;
848 }
849 
deactivate(void)850 void GfxSlider::deactivate(void) {
851 	selected = 0;
852 	window.update(_extent);
853 	gPanel::deactivate();
854 }
855 
pointerHit(gPanelMessage & msg)856 bool GfxSlider::pointerHit(gPanelMessage &msg) {
857 	// update the image index
858 	updateSliderIndexes(msg.pickPos);
859 
860 	// redraw the control should any visual change hath occured
861 	window.update(_extent);
862 
863 	activate(gEventMouseDown);
864 	return true;
865 }
866 
pointerMove(gPanelMessage & msg)867 void GfxSlider::pointerMove(gPanelMessage &msg) {
868 	if (selected) {
869 		// update the image index
870 		updateSliderIndexes(msg.pickPos);
871 
872 		// redraw the control should any visual change hath occured
873 		window.update(_extent);
874 
875 		notify(gEventMouseMove, _slCurrent);
876 	}
877 }
878 
pointerRelease(gPanelMessage &)879 void GfxSlider::pointerRelease(gPanelMessage &) {
880 	//  We have to test selected first because deactivate clears it.
881 	if (selected) {
882 		deactivate();                       // give back input focus
883 		notify(gEventNewValue, _slCurrent);       // notify App of successful hit
884 	} else deactivate();
885 }
886 
pointerDrag(gPanelMessage & msg)887 void GfxSlider::pointerDrag(gPanelMessage &msg) {
888 	// update the image index
889 	updateSliderIndexes(msg.pickPos);
890 
891 	notify(gEventNewValue, _slCurrent);       // notify App of successful hit
892 	// redraw the control should any visual change hath occured
893 	window.update(_extent);
894 }
895 
updateSliderIndexes(Point16 & pos)896 void GfxSlider::updateSliderIndexes(Point16 &pos) {
897 	pos.x = quantizedVolume(pos.x);
898 	// get x position units
899 	int32   unit    = (_extent.width * 100) / clamp(1, pos.x, _extent.width);
900 
901 	// find the ratio and get the current slider value
902 	_slCurrent       = (_slValMax * 100) / clamp(1, unit, unit);
903 
904 	// update the image position index
905 	_imagePosX           = clamp(_extent.x,
906 	                            pos.x,
907 	                            _extent.width - _imageRect.x);
908 }
909 
910 } // end of namespace Saga2
911