r125: This commit was manufactured by cvs2svn to create tag 'r1_1_7-last'.
[cinelerra_cv/mob.git] / hvirtual / guicast / bclistbox.C
blobd1b6ae04d5208ac818726e10132be4174cb5597b
1 #include "bcdragwindow.h"
2 #include "bclistbox.h"
3 #include "bclistboxitem.h"
4 #include "bcpixmap.h"
5 #include "bcresources.h"
6 #include "clip.h"
7 #include "cursors.h"
8 #include "fonts.h"
9 #include "keys.h"
10 #include "timer.h"
11 #include "vframe.h"
13 #include <string.h>
16 // ====================================================== scrollbars
19 BC_ListBoxYScroll::BC_ListBoxYScroll(BC_ListBox *listbox, 
20                           int total_height, 
21                                           int view_height, 
22                           int position)
23  : BC_ScrollBar(listbox->get_yscroll_x(), 
24         listbox->get_yscroll_y(), 
25         SCROLL_VERT, 
26         listbox->get_yscroll_height(), 
27         total_height, 
28         position, 
29         view_height)
31         this->listbox = listbox;
34 BC_ListBoxYScroll::~BC_ListBoxYScroll()
38 int BC_ListBoxYScroll::handle_event()
40         listbox->set_yposition(get_value());
41         return 1;
50 BC_ListBoxXScroll::BC_ListBoxXScroll(BC_ListBox *listbox, 
51                           int total_width, 
52                                           int view_width,
53                           int position)
54  : BC_ScrollBar(listbox->get_xscroll_x(), 
55         listbox->get_xscroll_y(), 
56         SCROLL_HORIZ, 
57         listbox->get_xscroll_width(), 
58         total_width, 
59         position, 
60         view_width)
62         this->listbox = listbox;
65 BC_ListBoxXScroll::~BC_ListBoxXScroll()
69 int BC_ListBoxXScroll::handle_event()
71         listbox->set_xposition(get_value());
72         return 1;
82 BC_ListBoxToggle::BC_ListBoxToggle(BC_ListBox *listbox, 
83         BC_ListBoxItem *item, 
84         int x, 
85         int y)
86  : BC_Toggle(x, 
87         y, 
88         BC_WindowBase::get_resources()->listbox_expand, 
89         item->get_expand())
91         this->listbox = listbox;
92         this->item = item;
95 void BC_ListBoxToggle::update(BC_ListBoxItem *item, int x, int y)
97         this->item = item;
98         if(item && item->get_expand() != get_value())
99         {
100                 BC_Toggle::update(item->get_expand(), 0);
101         }
102         reposition_window(x, y);
105 int BC_ListBoxToggle::handle_event()
107         listbox->expand_item(item, get_value());
108         return 1;
125 // ====================================================== box
127 BC_ListBox::BC_ListBox(int x, 
128         int y, 
129         int w, 
130         int h,
131         int display_format,
132         ArrayList<BC_ListBoxItem*> *data,
133         char **column_titles,
134         int *column_width,
135         int columns,
136         int yposition,
137         int popup,
138         int selection_mode,
139         int icon_position,
140         int allow_drag)
141  : BC_SubWindow(x, y, w, h, -1)
144         xposition = 0;
145         highlighted_item = -1;
146         highlighted_ptr = 0;
147         highlighted = 0;
148         xscrollbar = 0;
149         yscrollbar = 0;
150         highlighted_division = 0;
151         current_cursor = ARROW_CURSOR;
152         gui = 0;
153         view_h = 0;
154         view_w = 0;
155         title_h = 0;
156         active = 0;
157         new_value = 0;
158         need_xscroll = 0;
159         need_yscroll = 0;
160         bg_tile = 0;
161         drag_popup = 0;
162         selection_number1 = -1;
163         selection_number2 = -1;
164         bg_surface = 0;
165 // GCC 3.0.2 optimization fails if bg_surface is zeroed.
166 // printf("malloc 5\n");
167 // unsigned char *test3 = (unsigned char*)malloc(4628);
168 // printf("malloc 6\n");
169         bg_pixmap = 0;
170         current_operation = BCLISTBOX_NO_OPERATION;
171         allow_drag_scroll = 1;
173         popup_w = w;
174         popup_h = h;
176 //printf("BC_ListBox::BC_ListBox 1\n");
177         this->data = data;
178         this->columns = columns;
179         this->yposition = yposition;
180         this->popup = popup;
181         this->display_format = display_format;
182         this->selection_mode = selection_mode;
183         this->icon_position = icon_position;
184         this->allow_drag = allow_drag;
185         this->column_titles = 0;
186         this->column_width = 0;
187 //printf("BC_ListBox::BC_ListBox 1\n");
189         if((!column_titles && column_width) ||
190                 (column_titles && !column_width))
191         {
192                 printf("BC_ListBox::BC_ListBox either column_titles or column_widths == NULL but not both.\n");
193         }
194 //printf("BC_ListBox::BC_ListBox 2 %p %p\n", column_titles, column_width);
195         set_columns(column_titles, 
196                 column_width, 
197                 columns);
199 //printf("BC_ListBox::BC_ListBox 3\n");
205 // reset the search engine
206 //printf("BC_ListBox::BC_ListBox 4\n");
207         reset_query();
208 //printf("BC_ListBox::BC_ListBox 5\n");
211 BC_ListBox::~BC_ListBox()
213         expanders.remove_all_objects();
214         if(bg_surface) delete bg_surface;
215         if(bg_pixmap) delete bg_pixmap;
216         if(xscrollbar) delete xscrollbar;
217         if(yscrollbar) delete yscrollbar;
218         if(popup)
219         {
220                 delete images[0];
221                 delete images[1];
222                 delete images[2];
223         }
224         
225         delete_columns();
226         delete drag_icon;
229 void BC_ListBox::reset_query()
231         query[0] = 0;  // reset query
234 int BC_ListBox::evaluate_query(int list_item, char *string)
236         return(strcmp(string, data[0].values[list_item]->text) <= 0 && 
237                 data[0].values[list_item]->searchable);
240 int BC_ListBox::query_list()
242         if(query[0] == 0) return 0;
244         int done = 0;
245         int result;
246         int selection_changed = 0;
247         int prev_selection = -1;
248         for(int i = 0; !done && i < data[0].total; i++)
249         {
250                 if(evaluate_query(i, query))
251                 {
252                         result = i;
253                         done = 1;
254                 }
255         }
257         if(done)
258         {
259 // Deselect all
260                 for(int i = 0; i < data[0].total; i++)
261                 {
262                         for(int j = 0; j < columns; j++)
263                         {
264                                 if(data[j].values[i]->selected) prev_selection = i;
265                                 data[j].values[i]->selected = 0;
266                         }
267                 }
269 // Select one
270                 if(prev_selection != result)
271                         selection_changed = 1;
272                 for(int j = 0; j < columns; j++)
273                 {
274                         data[j].values[result]->selected = 1;
275                 }
276                 center_selection(result);
277         }
279         return selection_changed;
282 void BC_ListBox::init_column_width()
284         if(!column_width && data)
285         {
286                 int widest = 5, w;
287                 for(int i = 0; i < data[0].total; i++)
288                 {
289                         w = get_text_width(MEDIUMFONT, data[0].values[i]->get_text()) + 2 * LISTBOX_MARGIN;
290                         if(w > widest) widest = w;
291                 }
292 //              if(widest < popup_w - 4) widest = popup_w - 4;
293                 default_column_width[0] = widest;
294         }
297 int BC_ListBox::initialize()
299         if(popup)
300         {
301                 images[0] = new BC_Pixmap(parent_window, BC_WindowBase::get_resources()->listbox_button[0], PIXMAP_ALPHA);
302                 images[1] = new BC_Pixmap(parent_window, BC_WindowBase::get_resources()->listbox_button[1], PIXMAP_ALPHA);
303                 images[2] = new BC_Pixmap(parent_window, BC_WindowBase::get_resources()->listbox_button[2], PIXMAP_ALPHA);
304                 w = images[0]->get_w();
305                 h = images[0]->get_h();
306                 gui = 0;
307                 status = LISTBOX_UP;
308         }
309         else
310         {
311                 gui = this;
312         }
314         drag_icon = new BC_Pixmap(parent_window, 
315                 BC_WindowBase::get_resources()->type_to_icon[ICON_UNKNOWN], 
316                 PIXMAP_ALPHA);
317         BC_SubWindow::initialize();
319         init_column_width();
321         if(top_level->get_resources()->listbox_bg)
322                 bg_pixmap = new BC_Pixmap(this, 
323                         get_resources()->listbox_bg, 
324                         PIXMAP_OPAQUE);
326         draw_face();
327         draw_items();
328         if(!popup) gui->flash();
329         return 0;
332 void BC_ListBox::deactivate_selection()
334         current_operation = BCLISTBOX_NO_OPERATION;
337 int BC_ListBox::draw_face()
339 // Draw the button for a popup listbox
340         if(popup)
341         {
342                 draw_top_background(parent_window, 0, 0, w, h);
343                 images[status]->write_drawable(pixmap, 
344                         0, 
345                         0,
346                         w,
347                         h,
348                         0,
349                         0);
350                 flash();
351         }
352         return 0;
355 int BC_ListBox::calculate_item_coords()
357         if(!data) return 0;
359         int icon_x = 0;
360         int next_icon_x = 0;
361         int next_icon_y = 0;
362         int next_text_y = 0;
363 // Change the display_format to get the right item dimensions for both
364 // text and icons.
365         int display_format_temp = display_format;
368 // Scan the first column for lowest y coord of all text
369 // and lowest right x and y coord for all icons which aren't auto placable
370         calculate_last_coords_recursive(data,
371                 &icon_x,
372                 &next_icon_x, 
373                 &next_icon_y,
374                 &next_text_y,
375                 1);
377 // Reset last column width.  It's recalculated based on text width.
378         int *last_column_w = (column_width ? 
379                                                 &column_width[columns - 1] : 
380                                                 &default_column_width[columns - 1]);
381         if(this->column_titles)
382         {
383                 *last_column_w = 
384                         get_text_width(MEDIUMFONT, this->column_titles[this->columns - 1]) + 
385                         2 * 
386                         LISTBOX_MARGIN;
387         }
388         else
389         {
390                 *last_column_w = MIN_COLUMN_WIDTH;
391         }
393         calculate_item_coords_recursive(data,
394                 &icon_x,
395                 &next_icon_x, 
396                 &next_icon_y,
397                 &next_text_y,
398                 1);
402         display_format = display_format_temp;
404         return 0;
407 void BC_ListBox::calculate_last_coords_recursive(
408         ArrayList<BC_ListBoxItem*> *data,
409         int *icon_x,
410         int *next_icon_x,
411         int *next_icon_y,
412         int *next_text_y,
413         int top_level)
415         for(int i = 0; i < data[0].total; i++)
416         {
417                 int current_text_y = 0;
418                 int current_icon_x = 0;
419                 int current_icon_y = 0;
420                 BC_ListBoxItem *item = data[0].values[i];
422                 if(!item->autoplace_text)
423                 {
424 // Lowest text coordinate
425                         display_format = LISTBOX_TEXT;
426                         current_text_y = item->text_y + 
427                                 get_text_height(MEDIUMFONT);
428                         if(current_text_y > *next_text_y)
429                                 *next_text_y = current_text_y;
431 // Add sublist depth if it is expanded
432                         if(item->get_sublist() && 
433                                 item->get_columns() &&
434                                 item->get_expand())
435                         {
436                                 calculate_last_coords_recursive(item->get_sublist(),
437                                         icon_x,
438                                         next_icon_x, 
439                                         next_icon_y,
440                                         next_text_y,
441                                         0);
442                         }
443                 }
446                 if(top_level)
447                 {
448                         BC_ListBoxItem *item = data[0].values[i];
449                         if(!item->autoplace_icon)
450                         {
451                                 display_format = LISTBOX_ICONS;
452 // Lowest right icon coordinate.
453                                 current_icon_x = item->icon_x;
454                                 if(current_icon_x > *icon_x) *icon_x = current_icon_x;
455                                 if(current_icon_x + get_item_w(item) > *next_icon_x)
456                                         *next_icon_x = current_icon_x + get_item_w(item);
458                                 current_icon_y = item->icon_y + get_item_h(item);
459                                 if(current_icon_y > *next_icon_y) 
460                                         *next_icon_y = current_icon_y;
461                         }
462                 }
463         }
467 void BC_ListBox::calculate_item_coords_recursive(
468         ArrayList<BC_ListBoxItem*> *data,
469         int *icon_x,
470         int *next_icon_x,
471         int *next_icon_y,
472         int *next_text_y,
473         int top_level)
478 // Set up items which need autoplacement.
479 // Should fill icons down and then across
480         for(int i = 0; i < data[0].total; i++)
481         {
482 // Don't increase y unless the row requires autoplacing.
483                 int total_autoplaced_columns = 0;
485 // Set up icons in first column
486                 if(top_level)
487                 {
488                         BC_ListBoxItem *item = data[0].values[i];
489                         if(item->autoplace_icon)
490                         {
491 // 1 column only if icons are used
492                                 display_format = LISTBOX_ICONS;
493 // Test row height
494 // Start new row.
495                                 if(*next_icon_y + get_item_h(item) >= get_h() && 
496                                         *next_icon_y > 0)
497                                 {
498                                         *icon_x = *next_icon_x;
499                                         *next_icon_y = 0;
500                                 }
502                                 if(*icon_x + get_item_w(item) > *next_icon_x)
503                                         *next_icon_x = *icon_x + get_item_w(item);
506                                 item->set_icon_x(*icon_x);
507                                 item->set_icon_y(*next_icon_y);
509                                 *next_icon_y += get_item_h(item);
510                         }
511                 }
515 // Set up a text row
516                 int next_text_x = 0;
517                 for(int j = 0; j < columns; j++)
518                 {
519                         BC_ListBoxItem *item = data[j].values[i];
520                         if(item->autoplace_text)
521                         {
522                                 display_format = LISTBOX_TEXT;
523                                 item->set_text_x(next_text_x);
524                                 item->set_text_y(*next_text_y);
526 // printf("BC_ListBox::calculate_item_coords_recursive %p %d %d %d %d %s \n", 
527 // item->get_sublist(), 
528 // item->get_columns(), 
529 // item->get_expand(), 
530 // next_text_x, 
531 // *next_text_y,
532 // item->get_text());
533 // Increment position of next column
534                                 if(j < columns - 1)
535                                         next_text_x += (column_width ? 
536                                                 column_width[j] : 
537                                                 default_column_width[j]);
538                                 else
539 // Set last column width based on text width
540                                 {
541                                         int new_w = get_item_w(item);
543                                         int *previous_w = (column_width ? 
544                                                 &column_width[j] : 
545                                                 &default_column_width[j]);
546                                         if(new_w > *previous_w)
547                                                 *previous_w = new_w;
548                                 }
549                                 total_autoplaced_columns++;
550                         }
551                 }
553 // Increase the text vertical position
554                 if(total_autoplaced_columns)
555                 {
556                         display_format = LISTBOX_TEXT;
557                         *next_text_y += get_text_height(MEDIUMFONT);
558                 }
560 // Set up a sublist
561                 BC_ListBoxItem *item = data[0].values[i];
562                 if(item->get_sublist() &&
563                         item->get_columns() &&
564                         item->get_expand())
565                 {
566                         calculate_item_coords_recursive(
567                                 item->get_sublist(),
568                                 icon_x,
569                                 next_icon_x,
570                                 next_icon_y,
571                                 next_text_y,
572                                 0);
573                 }
574         }
577 int BC_ListBox::get_display_mode()
579         return display_format;
582 int BC_ListBox::get_yposition()
584         return yposition;
587 int BC_ListBox::get_xposition()
589         return xposition;
592 int BC_ListBox::get_highlighted_item()
594         return highlighted_item;
598 int BC_ListBox::get_item_x(BC_ListBoxItem *item)
600         if(display_format == LISTBOX_TEXT)
601                 return item->text_x - xposition + 2;
602         else
603                 return item->icon_x - xposition + 2;
606 int BC_ListBox::get_item_y(BC_ListBoxItem *item)
608         int result;
609         if(display_format == LISTBOX_TEXT)
610                 result = item->text_y - yposition + title_h + 2;
611         else
612                 result = item->icon_y - yposition + title_h + 2;
613         return result;
616 int BC_ListBox::get_item_w(BC_ListBoxItem *item)
618         if(display_format == LISTBOX_ICONS)
619         {
620                 int x, y, w, h;
621                 get_icon_mask(item, x, y, w, h);
622                 int icon_w = w;
623                 get_text_mask(item, x, y, w, h);
624                 int text_w = w;
626                 if(icon_position == ICON_LEFT)
627                         return icon_w + text_w;
628                 else
629                         return (icon_w > text_w) ? icon_w : text_w;
630         }
631         else
632         {
633                 return get_text_width(MEDIUMFONT, item->text) + 2 * LISTBOX_MARGIN;
634         }
637 int BC_ListBox::get_item_h(BC_ListBoxItem *item)
639         if(display_format == LISTBOX_ICONS)
640         {
641                 int x, y, w, h;
642                 get_icon_mask(item, x, y, w, h);
643                 int icon_h = h;
644                 get_text_mask(item, x, y, w, h);
645                 int text_h = h;
647                 if(icon_position == ICON_LEFT)
648                         return (icon_h > text_h) ? icon_h : text_h;
649                 else
650                         return icon_h + text_h;
651         }
652         else
653         {
654                 return get_text_height(MEDIUMFONT);
655         }
656         return 0;
660 int BC_ListBox::get_icon_w(BC_ListBoxItem *item)
662         BC_Pixmap *icon = item->icon;
663         if(icon) return icon->get_w();
664         return 0;
667 int BC_ListBox::get_icon_h(BC_ListBoxItem *item)
669         BC_Pixmap *icon = item->icon;
670         if(icon) return icon->get_h();
671         return 0;
674 int BC_ListBox::get_items_width()
676         int widest = 0;
678         if(display_format == LISTBOX_ICONS)
679         {
680                 for(int i = 0; i < columns; i++)
681                 {
682                         for(int j = 0; j < data[i].total; j++)
683                         {
684                                 int x1, x, y, w, h;
685                                 BC_ListBoxItem *item = data[i].values[j];
686                                 x1 = item->icon_x;
688                                 get_icon_mask(item, x, y, w, h);
689                                 if(x1 + w > widest) widest = x1 + w;
691                                 if(display_format == LISTBOX_ICONS && icon_position == ICON_LEFT)
692                                         x1 += w;
694                                 get_text_mask(item, x, y, w, h);
695                                 if(x1 + w > widest) widest = x1 + w;
696                         }
697                 }
698         }
699         else
700         if(display_format == LISTBOX_TEXT)
701         {
702                 return get_column_offset(columns);
703         }
704         return widest;
707 int BC_ListBox::get_items_height(ArrayList<BC_ListBoxItem*> *data, 
708         int columns,
709         int *result)
711         int temp = 0;
712         int top_level = 0;
713         int highest = 0;
714         if(!result)
715         {
716                 result = &temp;
717                 top_level = 1;
718         }
724         for(int j = 0; j < (data ? data[0].total : 0); j++)
725         {
726                 int y1, x, y, w, h;
727                 BC_ListBoxItem *item = data[0].values[j];
729                 if(display_format == LISTBOX_ICONS)
730                 {
731                         get_icon_mask(item, x, y, w, h);
732                         if(y + h > highest) highest = y + h;
734                         get_text_mask(item, x, y, w, h);
735                         if(y + h > highest) highest = y + h;
736                 }
737                 else
738                 {
739                         get_text_mask(item, x, y, w, h);
740                         *result += h;
743 // Descend into sublist
744                         if(item->get_sublist() &&
745                                 item->get_expand())
746                         {
747                                 get_items_height(item->get_sublist(), 
748                                         item->get_columns(), 
749                                         result);
750                         }
751                 }
752         }
753         if(display_format == LISTBOX_TEXT && top_level) 
754         {
755                 highest = LISTBOX_MARGIN + *result;
756         }
759         return highest;
762 int BC_ListBox::set_yposition(int position, int draw_items)
764         this->yposition = position;
765         if(draw_items)
766         {
767                 this->draw_items();
768                 gui->flash();
769         }
770         return 0;
773 int BC_ListBox::set_xposition(int position)
775         this->xposition = position;
776         draw_items();
777         gui->flash();
778         return 0;
781 void BC_ListBox::expand_item(BC_ListBoxItem *item, int expand)
783         if(item)
784         {
785                 item->expand = expand;
786 // Collapse sublists if this is collapsed to make it easier to calculate
787 // coordinates
788                 if(item->get_sublist())
789                         collapse_recursive(item->get_sublist());
792 // Set everything for autoplacement
793                 
794                 set_autoplacement(data, 0, 1);
796                 draw_items();
797                 gui->flash();
798         }
801 void BC_ListBox::collapse_recursive(ArrayList<BC_ListBoxItem*> *data)
803         for(int i = 0; i < data[0].total; i++)
804         {
805                 BC_ListBoxItem *item = data[0].values[i];
806                 if(item->get_sublist() && item->expand)
807                 {
808                         item->expand = 0;
809                         collapse_recursive(item->get_sublist());
810                 }
811         }
814 void BC_ListBox::set_autoplacement(ArrayList<BC_ListBoxItem*> *data,
815         int do_icons, 
816         int do_text)
818         for(int i = 0; i < data[0].total; i++)
819         {
820                 for(int j = 0; j < columns; j++)
821                 {
822                         if(do_icons) data[j].values[i]->autoplace_icon = 1;
823                         if(do_text) data[j].values[i]->autoplace_text = 1;
824                 }
826                 BC_ListBoxItem *item = data[0].values[i];
827                 if(item->get_sublist())
828                 {
829                         set_autoplacement(item->get_sublist(), do_icons, do_text);
830                 }
831         }
836 int BC_ListBox::get_w()
838         if(popup)
839                 return BCPOPUPLISTBOX_W;
840         else
841                 return popup_w;
844 int BC_ListBox::get_h()
846         if(popup)
847                 return BCPOPUPLISTBOX_H;
848         else
849                 return popup_h;
852 int BC_ListBox::get_yscroll_x()
854         if(popup)
855                 return popup_w - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w();
856         else
857                 return get_x() + 
858                         popup_w - 
859                         get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w();
862 int BC_ListBox::get_yscroll_y()
864         if(popup)
865                 return 0;
866         else
867                 return get_y();
870 int BC_ListBox::get_yscroll_height()
872         return popup_h - (need_xscroll ? 
873                 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h() : 
874                 0);
877 int BC_ListBox::get_xscroll_x()
879         if(popup)
880                 return 0;
881         else
882                 return get_x();
885 int BC_ListBox::get_xscroll_y()
887         if(popup)
888                 return popup_h - 
889                         get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h();
890         else
891                 return get_y() + 
892                         popup_h - 
893                         get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h();
896 int BC_ListBox::get_xscroll_width()
898         return popup_w - (need_yscroll ? 
899                 get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w() : 
900                 0);
903 int BC_ListBox::get_column_offset(int column)
905         int x = 0;
906         while(column > 0)
907         {
908                 x += column_width ? 
909                         column_width[--column] : 
910                         default_column_width[--column];
911         }
912         return x;
915 void BC_ListBox::column_width_boundaries()
917         if(column_width)
918         {
919                 for(int i = 0; i < columns; i++)
920                 {
921                         if(column_width[i] < MIN_COLUMN_WIDTH) column_width[i] = MIN_COLUMN_WIDTH;
922                 }
923         }
924         else
925         {
926                 for(int i = 0; i < columns; i++)
927                 {
928                         if(default_column_width[i] < MIN_COLUMN_WIDTH) default_column_width[i] = MIN_COLUMN_WIDTH;
929                 }
930         }
933 int BC_ListBox::get_column_width(int column, int clamp_right)
935         if(column < columns - 1 || !clamp_right)
936                 return column_width ? 
937                         column_width[column] : 
938                         default_column_width[column];
939         else
940                 return popup_w + 
941                         xposition - 
942                         get_column_offset(column);
945 int BC_ListBox::get_icon_mask(BC_ListBoxItem *item, 
946         int &x, 
947         int &y, 
948         int &w, 
949         int &h)
951         if(display_format == LISTBOX_ICONS)
952         {
953                 x = get_item_x(item);
954                 y = get_item_y(item);
955                 w = get_icon_w(item) + ICON_MARGIN * 2;
956                 h = get_icon_h(item) + ICON_MARGIN * 2;
957         }
958         else
959         if(display_format == LISTBOX_TEXT)
960         {
961                 x = y = w = h = 0;
962         }
963         return 0;
966 int BC_ListBox::get_text_mask(BC_ListBoxItem *item, 
967         int &x, 
968         int &y, 
969         int &w, 
970         int &h)
972         x = get_item_x(item);
973         y = get_item_y(item);
975         if(display_format == LISTBOX_ICONS)
976         {
977                 if(icon_position == ICON_LEFT)
978                 {
979                         x += get_icon_w(item) + ICON_MARGIN * 2;
980                         y += get_icon_h(item) - get_text_height(MEDIUMFONT);
981                 }
982                 else
983                 {
984                         y += get_icon_h(item) + ICON_MARGIN;
985                 }
987                 w = get_text_width(MEDIUMFONT, item->text) + ICON_MARGIN * 2;
988                 h = get_text_height(MEDIUMFONT) + ICON_MARGIN * 2;
989         }
990         else
991         if(display_format == LISTBOX_TEXT)
992         {
993                 w = get_text_width(MEDIUMFONT, item->text) + LISTBOX_MARGIN * 2;
994                 h = get_text_height(MEDIUMFONT);
995         }
996         return 0;
999 int BC_ListBox::get_item_highlight(ArrayList<BC_ListBoxItem*> *data, 
1000         int column, 
1001         int item)
1003         if(data[column].values[item]->selected)
1004                 return BLUE;
1005         else
1006         if(highlighted_ptr == data[0].values[item])
1007                 return LTGREY;
1008         else
1009                 return WHITE;
1012 int BC_ListBox::get_item_color(ArrayList<BC_ListBoxItem*> *data, 
1013         int column, 
1014         int item)
1016         int color = data[column].values[item]->color;
1017         if(get_item_highlight(data, column, item) == color)
1018                 return BLACK;
1019         else
1020                 return color;
1024 BC_ListBoxItem* BC_ListBox::get_selection(int column, 
1025         int selection_number)
1027         return get_selection_recursive(data,
1028                 column,
1029                 selection_number);
1032 BC_ListBoxItem* BC_ListBox::get_selection_recursive(
1033         ArrayList<BC_ListBoxItem*> *data,
1034         int column,
1035         int selection_number)
1037         if(!data) return 0;
1039         for(int i = 0; i < data[0].total; i++)
1040         {
1041                 BC_ListBoxItem *item = data[0].values[i];
1042                 if(item->selected)
1043                 {
1044                         selection_number--;
1045                         if(selection_number < 0)
1046                         {
1048                                 return data[column].values[i];
1049                         }
1050                 }
1052                 if(item->get_sublist())
1053                 {
1054                         BC_ListBoxItem *result = get_selection_recursive(item->get_sublist(),
1055                                 column,
1056                                 selection_number);
1057                         if(result) return result;
1058                 }
1059         }
1060         return 0;
1064 int BC_ListBox::get_selection_number(int column, 
1065         int selection_number)
1067         return get_selection_number_recursive(data,
1068                 column,
1069                 selection_number);
1072 int BC_ListBox::get_selection_number_recursive(
1073         ArrayList<BC_ListBoxItem*> *data,
1074         int column,
1075         int selection_number,
1076         int *counter)
1078         int temp = -1;
1079         if(!data) return 0;
1080         if(!counter) counter = &temp;
1082         for(int i = 0; i < data[0].total; i++)
1083         {
1084                 (*counter)++;
1085                 BC_ListBoxItem *item = data[0].values[i];
1086                 if(item->selected)
1087                 {
1088                         selection_number--;
1089                         if(selection_number < 0)
1090                         {
1091                                 return (*counter);
1092                         }
1093                 }
1094                 if(item->get_sublist())
1095                 {
1096                         int result = get_selection_number_recursive(
1097                                 item->get_sublist(),
1098                                 column,
1099                                 selection_number,
1100                                 counter);
1101                         if(result >= 0) return result;
1102                 }
1103         }
1104         return -1;
1108 int BC_ListBox::set_selection_mode(int mode)
1110         this->selection_mode = mode;
1111         return 0;
1114 void BC_ListBox::delete_columns()
1116         if(column_titles)
1117         {
1118                 for(int i = 0; i < columns; i++)
1119                 {
1120                         delete [] column_titles[i];
1121                 }
1122                 delete [] column_titles;
1123         }
1125         if(column_width) delete [] column_width;
1126         
1127         column_titles = 0;
1128         column_width = 0;
1131 // Need to copy titles so EDL can change
1132 void BC_ListBox::set_columns(char **column_titles, 
1133         int *column_width, 
1134         int columns)
1136         if((!column_titles && column_width) ||
1137                 (column_titles && !column_width))
1138         {
1139                 printf("BC_ListBox::set_columns either column_titles or column_width == NULL but not both.\n");
1140                 return;
1141         }
1144         delete_columns();
1146         if(column_titles)
1147         {
1148                 this->column_titles = new char*[columns];
1149                 for(int i = 0; i < columns; i++)
1150                 {
1151                         this->column_titles[i] = new char[strlen(column_titles[i]) + 1];
1152                         strcpy(this->column_titles[i], column_titles[i]);
1153                 }
1154         }
1155         
1156         if(column_width)
1157         {
1158                 this->column_width = new int[columns];
1159                 for(int i = 0; i < columns; i++)
1160                 {
1161                         this->column_width[i] = column_width[i];
1162                 }
1163         }
1164         
1165         this->columns = columns;
1170 int BC_ListBox::update(ArrayList<BC_ListBoxItem*> *data,
1171         char **column_titles,
1172         int *column_widths,
1173         int columns,
1174         int xposition,
1175         int yposition, 
1176         int highlighted_number,
1177         int recalc_positions,
1178         int draw)
1181         set_columns(column_titles, 
1182                 column_widths, 
1183                 columns);
1185         this->data = data;
1187         this->yposition = yposition;
1188         this->xposition = xposition;
1189         this->highlighted_item = highlighted_number;
1190         this->highlighted_ptr = index_to_item(data, highlighted_number, 0);
1192         if(recalc_positions)
1193                 set_autoplacement(data, 1, 1);
1195         init_column_width();
1197         if(gui && draw)
1198         {
1199                 draw_background();
1200                 draw_items();
1201                 update_scrollbars();
1202                 gui->flash();
1203         }
1205         return 0;
1208 void BC_ListBox::center_selection()
1210         int selection = get_selection_number(0, 0);
1212         calculate_item_coords();
1213         center_selection(selection);
1216         if(gui)
1217         {
1218                 draw_background();
1219                 draw_items();
1220                 update_scrollbars();
1221                 gui->flash();
1222         }
1225 void BC_ListBox::move_vertical(int pixels)
1229 void BC_ListBox::move_horizontal(int pixels)
1233 int BC_ListBox::select_previous(int skip, 
1234         BC_ListBoxItem *selected_item,
1235         int *counter,
1236         ArrayList<BC_ListBoxItem*> *data,
1237         int *got_first,
1238         int *got_second)
1240         int top_level = 0;
1241         if(!selected_item)
1242                 selected_item = get_selection(0, 0);
1243         int temp = -1;
1244         if(!counter)
1245                 counter = &temp;
1246         int temp2 = 0;
1247         if(!got_first)
1248         {
1249                 got_first = &temp2;
1250                 top_level = 1;
1251         }
1252         int temp3 = 0;
1253         if(!got_second)
1254                 got_second = &temp3;
1255         if(!data)
1256                 data = this->data;
1257         int done = 0;
1259 // Scan backwards to item pointer.  Then count visible items to get 
1260 // destination.  Repeat to get wraparound.
1261         do
1262         {
1263                 for(int i = data[0].total - 1; i >= 0; i--)
1264                 {
1265                         BC_ListBoxItem *current_item = data[0].values[i];
1266                         if(current_item->get_sublist() &&
1267                                 current_item->get_expand())
1268                         {
1269                                 int result = select_previous(skip, 
1270                                         selected_item,
1271                                         counter,
1272                                         current_item->get_sublist(),
1273                                         got_first,
1274                                         got_second);
1275                                 if(*got_second)
1276                                 {
1277                                         return result;
1278                                 }
1279                         }
1281                         if(*got_first)
1282                         {
1283                                 (*counter)++;
1284                                 if((*counter) >= skip)
1285                                 {
1286                                         for(int j = 0; j < columns; j++)
1287                                                 data[j].values[i]->selected = 1;
1288                                         (*got_second) = 1;
1289                                         return item_to_index(this->data, current_item);
1290                                 }
1291                         }
1292                         else
1293                         {
1294                                 if(current_item->selected)
1295                                 {
1296                                         for(int j = 0; j < columns; j++)
1297                                                 data[j].values[i]->selected = 0;
1298                                         (*got_first) = 1;
1299                                         (*counter)++;
1300                                 }
1301                         }
1302                 }
1304 // Hit bottom of top level without finding a selected item.
1305                 if(top_level && !(*got_first)) (*got_first) = 1;
1306         }while(top_level && data[0].total);
1307         return -1;
1310 int BC_ListBox::select_next(int skip, 
1311         BC_ListBoxItem *selected_item,
1312         int *counter,
1313         ArrayList<BC_ListBoxItem*> *data,
1314         int *got_first,
1315         int *got_second)
1317         int top_level = 0;
1318         if(!selected_item)
1319                 selected_item = get_selection(0, 0);
1320         int temp = -1;
1321         if(!counter)
1322                 counter = &temp;
1323         int temp2 = 0;
1324         if(!got_first)
1325         {
1326                 got_first = &temp2;
1327                 top_level = 1;
1328         }
1329         int temp3 = 0;
1330         if(!got_second)
1331                 got_second = &temp3;
1332         if(!data)
1333                 data = this->data;
1334         int done = 0;
1336 // Scan backwards to item pointer.  Then count visible items to get 
1337 // destination.  Repeat to get wraparound.
1338         do
1339         {
1340                 for(int i = 0; i < data[0].total; i++)
1341                 {
1342                         BC_ListBoxItem *current_item = data[0].values[i];
1343                         if(*got_first)
1344                         {
1345                                 (*counter)++;
1346                                 if((*counter) >= skip)
1347                                 {
1348                                         for(int j = 0; j < columns; j++)
1349                                                 data[j].values[i]->selected = 1;
1350                                         (*got_second) = 1;
1351                                         return item_to_index(this->data, current_item);
1352                                 }
1353                         }
1354                         else
1355                         {
1356                                 if(current_item->selected)
1357                                 {
1358                                         for(int j = 0; j < columns; j++)
1359                                                 data[j].values[i]->selected = 0;
1360                                         (*got_first) = 1;
1361                                         (*counter)++;
1362                                 }
1363                         }
1365                         if(current_item->get_sublist() &&
1366                                 current_item->get_expand())
1367                         {
1368                                 int result = select_next(skip, 
1369                                         selected_item,
1370                                         counter,
1371                                         current_item->get_sublist(),
1372                                         got_first,
1373                                         got_second);
1374                                 if(*got_second)
1375                                 {
1376                                         return result;
1377                                 }
1378                         }
1379                 }
1381 // Hit bottom of top level without finding a selected item.
1382                 if(top_level && !(*got_first)) (*got_first) = 1;
1383         }while(top_level && data[0].total);
1384         return -1;
1388 void BC_ListBox::fix_positions()
1390         if(yposition < 0) yposition = 0;
1391         else
1392         if(yposition > get_items_height(data, columns) - view_h)
1393                 yposition = get_items_height(data, columns) - view_h;
1395         if(yposition < 0) yposition = 0;
1397         if(xposition < 0) xposition = 0;
1398         else
1399         if(xposition >= get_items_width() - view_w)
1400                 xposition = get_items_width() - view_w;
1402         if(xposition < 0) xposition = 0;
1405 int BC_ListBox::center_selection(int selection,
1406         ArrayList<BC_ListBoxItem*> *data,
1407         int *counter)
1409         int temp = -1;
1410         if(!data) data = this->data;
1411         if(!counter) counter = &temp;
1413         for(int i = 0; i < data[0].total; i++)
1414         {
1415                 (*counter)++;
1417 // Got it
1418                 BC_ListBoxItem *item = data[0].values[i];
1419                 if((*counter) == selection)
1420                 {
1421                         BC_ListBoxItem *top_item = this->data[0].values[0];
1424                         if(display_format == LISTBOX_ICONS)
1425                         {
1426 // Icon is out of window
1427                                 if(item->icon_y - yposition  > 
1428                                         view_h - get_text_height(MEDIUMFONT) ||
1429                                         item->icon_y - yposition < 0)
1430                                 {
1431                                         yposition = item->icon_y - view_h / 2;
1432                                 }
1434                                 if(data[0].values[selection]->icon_x - xposition > view_w ||
1435                                         data[0].values[selection]->icon_x - xposition < 0)
1436                                 {
1437                                         xposition = item->icon_x - view_w / 2;
1438                                 }
1439                         }
1440                         else
1441                         if(display_format == LISTBOX_TEXT)
1442                         {
1443 // Text coordinate is out of window
1444                                 if(item->text_y - yposition  > 
1445                                         view_h - get_text_height(MEDIUMFONT) ||
1446                                         item->text_y - yposition < 0)
1447                                 {
1448                                         yposition = item->text_y - 
1449                                                 top_item->text_y -
1450                                                 view_h / 2;
1451                                 }
1452                         }
1453                         return 1;
1454                 }
1456 // Descend
1457                 if(item->get_sublist())
1458                 {
1459                         int result = center_selection(selection,
1460                                 item->get_sublist(),
1461                                 counter);
1462                         if(result) return result;
1463                 }
1464         }
1465         return 0;
1468 void BC_ListBox::update_scrollbars()
1470         int h_needed = get_items_height(data, columns);
1471         int w_needed = get_items_width();
1473         if(xscrollbar)
1474         {
1475                 if(xposition != xscrollbar->get_value())
1476                         xscrollbar->update_value(xposition);
1478                 if(w_needed != xscrollbar->get_length() || view_w != xscrollbar->get_handlelength())
1479                         xscrollbar->update_length(w_needed, xposition, view_w);
1480         }
1482         if(yscrollbar)
1483         {
1484                 if(yposition != yscrollbar->get_value())
1485                         yscrollbar->update_value(yposition);
1487                 if(h_needed != yscrollbar->get_length() || view_h != yscrollbar->get_handlelength())
1488                         yscrollbar->update_length(h_needed, yposition, view_h);
1489         }
1494 void BC_ListBox::set_drag_scroll(int value)
1496         allow_drag_scroll = value;
1500 // Test for scrolling by dragging
1502 void BC_ListBox::test_drag_scroll(int &redraw, int cursor_x, int cursor_y)
1504         int top_boundary = 2;
1505         if(display_format == LISTBOX_TEXT && column_titles)
1506                 top_boundary += title_h;
1508         if(!allow_drag_scroll) return;
1510         if(current_operation == BCLISTBOX_DRAG_DIVISION) return;
1512         if(cursor_y < top_boundary)
1513         {
1514                 yposition -= top_boundary - cursor_y;
1515                 redraw = 1;
1516         }
1517         else
1518         if(cursor_y >= view_h + title_h + 4)
1519         {
1520                 yposition += cursor_y - (view_h + title_h + 4);
1521                 redraw = 1;
1522         }
1524         if(cursor_x < 2)
1525         {
1526                 xposition -= 2 - cursor_x;
1527                 redraw = 1;
1528         }
1529         else
1530         if(cursor_x >= view_w + 2)
1531         {
1532                 xposition += cursor_x - (view_w + 2);
1533                 redraw = 1;
1534         }
1539 int BC_ListBox::select_rectangle(ArrayList<BC_ListBoxItem*> *data,
1540                 int x1, 
1541                 int y1,
1542                 int x2, 
1543                 int y2)
1545         int result = 0;
1546         for(int i = 0; i < data[0].total; i++)
1547         {
1548                 for(int j = 0; j < columns; j++)
1549                 {
1550                         BC_ListBoxItem *item = data[j].values[i];
1551                         if(display_format == LISTBOX_ICONS)
1552                         {
1553                                 int icon_x, icon_y, icon_w, icon_h;
1554                                 int text_x, text_y, text_w, text_h;
1555                                 get_icon_mask(item, icon_x, icon_y, icon_w, icon_h);
1556                                 get_text_mask(item, text_x, text_y, text_w, text_h);
1558                                 if((x2 >= icon_x && x1 < icon_x + icon_w &&
1559                                         y2 >= icon_y && y1 < icon_y + icon_h) ||
1560                                         (x2 >= text_x && x1 < text_x + text_w &&
1561                                         y2 >= text_y && y1 < text_y + text_h))
1562                                 {
1563                                         if(!item->selected)
1564                                         {
1565                                                 item->selected = 1;
1566                                                 result = 1;
1567                                         }
1568                                 }
1569                                 else
1570                                 {
1571                                         if(item->selected)
1572                                         {
1573                                                 item->selected = 0;
1574                                                 result = 1;
1575                                         }
1576                                 }
1577                         }
1578                         else
1579                         {
1580                                 if(x2 >= 0 && 
1581                                         x1 < (yscrollbar ? 
1582                                                 gui->get_w() - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w() : 
1583                                                 gui->get_w()) &&
1584                                         y2 > 0 && 
1585                                         y1 < gui->get_h() &&
1586                                         y2 >= get_item_y(item) &&
1587                                         y1 < get_item_y(item) + get_item_h(item))
1588                                 {
1589                                         if(!item->selected)
1590                                         {
1591                                                 item->selected = 1;
1592                                                 result = 1;
1593                                         }
1594                                 }
1595                                 else
1596                                 {
1597                                         if(item->selected)
1598                                         {
1599                                                 item->selected = 0;
1600                                                 result = 1;
1601                                         }
1602                                 }
1603                         }
1604                 }
1606                 BC_ListBoxItem *item = data[0].values[i];
1607                 if(item->get_sublist() &&
1608                         item->get_expand())
1609                         result |= select_rectangle(item->get_sublist(),
1610                                 x1, 
1611                                 y1,
1612                                 x2, 
1613                                 y2);
1614         }
1615         return result;
1618 int BC_ListBox::reposition_item(ArrayList<BC_ListBoxItem*> *data,
1619                 int selection_number,
1620                 int x,
1621                 int y,
1622                 int *counter)
1624         int temp = -1;
1625         if(!counter) counter = &temp;
1628         for(int i = 0; i < data[0].total; i++)
1629         {
1630                 BC_ListBoxItem *item = data[0].values[i];
1631                 (*counter)++;
1632                 if((*counter) == selection_number)
1633                 {
1634                         item->icon_x = x;
1635                         item->icon_y = y;
1636                         return 1;
1637                 }
1638 // Not recursive because it's only used for icons
1639         }
1640         return 0;
1643 void BC_ListBox::move_selection(ArrayList<BC_ListBoxItem*> *dst,
1644         ArrayList<BC_ListBoxItem*> *src)
1646         for(int i = 0; i < src[0].total; i++)
1647         {
1648                 BC_ListBoxItem *item = src[0].values[i];
1650 // Move item to dst
1651                 if(item->selected)
1652                 {
1653                         for(int j = 0; j < columns; j++)
1654                         {
1655                                 dst[j].append(src[j].values[i]);
1656                                 src[j].remove_number(i);
1657                         }
1658                 }
1659                 else
1660 // Descend into sublist
1661                 if(item->get_sublist())
1662                 {
1663                         move_selection(dst, 
1664                                 item->get_sublist());
1665                 }
1666         }
1669 int BC_ListBox::put_selection(ArrayList<BC_ListBoxItem*> *data,
1670         ArrayList<BC_ListBoxItem*> *src,
1671         int destination,
1672         int *counter)
1674         int temp = -1;
1675         if(!counter) counter = &temp;
1677         if(destination < 0)
1678         {
1679                 for(int j = 0; j < columns; j++)
1680                 {
1681                         for(int i = 0; i < src[0].total; i++)
1682                         {
1683                                 data[j].append(src[j].values[i]);
1684                         }
1685                 }
1686                 return 1;
1687         }
1688         else
1689         for(int i = 0; i < data[0].total; i++)
1690         {
1691                 (*counter)++;
1692                 if((*counter) == destination)
1693                 {
1694                         for(int j = 0; j < columns; j++)
1695                         {
1696                                 for(int k = 0; k < src[0].total; k++)
1697                                 {
1698                                         data[j].insert(src[j].values[k], destination + k);
1699                                 }
1700                         }
1701                         return 1;
1702                 }
1704                 BC_ListBoxItem *item = data[0].values[i];
1705                 if(item->get_sublist())
1706                 {
1707                         if(put_selection(item->get_sublist(),
1708                                 src,
1709                                 destination,
1710                                 counter))
1711                                 return 1;
1712                 }
1713         }
1714         return 0;
1719 int BC_ListBox::item_to_index(ArrayList<BC_ListBoxItem*> *data,
1720                 BC_ListBoxItem *item,
1721                 int *counter)
1723         int temp = -1;
1724         if(!counter) counter = &temp;
1726         for(int i = 0; i < data[0].total; i++)
1727         {
1728                 (*counter)++;
1729                 for(int j = 0; j < columns; j++)
1730                 {
1731                         BC_ListBoxItem *new_item = data[j].values[i];
1732                         if(new_item == item)
1733                         {
1734                                 return (*counter);
1735                         }
1736                 }
1738                 BC_ListBoxItem *new_item = data[0].values[i];
1739                 if(new_item->get_sublist())
1740                 {
1741                         if(item_to_index(new_item->get_sublist(),
1742                                 item,
1743                                 counter) >= 0)
1744                                 return (*counter);
1745                 }
1746         }
1747         return -1;
1750 BC_ListBoxItem* BC_ListBox::index_to_item(ArrayList<BC_ListBoxItem*> *data,
1751                 int number,
1752                 int column,
1753                 int *counter)
1755         int temp = -1;
1756         if(!counter) counter = &temp;
1757         for(int i = 0; i < data[0].total; i++)
1758         {
1759                 (*counter)++;
1760                 if((*counter) == number)
1761                 {
1762                         return data[column].values[i];
1763                 }
1764                 BC_ListBoxItem *item = data[0].values[i];
1765                 if(item->get_sublist())
1766                 {
1767                         BC_ListBoxItem *result = index_to_item(item->get_sublist(),
1768                                 number,
1769                                 column,
1770                                 counter);
1771                         if(result) return result;
1772                 }
1773         }
1774         return 0;
1777 int BC_ListBox::cursor_item(ArrayList<BC_ListBoxItem*> *data,
1778         int cursor_x, 
1779         int cursor_y, 
1780         BC_ListBoxItem **item_return,
1781         int *counter,
1782         int expanded)
1784         int temp = -1;
1785         if(!data) return -1;
1786         if(!counter) counter = &temp;
1788 // Icons are not treed
1789         if(display_format == LISTBOX_ICONS)
1790         {
1791                 for(int j = data[0].total - 1; j >= 0; j--)
1792                 {
1793                         int icon_x, icon_y, icon_w, icon_h;
1794                         int text_x, text_y, text_w, text_h;
1795                         BC_ListBoxItem *item = data[0].values[j];
1796                         get_icon_mask(item, icon_x, icon_y, icon_w, icon_h);
1797                         get_text_mask(item, text_x, text_y, text_w, text_h);
1799                         if((cursor_x >= icon_x && cursor_x < icon_x + icon_w &&
1800                                 cursor_y >= icon_y && cursor_y < icon_y + icon_h) ||
1801                                 (cursor_x >= text_x && cursor_x < text_x + text_w &&
1802                                 cursor_y >= text_y && cursor_y < text_y + text_h))
1803                         {
1804                                 if(item_return) (*item_return) = item;
1805                                 return j;
1806                         }
1807                 }
1808         }
1809         else
1810 // Text is treed
1811         if(display_format == LISTBOX_TEXT)
1812         {
1813 // Cursor is inside item rectangle
1814                 if(cursor_x >= 0 && 
1815                         cursor_x < (yscrollbar ? 
1816                                 gui->get_w() - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w() : 
1817                                 gui->get_w()) &&
1818                         cursor_y > 0 && 
1819                         cursor_y < gui->get_h())
1820                 {
1821 // Search table for cursor obstruction
1822                         for(int i = 0; i < data[0].total; i++)
1823                         {
1824                                 BC_ListBoxItem *item = data[0].values[i];
1825                                 (*counter)++;
1827 // Cursor is inside item on current level
1828                                 if(expanded &&
1829                                         item->selectable &&
1830                                         cursor_y >= get_item_y(item) &&
1831                                         cursor_y < get_item_y(item) + get_item_h(item))
1832                                 {
1833                                         if(item_return) (*item_return) = item;
1834                                         return (*counter);
1835                                 }
1837 // Descend into sublist
1838                                 if(item->get_sublist())
1839                                 {
1840                                         if(cursor_item(item->get_sublist(),
1841                                                 cursor_x, 
1842                                                 cursor_y, 
1843                                                 item_return,
1844                                                 counter,
1845                                                 item->get_expand()) >= 0)
1846                                                 return (*counter);
1847                                 }
1848                         }
1849                 }
1850         }
1851         return -1;
1854 int BC_ListBox::repeat_event(int64_t duration)
1856         if(duration == top_level->get_resources()->tooltip_delay &&
1857                 tooltip_text[0] != 0 &&
1858                 popup &&
1859                 status == LISTBOX_HIGH &&
1860                 !tooltip_done)
1861         {
1862                 show_tooltip();
1863                 tooltip_done = 1;
1864                 return 1;
1865         }
1866         return 0;
1870 int BC_ListBox::cursor_enter_event()
1872         int result = 0;
1873         
1874 //      if(active) result = 1;
1876         if(popup)
1877         {
1878                 if(top_level->event_win == win)
1879                 {
1880                         tooltip_done = 0;
1881                         if(top_level->button_down)
1882                         {
1883                                 status = LISTBOX_DN;
1884                         }
1885                         else
1886                         if(status == LISTBOX_UP)
1887                         {
1888                                 status = LISTBOX_HIGH;
1889                         }
1890 //printf("BC_ListBox::cursor_enter_event 1\n");
1891                         draw_face();
1892                         result = 1;
1893                 }
1894         }
1896         if(gui && top_level->event_win == gui->win)
1897         {
1898                 if(!highlighted)
1899                 {
1900 //printf("BC_ListBox::cursor_enter_event 2\n");
1901                         highlighted = 1;
1902                         draw_border();
1903 //                      flash();
1904                 }
1905                 result = 1;
1906         }
1907         return result;
1910 int BC_ListBox::cursor_leave_event()
1912         if(popup)
1913         {
1914                 hide_tooltip();
1915                 if(status == LISTBOX_HIGH)
1916                 {
1917                         status = LISTBOX_UP;
1918                         draw_face();
1919                 }
1920         }
1922         if(gui && highlighted)
1923         {
1924                 highlighted = 0;
1925                 if(highlighted_ptr) 
1926                 {
1927                         highlighted_ptr = 0;
1928                         highlighted_item = -1;
1929                         draw_items();
1930                 }
1931                 else
1932                         draw_border();
1933                 gui->flash();
1934         }
1935         return 0;
1938 int BC_ListBox::get_first_selection(ArrayList<BC_ListBoxItem*> *data, int *result)
1940         int temp = -1;
1941         if(!result) result = &temp;
1943         for(int i = 0; i < data[0].total; i++)
1944         {
1945                 BC_ListBoxItem *item = data[0].values[i];
1946                 (*result)++;
1947                 if(item->selected) return (*result);
1948                 if(item->get_sublist())
1949                 {
1950                         if(get_first_selection(item->get_sublist(), result) >= 0)
1951                                 return (*result);
1952                 }
1953         }
1954         return -1;
1957 int BC_ListBox::get_total_items(ArrayList<BC_ListBoxItem*> *data, int *result)
1959         int temp = 0;
1960         if(!result) result = &temp;
1962         for(int i = 0; i < data[0].total; i++)
1963         {
1964                 (*result)++;
1965                 if(data[0].values[i]->get_sublist())
1966                         get_total_items(data[0].values[i]->get_sublist(), result);
1967         }
1969         return (*result);
1973 int BC_ListBox::get_last_selection(ArrayList<BC_ListBoxItem*> *data, int *result)
1975         int temp = -1;
1976         int top_level = 0;
1977         if(!result)
1978         {
1979                 result = &temp;
1980                 top_level = 1;
1981         }
1983         for(int i = data[0].total - 1; i >= 0; i--)
1984         {
1985                 BC_ListBoxItem *item = data[0].values[i];
1986                 (*result)++;
1987                 if(item->selected)
1988                 {
1989                         if(top_level)
1990                                 return get_total_items(data) - (*result) /* - 1 */;
1991                         else
1992                                 return (*result);
1993                 }
1995                 if(item->get_sublist())
1996                 {
1997                         if(get_last_selection(item->get_sublist(), result) >= 0)
1998                         {
1999                                 if(top_level)
2000                                         return get_total_items(data) - (*result) /* - 1 */;
2001                                 else
2002                                         return (*result);
2003                         }
2004                 }
2005         }
2006         return -1;
2009 void BC_ListBox::select_range(ArrayList<BC_ListBoxItem*> *data,
2010                 int start,
2011                 int end,
2012                 int *current)
2014         int temp = -1;
2015         if(!current) current = &temp;
2017         for(int i = 0; i < data[0].total; i++)
2018         {
2019                 (*current)++;
2020                 if((*current) >= start && (*current) < end)
2021                 {
2022                         for(int j = 0; j < columns; j++)
2023                                 data[j].values[i]->selected = 1;
2024                 }
2025                 BC_ListBoxItem *item = data[0].values[i];
2026                 if(item->get_sublist())
2027                         select_range(item->get_sublist(),
2028                                 start,
2029                                 end,
2030                                 current);
2031         }
2035 // Fill items between current selection and new selection
2036 int BC_ListBox::expand_selection(int button_press, int selection_number)
2038         int old_selection_start = selection_start;
2039         int old_selection_end = selection_end;
2041 //printf("BC_ListBox::expand_selection %d %d\n", selection_center, selection_number);
2043 // Calculate the range to select based on selection_center and selection_number
2044         if(selection_number < selection_center)
2045         {
2046                 selection_start = selection_number;
2047         }
2048         else
2049         {
2050                 selection_end = selection_number + 1;
2051         }
2053 //printf("BC_ListBox::expand_selection %d %d %d %d\n", old_selection_start, old_selection_end, selection_start, selection_end);
2054 // Recurse through all the items and select the desired range
2055         select_range(data, selection_start, selection_end);
2057 // Trigger redraw
2058         return (old_selection_start != selection_start ||
2059                 old_selection_end != selection_end);
2062 int BC_ListBox::toggle_item_selection(ArrayList<BC_ListBoxItem*> *data,
2063         int selection_number,
2064         int *counter)
2066         int temp = -1;
2067         if(!counter) counter = &temp;
2069         for(int i = 0; i < data[0].total; i++)
2070         {
2071                 BC_ListBoxItem *item = data[0].values[i];
2072                 (*counter)++;
2073                 if((*counter) == selection_number)
2074                 {
2075 // Get new value for selection
2076                         int selected = !item->selected;
2077 // Set row
2078                         for(int j = 0; j < columns; j++)
2079                                 data[j].values[i]->selected = selected;
2080                         return 1;
2081                 }
2083 // Descend into sublist
2084                 if(item->get_sublist())
2085                 {
2086                         if(toggle_item_selection(item->get_sublist(),
2087                                 selection_number,
2088                                 counter))
2089                                 return 1;
2090                 }
2091         }
2093         return 0;
2097 void BC_ListBox::set_all_selected(ArrayList<BC_ListBoxItem*> *data, int value)
2099         for(int i = 0; i < data[0].total; i++)
2100         {
2101                 for(int j = 0; j < columns; j++)
2102                 {
2103                         BC_ListBoxItem *item = data[j].values[i];
2104                         item->selected = value;
2105                 }
2106                 BC_ListBoxItem *item = data[0].values[i];
2107                 if(item->get_sublist())
2108                 {
2109                         set_all_selected(item->get_sublist(), value);
2110                 }
2111         }
2114 void BC_ListBox::set_selected(ArrayList<BC_ListBoxItem*> *data, 
2115                 int item_number, 
2116                 int value,
2117                 int *counter)
2119         int temp = -1;
2120         if(!counter) counter = &temp;
2121         for(int i = 0; i < data[0].total && (*counter) != item_number; i++)
2122         {
2123                 (*counter)++;
2124                 if((*counter) == item_number)
2125                 {
2126                         for(int j = 0; j < columns; j++)
2127                         {
2128                                 BC_ListBoxItem *item = data[j].values[i];
2129                                 item->selected = value;
2130                         }
2131                         return;
2132                 }
2134                 BC_ListBoxItem *item = data[0].values[i];
2135                 if(item->get_sublist())
2136                 {
2137                         set_selected(item->get_sublist(), 
2138                                 item_number, 
2139                                 value,
2140                                 counter);
2141                 }
2142         }
2145 int BC_ListBox::update_selection(ArrayList<BC_ListBoxItem*> *data, 
2146         int selection_number,
2147         int *counter)
2149         int temp = -1;
2150         int result = 0;
2151         if(!counter) counter = &temp;
2153         for(int i = 0; i < data[0].total; i++)
2154         {
2155                 BC_ListBoxItem *item = data[0].values[i];
2156                 (*counter)++;
2157                 if((*counter) == selection_number && !item->selected)
2158                 {
2159                         result = 1;
2160                         for(int j = 0; j < columns; j++)
2161                                 data[j].values[i]->selected = 1;
2162                 }
2163                 else
2164                 if((*counter) != selection_number && item->selected)
2165                 {
2166                         result = 1;
2167                         for(int j = 0; j < columns; j++)
2168                                 data[j].values[i]->selected = 0;
2169                 }
2170                 if(item->get_sublist())
2171                         result |= update_selection(item->get_sublist(), 
2172                                 selection_number,
2173                                 counter);
2174         }
2175         return result;
2178 void BC_ListBox::promote_selections(ArrayList<BC_ListBoxItem*> *data,
2179         int old_value,
2180         int new_value)
2182         for(int i = 0; i < data[0].total; i++)
2183         {
2184                 for(int j = 0; j < columns; j++)
2185                 {
2186                         BC_ListBoxItem *item = data[j].values[i];
2187                         if(item->selected == old_value) item->selected = new_value;
2188                 }
2189                 BC_ListBoxItem *item = data[0].values[i];
2190                 if(item->get_sublist())
2191                         promote_selections(item->get_sublist(), old_value, new_value);
2192         }
2195 int BC_ListBox::button_press_event()
2197         int redraw = 0;
2198         int result = 0;
2200         selection_number = -1;
2201         hide_tooltip();
2202         if(popup)
2203         {
2204                 if(top_level->event_win == win)
2205                 {
2206                         status = LISTBOX_DN;
2207                         draw_face();
2208 // Deploy listbox
2209                         if(!active)
2210                         {
2211                                 top_level->deactivate();
2212                                 activate();
2213                         }
2215                         result = 1;
2216                 }
2217                 else
2218                 if((xscrollbar && top_level->event_win == xscrollbar->win) ||
2219                         (yscrollbar && top_level->event_win == yscrollbar->win) ||
2220                         (gui && top_level->event_win == gui->win))
2221                 {
2222                         result = 0;
2223                 }
2224                 else
2225                 if(active)
2226                 {
2227                         deactivate();
2228                         result = 1;
2229                 }
2230         }
2232         if(gui && top_level->event_win == gui->win)
2233         {
2234                 if(!active)
2235                 {
2236                         top_level->deactivate();
2237                         activate();
2238                 }
2240 // Wheel mouse behavior
2241                 if(get_buttonpress() == 4)
2242                 {
2243                         current_operation = BCLISTBOX_WHEEL;
2244                         if(yscrollbar)
2245                         {
2246                                 set_yposition(yposition - gui->get_h() / 10, 0);
2247                                 fix_positions();
2248                                 update_scrollbars();
2249                                 highlighted_ptr = 0;
2250                                 highlighted_item = cursor_item(data,
2251                                         top_level->cursor_x, 
2252                                         top_level->cursor_y, 
2253                                         &highlighted_ptr);
2254                                 draw_items();
2255                                 gui->flash();
2256                                 result = 1;
2257                         }
2258                 }
2259                 else
2260                 if(get_buttonpress() == 5)
2261                 {
2262                         current_operation = BCLISTBOX_WHEEL;
2263                         if(yscrollbar)
2264                         {
2265                                 set_yposition(yposition + gui->get_h() / 10, 0);
2266                                 fix_positions();
2267                                 update_scrollbars();
2268                                 highlighted_ptr = 0;
2269                                 highlighted_item = cursor_item(data,
2270                                         top_level->cursor_x, 
2271                                         top_level->cursor_y,
2272                                         &highlighted_ptr);
2273                                 draw_items();
2274                                 gui->flash();
2275                                 result = 1;
2276                         }
2277                 }
2278                 else
2279                 {
2280 // Get item button was pressed over
2281                         int new_cursor;
2282                         BC_ListBoxItem *current_item = 0;
2283                         selection_number2 = selection_number1;
2284                         selection_number1 = selection_number = cursor_item(data, 
2285                                         top_level->cursor_x, 
2286                                         top_level->cursor_y,
2287                                         &current_item);
2289 // Pressed over a title division
2290                         if(test_divisions(gui->get_cursor_x(), 
2291                                 gui->get_cursor_y(), 
2292                                 new_cursor))
2293                         {
2294                                 current_operation = BCLISTBOX_DRAG_DIVISION;
2295                                 reset_query();
2296                         }
2297                         else
2298 // Pressed over an item
2299                         if(current_item)
2300                         {
2301                                 selection_start = -1;
2302                                 selection_end = -1;
2305 // Multiple item selection is possible
2306                                 if(selection_mode == LISTBOX_MULTIPLE && 
2307                                         (ctrl_down() || shift_down()))
2308                                 {
2309 // Expand text selection.
2310 // Fill items between selected region and current item.
2311                                         if(shift_down() && display_format == LISTBOX_TEXT)
2312                                         {
2313 // Get first item selected
2314                                                 selection_start = get_first_selection(data);
2315 // Get last item selected
2316                                                 selection_end = get_last_selection(data);
2317 // Get center of selected region
2318                                                 if(selection_end > selection_start)
2319                                                 {
2320                                                         selection_center = (selection_end + selection_start) >> 1;
2321                                                 }
2322                                                 else
2323                                                 {
2324                                                         selection_center = selection_number;
2325                                                 }
2328 // Deselect everything.
2329                                                 set_all_selected(data, 0);
2330 // Select just the items
2331                                                 expand_selection(1, selection_number);
2332                                                 new_value = 1;
2333                                         }
2334                                         else
2335 // Toggle a single item on or off
2336                                         {
2337                                                 toggle_item_selection(data, selection_number);
2338                                                 new_value = current_item->selected;
2339                                         }
2340                                         current_operation = BCLISTBOX_SELECT;
2341                                 }
2342                                 else
2343 // Select single item
2344                                 {
2345                                         if(!current_item->selected)
2346                                         {
2347                                                 set_all_selected(data, 0);
2348                                                 set_selected(data,
2349                                                         selection_number,
2350                                                         1);
2351                                                 new_value = 1;
2352                                                 current_operation = BCLISTBOX_SELECT;
2353                                         }
2354                                 }
2357                                 highlighted_item = -1;
2358                                 highlighted_ptr = 0;
2359                                 reset_query();
2360                                 redraw = 1;
2361                                 result = 1;
2362                         }
2363                         else
2364                         if(data)
2365 // Pressed over nothing
2366                         {
2367                                 if(get_buttonpress() == 1 && 
2368                                         selection_mode == LISTBOX_MULTIPLE)
2369                                 {
2370                                         if(!shift_down())
2371                                         {
2372 // Deselect all and redraw if anything was selected
2373                                                 if(get_selection_number(0, 0) >= 0)
2374                                                 {
2375                                                         set_all_selected(data, 0);
2376                                                         redraw = 1;
2377                                                         result = 1;
2378                                                 }
2379                                         }
2380                                         else
2381                                         {
2382 // Promote selections to protect from a rectangle selection
2383                                                 promote_selections(data, 1, 2);
2384                                         }
2386 // Start rectangle selection
2387                                         current_operation = BCLISTBOX_SELECT_RECT;
2388                                         rect_x1 = rect_x2 = get_cursor_x();
2389                                         rect_y1 = rect_y2 = get_cursor_y();
2390                                 }
2391                         }
2392                 }
2393                 reset_query();
2394         }
2395         else
2396         if(!popup && active)
2397         {
2398                 deactivate();
2399         }
2402         if(redraw)
2403         {
2404                 draw_items();
2405                 gui->flash();
2406                 selection_changed();
2407         }
2409         return result;
2412 int BC_ListBox::button_release_event()
2414         int result = 0;
2415         int cursor_x, cursor_y;
2416         new_value = 0;
2418         if(current_operation == BCLISTBOX_WHEEL)
2419         {
2420                 current_operation = BCLISTBOX_NO_OPERATION;
2421                 return 1;
2422         }
2424         if(current_operation == BCLISTBOX_SELECT_RECT)
2425         {
2426                 if(data)
2427                 {
2428 // Demote selections from rectangle selection
2429                         promote_selections(data, 2, 1);
2430                 }
2432 // Hide rectangle overlay
2433                 draw_rectangle();
2434                 gui->flash();
2435                 gui->flush();
2436         }
2438         current_operation = BCLISTBOX_NO_OPERATION;
2440 // Popup window
2441         if(popup)
2442         {
2443                 hide_tooltip();
2444                 button_releases++;
2445                 if(status == LISTBOX_DN)
2446                 {
2447                         status = LISTBOX_HIGH;
2448                         draw_face();
2449                         result = 1;
2450                 }
2452 // Second button release inside button
2453                 if(top_level->event_win == win && 
2454                         cursor_inside() && 
2455                         button_releases > 1)
2456                 {
2457                         deactivate();
2458                         result = 1;
2459                 }
2460 // First button release inside button
2461                 else
2462                 if(top_level->event_win == win && cursor_inside())
2463                 {
2464                         result = 1;
2465                 }
2466 // Button released in popup window
2467                 else
2468                 if(gui && 
2469                         (top_level->event_win == win || top_level->event_win == gui->win))
2470                 {
2471                         Window tempwin;
2472                         XTranslateCoordinates(top_level->display, 
2473                                 top_level->event_win, 
2474                                 gui->win, 
2475                                 top_level->cursor_x, 
2476                                 top_level->cursor_y, 
2477                                 &cursor_x, 
2478                                 &cursor_y, 
2479                                 &tempwin);
2481                         selection_number = cursor_item(data,
2482                                 cursor_x, 
2483                                 cursor_y);
2485                         if(selection_number >= 0)
2486                         {
2487                                 handle_event();
2488                         }
2489                         deactivate();
2490                         result = 1;
2491                 }
2492 // Button release outside all ranges
2493                 else
2494                 if(active)
2495                 {
2496                         deactivate();
2497                         result = 1;
2498                 }
2499         }
2500         else
2501 // No popup window
2502         if(gui &&
2503                 top_level->event_win == gui->win &&
2504                 top_level->get_double_click() &&
2505                 selection_number2 == selection_number1 &&
2506                 selection_number2 >= 0 &&
2507                 selection_number1 >= 0)
2508         {
2509                 handle_event();
2510                 result = 1;
2511         }
2513         return result;
2516 int BC_ListBox::get_title_h()
2518         if(display_format != LISTBOX_ICONS)
2519                 return column_titles ? (get_text_height(MEDIUMFONT) + 4) : 0;
2520         else
2521                 return 0;
2524 void BC_ListBox::reset_cursor(int new_cursor)
2526         if(popup)
2527         {
2528                 if(gui->get_cursor() != new_cursor)
2529                 {
2530                         gui->set_cursor(new_cursor);
2531                 }
2532         }
2533         else
2534         if(get_cursor() != new_cursor)
2535         {
2536                 set_cursor(new_cursor);
2537         }
2540 int BC_ListBox::test_divisions(int cursor_x, int cursor_y, int &new_cursor)
2542         if(column_titles && cursor_y < get_title_h())
2543         {
2544                 for(int i = 1; i < columns; i++)
2545                 {
2546                         if(cursor_x > -xposition + get_column_offset(i) - 5 &&
2547                                 cursor_x <  -xposition + get_column_offset(i) + 5)
2548                         {
2549                                 highlighted_division = i;
2550                                 new_cursor = HSEPARATE_CURSOR;
2551                                 return 1;
2552                         }
2553                 }
2554         }
2555         return 0;
2558 int BC_ListBox::cursor_motion_event()
2560         int redraw = 0, result = 0;
2561         int cursor_x = 0, cursor_y = 0;
2562         int new_cursor = ARROW_CURSOR;
2564         selection_number = -1;
2566         if(popup && 
2567                 top_level->event_win == win && 
2568                 status == LISTBOX_DN && 
2569                 !cursor_inside())
2570         {
2571                 status = LISTBOX_UP;
2572                 draw_face();
2573         }
2575         if(gui && 
2576                 (top_level->event_win == win || 
2577                 (popup && top_level->event_win == gui->win)))
2578         {
2580 // For some reason XTranslateCoordinates can take a long time to return.
2581 // We work around this by only calling it when the event windows are different.
2582                 translate_coordinates(top_level->event_win, 
2583                         gui->win,
2584                         top_level->cursor_x,
2585                         top_level->cursor_y,
2586                         &cursor_x,
2587                         &cursor_y);
2589                 result = 1;
2590                 int old_highlighted_item = highlighted_item;
2591                 BC_ListBoxItem *old_highlighted_ptr = highlighted_ptr;
2592                 highlighted_item = -1;
2593                 highlighted_ptr = 0;
2594                 highlighted_item = selection_number = cursor_item(data, 
2595                         cursor_x, 
2596                         cursor_y,
2597                         &highlighted_ptr);
2599 //printf("BC_ListBox::cursor_motion_event %p %p\n", old_highlighted_item, highlighted_item);
2601 // Cursor just moved in after pressing popup button
2602                 if(popup && 
2603                         top_level->get_button_down() && 
2604                         selection_number >= 0 && current_operation != BCLISTBOX_SELECT) 
2605                         current_operation = BCLISTBOX_SELECT;
2607 // Moving column division
2608                 if(current_operation == BCLISTBOX_DRAG_DIVISION && 
2609                         top_level->get_button_down())
2610                 {
2611                         new_cursor = HSEPARATE_CURSOR;
2612                         int new_w = cursor_x + xposition - get_column_offset(highlighted_division - 1);
2613 //printf("BC_ListBox::cursor_motion_event 1 %d\n", new_w);
2615                         if(column_width)
2616                         {
2617                                 column_width[highlighted_division - 1] = new_w;
2618                         }
2619                         else
2620                         {
2621                                 default_column_width[highlighted_division - 1] = new_w;
2622                         }
2624                         column_width_boundaries();
2626 // Force update of coords
2627                         set_autoplacement(data, 0, 1);
2628                         column_resize_event();
2630                         redraw = 1;
2631                 }
2632                 else
2633 // Cursor is inside and selecting an item
2634                 if(selection_number >= 0 && 
2635                         current_operation == BCLISTBOX_SELECT &&
2636                         !allow_drag)
2637                 {
2638 // Deselect all items and select just the one we're over
2639                         if(selection_mode == LISTBOX_SINGLE ||
2640                                 (!shift_down() && 
2641                                         !ctrl_down()))
2642                         {
2643                                 redraw = update_selection(data, selection_number);
2644                         }
2645                         else
2646 // Expand multiple selection
2647                         {
2648 // Expand selected region in text mode centered around initial range
2649                                 if(display_format == LISTBOX_TEXT && shift_down())
2650                                 {
2651 // Deselect everything.
2652                                         set_all_selected(data, 0);
2653 // Select just the items
2655                                         redraw = expand_selection(0, selection_number);
2656                                 }
2657                                 else
2658 // Set the one item we're over to the selection value determined in
2659 // button_press_event.
2660                                 {
2661                                         set_selected(data, 
2662                                                 selection_number, 
2663                                                 new_value);
2664                                 }
2665                         }
2666                 }
2667                 else
2668                 if(current_operation == BCLISTBOX_SELECT_RECT)
2669                 {
2670                         draw_rectangle();
2671                         rect_x2 = get_cursor_x();
2672                         rect_y2 = get_cursor_y();
2673 // Adjust rectangle coverage
2674                         if(data)
2675                         {
2676                                 int x1 = MIN(rect_x1, rect_x2);
2677                                 int x2 = MAX(rect_x1, rect_x2);
2678                                 int y1 = MIN(rect_y1, rect_y2);
2679                                 int y2 = MAX(rect_y1, rect_y2);
2681                                 redraw = select_rectangle(data,
2682                                         x1, 
2683                                         y1,
2684                                         x2, 
2685                                         y2);
2687                         }
2689 // Refresh just rectangle
2690                         if(!redraw)
2691                         {
2692                                 draw_rectangle();
2693                                 flash();
2694                                 flush();
2695                         }
2696                 }
2697                 else
2698 // Test if cursor moved over a title division
2699                 {
2700                         test_divisions(cursor_x, cursor_y, new_cursor);
2701                 }
2703                 if(top_level->get_button_down() && 
2704                         current_operation == BCLISTBOX_SELECT)
2705                 {
2706                         test_drag_scroll(redraw, cursor_x, cursor_y);
2707                 }
2708                 else
2709                 if(highlighted_item != old_highlighted_item)
2710                 {
2711                         redraw = 1;
2712                 }
2715 // Change cursor to title division adjustment
2716                 reset_cursor(new_cursor);
2718         }
2721 //printf("BC_ListBox::cursor_motion_event 50 %d %d %p\n", redraw, result, highlighted_item);
2724         if(redraw)
2725         {
2726                 fix_positions();
2727                 draw_items();
2728                 update_scrollbars();
2729                 gui->flash();
2730                 gui->flush();
2731                 if(current_operation == BCLISTBOX_SELECT) selection_changed();
2732                 result = 1;
2733         }
2734         else
2735         if(!result && highlighted_item >= 0)
2736         {
2737                 highlighted_item = -1;
2738                 highlighted_ptr = 0;
2739                 draw_items();
2740                 gui->flash();
2741                 gui->flush();
2742                 result = 0;
2743         }
2745 //printf("BC_ListBox::cursor_motion_event 100\n");
2746         return result;
2749 int BC_ListBox::drag_start_event()
2751         if(gui && 
2752                 top_level->event_win == gui->win && 
2753                 allow_drag && 
2754                 current_operation != BCLISTBOX_DRAG_DIVISION)
2755         {
2756                 BC_ListBoxItem *item_return = 0;
2757                 selection_number = cursor_item(data, 
2758                         top_level->cursor_x, 
2759                         top_level->cursor_y,
2760                         &item_return);
2762                 if(selection_number >= 0)
2763                 {
2764                         BC_Pixmap *pixmap = item_return->icon ? 
2765                                 item_return->icon : 
2766                                 drag_icon;
2767                         drag_popup = new BC_DragWindow(this, 
2768                                 pixmap, 
2769                                 get_abs_cursor_x() - pixmap->get_w() / 2,
2770                                 get_abs_cursor_y() - pixmap->get_h() / 2);
2771                         return 1;
2772                 }
2773         }
2774         return 0;
2777 int BC_ListBox::drag_motion_event()
2779         if(drag_popup)
2780         {
2781                 int redraw = 0;
2782                 test_drag_scroll(redraw, 
2783                         top_level->cursor_x, 
2784                         top_level->cursor_y);
2786                 int new_highlighted_item = -1;
2787                 BC_ListBoxItem *new_highlighted_ptr = 0;
2788                 int new_highlight = new_highlighted_item = cursor_item(data,
2789                         top_level->cursor_x, 
2790                         top_level->cursor_y,
2791                         &new_highlighted_ptr);
2793 //printf("BC_ListBox::drag_motion_event %d %d %d\n", 
2794 //      top_level->cursor_x, top_level->cursor_y, new_highlight);
2795                 if(new_highlighted_item != highlighted_item)
2796                 {
2797                         redraw = 1;
2798                         highlighted_item = new_highlighted_item;
2799                         highlighted_ptr = new_highlighted_ptr;
2800                 }
2802                 if(redraw)
2803                 {
2804                         fix_positions();
2805                         draw_items();
2806                         update_scrollbars();
2807                         gui->flash();
2808                 }
2810                 return drag_popup->cursor_motion_event();
2811                 return 1;
2812         }
2813         return 0;
2816 int BC_ListBox::drag_stop_event()
2818         if(drag_popup)
2819         {
2820 // Inside window boundary
2821                 if(top_level->cursor_x > 0 && 
2822                         top_level->cursor_x < gui->get_w() - drag_popup->get_w() / 2 && 
2823                         top_level->cursor_y > 0 &&
2824                         top_level->cursor_y < gui->get_h() - drag_popup->get_h() / 2)
2825                 {
2826 // Move icon
2829                         if(display_format == LISTBOX_ICONS)
2830                         {
2831                                 reposition_item(data, 
2832                                         selection_number, 
2833                                         top_level->cursor_x + 
2834                                                 drag_popup->get_offset_x() - 
2835                                                 LISTBOX_MARGIN - 
2836                                                 2 + 
2837                                                 xposition,
2838                                         top_level->cursor_y + 
2839                                                 drag_popup->get_offset_y() - 
2840                                                 LISTBOX_MARGIN - 
2841                                                 2 + 
2842                                                 yposition);
2843                         }
2844                         else
2845 // Move rows
2846                         {
2847 // Move selected items from data to temporary
2848                                 ArrayList<BC_ListBoxItem*> *src_items = 
2849                                         new ArrayList<BC_ListBoxItem*>[columns];
2850                                 move_selection(src_items, data);
2852 // Insert items from temporary to data
2853                                 int destination = highlighted_item = item_to_index(data,
2854                                         highlighted_ptr);
2855                                 put_selection(data,
2856                                         src_items,
2857                                         destination);
2860                                 delete [] src_items;                            
2861                                 set_autoplacement(data, 0, 1);
2862                         }
2863                         
2864                         
2865                         draw_items();
2866                         gui->flash();
2867                 }
2868                 else
2869                         drag_popup->drag_failure_event();
2871                 delete drag_popup;
2872                 drag_popup = 0;
2873                 current_operation = BCLISTBOX_NO_OPERATION;
2874                 new_value = 0;
2875                 return 1;
2876         }
2877         return 0;
2880 BC_DragWindow* BC_ListBox::get_drag_popup()
2882         return drag_popup;
2885 int BC_ListBox::translation_event()
2887         if(popup && gui)
2888         {
2889                 int new_x = gui->get_x() + 
2890                         (top_level->last_translate_x - 
2891                                 top_level->prev_x - 
2892                                 top_level->get_resources()->get_left_border());
2893                 int new_y = gui->get_y() + 
2894                         (top_level->last_translate_y - 
2895                                 top_level->prev_y -
2896                                 top_level->get_resources()->get_top_border());
2898                 gui->reposition_window(new_x, new_y);
2899                 
2900         }
2901         return 0;
2904 int BC_ListBox::reposition_window(int x, int y, int w, int h)
2906         if(w != -1)
2907         {
2908                 if(w != -1) popup_w = w;
2909                 if(h != -1) popup_h = h;
2910 //printf("BC_ListBox::reposition_window %d %d\n", popup_w, popup_h);
2912                 if(!popup)
2913                 {
2914                         if(w != -1) popup_w = w;
2915                         if(h != -1) popup_h = h;
2916                         if(xscrollbar)
2917                                 xscrollbar->reposition_window(get_xscroll_x(), 
2918                                         get_xscroll_y(), 
2919                                         get_xscroll_width());
2920                         if(yscrollbar)
2921                                 yscrollbar->reposition_window(get_yscroll_x(), 
2922                                         get_yscroll_y(), 
2923                                         get_yscroll_height());
2924                 }
2925         }
2928         BC_WindowBase::reposition_window(x, y, w, h);
2929         draw_face();
2930         draw_items();
2931         flash();
2932         return 0;
2935 int BC_ListBox::deactivate()
2937         if(active)
2938         {
2939                 active = 0;
2940                 if(popup)
2941                 {
2942                         if(gui) delete gui;
2943                         xscrollbar = 0;
2944                         yscrollbar = 0;
2945                         gui = 0;
2946                         highlighted_item = -1;
2947                         highlighted_ptr = 0;
2948                 }
2949                 top_level->active_subwindow = 0;
2950         }
2951         return 0;
2954 int BC_ListBox::activate()
2956         if(!active)
2957         {
2958                 top_level->active_subwindow = this;
2959                 active = 1;
2960                 button_releases = 0;
2962                 if(popup)
2963                 {
2964                         Window tempwin;
2965                         int new_x, new_y;
2966                         XTranslateCoordinates(top_level->display, 
2967                                 parent_window->win, 
2968                                 top_level->rootwin, 
2969                                 get_x() - popup_w + get_w(), 
2970                                 get_y() + get_h(), 
2971                                 &new_x, 
2972                                 &new_y, 
2973                                 &tempwin);
2975                         if(new_x < 0) new_x = 0;
2976                         if(new_y + popup_h > top_level->get_root_h()) new_y -= get_h() + popup_h;
2978 //printf("BC_ListBox::activate %d %d\n", popup_w, popup_h);
2979                         add_subwindow(gui = new BC_Popup(this, 
2980                                 new_x, 
2981                                 new_y, 
2982                                 popup_w, 
2983                                 popup_h, 
2984                                 -1,
2985                                 0,
2986                                 0));
2987                         draw_items();
2988 //printf("BC_ListBox::activate 1\n");
2989                         gui->flash();
2990                 }
2991         }
2992         return 0;
2995 int BC_ListBox::keypress_event()
2997         if(!active) return 0;
2998         
2999         int result = 0, redraw = 0, done, view_items = view_h / get_text_height(MEDIUMFONT);
3000         int new_item = -1, new_selection = 0;
3002         switch(top_level->get_keypress())
3003         {
3004                 case ESC:
3005                 case RETURN:
3006                         top_level->deactivate();
3007                         result = 0;
3008                         break;
3010                 case UP:
3011                         new_selection = new_item = select_previous(0);
3013 //printf("BC_ListBox::keypress_event 1 %d\n", new_item);
3014                         if(new_item >= 0)
3015                         {
3016                                 center_selection(new_item);
3017                                 redraw = 1;
3018                         }
3019                         result = 1;
3020                         break;
3022                 case DOWN:
3023                         new_selection = new_item = select_next(0);
3025                         if(new_item >= 0)
3026                         {
3027                                 center_selection(new_item);
3028                                 redraw = 1;
3029                         }
3030                         result = 1;
3031                         break;
3033                 case PGUP:
3034                         new_selection = new_item = select_previous(view_items - 1);
3036                         if(new_item >= 0)
3037                         {
3038                                 center_selection(new_item);
3039                                 redraw = 1;
3040                         }
3041                         result = 1;
3042                         break;
3044                 case PGDN:
3045                         new_selection = new_item = select_next(view_items - 1);
3047                         if(new_item >= 0)
3048                         {
3049                                 center_selection(new_item);
3050                                 redraw = 1;
3051                         }
3052                         result = 1;
3053                         break;
3055                 case LEFT:
3056                         xposition -= 10;
3057                         redraw = 1;
3058                         result = 1;
3059                         break;
3061                 case RIGHT:
3062                         xposition += 10;
3063                         redraw = 1;
3064                         result = 1;
3065                         break;
3067                 default:
3068                         if(!ctrl_down())
3069                         {
3070                                 if(top_level->get_keypress() > 30 && 
3071                                         top_level->get_keypress() < 127)
3072                                 {
3073                                         int query_len = strlen(query);
3074                                         query[query_len++] = top_level->get_keypress();
3075                                         query[query_len] = 0;
3076                                         new_selection = query_list();
3077                                 }
3078                                 else
3079                                 if(top_level->get_keypress() == BACKSPACE)
3080                                 {
3081                                         int query_len = strlen(query);
3082                                         if(query_len > 0) query[--query_len] = 0;
3083                                         new_selection = query_list();
3084                                 }
3086                                 redraw = 1;
3087                                 result = 1;
3088                         }
3089                         break;
3090         }
3092         if(redraw)
3093         {
3094                 fix_positions();
3095                 draw_items();
3096                 update_scrollbars();
3097                 gui->flash();
3098         }
3099         
3100         if(new_selection >= 0)
3101         {
3102                 selection_changed();
3103         }
3105         return result;
3108 int BC_ListBox::get_scrollbars()
3110         int h_needed = get_items_height(data, columns);
3111         int w_needed = get_items_width();
3115         title_h = get_title_h();
3117         view_h = popup_h - title_h - 4;
3118         view_w = popup_w - 4;
3120 // Create scrollbars as needed
3121         for(int i = 0; i < 2; i++)
3122         {
3123                 if(w_needed > view_w)
3124                 {
3125                         need_xscroll = 1;
3126                         view_h = popup_h - 
3127                                 title_h - 
3128                                 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h() - 
3129                                 4;
3130                 }
3131                 else
3132                 {
3133                         need_xscroll = 0;
3134                 }
3136                 if(h_needed > view_h)
3137                 {
3138                         need_yscroll = 1;
3139                         view_w = popup_w - 
3140                                 get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w() - 
3141                                 4;
3142                 }
3143                 else
3144                 {
3145                         need_yscroll = 0;
3146                 }
3147         }
3149 // Update subwindow size
3150         int new_w = popup_w;
3151         int new_h = popup_h;
3152         if(need_xscroll) new_h -= get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h();
3153         if(need_yscroll) new_w -= get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w();
3155         if(!popup)
3156                 if(new_w != BC_WindowBase::get_w() || new_h != BC_WindowBase::get_h())
3157                         gui->resize_window(new_w, new_h);
3159         BC_WindowBase *destination = (popup ? gui : parent_window);
3160         if(need_xscroll)
3161         {
3162                 if(!xscrollbar)
3163                 {
3164                         destination->add_subwindow(xscrollbar = 
3165                                 new BC_ListBoxXScroll(this, 
3166                                         w_needed, 
3167                                         view_w, 
3168                                         xposition));
3169                         xscrollbar->bound_to = this;
3170                 }
3171                 else
3172                         xscrollbar->reposition_window(get_xscroll_x(),
3173                                 get_xscroll_y(),
3174                                 get_xscroll_width());
3175         }
3176         else
3177         {
3178                 if(xscrollbar) delete xscrollbar;
3179                 xscrollbar = 0;
3180                 xposition = 0;
3181         }
3183         if(need_yscroll)
3184         {
3185                 if(!yscrollbar)
3186                 {
3187                         destination->add_subwindow(yscrollbar = 
3188                                 new BC_ListBoxYScroll(this, 
3189                                         h_needed, 
3190                                         view_h, 
3191                                         yposition));
3192                         yscrollbar->bound_to = this;
3193                 }
3194                 else
3195                         yscrollbar->reposition_window(get_yscroll_x(),
3196                                 get_yscroll_y(),
3197                                 get_yscroll_height());
3198         }
3199         else
3200         {
3201                 if(yscrollbar) delete yscrollbar;
3202                 yscrollbar = 0;
3203                 yposition = 0;
3204         }
3205         
3206         if(!bg_surface ||
3207                 view_w + 4 != bg_surface->get_w() ||
3208                 view_h + 4 != bg_surface->get_h())
3209         {
3210                 if(bg_surface) delete bg_surface;
3211                 bg_surface = new BC_Pixmap(gui, view_w + 4, view_h + 4);
3212                 draw_background();
3213         }
3215         return 0;
3218 BC_Pixmap* BC_ListBox::get_bg_surface()
3220         return bg_surface;
3224 void BC_ListBox::draw_background()
3226 // White background pixmap
3227         set_color(WHITE);
3228         draw_box(0, 0, bg_surface->get_w(), bg_surface->get_h(), bg_surface);
3230 // Optional heroine pixmap
3231         if(bg_pixmap)
3232                 bg_surface->draw_pixmap(bg_pixmap,
3233                         bg_surface->get_w() - top_level->get_resources()->listbox_bg->get_w(),
3234                         0);
3237 void BC_ListBox::clear_listbox(int x, int y, int w, int h)
3239         gui->draw_pixmap(bg_surface, 
3240                 x, 
3241                 y, 
3242                 w, 
3243                 h,
3244                 x,
3245                 y - title_h);
3248 void BC_ListBox::update_format(int display_format, int redraw)
3250         this->display_format = display_format;
3251         if(redraw)
3252         {
3253                 draw_items();
3254                 if(gui) gui->flash();
3255         }
3258 int BC_ListBox::get_format()
3260         return display_format;
3265 int BC_ListBox::draw_items()
3267         if(gui)
3268         {
3269 //dump(data, columns);
3271 // Calculate items width 
3272                 calculate_item_coords();
3275 // Create and destroy scrollbars as needed
3276                 get_scrollbars();
3280 //              draw_background();
3282 // Icon display
3283                 if(display_format == LISTBOX_ICONS)
3284                 {
3285                         clear_listbox(2, 2 + title_h, view_w, view_h);
3287                         set_font(MEDIUMFONT);
3288                         for(int i = 0; i < data[0].total; i++)
3289                         {
3290                                 BC_ListBoxItem *item = data[0].values[i];
3291                                 if(get_item_x(item) >= -get_item_w(item) && 
3292                                         get_item_x(item) < view_w &&
3293                                         get_item_y(item) >= -get_item_h(item) + title_h &&
3294                                         get_item_y(item) < view_h + title_h)
3295                                 {
3296                                         int item_color = get_item_highlight(data, 0, i);
3297                                         int icon_x, icon_y, icon_w, icon_h;
3298                                         int text_x, text_y, text_w, text_h;
3300 // Draw highlights
3301                                         get_icon_mask(item, icon_x, icon_y, icon_w, icon_h);
3302                                         get_text_mask(item, text_x, text_y, text_w, text_h);
3304                                         if(item_color != WHITE)
3305                                         {
3306                                                 gui->set_color(BLACK);
3307                                                 gui->draw_rectangle(icon_x, icon_y, icon_w, icon_h);
3308                                                 gui->set_color(item_color);
3309                                                 gui->draw_box(icon_x + 1, icon_y + 1, icon_w - 2, icon_h - 2);
3310                                                 gui->set_color(BLACK);
3311                                                 gui->draw_rectangle(text_x, text_y, text_w, text_h);
3312                                                 gui->set_color(item_color);
3313                                                 gui->draw_box(text_x + 1, text_y + 1, text_w - 2, text_h - 2);
3315                                                 if(icon_position == ICON_LEFT)
3316                                                         gui->draw_box(text_x - 1, text_y + 1, 2, text_h - 2);
3317                                                 else
3318                                                 if(icon_position == ICON_TOP)
3319                                                         gui->draw_line(text_x + 1, text_y, text_x + icon_w - 2, text_y);
3320                                         }
3322 // Draw icons
3323                                         gui->set_color(get_item_color(data, 0, i));
3324                                         if(item->icon)
3325                                                 item->icon->write_drawable(gui->pixmap, 
3326                                                         icon_x + ICON_MARGIN, 
3327                                                         icon_y + ICON_MARGIN);
3328                                         gui->draw_text(text_x + ICON_MARGIN, 
3329                                                 text_y + ICON_MARGIN + get_text_ascent(MEDIUMFONT), 
3330                                                 item->text);
3331                                 }
3332                         }
3333                 }
3334                 else
3335 // Text display
3336                 if(display_format == LISTBOX_TEXT)
3337                 {
3338 // Draw one column at a time so text overruns don't go into the next column
3339 // clear column backgrounds
3340                         int current_toggle = 0;
3341                         for(int j = 0; j < columns; j++)
3342                         {
3343                                 clear_listbox(LISTBOX_BORDER + get_column_offset(j) - xposition, 
3344                                         LISTBOX_BORDER + title_h, 
3345                                         get_column_width(j, 1), 
3346                                         view_h);
3348 // Draw rows in the column recursively
3349                                 draw_text_recursive(data, j, 0, &current_toggle);
3350                         }
3352 // Delete excess expanders
3353                         while(expanders.total > current_toggle)
3354                         {
3355                                 expanders.remove_object();
3356                         }
3357                 }
3359 // Draw titles on top of rows for superposition effect
3360                 if(column_titles && display_format != LISTBOX_ICONS)
3361                 {
3362                         for(int i = 0; i < columns; i++)
3363                         {
3364                                 gui->draw_3d_box(get_column_offset(i) - xposition + 2, 
3365                                         2, 
3366                                         get_column_width(i, 1), 
3367                                         title_h, 
3368                                         top_level->get_resources()->button_light, 
3369                                         top_level->get_resources()->button_up, 
3370                                         top_level->get_resources()->button_up, 
3371                                         top_level->get_resources()->button_shadow,
3372                                         BLACK);
3374                                 gui->set_color(BLACK);
3375                                 gui->draw_text(-xposition + get_column_offset(i) + LISTBOX_MARGIN + 2, 
3376                                         2 + get_text_ascent(MEDIUMFONT), column_titles[i]);
3377                         }
3378                 }
3380 // Clear garbage from bottom right corner
3381                 if(xscrollbar && yscrollbar && popup)
3382                 {
3383                         gui->draw_top_background(parent_window, 
3384                                 popup_w - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w(), 
3385                                 popup_h - get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h(), 
3386                                 get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w(),
3387                                 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h());
3388                 }
3390 // Draw borders
3391                 draw_border();
3394                 if(current_operation == BCLISTBOX_SELECT_RECT)
3395                         draw_rectangle();
3396         }
3398         return 0;
3402 void BC_ListBox::draw_text_recursive(ArrayList<BC_ListBoxItem*> *data, 
3403         int column,
3404         int indent,
3405         int *current_toggle)
3407         if(!data) return;
3409         set_font(MEDIUMFONT);
3410         int subindent = 0;
3412 // Search for a branch and make room for toggle if there is one
3413         if(column == 0)
3414         {
3415                 for(int i = 0; i < data[column].total; i++)
3416                 {
3417                         if(data[column].values[i]->get_sublist())
3418                         {
3419                                 subindent = BC_WindowBase::get_resources()->listbox_expand[0]->get_w();
3420                                 break;
3421                         }
3422                 }
3423         }
3425         for(int i = 0; i < data[column].total; i++)
3426         {
3427 // Draw a row
3428                 BC_ListBoxItem *item = data[column].values[i];
3429                 BC_ListBoxItem *first_item = data[0].values[i];
3431                 if(get_item_y(item) >= -get_item_h(item) + title_h &&
3432                         get_item_y(item) < view_h + title_h)
3433                 {
3434                         int row_color = get_item_highlight(data, 0, i);
3435                         int x, y, w, h, column_width;
3437                         get_text_mask(item, x, y, w, h);
3438                         column_width = get_column_width(column, 1);
3439                         if(x + column_width > view_w + LISTBOX_BORDER * 2)
3440                                 column_width = view_w + LISTBOX_BORDER * 2 - x;
3442                         if(row_color != WHITE)
3443                         {
3444                                 gui->set_color(row_color);
3445                                 gui->draw_box(x, 
3446                                         y, 
3447                                         column_width, 
3448                                         h);
3449                                 gui->set_color(BLACK);
3450                                 gui->draw_line(x, 
3451                                         y, 
3452                                         x + column_width - 1, 
3453                                         y);
3454                                 gui->draw_line(x, 
3455                                         y + get_text_height(MEDIUMFONT), 
3456                                         x + column_width - 1, 
3457                                         y + get_text_height(MEDIUMFONT));
3458                         }
3460                         gui->set_color(get_item_color(data, column, i));
3463 // Indent only applies to first column
3464                         gui->draw_text(
3465                                 x + 
3466                                         LISTBOX_BORDER + 
3467                                         LISTBOX_MARGIN + 
3468                                         (column == 0 ? indent + subindent : 0), 
3469                                 y + get_text_ascent(MEDIUMFONT), 
3470                                 item->text);
3473 // Update expander
3474                         if(column == 0 &&
3475                                 item->get_sublist() && 
3476                                 item->get_columns())
3477                         {
3478 // Must be below column titles
3479                                 if(!column_titles || y > get_text_height(MEDIUMFONT))
3480                                 {
3481                                 
3484 // Create new expander
3485                                         if(*current_toggle >= expanders.total)
3486                                         {
3487                                                 BC_ListBoxToggle *toggle = 
3488                                                         new BC_ListBoxToggle(this, 
3489                                                                 item, 
3490                                                                 x + LISTBOX_BORDER + LISTBOX_MARGIN + indent,
3491                                                                 y);
3492                                                 gui->add_subwindow(toggle);
3493                                                 expanders.append(toggle);
3494                                         }
3495                                         else
3496 // Reposition existing expander
3497                                         {
3498                                                 BC_ListBoxToggle *toggle = expanders.values[*current_toggle];
3499                                                 toggle->update(item, 
3500                                                         x + LISTBOX_BORDER + LISTBOX_MARGIN + indent,
3501                                                         y);
3502                                         }
3503                                         (*current_toggle)++;
3504                                 }
3505                         }
3509                 }
3511 // Descend into sublist
3512                 if(first_item->get_expand())
3513                 {
3514                         draw_text_recursive(first_item->get_sublist(), 
3515                                 column, 
3516                                 indent + LISTBOX_INDENT, 
3517                                 current_toggle);
3518                 }
3519         }
3526 int BC_ListBox::draw_border()
3528         gui->draw_3d_border(0, 
3529                 0, 
3530                 view_w + LISTBOX_BORDER * 2, 
3531                 view_h + title_h + LISTBOX_BORDER * 2, 
3532                 top_level->get_resources()->button_shadow, 
3533                 highlighted ? RED : BLACK, 
3534                 highlighted ? RED : top_level->get_resources()->button_up, 
3535                 top_level->get_resources()->button_light);
3536         return 0;
3539 int BC_ListBox::draw_rectangle()
3541         int x1 = MIN(rect_x1, rect_x2);
3542         int x2 = MAX(rect_x1, rect_x2);
3543         int y1 = MIN(rect_y1, rect_y2);
3544         int y2 = MAX(rect_y1, rect_y2);
3546         if(x1 == x2 || y1 == y2) return 0;
3548         gui->set_inverse();
3549         gui->set_color(WHITE);
3550         gui->draw_rectangle(x1, y1, x2 - x1, y2 - y1);
3551         gui->set_opaque();
3552         return 0;
3555 void BC_ListBox::dump(ArrayList<BC_ListBoxItem*> *data, int columns, int indent)
3557         if(!indent)
3558         {
3559                 printf("BC_ListBox::dump 1\n");
3560         }
3562         for(int i = 0; i < data[0].total; i++)
3563         {
3564                 for(int k = 0; k < indent; k++)
3565                         printf(" ");
3566                 for(int j = 0; j < columns; j++)
3567                 {
3568                         BC_ListBoxItem *item = data[j].values[i];
3569                         printf("%d,%d,%d=%s ", 
3570                                 item->get_text_x(), 
3571                                 item->get_text_y(),
3572                                 item->autoplace_text, 
3573                                 item->get_text());
3574                 }
3575                 printf("\n");
3577                 if(data[0].values[i]->get_sublist())
3578                 {
3579                         dump(data[0].values[i]->get_sublist(),
3580                                 data[0].values[i]->get_columns(),
3581                                 indent + 4);
3582                 }
3583         }
3585