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: puAuxComboBox.cxx 2050 2005-11-10 20:07:08Z fayjf $
22 */
23 
24 
25 #include "puAuxLocal.h"
26 
UL_RTTI_DEF1(puaComboBox,puGroup)27 UL_RTTI_DEF1(puaComboBox,puGroup)
28 
29 
30 void puaComboBox::input_cb ( puObject *inp )
31 {
32   puaComboBox *cbox = (puaComboBox *) inp -> getUserData () ;
33 
34   if ( strcmp ( inp->getStringValue (), cbox->getStringValue () ) )
35   {
36     cbox->update_current_item () ;
37     cbox->setCallbackSource ( PUACOMBOBOX_CALLBACK_INPUT ) ;
38     cbox -> invokeCallback () ;
39   }
40 }
41 
input_active_cb(puObject * inp)42 void puaComboBox::input_active_cb ( puObject *inp )
43 {
44   puaComboBox *cbox = (puaComboBox *) inp -> getUserData () ;
45 
46   cbox->update_current_item () ;
47   cbox->setCallbackSource ( PUACOMBOBOX_CALLBACK_INPUT ) ;
48   cbox -> invokeActiveCallback () ;
49 }
50 
input_down_cb(puObject * inp)51 void puaComboBox::input_down_cb ( puObject *inp )
52 {
53   puaComboBox *cbox = (puaComboBox *) inp -> getUserData () ;
54 
55   cbox->update_current_item () ;
56   cbox->setCallbackSource ( PUACOMBOBOX_CALLBACK_INPUT ) ;
57   cbox -> invokeCallback () ;
58 }
59 
handle_arrow(puObject * arrow)60 void puaComboBox::handle_arrow ( puObject *arrow )
61 {
62   puaComboBox *cbox = (puaComboBox *) arrow -> getUserData () ;
63 
64   if ( ! cbox -> __getPopupMenu () -> isVisible () )
65     cbox -> __getPopupMenu () -> reveal () ;
66   else
67     cbox -> __getPopupMenu () -> hide () ;
68 
69   /* arrow -> setStyle ( - arrow -> getStyle () ) ; */
70 }
71 
handle_popup(puObject * popupm)72 void puaComboBox::handle_popup ( puObject *popupm )
73 {
74   puaComboBox *cbox = (puaComboBox *) popupm -> getUserData () ;
75 
76   cbox -> setCurrentItem ( popupm -> getLegend () ) ;
77 }
78 
79 
update_widgets(void)80 void puaComboBox::update_widgets ( void )
81 {
82   if ( curr_item >= 0 )
83   /* There are some items */
84   {
85     setValue ( list[curr_item] ) ;
86 
87     arrow_btn -> activate () ;
88   }
89   else
90   /* There aren't any items */
91   {
92     setValue ( "" ) ;
93 
94     arrow_btn -> greyOut () ;
95   }
96 
97   input->setValue ( getStringValue () ) ;
98 }
99 
100 
update_current_item(void)101 void puaComboBox::update_current_item ( void )
102 {
103   if ( strcmp ( getStringValue (), input->getStringValue () ) )
104   {
105     /* User has typed in an arbitrary string; see if it is in the list */
106     int i ;
107     for ( i = 0 ; i < num_items ; i++ )
108     {
109       if ( !strcmp ( list[i], input->getStringValue () ) )
110       {
111         /* ... yes, it is ! */
112         curr_item = i ;
113         break ;
114       }
115     }
116 
117     if ( ( i == num_items ) || ( num_items == 0 ) )
118     {
119       /* Didn't find it in the list--or the list is empty */
120       char **old_list = list ;
121       list = new char * [ num_items + 2 ] ;
122       for ( i = 0; i < num_items; i++ )  /* Copy over the old list */
123         list[i] = old_list[i] ;
124 
125       delete old_list ;
126 
127       num_items++ ;
128       int len = strlen ( input->getStringValue () ) + 1 ;
129       curr_item = num_items - 1 ;
130       list[curr_item] = new char [ len ] ;
131       memcpy ( list[curr_item], input->getStringValue (), len ) ;
132       list[num_items] = NULL ;
133       newList ( list ) ;
134       update_widgets () ;
135     }
136 
137     setValue ( input->getStringValue () ) ;
138   }
139 }
140 
141 
newList(char ** _list)142 void puaComboBox::newList ( char ** _list )
143 {
144   // Delete the existing list--if it has not been passed in as the argument
145   int i ;
146   if ( list && ( list != _list ) )
147   {
148     for ( i = 0; i < num_items; i++ )
149       delete list[i] ;
150 
151     delete list ;
152     list = NULL ;
153   }
154 
155   popup_menu -> empty () ;
156 
157   if ( _list == NULL )
158     num_items = 0 ;
159   else
160   {
161     for ( num_items = 0 ; _list[num_items] != NULL ; num_items++ )
162       /* Count number of items */ ;
163 
164     if ( num_items > 0 )
165     {
166       if ( list != _list )
167       {
168         list = new char * [ num_items + 1 ] ;  /* '+ 1' to capture the trailing NULL */
169         for ( i = 0; i < num_items; i++ )
170         {
171           int len = strlen ( _list[i] ) + 1 ;  /* "+ 1" to capture the \0 */
172           list[i] = new char [ len ] ;
173           memcpy ( list[i], _list[i], len * sizeof(char) ) ;
174         }
175 
176         list[num_items] = NULL ;
177       }
178 
179       int dummy, h ;
180       int old_height = abox.max[1] - abox.min[1] ;
181 
182       puPushGroup ( popup_menu ) ;
183 
184       for ( i = (num_items - 1) ; i >= 0 ; i-- )
185       {
186         puObject *menu_item = popup_menu -> add_item ( list[i], handle_popup ) ;
187 
188         menu_item -> setUserData ( this ) ;
189         menu_item -> getSize ( &dummy, &h ) ;
190         menu_item -> setSize ( abox.max[0] - abox.min[0], h ) ;
191       }
192 
193       popup_menu -> close() ;
194 
195       /* Position popup menu correctly */
196 
197       popup_menu -> getSize ( &dummy, &h ) ;
198 
199       if ( (abox.min[1] - h) >= 0 )
200       {
201         popup_menu -> setPosition ( 0, 0 - h ) ;
202 
203         arrow_btn  -> setArrowType ( PUARROW_DOWN ) ;
204       }
205       else
206       {
207         popup_menu -> setPosition ( 0, old_height ) ;
208 
209         arrow_btn  -> setArrowType ( PUARROW_UP   ) ;
210       }
211     }
212   }
213 
214   if ( ( curr_item >= num_items ) || ( curr_item < 0 ) )
215   {
216     curr_item = ( num_items > 0 ? 0 : - 1 ) ;
217     update_widgets () ;
218   }
219 }
220 
getCurrentItem(void)221 int puaComboBox::getCurrentItem ( void )
222 {
223   update_current_item () ;
224 
225   return curr_item ;
226 }
227 
setCurrentItem(const char * item_ptr)228 void puaComboBox::setCurrentItem ( const char *item_ptr )
229 {
230   int i ;
231 
232   for ( i = 0 ; i < num_items ; i++ )
233   {
234     if ( list[i] == item_ptr )
235     {
236       setCurrentItem ( i ) ;
237 
238       break ;
239     }
240   }
241 }
242 
243 
draw(int dx,int dy)244 void puaComboBox::draw ( int dx, int dy )
245 {
246   if ( !visible || ( window != puGetWindow () ) ) return ;
247 
248   draw_label ( dx, dy ) ;
249 
250   puGroup::draw ( dx, dy ) ;
251 }
252 
checkHit(int button,int updown,int x,int y)253 int puaComboBox::checkHit ( int button, int updown, int x, int y )
254 {
255   if ( input -> checkHit ( button, updown, x-abox.min[0], y-abox.min[1] ) )
256   {
257     popup_menu -> hide () ;
258     puSetActiveWidget ( this, x, y ) ;
259 
260     return TRUE ;
261   }
262   else
263     return puGroup::checkHit ( button, updown, x, y ) ;
264 }
265 
checkKey(int key,int updown)266 int puaComboBox::checkKey ( int key, int updown )
267 {
268   if ( updown == PU_UP || ! input -> isAcceptingInput () ||
269        ! isVisible () || ! isActive () || ( window != puGetWindow () ) )
270     return FALSE ;
271 
272   switch ( key )
273   {
274     case PU_KEY_HOME      :
275       setCurrentItem ( 0 ) ;
276       break ;
277 
278     case PU_KEY_END       :
279       setCurrentItem ( num_items - 1 ) ;
280       break ;
281 
282     case PU_KEY_UP        :
283       setCurrentItem ( getCurrentItem () + 1 ) ;
284       break ;
285 
286     case PU_KEY_DOWN      :
287       setCurrentItem ( getCurrentItem () - 1 ) ;
288       break ;
289 
290     case PU_KEY_PAGE_UP   :
291     case PU_KEY_PAGE_DOWN :
292       if ( ! popup_menu -> isVisible () )
293         popup_menu -> reveal () ;
294       else
295         popup_menu -> hide () ;
296 
297       break ;
298 
299     default :
300       return input -> checkKey ( key, updown ) ;
301       break ;
302   }
303 
304   return TRUE ;
305 }
306 
setColourScheme(float r,float g,float b,float a)307 void puaComboBox::setColourScheme ( float r, float g, float b, float a )
308 {
309   puObject::setColourScheme ( r, g, b, a ) ;
310   setChildColourScheme( PUCLASS_INPUT,
311       colour [ PUCOL_EDITFIELD ][0],
312       colour [ PUCOL_EDITFIELD ][1],
313       colour [ PUCOL_EDITFIELD ][2],
314       colour [ PUCOL_EDITFIELD ][3] ) ;
315 }
316 
setColour(int which,float r,float g,float b,float a)317 void puaComboBox::setColour ( int which, float r, float g, float b, float a )
318 {
319   if (which == PUCOL_EDITFIELD)
320     input->setColourScheme ( r, g, b, a ) ;
321   else
322     puObject::setColour ( which, r, g, b, a ) ;
323 }
324 
325 
puaComboBox(int minx,int miny,int maxx,int maxy,char ** entries,int editable)326 puaComboBox::puaComboBox ( int minx, int miny, int maxx, int maxy,
327                            char **entries, int editable ) :
328    puGroup( minx, miny )
329 {
330   type |= PUCLASS_COMBOBOX ;
331 
332   char *stringval ;
333   int arrow_width = (int) ( (maxy-miny) / 1.5f ) ;
334 
335   input = new puInput ( 0, 0, maxx-minx - arrow_width, maxy-miny ) ;
336   input -> setUserData ( this ) ;
337   input -> setCallback ( input_cb ) ;
338   input -> setActiveCallback ( input_active_cb ) ;
339   input -> setDownCallback ( input_down_cb ) ;
340 
341   input -> setStyle ( PUSTYLE_SMALL_SHADED ) ;
342 
343   if ( ! editable )
344     input -> disableInput () ;
345 
346   /* Share 'string' value with input box */
347   input -> getValue ( &stringval ) ;
348 //  setValuator ( stringval ) ;
349 
350   arrow_btn = new puArrowButton ( maxx-minx - arrow_width, 0,
351                                   maxx-minx, maxy-miny,
352                                   PUARROW_DOWN ) ;
353   arrow_btn -> setStyle ( PUSTYLE_SMALL_SHADED ) ;
354   arrow_btn -> setUserData ( this ) ;
355   arrow_btn -> setCallback ( handle_arrow ) ;
356 
357   popup_menu = new puPopupMenu ( 0, 0 ) ;
358   popup_menu -> close () ;
359 
360   close () ;
361 
362   list = NULL ;
363   curr_item = 0 ;
364   num_items = 0 ;
365   callback_source = PUACOMBOBOX_CALLBACK_NONE ;
366   newList ( entries ) ;
367   update_widgets () ;
368 }
369 
setSize(int w,int h)370 void puaComboBox::setSize ( int w, int h )
371 {
372   int arrow_width = (int) ( float(h) / 1.5f ) ;
373   input->setSize ( w - arrow_width, h ) ;
374   arrow_btn->setPosition ( w - arrow_width, 0 ) ;
375   arrow_btn->setSize ( arrow_width, h ) ;
376 }
377 
378