ifdef RCS for rcsid
[btb/d2x.git] / ui / listbox.c
1 /*
2 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
3 SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
4 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
5 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
6 IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
7 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
8 FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
9 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
10 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.  
11 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
12 */
13
14 #ifdef RCS
15 static char rcsid[] = "$Id: listbox.c,v 1.2 2004-12-19 14:10:33 btb Exp $";
16 #endif
17 #include <stdlib.h>
18
19 #include "fix.h"
20 #include "types.h"
21 #include "gr.h"
22 #include "ui.h"
23 #include "key.h"
24
25 #define TICKER (*(volatile int *)0x46C)
26
27 void ui_draw_listbox( UI_GADGET_LISTBOX * listbox )
28 {
29         int i, x, y, stop;
30         int w, h,  aw;
31
32         //if (listbox->current_item<0)
33         //    listbox->current_item=0;
34         //if (listbox->current_item>=listbox->num_items)
35         //    listbox->current_item = listbox->num_items-1;
36         //if (listbox->first_item<0)
37         //   listbox->first_item=0;
38         //if (listbox->first_item>(listbox->num_items-listbox->num_items_displayed))
39         //    listbox->first_item=(listbox->num_items-listbox->num_items_displayed);
40
41         if ((listbox->status!=1) && !listbox->moved )
42                 return;
43
44         stop = listbox->first_item+listbox->num_items_displayed;
45         if (stop>listbox->num_items) stop = listbox->num_items;
46
47         listbox->status = 0;
48
49         x = y = 0;
50         ui_mouse_hide();
51         gr_set_current_canvas( listbox->canvas );
52
53         for (i= listbox->first_item; i< stop; i++ )
54         {
55                 if (i !=listbox->current_item)
56                 {
57                         if ((listbox->current_item == -1) && (CurWindow->keyboard_focus_gadget == (UI_GADGET *)listbox) && (i == listbox->first_item)  )
58                                 gr_set_fontcolor( CRED, CBLACK );
59                         else
60                                 gr_set_fontcolor( CWHITE, CBLACK );
61                 }
62                 else
63                 {
64                         if (CurWindow->keyboard_focus_gadget == (UI_GADGET *)listbox)
65                                 gr_set_fontcolor( CRED, CGREY );
66                         else
67                                 gr_set_fontcolor( CBLACK, CGREY );
68                 }
69                 gr_string( x+2, y, listbox->list+i*listbox->text_width );
70                 gr_get_string_size(listbox->list+i*listbox->text_width, &w, &h,&aw );
71
72                 if (i==listbox->current_item)
73                         gr_setcolor( CGREY );
74                 else
75                         gr_setcolor( CBLACK );
76
77                 gr_rect( x+w+2, y, listbox->width-1, y+h-1 );
78                 gr_rect( x, y, x+1, y+h-1 );
79
80                 y += h;
81         }
82
83         if (stop < listbox->num_items_displayed-1 )
84         {
85                 gr_setcolor(CBLACK);
86                 gr_rect( x, y, listbox->width-1, listbox->height-1 );
87         }
88
89         //gr_ubox( -1, -1, listbox->width, listbox->height);
90         ui_mouse_show();
91
92 }
93
94
95 void gr_draw_sunken_border( short x1, short y1, short x2, short y2 )
96 {
97
98         gr_setcolor( CGREY );
99         Hline( x1-1, x2+1, y1-1);
100         Vline( y1-1, y2+1, x1-1);
101
102         gr_setcolor( CBRIGHT );
103         Hline( x1-1, x2+1, y2+1);
104         Vline( y1, y2+1, x2+1);
105
106 }
107
108
109 UI_GADGET_LISTBOX * ui_add_gadget_listbox( UI_WINDOW * wnd, short x, short y, short w, short h, short numitems, char * list, int text_width )
110 {
111         int tw, th, taw, i;
112
113         UI_GADGET_LISTBOX * listbox;
114
115         gr_get_string_size("*", &tw, &th, &taw );
116
117         i = h / th;
118         h = i * th;
119
120         listbox = (UI_GADGET_LISTBOX *)ui_gadget_add( wnd, 2, x, y, x+w-1, y+h-1 );
121
122         listbox->list = list;
123         listbox->text_width = text_width;
124         listbox->width = w;
125         listbox->height = h;
126         listbox->num_items = numitems;
127         listbox->num_items_displayed = i;
128         listbox->first_item = 0;
129         listbox->current_item = -1;
130         listbox->last_scrolled = 0;
131         listbox->textheight = th;
132         listbox->dragging = 0;
133         listbox->selected_item = -1;
134         listbox->moved = 1;
135
136         listbox->scrollbar = ui_add_gadget_scrollbar( wnd, x+w+3, y, 0, h, 0, numitems-i, 0, i );
137         listbox->scrollbar->parent = (UI_GADGET *)listbox;
138
139         gr_set_current_canvas( listbox->canvas );
140
141         gr_setcolor(CBLACK);
142         gr_rect( 0, 0, w-1, h-1);
143
144         gr_draw_sunken_border( -2, -2, w+listbox->scrollbar->width+4, h+1);
145
146         return listbox;
147
148 }
149
150 void ui_listbox_do( UI_GADGET_LISTBOX * listbox, int keypress )
151 {
152         int OnMe, mitem, oldfakepos, kf;
153
154         listbox->selected_item = -1;
155
156         listbox->moved = 0;
157
158         if (listbox->num_items < 1 ) {
159                 listbox->current_item = -1;
160                 listbox->first_item = 0;
161                 listbox->old_current_item = listbox->current_item;
162                 listbox->old_first_item = listbox->first_item;
163                 ui_draw_listbox( listbox );
164
165                 if (CurWindow->keyboard_focus_gadget == (UI_GADGET *)listbox)
166                 {
167                         CurWindow->keyboard_focus_gadget = ui_gadget_get_next((UI_GADGET *)listbox);
168                 }
169
170                 return;
171         }
172
173         listbox->old_current_item = listbox->current_item;
174         listbox->old_first_item = listbox->first_item;
175
176         OnMe = ui_mouse_on_gadget( (UI_GADGET *)listbox );
177
178
179         if (listbox->scrollbar->moved )
180         {
181                 listbox->moved = 1;
182
183                 listbox->first_item = listbox->scrollbar->position;
184
185                 if (listbox->current_item<listbox->first_item)
186                         listbox->current_item = listbox->first_item;
187
188                 if (listbox->current_item>(listbox->first_item+listbox->num_items_displayed-1))
189                         listbox->current_item = listbox->first_item + listbox->num_items_displayed-1;
190
191         }
192
193         if (!B1_PRESSED )
194                 listbox->dragging = 0;
195
196         if (B1_PRESSED && OnMe )
197                 listbox->dragging = 1;
198
199         if ( CurWindow->keyboard_focus_gadget==(UI_GADGET *)listbox )
200         {
201                 if (keypress==KEY_ENTER)   {
202                         listbox->selected_item = listbox->current_item;
203                 }
204
205                 kf = 0;
206
207                 switch(keypress)
208                 {
209                         case (KEY_UP):
210                                 listbox->current_item--;
211                                 kf = 1;
212                                 break;
213                         case (KEY_DOWN):
214                                 listbox->current_item++;
215                                 kf = 1;
216                                 break;
217                         case (KEY_HOME):
218                                 listbox->current_item=0;
219                                 kf = 1;
220                                 break;
221                         case (KEY_END):
222                                 listbox->current_item=listbox->num_items-1;
223                                 kf = 1;
224                                 break;
225                         case (KEY_PAGEUP):
226                                 listbox->current_item -= listbox->num_items_displayed;
227                                 kf = 1;
228                                 break;
229                         case (KEY_PAGEDOWN):
230                                 listbox->current_item += listbox->num_items_displayed;
231                                 kf = 1;
232                                 break;
233                 }
234
235                 if (kf==1)
236                 {
237                         listbox->moved = 1;
238
239                         if (listbox->current_item<0)
240                                 listbox->current_item=0;
241
242                         if (listbox->current_item>=listbox->num_items)
243                                 listbox->current_item = listbox->num_items-1;
244
245                         if (listbox->current_item<listbox->first_item)
246                                 listbox->first_item = listbox->current_item;
247
248                         if (listbox->current_item>=(listbox->first_item+listbox->num_items_displayed))
249                                 listbox->first_item = listbox->current_item-listbox->num_items_displayed+1;
250
251                         if (listbox->num_items <= listbox->num_items_displayed )
252                                 listbox->first_item = 0;
253                         else
254                         {
255                                 oldfakepos = listbox->scrollbar->position;
256                                 listbox->scrollbar->position = listbox->first_item;
257
258                                 listbox->scrollbar->fake_position = listbox->scrollbar->position-listbox->scrollbar->start;
259                                 listbox->scrollbar->fake_position *= listbox->scrollbar->height-listbox->scrollbar->fake_size;
260                                 listbox->scrollbar->fake_position /= (listbox->scrollbar->stop-listbox->scrollbar->start);
261
262                                 if (listbox->scrollbar->fake_position<0)
263                                 {
264                                         listbox->scrollbar->fake_position = 0;
265                                 }
266                                 if (listbox->scrollbar->fake_position > (listbox->scrollbar->height-listbox->scrollbar->fake_size))
267                                 {
268                                         listbox->scrollbar->fake_position = (listbox->scrollbar->height-listbox->scrollbar->fake_size);
269                                 }
270
271                                 if (oldfakepos != listbox->scrollbar->position )
272                                         listbox->scrollbar->status = 1;
273                         }
274                 }
275         }
276
277
278         if (selected_gadget==(UI_GADGET *)listbox)
279         {
280                 if (B1_PRESSED && listbox->dragging)
281                 {
282                         if (Mouse.y < listbox->y1)
283                                 mitem = -1;
284                         else
285                                 mitem = (Mouse.y - listbox->y1)/listbox->textheight;
286
287                         if  ( (mitem < 0 ) && ( TICKER > listbox->last_scrolled+1) )
288                         {
289                                 listbox->current_item--;
290                                 listbox->last_scrolled = TICKER;
291                                 listbox->moved = 1;
292                         }
293
294                         if ( ( mitem >= listbox->num_items_displayed ) &&
295                                  ( TICKER > listbox->last_scrolled+1)         )
296                         {
297                                 listbox->current_item++;
298                                 listbox->last_scrolled = TICKER;
299                                 listbox->moved = 1;
300                         }
301
302                         if ((mitem>=0) && (mitem<listbox->num_items_displayed))
303                         {
304                                 listbox->current_item = mitem+listbox->first_item;
305                                 listbox->moved=1;
306                         }
307
308                         if (listbox->current_item <0 )
309                                 listbox->current_item = 0;
310
311                         if (listbox->current_item >= listbox->num_items )
312                                 listbox->current_item = listbox->num_items-1;
313
314                         if (listbox->current_item<listbox->first_item)
315                                 listbox->first_item = listbox->current_item;
316
317                         if (listbox->current_item>=(listbox->first_item+listbox->num_items_displayed))
318                                 listbox->first_item = listbox->current_item-listbox->num_items_displayed+1;
319
320                         if (listbox->num_items <= listbox->num_items_displayed )
321                                 listbox->first_item = 0;
322                         else
323                         {
324                                 oldfakepos = listbox->scrollbar->position;
325                                 listbox->scrollbar->position = listbox->first_item;
326
327                                 listbox->scrollbar->fake_position = listbox->scrollbar->position-listbox->scrollbar->start;
328                                 listbox->scrollbar->fake_position *= listbox->scrollbar->height-listbox->scrollbar->fake_size;
329                                 listbox->scrollbar->fake_position /= (listbox->scrollbar->stop-listbox->scrollbar->start);
330
331                                 if (listbox->scrollbar->fake_position<0)
332                                 {
333                                         listbox->scrollbar->fake_position = 0;
334                                 }
335                                 if (listbox->scrollbar->fake_position > (listbox->scrollbar->height-listbox->scrollbar->fake_size))
336                                 {
337                                         listbox->scrollbar->fake_position = (listbox->scrollbar->height-listbox->scrollbar->fake_size);
338                                 }
339
340                                 if (oldfakepos != listbox->scrollbar->position )
341                                         listbox->scrollbar->status = 1;
342                         }
343
344                 }
345
346                 if (B1_DOUBLE_CLICKED )
347                 {
348                         listbox->selected_item = listbox->current_item;
349                 }
350
351         }
352
353         ui_draw_listbox( listbox );
354
355 }
356
357 void ui_listbox_change( UI_WINDOW * wnd, UI_GADGET_LISTBOX * listbox, short numitems, char * list, int text_width )
358 {
359         int stop, start;
360         UI_GADGET_SCROLLBAR * scrollbar;
361
362         wnd = wnd;
363
364         listbox->list = list;
365         listbox->text_width = text_width;
366         listbox->num_items = numitems;
367         listbox->first_item = 0;
368         listbox->current_item = -1;
369         listbox->last_scrolled = TICKER;
370         listbox->dragging = 0;
371         listbox->selected_item = -1;
372         listbox->status = 1;
373         listbox->first_item = 0;
374         listbox->current_item = listbox->old_current_item = 0;
375         listbox->moved = 0;
376
377         scrollbar = listbox->scrollbar;
378
379         start=0;
380         stop= numitems - listbox->num_items_displayed;
381
382         if (stop < start) stop = start;
383
384         scrollbar->horz = 0;
385         scrollbar->start = start;
386         scrollbar->stop = stop;
387         scrollbar->fake_length = scrollbar->height;
388         scrollbar->fake_position =  0;
389         if (stop!=start)
390                 scrollbar->fake_size = (listbox->num_items_displayed * scrollbar->height)/(stop-start+1+listbox->num_items_displayed);
391         else
392                 scrollbar->fake_size = scrollbar->height;
393
394         if (scrollbar->fake_size < 7) scrollbar->fake_size = 7;
395         scrollbar->dragging = 0;
396         scrollbar->moved=0;
397         scrollbar->status=1;
398
399
400 }