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