1 /*
2 PLIB - A Suite of Portable Game Libraries
3 Copyright (C) 1998,2002 Steve Baker
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19 For further information visit http://plib.sourceforge.net
20
21 $Id: puObject.cxx 2051 2005-11-10 20:21:22Z fayjf $
22 */
23
24
25 #include "puLocal.h"
26
UL_RTTI_DEF1(puObject,puValue)27 UL_RTTI_DEF1(puObject,puValue)
28
29
30 static inline float clamp01 ( float x )
31 {
32 return (x >= 1.0f) ? 1.0f : x ;
33 }
34
35 static puColour _puDefaultColourTable[] =
36 {
37 { 0.5f, 0.5f, 0.5f, 1.0f }, /* PUCOL_FOREGROUND */
38 { 0.3f, 0.3f, 0.3f, 1.0f }, /* PUCOL_BACKGROUND */
39 { 0.7f, 0.7f, 0.7f, 1.0f }, /* PUCOL_HIGHLIGHT */
40 { 0.0f, 0.0f, 0.0f, 1.0f }, /* PUCOL_LABEL */
41 { 1.0f, 1.0f, 1.0f, 1.0f }, /* PUCOL_LEGEND */
42 { 0.0f, 0.0f, 0.0f, 1.0f }, /* PUCOL_MISC */
43 { 0.8f, 0.7f, 0.7f, 1.0f } /* PUCOL_EDITFIELD */
44 } ;
45
46
load_colour_scheme(float col[][4],float r,float g,float b,float a)47 static void load_colour_scheme ( float col[][4], float r, float g,
48 float b, float a )
49 {
50 puSetColour ( col [ PUCOL_FOREGROUND ], r, g, b, a ) ;
51 puSetColour ( col [ PUCOL_BACKGROUND ], r/2.0f, g/2.0f, b/2.0f, a ) ;
52 puSetColour ( col [ PUCOL_HIGHLIGHT ], clamp01(r*1.3f), clamp01(g*1.3f),
53 clamp01(b*1.3f), a ) ;
54
55 if ( 4.0f * g + 3.0f * r + b > 4.0f )
56 {
57 puSetColour ( col [ PUCOL_LEGEND ], 0.0f, 0.0f, 0.0f, a ) ;
58 puSetColour ( col [ PUCOL_MISC ], 0.0f, 0.0f, 0.0f, a ) ;
59 }
60 else
61 {
62 puSetColour ( col [ PUCOL_LEGEND ], 1.0f, 1.0f, 1.0f, a ) ;
63 puSetColour ( col [ PUCOL_MISC ], 1.0f, 1.0f, 1.0f, a ) ;
64 }
65 }
66
67
68 static int defaultStyle = PUSTYLE_DEFAULT ;
69 static int defaultBorderThickness = 5 ;
70 static puFont defaultLegendFont ;
71 static puFont defaultLabelFont ;
72 static float defaultColourScheme [ 4 ] ;
73
puSetDefaultStyle(int style)74 void puSetDefaultStyle ( int style )
75 {
76 defaultStyle = style ;
77
78 switch ( abs(style) )
79 {
80 case PUSTYLE_SPECIAL_UNDERLINED :
81 defaultBorderThickness = 1 ;
82 break ;
83
84 case PUSTYLE_SMALL_BEVELLED :
85 case PUSTYLE_SMALL_SHADED :
86 case PUSTYLE_BOXED :
87 defaultBorderThickness = 2 ;
88 break ;
89
90 case PUSTYLE_BEVELLED :
91 case PUSTYLE_SHADED :
92 case PUSTYLE_DROPSHADOW :
93 defaultBorderThickness = 5 ;
94 break ;
95 }
96 }
puGetDefaultStyle(void)97 int puGetDefaultStyle ( void ) { return defaultStyle ; }
98
puSetDefaultBorderThickness(int t)99 void puSetDefaultBorderThickness ( int t ) { defaultBorderThickness = t ; }
puGetDefaultBorderThickness(void)100 int puGetDefaultBorderThickness ( void ) { return defaultBorderThickness ; }
101
puSetDefaultFonts(puFont legendFont,puFont labelFont)102 void puSetDefaultFonts ( puFont legendFont, puFont labelFont )
103 {
104 defaultLegendFont = legendFont ;
105 defaultLabelFont = labelFont ;
106 }
107
puGetDefaultLabelFont(void)108 puFont puGetDefaultLabelFont ( void ) { return defaultLabelFont ; }
puGetDefaultLegendFont(void)109 puFont puGetDefaultLegendFont ( void ) { return defaultLegendFont ; }
110
puGetDefaultFonts(puFont * legendFont,puFont * labelFont)111 void puGetDefaultFonts ( puFont *legendFont, puFont *labelFont )
112 {
113 if ( legendFont ) *legendFont = defaultLegendFont ;
114 if ( labelFont ) *labelFont = defaultLabelFont ;
115 }
116
puSetDefaultColourScheme(float r,float g,float b,float a)117 void puSetDefaultColourScheme ( float r, float g, float b, float a )
118 {
119 defaultColourScheme[0] = r ;
120 defaultColourScheme[1] = g ;
121 defaultColourScheme[2] = b ;
122 defaultColourScheme[3] = a ;
123 load_colour_scheme ( _puDefaultColourTable, r, g, b, a ) ;
124 }
125
puGetDefaultColourScheme(float * r,float * g,float * b,float * a)126 void puGetDefaultColourScheme ( float *r, float *g, float *b, float *a )
127 {
128 if ( r ) *r = defaultColourScheme[0] ;
129 if ( g ) *g = defaultColourScheme[1] ;
130 if ( b ) *b = defaultColourScheme[2] ;
131 if ( a ) *a = defaultColourScheme[3] ;
132 }
133
134
135
setColourScheme(float r,float g,float b,float a)136 void puObject::setColourScheme ( float r, float g, float b, float a )
137 {
138 load_colour_scheme ( colour, r, g, b, a ) ;
139 puPostRefresh () ;
140 }
141
puObject(int minx,int miny,int maxx,int maxy)142 puObject::puObject ( int minx, int miny, int maxx, int maxy ) : puValue ()
143 {
144 type |= PUCLASS_OBJECT ;
145
146 bbox.min[0] = abox.min[0] = minx ;
147 bbox.min[1] = abox.min[1] = miny ;
148 bbox.max[0] = abox.max[0] = maxx ;
149 bbox.max[1] = abox.max[1] = maxy ;
150
151 active_mouse_edge = PU_UP ;
152 active_mouse_button = PU_LEFT_BUTTON ;
153 style = defaultStyle ;
154 visible = active = TRUE ;
155 highlighted = FALSE ;
156 am_default = FALSE ;
157 window = puGetWindow () ;
158 v_status = 0 ;
159
160 cb = NULL ;
161 active_cb = NULL ;
162 down_cb = NULL ;
163 r_cb = NULL ;
164 border_thickness = defaultBorderThickness ;
165 render_data = NULL ;
166 user_data = NULL ;
167 next = prev = NULL ;
168 label = NULL ;
169 labelPlace = PUPLACE_LABEL_DEFAULT ;
170 labelFont = defaultLabelFont ;
171 legend = NULL ;
172 legendFont = defaultLegendFont ;
173 legendPlace = PUPLACE_LEGEND_DEFAULT ;
174
175 when_to_deactivate = PUDEACTIVATE_ON_MOUSE_CLICK ;
176
177 for ( int i = 0 ; i < PUCOL_MAX ; i++ )
178 puSetColour ( colour[i], _puDefaultColourTable[i] ) ;
179
180 parent = NULL ;
181
182 if ( ! puNoGroup() )
183 puGetCurrGroup() -> add ( this ) ;
184
185 puPostRefresh () ;
186 }
187
188
~puObject()189 puObject::~puObject ()
190 {
191 if ( parent != this && parent != NULL )
192 parent -> remove ( this ) ;
193
194 if ( this == puActiveWidget () )
195 puDeactivateWidget () ;
196
197 puPostRefresh () ;
198 }
199
recalc_bbox(void)200 void puObject::recalc_bbox ( void )
201 {
202 bbox = abox ;
203
204 if ( label != NULL )
205 {
206 switch ( labelPlace ) // Extend the bounding box left and right
207 {
208 case PUPLACE_ABOVE_LEFT :
209 case PUPLACE_UPPER_LEFT :
210 case PUPLACE_CENTERED_LEFT :
211 case PUPLACE_LOWER_LEFT :
212 case PUPLACE_BELOW_LEFT :
213 bbox.min[0] -= labelFont.getStringWidth ( label ) + PUSTR_LGAP ;
214 break ;
215
216 case PUPLACE_ABOVE_RIGHT :
217 case PUPLACE_UPPER_RIGHT :
218 case PUPLACE_CENTERED_RIGHT :
219 case PUPLACE_LOWER_RIGHT :
220 case PUPLACE_BELOW_RIGHT :
221 bbox.max[0] += labelFont.getStringWidth ( label ) + PUSTR_RGAP ;
222 break ;
223 }
224
225 switch ( labelPlace ) // Extend the bounding box up and down
226 {
227 case PUPLACE_ABOVE_LEFT :
228 case PUPLACE_TOP_LEFT :
229 case PUPLACE_TOP_CENTERED :
230 case PUPLACE_TOP_RIGHT :
231 case PUPLACE_ABOVE_RIGHT :
232 bbox.max[1] += labelFont.getStringHeight ( label ) + labelFont.getStringDescender () +
233 PUSTR_TGAP ;
234 break ;
235
236 case PUPLACE_BELOW_LEFT :
237 case PUPLACE_BOTTOM_LEFT :
238 case PUPLACE_BOTTOM_CENTERED :
239 case PUPLACE_BOTTOM_RIGHT :
240 case PUPLACE_BELOW_RIGHT :
241 bbox.min[1] -= labelFont.getStringHeight ( label ) + labelFont.getStringDescender () +
242 PUSTR_BGAP ;
243 break ;
244 }
245 }
246
247 if ( parent != NULL )
248 parent -> recalc_bbox () ;
249 }
250
getAbsolutePosition(int * x,int * y) const251 void puObject::getAbsolutePosition ( int *x, int *y ) const
252 {
253 puGroup *par ;
254 *x = abox.min[0] ;
255 *y = abox.min[1] ;
256
257 for ( par = getParent () ; par != NULL ; par = par -> getParent () )
258 {
259 int x_offset, y_offset ;
260 par -> getPosition ( &x_offset, &y_offset ) ;
261
262 *x += x_offset ;
263 *y += y_offset ;
264 }
265 }
266
draw_legend(int dx,int dy)267 void puObject::draw_legend ( int dx, int dy )
268 {
269 if ( legend == NULL )
270 return ;
271
272 int xx, yy ;
273
274 int lgap = PUSTR_LGAP ;
275 int rgap = PUSTR_RGAP ;
276 int tgap = PUSTR_TGAP ;
277 int bgap = PUSTR_BGAP ;
278
279 if ( ( abs(style) != PUSTYLE_NONE ) &&
280 ( abs(style) != PUSTYLE_PLAIN ) &&
281 ( abs(style) != PUSTYLE_DROPSHADOW ) )
282 {
283 if ( abs(style) != PUSTYLE_SPECIAL_UNDERLINED )
284 {
285 lgap += getBorderThickness () ;
286 rgap += getBorderThickness () ;
287 tgap += getBorderThickness () ;
288 }
289 bgap += getBorderThickness () ;
290 }
291
292 /* If greyed out then halve the opacity when drawing the legend */
293
294 if ( active )
295 glColor4fv ( colour [ PUCOL_LEGEND ] ) ;
296 else
297 glColor4f ( colour [ PUCOL_LEGEND ][0],
298 colour [ PUCOL_LEGEND ][1],
299 colour [ PUCOL_LEGEND ][2],
300 colour [ PUCOL_LEGEND ][3] / 2.0f ) ; /* 50% more transparent */
301
302 switch ( getLegendPlace() )
303 {
304 case PUPLACE_TOP_LEFT :
305 case PUPLACE_CENTERED_LEFT :
306 case PUPLACE_BOTTOM_LEFT :
307 case PUPLACE_LOWER_LEFT :
308 xx = lgap ;
309 break ;
310
311 case PUPLACE_TOP_CENTERED :
312 case PUPLACE_CENTERED_CENTERED :
313 case PUPLACE_BOTTOM_CENTERED :
314 xx = ( abox.max[0] - abox.min[0] - legendFont.getStringWidth (legend) ) / 2 ;
315 break ;
316
317 case PUPLACE_TOP_RIGHT :
318 case PUPLACE_CENTERED_RIGHT :
319 case PUPLACE_BOTTOM_RIGHT :
320 case PUPLACE_LOWER_RIGHT :
321 xx = abox.max[0] - abox.min[0] - legendFont.getStringWidth ( legend ) - rgap ;
322 break ;
323
324 default :
325 ulSetError ( UL_WARNING, "PUI: Unrecognised LEGEND place %d", getLegendPlace() ) ;
326 return ;
327 }
328
329 switch ( getLegendPlace() )
330 {
331 case PUPLACE_TOP_LEFT :
332 case PUPLACE_TOP_CENTERED :
333 case PUPLACE_TOP_RIGHT :
334 yy = abox.max[1] - abox.min[1] - legendFont.getStringHeight ( legend ) -
335 legendFont.getStringDescender () - tgap ;
336 break ;
337
338 case PUPLACE_CENTERED_LEFT :
339 case PUPLACE_CENTERED_CENTERED :
340 case PUPLACE_CENTERED_RIGHT :
341 case PUPLACE_LOWER_LEFT : /* Backwards compatibility to PUPLACE_LEFT */
342 case PUPLACE_LOWER_RIGHT : /* Backwards compatibility to PUPLACE_RIGHT */
343 default :
344 yy = ( abox.max[1] - abox.min[1]
345 - legendFont.getStringHeight ( legend ) ) / 2
346 + legendFont.getStringDescender () ;
347 break ;
348
349 case PUPLACE_BOTTOM_LEFT :
350 case PUPLACE_BOTTOM_CENTERED :
351 case PUPLACE_BOTTOM_RIGHT :
352 yy = bgap + legendFont.getStringDescender () ;
353 break ;
354 }
355
356 legendFont.drawString ( legend, dx + abox.min[0] + xx,
357 dy + abox.min[1] + yy ) ;
358 }
359
draw_label(int dx,int dy)360 void puObject::draw_label ( int dx, int dy )
361 {
362 if ( label == NULL )
363 return ;
364
365 int xx, yy ;
366
367 /* If greyed out then halve the opacity when drawing the label */
368
369 if ( active )
370 glColor4fv ( colour [ PUCOL_LABEL ] ) ;
371 else
372 glColor4f ( colour [ PUCOL_LABEL ][0],
373 colour [ PUCOL_LABEL ][1],
374 colour [ PUCOL_LABEL ][2],
375 colour [ PUCOL_LABEL ][3] / 2.0f ) ; /* 50% more transparent */
376
377 switch ( getLabelPlace() )
378 {
379 case PUPLACE_ABOVE_LEFT :
380 case PUPLACE_UPPER_LEFT :
381 case PUPLACE_CENTERED_LEFT :
382 case PUPLACE_LOWER_LEFT :
383 case PUPLACE_BELOW_LEFT :
384 xx = 0 ;
385 break ;
386
387 case PUPLACE_TOP_LEFT :
388 case PUPLACE_BOTTOM_LEFT :
389 xx = abox.min[0] - bbox.min[0] + PUSTR_LGAP ;
390 break ;
391
392 case PUPLACE_TOP_CENTERED :
393 case PUPLACE_BOTTOM_CENTERED :
394 xx = ( bbox.max[0] - bbox.min[0] - labelFont.getStringWidth ( label ) ) / 2 ;
395 break ;
396
397 case PUPLACE_TOP_RIGHT :
398 case PUPLACE_BOTTOM_RIGHT :
399 xx = abox.max[0] - bbox.min[0] - labelFont.getStringWidth ( label ) - PUSTR_RGAP ;
400 break ;
401
402 case PUPLACE_ABOVE_RIGHT :
403 case PUPLACE_UPPER_RIGHT :
404 case PUPLACE_CENTERED_RIGHT :
405 case PUPLACE_LOWER_RIGHT :
406 case PUPLACE_BELOW_RIGHT :
407 xx = bbox.max[0] - bbox.min[0] - labelFont.getStringWidth ( label ) ;
408 break ;
409
410 default :
411 ulSetError ( UL_WARNING, "PUI: Unrecognised LABEL place %d", getLegendPlace() ) ;
412 return ;
413 }
414
415 switch ( getLabelPlace() )
416 {
417 case PUPLACE_ABOVE_LEFT :
418 case PUPLACE_TOP_LEFT :
419 case PUPLACE_TOP_CENTERED :
420 case PUPLACE_TOP_RIGHT :
421 case PUPLACE_ABOVE_RIGHT :
422 yy = bbox.max[1] - bbox.min[1] - labelFont.getStringHeight () -
423 labelFont.getStringDescender () ;
424 break ;
425
426 case PUPLACE_UPPER_LEFT :
427 case PUPLACE_UPPER_RIGHT :
428 yy = abox.max[1] - bbox.min[1] - labelFont.getStringHeight ( label ) - PUSTR_TGAP ;
429 break ;
430
431 case PUPLACE_CENTERED_LEFT :
432 case PUPLACE_CENTERED_RIGHT :
433 default :
434 yy = ( bbox.max[1] - bbox.min[1] -
435 labelFont.getStringHeight ( label ) ) / 2 +
436 labelFont.getStringDescender () ;
437 break ;
438
439 case PUPLACE_LOWER_LEFT :
440 case PUPLACE_LOWER_RIGHT :
441 yy = abox.min[1] - bbox.min[1] + labelFont.getStringDescender () + PUSTR_BGAP ;
442 break ;
443
444 case PUPLACE_BELOW_LEFT :
445 case PUPLACE_BOTTOM_LEFT :
446 case PUPLACE_BOTTOM_CENTERED :
447 case PUPLACE_BOTTOM_RIGHT :
448 case PUPLACE_BELOW_RIGHT :
449 yy = labelFont.getStringDescender () ;
450 break ;
451 }
452
453 labelFont.drawString ( label, dx + bbox.min[0] + xx,
454 dy + bbox.min[1] + yy ) ;
455 }
456
457
checkKey(int key,int updown)458 int puObject::checkKey ( int key, int updown )
459 {
460 if ( updown == PU_UP )
461 return FALSE ;
462
463 if ( isReturnDefault() && ( key == '\r' || key == '\n' ) && ( window == puGetWindow () ) )
464 {
465 if ( puActiveWidget() && ( this != puActiveWidget() ) )
466 {
467 puActiveWidget() -> invokeDownCallback () ;
468 puDeactivateWidget () ;
469 }
470
471 checkHit ( active_mouse_button, PU_DOWN, (abox.min[0]+abox.max[0])/2,
472 (abox.min[1]+abox.max[1])/2 ) ;
473 checkHit ( active_mouse_button, PU_UP , (abox.min[0]+abox.max[0])/2,
474 (abox.min[1]+abox.max[1])/2 ) ;
475 return TRUE ;
476 }
477
478 return FALSE ;
479 }
480
481
doHit(int button,int updown,int x,int y)482 void puObject::doHit ( int button, int updown, int x, int y )
483 {
484 if ( puActiveWidget() && ( this != puActiveWidget() ) )
485 {
486 puActiveWidget() -> invokeDownCallback () ;
487 puDeactivateWidget () ;
488 }
489
490 if ( updown != PU_DRAG )
491 puMoveToLast ( this );
492
493 if ( button == active_mouse_button )
494 {
495 if ( ( updown == active_mouse_edge ) || ( active_mouse_edge == PU_UP_AND_DOWN ) )
496 {
497 lowlight () ;
498 puSetActiveWidget ( this, x, y ) ;
499 invokeCallback () ;
500 }
501 else
502 highlight () ;
503 }
504 else
505 lowlight () ;
506 }
507
checkHit(int button,int updown,int x,int y)508 int puObject::checkHit ( int button, int updown, int x, int y )
509 {
510 if ( ( puGetPressedButton () || ( updown == PU_UP ) ) && isHit( x, y ) ||
511 puGetPressedButton () && ( isHit( x, y ) || ( puActiveWidget () == this ) ) )
512 {
513 doHit ( button, updown, x, y ) ;
514 return TRUE ;
515 }
516
517 return FALSE ;
518 }
519
520
521