r370: Heroine Virutal's official release 1.2.1
[cinelerra_cv/mob.git] / hvirtual / guicast / bclistbox.C
blobc3365faa5bcb915b3c915843051cad9b0f3c8e4c
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 "bctimer.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)
87         this->listbox = listbox;
88         this->item = item;
89         this->x = x;
90         this->y = y;
91         this->value = item->get_expand();
92         if(this->value) 
93                 state = BC_Toggle::TOGGLE_CHECKED;
94         else
95                 state = BC_Toggle::TOGGLE_UP;
98 void BC_ListBoxToggle::update(BC_ListBoxItem *item, 
99         int x, 
100         int y,
101         int flash)
103         this->value = item->get_expand();
104         this->item = item;
105         this->x = x;
106         this->y = y;
108 // update state
109         switch(state)
110         {
111                 case TOGGLE_UP:
112                         if(value)
113                                 state = TOGGLE_CHECKED;
114                         break;
116                 case TOGGLE_UPHI:
117                         if(value)
118                                 state = TOGGLE_CHECKEDHI;
119                         break;
121                 case TOGGLE_CHECKED:
122                         if(!value)
123                                 state = TOGGLE_UP;
124                         break;
126                 case TOGGLE_DOWN:
127                         break;
129                 case TOGGLE_CHECKEDHI:
130                         if(!value)
131                                 state = TOGGLE_UPHI;
132                         break;
134                 case TOGGLE_DOWN_EXIT:
135                         break;
136         }
139         draw(flash);
142 int BC_ListBoxToggle::cursor_motion_event(int *redraw_toggles)
144         int w = listbox->toggle_images[0]->get_w();
145         int h = listbox->toggle_images[0]->get_h();
146         int cursor_inside = listbox->get_cursor_x() >= x && 
147                 listbox->get_cursor_x() < x + w &&
148                 listbox->get_cursor_y() >= y && 
149                 listbox->get_cursor_y() < y + h;
150         int result = 0;
152         switch(state)
153         {
154                 case BC_ListBoxToggle::TOGGLE_UPHI:
155                         if(!cursor_inside)
156                         {
157                                 state = BC_ListBoxToggle::TOGGLE_UP;
158                                 *redraw_toggles = 1;
159                         }
160                         break;
162                 case BC_ListBoxToggle::TOGGLE_CHECKEDHI:
163                         if(!cursor_inside)
164                         {
165                                 state = BC_ListBoxToggle::TOGGLE_CHECKED;
166                                 *redraw_toggles = 1;
167                         }
168                         break;
170                 case BC_ListBoxToggle::TOGGLE_DOWN:
171                         if(!cursor_inside)
172                         {
173                                 state = BC_ListBoxToggle::TOGGLE_DOWN_EXIT;
174                                 *redraw_toggles = 1;
175                         }
176                         result = 1;
177                         break;
179                 case BC_ListBoxToggle::TOGGLE_DOWN_EXIT:
180                         if(cursor_inside)
181                         {
182                                 state = BC_ListBoxToggle::TOGGLE_DOWN;
183                                 *redraw_toggles = 1;
184                         }
185                         result = 1;
186                         break;
188                 default:
189                         if(cursor_inside)
190                         {
191                                 if(value)
192                                         state = BC_ListBoxToggle::TOGGLE_CHECKEDHI;
193                                 else
194                                         state = BC_ListBoxToggle::TOGGLE_UPHI;
195                                 *redraw_toggles = 1;
196                         }
197                         break;
198         }
199         return result;
202 int BC_ListBoxToggle::cursor_leave_event(int *redraw_toggles)
204         if(value)
205                 state = BC_ListBoxToggle::TOGGLE_CHECKED;
206         else
207                 state = BC_ListBoxToggle::TOGGLE_UP;
210 int BC_ListBoxToggle::button_press_event()
212         int w = listbox->toggle_images[0]->get_w();
213         int h = listbox->toggle_images[0]->get_h();
215         if(listbox->gui->get_cursor_x() >= x && 
216                 listbox->gui->get_cursor_x() < x + w &&
217                 listbox->gui->get_cursor_y() >= y && 
218                 listbox->gui->get_cursor_y() < y + h)
219         {
220                 state = BC_ListBoxToggle::TOGGLE_DOWN;
221                 return 1;
222         }
223         return 0;
226 int BC_ListBoxToggle::button_release_event(int *redraw_toggles)
228         int result = 0;
229         switch(state)
230         {
231                 case BC_ListBoxToggle::TOGGLE_DOWN:
232                         value = !value;
233                         if(value)
234                                 state = BC_ListBoxToggle::TOGGLE_CHECKEDHI;
235                         else
236                                 state = BC_ListBoxToggle::TOGGLE_UPHI;
237                         listbox->expand_item(item, value);
238                         result = 1;
239                         break;
241                 case BC_ListBoxToggle::TOGGLE_DOWN_EXIT:
242                         if(value)
243                                 state = BC_ListBoxToggle::TOGGLE_CHECKED;
244                         else
245                                 state = BC_ListBoxToggle::TOGGLE_UP;
246                         *redraw_toggles = 1;
247                         result = 1;
248                         break;
249         }
250         return result;
253 void BC_ListBoxToggle::draw(int flash)
255         if(listbox->gui)
256         {
257                 int image_number = 0;
258                 int w = listbox->toggle_images[0]->get_w();
259                 int h = listbox->toggle_images[0]->get_h();
261                 switch(state)
262                 {
263                         case BC_ListBoxToggle::TOGGLE_UP: image_number = 0; break;
264                         case BC_ListBoxToggle::TOGGLE_UPHI: image_number = 1; break;
265                         case BC_ListBoxToggle::TOGGLE_CHECKED: image_number = 2; break;
266                         case BC_ListBoxToggle::TOGGLE_DOWN: image_number = 3; break;
267                         case BC_ListBoxToggle::TOGGLE_CHECKEDHI: image_number = 4; break;
268                         case BC_ListBoxToggle::TOGGLE_DOWN_EXIT:
269                                 if(value)
270                                         image_number = 2;
271                                 else
272                                         image_number = 0;
273                                 break;
274                 }
276 //printf("BC_ListBoxToggle::draw 1 %d\n", state);
277                 listbox->gui->draw_pixmap(listbox->toggle_images[image_number],
278                         x,
279                         y);
282                 if(flash)
283                 {
284                         listbox->gui->flash(x, y, w, h);
285                         listbox->gui->flush();
286                 }
287         }
303 // ====================================================== box
305 BC_ListBox::BC_ListBox(int x, 
306         int y, 
307         int w, 
308         int h,
309         int display_format,
310         ArrayList<BC_ListBoxItem*> *data,
311         char **column_titles,
312         int *column_width,
313         int columns,
314         int yposition,
315         int is_popup,
316         int selection_mode,
317         int icon_position,
318         int allow_drag)
319  : BC_SubWindow(x, y, w, h, -1)
322         xposition = 0;
323         highlighted_item = -1;
324         highlighted_title = -1;
325         highlighted_division = -1;
326         highlighted_ptr = 0;
327         xscrollbar = 0;
328         yscrollbar = 0;
329         current_cursor = ARROW_CURSOR;
330         gui = 0;
331         view_h = 0;
332         view_w = 0;
333         title_h = 0;
334         active = 0;
335         new_value = 0;
336         need_xscroll = 0;
337         need_yscroll = 0;
338         bg_tile = 0;
339         drag_popup = 0;
340         selection_number1 = -1;
341         selection_number2 = -1;
342         bg_surface = 0;
343         bg_pixmap = 0;
345         current_operation = NO_OPERATION;
346         button_highlighted = 0;
347         list_highlighted = 0;
349         allow_drag_scroll = 1;
350         process_drag = 1;
352         sort_column = -1;
353         sort_order = 0;
355         allow_drag_column = 0;
356         master_column = 0;
357         search_column = 0;
359         popup_w = w;
360         popup_h = h;
362         for(int i = 0; i < 3; i++)
363         {
364                 button_images[i] = 0;
365                 column_bg[i] = 0;
366         }
367         for(int i = 0; i < 5; i++)
368                 toggle_images[i] = 0;
370         column_sort_up = 0;
371         column_sort_dn = 0;
373 //printf("BC_ListBox::BC_ListBox 1\n");
374         this->data = data;
375         this->columns = columns;
376         this->yposition = yposition;
377         this->is_popup = is_popup;
378         this->display_format = display_format;
379         this->selection_mode = selection_mode;
380         this->icon_position = icon_position;
381         this->allow_drag = allow_drag;
382         this->column_titles = 0;
383         this->column_width = 0;
384 //printf("BC_ListBox::BC_ListBox 1\n");
386         if((!column_titles && column_width) ||
387                 (column_titles && !column_width))
388         {
389                 printf("BC_ListBox::BC_ListBox either column_titles or column_widths == NULL but not both.\n");
390         }
391 //printf("BC_ListBox::BC_ListBox 2 %p %p\n", column_titles, column_width);
392         set_columns(column_titles, 
393                 column_width, 
394                 columns);
396 //printf("BC_ListBox::BC_ListBox 3\n");
398         drag_icon_vframe = 0;
399         drag_column_icon_vframe = 0;
403 // reset the search engine
404 //printf("BC_ListBox::BC_ListBox 4\n");
405         reset_query();
406 //printf("BC_ListBox::BC_ListBox 5\n");
409 BC_ListBox::~BC_ListBox()
411         expanders.remove_all_objects();
412         if(bg_surface) delete bg_surface;
413         if(bg_pixmap) delete bg_pixmap;
414         if(xscrollbar) delete xscrollbar;
415         if(yscrollbar) delete yscrollbar;
416         for(int i = 0; i < 3; i++)
417         {
418                 if(button_images[i]) delete button_images[i];
419                 if(column_bg[i]) delete column_bg[i];
420         }
421         for(int i = 0; i < 5; i++)
422                 if(toggle_images[i]) delete toggle_images[i];
423         if(column_sort_up) delete column_sort_up;
424         if(column_sort_dn) delete column_sort_dn;
426         delete_columns();
427         if(drag_popup) delete drag_popup;
430 void BC_ListBox::reset_query()
432         query[0] = 0;  // reset query
435 int BC_ListBox::evaluate_query(int list_item, char *string)
437         return(strcmp(string, data[search_column].values[list_item]->text) <= 0 && 
438                 data[search_column].values[list_item]->searchable);
441 int BC_ListBox::query_list()
443         if(query[0] == 0) return 0;
445         int done = 0;
446         int result;
447         int selection_changed = 0;
448         int prev_selection = -1;
449         for(int i = 0; !done && i < data[0].total; i++)
450         {
451                 if(evaluate_query(i, query))
452                 {
453                         result = i;
454                         done = 1;
455                 }
456         }
458         if(done)
459         {
460 // Deselect all
461                 for(int i = 0; i < data[0].total; i++)
462                 {
463                         for(int j = 0; j < columns; j++)
464                         {
465                                 if(data[j].values[i]->selected) prev_selection = i;
466                                 data[j].values[i]->selected = 0;
467                         }
468                 }
470 // Select one
471                 if(prev_selection != result)
472                         selection_changed = 1;
473                 for(int j = 0; j < columns; j++)
474                 {
475                         data[j].values[result]->selected = 1;
476                 }
477                 center_selection(result);
478         }
480         return selection_changed;
483 void BC_ListBox::init_column_width()
485         if(!column_width && data)
486         {
487                 int widest = 5, w;
488                 for(int i = 0; i < data[0].total; i++)
489                 {
490                         w = get_text_width(MEDIUMFONT, data[0].values[i]->get_text()) + 2 * LISTBOX_MARGIN;
491                         if(w > widest) widest = w;
492                 }
493                 default_column_width[0] = widest;
494         }
497 int BC_ListBox::initialize()
499         if(is_popup)
500         {
501                 for(int i = 0; i < 3; i++)
502                 {
503                         button_images[i] = new BC_Pixmap(parent_window, 
504                                 BC_WindowBase::get_resources()->listbox_button[i], 
505                                 PIXMAP_ALPHA);
506                 }
507                 w = button_images[0]->get_w();
508                 h = button_images[0]->get_h();
509                 
510                 gui = 0;
511                 current_operation = NO_OPERATION;
512         }
513         else
514         {
515                 gui = this;
516                 current_operation = NO_OPERATION;
517         }
519         for(int i = 0; i < 3; i++)
520         {
521                 column_bg[i] = new BC_Pixmap(parent_window,
522                         get_resources()->listbox_column[i],
523                         PIXMAP_ALPHA);
524         }
525         for(int i = 0; i < 5; i++)
526         {
527                 toggle_images[i] = new BC_Pixmap(parent_window,
528                         get_resources()->listbox_expand[i],
529                         PIXMAP_ALPHA);
530         }
532         column_sort_up = new BC_Pixmap(parent_window, 
533                 BC_WindowBase::get_resources()->listbox_up, 
534                 PIXMAP_ALPHA);
535         column_sort_dn = new BC_Pixmap(parent_window, 
536                 BC_WindowBase::get_resources()->listbox_dn, 
537                 PIXMAP_ALPHA);
539 //printf("BC_ListBox::initialize 10\n");
540         drag_icon_vframe = get_resources()->type_to_icon[ICON_UNKNOWN];
541         drag_column_icon_vframe = get_resources()->type_to_icon[ICON_COLUMN];
542 // = new BC_Pixmap(parent_window, 
543 //              get_resources()->type_to_icon[ICON_UNKNOWN], 
544 //              PIXMAP_ALPHA);
545 //      drag_column_icon = new BC_Pixmap(parent_window,
546 //              get_resources()->type_to_icon[ICON_COLUMN],
547 //              PIXMAP_ALPHA);
548         BC_SubWindow::initialize();
550         init_column_width();
552         if(top_level->get_resources()->listbox_bg)
553                 bg_pixmap = new BC_Pixmap(this, 
554                         get_resources()->listbox_bg, 
555                         PIXMAP_OPAQUE);
557         draw_button();
558         draw_items(1);
559         return 0;
562 void BC_ListBox::deactivate_selection()
564         current_operation = NO_OPERATION;
567 int BC_ListBox::draw_button()
569 // Draw the button for a popup listbox
570         if(is_popup)
571         {
572                 int image_number = 0;
574                 draw_top_background(parent_window, 0, 0, w, h);
576                 if(button_highlighted)
577                         image_number = 1;
578                 if(current_operation == BUTTON_DN)
579                         image_number = 2;
582                 button_images[image_number]->write_drawable(pixmap, 
583                         0, 
584                         0,
585                         w,
586                         h,
587                         0,
588                         0);
589                 flash();
590         }
591         return 0;
594 int BC_ListBox::calculate_item_coords()
596         if(!data) return 0;
598         int icon_x = 0;
599         int next_icon_x = 0;
600         int next_icon_y = 0;
601         int next_text_y = 0;
602 // Change the display_format to get the right item dimensions for both
603 // text and icons.
604         int display_format_temp = display_format;
607 // Scan the first column for lowest y coord of all text
608 // and lowest right x and y coord for all icons which aren't auto placable
609         calculate_last_coords_recursive(data,
610                 &icon_x,
611                 &next_icon_x, 
612                 &next_icon_y,
613                 &next_text_y,
614                 1);
616 // Reset last column width.  It's recalculated based on text width.
618         calculate_item_coords_recursive(data,
619                 &icon_x,
620                 &next_icon_x, 
621                 &next_icon_y,
622                 &next_text_y,
623                 1);
627         display_format = display_format_temp;
629         return 0;
632 void BC_ListBox::calculate_last_coords_recursive(
633         ArrayList<BC_ListBoxItem*> *data,
634         int *icon_x,
635         int *next_icon_x,
636         int *next_icon_y,
637         int *next_text_y,
638         int top_level)
640         for(int i = 0; i < data[0].total; i++)
641         {
642                 int current_text_y = 0;
643                 int current_icon_x = 0;
644                 int current_icon_y = 0;
645                 BC_ListBoxItem *item = data[0].values[i];
647 // Get next_text_y
648                 if(!item->autoplace_text)
649                 {
650 // Lowest text coordinate
651                         display_format = LISTBOX_TEXT;
652                         current_text_y = item->text_y + 
653                                 get_text_height(MEDIUMFONT);
654                         if(current_text_y > *next_text_y)
655                                 *next_text_y = current_text_y;
657 // Add sublist depth if it is expanded
658                         if(item->get_sublist() && 
659                                 item->get_columns() &&
660                                 item->get_expand())
661                         {
662                                 calculate_last_coords_recursive(item->get_sublist(),
663                                         icon_x,
664                                         next_icon_x, 
665                                         next_icon_y,
666                                         next_text_y,
667                                         0);
668                         }
669                 }
671 // Get next_icon coordinate
672                 if(top_level)
673                 {
674                         BC_ListBoxItem *item = data[master_column].values[i];
675                         if(!item->autoplace_icon)
676                         {
677                                 display_format = LISTBOX_ICONS;
678 // Lowest right icon coordinate.
679                                 current_icon_x = item->icon_x;
680                                 if(current_icon_x > *icon_x) *icon_x = current_icon_x;
681                                 if(current_icon_x + get_item_w(item) > *next_icon_x)
682                                         *next_icon_x = current_icon_x + get_item_w(item);
684                                 current_icon_y = item->icon_y + get_item_h(item);
685                                 if(current_icon_y > *next_icon_y) 
686                                         *next_icon_y = current_icon_y;
687                         }
688                 }
689         }
693 void BC_ListBox::calculate_item_coords_recursive(
694         ArrayList<BC_ListBoxItem*> *data,
695         int *icon_x,
696         int *next_icon_x,
697         int *next_icon_y,
698         int *next_text_y,
699         int top_level)
704 // Set up items which need autoplacement.
705 // Should fill icons down and then across
706         for(int i = 0; i < data[0].total; i++)
707         {
708 // Don't increase y unless the row requires autoplacing.
709                 int total_autoplaced_columns = 0;
711 // Set up icons in first column
712                 if(top_level)
713                 {
714                         BC_ListBoxItem *item = data[master_column].values[i];
715                         if(item->autoplace_icon)
716                         {
717 // 1 column only if icons are used
718                                 display_format = LISTBOX_ICONS;
719 // Test row height
720 // Start new row.
721                                 if(*next_icon_y + get_item_h(item) >= get_h() && 
722                                         *next_icon_y > 0)
723                                 {
724                                         *icon_x = *next_icon_x;
725                                         *next_icon_y = 0;
726                                 }
728                                 if(*icon_x + get_item_w(item) > *next_icon_x)
729                                         *next_icon_x = *icon_x + get_item_w(item);
732                                 item->set_icon_x(*icon_x);
733                                 item->set_icon_y(*next_icon_y);
735                                 *next_icon_y += get_item_h(item);
736                         }
737                 }
741 // Set up a text row
742                 int next_text_x = 0;
743                 for(int j = 0; j < columns; j++)
744                 {
745                         BC_ListBoxItem *item = data[j].values[i];
746                         if(item->autoplace_text)
747                         {
748                                 display_format = LISTBOX_TEXT;
749                                 item->set_text_x(next_text_x);
750                                 item->set_text_y(*next_text_y);
752 // printf("BC_ListBox::calculate_item_coords_recursive %p %d %d %d %d %s \n", 
753 // item->get_sublist(), 
754 // item->get_columns(), 
755 // item->get_expand(), 
756 // next_text_x, 
757 // *next_text_y,
758 // item->get_text());
759 // Increment position of next column
760                                 if(j < columns - 1)
761                                         next_text_x += (column_width ? 
762                                                 column_width[j] : 
763                                                 default_column_width[j]);
764                                 else
765 // Set last column width based on text width
766                                 {
767                                         int new_w = get_item_w(item);
769                                         int *previous_w = (column_width ? 
770                                                 &column_width[j] : 
771                                                 &default_column_width[j]);
772                                         if(new_w > *previous_w)
773                                                 *previous_w = new_w;
774 //printf("BC_ListBox::calculate_item_coords_recursive 1 %d\n", new_w);
775                                 }
776                                 total_autoplaced_columns++;
777                         }
778                 }
780 // Increase the text vertical position
781                 if(total_autoplaced_columns)
782                 {
783                         display_format = LISTBOX_TEXT;
784                         *next_text_y += get_text_height(MEDIUMFONT);
785                 }
787 // Set up a sublist
788                 BC_ListBoxItem *item = data[master_column].values[i];
789                 if(item->get_sublist() &&
790                         item->get_columns() &&
791                         item->get_expand())
792                 {
793                         calculate_item_coords_recursive(
794                                 item->get_sublist(),
795                                 icon_x,
796                                 next_icon_x,
797                                 next_icon_y,
798                                 next_text_y,
799                                 0);
800                 }
801         }
806 void BC_ListBox::set_allow_drag_column(int value)
808         this->allow_drag_column = value;
811 void BC_ListBox::set_process_drag(int value)
813         this->process_drag = value;
816 void BC_ListBox::set_master_column(int value, int redraw)
818         this->master_column = value;
819         if(redraw)
820         {
821                 draw_items(1);
822         }
825 void BC_ListBox::set_search_column(int value)
827         this->search_column = value;
830 int BC_ListBox::get_sort_column()
832         return sort_column;
835 void BC_ListBox::set_sort_column(int value, int redraw)
837         sort_column = value;
838         if(redraw)
839         {
840                 draw_titles(1);
841         }
844 int BC_ListBox::get_sort_order()
846         return sort_order;
849 void BC_ListBox::set_sort_order(int value, int redraw)
851         sort_order = value;
852         if(redraw)
853         {
854                 draw_titles(1);
855         }
862 int BC_ListBox::get_display_mode()
864         return display_format;
867 int BC_ListBox::get_yposition()
869         return yposition;
872 int BC_ListBox::get_xposition()
874         return xposition;
877 int BC_ListBox::get_highlighted_item()
879         return highlighted_item;
883 int BC_ListBox::get_item_x(BC_ListBoxItem *item)
885         if(display_format == LISTBOX_TEXT)
886                 return item->text_x - xposition + 2;
887         else
888                 return item->icon_x - xposition + 2;
891 int BC_ListBox::get_item_y(BC_ListBoxItem *item)
893         int result;
894         if(display_format == LISTBOX_TEXT)
895                 result = item->text_y - yposition + title_h + 2;
896         else
897                 result = item->icon_y - yposition + title_h + 2;
898         return result;
901 int BC_ListBox::get_item_w(BC_ListBoxItem *item)
903         if(display_format == LISTBOX_ICONS)
904         {
905                 int x, y, w, h;
906                 get_icon_mask(item, x, y, w, h);
907                 int icon_w = w;
908                 get_text_mask(item, x, y, w, h);
909                 int text_w = w;
911                 if(icon_position == ICON_LEFT)
912                         return icon_w + text_w;
913                 else
914                         return (icon_w > text_w) ? icon_w : text_w;
915         }
916         else
917         {
918                 return get_text_width(MEDIUMFONT, item->text) + 2 * LISTBOX_MARGIN;
919         }
922 int BC_ListBox::get_item_h(BC_ListBoxItem *item)
924         if(display_format == LISTBOX_ICONS)
925         {
926                 int x, y, w, h;
927                 get_icon_mask(item, x, y, w, h);
928                 int icon_h = h;
929                 get_text_mask(item, x, y, w, h);
930                 int text_h = h;
932                 if(icon_position == ICON_LEFT)
933                         return (icon_h > text_h) ? icon_h : text_h;
934                 else
935                         return icon_h + text_h;
936         }
937         else
938         {
939                 return get_text_height(MEDIUMFONT);
940         }
941         return 0;
945 int BC_ListBox::get_icon_w(BC_ListBoxItem *item)
947         BC_Pixmap *icon = item->icon;
948         if(icon) return icon->get_w();
949         return 0;
952 int BC_ListBox::get_icon_h(BC_ListBoxItem *item)
954         BC_Pixmap *icon = item->icon;
955         if(icon) return icon->get_h();
956         return 0;
959 int BC_ListBox::get_items_width()
961         int widest = 0;
963         if(display_format == LISTBOX_ICONS)
964         {
965                 for(int i = 0; i < columns; i++)
966                 {
967                         for(int j = 0; j < data[i].total; j++)
968                         {
969                                 int x1, x, y, w, h;
970                                 BC_ListBoxItem *item = data[i].values[j];
971                                 x1 = item->icon_x;
973                                 get_icon_mask(item, x, y, w, h);
974                                 if(x1 + w > widest) widest = x1 + w;
976                                 if(display_format == LISTBOX_ICONS && icon_position == ICON_LEFT)
977                                         x1 += w;
979                                 get_text_mask(item, x, y, w, h);
980                                 if(x1 + w > widest) widest = x1 + w;
981                         }
982                 }
983         }
984         else
985         if(display_format == LISTBOX_TEXT)
986         {
987                 return get_column_offset(columns);
988         }
989         return widest;
992 int BC_ListBox::get_items_height(ArrayList<BC_ListBoxItem*> *data, 
993         int columns,
994         int *result)
996         int temp = 0;
997         int top_level = 0;
998         int highest = 0;
999         if(!result)
1000         {
1001                 result = &temp;
1002                 top_level = 1;
1003         }
1009         for(int j = 0; j < (data ? data[master_column].total : 0); j++)
1010         {
1011                 int y1, x, y, w, h;
1012                 BC_ListBoxItem *item = data[master_column].values[j];
1014                 if(display_format == LISTBOX_ICONS)
1015                 {
1016                         get_icon_mask(item, x, y, w, h);
1017                         if(y + h + yposition > highest) highest = y + h + yposition;
1019                         get_text_mask(item, x, y, w, h);
1020                         if(y + h + yposition > highest) highest = y + h + yposition;
1021                 }
1022                 else
1023                 {
1024                         get_text_mask(item, x, y, w, h);
1025                         *result += h;
1028 // Descend into sublist
1029                         if(item->get_sublist() &&
1030                                 item->get_expand())
1031                         {
1032                                 get_items_height(item->get_sublist(), 
1033                                         item->get_columns(), 
1034                                         result);
1035                         }
1036                 }
1037         }
1038         if(display_format == LISTBOX_TEXT && top_level) 
1039         {
1040                 highest = LISTBOX_MARGIN + *result;
1041         }
1044         return highest;
1047 int BC_ListBox::set_yposition(int position, int draw_items)
1049         this->yposition = position;
1050         if(draw_items)
1051         {
1052                 this->draw_items(1);
1053         }
1054         return 0;
1057 int BC_ListBox::set_xposition(int position)
1059         this->xposition = position;
1060         draw_items(1);
1061         return 0;
1064 void BC_ListBox::expand_item(BC_ListBoxItem *item, int expand)
1066         if(item)
1067         {
1068                 item->expand = expand;
1069 // Collapse sublists if this is collapsed to make it easier to calculate
1070 // coordinates
1071                 if(item->get_sublist())
1072                         collapse_recursive(item->get_sublist(), master_column);
1075 // Set everything for autoplacement
1076                 
1077                 set_autoplacement(data, 0, 1);
1079                 draw_items(1);
1080         }
1083 void BC_ListBox::collapse_recursive(ArrayList<BC_ListBoxItem*> *data,
1084                 int master_column)
1086         for(int i = 0; i < data[master_column].total; i++)
1087         {
1088                 BC_ListBoxItem *item = data[master_column].values[i];
1089                 if(item->get_sublist() && item->expand)
1090                 {
1091                         item->expand = 0;
1092                         collapse_recursive(item->get_sublist(), master_column);
1093                 }
1094         }
1097 void BC_ListBox::set_autoplacement(ArrayList<BC_ListBoxItem*> *data,
1098         int do_icons, 
1099         int do_text)
1101         for(int i = 0; i < data[0].total; i++)
1102         {
1103                 for(int j = 0; j < columns; j++)
1104                 {
1105                         if(do_icons) data[j].values[i]->autoplace_icon = 1;
1106                         if(do_text) data[j].values[i]->autoplace_text = 1;
1107                 }
1109                 BC_ListBoxItem *item = data[master_column].values[i];
1110                 if(item->get_sublist())
1111                 {
1112                         set_autoplacement(item->get_sublist(), do_icons, do_text);
1113                 }
1114         }
1119 int BC_ListBox::get_w()
1121         if(is_popup)
1122                 return BCPOPUPLISTBOX_W;
1123         else
1124                 return popup_w;
1127 int BC_ListBox::get_h()
1129         if(is_popup)
1130                 return BCPOPUPLISTBOX_H;
1131         else
1132                 return popup_h;
1135 int BC_ListBox::get_yscroll_x()
1137         if(is_popup)
1138                 return popup_w - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w();
1139         else
1140                 return get_x() + 
1141                         popup_w - 
1142                         get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w();
1145 int BC_ListBox::get_yscroll_y()
1147         if(is_popup)
1148                 return 0;
1149         else
1150                 return get_y();
1153 int BC_ListBox::get_yscroll_height()
1155         return popup_h - (need_xscroll ? 
1156                 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h() : 
1157                 0);
1160 int BC_ListBox::get_xscroll_x()
1162         if(is_popup)
1163                 return 0;
1164         else
1165                 return get_x();
1168 int BC_ListBox::get_xscroll_y()
1170         if(is_popup)
1171                 return popup_h - 
1172                         get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h();
1173         else
1174                 return get_y() + 
1175                         popup_h - 
1176                         get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h();
1179 int BC_ListBox::get_xscroll_width()
1181         return popup_w - (need_yscroll ? 
1182                 get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w() : 
1183                 0);
1186 int BC_ListBox::get_column_offset(int column)
1188         int x = 0;
1189         while(column > 0)
1190         {
1191                 x += column_width ? 
1192                         column_width[--column] : 
1193                         default_column_width[--column];
1194         }
1195         return x;
1198 void BC_ListBox::column_width_boundaries()
1200         if(column_width)
1201         {
1202                 for(int i = 0; i < columns; i++)
1203                 {
1204                         if(column_width[i] < MIN_COLUMN_WIDTH) column_width[i] = MIN_COLUMN_WIDTH;
1205                 }
1206         }
1207         else
1208         {
1209                 for(int i = 0; i < columns; i++)
1210                 {
1211                         if(default_column_width[i] < MIN_COLUMN_WIDTH) default_column_width[i] = MIN_COLUMN_WIDTH;
1212                 }
1213         }
1216 int BC_ListBox::get_column_width(int column, int clamp_right)
1218         if(column < columns - 1 || !clamp_right)
1219                 return column_width ? 
1220                         column_width[column] : 
1221                         default_column_width[column];
1222         else
1223                 return popup_w + 
1224                         xposition - 
1225                         get_column_offset(column);
1228 int BC_ListBox::get_icon_mask(BC_ListBoxItem *item, 
1229         int &x, 
1230         int &y, 
1231         int &w, 
1232         int &h)
1234         if(display_format == LISTBOX_ICONS)
1235         {
1236                 x = get_item_x(item);
1237                 y = get_item_y(item);
1238                 w = get_icon_w(item) + ICON_MARGIN * 2;
1239                 h = get_icon_h(item) + ICON_MARGIN * 2;
1240         }
1241         else
1242         if(display_format == LISTBOX_TEXT)
1243         {
1244                 x = y = w = h = 0;
1245         }
1246         return 0;
1249 int BC_ListBox::get_text_mask(BC_ListBoxItem *item, 
1250         int &x, 
1251         int &y, 
1252         int &w, 
1253         int &h)
1255         x = get_item_x(item);
1256         y = get_item_y(item);
1258         if(display_format == LISTBOX_ICONS)
1259         {
1260                 if(icon_position == ICON_LEFT)
1261                 {
1262                         x += get_icon_w(item) + ICON_MARGIN * 2;
1263                         y += get_icon_h(item) - get_text_height(MEDIUMFONT);
1264                 }
1265                 else
1266                 {
1267                         y += get_icon_h(item) + ICON_MARGIN;
1268                 }
1270                 w = get_text_width(MEDIUMFONT, item->text) + ICON_MARGIN * 2;
1271                 h = get_text_height(MEDIUMFONT) + ICON_MARGIN * 2;
1272         }
1273         else
1274         if(display_format == LISTBOX_TEXT)
1275         {
1276                 w = get_text_width(MEDIUMFONT, item->text) + LISTBOX_MARGIN * 2;
1277                 h = get_text_height(MEDIUMFONT);
1278         }
1279         return 0;
1282 int BC_ListBox::get_item_highlight(ArrayList<BC_ListBoxItem*> *data, 
1283         int column, 
1284         int item)
1286         if(data[column].values[item]->selected)
1287                 return BLUE;
1288         else
1289         if(highlighted_item >= 0 &&
1290                 highlighted_ptr == data[master_column].values[item])
1291                 return LTGREY;
1292         else
1293                 return WHITE;
1296 int BC_ListBox::get_item_color(ArrayList<BC_ListBoxItem*> *data, 
1297         int column, 
1298         int item)
1300         int color = data[column].values[item]->color;
1301         if(get_item_highlight(data, column, item) == color)
1302                 return BLACK;
1303         else
1304                 return color;
1307 int BC_ListBox::get_from_column()
1309         return dragged_title;
1312 int BC_ListBox::get_to_column()
1314         return highlighted_title;
1318 BC_ListBoxItem* BC_ListBox::get_selection(int column, 
1319         int selection_number)
1321         return get_selection_recursive(data,
1322                 column,
1323                 selection_number);
1326 BC_ListBoxItem* BC_ListBox::get_selection_recursive(
1327         ArrayList<BC_ListBoxItem*> *data,
1328         int column,
1329         int selection_number)
1331         if(!data) return 0;
1333         for(int i = 0; i < data[master_column].total; i++)
1334         {
1335                 BC_ListBoxItem *item = data[master_column].values[i];
1336                 if(item->selected)
1337                 {
1338                         selection_number--;
1339                         if(selection_number < 0)
1340                         {
1342                                 return data[column].values[i];
1343                         }
1344                 }
1346                 if(item->get_sublist())
1347                 {
1348                         BC_ListBoxItem *result = get_selection_recursive(item->get_sublist(),
1349                                 column,
1350                                 selection_number);
1351                         if(result) return result;
1352                 }
1353         }
1354         return 0;
1358 int BC_ListBox::get_selection_number(int column, 
1359         int selection_number)
1361         return get_selection_number_recursive(data,
1362                 column,
1363                 selection_number);
1366 int BC_ListBox::get_selection_number_recursive(
1367         ArrayList<BC_ListBoxItem*> *data,
1368         int column,
1369         int selection_number,
1370         int *counter)
1372         int temp = -1;
1373         if(!data) return 0;
1374         if(!counter) counter = &temp;
1376         for(int i = 0; i < data[master_column].total; i++)
1377         {
1378                 (*counter)++;
1379                 BC_ListBoxItem *item = data[master_column].values[i];
1380                 if(item->selected)
1381                 {
1382                         selection_number--;
1383                         if(selection_number < 0)
1384                         {
1385                                 return (*counter);
1386                         }
1387                 }
1388                 if(item->get_sublist())
1389                 {
1390                         int result = get_selection_number_recursive(
1391                                 item->get_sublist(),
1392                                 column,
1393                                 selection_number,
1394                                 counter);
1395                         if(result >= 0) return result;
1396                 }
1397         }
1398         return -1;
1402 int BC_ListBox::set_selection_mode(int mode)
1404         this->selection_mode = mode;
1405         return 0;
1408 void BC_ListBox::delete_columns()
1410         if(column_titles)
1411         {
1412                 for(int i = 0; i < columns; i++)
1413                 {
1414                         delete [] column_titles[i];
1415                 }
1416                 delete [] column_titles;
1417         }
1419         if(column_width) delete [] column_width;
1420         
1421         column_titles = 0;
1422         column_width = 0;
1425 // Need to copy titles so EDL can change
1426 void BC_ListBox::set_columns(char **column_titles, 
1427         int *column_width, 
1428         int columns)
1430         if((!column_titles && column_width) ||
1431                 (column_titles && !column_width))
1432         {
1433                 printf("BC_ListBox::set_columns either column_titles or column_width == NULL but not both.\n");
1434                 return;
1435         }
1438         delete_columns();
1440         if(column_titles)
1441         {
1442                 this->column_titles = new char*[columns];
1443                 for(int i = 0; i < columns; i++)
1444                 {
1445                         this->column_titles[i] = new char[strlen(column_titles[i]) + 1];
1446                         strcpy(this->column_titles[i], column_titles[i]);
1447                 }
1448         }
1449         
1450         if(column_width)
1451         {
1452                 this->column_width = new int[columns];
1453                 for(int i = 0; i < columns; i++)
1454                 {
1455                         this->column_width[i] = column_width[i];
1456                 }
1457         }
1458         
1459         this->columns = columns;
1464 int BC_ListBox::update(ArrayList<BC_ListBoxItem*> *data,
1465         char **column_titles,
1466         int *column_widths,
1467         int columns,
1468         int xposition,
1469         int yposition, 
1470         int highlighted_number,
1471         int recalc_positions,
1472         int draw)
1475         set_columns(column_titles, 
1476                 column_widths, 
1477                 columns);
1479         this->data = data;
1481         this->yposition = yposition;
1482         this->xposition = xposition;
1483         this->highlighted_item = highlighted_number;
1484         this->highlighted_ptr = index_to_item(data, highlighted_number, 0);
1486         if(recalc_positions)
1487                 set_autoplacement(data, 1, 1);
1489         init_column_width();
1491         if(gui && draw)
1492         {
1493                 draw_background();
1494                 draw_items(1);
1495                 update_scrollbars();
1496         }
1498         return 0;
1501 void BC_ListBox::center_selection()
1503         int selection = get_selection_number(0, 0);
1505         calculate_item_coords();
1506         center_selection(selection);
1509         if(gui)
1510         {
1511                 draw_background();
1512                 draw_items(1);
1513                 update_scrollbars();
1514         }
1517 void BC_ListBox::move_vertical(int pixels)
1521 void BC_ListBox::move_horizontal(int pixels)
1525 int BC_ListBox::select_previous(int skip, 
1526         BC_ListBoxItem *selected_item,
1527         int *counter,
1528         ArrayList<BC_ListBoxItem*> *data,
1529         int *got_first,
1530         int *got_second)
1532         int top_level = 0;
1533         if(!selected_item)
1534                 selected_item = get_selection(0, 0);
1535         int temp = -1;
1536         if(!counter)
1537                 counter = &temp;
1538         int temp2 = 0;
1539         if(!got_first)
1540         {
1541                 got_first = &temp2;
1542                 top_level = 1;
1543         }
1544         int temp3 = 0;
1545         if(!got_second)
1546                 got_second = &temp3;
1547         if(!data)
1548                 data = this->data;
1549         int done = 0;
1551 // Scan backwards to item pointer.  Then count visible items to get 
1552 // destination.  Repeat to get wraparound.
1553         do
1554         {
1555                 for(int i = data[master_column].total - 1; i >= 0; i--)
1556                 {
1557                         BC_ListBoxItem *current_item = data[master_column].values[i];
1558                         if(current_item->get_sublist() &&
1559                                 current_item->get_expand())
1560                         {
1561                                 int result = select_previous(skip, 
1562                                         selected_item,
1563                                         counter,
1564                                         current_item->get_sublist(),
1565                                         got_first,
1566                                         got_second);
1567                                 if(*got_second)
1568                                 {
1569                                         return result;
1570                                 }
1571                         }
1573                         if(*got_first)
1574                         {
1575                                 (*counter)++;
1576                                 if((*counter) >= skip)
1577                                 {
1578                                         for(int j = 0; j < columns; j++)
1579                                                 data[j].values[i]->selected = 1;
1580                                         (*got_second) = 1;
1581                                         return item_to_index(this->data, current_item);
1582                                 }
1583                         }
1584                         else
1585                         {
1586                                 if(current_item->selected)
1587                                 {
1588                                         for(int j = 0; j < columns; j++)
1589                                                 data[j].values[i]->selected = 0;
1590                                         (*got_first) = 1;
1591                                         (*counter)++;
1592                                 }
1593                         }
1594                 }
1596 // Hit bottom of top level without finding a selected item.
1597                 if(top_level && !(*got_first)) (*got_first) = 1;
1598         }while(top_level && data[master_column].total);
1599         return -1;
1602 int BC_ListBox::select_next(int skip, 
1603         BC_ListBoxItem *selected_item,
1604         int *counter,
1605         ArrayList<BC_ListBoxItem*> *data,
1606         int *got_first,
1607         int *got_second)
1609         int top_level = 0;
1610         if(!selected_item)
1611                 selected_item = get_selection(0, 0);
1612         int temp = -1;
1613         if(!counter)
1614                 counter = &temp;
1615         int temp2 = 0;
1616         if(!got_first)
1617         {
1618                 got_first = &temp2;
1619                 top_level = 1;
1620         }
1621         int temp3 = 0;
1622         if(!got_second)
1623                 got_second = &temp3;
1624         if(!data)
1625                 data = this->data;
1626         int done = 0;
1628 // Scan backwards to item pointer.  Then count visible items to get 
1629 // destination.  Repeat to get wraparound.
1630         do
1631         {
1632                 for(int i = 0; i < data[master_column].total; i++)
1633                 {
1634                         BC_ListBoxItem *current_item = data[master_column].values[i];
1635                         if(*got_first)
1636                         {
1637                                 (*counter)++;
1638                                 if((*counter) >= skip)
1639                                 {
1640                                         for(int j = 0; j < columns; j++)
1641                                                 data[j].values[i]->selected = 1;
1642                                         (*got_second) = 1;
1643                                         return item_to_index(this->data, current_item);
1644                                 }
1645                         }
1646                         else
1647                         {
1648                                 if(current_item->selected)
1649                                 {
1650                                         for(int j = 0; j < columns; j++)
1651                                                 data[j].values[i]->selected = 0;
1652                                         (*got_first) = 1;
1653                                         (*counter)++;
1654                                 }
1655                         }
1657                         if(current_item->get_sublist() &&
1658                                 current_item->get_expand())
1659                         {
1660                                 int result = select_next(skip, 
1661                                         selected_item,
1662                                         counter,
1663                                         current_item->get_sublist(),
1664                                         got_first,
1665                                         got_second);
1666                                 if(*got_second)
1667                                 {
1668                                         return result;
1669                                 }
1670                         }
1671                 }
1673 // Hit bottom of top level without finding a selected item.
1674                 if(top_level && !(*got_first)) (*got_first) = 1;
1675         }while(top_level && data[master_column].total);
1676         return -1;
1680 void BC_ListBox::clamp_positions()
1682         items_w = get_items_width();
1683         items_h = get_items_height(data, columns);
1685         if(yposition < 0) yposition = 0;
1686         else
1687         if(yposition > items_h - view_h)
1688                 yposition = items_h - view_h;
1690         if(yposition < 0) yposition = 0;
1692         if(xposition < 0) xposition = 0;
1693         else
1694         if(xposition >= items_w - view_w)
1695                 xposition = items_w - view_w;
1697         if(xposition < 0) xposition = 0;
1700 int BC_ListBox::center_selection(int selection,
1701         ArrayList<BC_ListBoxItem*> *data,
1702         int *counter)
1704         int temp = -1;
1705         if(!data) data = this->data;
1706         if(!counter) counter = &temp;
1708         for(int i = 0; i < data[master_column].total; i++)
1709         {
1710                 (*counter)++;
1712 // Got it
1713                 BC_ListBoxItem *item = data[master_column].values[i];
1714                 if((*counter) == selection)
1715                 {
1716                         BC_ListBoxItem *top_item = this->data[master_column].values[0];
1719                         if(display_format == LISTBOX_ICONS)
1720                         {
1721 // Icon is out of window
1722                                 if(item->icon_y - yposition  > 
1723                                         view_h - get_text_height(MEDIUMFONT) ||
1724                                         item->icon_y - yposition < 0)
1725                                 {
1726                                         yposition = item->icon_y - view_h / 2;
1727                                 }
1729                                 if(data[master_column].values[selection]->icon_x - xposition > view_w ||
1730                                         data[master_column].values[selection]->icon_x - xposition < 0)
1731                                 {
1732                                         xposition = item->icon_x - view_w / 2;
1733                                 }
1734                         }
1735                         else
1736                         if(display_format == LISTBOX_TEXT)
1737                         {
1738 // Text coordinate is out of window
1739                                 if(item->text_y - yposition  > 
1740                                         view_h - get_text_height(MEDIUMFONT) ||
1741                                         item->text_y - yposition < 0)
1742                                 {
1743                                         yposition = item->text_y - 
1744                                                 top_item->text_y -
1745                                                 view_h / 2;
1746                                 }
1747                         }
1748                         return 1;
1749                 }
1751 // Descend
1752                 if(item->get_sublist())
1753                 {
1754                         int result = center_selection(selection,
1755                                 item->get_sublist(),
1756                                 counter);
1757                         if(result) return result;
1758                 }
1759         }
1760         return 0;
1763 void BC_ListBox::update_scrollbars()
1765         int h_needed = items_h = get_items_height(data, columns);
1766         int w_needed = items_w = get_items_width();
1768 // if(columns > 0 && column_width)
1769 // printf("BC_ListBox::update_scrollbars 1 %d %d\n", column_width[columns - 1], w_needed);
1771         if(xscrollbar)
1772         {
1773                 if(xposition != xscrollbar->get_value())
1774                         xscrollbar->update_value(xposition);
1776                 if(w_needed != xscrollbar->get_length() || 
1777                         view_w != xscrollbar->get_handlelength())
1778                         xscrollbar->update_length(w_needed, xposition, view_w);
1779         }
1781         if(yscrollbar)
1782         {
1783                 if(yposition != yscrollbar->get_value())
1784                         yscrollbar->update_value(yposition);
1786                 if(h_needed != yscrollbar->get_length() || view_h != yscrollbar->get_handlelength())
1787                         yscrollbar->update_length(h_needed, yposition, view_h);
1788         }
1791 int BC_ListBox::get_scrollbars()
1793         int h_needed = items_h = get_items_height(data, columns);
1794         int w_needed = items_w = get_items_width();
1798         title_h = get_title_h();
1800         view_h = popup_h - title_h - 4;
1801         view_w = popup_w - 4;
1803 // Create scrollbars as needed
1804         for(int i = 0; i < 2; i++)
1805         {
1806                 if(w_needed > view_w)
1807                 {
1808                         need_xscroll = 1;
1809                         view_h = popup_h - 
1810                                 title_h - 
1811                                 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h() - 
1812                                 4;
1813                 }
1814                 else
1815                 {
1816                         need_xscroll = 0;
1817                 }
1819                 if(h_needed > view_h)
1820                 {
1821                         need_yscroll = 1;
1822                         view_w = popup_w - 
1823                                 get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w() - 
1824                                 4;
1825                 }
1826                 else
1827                 {
1828                         need_yscroll = 0;
1829                 }
1830         }
1832 // Update subwindow size
1833         int new_w = popup_w;
1834         int new_h = popup_h;
1835         if(need_xscroll) new_h -= get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h();
1836         if(need_yscroll) new_w -= get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w();
1838         if(!is_popup)
1839                 if(new_w != BC_WindowBase::get_w() || new_h != BC_WindowBase::get_h())
1840                         gui->resize_window(new_w, new_h);
1842         BC_WindowBase *destination = (is_popup ? gui : parent_window);
1843         if(need_xscroll)
1844         {
1845                 if(!xscrollbar)
1846                 {
1847                         destination->add_subwindow(xscrollbar = 
1848                                 new BC_ListBoxXScroll(this, 
1849                                         w_needed, 
1850                                         view_w, 
1851                                         xposition));
1852                         xscrollbar->bound_to = this;
1853                 }
1854                 else
1855                 {
1856                     xscrollbar->update_length(w_needed, xposition, view_w);
1857                         xscrollbar->reposition_window(get_xscroll_x(),
1858                                 get_xscroll_y(),
1859                                 get_xscroll_width());
1860                 }
1861         }
1862         else
1863         {
1864                 if(xscrollbar) delete xscrollbar;
1865                 xscrollbar = 0;
1866                 xposition = 0;
1867         }
1869         if(need_yscroll)
1870         {
1871                 if(!yscrollbar)
1872                 {
1873                         destination->add_subwindow(yscrollbar = 
1874                                 new BC_ListBoxYScroll(this, 
1875                                         h_needed, 
1876                                         view_h, 
1877                                         yposition));
1878                         yscrollbar->bound_to = this;
1879                 }
1880                 else
1881                 {
1882                         yscrollbar->update_length(h_needed, yposition, view_h);
1883                         yscrollbar->reposition_window(get_yscroll_x(),
1884                                 get_yscroll_y(),
1885                                 get_yscroll_height());
1886                 }
1887         }
1888         else
1889         {
1890                 if(yscrollbar) delete yscrollbar;
1891                 yscrollbar = 0;
1892                 yposition = 0;
1893         }
1894         
1895         if(!bg_surface ||
1896                 view_w + 4 != bg_surface->get_w() ||
1897                 view_h + 4 != bg_surface->get_h())
1898         {
1899                 if(bg_surface) delete bg_surface;
1900                 bg_surface = new BC_Pixmap(gui, view_w + 4, view_h + 4);
1901                 draw_background();
1902         }
1904         return 0;
1909 void BC_ListBox::set_drag_scroll(int value)
1911         allow_drag_scroll = value;
1915 // Test for scrolling by dragging
1917 int BC_ListBox::test_drag_scroll(int cursor_x, int cursor_y)
1919         int result = 0;
1920         if(allow_drag_scroll || 
1921                 current_operation == SELECT_RECT)
1922         {
1924                 int top_boundary = get_title_h();
1926                 if(cursor_y < top_boundary ||
1927                         cursor_y >= view_h + title_h + LISTBOX_BORDER * 2 ||
1928                         cursor_x < LISTBOX_BORDER ||
1929                         cursor_x >= view_w + LISTBOX_BORDER)
1930                 {
1931                         result = 1;
1932                 }
1933         }
1934         return result;
1937 int BC_ListBox::drag_scroll_event()
1939         int top_boundary = get_title_h();
1940         int result = 0;
1942         if(get_cursor_y() < top_boundary)
1943         {
1944                 yposition -= top_boundary - get_cursor_y();
1945                 result = 1;
1946         }
1947         else
1948         if(get_cursor_y() >= view_h + title_h + 4)
1949         {
1950                 yposition += get_cursor_y() - (view_h + title_h + 4);
1951                 result = 1;
1952         }
1954         if(get_cursor_x() < 2)
1955         {
1956                 xposition -= 2 - get_cursor_x();
1957                 result = 1;
1958         }
1959         else
1960         if(get_cursor_x() >= view_w + 2)
1961         {
1962                 xposition += get_cursor_x() - (view_w + 2);
1963                 result = 1;
1964         }
1965         if(result) clamp_positions();
1966         return result;
1969 int BC_ListBox::rectangle_scroll_event()
1971         int old_xposition = xposition;
1972         int old_yposition = yposition;
1973         int result = drag_scroll_event();
1975         if(result)
1976         {
1977                 rect_x1 += old_xposition - xposition;
1978                 rect_y1 += old_yposition - yposition;
1979                 rect_x2 = get_cursor_x();
1980                 rect_y2 = get_cursor_y();
1982                 int x1 = MIN(rect_x1, rect_x2);
1983                 int x2 = MAX(rect_x1, rect_x2);
1984                 int y1 = MIN(rect_y1, rect_y2);
1985                 int y2 = MAX(rect_y1, rect_y2);
1987                 if(select_rectangle(data,
1988                         x1, 
1989                         y1,
1990                         x2, 
1991                         y2))
1992                 {
1993                         selection_changed();
1994                 }
1996                 clamp_positions();
1997                 draw_items(1);
1998                 update_scrollbars();
1999         }
2000         return result;
2003 int BC_ListBox::select_scroll_event()
2005         int result = drag_scroll_event();
2007         if(result)
2008         {
2009                 highlighted_item = selection_number = get_cursor_item(data, 
2010                         get_cursor_x(), 
2011                         get_cursor_y(),
2012                         &highlighted_ptr);
2013                 clamp_positions();
2014                 draw_items(1);
2015                 update_scrollbars();
2016                 selection_changed();
2017         }
2018         return result;
2021 int BC_ListBox::select_rectangle(ArrayList<BC_ListBoxItem*> *data,
2022                 int x1, 
2023                 int y1,
2024                 int x2, 
2025                 int y2)
2027         int result = 0;
2028         for(int i = 0; i < data[master_column].total; i++)
2029         {
2030                 for(int j = 0; j < columns; j++)
2031                 {
2032                         BC_ListBoxItem *item = data[j].values[i];
2033                         if(display_format == LISTBOX_ICONS)
2034                         {
2035                                 int icon_x, icon_y, icon_w, icon_h;
2036                                 int text_x, text_y, text_w, text_h;
2037                                 get_icon_mask(item, icon_x, icon_y, icon_w, icon_h);
2038                                 get_text_mask(item, text_x, text_y, text_w, text_h);
2040                                 if((x2 >= icon_x && x1 < icon_x + icon_w &&
2041                                         y2 >= icon_y && y1 < icon_y + icon_h) ||
2042                                         (x2 >= text_x && x1 < text_x + text_w &&
2043                                         y2 >= text_y && y1 < text_y + text_h))
2044                                 {
2045                                         if(!item->selected)
2046                                         {
2047                                                 item->selected = 1;
2048                                                 result = 1;
2049                                         }
2050                                 }
2051                                 else
2052                                 {
2053                                         if(item->selected)
2054                                         {
2055                                                 item->selected = 0;
2056                                                 result = 1;
2057                                         }
2058                                 }
2059                         }
2060                         else
2061                         {
2062                                 if(x2 >= 0 && 
2063                                         x1 < (yscrollbar ? 
2064                                                 gui->get_w() - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w() : 
2065                                                 gui->get_w()) &&
2066                                         y2 > 0 && 
2067                                         y1 < gui->get_h() &&
2068                                         y2 >= get_item_y(item) &&
2069                                         y1 < get_item_y(item) + get_item_h(item))
2070                                 {
2071                                         if(!item->selected)
2072                                         {
2073                                                 item->selected = 1;
2074                                                 result = 1;
2075                                         }
2076                                 }
2077                                 else
2078                                 {
2079                                         if(item->selected)
2080                                         {
2081                                                 item->selected = 0;
2082                                                 result = 1;
2083                                         }
2084                                 }
2085                         }
2086                 }
2088                 BC_ListBoxItem *item = data[master_column].values[i];
2089                 if(item->get_sublist() &&
2090                         item->get_expand())
2091                         result |= select_rectangle(item->get_sublist(),
2092                                 x1, 
2093                                 y1,
2094                                 x2, 
2095                                 y2);
2096         }
2097         return result;
2100 int BC_ListBox::reposition_item(ArrayList<BC_ListBoxItem*> *data,
2101                 int selection_number,
2102                 int x,
2103                 int y,
2104                 int *counter)
2106         int temp = -1;
2107         if(!counter) counter = &temp;
2110         for(int i = 0; i < data[master_column].total; i++)
2111         {
2112                 BC_ListBoxItem *item = data[master_column].values[i];
2113                 (*counter)++;
2114                 if((*counter) == selection_number)
2115                 {
2116                         item->icon_x = x;
2117                         item->icon_y = y;
2118                         return 1;
2119                 }
2120 // Not recursive because it's only used for icons
2121         }
2122         return 0;
2125 void BC_ListBox::move_selection(ArrayList<BC_ListBoxItem*> *dst,
2126         ArrayList<BC_ListBoxItem*> *src)
2128         for(int i = 0; i < src[master_column].total; i++)
2129         {
2130                 BC_ListBoxItem *item = src[master_column].values[i];
2132 // Move item to dst
2133                 if(item->selected)
2134                 {
2135                         for(int j = 0; j < columns; j++)
2136                         {
2137                                 dst[j].append(src[j].values[i]);
2138                                 src[j].remove_number(i);
2139                         }
2140                 }
2141                 else
2142 // Descend into sublist
2143                 if(item->get_sublist())
2144                 {
2145                         move_selection(dst, 
2146                                 item->get_sublist());
2147                 }
2148         }
2151 int BC_ListBox::put_selection(ArrayList<BC_ListBoxItem*> *data,
2152         ArrayList<BC_ListBoxItem*> *src,
2153         int destination,
2154         int *counter)
2156         int temp = -1;
2157         if(!counter) counter = &temp;
2159         if(destination < 0)
2160         {
2161                 for(int j = 0; j < columns; j++)
2162                 {
2163                         for(int i = 0; i < src[j].total; i++)
2164                         {
2165                                 data[j].append(src[j].values[i]);
2166                         }
2167                 }
2168                 return 1;
2169         }
2170         else
2171         for(int i = 0; i < data[master_column].total; i++)
2172         {
2173                 (*counter)++;
2174                 if((*counter) == destination)
2175                 {
2176                         for(int j = 0; j < columns; j++)
2177                         {
2178                                 for(int k = 0; k < src[j].total; k++)
2179                                 {
2180                                         data[j].insert(src[j].values[k], destination + k);
2181                                 }
2182                         }
2183                         return 1;
2184                 }
2186                 BC_ListBoxItem *item = data[master_column].values[i];
2187                 if(item->get_sublist())
2188                 {
2189                         if(put_selection(item->get_sublist(),
2190                                 src,
2191                                 destination,
2192                                 counter))
2193                                 return 1;
2194                 }
2195         }
2196         return 0;
2201 int BC_ListBox::item_to_index(ArrayList<BC_ListBoxItem*> *data,
2202                 BC_ListBoxItem *item,
2203                 int *counter)
2205         int temp = -1;
2206         if(!counter) counter = &temp;
2208         for(int i = 0; i < data[master_column].total; i++)
2209         {
2210                 (*counter)++;
2211                 for(int j = 0; j < columns; j++)
2212                 {
2213                         BC_ListBoxItem *new_item = data[j].values[i];
2214 //printf("BC_ListBox::item_to_index 1 %d %d %p\n", j, i, new_item);
2215                         if(new_item == item)
2216                         {
2217                                 return (*counter);
2218                         }
2219                 }
2221                 BC_ListBoxItem *new_item = data[master_column].values[i];
2222                 if(new_item->get_sublist())
2223                 {
2224                         if(item_to_index(new_item->get_sublist(),
2225                                 item,
2226                                 counter) >= 0)
2227                                 return (*counter);
2228                 }
2229         }
2231         return -1;
2234 BC_ListBoxItem* BC_ListBox::index_to_item(ArrayList<BC_ListBoxItem*> *data,
2235                 int number,
2236                 int column,
2237                 int *counter)
2239         int temp = -1;
2240         if(!counter) counter = &temp;
2241         for(int i = 0; i < data[master_column].total; i++)
2242         {
2243                 (*counter)++;
2244                 if((*counter) == number)
2245                 {
2246                         return data[column].values[i];
2247                 }
2248                 BC_ListBoxItem *item = data[master_column].values[i];
2249                 if(item->get_sublist())
2250                 {
2251                         BC_ListBoxItem *result = index_to_item(item->get_sublist(),
2252                                 number,
2253                                 column,
2254                                 counter);
2255                         if(result) return result;
2256                 }
2257         }
2258         return 0;
2261 int BC_ListBox::get_cursor_item(ArrayList<BC_ListBoxItem*> *data,
2262         int cursor_x, 
2263         int cursor_y, 
2264         BC_ListBoxItem **item_return,
2265         int *counter,
2266         int expanded)
2268         int temp = -1;
2269         if(!data) return -1;
2270         if(!counter) counter = &temp;
2272 // Icons are not treed
2273         if(display_format == LISTBOX_ICONS)
2274         {
2275                 for(int j = data[master_column].total - 1; j >= 0; j--)
2276                 {
2277                         int icon_x, icon_y, icon_w, icon_h;
2278                         int text_x, text_y, text_w, text_h;
2279                         BC_ListBoxItem *item = data[master_column].values[j];
2280                         get_icon_mask(item, icon_x, icon_y, icon_w, icon_h);
2281                         get_text_mask(item, text_x, text_y, text_w, text_h);
2283                         if((cursor_x >= icon_x && cursor_x < icon_x + icon_w &&
2284                                 cursor_y >= icon_y && cursor_y < icon_y + icon_h) ||
2285                                 (cursor_x >= text_x && cursor_x < text_x + text_w &&
2286                                 cursor_y >= text_y && cursor_y < text_y + text_h))
2287                         {
2288                                 if(item_return) (*item_return) = item;
2289                                 return j;
2290                         }
2291                 }
2292         }
2293         else
2294 // Text is treed
2295         if(display_format == LISTBOX_TEXT)
2296         {
2297 // Cursor is inside items rectangle
2298                 if(cursor_x >= 0 && 
2299                         cursor_x < (yscrollbar ? 
2300                                 gui->get_w() - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w() : 
2301                                 gui->get_w()) &&
2302 // Only clamp y if we're not in a SELECT operation.
2303                         (current_operation == BC_ListBox::SELECT ||
2304                                 (cursor_y > get_title_h() + LISTBOX_BORDER && 
2305                                 cursor_y < gui->get_h())))
2306                 {
2307 // Search table for cursor obstruction
2308                         for(int i = 0; i < data[master_column].total; i++)
2309                         {
2310                                 BC_ListBoxItem *item = data[master_column].values[i];
2311                                 (*counter)++;
2313 // Cursor is inside item on current level
2314                                 if(expanded &&
2315                                         item->selectable &&
2316                                         cursor_y >= get_item_y(item) &&
2317                                         cursor_y < get_item_y(item) + get_item_h(item))
2318                                 {
2319 //printf("BC_ListBox::get_cursor_item %d %d %p\n", master_column, i, item);
2320                                         if(item_return) (*item_return) = item;
2321                                         return (*counter);
2322                                 }
2324 // Descend into sublist
2325                                 if(item->get_sublist())
2326                                 {
2327                                         if(get_cursor_item(item->get_sublist(),
2328                                                 cursor_x, 
2329                                                 cursor_y, 
2330                                                 item_return,
2331                                                 counter,
2332                                                 item->get_expand()) >= 0)
2333                                                 return (*counter);
2334                                 }
2335                         }
2336                 }
2337         }
2338         return -1;
2341 int BC_ListBox::repeat_event(int64_t duration)
2343         switch(current_operation)
2344         {
2345 // Repeat out of bounds selection
2346                 case SELECT_RECT:
2347                         if(duration == get_resources()->scroll_repeat)
2348                                 return rectangle_scroll_event();
2349                         break;
2351                 case SELECT:
2352                         if(duration == get_resources()->scroll_repeat)
2353                                 return select_scroll_event();
2354                         break;
2356                 case NO_OPERATION:
2357 // Show tooltip
2358                         if(button_highlighted &&
2359                                 duration == get_resources()->tooltip_delay &&
2360                                 tooltip_text[0] != 0 &&
2361                                 is_popup &&
2362                                 !tooltip_done)
2363                         {
2364                                 show_tooltip();
2365                                 tooltip_done = 1;
2366                                 return 1;
2367                         }
2368                         break;
2369         }
2370         return 0;
2374 int BC_ListBox::cursor_enter_event()
2376         int result = 0;
2378         switch(current_operation)
2379         {
2380 // Cursor moved over button, pressed, and exited.
2381                 case BUTTON_DOWN_SELECT:
2382                         if(top_level->event_win == win)
2383                         {
2384                                 current_operation = BUTTON_DN;
2385                                 result = 1;
2386                                 button_highlighted = 1;
2387                                 draw_button();
2388                         }
2389                         break;
2391                 case NO_OPERATION:
2392 // Cursor entered button
2393                         if(is_popup && top_level->event_win == win)
2394                         {
2395                                 button_highlighted = 1;
2396                                 result = 1;
2397                                 draw_button();
2398                         }
2399                         else
2400 // TODO: Need to get the highlighted column title or item
2401                         if(gui && top_level->event_win == gui->win)
2402                         {
2403                                 list_highlighted = 1;
2404                                 draw_border(1);
2405                                 result = 1;
2406                         }
2407                         break;
2408         }
2410         return result;
2413 int BC_ListBox::cursor_leave_event()
2415         int redraw_button = 0;
2416         int redraw_border = 0;
2417         int redraw_titles = 0;
2418         int redraw_items = 0;
2420         if(current_operation == COLUMN_DRAG) return 0;
2422 // Left button area
2423         if(button_highlighted)
2424         {
2425                 button_highlighted = 0;
2426                 hide_tooltip();
2427                 draw_button();
2428         }
2430         if(list_highlighted)
2431         {
2432                 list_highlighted = 0;
2433                 highlighted_item = -1;
2434                 highlighted_ptr = 0;
2435                 highlighted_title = -1;
2436                 int redraw_toggles = 0;
2437                 for(int i = 0; i < expanders.total; i++)
2438                         expanders.values[i]->cursor_leave_event(&redraw_toggles);
2440                 draw_items(1);
2441         }
2443         return 0;
2446 int BC_ListBox::get_first_selection(ArrayList<BC_ListBoxItem*> *data, int *result)
2448         int temp = -1;
2449         if(!result) result = &temp;
2451         for(int i = 0; i < data[master_column].total; i++)
2452         {
2453                 BC_ListBoxItem *item = data[master_column].values[i];
2454                 (*result)++;
2455                 if(item->selected) return (*result);
2456                 if(item->get_sublist())
2457                 {
2458                         if(get_first_selection(item->get_sublist(), result) >= 0)
2459                                 return (*result);
2460                 }
2461         }
2462         return -1;
2465 int BC_ListBox::get_total_items(ArrayList<BC_ListBoxItem*> *data, 
2466         int *result,
2467         int master_column)
2469         int temp = 0;
2470         if(!result) result = &temp;
2472         for(int i = 0; i < data[master_column].total; i++)
2473         {
2474                 (*result)++;
2475                 if(data[master_column].values[i]->get_sublist())
2476                         get_total_items(data[master_column].values[i]->get_sublist(), 
2477                                 result,
2478                                 master_column);
2479         }
2481         return (*result);
2485 int BC_ListBox::get_last_selection(ArrayList<BC_ListBoxItem*> *data, 
2486         int *result)
2488         int temp = -1;
2489         int top_level = 0;
2490         if(!result)
2491         {
2492                 result = &temp;
2493                 top_level = 1;
2494         }
2496         for(int i = data[master_column].total - 1; i >= 0; i--)
2497         {
2498                 BC_ListBoxItem *item = data[master_column].values[i];
2499                 (*result)++;
2500                 if(item->selected)
2501                 {
2502                         if(top_level)
2503                                 return get_total_items(data, 0, master_column) - (*result) /* - 1 */;
2504                         else
2505                                 return (*result);
2506                 }
2508                 if(item->get_sublist())
2509                 {
2510                         if(get_last_selection(item->get_sublist(), result) >= 0)
2511                         {
2512                                 if(top_level)
2513                                         return get_total_items(data, 0, master_column) - (*result) /* - 1 */;
2514                                 else
2515                                         return (*result);
2516                         }
2517                 }
2518         }
2519         return -1;
2522 void BC_ListBox::select_range(ArrayList<BC_ListBoxItem*> *data,
2523                 int start,
2524                 int end,
2525                 int *current)
2527         int temp = -1;
2528         if(!current) current = &temp;
2530         for(int i = 0; i < data[master_column].total; i++)
2531         {
2532                 (*current)++;
2533                 if((*current) >= start && (*current) < end)
2534                 {
2535                         for(int j = 0; j < columns; j++)
2536                                 data[j].values[i]->selected = 1;
2537                 }
2538                 BC_ListBoxItem *item = data[master_column].values[i];
2539                 if(item->get_sublist())
2540                         select_range(item->get_sublist(),
2541                                 start,
2542                                 end,
2543                                 current);
2544         }
2548 // Fill items between current selection and new selection
2549 int BC_ListBox::expand_selection(int button_press, int selection_number)
2551         int old_selection_start = selection_start;
2552         int old_selection_end = selection_end;
2554 // printf("BC_ListBox::expand_selection %d %d\n", 
2555 // selection_center, 
2556 // selection_number);
2558 // Calculate the range to select based on selection_center and selection_number
2559         if(selection_number < selection_center)
2560         {
2561                 selection_start = selection_number;
2562         }
2563         else
2564         {
2565                 selection_end = selection_number + 1;
2566         }
2568 //printf("BC_ListBox::expand_selection %d %d %d %d\n", old_selection_start, old_selection_end, selection_start, selection_end);
2569 // Recurse through all the items and select the desired range
2570         select_range(data, selection_start, selection_end);
2572 // Trigger redraw
2573         return (old_selection_start != selection_start ||
2574                 old_selection_end != selection_end);
2577 int BC_ListBox::toggle_item_selection(ArrayList<BC_ListBoxItem*> *data,
2578         int selection_number,
2579         int *counter)
2581         int temp = -1;
2582         if(!counter) counter = &temp;
2584         for(int i = 0; i < data[master_column].total; i++)
2585         {
2586                 BC_ListBoxItem *item = data[master_column].values[i];
2587                 (*counter)++;
2588                 if((*counter) == selection_number)
2589                 {
2590 // Get new value for selection
2591                         int selected = !item->selected;
2592 // Set row
2593                         for(int j = 0; j < columns; j++)
2594                                 data[j].values[i]->selected = selected;
2595                         return 1;
2596                 }
2598 // Descend into sublist
2599                 if(item->get_sublist())
2600                 {
2601                         if(toggle_item_selection(item->get_sublist(),
2602                                 selection_number,
2603                                 counter))
2604                                 return 1;
2605                 }
2606         }
2608         return 0;
2612 void BC_ListBox::set_all_selected(ArrayList<BC_ListBoxItem*> *data, int value)
2614         for(int i = 0; i < data[master_column].total; i++)
2615         {
2616                 for(int j = 0; j < columns; j++)
2617                 {
2618                         BC_ListBoxItem *item = data[j].values[i];
2619                         item->selected = value;
2620                 }
2621                 BC_ListBoxItem *item = data[master_column].values[i];
2622                 if(item->get_sublist())
2623                 {
2624                         set_all_selected(item->get_sublist(), value);
2625                 }
2626         }
2629 void BC_ListBox::set_selected(ArrayList<BC_ListBoxItem*> *data, 
2630                 int item_number, 
2631                 int value,
2632                 int *counter)
2634         int temp = -1;
2635         if(!counter) counter = &temp;
2636         for(int i = 0; i < data[master_column].total && (*counter) != item_number; i++)
2637         {
2638                 (*counter)++;
2639                 if((*counter) == item_number)
2640                 {
2641                         for(int j = 0; j < columns; j++)
2642                         {
2643                                 BC_ListBoxItem *item = data[j].values[i];
2644                                 item->selected = value;
2645                         }
2646                         return;
2647                 }
2649                 BC_ListBoxItem *item = data[master_column].values[i];
2650                 if(item->get_sublist())
2651                 {
2652                         set_selected(item->get_sublist(), 
2653                                 item_number, 
2654                                 value,
2655                                 counter);
2656                 }
2657         }
2660 int BC_ListBox::update_selection(ArrayList<BC_ListBoxItem*> *data, 
2661         int selection_number,
2662         int *counter)
2664         int temp = -1;
2665         int result = 0;
2666         if(!counter) counter = &temp;
2668         for(int i = 0; i < data[master_column].total; i++)
2669         {
2670                 BC_ListBoxItem *item = data[master_column].values[i];
2671                 (*counter)++;
2672                 if((*counter) == selection_number && !item->selected)
2673                 {
2674                         result = 1;
2675                         for(int j = 0; j < columns; j++)
2676                                 data[j].values[i]->selected = 1;
2677                 }
2678                 else
2679                 if((*counter) != selection_number && item->selected)
2680                 {
2681                         result = 1;
2682                         for(int j = 0; j < columns; j++)
2683                                 data[j].values[i]->selected = 0;
2684                 }
2685                 if(item->get_sublist())
2686                         result |= update_selection(item->get_sublist(), 
2687                                 selection_number,
2688                                 counter);
2689         }
2690         return result;
2693 void BC_ListBox::promote_selections(ArrayList<BC_ListBoxItem*> *data,
2694         int old_value,
2695         int new_value)
2697         for(int i = 0; i < data[master_column].total; i++)
2698         {
2699                 for(int j = 0; j < columns; j++)
2700                 {
2701                         BC_ListBoxItem *item = data[j].values[i];
2702                         if(item->selected == old_value) item->selected = new_value;
2703                 }
2704                 BC_ListBoxItem *item = data[master_column].values[i];
2705                 if(item->get_sublist())
2706                         promote_selections(item->get_sublist(), old_value, new_value);
2707         }
2710 int BC_ListBox::focus_out_event()
2712         deactivate();
2713         return 0;
2716 int BC_ListBox::button_press_event()
2718         int result = 0;
2719         BC_ListBoxItem *current_item = 0;
2720         int new_cursor;
2721         int do_selection_change = 0;
2723         hide_tooltip();
2727 // Pressed in button
2728         if(is_popup && top_level->event_win == win)
2729         {
2730                 current_operation = BUTTON_DN;
2731                 draw_button();
2733 // Deploy listbox
2734                 if(!active)
2735                 {
2736                         top_level->deactivate();
2737                         activate();
2738                 }
2740                 result = 1;
2741         }
2742         else
2743 // Pressed in scrollbar
2744         if((xscrollbar && top_level->event_win == xscrollbar->win) ||
2745                 (yscrollbar && top_level->event_win == yscrollbar->win))
2746         {
2747                 result = 0;
2748         }
2749         else
2750 // Pressed in items
2751         if(gui && top_level->event_win == gui->win)
2752         {
2753 // Activate list items
2754                 if(!active)
2755                 {
2756                         top_level->deactivate();
2757                         activate();
2758                 }
2760 // Wheel mouse pressed
2761                 if(get_buttonpress() == 4)
2762                 {
2763                         current_operation = WHEEL;
2764                         if(yscrollbar)
2765                         {
2766                                 set_yposition(yposition - gui->get_h() / 10, 0);
2767                                 clamp_positions();
2768                                 update_scrollbars();
2769                                 highlighted_ptr = 0;
2770                                 highlighted_item = get_cursor_item(data,
2771                                         top_level->cursor_x, 
2772                                         top_level->cursor_y, 
2773                                         &highlighted_ptr);
2774                                 draw_items(1);
2775                                 result = 1;
2776                         }
2777                 }
2778                 else
2779                 if(get_buttonpress() == 5)
2780                 {
2781                         current_operation = WHEEL;
2782                         if(yscrollbar)
2783                         {
2784                                 set_yposition(yposition + gui->get_h() / 10, 0);
2785                                 clamp_positions();
2786                                 update_scrollbars();
2787                                 highlighted_ptr = 0;
2788                                 highlighted_item = get_cursor_item(data,
2789                                         top_level->cursor_x, 
2790                                         top_level->cursor_y,
2791                                         &highlighted_ptr);
2792                                 draw_items(1);
2793                                 result = 1;
2794                         }
2795                 }
2796                 else
2797 // Pressed over column title division
2798                 if(test_column_divisions(gui->get_cursor_x(), 
2799                         gui->get_cursor_y(), 
2800                         new_cursor))
2801                 {
2802                         current_operation = DRAG_DIVISION;
2803                         reset_query();
2804                 }
2805                 else
2806 // Pressed in column title
2807                 if(test_column_titles(gui->get_cursor_x(), gui->get_cursor_y()))
2808                 {
2809                         current_operation = COLUMN_DN;
2810                         button_highlighted = 0;
2811                         list_highlighted = 1;
2812                         draw_items(1);
2813                         result = 1;
2814                 }
2815                 else
2816 // Pressed in expander
2817                 if(test_expanders())
2818                 {
2819                         current_operation = EXPAND_DN;
2820 // Need to redraw items because of alpha
2821                         draw_items(1);
2822                         result = 1;
2823                 }
2824                 else
2825 // Pressed over item
2826                 if((selection_number = get_cursor_item(data, 
2827                                         gui->get_cursor_x(), 
2828                                         gui->get_cursor_y(),
2829                                         &current_item)) >= 0)
2830                 {
2831 // Get item button was pressed over
2832                         selection_number2 = selection_number1;
2833                         selection_number1 = selection_number;
2835                         selection_start = -1;
2836                         selection_end = -1;
2839 // Multiple item selection is possible
2840                         if(selection_mode == LISTBOX_MULTIPLE && 
2841                                 (ctrl_down() || shift_down()))
2842                         {
2843 // Expand text selection.
2844 // Fill items between selected region and current item.
2845                                 if(shift_down() && display_format == LISTBOX_TEXT)
2846                                 {
2847 // Get first item selected
2848                                         selection_start = get_first_selection(data);
2849 // Get last item selected
2850                                         selection_end = get_last_selection(data);
2851 // Get center of selected region
2852                                         if(selection_end > selection_start)
2853                                         {
2854                                                 selection_center = (selection_end + selection_start) >> 1;
2855                                         }
2856                                         else
2857                                         {
2858                                                 selection_center = selection_number;
2859                                         }
2862 // Deselect everything.
2863                                         set_all_selected(data, 0);
2864 // Select just the items
2865                                         expand_selection(1, selection_number);
2866                                         new_value = 1;
2867                                 }
2868                                 else
2869 // Toggle a single item on or off
2870                                 {
2871                                         toggle_item_selection(data, selection_number);
2872                                         new_value = current_item->selected;
2873                                 }
2874                         }
2875                         else
2876 // Select single item
2877                         {
2878                                 if(!current_item->selected)
2879                                 {
2880                                         set_all_selected(data, 0);
2881                                         set_selected(data,
2882                                                 selection_number,
2883                                                 1);
2884                                 }
2885                                 new_value = 1;
2886                         }
2889                         current_operation = SELECT;
2890                         highlighted_item = selection_number;
2891                         highlighted_ptr = current_item;
2892                         button_highlighted = 0;
2893                         list_highlighted = 1;
2894                         reset_query();
2895                         draw_items(1);
2896                         do_selection_change = 1;
2897                         result = 1;
2898                 }
2899                 else
2900                 if(data)
2901 // Pressed over nothing.  Start rectangle selection.
2902                 {
2903                         if(get_buttonpress() == 1 && 
2904                                 selection_mode == LISTBOX_MULTIPLE)
2905                         {
2906                                 if(!shift_down())
2907                                 {
2908 // Deselect all and redraw if anything was selected
2909                                         if(get_selection_number(0, 0) >= 0)
2910                                         {
2911                                                 set_all_selected(data, 0);
2912                                                 draw_items(1);
2913                                                 do_selection_change = 1;
2914                                                 result = 1;
2915                                         }
2916                                 }
2917                                 else
2918                                 {
2919 // Promote selections to protect from a rectangle selection
2920                                         promote_selections(data, 1, 2);
2921                                 }
2923 // Start rectangle selection
2924                                 current_operation = SELECT_RECT;
2925                                 rect_x1 = rect_x2 = get_cursor_x();
2926                                 rect_y1 = rect_y2 = get_cursor_y();
2927                         }
2928                 }
2931                 reset_query();
2932         }
2933         else
2934         if(is_popup && active)
2935         {
2936                 deactivate();
2937                 result = 1;
2938         }
2941         if(do_selection_change) selection_changed();
2943         return result;
2946 int BC_ListBox::button_release_event()
2948         int result = 0;
2949         int cursor_x, cursor_y;
2950         int do_event = 0;
2951         new_value = 0;
2953 //printf("BC_ListBox::button_release_event 1 %d\n", current_operation);
2954         switch(current_operation)
2955         {
2956                 case DRAG_DIVISION:
2957                         current_operation = NO_OPERATION;
2958                         result = 1;
2959                         break;
2961                 case WHEEL:
2962                         current_operation = NO_OPERATION;
2963                         result = 1;
2964                         break;
2966 // Release item selection
2967                 case BUTTON_DOWN_SELECT:
2968                 case SELECT:
2969 //printf("BC_ListBox::button_release_event 10\n");
2970                         unset_repeat(get_resources()->scroll_repeat);
2971                         current_operation = NO_OPERATION;
2972                         translate_coordinates(top_level->event_win,
2973                                 gui->win,
2974                                 gui->get_cursor_x(),
2975                                 gui->get_cursor_y(),
2976                                 &cursor_x,
2977                                 &cursor_y);
2979                         selection_number1 = 
2980                                 selection_number = 
2981                                 get_cursor_item(data, cursor_x, cursor_y);
2982 //printf("BC_ListBox::button_release_event %d %d\n", selection_number2, selection_number1);
2984                         if(is_popup)
2985                         {
2986                                 button_releases++;
2987                                 if(selection_number >= 0)
2988                                 {
2989                                         deactivate();
2990                                         do_event = 1;
2991                                 }
2992                                 else
2993 // Second button release outside button
2994                                 if(button_releases > 1)
2995                                 {
2996                                         deactivate();
2997                                 }
2998                         }
2999                         else
3000                         {
3001                                 if(top_level->get_double_click() &&
3002                                         selection_number2 == selection_number1 &&
3003                                         selection_number2 >= 0 &&
3004                                         selection_number1 >= 0)
3005                                 {
3006                                         do_event = 1;
3007                                 }
3008                                 result = 1;
3009                         }
3010                         break;
3013                 case SELECT_RECT:
3014                         unset_repeat(get_resources()->scroll_repeat);
3015                         if(data)
3016                         {
3017 // Demote selections from rectangle selection
3018                                 promote_selections(data, 2, 1);
3019                         }
3021 // Hide rectangle overlay
3022                         draw_rectangle(1);
3023                         current_operation = NO_OPERATION;
3024                         result = 1;
3025                         break;
3027 // Release popup button
3028                 case BUTTON_DN:
3029                         hide_tooltip();
3030                         current_operation = NO_OPERATION;
3031                         button_releases++;
3032                         draw_button();
3034 // Second button release inside button
3035                         if(button_releases > 1)
3036                         {
3037                                 deactivate();
3038                         }
3039                         result = 1;
3040                         break;
3042                 case COLUMN_DN:
3043                         current_operation = NO_OPERATION;
3044 // Update the sort column and the sort order for the user only if the existing
3045 // sort column is valid.
3046                         if(sort_column >= 0)
3047                         {
3048 // Invert order only if column is the same
3049                                 if(highlighted_title == sort_column)
3050                                         sort_order = 
3051                                                 (sort_order == SORT_ASCENDING) ? 
3052                                                 SORT_DESCENDING : 
3053                                                 SORT_ASCENDING;
3054 // Set the new sort column
3055                                 sort_column = highlighted_title;
3056                                 if(!sort_order_event())
3057                                 {
3058                                         draw_titles(1);
3059                                 }
3060                         }
3061                         else
3062 // Sorting not enabled.  Redraw the title state.
3063                         {
3064                                 draw_titles(1);
3065                         }
3066                         result = 1;
3067                         break;
3069                 case EXPAND_DN:
3070                 {
3071                         int redraw_toggles = 0;
3072                         for(int i = 0; i < expanders.total && !result; i++)
3073                         {
3074                                 if(expanders.values[i]->button_release_event(&redraw_toggles))
3075                                 {
3076                                         result = 1;
3077                                 }
3078                         }
3079 // Need to redraw items because of alpha
3080                         if(redraw_toggles) draw_items(1);
3081                         current_operation = NO_OPERATION;
3082                         break;
3083                 }
3085                 default:
3086 // Can't default to NO_OPERATION because it may be used in a drag event.
3087                         break;
3088         }
3091         if(do_event) handle_event();
3093         return result;
3096 int BC_ListBox::get_title_h()
3098         if(display_format == LISTBOX_TEXT)
3099                 return column_titles ? column_bg[0]->get_h() : 0;
3100         else
3101                 return 0;
3104 void BC_ListBox::reset_cursor(int new_cursor)
3106         if(is_popup)
3107         {
3108                 if(gui->get_cursor() != new_cursor)
3109                 {
3110                         gui->set_cursor(new_cursor);
3111                 }
3112         }
3113         else
3114         if(get_cursor() != new_cursor)
3115         {
3116                 set_cursor(new_cursor);
3117         }
3120 int BC_ListBox::test_column_divisions(int cursor_x, int cursor_y, int &new_cursor)
3122         if(gui &&
3123                 column_titles && 
3124                 cursor_y >= 0 && 
3125                 cursor_y < get_title_h() &&
3126                 cursor_x >= 0 &&
3127                 cursor_x < gui->get_w())
3128         {
3129                 for(int i = 1; i < columns; i++)
3130                 {
3131                         if(cursor_x >= -xposition + get_column_offset(i) - 5 &&
3132                                 cursor_x <  -xposition + get_column_offset(i) + 5)
3133                         {
3134                                 highlighted_item = -1;
3135                                 highlighted_ptr = 0;
3136                                 highlighted_division = i;
3137                                 highlighted_title = -1;
3138                                 list_highlighted = 1;
3139                                 new_cursor = HSEPARATE_CURSOR;
3140                                 return 1;
3141                         }
3142                 }
3143         }
3144         highlighted_division = -1;
3145         return 0;
3148 int BC_ListBox::test_column_titles(int cursor_x, int cursor_y)
3150         if(gui &&
3151                 column_titles && 
3152                 cursor_y >= 0 && 
3153                 cursor_y < get_title_h() &&
3154                 cursor_x >= 0 && 
3155                 cursor_x < gui->get_w())
3156         {
3157                 for(int i = 0; i < columns; i++)
3158                 {
3159                         if(cursor_x >= -xposition + get_column_offset(i) &&
3160                                 (cursor_x < -xposition + get_column_offset(i + 1) ||
3161                                         i == columns - 1))
3162                         {
3163                                 highlighted_item = -1;
3164                                 highlighted_ptr = 0;
3165                                 highlighted_division = -1;
3166                                 highlighted_title = i;
3167                                 list_highlighted = 1;
3168                                 return 1;
3169                         }
3170                 }
3171         }
3172         highlighted_title = -1;
3173         return 0;
3176 int BC_ListBox::test_expanders()
3178         for(int i = 0; i < expanders.total; i++)
3179         {
3180                 if(expanders.values[i]->button_press_event())
3181                 {
3182                         current_operation = EXPAND_DN;
3183                         draw_toggles(1);
3184                         return 1;
3185                 }
3186         }
3187         return 0 ;
3190 int BC_ListBox::cursor_motion_event()
3192         int redraw = 0, result = 0;
3193         int new_cursor = ARROW_CURSOR;
3195         selection_number = -1;
3198         switch(current_operation)
3199         {
3200                 case BUTTON_DN:
3201 // Button pressed and slid off button
3202                         if(!cursor_inside())
3203                         {
3204                                 current_operation = BUTTON_DOWN_SELECT;
3205                                 draw_button();
3206                                 result = 1;
3207                         }
3208                         break;
3210                 case DRAG_DIVISION:
3211                 {
3212                         int new_w = get_cursor_x() + 
3213                                 xposition - 
3214                                 get_column_offset(highlighted_division - 1);
3215                         new_cursor = HSEPARATE_CURSOR;
3217                         if(column_width)
3218                         {
3219                                 column_width[highlighted_division - 1] = new_w;
3220                         }
3221                         else
3222                         {
3223                                 default_column_width[highlighted_division - 1] = new_w;
3224                         }
3226                         column_width_boundaries();
3228 // Force update of coords
3229                         set_autoplacement(data, 0, 1);
3230                         column_resize_event();
3232                         clamp_positions();
3233                         draw_items(1);
3234                         update_scrollbars();
3235                         result = 1;
3236                         break;
3237                 }
3239                 case SELECT_RECT:
3240                 {
3241                         if(test_drag_scroll(get_cursor_x(), get_cursor_y()))
3242                         {
3243                                 set_repeat(get_resources()->scroll_repeat);
3244                         }
3246                         int old_x1 = MIN(rect_x1, rect_x2);
3247                         int old_x2 = MAX(rect_x1, rect_x2);
3248                         int old_y1 = MIN(rect_y1, rect_y2);
3249                         int old_y2 = MAX(rect_y1, rect_y2);
3251                         int new_rect_x2 = get_cursor_x();
3252                         int new_rect_y2 = get_cursor_y();
3254                         int x1 = MIN(rect_x1, new_rect_x2);
3255                         int x2 = MAX(rect_x1, new_rect_x2);
3256                         int y1 = MIN(rect_y1, new_rect_y2);
3257                         int y2 = MAX(rect_y1, new_rect_y2);
3259 // Adjust rectangle coverage
3260                         if(old_x1 != x1 ||
3261                                 old_x2 != x2 ||
3262                                 old_y1 != y1 ||
3263                                 old_y2 != y2)
3264                         {
3265                                 if(data)
3266                                 {
3267                                         redraw = select_rectangle(data,
3268                                                 x1, 
3269                                                 y1,
3270                                                 x2, 
3271                                                 y2);
3272                                 }
3274 // hide rectangle
3275                                 if(!redraw)
3276                                         draw_rectangle(0);
3277                         }
3279                         rect_x2 = get_cursor_x();
3280                         rect_y2 = get_cursor_y();
3281                         if(redraw)
3282                         {
3283                                 clamp_positions();
3284                                 draw_items(1);
3285                                 update_scrollbars();
3286                                 selection_changed();
3287                         }
3288                         else
3289                         {
3290                                 draw_rectangle(1);
3291                         }
3292                         result = 1;
3293                         break;
3294                 }
3296                 case SELECT:
3297                 {
3298                         int old_highlighted_item = highlighted_item;
3299                         int old_highlighted_title = highlighted_title;
3300                         BC_ListBoxItem *old_highlighted_ptr = highlighted_ptr;
3302                         if(test_drag_scroll(get_cursor_x(), 
3303                                 get_cursor_y()))
3304                         {
3305                                 set_repeat(get_resources()->scroll_repeat);
3306                         }
3309                         highlighted_item = selection_number = get_cursor_item(data, 
3310                                 get_cursor_x(), 
3311                                 get_cursor_y(),
3312                                 &highlighted_ptr);
3313                         result = 1;
3315 // Deselect all items and select just the one we're over
3316                         if(selection_number >= 0 && 
3317                                 !allow_drag &&
3318                                 ((!shift_down() &&
3319                                         !ctrl_down()) ||
3320                                         selection_mode == LISTBOX_SINGLE))
3321                         {
3322                                 redraw = update_selection(data, selection_number);
3323                         }
3324                         else
3325                         if(selection_mode == LISTBOX_MULTIPLE &&
3326                                 (shift_down() || ctrl_down()))
3327 // Expand multiple selection
3328                         {
3329 // Expand selected region in text mode centered around initial range
3330                                 if(display_format == LISTBOX_TEXT && shift_down())
3331                                 {
3332 // Deselect everything.
3333                                         set_all_selected(data, 0);
3335 // Select just the items
3336                                         redraw = expand_selection(0, selection_number);
3337                                 }
3338                                 else
3339 // Set the one item we're over to the selection value determined in
3340 // button_press_event.
3341                                 {
3342                                         set_selected(data, 
3343                                                 selection_number, 
3344                                                 new_value);
3345                                 }
3346                         }
3348                         if(highlighted_item != old_highlighted_item)
3349                         {
3350                                 clamp_positions();
3351                                 draw_items(1);
3352                                 update_scrollbars();
3353 //printf("BC_ListBox::cursor_motion_event %d %d\n", highlighted_item, old_highlighted_item);
3354                                 selection_changed();
3355                         }
3356                         break;
3357                 }
3359                 case BUTTON_DOWN_SELECT:
3360 // Went back into button area
3361                         if(cursor_inside())
3362                         {
3363                                 current_operation = BUTTON_DN;
3364                                 draw_button();
3365                                 result = 1;
3366                         }
3367                         else
3368 // Went into item area
3369                         if(gui)
3370                         {
3371                                 int cursor_x = 0, cursor_y = 0;
3372                                 translate_coordinates(top_level->event_win, 
3373                                         gui->win,
3374                                         top_level->cursor_x,
3375                                         top_level->cursor_y,
3376                                         &cursor_x,
3377                                         &cursor_y);
3378                                 int old_highlighted_item = highlighted_item;
3379                                 highlighted_item = selection_number = get_cursor_item(data, 
3380                                                 cursor_x, 
3381                                                 cursor_y,
3382                                                 &highlighted_ptr);
3384                                 if(highlighted_item != old_highlighted_item)
3385                                 {
3386                                         update_selection(data, selection_number);
3387                                         draw_items(1);
3388                                         selection_changed();
3389                                 }
3390                         }
3391                         break;
3393                 case EXPAND_DN:
3394                 {
3395                         int redraw_toggles = 0;
3396                         for(int i = 0; i < expanders.total && !result; i++)
3397                         {
3398                                 result = expanders.values[i]->cursor_motion_event(
3399                                         &redraw_toggles);
3400                         }
3401                         if(redraw_toggles)
3402                         {
3403 // Need to redraw items because of the alpha
3404                                 draw_items(1);
3405                         }
3406                         break;
3407                 }
3409                 case NO_OPERATION:
3410                 {
3411                         int cursor_x = get_cursor_x(), cursor_y = get_cursor_y();
3412                         if(gui && top_level->event_win == gui->win)
3413                         {
3414                                 int old_highlighted_title = highlighted_title;
3415                                 int old_list_highlighted = list_highlighted;
3416                                 int old_highlighted_division = highlighted_division;
3417                                 int old_highlighted_item = highlighted_item;
3418                                 int redraw_titles = 0;
3419                                 int redraw_border = 0;
3420                                 int redraw_items = 0;
3421                                 int redraw_toggles = 0;
3422                                 result = 1;
3425 // Test if cursor moved over a title division
3426                                 test_column_divisions(cursor_x, cursor_y, new_cursor);
3428 // Test if cursor moved over a title
3429                                 if(highlighted_division < 0)
3430                                 {
3431                                         test_column_titles(cursor_x, cursor_y);
3432                                 }
3434 // Test if cursor moved over expander
3435                                 if(highlighted_division < 0 && 
3436                                         highlighted_title < 0 &&
3437                                         display_format == LISTBOX_TEXT)
3438                                 {
3439                                         for(int i = 0; i < expanders.total; i++)
3440                                         {
3441                                                 expanders.values[i]->cursor_motion_event(
3442                                                         &redraw_toggles);
3443                                         }
3444 //printf("BC_ListBox::cursor_motion_event %d\n", redraw_toggles);
3445                                 }
3447 // Test if cursor moved over an item
3448                                 if(highlighted_division < 0 && 
3449                                         highlighted_title < 0)
3450                                 {
3451                                         highlighted_item = get_cursor_item(data, 
3452                                                 cursor_x, 
3453                                                 cursor_y,
3454                                                 &highlighted_ptr);
3455                                 }
3458 // Clear title highlighting if moved over division
3459                                 if(old_highlighted_title != highlighted_title)
3460                                 {
3461                                         redraw_titles = 1;
3462                                 }
3464 // Highlight list border
3465                                 if(old_list_highlighted != list_highlighted)
3466                                 {
3467                                         redraw_border = 1;
3468                                 }
3470 // Moved out of item area
3471                                 if(old_highlighted_item != highlighted_item)
3472                                 {
3473                                         redraw_items = 1;
3474                                 }
3476 //printf("BC_ListBox::cursor_motion_event 1 %d\n", highlighted_item);
3478 // Change cursor to title division adjustment
3479                                 reset_cursor(new_cursor);
3481                                 if(redraw_items)
3482                                 {
3483                                         draw_items(0);
3484                                 }
3485                                 else
3486                                 {
3487                                         if(redraw_titles)
3488                                                 draw_titles(0);
3489                                         if(redraw_border)
3490                                                 draw_border(0);
3491                                         if(redraw_toggles)
3492                                                 draw_toggles(0);
3493                                 }
3495                                 if(redraw_items || 
3496                                         redraw_titles || 
3497                                         redraw_border || 
3498                                         redraw_toggles)
3499                                 {
3500                                         gui->flash();
3501                                         gui->flush();
3502                                 }
3503                         }
3506                         if(!result && list_highlighted)
3507                         {
3508                                 list_highlighted = 0;
3509                                 highlighted_item = -1;
3510                                 highlighted_ptr = 0;
3511                                 highlighted_title = -1;
3512                                 highlighted_division = -1;
3513                                 draw_items(1);
3514                                 result = 0;
3515                         }
3516                         break;
3517                 }
3518         }
3521         return result;
3524 int BC_ListBox::drag_start_event()
3526         switch(current_operation)
3527         {
3528                 case SELECT:
3529                         if(gui && 
3530                                 gui->is_event_win() && 
3531                                 allow_drag)
3532                         {
3533                                 BC_ListBoxItem *item_return = 0;
3534                                 selection_number = get_cursor_item(data, 
3535                                         top_level->cursor_x, 
3536                                         top_level->cursor_y,
3537                                         &item_return);
3539                                 if(selection_number >= 0)
3540                                 {
3541                                         
3542                                         if (item_return->icon_vframe)
3543                                         {
3544                                                 drag_popup = new BC_DragWindow(this, 
3545                                                         item_return->icon_vframe, 
3546                                                         get_abs_cursor_x(0) - item_return->icon_vframe->get_w() / 2,
3547                                                         get_abs_cursor_y(0) - item_return->icon_vframe->get_h() / 2);
3548                                         }
3549                                         else    
3550 // this probably works not!
3551                                         if (item_return->icon)  
3552                                                 drag_popup = new BC_DragWindow(this, 
3553                                                         item_return->icon, 
3554                                                         get_abs_cursor_x(0) - item_return->icon->get_w() / 2,
3555                                                         get_abs_cursor_y(0) - item_return->icon->get_h() / 2);
3556                                         else
3557                                                 drag_popup = new BC_DragWindow(this, 
3558                                                         drag_icon_vframe, 
3559                                                         get_abs_cursor_x(0) - drag_icon_vframe->get_w() / 2,
3560                                                         get_abs_cursor_y(0) - drag_icon_vframe->get_h() / 2);
3561                                         current_operation = DRAG_ITEM;
3562                                         return 1;
3563                                 }
3564                         }
3565                         break;
3567                 case COLUMN_DN:
3568                         if(gui && gui->is_event_win() && allow_drag_column)
3569                         {
3570                                 drag_popup = new BC_DragWindow(this, 
3571                                         drag_column_icon_vframe, 
3572                                         get_abs_cursor_x(0) - drag_column_icon_vframe->get_w() / 2,
3573                                         get_abs_cursor_y(0) - drag_column_icon_vframe->get_h() / 2);
3574                                 dragged_title = highlighted_title;
3575                                 current_operation = COLUMN_DRAG;
3576                                 draw_titles(1);
3577                                 return 1;
3578                         }
3579                         break;
3580         }
3582         return 0;
3585 int BC_ListBox::drag_motion_event()
3587 //printf("BC_ListBox::drag_motion_event 1 %d\n", current_operation);
3588         switch(current_operation)
3589         {
3590                 case DRAG_ITEM:
3591                 {
3592                         int redraw = 0;
3594                         int new_highlighted_item = -1;
3595                         BC_ListBoxItem *new_highlighted_ptr = 0;
3596                         int new_highlight = new_highlighted_item = get_cursor_item(data,
3597                                 top_level->cursor_x, 
3598                                 top_level->cursor_y,
3599                                 &new_highlighted_ptr);
3601                         if(new_highlighted_item != highlighted_item)
3602                         {
3603                                 redraw = 1;
3604                         }
3606 // Always update highlighted value for drag_stop
3607                         highlighted_item = new_highlighted_item;
3608                         highlighted_ptr = new_highlighted_ptr;
3609 //printf("BC_ListBox::drag_motion_event 1 %p\n", highlighted_ptr);
3610                         if(redraw)
3611                         {
3612                                 clamp_positions();
3613                                 draw_items(1);
3614                                 update_scrollbars();
3615                         }
3617                         return drag_popup->cursor_motion_event();
3618                         break;
3619                 }
3621                 case COLUMN_DRAG:
3622                 {
3623                         int old_highlighted_title = highlighted_title;
3624                         test_column_titles(get_cursor_x(), get_cursor_y());
3625                         if(old_highlighted_title != highlighted_title)
3626                         {
3627                                 draw_titles(1);
3628                         }
3629                         return drag_popup->cursor_motion_event();
3630                         break;
3631                 }
3632         }
3633         return 0;
3636 int BC_ListBox::drag_stop_event()
3638         switch(current_operation)
3639         {
3640                 case DRAG_ITEM:
3641 // Inside window boundary
3642                         if(top_level->cursor_x > 0 && 
3643                                 top_level->cursor_x < gui->get_w() - drag_popup->get_w() / 2 && 
3644                                 top_level->cursor_y > 0 &&
3645                                 top_level->cursor_y < gui->get_h() - drag_popup->get_h() / 2)
3646                         {
3647 // Move icon
3650                                 if(display_format == LISTBOX_ICONS)
3651                                 {
3652                                         reposition_item(data, 
3653                                                 selection_number, 
3654                                                 top_level->cursor_x + 
3655                                                         drag_popup->get_offset_x() - 
3656                                                         LISTBOX_MARGIN - 
3657                                                         2 + 
3658                                                         xposition,
3659                                                 top_level->cursor_y + 
3660                                                         drag_popup->get_offset_y() - 
3661                                                         LISTBOX_MARGIN - 
3662                                                         2 + 
3663                                                         yposition);
3664                                 }
3665                                 else
3666 // Move rows
3667                                 if(process_drag)
3668                                 {
3669 // Get destination
3670                                         int destination = highlighted_item = item_to_index(data,
3671                                                 highlighted_ptr);
3672 //printf("BC_ListBox::drag_stop_event 1 %p %d\n", highlighted_ptr, destination);
3674 // Move selected items from data to temporary
3675                                         ArrayList<BC_ListBoxItem*> *src_items = 
3676                                                 new ArrayList<BC_ListBoxItem*>[columns];
3678                                         move_selection(src_items, data);
3680 // Insert items from temporary to data
3681                                         put_selection(data,
3682                                                 src_items,
3683                                                 destination);
3686                                         delete [] src_items;                            
3687                                         set_autoplacement(data, 0, 1);
3688                                 }
3690                         
3691                                 draw_items(1);
3692                         }
3693                         else
3694                                 drag_popup->drag_failure_event();
3696                         delete drag_popup;
3697                         drag_popup = 0;
3698                         current_operation = NO_OPERATION;
3699                         new_value = 0;
3700                         return 1;
3701                         break;
3703                 case COLUMN_DRAG:
3704                         if(dragged_title != highlighted_title)
3705                         {
3706                                 if(highlighted_title >= 0)
3707                                 {
3708                                         if(!move_column_event()) draw_titles(1);
3709                                 }
3710                                 else
3711                                         drag_popup->drag_failure_event();
3712                         }
3713                         current_operation = NO_OPERATION;
3714                         delete drag_popup;
3715                         drag_popup = 0;
3716                         return 1;
3717                         break;
3718         }
3719         return 0;
3722 BC_DragWindow* BC_ListBox::get_drag_popup()
3724         return drag_popup;
3727 int BC_ListBox::translation_event()
3729         if(is_popup && gui)
3730         {
3731                 int new_x = gui->get_x() + 
3732                         (top_level->last_translate_x - 
3733                                 top_level->prev_x - 
3734                                 top_level->get_resources()->get_left_border());
3735                 int new_y = gui->get_y() + 
3736                         (top_level->last_translate_y - 
3737                                 top_level->prev_y -
3738                                 top_level->get_resources()->get_top_border());
3740                 gui->reposition_window(new_x, new_y);
3741                 
3742         }
3743         return 0;
3746 int BC_ListBox::reposition_window(int x, int y, int w, int h)
3748         if(w != -1)
3749         {
3750                 if(w != -1) popup_w = w;
3751                 if(h != -1) popup_h = h;
3752 //printf("BC_ListBox::reposition_window %d %d\n", popup_w, popup_h);
3754                 if(!is_popup)
3755                 {
3756                         if(w != -1) popup_w = w;
3757                         if(h != -1) popup_h = h;
3758                         if(xscrollbar)
3759                                 xscrollbar->reposition_window(get_xscroll_x(), 
3760                                         get_xscroll_y(), 
3761                                         get_xscroll_width());
3762                         if(yscrollbar)
3763                                 yscrollbar->reposition_window(get_yscroll_x(), 
3764                                         get_yscroll_y(), 
3765                                         get_yscroll_height());
3766                 }
3767         }
3770         BC_WindowBase::reposition_window(x, y, w, h);
3771         draw_button();
3772         draw_items(1);
3773         return 0;
3776 int BC_ListBox::deactivate()
3778         if(active)
3779         {
3780                 active = 0;
3781                 if(is_popup)
3782                 {
3783                         if(gui) delete gui;
3784                         xscrollbar = 0;
3785                         yscrollbar = 0;
3786                         gui = 0;
3787                         highlighted_item = -1;
3788                         highlighted_ptr = 0;
3789                 }
3790                 top_level->active_subwindow = 0;
3791         }
3792         return 0;
3795 int BC_ListBox::activate()
3797         if(!active)
3798         {
3799                 top_level->active_subwindow = this;
3800                 active = 1;
3801                 button_releases = 0;
3803                 if(is_popup)
3804                 {
3805                         Window tempwin;
3806                         int new_x, new_y;
3807                         XTranslateCoordinates(top_level->display, 
3808                                 parent_window->win, 
3809                                 top_level->rootwin, 
3810                                 get_x() - popup_w + get_w(), 
3811                                 get_y() + get_h(), 
3812                                 &new_x, 
3813                                 &new_y, 
3814                                 &tempwin);
3816                         if(new_x < 0) new_x = 0;
3817                         if(new_y + popup_h > top_level->get_root_h(0)) 
3818                                 new_y -= get_h() + popup_h;
3820 //printf("BC_ListBox::activate %d %d\n", popup_w, popup_h);
3821                         add_subwindow(gui = new BC_Popup(this, 
3822                                 new_x, 
3823                                 new_y, 
3824                                 popup_w, 
3825                                 popup_h, 
3826                                 -1,
3827                                 0,
3828                                 0));
3829                         draw_items(1);
3830                 }
3831         }
3832         return 0;
3835 int BC_ListBox::keypress_event()
3837         if(!active) return 0;
3838         
3839         int result = 0, redraw = 0, done, view_items = view_h / get_text_height(MEDIUMFONT);
3840         int new_item = -1, new_selection = 0;
3842         switch(top_level->get_keypress())
3843         {
3844                 case ESC:
3845                 case RETURN:
3846                         top_level->deactivate();
3847                         result = 0;
3848                         break;
3850                 case UP:
3851                         new_selection = new_item = select_previous(0);
3853 //printf("BC_ListBox::keypress_event 1 %d\n", new_item);
3854                         if(new_item >= 0)
3855                         {
3856                                 center_selection(new_item);
3857                                 redraw = 1;
3858                         }
3859                         result = 1;
3860                         break;
3862                 case DOWN:
3863                         new_selection = new_item = select_next(0);
3865                         if(new_item >= 0)
3866                         {
3867                                 center_selection(new_item);
3868                                 redraw = 1;
3869                         }
3870                         result = 1;
3871                         break;
3873                 case PGUP:
3874                         new_selection = new_item = select_previous(view_items - 1);
3876                         if(new_item >= 0)
3877                         {
3878                                 center_selection(new_item);
3879                                 redraw = 1;
3880                         }
3881                         result = 1;
3882                         break;
3884                 case PGDN:
3885                         new_selection = new_item = select_next(view_items - 1);
3887                         if(new_item >= 0)
3888                         {
3889                                 center_selection(new_item);
3890                                 redraw = 1;
3891                         }
3892                         result = 1;
3893                         break;
3895                 case LEFT:
3896                         xposition -= 10;
3897                         redraw = 1;
3898                         result = 1;
3899                         break;
3901                 case RIGHT:
3902                         xposition += 10;
3903                         redraw = 1;
3904                         result = 1;
3905                         break;
3907                 default:
3908                         if(!ctrl_down())
3909                         {
3910                                 if(top_level->get_keypress() > 30 && 
3911                                         top_level->get_keypress() < 127)
3912                                 {
3913                                         int query_len = strlen(query);
3914                                         query[query_len++] = top_level->get_keypress();
3915                                         query[query_len] = 0;
3916                                         new_selection = query_list();
3917                                 }
3918                                 else
3919                                 if(top_level->get_keypress() == BACKSPACE)
3920                                 {
3921                                         int query_len = strlen(query);
3922                                         if(query_len > 0) query[--query_len] = 0;
3923                                         new_selection = query_list();
3924                                 }
3926                                 redraw = 1;
3927                                 result = 1;
3928                         }
3929                         break;
3930         }
3932         if(redraw)
3933         {
3934                 clamp_positions();
3935                 draw_items(1);
3936                 update_scrollbars();
3937         }
3938         
3939         if(new_selection >= 0)
3940         {
3941                 selection_changed();
3942         }
3944         return result;
3948 BC_Pixmap* BC_ListBox::get_bg_surface()
3950         return bg_surface;
3954 void BC_ListBox::draw_background()
3956 // White background pixmap
3957         set_color(WHITE);
3958         draw_box(0, 0, bg_surface->get_w(), bg_surface->get_h(), bg_surface);
3960 // Optional heroine pixmap
3961         if(bg_pixmap)
3962                 bg_surface->draw_pixmap(bg_pixmap,
3963                         bg_surface->get_w() - top_level->get_resources()->listbox_bg->get_w(),
3964                         0);
3967 void BC_ListBox::clear_listbox(int x, int y, int w, int h)
3969         gui->draw_pixmap(bg_surface, 
3970                 x, 
3971                 y, 
3972                 w, 
3973                 h,
3974                 x,
3975                 y - title_h);
3978 void BC_ListBox::update_format(int display_format, int redraw)
3980         this->display_format = display_format;
3981         if(redraw)
3982         {
3983                 if(gui) draw_items(1);
3984         }
3987 int BC_ListBox::get_format()
3989         return display_format;
3994 int BC_ListBox::draw_items(int flash)
3996         if(gui)
3997         {
3998 //dump(data, columns);
4000 // Calculate items width 
4001                 calculate_item_coords();
4004 // Create and destroy scrollbars as needed
4005                 get_scrollbars();
4009 //              draw_background();
4011 // Icon display
4012                 if(display_format == LISTBOX_ICONS)
4013                 {
4014                         clear_listbox(2, 2 + title_h, view_w, view_h);
4016                         set_font(MEDIUMFONT);
4017                         for(int i = 0; i < data[master_column].total; i++)
4018                         {
4019                                 BC_ListBoxItem *item = data[master_column].values[i];
4020                                 if(get_item_x(item) >= -get_item_w(item) && 
4021                                         get_item_x(item) < view_w &&
4022                                         get_item_y(item) >= -get_item_h(item) + title_h &&
4023                                         get_item_y(item) < view_h + title_h)
4024                                 {
4025                                         int item_color = get_item_highlight(data, 0, i);
4026                                         int icon_x, icon_y, icon_w, icon_h;
4027                                         int text_x, text_y, text_w, text_h;
4029 // Draw highlights
4030                                         get_icon_mask(item, icon_x, icon_y, icon_w, icon_h);
4031                                         get_text_mask(item, text_x, text_y, text_w, text_h);
4033                                         if(item_color != WHITE)
4034                                         {
4035                                                 gui->set_color(BLACK);
4036                                                 gui->draw_rectangle(icon_x, icon_y, icon_w, icon_h);
4037                                                 gui->set_color(item_color);
4038                                                 gui->draw_box(icon_x + 1, icon_y + 1, icon_w - 2, icon_h - 2);
4039                                                 gui->set_color(BLACK);
4040                                                 gui->draw_rectangle(text_x, text_y, text_w, text_h);
4041                                                 gui->set_color(item_color);
4042                                                 gui->draw_box(text_x + 1, text_y + 1, text_w - 2, text_h - 2);
4044                                                 if(icon_position == ICON_LEFT)
4045                                                         gui->draw_box(text_x - 1, text_y + 1, 2, text_h - 2);
4046                                                 else
4047                                                 if(icon_position == ICON_TOP)
4048                                                         gui->draw_line(text_x + 1, text_y, text_x + icon_w - 2, text_y);
4049                                         }
4051 // Draw icons
4052                                         gui->set_color(get_item_color(data, 0, i));
4053                                         if(item->icon)
4054                                                 item->icon->write_drawable(gui->pixmap, 
4055                                                         icon_x + ICON_MARGIN, 
4056                                                         icon_y + ICON_MARGIN);
4057                                         gui->draw_text(text_x + ICON_MARGIN, 
4058                                                 text_y + ICON_MARGIN + get_text_ascent(MEDIUMFONT), 
4059                                                 item->text);
4060                                 }
4061                         }
4062                 }
4063                 else
4064 // Text display
4065                 if(display_format == LISTBOX_TEXT)
4066                 {
4067 // Draw one column at a time so text overruns don't go into the next column
4068 // clear column backgrounds
4069                         int current_toggle = 0;
4070                         for(int j = 0; j < columns; j++)
4071                         {
4072                                 clear_listbox(LISTBOX_BORDER + get_column_offset(j) - xposition, 
4073                                         LISTBOX_BORDER + title_h, 
4074                                         get_column_width(j, 1), 
4075                                         view_h);
4077 // Draw rows in the column recursively
4078                                 draw_text_recursive(data, j, 0, &current_toggle);
4079                         }
4081 // Delete excess expanders
4082                         while(expanders.total > current_toggle)
4083                         {
4084                                 expanders.remove_object();
4085                         }
4086                 }
4088 // Draw titles on top of rows for superposition effect
4089                 draw_titles(0);
4091 // Clear garbage from bottom right corner
4092                 if(xscrollbar && yscrollbar && is_popup)
4093                 {
4094                         gui->draw_top_background(parent_window, 
4095                                 popup_w - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w(), 
4096                                 popup_h - get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h(), 
4097                                 get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w(),
4098                                 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h());
4099                 }
4101 // Draw borders
4102                 draw_border(0);
4105                 if(current_operation == SELECT_RECT)
4106                         draw_rectangle(0);
4108                 if(flash)
4109                 {
4110                         gui->flash();
4111                         gui->flush();
4112                 }
4113         }
4115         return 0;
4119 void BC_ListBox::draw_text_recursive(ArrayList<BC_ListBoxItem*> *data, 
4120         int column,
4121         int indent,
4122         int *current_toggle)
4124         if(!data) return;
4126         set_font(MEDIUMFONT);
4127         int subindent = 0;
4129 // Search for a branch and make room for toggle if there is one
4130         if(column == 0)
4131         {
4132                 for(int i = 0; i < data[column].total; i++)
4133                 {
4134                         if(data[column].values[i]->get_sublist())
4135                         {
4136                                 subindent = BC_WindowBase::get_resources()->listbox_expand[0]->get_w();
4137                                 break;
4138                         }
4139                 }
4140         }
4142         for(int i = 0; i < data[column].total; i++)
4143         {
4144 // Draw a row
4145                 BC_ListBoxItem *item = data[column].values[i];
4146                 BC_ListBoxItem *first_item = data[master_column].values[i];
4148                 if(get_item_y(item) >= -get_item_h(item) + title_h &&
4149                         get_item_y(item) < view_h + title_h)
4150                 {
4151                         int row_color = get_item_highlight(data, 0, i);
4152                         int x, y, w, h, column_width;
4154                         get_text_mask(item, x, y, w, h);
4155                         column_width = get_column_width(column, 1);
4156                         if(x + column_width > view_w + LISTBOX_BORDER * 2)
4157                                 column_width = view_w + LISTBOX_BORDER * 2 - x;
4159                         if(row_color != WHITE)
4160                         {
4161                                 gui->set_color(row_color);
4162                                 gui->draw_box(x, 
4163                                         y, 
4164                                         column_width, 
4165                                         h);
4166                                 gui->set_color(BLACK);
4167                                 gui->draw_line(x, 
4168                                         y, 
4169                                         x + column_width - 1, 
4170                                         y);
4171                                 gui->draw_line(x, 
4172                                         y + get_text_height(MEDIUMFONT), 
4173                                         x + column_width - 1, 
4174                                         y + get_text_height(MEDIUMFONT));
4175                         }
4177                         gui->set_color(get_item_color(data, column, i));
4180 // Indent only applies to first column
4181                         gui->draw_text(
4182                                 x + 
4183                                         LISTBOX_BORDER + 
4184                                         LISTBOX_MARGIN + 
4185                                         (column == 0 ? indent + subindent : 0), 
4186                                 y + get_text_ascent(MEDIUMFONT), 
4187                                 item->text);
4190 // Update expander
4191                         if(column == 0 &&
4192                                 item->get_sublist() && 
4193                                 item->get_columns())
4194                         {
4195 // Create new expander
4196                                 if(*current_toggle >= expanders.total)
4197                                 {
4198                                         BC_ListBoxToggle *toggle = 
4199                                                 new BC_ListBoxToggle(this, 
4200                                                         item, 
4201                                                         x + LISTBOX_BORDER + LISTBOX_MARGIN + indent,
4202                                                         y);
4203                                         toggle->draw(0);
4204                                         expanders.append(toggle);
4205                                 }
4206                                 else
4207 // Reposition existing expander
4208                                 {
4209                                         BC_ListBoxToggle *toggle = expanders.values[*current_toggle];
4210 //printf("BC_ListBox::draw_text_recursive 1 %d\n", *current_toggle);
4211                                         toggle->update(item, 
4212                                                 x + LISTBOX_BORDER + LISTBOX_MARGIN + indent,
4213                                                 y,
4214                                                 0);
4215                                 }
4216                                 (*current_toggle)++;
4217                         }
4221                 }
4223 // Descend into sublist
4224                 if(first_item->get_expand())
4225                 {
4226                         draw_text_recursive(first_item->get_sublist(), 
4227                                 column, 
4228                                 indent + LISTBOX_INDENT, 
4229                                 current_toggle);
4230                 }
4231         }
4238 int BC_ListBox::draw_border(int flash)
4240         gui->draw_3d_border(0, 
4241                 0, 
4242                 view_w + LISTBOX_BORDER * 2, 
4243                 view_h + title_h + LISTBOX_BORDER * 2, 
4244                 top_level->get_resources()->button_shadow, 
4245                 list_highlighted ? RED : BLACK, 
4246                 list_highlighted ? RED : top_level->get_resources()->button_up, 
4247                 top_level->get_resources()->button_light);
4249         if(flash)
4250         {
4251                 gui->flash();
4252                 gui->flush();
4253         }
4254         return 0;
4257 int BC_ListBox::draw_titles(int flash)
4259         if(column_titles && display_format == LISTBOX_TEXT)
4260         {
4261 //printf("BC_ListBox::draw_titles 1 %d\n", highlighted_title);
4262                 for(int i = 0; i < columns; i++)
4263                 {
4266 // Column title background
4267                         int image_number = 0;
4268                         if(i == highlighted_title)
4269                         {
4270                                 image_number = 1;
4271                                 if(current_operation == COLUMN_DN)
4272                                         image_number = 2;
4273                         }
4275                         int column_offset = get_column_offset(i) - xposition + LISTBOX_BORDER;
4276                         int column_width = get_column_width(i, 1);
4277                         gui->draw_3segmenth(get_column_offset(i) - xposition + LISTBOX_BORDER,
4278                                 LISTBOX_BORDER,
4279                                 get_column_width(i, 1),
4280                                 column_bg[image_number]);
4282 // Column title sort order
4283                         if(i == sort_column)
4284                         {
4285                                 BC_Pixmap *src;
4286                                 if(sort_order == SORT_ASCENDING) 
4287                                         src = column_sort_dn;
4288                                 else
4289                                         src = column_sort_up;
4291                                 int x = column_offset + column_width - LISTBOX_BORDER;
4292                                 if(x > items_w) x = items_w;
4293                                 x -= 5 + src->get_w();
4295 //printf("BC_ListBox::draw_titles 1 %d\n", x);
4296                                 gui->draw_pixmap(src,
4297                                         x,
4298                                         title_h / 2 - src->get_h() / 2 + LISTBOX_BORDER);
4299                         }
4302                         gui->set_color(BLACK);
4303                         gui->draw_text(-xposition + get_column_offset(i) + LISTBOX_MARGIN + LISTBOX_BORDER, 
4304                                 LISTBOX_MARGIN + LISTBOX_BORDER + get_text_ascent(MEDIUMFONT), 
4305                                 column_titles[i]);
4306                 }
4307                 draw_border(0);
4308         }
4310         if(flash)
4311         {
4312                 gui->flash();
4313                 gui->flush();
4314         }
4317 void BC_ListBox::draw_toggles(int flash)
4319         for(int i = 0; i < expanders.total; i++)
4320                 expanders.values[i]->draw(0);
4322 //printf("BC_ListBox::draw_toggles 1 %d\n", flash);
4323         if(flash && expanders.total)
4324         {
4325                 gui->flash();
4326                 gui->flush();
4327         }
4330 int BC_ListBox::draw_rectangle(int flash)
4332         int x1 = MIN(rect_x1, rect_x2);
4333         int x2 = MAX(rect_x1, rect_x2);
4334         int y1 = MIN(rect_y1, rect_y2);
4335         int y2 = MAX(rect_y1, rect_y2);
4337         if(x1 == x2 || y1 == y2) return 0;
4339         gui->set_inverse();
4340         gui->set_color(WHITE);
4341         gui->draw_rectangle(x1, y1, x2 - x1, y2 - y1);
4342         gui->set_opaque();
4345         if(flash)
4346         {
4347                 gui->flash();
4348                 gui->flush();
4349         }
4350         return 0;
4353 void BC_ListBox::dump(ArrayList<BC_ListBoxItem*> *data, 
4354         int columns, 
4355         int indent,
4356         int master_column)
4358         if(!indent)
4359         {
4360                 printf("BC_ListBox::dump 1\n");
4361         }
4363         for(int i = 0; i < data[master_column].total; i++)
4364         {
4365                 for(int k = 0; k < indent; k++)
4366                         printf(" ");
4367                 for(int j = 0; j < columns; j++)
4368                 {
4369                         BC_ListBoxItem *item = data[j].values[i];
4370                         printf("%d,%d,%d=%s ", 
4371                                 item->get_text_x(), 
4372                                 item->get_text_y(),
4373                                 item->autoplace_text, 
4374                                 item->get_text());
4375                 }
4376                 printf("\n");
4378                 if(data[master_column].values[i]->get_sublist())
4379                 {
4380                         dump(data[master_column].values[i]->get_sublist(),
4381                                 data[master_column].values[i]->get_columns(),
4382                                 indent + 4,
4383                                 master_column);
4384                 }
4385         }
4387