r701: Jean-Luc Coulon has gettextized [tm] 2 more strings in the time average effect.
[cinelerra_cv.git] / guicast / bclistbox.C
blobaeb3e272eb9386a2675faa5cbc37826365ffa324
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 "language.h"
11 #include "bctimer.h"
12 #include "vframe.h"
14 #include <string.h>
15 #include <unistd.h>
17 // ====================================================== scrollbars
20 BC_ListBoxYScroll::BC_ListBoxYScroll(BC_ListBox *listbox, 
21                           int total_height, 
22                                           int view_height, 
23                           int position)
24  : BC_ScrollBar(listbox->get_yscroll_x(), 
25         listbox->get_yscroll_y(), 
26         SCROLL_VERT, 
27         listbox->get_yscroll_height(), 
28         total_height, 
29         position, 
30         view_height)
32         this->listbox = listbox;
35 BC_ListBoxYScroll::~BC_ListBoxYScroll()
39 int BC_ListBoxYScroll::handle_event()
41         listbox->set_yposition(get_value());
42         return 1;
51 BC_ListBoxXScroll::BC_ListBoxXScroll(BC_ListBox *listbox, 
52                           int total_width, 
53                                           int view_width,
54                           int position)
55  : BC_ScrollBar(listbox->get_xscroll_x(), 
56         listbox->get_xscroll_y(), 
57         SCROLL_HORIZ, 
58         listbox->get_xscroll_width(), 
59         total_width, 
60         position, 
61         view_width)
63         this->listbox = listbox;
66 BC_ListBoxXScroll::~BC_ListBoxXScroll()
70 int BC_ListBoxXScroll::handle_event()
72         listbox->set_xposition(get_value());
73         return 1;
83 BC_ListBoxToggle::BC_ListBoxToggle(BC_ListBox *listbox, 
84         BC_ListBoxItem *item, 
85         int x, 
86         int y)
88         this->listbox = listbox;
89         this->item = item;
90         this->x = x;
91         this->y = y;
92         this->value = item->get_expand();
93         if(this->value) 
94                 state = BC_Toggle::TOGGLE_CHECKED;
95         else
96                 state = BC_Toggle::TOGGLE_UP;
99 void BC_ListBoxToggle::update(BC_ListBoxItem *item, 
100         int x, 
101         int y,
102         int flash)
104         this->value = item->get_expand();
105         this->item = item;
106         this->x = x;
107         this->y = y;
109 // update state
110         switch(state)
111         {
112                 case TOGGLE_UP:
113                         if(value)
114                                 state = TOGGLE_CHECKED;
115                         break;
117                 case TOGGLE_UPHI:
118                         if(value)
119                                 state = TOGGLE_CHECKEDHI;
120                         break;
122                 case TOGGLE_CHECKED:
123                         if(!value)
124                                 state = TOGGLE_UP;
125                         break;
127                 case TOGGLE_DOWN:
128                         break;
130                 case TOGGLE_CHECKEDHI:
131                         if(!value)
132                                 state = TOGGLE_UPHI;
133                         break;
135                 case TOGGLE_DOWN_EXIT:
136                         break;
137         }
140         draw(flash);
143 int BC_ListBoxToggle::cursor_motion_event(int *redraw_toggles)
145         int w = listbox->toggle_images[0]->get_w();
146         int h = listbox->toggle_images[0]->get_h();
147         int cursor_inside = listbox->get_cursor_x() >= x && 
148                 listbox->get_cursor_x() < x + w &&
149                 listbox->get_cursor_y() >= y && 
150                 listbox->get_cursor_y() < y + h;
151         int result = 0;
153         switch(state)
154         {
155                 case BC_ListBoxToggle::TOGGLE_UPHI:
156                         if(!cursor_inside)
157                         {
158                                 state = BC_ListBoxToggle::TOGGLE_UP;
159                                 *redraw_toggles = 1;
160                         }
161                         break;
163                 case BC_ListBoxToggle::TOGGLE_CHECKEDHI:
164                         if(!cursor_inside)
165                         {
166                                 state = BC_ListBoxToggle::TOGGLE_CHECKED;
167                                 *redraw_toggles = 1;
168                         }
169                         break;
171                 case BC_ListBoxToggle::TOGGLE_DOWN:
172                         if(!cursor_inside)
173                         {
174                                 state = BC_ListBoxToggle::TOGGLE_DOWN_EXIT;
175                                 *redraw_toggles = 1;
176                         }
177                         result = 1;
178                         break;
180                 case BC_ListBoxToggle::TOGGLE_DOWN_EXIT:
181                         if(cursor_inside)
182                         {
183                                 state = BC_ListBoxToggle::TOGGLE_DOWN;
184                                 *redraw_toggles = 1;
185                         }
186                         result = 1;
187                         break;
189                 default:
190                         if(cursor_inside)
191                         {
192                                 if(value)
193                                         state = BC_ListBoxToggle::TOGGLE_CHECKEDHI;
194                                 else
195                                         state = BC_ListBoxToggle::TOGGLE_UPHI;
196                                 *redraw_toggles = 1;
197                         }
198                         break;
199         }
200         return result;
203 int BC_ListBoxToggle::cursor_leave_event(int *redraw_toggles)
205         if(value)
206                 state = BC_ListBoxToggle::TOGGLE_CHECKED;
207         else
208                 state = BC_ListBoxToggle::TOGGLE_UP;
211 int BC_ListBoxToggle::button_press_event()
213         int w = listbox->toggle_images[0]->get_w();
214         int h = listbox->toggle_images[0]->get_h();
216         if(listbox->gui->get_cursor_x() >= x && 
217                 listbox->gui->get_cursor_x() < x + w &&
218                 listbox->gui->get_cursor_y() >= y && 
219                 listbox->gui->get_cursor_y() < y + h)
220         {
221                 state = BC_ListBoxToggle::TOGGLE_DOWN;
222                 return 1;
223         }
224         return 0;
227 int BC_ListBoxToggle::button_release_event(int *redraw_toggles)
229         int result = 0;
230         switch(state)
231         {
232                 case BC_ListBoxToggle::TOGGLE_DOWN:
233                         value = !value;
234                         if(value)
235                                 state = BC_ListBoxToggle::TOGGLE_CHECKEDHI;
236                         else
237                                 state = BC_ListBoxToggle::TOGGLE_UPHI;
238                         listbox->expand_item(item, value);
239                         result = 1;
240                         break;
242                 case BC_ListBoxToggle::TOGGLE_DOWN_EXIT:
243                         if(value)
244                                 state = BC_ListBoxToggle::TOGGLE_CHECKED;
245                         else
246                                 state = BC_ListBoxToggle::TOGGLE_UP;
247                         *redraw_toggles = 1;
248                         result = 1;
249                         break;
250         }
251         return result;
254 void BC_ListBoxToggle::draw(int flash)
256         if(listbox->gui)
257         {
258                 int image_number = 0;
259                 int w = listbox->toggle_images[0]->get_w();
260                 int h = listbox->toggle_images[0]->get_h();
262                 switch(state)
263                 {
264                         case BC_ListBoxToggle::TOGGLE_UP: image_number = 0; break;
265                         case BC_ListBoxToggle::TOGGLE_UPHI: image_number = 1; break;
266                         case BC_ListBoxToggle::TOGGLE_CHECKED: image_number = 2; break;
267                         case BC_ListBoxToggle::TOGGLE_DOWN: image_number = 3; break;
268                         case BC_ListBoxToggle::TOGGLE_CHECKEDHI: image_number = 4; break;
269                         case BC_ListBoxToggle::TOGGLE_DOWN_EXIT:
270                                 if(value)
271                                         image_number = 2;
272                                 else
273                                         image_number = 0;
274                                 break;
275                 }
277 //printf("BC_ListBoxToggle::draw 1 %d\n", state);
278                 listbox->gui->draw_pixmap(listbox->toggle_images[image_number],
279                         x,
280                         y);
283                 if(flash)
284                 {
285                         listbox->gui->flash(x, y, w, h);
286                         listbox->gui->flush();
287                 }
288         }
304 // ====================================================== box
306 BC_ListBox::BC_ListBox(int x, 
307         int y, 
308         int w, 
309         int h,
310         int display_format,
311         ArrayList<BC_ListBoxItem*> *data,
312         char **column_titles,
313         int *column_width,
314         int columns,
315         int yposition,
316         int is_popup,
317         int selection_mode,
318         int icon_position,
319         int allow_drag)
320  : BC_SubWindow(x, y, w, h, -1)
322         justify = LISTBOX_RIGHT;
323         xposition = 0;
324         highlighted_item = -1;
325         highlighted_title = -1;
326         highlighted_division = -1;
327         highlighted_ptr = 0;
328         xscrollbar = 0;
329         yscrollbar = 0;
330         current_cursor = ARROW_CURSOR;
331         gui = 0;
332         view_h = 0;
333         view_w = 0;
334         title_h = 0;
335         active = 0;
336         new_value = 0;
337         need_xscroll = 0;
338         need_yscroll = 0;
339         bg_tile = 0;
340         drag_popup = 0;
341         selection_number1 = -1;
342         selection_number2 = -1;
343         bg_surface = 0;
344         bg_pixmap = 0;
346         current_operation = NO_OPERATION;
347         button_highlighted = 0;
349         disabled = 0;
351         list_highlighted = 0;
353         allow_drag_scroll = 1;
354         process_drag = 1;
356         sort_column = -1;
357         sort_order = 0;
359         allow_drag_column = 0;
360         master_column = 0;
361         search_column = 0;
363         popup_w = w;
364         popup_h = h;
366         for(int i = 0; i < 3; i++)
367                 column_bg[i] = 0;
369         for(int i = 0; i < 4; i++)
370                 button_images[i] = 0;
372         for(int i = 0; i < 5; i++)
373                 toggle_images[i] = 0;
375         column_sort_up = 0;
376         column_sort_dn = 0;
378 //printf("BC_ListBox::BC_ListBox 1\n");
379         this->data = data;
380         this->columns = columns;
381         this->yposition = yposition;
382         this->is_popup = is_popup;
383         this->display_format = display_format;
384         this->selection_mode = selection_mode;
385         this->icon_position = icon_position;
386         this->allow_drag = allow_drag;
387         this->column_titles = 0;
388         this->column_width = 0;
389 //printf("BC_ListBox::BC_ListBox 1\n");
391         if((!column_titles && column_width) ||
392                 (column_titles && !column_width))
393         {
394                 printf("BC_ListBox::BC_ListBox either column_titles or column_widths == NULL but not both.\n");
395         }
396 //printf("BC_ListBox::BC_ListBox 2 %p %p\n", column_titles, column_width);
397         set_columns(column_titles, 
398                 column_width, 
399                 columns);
401 //printf("BC_ListBox::BC_ListBox 3\n");
403         drag_icon_vframe = 0;
404         drag_column_icon_vframe = 0;
408 // reset the search engine
409 //printf("BC_ListBox::BC_ListBox 4\n");
410         reset_query();
411 //printf("BC_ListBox::BC_ListBox 5\n");
414 BC_ListBox::~BC_ListBox()
416         expanders.remove_all_objects();
417         if(bg_surface) delete bg_surface;
418         if(bg_pixmap) delete bg_pixmap;
419         if(xscrollbar) delete xscrollbar;
420         if(yscrollbar) delete yscrollbar;
421         for(int i = 0; i < 3; i++)
422                 if(column_bg[i]) delete column_bg[i];
423         for(int i = 0; i < 4; i++)
424                 if(button_images[i]) delete button_images[i];
425         for(int i = 0; i < 5; i++)
426                 if(toggle_images[i]) delete toggle_images[i];
427         if(column_sort_up) delete column_sort_up;
428         if(column_sort_dn) delete column_sort_dn;
430         delete_columns();
431         if(drag_popup) delete drag_popup;
434 int BC_ListBox::enable()
436   disabled = 0;
437   draw_button();
438   return 1;
441 int BC_ListBox::disable()
443   disabled = 1;
444   draw_button();
445   return 1;
448 void BC_ListBox::reset_query()
450         query[0] = 0;  // reset query
453 int BC_ListBox::evaluate_query(int list_item, char *string)
455         return(strcmp(string, data[search_column].values[list_item]->text) <= 0 && 
456                 data[search_column].values[list_item]->searchable);
459 int BC_ListBox::query_list()
461         if(query[0] == 0) return 0;
463         int done = 0;
464         int result;
465         int selection_changed = 0;
466         int prev_selection = -1;
467         for(int i = 0; !done && i < data[0].total; i++)
468         {
469                 if(evaluate_query(i, query))
470                 {
471                         result = i;
472                         done = 1;
473                 }
474         }
476         if(done)
477         {
478 // Deselect all
479                 for(int i = 0; i < data[0].total; i++)
480                 {
481                         for(int j = 0; j < columns; j++)
482                         {
483                                 if(data[j].values[i]->selected) prev_selection = i;
484                                 data[j].values[i]->selected = 0;
485                         }
486                 }
488 // Select one
489                 if(prev_selection != result)
490                         selection_changed = 1;
491                 for(int j = 0; j < columns; j++)
492                 {
493                         data[j].values[result]->selected = 1;
494                 }
495                 center_selection(result);
496         }
498         return selection_changed;
501 void BC_ListBox::init_column_width()
503         if(!column_width && data)
504         {
505                 int widest = 5, w;
506                 for(int i = 0; i < data[0].total; i++)
507                 {
508                         w = get_text_width(MEDIUMFONT, data[0].values[i]->get_text()) + 2 * LISTBOX_MARGIN;
509                         if(w > widest) widest = w;
510                 }
511                 default_column_width[0] = widest;
512         }
515 int BC_ListBox::initialize()
517         if(is_popup)
518         {
519                 for(int i = 0; i < 4; i++)
520                 {
521                         button_images[i] = new BC_Pixmap(parent_window, 
522                                 BC_WindowBase::get_resources()->listbox_button[i], 
523                                 PIXMAP_ALPHA);
524                 }
525                 w = button_images[0]->get_w();
526                 h = button_images[0]->get_h();
527                 
528                 gui = 0;
529                 current_operation = NO_OPERATION;
530         }
531         else
532         {
533                 gui = this;
534                 current_operation = NO_OPERATION;
535         }
537         for(int i = 0; i < 3; i++)
538         {
539                 column_bg[i] = new BC_Pixmap(parent_window,
540                         get_resources()->listbox_column[i],
541                         PIXMAP_ALPHA);
542         }
543         for(int i = 0; i < 5; i++)
544         {
545                 toggle_images[i] = new BC_Pixmap(parent_window,
546                         get_resources()->listbox_expand[i],
547                         PIXMAP_ALPHA);
548         }
550         column_sort_up = new BC_Pixmap(parent_window, 
551                 BC_WindowBase::get_resources()->listbox_up, 
552                 PIXMAP_ALPHA);
553         column_sort_dn = new BC_Pixmap(parent_window, 
554                 BC_WindowBase::get_resources()->listbox_dn, 
555                 PIXMAP_ALPHA);
557 //printf("BC_ListBox::initialize 10\n");
558         drag_icon_vframe = get_resources()->type_to_icon[ICON_UNKNOWN];
559         drag_column_icon_vframe = get_resources()->type_to_icon[ICON_COLUMN];
560 // = new BC_Pixmap(parent_window, 
561 //              get_resources()->type_to_icon[ICON_UNKNOWN], 
562 //              PIXMAP_ALPHA);
563 //      drag_column_icon = new BC_Pixmap(parent_window,
564 //              get_resources()->type_to_icon[ICON_COLUMN],
565 //              PIXMAP_ALPHA);
566         BC_SubWindow::initialize();
568         init_column_width();
570         if(top_level->get_resources()->listbox_bg)
571                 bg_pixmap = new BC_Pixmap(this, 
572                         get_resources()->listbox_bg, 
573                         PIXMAP_OPAQUE);
575         draw_button();
576         draw_items(1);
577         return 0;
580 void BC_ListBox::deactivate_selection()
582         current_operation = NO_OPERATION;
585 int BC_ListBox::draw_button()
587 // Draw the button for a popup listbox
588         if(is_popup)
589         {
590                 int image_number = 0;
592                 draw_top_background(parent_window, 0, 0, w, h);
594                 if(button_highlighted)
595                         image_number = 1;
596                 if(current_operation == BUTTON_DN)
597                         image_number = 2;
598                 if(disabled)
599                         image_number = 3;
602                 button_images[image_number]->write_drawable(pixmap, 
603                         0, 
604                         0,
605                         w,
606                         h,
607                         0,
608                         0);
609                 flash();
610         }
611         return 0;
614 int BC_ListBox::calculate_item_coords()
616         if(!data) return 0;
618         int icon_x = 0;
619         int next_icon_x = 0;
620         int next_icon_y = 0;
621         int next_text_y = 0;
622 // Change the display_format to get the right item dimensions for both
623 // text and icons.
624         int display_format_temp = display_format;
627 // Scan the first column for lowest y coord of all text
628 // and lowest right x and y coord for all icons which aren't auto placable
629         calculate_last_coords_recursive(data,
630                 &icon_x,
631                 &next_icon_x, 
632                 &next_icon_y,
633                 &next_text_y,
634                 1);
636 // Reset last column width.  It's recalculated based on text width.
638         calculate_item_coords_recursive(data,
639                 &icon_x,
640                 &next_icon_x, 
641                 &next_icon_y,
642                 &next_text_y,
643                 1);
647         display_format = display_format_temp;
649         return 0;
652 void BC_ListBox::calculate_last_coords_recursive(
653         ArrayList<BC_ListBoxItem*> *data,
654         int *icon_x,
655         int *next_icon_x,
656         int *next_icon_y,
657         int *next_text_y,
658         int top_level)
660         for(int i = 0; i < data[0].total; i++)
661         {
662                 int current_text_y = 0;
663                 int current_icon_x = 0;
664                 int current_icon_y = 0;
665                 BC_ListBoxItem *item = data[0].values[i];
667 // Get next_text_y
668                 if(!item->autoplace_text)
669                 {
670 // Lowest text coordinate
671                         display_format = LISTBOX_TEXT;
672                         current_text_y = item->text_y + 
673                                 get_text_height(MEDIUMFONT);
674                         if(current_text_y > *next_text_y)
675                                 *next_text_y = current_text_y;
677 // Add sublist depth if it is expanded
678                         if(item->get_sublist() && 
679                                 item->get_columns() &&
680                                 item->get_expand())
681                         {
682                                 calculate_last_coords_recursive(item->get_sublist(),
683                                         icon_x,
684                                         next_icon_x, 
685                                         next_icon_y,
686                                         next_text_y,
687                                         0);
688                         }
689                 }
691 // Get next_icon coordinate
692                 if(top_level)
693                 {
694                         BC_ListBoxItem *item = data[master_column].values[i];
695                         if(!item->autoplace_icon)
696                         {
697                                 display_format = LISTBOX_ICONS;
698 // Lowest right icon coordinate.
699                                 current_icon_x = item->icon_x;
700                                 if(current_icon_x > *icon_x) *icon_x = current_icon_x;
701                                 if(current_icon_x + get_item_w(item) > *next_icon_x)
702                                         *next_icon_x = current_icon_x + get_item_w(item);
704                                 current_icon_y = item->icon_y + get_item_h(item);
705                                 if(current_icon_y > *next_icon_y) 
706                                         *next_icon_y = current_icon_y;
707                         }
708                 }
709         }
713 void BC_ListBox::calculate_item_coords_recursive(
714         ArrayList<BC_ListBoxItem*> *data,
715         int *icon_x,
716         int *next_icon_x,
717         int *next_icon_y,
718         int *next_text_y,
719         int top_level)
724 // Set up items which need autoplacement.
725 // Should fill icons down and then across
726         for(int i = 0; i < data[0].total; i++)
727         {
728 // Don't increase y unless the row requires autoplacing.
729                 int total_autoplaced_columns = 0;
731 // Set up icons in first column
732                 if(top_level)
733                 {
734                         BC_ListBoxItem *item = data[master_column].values[i];
735                         if(item->autoplace_icon)
736                         {
737 // 1 column only if icons are used
738                                 display_format = LISTBOX_ICONS;
739 // Test row height
740 // Start new row.
741                                 if(*next_icon_y + get_item_h(item) >= get_h() && 
742                                         *next_icon_y > 0)
743                                 {
744                                         *icon_x = *next_icon_x;
745                                         *next_icon_y = 0;
746                                 }
748                                 if(*icon_x + get_item_w(item) > *next_icon_x)
749                                         *next_icon_x = *icon_x + get_item_w(item);
752                                 item->set_icon_x(*icon_x);
753                                 item->set_icon_y(*next_icon_y);
755                                 *next_icon_y += get_item_h(item);
756                         }
757                 }
761 // Set up a text row
762                 int next_text_x = 0;
763                 for(int j = 0; j < columns; j++)
764                 {
765                         BC_ListBoxItem *item = data[j].values[i];
766                         if(item->autoplace_text)
767                         {
768                                 display_format = LISTBOX_TEXT;
769                                 item->set_text_x(next_text_x);
770                                 item->set_text_y(*next_text_y);
772 // printf("BC_ListBox::calculate_item_coords_recursive %p %d %d %d %d %s \n", 
773 // item->get_sublist(), 
774 // item->get_columns(), 
775 // item->get_expand(), 
776 // next_text_x, 
777 // *next_text_y,
778 // item->get_text());
779 // Increment position of next column
780                                 if(j < columns - 1)
781                                         next_text_x += (column_width ? 
782                                                 column_width[j] : 
783                                                 default_column_width[j]);
784                                 else
785 // Set last column width based on text width
786                                 {
787                                         int new_w = get_item_w(item);
789                                         int *previous_w = (column_width ? 
790                                                 &column_width[j] : 
791                                                 &default_column_width[j]);
792                                         if(new_w > *previous_w)
793                                                 *previous_w = new_w;
794 //printf("BC_ListBox::calculate_item_coords_recursive 1 %d\n", new_w);
795                                 }
796                                 total_autoplaced_columns++;
797                         }
798                 }
800 // Increase the text vertical position
801                 if(total_autoplaced_columns)
802                 {
803                         display_format = LISTBOX_TEXT;
804                         *next_text_y += get_text_height(MEDIUMFONT);
805                 }
807 // Set up a sublist
808                 BC_ListBoxItem *item = data[master_column].values[i];
809                 if(item->get_sublist() &&
810                         item->get_columns() &&
811                         item->get_expand())
812                 {
813                         calculate_item_coords_recursive(
814                                 item->get_sublist(),
815                                 icon_x,
816                                 next_icon_x,
817                                 next_icon_y,
818                                 next_text_y,
819                                 0);
820                 }
821         }
824 void BC_ListBox::set_justify(int value)
826         this->justify = value;
829 void BC_ListBox::set_allow_drag_column(int value)
831         this->allow_drag_column = value;
834 void BC_ListBox::set_process_drag(int value)
836         this->process_drag = value;
839 void BC_ListBox::set_master_column(int value, int redraw)
841         this->master_column = value;
842         if(redraw)
843         {
844                 draw_items(1);
845         }
848 void BC_ListBox::set_search_column(int value)
850         this->search_column = value;
853 int BC_ListBox::get_sort_column()
855         return sort_column;
858 void BC_ListBox::set_sort_column(int value, int redraw)
860         sort_column = value;
861         if(redraw)
862         {
863                 draw_titles(1);
864         }
867 int BC_ListBox::get_sort_order()
869         return sort_order;
872 void BC_ListBox::set_sort_order(int value, int redraw)
874         sort_order = value;
875         if(redraw)
876         {
877                 draw_titles(1);
878         }
885 int BC_ListBox::get_display_mode()
887         return display_format;
890 int BC_ListBox::get_yposition()
892         return yposition;
895 int BC_ListBox::get_xposition()
897         return xposition;
900 int BC_ListBox::get_highlighted_item()
902         return highlighted_item;
906 int BC_ListBox::get_item_x(BC_ListBoxItem *item)
908         if(display_format == LISTBOX_TEXT)
909                 return item->text_x - xposition + 2;
910         else
911                 return item->icon_x - xposition + 2;
914 int BC_ListBox::get_item_y(BC_ListBoxItem *item)
916         int result;
917         if(display_format == LISTBOX_TEXT)
918                 result = item->text_y - yposition + title_h + 2;
919         else
920                 result = item->icon_y - yposition + title_h + 2;
921         return result;
924 int BC_ListBox::get_item_w(BC_ListBoxItem *item)
926         if(display_format == LISTBOX_ICONS)
927         {
928                 int x, y, w, h;
929                 get_icon_mask(item, x, y, w, h);
930                 int icon_w = w;
931                 get_text_mask(item, x, y, w, h);
932                 int text_w = w;
934                 if(icon_position == ICON_LEFT)
935                         return icon_w + text_w;
936                 else
937                         return (icon_w > text_w) ? icon_w : text_w;
938         }
939         else
940         {
941                 return get_text_width(MEDIUMFONT, item->text) + 2 * LISTBOX_MARGIN;
942         }
945 int BC_ListBox::get_item_h(BC_ListBoxItem *item)
947         if(display_format == LISTBOX_ICONS)
948         {
949                 int x, y, w, h;
950                 get_icon_mask(item, x, y, w, h);
951                 int icon_h = h;
952                 get_text_mask(item, x, y, w, h);
953                 int text_h = h;
955                 if(icon_position == ICON_LEFT)
956                         return (icon_h > text_h) ? icon_h : text_h;
957                 else
958                         return icon_h + text_h;
959         }
960         else
961         {
962                 return get_text_height(MEDIUMFONT);
963         }
964         return 0;
968 int BC_ListBox::get_icon_w(BC_ListBoxItem *item)
970         BC_Pixmap *icon = item->icon;
971         if(icon) return icon->get_w();
972         return 0;
975 int BC_ListBox::get_icon_h(BC_ListBoxItem *item)
977         BC_Pixmap *icon = item->icon;
978         if(icon) return icon->get_h();
979         return 0;
982 int BC_ListBox::get_items_width()
984         int widest = 0;
986         if(display_format == LISTBOX_ICONS)
987         {
988                 for(int i = 0; i < columns; i++)
989                 {
990                         for(int j = 0; j < data[i].total; j++)
991                         {
992                                 int x1, x, y, w, h;
993                                 BC_ListBoxItem *item = data[i].values[j];
994                                 x1 = item->icon_x;
996                                 get_icon_mask(item, x, y, w, h);
997                                 if(x1 + w > widest) widest = x1 + w;
999                                 if(display_format == LISTBOX_ICONS && icon_position == ICON_LEFT)
1000                                         x1 += w;
1002                                 get_text_mask(item, x, y, w, h);
1003                                 if(x1 + w > widest) widest = x1 + w;
1004                         }
1005                 }
1006         }
1007         else
1008         if(display_format == LISTBOX_TEXT)
1009         {
1010                 return get_column_offset(columns);
1011         }
1012         return widest;
1015 int BC_ListBox::get_items_height(ArrayList<BC_ListBoxItem*> *data, 
1016         int columns,
1017         int *result)
1019         int temp = 0;
1020         int top_level = 0;
1021         int highest = 0;
1022         if(!result)
1023         {
1024                 result = &temp;
1025                 top_level = 1;
1026         }
1032         for(int j = 0; j < (data ? data[master_column].total : 0); j++)
1033         {
1034                 int y1, x, y, w, h;
1035                 BC_ListBoxItem *item = data[master_column].values[j];
1037                 if(display_format == LISTBOX_ICONS)
1038                 {
1039                         get_icon_mask(item, x, y, w, h);
1040                         if(y + h + yposition > highest) highest = y + h + yposition;
1042                         get_text_mask(item, x, y, w, h);
1043                         if(y + h + yposition > highest) highest = y + h + yposition;
1044                 }
1045                 else
1046                 {
1047                         get_text_mask(item, x, y, w, h);
1048                         *result += h;
1051 // Descend into sublist
1052                         if(item->get_sublist() &&
1053                                 item->get_expand())
1054                         {
1055                                 get_items_height(item->get_sublist(), 
1056                                         item->get_columns(), 
1057                                         result);
1058                         }
1059                 }
1060         }
1061         if(display_format == LISTBOX_TEXT && top_level) 
1062         {
1063                 highest = LISTBOX_MARGIN + *result;
1064         }
1067         return highest;
1070 int BC_ListBox::set_yposition(int position, int draw_items)
1072         this->yposition = position;
1073         if(draw_items)
1074         {
1075                 this->draw_items(1);
1076         }
1077         return 0;
1080 int BC_ListBox::set_xposition(int position)
1082         this->xposition = position;
1083         draw_items(1);
1084         return 0;
1087 void BC_ListBox::expand_item(BC_ListBoxItem *item, int expand)
1089         if(item)
1090         {
1091                 item->expand = expand;
1092 // Collapse sublists if this is collapsed to make it easier to calculate
1093 // coordinates
1094                 if(item->get_sublist())
1095                         collapse_recursive(item->get_sublist(), master_column);
1098 // Set everything for autoplacement
1099                 
1100                 set_autoplacement(data, 0, 1);
1102                 draw_items(1);
1103         }
1106 void BC_ListBox::collapse_recursive(ArrayList<BC_ListBoxItem*> *data,
1107                 int master_column)
1109         for(int i = 0; i < data[master_column].total; i++)
1110         {
1111                 BC_ListBoxItem *item = data[master_column].values[i];
1112                 if(item->get_sublist() && item->expand)
1113                 {
1114                         item->expand = 0;
1115                         collapse_recursive(item->get_sublist(), master_column);
1116                 }
1117         }
1120 void BC_ListBox::set_autoplacement(ArrayList<BC_ListBoxItem*> *data,
1121         int do_icons, 
1122         int do_text)
1124         for(int i = 0; i < data[0].total; i++)
1125         {
1126                 for(int j = 0; j < columns; j++)
1127                 {
1128                         if(do_icons) data[j].values[i]->autoplace_icon = 1;
1129                         if(do_text) data[j].values[i]->autoplace_text = 1;
1130                 }
1132                 BC_ListBoxItem *item = data[master_column].values[i];
1133                 if(item->get_sublist())
1134                 {
1135                         set_autoplacement(item->get_sublist(), do_icons, do_text);
1136                 }
1137         }
1142 int BC_ListBox::get_w()
1144         if(is_popup)
1145                 return BCPOPUPLISTBOX_W;
1146         else
1147                 return popup_w;
1150 int BC_ListBox::get_h()
1152         if(is_popup)
1153                 return BCPOPUPLISTBOX_H;
1154         else
1155                 return popup_h;
1158 int BC_ListBox::get_yscroll_x()
1160         if(is_popup)
1161                 return popup_w - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w();
1162         else
1163                 return get_x() + 
1164                         popup_w - 
1165                         get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w();
1168 int BC_ListBox::get_yscroll_y()
1170         if(is_popup)
1171                 return 0;
1172         else
1173                 return get_y();
1176 int BC_ListBox::get_yscroll_height()
1178         return popup_h - (need_xscroll ? 
1179                 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h() : 
1180                 0);
1183 int BC_ListBox::get_xscroll_x()
1185         if(is_popup)
1186                 return 0;
1187         else
1188                 return get_x();
1191 int BC_ListBox::get_xscroll_y()
1193         if(is_popup)
1194                 return popup_h - 
1195                         get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h();
1196         else
1197                 return get_y() + 
1198                         popup_h - 
1199                         get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h();
1202 int BC_ListBox::get_xscroll_width()
1204         return popup_w - (need_yscroll ? 
1205                 get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w() : 
1206                 0);
1209 int BC_ListBox::get_column_offset(int column)
1211         int x = 0;
1212         while(column > 0)
1213         {
1214                 x += column_width ? 
1215                         column_width[--column] : 
1216                         default_column_width[--column];
1217         }
1218         return x;
1221 void BC_ListBox::column_width_boundaries()
1223         if(column_width)
1224         {
1225                 for(int i = 0; i < columns; i++)
1226                 {
1227                         if(column_width[i] < MIN_COLUMN_WIDTH) column_width[i] = MIN_COLUMN_WIDTH;
1228                 }
1229         }
1230         else
1231         {
1232                 for(int i = 0; i < columns; i++)
1233                 {
1234                         if(default_column_width[i] < MIN_COLUMN_WIDTH) default_column_width[i] = MIN_COLUMN_WIDTH;
1235                 }
1236         }
1239 int BC_ListBox::get_column_width(int column, int clamp_right)
1241         if(column < columns - 1 || !clamp_right)
1242                 return column_width ? 
1243                         column_width[column] : 
1244                         default_column_width[column];
1245         else
1246                 return popup_w + 
1247                         xposition - 
1248                         get_column_offset(column);
1251 int BC_ListBox::get_icon_mask(BC_ListBoxItem *item, 
1252         int &x, 
1253         int &y, 
1254         int &w, 
1255         int &h)
1257         if(display_format == LISTBOX_ICONS)
1258         {
1259                 x = get_item_x(item);
1260                 y = get_item_y(item);
1261                 w = get_icon_w(item) + ICON_MARGIN * 2;
1262                 h = get_icon_h(item) + ICON_MARGIN * 2;
1263         }
1264         else
1265         if(display_format == LISTBOX_TEXT)
1266         {
1267                 x = y = w = h = 0;
1268         }
1269         return 0;
1272 int BC_ListBox::get_text_mask(BC_ListBoxItem *item, 
1273         int &x, 
1274         int &y, 
1275         int &w, 
1276         int &h)
1278         x = get_item_x(item);
1279         y = get_item_y(item);
1281         if(display_format == LISTBOX_ICONS)
1282         {
1283                 if(icon_position == ICON_LEFT)
1284                 {
1285                         x += get_icon_w(item) + ICON_MARGIN * 2;
1286                         y += get_icon_h(item) - get_text_height(MEDIUMFONT);
1287                 }
1288                 else
1289                 {
1290                         y += get_icon_h(item) + ICON_MARGIN;
1291                 }
1293                 w = get_text_width(MEDIUMFONT, item->text) + ICON_MARGIN * 2;
1294                 h = get_text_height(MEDIUMFONT) + ICON_MARGIN * 2;
1295         }
1296         else
1297         if(display_format == LISTBOX_TEXT)
1298         {
1299                 w = get_text_width(MEDIUMFONT, item->text) + LISTBOX_MARGIN * 2;
1300                 h = get_text_height(MEDIUMFONT);
1301         }
1302         return 0;
1305 int BC_ListBox::get_item_highlight(ArrayList<BC_ListBoxItem*> *data, 
1306         int column, 
1307         int item)
1309         BC_Resources *resources = get_resources();
1310         if(data[column].values[item]->selected)
1311                 return resources->listbox_selected;
1312         else
1313         if(highlighted_item >= 0 &&
1314                 highlighted_ptr == data[master_column].values[item])
1315                 return resources->listbox_highlighted;
1316         else
1317                 return resources->listbox_inactive;
1320 int BC_ListBox::get_item_color(ArrayList<BC_ListBoxItem*> *data, 
1321         int column, 
1322         int item)
1324         int color = data[column].values[item]->color;
1325         if(color == -1) color = get_resources()->listbox_text;
1326         if(get_item_highlight(data, column, item) == color)
1327                 return BLACK;
1328         else
1329                 return color;
1332 int BC_ListBox::get_from_column()
1334         return dragged_title;
1337 int BC_ListBox::get_to_column()
1339         return highlighted_title;
1343 BC_ListBoxItem* BC_ListBox::get_selection(int column, 
1344         int selection_number)
1346         return get_selection_recursive(data,
1347                 column,
1348                 selection_number);
1351 BC_ListBoxItem* BC_ListBox::get_selection_recursive(
1352         ArrayList<BC_ListBoxItem*> *data,
1353         int column,
1354         int selection_number)
1356         if(!data) return 0;
1358         for(int i = 0; i < data[master_column].total; i++)
1359         {
1360                 BC_ListBoxItem *item = data[master_column].values[i];
1361                 if(item->selected)
1362                 {
1363                         selection_number--;
1364                         if(selection_number < 0)
1365                         {
1367                                 return data[column].values[i];
1368                         }
1369                 }
1371                 if(item->get_sublist())
1372                 {
1373                         BC_ListBoxItem *result = get_selection_recursive(item->get_sublist(),
1374                                 column,
1375                                 selection_number);
1376                         if(result) return result;
1377                 }
1378         }
1379         return 0;
1383 int BC_ListBox::get_selection_number(int column, 
1384         int selection_number)
1386         return get_selection_number_recursive(data,
1387                 column,
1388                 selection_number);
1391 int BC_ListBox::get_selection_number_recursive(
1392         ArrayList<BC_ListBoxItem*> *data,
1393         int column,
1394         int selection_number,
1395         int *counter)
1397         int temp = -1;
1398         if(!data) return 0;
1399         if(!counter) counter = &temp;
1401         for(int i = 0; i < data[master_column].total; i++)
1402         {
1403                 (*counter)++;
1404                 BC_ListBoxItem *item = data[master_column].values[i];
1405                 if(item->selected)
1406                 {
1407                         selection_number--;
1408                         if(selection_number < 0)
1409                         {
1410                                 return (*counter);
1411                         }
1412                 }
1413                 if(item->get_sublist())
1414                 {
1415                         int result = get_selection_number_recursive(
1416                                 item->get_sublist(),
1417                                 column,
1418                                 selection_number,
1419                                 counter);
1420                         if(result >= 0) return result;
1421                 }
1422         }
1423         return -1;
1427 int BC_ListBox::set_selection_mode(int mode)
1429         this->selection_mode = mode;
1430         return 0;
1433 void BC_ListBox::delete_columns()
1435         if(column_titles)
1436         {
1437                 for(int i = 0; i < columns; i++)
1438                 {
1439                         delete [] column_titles[i];
1440                 }
1441                 delete [] column_titles;
1442         }
1444         if(column_width) delete [] column_width;
1445         
1446         column_titles = 0;
1447         column_width = 0;
1450 // Need to copy titles so EDL can change
1451 void BC_ListBox::set_columns(char **column_titles, 
1452         int *column_width, 
1453         int columns)
1455         if((!column_titles && column_width) ||
1456                 (column_titles && !column_width))
1457         {
1458                 printf("BC_ListBox::set_columns either column_titles or column_width == NULL but not both.\n");
1459                 return;
1460         }
1463         delete_columns();
1465         if(column_titles)
1466         {
1467                 this->column_titles = new char*[columns];
1468                 for(int i = 0; i < columns; i++)
1469                 {
1470                         this->column_titles[i] = new char[strlen(column_titles[i]) + 1];
1471                         strcpy(this->column_titles[i], column_titles[i]);
1472                 }
1473         }
1474         
1475         if(column_width)
1476         {
1477                 this->column_width = new int[columns];
1478                 for(int i = 0; i < columns; i++)
1479                 {
1480                         this->column_width[i] = column_width[i];
1481                 }
1482         }
1483         
1484         this->columns = columns;
1489 int BC_ListBox::update(ArrayList<BC_ListBoxItem*> *data,
1490         char **column_titles,
1491         int *column_widths,
1492         int columns,
1493         int xposition,
1494         int yposition, 
1495         int highlighted_number,
1496         int recalc_positions,
1497         int draw)
1500         set_columns(column_titles, 
1501                 column_widths, 
1502                 columns);
1504         this->data = data;
1506         this->yposition = yposition;
1507         this->xposition = xposition;
1508         this->highlighted_item = highlighted_number;
1509         this->highlighted_ptr = index_to_item(data, highlighted_number, 0);
1511         if(recalc_positions)
1512                 set_autoplacement(data, 1, 1);
1514         init_column_width();
1516         if(gui && draw)
1517         {
1518                 draw_background();
1519                 draw_items(1);
1520                 update_scrollbars();
1521         }
1523         return 0;
1526 void BC_ListBox::center_selection()
1528         int selection = get_selection_number(0, 0);
1530         calculate_item_coords();
1531         center_selection(selection);
1534         if(gui)
1535         {
1536                 draw_background();
1537                 draw_items(1);
1538                 update_scrollbars();
1539         }
1542 void BC_ListBox::move_vertical(int pixels)
1546 void BC_ListBox::move_horizontal(int pixels)
1550 int BC_ListBox::select_previous(int skip, 
1551         BC_ListBoxItem *selected_item,
1552         int *counter,
1553         ArrayList<BC_ListBoxItem*> *data,
1554         int *got_first,
1555         int *got_second)
1557         int top_level = 0;
1558         if(!selected_item)
1559                 selected_item = get_selection(0, 0);
1560         int temp = -1;
1561         if(!counter)
1562                 counter = &temp;
1563         int temp2 = 0;
1564         if(!got_first)
1565         {
1566                 got_first = &temp2;
1567                 top_level = 1;
1568         }
1569         int temp3 = 0;
1570         if(!got_second)
1571                 got_second = &temp3;
1572         if(!data)
1573                 data = this->data;
1574         int done = 0;
1576 // Scan backwards to item pointer.  Then count visible items to get 
1577 // destination.  Repeat to get wraparound.
1578         do
1579         {
1580                 for(int i = data[master_column].total - 1; i >= 0; i--)
1581                 {
1582                         BC_ListBoxItem *current_item = data[master_column].values[i];
1583                         if(current_item->get_sublist() &&
1584                                 current_item->get_expand())
1585                         {
1586                                 int result = select_previous(skip, 
1587                                         selected_item,
1588                                         counter,
1589                                         current_item->get_sublist(),
1590                                         got_first,
1591                                         got_second);
1592                                 if(*got_second)
1593                                 {
1594                                         return result;
1595                                 }
1596                         }
1598                         if(*got_first)
1599                         {
1600                                 (*counter)++;
1601                                 if((*counter) >= skip)
1602                                 {
1603                                         for(int j = 0; j < columns; j++)
1604                                                 data[j].values[i]->selected = 1;
1605                                         (*got_second) = 1;
1606                                         return item_to_index(this->data, current_item);
1607                                 }
1608                         }
1609                         else
1610                         {
1611                                 if(current_item->selected)
1612                                 {
1613                                         for(int j = 0; j < columns; j++)
1614                                                 data[j].values[i]->selected = 0;
1615                                         (*got_first) = 1;
1616                                         (*counter)++;
1617                                 }
1618                         }
1619                 }
1621 // Hit bottom of top level without finding a selected item.
1622                 if(top_level && !(*got_first)) (*got_first) = 1;
1623         }while(top_level && data[master_column].total);
1624         return -1;
1627 int BC_ListBox::select_next(int skip, 
1628         BC_ListBoxItem *selected_item,
1629         int *counter,
1630         ArrayList<BC_ListBoxItem*> *data,
1631         int *got_first,
1632         int *got_second)
1634         int top_level = 0;
1635         if(!selected_item)
1636                 selected_item = get_selection(0, 0);
1637         int temp = -1;
1638         if(!counter)
1639                 counter = &temp;
1640         int temp2 = 0;
1641         if(!got_first)
1642         {
1643                 got_first = &temp2;
1644                 top_level = 1;
1645         }
1646         int temp3 = 0;
1647         if(!got_second)
1648                 got_second = &temp3;
1649         if(!data)
1650                 data = this->data;
1651         int done = 0;
1653 // Scan backwards to item pointer.  Then count visible items to get 
1654 // destination.  Repeat to get wraparound.
1655         do
1656         {
1657                 for(int i = 0; i < data[master_column].total; i++)
1658                 {
1659                         BC_ListBoxItem *current_item = data[master_column].values[i];
1660                         if(*got_first)
1661                         {
1662                                 (*counter)++;
1663                                 if((*counter) >= skip)
1664                                 {
1665                                         for(int j = 0; j < columns; j++)
1666                                                 data[j].values[i]->selected = 1;
1667                                         (*got_second) = 1;
1668                                         return item_to_index(this->data, current_item);
1669                                 }
1670                         }
1671                         else
1672                         {
1673                                 if(current_item->selected)
1674                                 {
1675                                         for(int j = 0; j < columns; j++)
1676                                                 data[j].values[i]->selected = 0;
1677                                         (*got_first) = 1;
1678                                         (*counter)++;
1679                                 }
1680                         }
1682                         if(current_item->get_sublist() &&
1683                                 current_item->get_expand())
1684                         {
1685                                 int result = select_next(skip, 
1686                                         selected_item,
1687                                         counter,
1688                                         current_item->get_sublist(),
1689                                         got_first,
1690                                         got_second);
1691                                 if(*got_second)
1692                                 {
1693                                         return result;
1694                                 }
1695                         }
1696                 }
1698 // Hit bottom of top level without finding a selected item.
1699                 if(top_level && !(*got_first)) (*got_first) = 1;
1700         }while(top_level && data[master_column].total);
1701         return -1;
1705 void BC_ListBox::clamp_positions()
1707         items_w = get_items_width();
1708         items_h = get_items_height(data, columns);
1710         if(yposition < 0) yposition = 0;
1711         else
1712         if(yposition > items_h - view_h)
1713                 yposition = items_h - view_h;
1715         if(yposition < 0) yposition = 0;
1717         if(xposition < 0) xposition = 0;
1718         else
1719         if(xposition >= items_w - view_w)
1720                 xposition = items_w - view_w;
1722         if(xposition < 0) xposition = 0;
1725 int BC_ListBox::center_selection(int selection,
1726         ArrayList<BC_ListBoxItem*> *data,
1727         int *counter)
1729         int temp = -1;
1730         if(!data) data = this->data;
1731         if(!counter) counter = &temp;
1733         for(int i = 0; i < data[master_column].total; i++)
1734         {
1735                 (*counter)++;
1737 // Got it
1738                 BC_ListBoxItem *item = data[master_column].values[i];
1739                 if((*counter) == selection)
1740                 {
1741                         BC_ListBoxItem *top_item = this->data[master_column].values[0];
1744                         if(display_format == LISTBOX_ICONS)
1745                         {
1746 // Icon is out of window
1747                                 if(item->icon_y - yposition  > 
1748                                         view_h - get_text_height(MEDIUMFONT) ||
1749                                         item->icon_y - yposition < 0)
1750                                 {
1751                                         yposition = item->icon_y - view_h / 2;
1752                                 }
1754                                 if(data[master_column].values[selection]->icon_x - xposition > view_w ||
1755                                         data[master_column].values[selection]->icon_x - xposition < 0)
1756                                 {
1757                                         xposition = item->icon_x - view_w / 2;
1758                                 }
1759                         }
1760                         else
1761                         if(display_format == LISTBOX_TEXT)
1762                         {
1763 // Text coordinate is out of window
1764                                 if(item->text_y - yposition  > 
1765                                         view_h - get_text_height(MEDIUMFONT) ||
1766                                         item->text_y - yposition < 0)
1767                                 {
1768                                         yposition = item->text_y - 
1769                                                 top_item->text_y -
1770                                                 view_h / 2;
1771                                 }
1772                         }
1773                         return 1;
1774                 }
1776 // Descend
1777                 if(item->get_sublist())
1778                 {
1779                         int result = center_selection(selection,
1780                                 item->get_sublist(),
1781                                 counter);
1782                         if(result) return result;
1783                 }
1784         }
1785         return 0;
1788 void BC_ListBox::update_scrollbars()
1790         int h_needed = items_h = get_items_height(data, columns);
1791         int w_needed = items_w = get_items_width();
1793 // if(columns > 0 && column_width)
1794 // printf("BC_ListBox::update_scrollbars 1 %d %d\n", column_width[columns - 1], w_needed);
1796         if(xscrollbar)
1797         {
1798                 if(xposition != xscrollbar->get_value())
1799                         xscrollbar->update_value(xposition);
1801                 if(w_needed != xscrollbar->get_length() || 
1802                         view_w != xscrollbar->get_handlelength())
1803                         xscrollbar->update_length(w_needed, xposition, view_w);
1804         }
1806         if(yscrollbar)
1807         {
1808                 if(yposition != yscrollbar->get_value())
1809                         yscrollbar->update_value(yposition);
1811                 if(h_needed != yscrollbar->get_length() || view_h != yscrollbar->get_handlelength())
1812                         yscrollbar->update_length(h_needed, yposition, view_h);
1813         }
1816 int BC_ListBox::get_scrollbars()
1818         int h_needed = items_h = get_items_height(data, columns);
1819         int w_needed = items_w = get_items_width();
1823         title_h = get_title_h();
1825         view_h = popup_h - title_h - 4;
1826         view_w = popup_w - 4;
1828 // Create scrollbars as needed
1829         for(int i = 0; i < 2; i++)
1830         {
1831                 if(w_needed > view_w)
1832                 {
1833                         need_xscroll = 1;
1834                         view_h = popup_h - 
1835                                 title_h - 
1836                                 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h() - 
1837                                 4;
1838                 }
1839                 else
1840                 {
1841                         need_xscroll = 0;
1842                 }
1844                 if(h_needed > view_h)
1845                 {
1846                         need_yscroll = 1;
1847                         view_w = popup_w - 
1848                                 get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w() - 
1849                                 4;
1850                 }
1851                 else
1852                 {
1853                         need_yscroll = 0;
1854                 }
1855         }
1857 // Update subwindow size
1858         int new_w = popup_w;
1859         int new_h = popup_h;
1860         if(need_xscroll) new_h -= get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h();
1861         if(need_yscroll) new_w -= get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w();
1863         if(!is_popup)
1864                 if(new_w != BC_WindowBase::get_w() || new_h != BC_WindowBase::get_h())
1865                         gui->resize_window(new_w, new_h);
1867         BC_WindowBase *destination = (is_popup ? gui : parent_window);
1868         if(need_xscroll)
1869         {
1870                 if(!xscrollbar)
1871                 {
1872                         destination->add_subwindow(xscrollbar = 
1873                                 new BC_ListBoxXScroll(this, 
1874                                         w_needed, 
1875                                         view_w, 
1876                                         xposition));
1877                         xscrollbar->bound_to = this;
1878                 }
1879                 else
1880                 {
1881                     xscrollbar->update_length(w_needed, xposition, view_w);
1882                         xscrollbar->reposition_window(get_xscroll_x(),
1883                                 get_xscroll_y(),
1884                                 get_xscroll_width());
1885                 }
1886         }
1887         else
1888         {
1889                 if(xscrollbar) delete xscrollbar;
1890                 xscrollbar = 0;
1891                 xposition = 0;
1892         }
1894         if(need_yscroll)
1895         {
1896                 if(!yscrollbar)
1897                 {
1898                         destination->add_subwindow(yscrollbar = 
1899                                 new BC_ListBoxYScroll(this, 
1900                                         h_needed, 
1901                                         view_h, 
1902                                         yposition));
1903                         yscrollbar->bound_to = this;
1904                 }
1905                 else
1906                 {
1907                         yscrollbar->update_length(h_needed, yposition, view_h);
1908                         yscrollbar->reposition_window(get_yscroll_x(),
1909                                 get_yscroll_y(),
1910                                 get_yscroll_height());
1911                 }
1912         }
1913         else
1914         {
1915                 if(yscrollbar) delete yscrollbar;
1916                 yscrollbar = 0;
1917                 yposition = 0;
1918         }
1919         
1920         if(!bg_surface ||
1921                 view_w + 4 != bg_surface->get_w() ||
1922                 view_h + 4 != bg_surface->get_h())
1923         {
1924                 if(bg_surface) delete bg_surface;
1925                 bg_surface = new BC_Pixmap(gui, view_w + 4, view_h + 4);
1926                 draw_background();
1927         }
1929         return 0;
1934 void BC_ListBox::set_drag_scroll(int value)
1936         allow_drag_scroll = value;
1940 // Test for scrolling by dragging
1942 int BC_ListBox::test_drag_scroll(int cursor_x, int cursor_y)
1944         int result = 0;
1945         if(allow_drag_scroll || 
1946                 current_operation == SELECT_RECT)
1947         {
1949                 int top_boundary = get_title_h();
1951                 if(cursor_y < top_boundary ||
1952                         cursor_y >= view_h + title_h + LISTBOX_BORDER * 2 ||
1953                         cursor_x < LISTBOX_BORDER ||
1954                         cursor_x >= view_w + LISTBOX_BORDER)
1955                 {
1956                         result = 1;
1957                 }
1958         }
1959         return result;
1962 int BC_ListBox::drag_scroll_event()
1964         int top_boundary = get_title_h();
1965         int result = 0;
1967         if(get_cursor_y() < top_boundary)
1968         {
1969                 yposition -= top_boundary - get_cursor_y();
1970                 result = 1;
1971         }
1972         else
1973         if(get_cursor_y() >= view_h + title_h + 4)
1974         {
1975                 yposition += get_cursor_y() - (view_h + title_h + 4);
1976                 result = 1;
1977         }
1979         if(get_cursor_x() < 2)
1980         {
1981                 xposition -= 2 - get_cursor_x();
1982                 result = 1;
1983         }
1984         else
1985         if(get_cursor_x() >= view_w + 2)
1986         {
1987                 xposition += get_cursor_x() - (view_w + 2);
1988                 result = 1;
1989         }
1990         if(result) clamp_positions();
1991         return result;
1994 int BC_ListBox::rectangle_scroll_event()
1996         int old_xposition = xposition;
1997         int old_yposition = yposition;
1998         int result = drag_scroll_event();
2000         if(result)
2001         {
2002                 rect_x1 += old_xposition - xposition;
2003                 rect_y1 += old_yposition - yposition;
2004                 rect_x2 = get_cursor_x();
2005                 rect_y2 = get_cursor_y();
2007                 int x1 = MIN(rect_x1, rect_x2);
2008                 int x2 = MAX(rect_x1, rect_x2);
2009                 int y1 = MIN(rect_y1, rect_y2);
2010                 int y2 = MAX(rect_y1, rect_y2);
2012                 if(select_rectangle(data,
2013                         x1, 
2014                         y1,
2015                         x2, 
2016                         y2))
2017                 {
2018                         selection_changed();
2019                 }
2021                 clamp_positions();
2022                 draw_items(1);
2023                 update_scrollbars();
2024         }
2025         return result;
2028 int BC_ListBox::select_scroll_event()
2030         int result = drag_scroll_event();
2032         if(result)
2033         {
2034                 highlighted_item = selection_number = get_cursor_item(data, 
2035                         get_cursor_x(), 
2036                         get_cursor_y(),
2037                         &highlighted_ptr);
2038                 clamp_positions();
2039                 draw_items(1);
2040                 update_scrollbars();
2041                 selection_changed();
2042         }
2043         return result;
2046 int BC_ListBox::select_rectangle(ArrayList<BC_ListBoxItem*> *data,
2047                 int x1, 
2048                 int y1,
2049                 int x2, 
2050                 int y2)
2052         int result = 0;
2053         for(int i = 0; i < data[master_column].total; i++)
2054         {
2055                 for(int j = 0; j < columns; j++)
2056                 {
2057                         BC_ListBoxItem *item = data[j].values[i];
2058                         if(display_format == LISTBOX_ICONS)
2059                         {
2060                                 int icon_x, icon_y, icon_w, icon_h;
2061                                 int text_x, text_y, text_w, text_h;
2062                                 get_icon_mask(item, icon_x, icon_y, icon_w, icon_h);
2063                                 get_text_mask(item, text_x, text_y, text_w, text_h);
2065                                 if((x2 >= icon_x && x1 < icon_x + icon_w &&
2066                                         y2 >= icon_y && y1 < icon_y + icon_h) ||
2067                                         (x2 >= text_x && x1 < text_x + text_w &&
2068                                         y2 >= text_y && y1 < text_y + text_h))
2069                                 {
2070                                         if(!item->selected)
2071                                         {
2072                                                 item->selected = 1;
2073                                                 result = 1;
2074                                         }
2075                                 }
2076                                 else
2077                                 {
2078                                         if(item->selected)
2079                                         {
2080                                                 item->selected = 0;
2081                                                 result = 1;
2082                                         }
2083                                 }
2084                         }
2085                         else
2086                         {
2087                                 if(x2 >= 0 && 
2088                                         x1 < (yscrollbar ? 
2089                                                 gui->get_w() - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w() : 
2090                                                 gui->get_w()) &&
2091                                         y2 > 0 && 
2092                                         y1 < gui->get_h() &&
2093                                         y2 >= get_item_y(item) &&
2094                                         y1 < get_item_y(item) + get_item_h(item))
2095                                 {
2096                                         if(!item->selected)
2097                                         {
2098                                                 item->selected = 1;
2099                                                 result = 1;
2100                                         }
2101                                 }
2102                                 else
2103                                 {
2104                                         if(item->selected)
2105                                         {
2106                                                 item->selected = 0;
2107                                                 result = 1;
2108                                         }
2109                                 }
2110                         }
2111                 }
2113                 BC_ListBoxItem *item = data[master_column].values[i];
2114                 if(item->get_sublist() &&
2115                         item->get_expand())
2116                         result |= select_rectangle(item->get_sublist(),
2117                                 x1, 
2118                                 y1,
2119                                 x2, 
2120                                 y2);
2121         }
2122         return result;
2125 int BC_ListBox::reposition_item(ArrayList<BC_ListBoxItem*> *data,
2126                 int selection_number,
2127                 int x,
2128                 int y,
2129                 int *counter)
2131         int temp = -1;
2132         if(!counter) counter = &temp;
2135         for(int i = 0; i < data[master_column].total; i++)
2136         {
2137                 BC_ListBoxItem *item = data[master_column].values[i];
2138                 (*counter)++;
2139                 if((*counter) == selection_number)
2140                 {
2141                         item->icon_x = x;
2142                         item->icon_y = y;
2143                         return 1;
2144                 }
2145 // Not recursive because it's only used for icons
2146         }
2147         return 0;
2150 void BC_ListBox::move_selection(ArrayList<BC_ListBoxItem*> *dst,
2151         ArrayList<BC_ListBoxItem*> *src)
2153         for(int i = 0; i < src[master_column].total; i++)
2154         {
2155                 BC_ListBoxItem *item = src[master_column].values[i];
2157 // Move item to dst
2158                 if(item->selected)
2159                 {
2160                         for(int j = 0; j < columns; j++)
2161                         {
2162                                 dst[j].append(src[j].values[i]);
2163                                 src[j].remove_number(i);
2164                         }
2165                 }
2166                 else
2167 // Descend into sublist
2168                 if(item->get_sublist())
2169                 {
2170                         move_selection(dst, 
2171                                 item->get_sublist());
2172                 }
2173         }
2176 int BC_ListBox::put_selection(ArrayList<BC_ListBoxItem*> *data,
2177         ArrayList<BC_ListBoxItem*> *src,
2178         int destination,
2179         int *counter)
2181         int temp = -1;
2182         if(!counter) counter = &temp;
2184         if(destination < 0)
2185         {
2186                 for(int j = 0; j < columns; j++)
2187                 {
2188                         for(int i = 0; i < src[j].total; i++)
2189                         {
2190                                 data[j].append(src[j].values[i]);
2191                         }
2192                 }
2193                 return 1;
2194         }
2195         else
2196         for(int i = 0; i < data[master_column].total; i++)
2197         {
2198                 (*counter)++;
2199                 if((*counter) == destination)
2200                 {
2201                         for(int j = 0; j < columns; j++)
2202                         {
2203                                 for(int k = 0; k < src[j].total; k++)
2204                                 {
2205                                         data[j].insert(src[j].values[k], destination + k);
2206                                 }
2207                         }
2208                         return 1;
2209                 }
2211                 BC_ListBoxItem *item = data[master_column].values[i];
2212                 if(item->get_sublist())
2213                 {
2214                         if(put_selection(item->get_sublist(),
2215                                 src,
2216                                 destination,
2217                                 counter))
2218                                 return 1;
2219                 }
2220         }
2221         return 0;
2226 int BC_ListBox::item_to_index(ArrayList<BC_ListBoxItem*> *data,
2227                 BC_ListBoxItem *item,
2228                 int *counter)
2230         int temp = -1;
2231         if(!counter) counter = &temp;
2233         for(int i = 0; i < data[master_column].total; i++)
2234         {
2235                 (*counter)++;
2236                 for(int j = 0; j < columns; j++)
2237                 {
2238                         BC_ListBoxItem *new_item = data[j].values[i];
2239 //printf("BC_ListBox::item_to_index 1 %d %d %p\n", j, i, new_item);
2240                         if(new_item == item)
2241                         {
2242                                 return (*counter);
2243                         }
2244                 }
2246                 BC_ListBoxItem *new_item = data[master_column].values[i];
2247                 if(new_item->get_sublist())
2248                 {
2249                         if(item_to_index(new_item->get_sublist(),
2250                                 item,
2251                                 counter) >= 0)
2252                                 return (*counter);
2253                 }
2254         }
2256         return -1;
2259 BC_ListBoxItem* BC_ListBox::index_to_item(ArrayList<BC_ListBoxItem*> *data,
2260                 int number,
2261                 int column,
2262                 int *counter)
2264         int temp = -1;
2265         if(!counter) counter = &temp;
2266         for(int i = 0; i < data[master_column].total; i++)
2267         {
2268                 (*counter)++;
2269                 if((*counter) == number)
2270                 {
2271                         return data[column].values[i];
2272                 }
2273                 BC_ListBoxItem *item = data[master_column].values[i];
2274                 if(item->get_sublist())
2275                 {
2276                         BC_ListBoxItem *result = index_to_item(item->get_sublist(),
2277                                 number,
2278                                 column,
2279                                 counter);
2280                         if(result) return result;
2281                 }
2282         }
2283         return 0;
2286 int BC_ListBox::get_cursor_item(ArrayList<BC_ListBoxItem*> *data,
2287         int cursor_x, 
2288         int cursor_y, 
2289         BC_ListBoxItem **item_return,
2290         int *counter,
2291         int expanded)
2293         int temp = -1;
2294         if(!data) return -1;
2295         if(!counter) counter = &temp;
2297 // Icons are not treed
2298         if(display_format == LISTBOX_ICONS)
2299         {
2300                 for(int j = data[master_column].total - 1; j >= 0; j--)
2301                 {
2302                         int icon_x, icon_y, icon_w, icon_h;
2303                         int text_x, text_y, text_w, text_h;
2304                         BC_ListBoxItem *item = data[master_column].values[j];
2305                         get_icon_mask(item, icon_x, icon_y, icon_w, icon_h);
2306                         get_text_mask(item, text_x, text_y, text_w, text_h);
2308                         if((cursor_x >= icon_x && cursor_x < icon_x + icon_w &&
2309                                 cursor_y >= icon_y && cursor_y < icon_y + icon_h) ||
2310                                 (cursor_x >= text_x && cursor_x < text_x + text_w &&
2311                                 cursor_y >= text_y && cursor_y < text_y + text_h))
2312                         {
2313                                 if(item_return) (*item_return) = item;
2314                                 return j;
2315                         }
2316                 }
2317         }
2318         else
2319 // Text is treed
2320         if(display_format == LISTBOX_TEXT)
2321         {
2322 // Cursor is inside items rectangle
2323                 if(cursor_x >= 0 && 
2324                         cursor_x < (yscrollbar ? 
2325                                 gui->get_w() - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w() : 
2326                                 gui->get_w()) &&
2327 // Only clamp y if we're not in a SELECT operation.
2328                         (current_operation == BC_ListBox::SELECT ||
2329                                 (cursor_y > get_title_h() + LISTBOX_BORDER && 
2330                                 cursor_y < gui->get_h())))
2331                 {
2332 // Search table for cursor obstruction
2333                         for(int i = 0; i < data[master_column].total; i++)
2334                         {
2335                                 BC_ListBoxItem *item = data[master_column].values[i];
2336                                 (*counter)++;
2338 // Cursor is inside item on current level
2339                                 if(expanded &&
2340                                         item->selectable &&
2341                                         cursor_y >= get_item_y(item) &&
2342                                         cursor_y < get_item_y(item) + get_item_h(item))
2343                                 {
2344 //printf("BC_ListBox::get_cursor_item %d %d %p\n", master_column, i, item);
2345                                         if(item_return) (*item_return) = item;
2346                                         return (*counter);
2347                                 }
2349 // Descend into sublist
2350                                 if(item->get_sublist())
2351                                 {
2352                                         if(get_cursor_item(item->get_sublist(),
2353                                                 cursor_x, 
2354                                                 cursor_y, 
2355                                                 item_return,
2356                                                 counter,
2357                                                 item->get_expand()) >= 0)
2358                                                 return (*counter);
2359                                 }
2360                         }
2361                 }
2362         }
2363         return -1;
2366 int BC_ListBox::repeat_event(int64_t duration)
2368         switch(current_operation)
2369         {
2370 // Repeat out of bounds selection
2371                 case SELECT_RECT:
2372                         if(duration == get_resources()->scroll_repeat)
2373                                 return rectangle_scroll_event();
2374                         break;
2376                 case SELECT:
2377                         if(duration == get_resources()->scroll_repeat)
2378                                 return select_scroll_event();
2379                         break;
2381                 case NO_OPERATION:
2382 // Show tooltip
2383                         if(button_highlighted &&
2384                                 duration == get_resources()->tooltip_delay &&
2385                                 tooltip_text[0] != 0 &&
2386                                 is_popup &&
2387                                 !tooltip_done)
2388                         {
2389                                 show_tooltip();
2390                                 tooltip_done = 1;
2391                                 return 1;
2392                         }
2393                         break;
2394         }
2395         return 0;
2399 int BC_ListBox::cursor_enter_event()
2401         int result = 0;
2403         switch(current_operation)
2404         {
2405 // Cursor moved over button, pressed, and exited.
2406                 case BUTTON_DOWN_SELECT:
2407                         if(top_level->event_win == win)
2408                         {
2409                                 current_operation = BUTTON_DN;
2410                                 result = 1;
2411                                 button_highlighted = 1;
2412                                 draw_button();
2413                         }
2414                         break;
2416                 case NO_OPERATION:
2417 // Cursor entered button
2418                         if(is_popup && top_level->event_win == win)
2419                         {
2420                                 button_highlighted = 1;
2421                                 result = 1;
2422                                 draw_button();
2423                         }
2424                         else
2425 // TODO: Need to get the highlighted column title or item
2426                         if(gui && top_level->event_win == gui->win)
2427                         {
2428                                 list_highlighted = 1;
2429                                 draw_border(1);
2430                                 result = 1;
2431                         }
2432                         break;
2433         }
2435         return result;
2438 int BC_ListBox::cursor_leave_event()
2440         int redraw_button = 0;
2441         int redraw_border = 0;
2442         int redraw_titles = 0;
2443         int redraw_items = 0;
2445         if(current_operation == COLUMN_DRAG) return 0;
2447 // Left button area
2448         if(button_highlighted)
2449         {
2450                 button_highlighted = 0;
2451                 hide_tooltip();
2452                 draw_button();
2453         }
2455         if(list_highlighted)
2456         {
2457                 list_highlighted = 0;
2458                 highlighted_item = -1;
2459                 highlighted_ptr = 0;
2460                 highlighted_title = -1;
2461                 int redraw_toggles = 0;
2462                 for(int i = 0; i < expanders.total; i++)
2463                         expanders.values[i]->cursor_leave_event(&redraw_toggles);
2465                 draw_items(1);
2466         }
2468         return 0;
2471 int BC_ListBox::get_first_selection(ArrayList<BC_ListBoxItem*> *data, int *result)
2473         int temp = -1;
2474         if(!result) result = &temp;
2476         for(int i = 0; i < data[master_column].total; i++)
2477         {
2478                 BC_ListBoxItem *item = data[master_column].values[i];
2479                 (*result)++;
2480                 if(item->selected) return (*result);
2481                 if(item->get_sublist())
2482                 {
2483                         if(get_first_selection(item->get_sublist(), result) >= 0)
2484                                 return (*result);
2485                 }
2486         }
2487         return -1;
2490 int BC_ListBox::get_total_items(ArrayList<BC_ListBoxItem*> *data, 
2491         int *result,
2492         int master_column)
2494         int temp = 0;
2495         if(!result) result = &temp;
2497         for(int i = 0; i < data[master_column].total; i++)
2498         {
2499                 (*result)++;
2500                 if(data[master_column].values[i]->get_sublist())
2501                         get_total_items(data[master_column].values[i]->get_sublist(), 
2502                                 result,
2503                                 master_column);
2504         }
2506         return (*result);
2510 int BC_ListBox::get_last_selection(ArrayList<BC_ListBoxItem*> *data, 
2511         int *result)
2513         int temp = -1;
2514         int top_level = 0;
2515         if(!result)
2516         {
2517                 result = &temp;
2518                 top_level = 1;
2519         }
2521         for(int i = data[master_column].total - 1; i >= 0; i--)
2522         {
2523                 BC_ListBoxItem *item = data[master_column].values[i];
2524                 (*result)++;
2525                 if(item->selected)
2526                 {
2527                         if(top_level)
2528                                 return get_total_items(data, 0, master_column) - (*result) /* - 1 */;
2529                         else
2530                                 return (*result);
2531                 }
2533                 if(item->get_sublist())
2534                 {
2535                         if(get_last_selection(item->get_sublist(), result) >= 0)
2536                         {
2537                                 if(top_level)
2538                                         return get_total_items(data, 0, master_column) - (*result) /* - 1 */;
2539                                 else
2540                                         return (*result);
2541                         }
2542                 }
2543         }
2544         return -1;
2547 void BC_ListBox::select_range(ArrayList<BC_ListBoxItem*> *data,
2548                 int start,
2549                 int end,
2550                 int *current)
2552         int temp = -1;
2553         if(!current) current = &temp;
2555         for(int i = 0; i < data[master_column].total; i++)
2556         {
2557                 (*current)++;
2558                 if((*current) >= start && (*current) < end)
2559                 {
2560                         for(int j = 0; j < columns; j++)
2561                                 data[j].values[i]->selected = 1;
2562                 }
2563                 BC_ListBoxItem *item = data[master_column].values[i];
2564                 if(item->get_sublist())
2565                         select_range(item->get_sublist(),
2566                                 start,
2567                                 end,
2568                                 current);
2569         }
2573 // Fill items between current selection and new selection
2574 int BC_ListBox::expand_selection(int button_press, int selection_number)
2576         int old_selection_start = selection_start;
2577         int old_selection_end = selection_end;
2579 // printf("BC_ListBox::expand_selection %d %d\n", 
2580 // selection_center, 
2581 // selection_number);
2583 // Calculate the range to select based on selection_center and selection_number
2584         if(selection_number < selection_center)
2585         {
2586                 selection_start = selection_number;
2587         }
2588         else
2589         {
2590                 selection_end = selection_number + 1;
2591         }
2593 //printf("BC_ListBox::expand_selection %d %d %d %d\n", old_selection_start, old_selection_end, selection_start, selection_end);
2594 // Recurse through all the items and select the desired range
2595         select_range(data, selection_start, selection_end);
2597 // Trigger redraw
2598         return (old_selection_start != selection_start ||
2599                 old_selection_end != selection_end);
2602 int BC_ListBox::toggle_item_selection(ArrayList<BC_ListBoxItem*> *data,
2603         int selection_number,
2604         int *counter)
2606         int temp = -1;
2607         if(!counter) counter = &temp;
2609         for(int i = 0; i < data[master_column].total; i++)
2610         {
2611                 BC_ListBoxItem *item = data[master_column].values[i];
2612                 (*counter)++;
2613                 if((*counter) == selection_number)
2614                 {
2615 // Get new value for selection
2616                         int selected = !item->selected;
2617 // Set row
2618                         for(int j = 0; j < columns; j++)
2619                                 data[j].values[i]->selected = selected;
2620                         return 1;
2621                 }
2623 // Descend into sublist
2624                 if(item->get_sublist())
2625                 {
2626                         if(toggle_item_selection(item->get_sublist(),
2627                                 selection_number,
2628                                 counter))
2629                                 return 1;
2630                 }
2631         }
2633         return 0;
2637 void BC_ListBox::set_all_selected(ArrayList<BC_ListBoxItem*> *data, int value)
2639         for(int i = 0; i < data[master_column].total; i++)
2640         {
2641                 for(int j = 0; j < columns; j++)
2642                 {
2643                         BC_ListBoxItem *item = data[j].values[i];
2644                         item->selected = value;
2645                 }
2646                 BC_ListBoxItem *item = data[master_column].values[i];
2647                 if(item->get_sublist())
2648                 {
2649                         set_all_selected(item->get_sublist(), value);
2650                 }
2651         }
2654 void BC_ListBox::set_selected(ArrayList<BC_ListBoxItem*> *data, 
2655                 int item_number, 
2656                 int value,
2657                 int *counter)
2659         int temp = -1;
2660         if(!counter) counter = &temp;
2661         for(int i = 0; i < data[master_column].total && (*counter) != item_number; i++)
2662         {
2663                 (*counter)++;
2664                 if((*counter) == item_number)
2665                 {
2666                         for(int j = 0; j < columns; j++)
2667                         {
2668                                 BC_ListBoxItem *item = data[j].values[i];
2669                                 item->selected = value;
2670                         }
2671                         return;
2672                 }
2674                 BC_ListBoxItem *item = data[master_column].values[i];
2675                 if(item->get_sublist())
2676                 {
2677                         set_selected(item->get_sublist(), 
2678                                 item_number, 
2679                                 value,
2680                                 counter);
2681                 }
2682         }
2685 int BC_ListBox::update_selection(ArrayList<BC_ListBoxItem*> *data, 
2686         int selection_number,
2687         int *counter)
2689         int temp = -1;
2690         int result = 0;
2691         if(!counter) counter = &temp;
2693         for(int i = 0; i < data[master_column].total; i++)
2694         {
2695                 BC_ListBoxItem *item = data[master_column].values[i];
2696                 (*counter)++;
2697                 if((*counter) == selection_number && !item->selected)
2698                 {
2699                         result = 1;
2700                         for(int j = 0; j < columns; j++)
2701                                 data[j].values[i]->selected = 1;
2702                 }
2703                 else
2704                 if((*counter) != selection_number && item->selected)
2705                 {
2706                         result = 1;
2707                         for(int j = 0; j < columns; j++)
2708                                 data[j].values[i]->selected = 0;
2709                 }
2710                 if(item->get_sublist())
2711                         result |= update_selection(item->get_sublist(), 
2712                                 selection_number,
2713                                 counter);
2714         }
2715         return result;
2718 void BC_ListBox::promote_selections(ArrayList<BC_ListBoxItem*> *data,
2719         int old_value,
2720         int new_value)
2722         for(int i = 0; i < data[master_column].total; i++)
2723         {
2724                 for(int j = 0; j < columns; j++)
2725                 {
2726                         BC_ListBoxItem *item = data[j].values[i];
2727                         if(item->selected == old_value) item->selected = new_value;
2728                 }
2729                 BC_ListBoxItem *item = data[master_column].values[i];
2730                 if(item->get_sublist())
2731                         promote_selections(item->get_sublist(), old_value, new_value);
2732         }
2735 int BC_ListBox::focus_out_event()
2737         deactivate();
2738         return 0;
2741 int BC_ListBox::button_press_event()
2743         int result = 0;
2744         BC_ListBoxItem *current_item = 0;
2745         int new_cursor;
2746         int do_selection_change = 0;
2748         hide_tooltip();
2752 // Pressed in button
2753         if(is_popup && top_level->event_win == win)
2754         {
2755                 current_operation = BUTTON_DN;
2756                 draw_button();
2758 // Deploy listbox
2759                 if(!active && !disabled)
2760                 {
2761                         top_level->deactivate();
2762                         activate();
2763                 }
2765                 result = 1;
2766         }
2767         else
2768 // Pressed in scrollbar
2769         if((xscrollbar && top_level->event_win == xscrollbar->win) ||
2770                 (yscrollbar && top_level->event_win == yscrollbar->win))
2771         {
2772                 result = 0;
2773         }
2774         else
2775 // Pressed in items
2776         if(gui && top_level->event_win == gui->win)
2777         {
2778 // Activate list items
2779                 if(!active)
2780                 {
2781                         top_level->deactivate();
2782                         activate();
2783                 }
2785 // Wheel mouse pressed
2786                 if(get_buttonpress() == 4 && current_operation == NO_OPERATION)
2787                 {
2788                         current_operation = WHEEL;
2789                         if(yscrollbar)
2790                         {
2791                                 set_yposition(yposition - gui->get_h() / 10, 0);
2792                                 clamp_positions();
2793                                 update_scrollbars();
2794                                 highlighted_ptr = 0;
2795                                 highlighted_item = get_cursor_item(data,
2796                                         top_level->cursor_x, 
2797                                         top_level->cursor_y, 
2798                                         &highlighted_ptr);
2799                                 draw_items(1);
2800                                 result = 1;
2801                         }
2802                 }
2803                 else
2804                 if(get_buttonpress() == 5 && current_operation == NO_OPERATION)
2805                 {
2806                         current_operation = WHEEL;
2807                         if(yscrollbar)
2808                         {
2809                                 set_yposition(yposition + gui->get_h() / 10, 0);
2810                                 clamp_positions();
2811                                 update_scrollbars();
2812                                 highlighted_ptr = 0;
2813                                 highlighted_item = get_cursor_item(data,
2814                                         top_level->cursor_x, 
2815                                         top_level->cursor_y,
2816                                         &highlighted_ptr);
2817                                 draw_items(1);
2818                                 result = 1;
2819                         }
2820                 }
2821                 else
2822 // Pressed over column title division
2823                 if(test_column_divisions(gui->get_cursor_x(), 
2824                         gui->get_cursor_y(), 
2825                         new_cursor))
2826                 {
2827                         current_operation = DRAG_DIVISION;
2828                         reset_query();
2829                 }
2830                 else
2831 // Pressed in column title
2832                 if(test_column_titles(gui->get_cursor_x(), gui->get_cursor_y()))
2833                 {
2834                         current_operation = COLUMN_DN;
2835                         button_highlighted = 0;
2836                         list_highlighted = 1;
2837                         draw_items(1);
2838                         result = 1;
2839                 }
2840                 else
2841 // Pressed in expander
2842                 if(test_expanders())
2843                 {
2844                         current_operation = EXPAND_DN;
2845 // Need to redraw items because of alpha
2846                         draw_items(1);
2847                         result = 1;
2848                 }
2849                 else
2850 // Pressed over item
2851                 if((selection_number = get_cursor_item(data, 
2852                                         gui->get_cursor_x(), 
2853                                         gui->get_cursor_y(),
2854                                         &current_item)) >= 0)
2855                 {
2856 // Get item button was pressed over
2857                         selection_number2 = selection_number1;
2858                         selection_number1 = selection_number;
2860                         selection_start = -1;
2861                         selection_end = -1;
2864 // Multiple item selection is possible
2865                         if(selection_mode == LISTBOX_MULTIPLE && 
2866                                 (ctrl_down() || shift_down()))
2867                         {
2868 // Expand text selection.
2869 // Fill items between selected region and current item.
2870                                 if(shift_down() && display_format == LISTBOX_TEXT)
2871                                 {
2872 // Get first item selected
2873                                         selection_start = get_first_selection(data);
2874 // Get last item selected
2875                                         selection_end = get_last_selection(data);
2876 // Get center of selected region
2877                                         if(selection_end > selection_start)
2878                                         {
2879                                                 selection_center = (selection_end + selection_start) >> 1;
2880                                         }
2881                                         else
2882                                         {
2883                                                 selection_center = selection_number;
2884                                         }
2887 // Deselect everything.
2888                                         set_all_selected(data, 0);
2889 // Select just the items
2890                                         expand_selection(1, selection_number);
2891                                         new_value = 1;
2892                                 }
2893                                 else
2894 // Toggle a single item on or off
2895                                 {
2896                                         toggle_item_selection(data, selection_number);
2897                                         new_value = current_item->selected;
2898                                 }
2899                         }
2900                         else
2901 // Select single item
2902                         {
2903                                 if(!current_item->selected)
2904                                 {
2905                                         set_all_selected(data, 0);
2906                                         set_selected(data,
2907                                                 selection_number,
2908                                                 1);
2909                                 }
2910                                 new_value = 1;
2911                         }
2914                         current_operation = SELECT;
2915                         highlighted_item = selection_number;
2916                         highlighted_ptr = current_item;
2917                         button_highlighted = 0;
2918                         list_highlighted = 1;
2919                         reset_query();
2920                         draw_items(1);
2921                         do_selection_change = 1;
2922                         result = 1;
2923                 }
2924                 else
2925                 if(data)
2926 // Pressed over nothing.  Start rectangle selection.
2927                 {
2928                         if(get_buttonpress() == 1 && 
2929                                 selection_mode == LISTBOX_MULTIPLE)
2930                         {
2931                                 if(!shift_down())
2932                                 {
2933 // Deselect all and redraw if anything was selected
2934                                         if(get_selection_number(0, 0) >= 0)
2935                                         {
2936                                                 set_all_selected(data, 0);
2937                                                 draw_items(1);
2938                                                 do_selection_change = 1;
2939                                                 result = 1;
2940                                         }
2941                                 }
2942                                 else
2943                                 {
2944 // Promote selections to protect from a rectangle selection
2945                                         promote_selections(data, 1, 2);
2946                                 }
2948 // Start rectangle selection
2949                                 current_operation = SELECT_RECT;
2950                                 rect_x1 = rect_x2 = get_cursor_x();
2951                                 rect_y1 = rect_y2 = get_cursor_y();
2952                         }
2953                 }
2956                 reset_query();
2957         }
2958         else
2959         if(is_popup && active)
2960         {
2961                 deactivate();
2962                 result = 1;
2963         }
2966         if(do_selection_change) selection_changed();
2968         return result;
2971 int BC_ListBox::button_release_event()
2973         int result = 0;
2974         int cursor_x, cursor_y;
2975         int do_event = 0;
2976         new_value = 0;
2978 //printf("BC_ListBox::button_release_event 1 %d\n", current_operation);
2979         switch(current_operation)
2980         {
2981                 case DRAG_DIVISION:
2982                         current_operation = NO_OPERATION;
2983                         result = 1;
2984                         break;
2986                 case WHEEL:
2987                         current_operation = NO_OPERATION;
2988                         result = 1;
2989                         break;
2991 // Release item selection
2992                 case BUTTON_DOWN_SELECT:
2993                 case SELECT:
2994 //printf("BC_ListBox::button_release_event 10\n");
2995                         unset_repeat(get_resources()->scroll_repeat);
2996                         current_operation = NO_OPERATION;
2997                         translate_coordinates(top_level->event_win,
2998                                 gui->win,
2999                                 gui->get_cursor_x(),
3000                                 gui->get_cursor_y(),
3001                                 &cursor_x,
3002                                 &cursor_y);
3004                         selection_number1 = 
3005                                 selection_number = 
3006                                 get_cursor_item(data, cursor_x, cursor_y);
3007 //printf("BC_ListBox::button_release_event %d %d\n", selection_number2, selection_number1);
3009                         if(is_popup)
3010                         {
3011                                 button_releases++;
3012                                 if(selection_number >= 0)
3013                                 {
3014                                         deactivate();
3015                                         do_event = 1;
3016                                 }
3017                                 else
3018 // Second button release outside button
3019                                 if(button_releases > 1)
3020                                 {
3021                                         deactivate();
3022                                 }
3023                         }
3024                         else
3025                         {
3026                                 if(top_level->get_double_click() &&
3027                                         selection_number2 == selection_number1 &&
3028                                         selection_number2 >= 0 &&
3029                                         selection_number1 >= 0)
3030                                 {
3031                                         do_event = 1;
3032                                 }
3033                                 result = 1;
3034                         }
3035                         break;
3038                 case SELECT_RECT:
3039                         unset_repeat(get_resources()->scroll_repeat);
3040                         if(data)
3041                         {
3042 // Demote selections from rectangle selection
3043                                 promote_selections(data, 2, 1);
3044                         }
3046 // Hide rectangle overlay
3047                         draw_rectangle(1);
3048                         current_operation = NO_OPERATION;
3049                         result = 1;
3050                         break;
3052 // Release popup button
3053                 case BUTTON_DN:
3054                         hide_tooltip();
3055                         current_operation = NO_OPERATION;
3056                         button_releases++;
3057                         draw_button();
3059 // Second button release inside button
3060                         if(button_releases > 1)
3061                         {
3062                                 deactivate();
3063                         }
3064                         result = 1;
3065                         break;
3067                 case COLUMN_DN:
3068                         current_operation = NO_OPERATION;
3069 // Update the sort column and the sort order for the user only if the existing
3070 // sort column is valid.
3071                         if(sort_column >= 0)
3072                         {
3073 // Invert order only if column is the same
3074                                 if(highlighted_title == sort_column)
3075                                         sort_order = 
3076                                                 (sort_order == SORT_ASCENDING) ? 
3077                                                 SORT_DESCENDING : 
3078                                                 SORT_ASCENDING;
3079 // Set the new sort column
3080                                 sort_column = highlighted_title;
3081                                 if(!sort_order_event())
3082                                 {
3083                                         draw_titles(1);
3084                                 }
3085                         }
3086                         else
3087 // Sorting not enabled.  Redraw the title state.
3088                         {
3089                                 draw_titles(1);
3090                         }
3091                         result = 1;
3092                         break;
3094                 case EXPAND_DN:
3095                 {
3096                         int redraw_toggles = 0;
3097                         for(int i = 0; i < expanders.total && !result; i++)
3098                         {
3099                                 if(expanders.values[i]->button_release_event(&redraw_toggles))
3100                                 {
3101                                         result = 1;
3102                                 }
3103                         }
3104 // Need to redraw items because of alpha
3105                         if(redraw_toggles) draw_items(1);
3106                         current_operation = NO_OPERATION;
3107                         break;
3108                 }
3110                 default:
3111 // Can't default to NO_OPERATION because it may be used in a drag event.
3112                         break;
3113         }
3116         if(do_event) handle_event();
3118         return result;
3121 int BC_ListBox::get_title_h()
3123         if(display_format == LISTBOX_TEXT)
3124                 return column_titles ? column_bg[0]->get_h() : 0;
3125         else
3126                 return 0;
3129 void BC_ListBox::reset_cursor(int new_cursor)
3131         if(is_popup)
3132         {
3133                 if(gui->get_cursor() != new_cursor)
3134                 {
3135                         gui->set_cursor(new_cursor);
3136                 }
3137         }
3138         else
3139         if(get_cursor() != new_cursor)
3140         {
3141                 set_cursor(new_cursor);
3142         }
3145 int BC_ListBox::test_column_divisions(int cursor_x, int cursor_y, int &new_cursor)
3147         if(gui &&
3148                 column_titles && 
3149                 cursor_y >= 0 && 
3150                 cursor_y < get_title_h() &&
3151                 cursor_x >= 0 &&
3152                 cursor_x < gui->get_w())
3153         {
3154                 for(int i = 1; i < columns; i++)
3155                 {
3156                         if(cursor_x >= -xposition + get_column_offset(i) - 5 &&
3157                                 cursor_x <  -xposition + get_column_offset(i) + 
3158                                         get_resources()->listbox_title_hotspot)
3159                         {
3160                                 highlighted_item = -1;
3161                                 highlighted_ptr = 0;
3162                                 highlighted_division = i;
3163                                 highlighted_title = -1;
3164                                 list_highlighted = 1;
3165                                 new_cursor = HSEPARATE_CURSOR;
3166                                 return 1;
3167                         }
3168                 }
3169         }
3170         highlighted_division = -1;
3171         return 0;
3174 int BC_ListBox::test_column_titles(int cursor_x, int cursor_y)
3176         if(gui &&
3177                 column_titles && 
3178                 cursor_y >= 0 && 
3179                 cursor_y < get_title_h() &&
3180                 cursor_x >= 0 && 
3181                 cursor_x < gui->get_w())
3182         {
3183                 for(int i = 0; i < columns; i++)
3184                 {
3185                         if(cursor_x >= -xposition + get_column_offset(i) &&
3186                                 (cursor_x < -xposition + get_column_offset(i + 1) ||
3187                                         i == columns - 1))
3188                         {
3189                                 highlighted_item = -1;
3190                                 highlighted_ptr = 0;
3191                                 highlighted_division = -1;
3192                                 highlighted_title = i;
3193                                 list_highlighted = 1;
3194                                 return 1;
3195                         }
3196                 }
3197         }
3198         highlighted_title = -1;
3199         return 0;
3202 int BC_ListBox::test_expanders()
3204         for(int i = 0; i < expanders.total; i++)
3205         {
3206                 if(expanders.values[i]->button_press_event())
3207                 {
3208                         current_operation = EXPAND_DN;
3209                         draw_toggles(1);
3210                         return 1;
3211                 }
3212         }
3213         return 0 ;
3216 int BC_ListBox::cursor_motion_event()
3218         int redraw = 0, result = 0;
3219         int new_cursor = ARROW_CURSOR;
3221         selection_number = -1;
3224         switch(current_operation)
3225         {
3226                 case BUTTON_DN:
3227 // Button pressed and slid off button
3228                         if(!cursor_inside())
3229                         {
3230                                 current_operation = BUTTON_DOWN_SELECT;
3231                                 draw_button();
3232                                 result = 1;
3233                         }
3234                         break;
3236                 case DRAG_DIVISION:
3237                 {
3238                         int new_w = get_cursor_x() + 
3239                                 xposition - 
3240                                 get_column_offset(highlighted_division - 1);
3241                         new_cursor = HSEPARATE_CURSOR;
3243                         if(column_width)
3244                         {
3245                                 column_width[highlighted_division - 1] = new_w;
3246                         }
3247                         else
3248                         {
3249                                 default_column_width[highlighted_division - 1] = new_w;
3250                         }
3252                         column_width_boundaries();
3254 // Force update of coords
3255                         set_autoplacement(data, 0, 1);
3256                         column_resize_event();
3258                         clamp_positions();
3259                         draw_items(1);
3260                         update_scrollbars();
3261                         result = 1;
3262                         break;
3263                 }
3265                 case SELECT_RECT:
3266                 {
3267                         if(test_drag_scroll(get_cursor_x(), get_cursor_y()))
3268                         {
3269                                 set_repeat(get_resources()->scroll_repeat);
3270                         }
3272                         int old_x1 = MIN(rect_x1, rect_x2);
3273                         int old_x2 = MAX(rect_x1, rect_x2);
3274                         int old_y1 = MIN(rect_y1, rect_y2);
3275                         int old_y2 = MAX(rect_y1, rect_y2);
3277                         int new_rect_x2 = get_cursor_x();
3278                         int new_rect_y2 = get_cursor_y();
3280                         int x1 = MIN(rect_x1, new_rect_x2);
3281                         int x2 = MAX(rect_x1, new_rect_x2);
3282                         int y1 = MIN(rect_y1, new_rect_y2);
3283                         int y2 = MAX(rect_y1, new_rect_y2);
3285 // Adjust rectangle coverage
3286                         if(old_x1 != x1 ||
3287                                 old_x2 != x2 ||
3288                                 old_y1 != y1 ||
3289                                 old_y2 != y2)
3290                         {
3291                                 if(data)
3292                                 {
3293                                         redraw = select_rectangle(data,
3294                                                 x1, 
3295                                                 y1,
3296                                                 x2, 
3297                                                 y2);
3298                                 }
3300 // hide rectangle
3301                                 if(!redraw)
3302                                         draw_rectangle(0);
3303                         }
3305                         rect_x2 = get_cursor_x();
3306                         rect_y2 = get_cursor_y();
3307                         if(redraw)
3308                         {
3309                                 clamp_positions();
3310                                 draw_items(1);
3311                                 update_scrollbars();
3312                                 selection_changed();
3313                         }
3314                         else
3315                         {
3316                                 draw_rectangle(1);
3317                         }
3318                         result = 1;
3319                         break;
3320                 }
3322                 case SELECT:
3323                 {
3324                         int old_highlighted_item = highlighted_item;
3325                         int old_highlighted_title = highlighted_title;
3326                         BC_ListBoxItem *old_highlighted_ptr = highlighted_ptr;
3328                         if(test_drag_scroll(get_cursor_x(), 
3329                                 get_cursor_y()))
3330                         {
3331                                 set_repeat(get_resources()->scroll_repeat);
3332                         }
3335                         highlighted_item = selection_number = get_cursor_item(data, 
3336                                 get_cursor_x(), 
3337                                 get_cursor_y(),
3338                                 &highlighted_ptr);
3339                         result = 1;
3341 // Deselect all items and select just the one we're over
3342                         if(selection_number >= 0 && 
3343                                 !allow_drag &&
3344                                 ((!shift_down() &&
3345                                         !ctrl_down()) ||
3346                                         selection_mode == LISTBOX_SINGLE))
3347                         {
3348                                 redraw = update_selection(data, selection_number);
3349                         }
3350                         else
3351                         if(selection_mode == LISTBOX_MULTIPLE &&
3352                                 (shift_down() || ctrl_down()))
3353 // Expand multiple selection
3354                         {
3355 // Expand selected region in text mode centered around initial range
3356                                 if(display_format == LISTBOX_TEXT && shift_down())
3357                                 {
3358 // Deselect everything.
3359                                         set_all_selected(data, 0);
3361 // Select just the items
3362                                         redraw = expand_selection(0, selection_number);
3363                                 }
3364                                 else
3365 // Set the one item we're over to the selection value determined in
3366 // button_press_event.
3367                                 {
3368                                         set_selected(data, 
3369                                                 selection_number, 
3370                                                 new_value);
3371                                 }
3372                         }
3374                         if(highlighted_item != old_highlighted_item)
3375                         {
3376                                 clamp_positions();
3377                                 draw_items(1);
3378                                 update_scrollbars();
3379 //printf("BC_ListBox::cursor_motion_event %d %d\n", highlighted_item, old_highlighted_item);
3380                                 selection_changed();
3381                         }
3382                         break;
3383                 }
3385                 case BUTTON_DOWN_SELECT:
3386 // Went back into button area
3387                         if(cursor_inside())
3388                         {
3389                                 current_operation = BUTTON_DN;
3390                                 draw_button();
3391                                 result = 1;
3392                         }
3393                         else
3394 // Went into item area
3395                         if(gui)
3396                         {
3397                                 int cursor_x = 0, cursor_y = 0;
3398                                 translate_coordinates(top_level->event_win, 
3399                                         gui->win,
3400                                         top_level->cursor_x,
3401                                         top_level->cursor_y,
3402                                         &cursor_x,
3403                                         &cursor_y);
3404                                 int old_highlighted_item = highlighted_item;
3405                                 highlighted_item = selection_number = get_cursor_item(data, 
3406                                                 cursor_x, 
3407                                                 cursor_y,
3408                                                 &highlighted_ptr);
3410                                 if(highlighted_item != old_highlighted_item)
3411                                 {
3412                                         update_selection(data, selection_number);
3413                                         draw_items(1);
3414                                         selection_changed();
3415                                 }
3416                         }
3417                         break;
3419                 case EXPAND_DN:
3420                 {
3421                         int redraw_toggles = 0;
3422                         for(int i = 0; i < expanders.total && !result; i++)
3423                         {
3424                                 result = expanders.values[i]->cursor_motion_event(
3425                                         &redraw_toggles);
3426                         }
3427                         if(redraw_toggles)
3428                         {
3429 // Need to redraw items because of the alpha
3430                                 draw_items(1);
3431                         }
3432                         break;
3433                 }
3435                 case NO_OPERATION:
3436                 {
3437                         int cursor_x = get_cursor_x(), cursor_y = get_cursor_y();
3438                         if(gui && top_level->event_win == gui->win)
3439                         {
3440                                 int old_highlighted_title = highlighted_title;
3441                                 int old_list_highlighted = list_highlighted;
3442                                 int old_highlighted_division = highlighted_division;
3443                                 int old_highlighted_item = highlighted_item;
3444                                 int redraw_titles = 0;
3445                                 int redraw_border = 0;
3446                                 int redraw_items = 0;
3447                                 int redraw_toggles = 0;
3448                                 result = 1;
3451 // Test if cursor moved over a title division
3452                                 test_column_divisions(cursor_x, cursor_y, new_cursor);
3454 // Test if cursor moved over a title
3455                                 if(highlighted_division < 0)
3456                                 {
3457                                         test_column_titles(cursor_x, cursor_y);
3458                                 }
3460 // Test if cursor moved over expander
3461                                 if(highlighted_division < 0 && 
3462                                         highlighted_title < 0 &&
3463                                         display_format == LISTBOX_TEXT)
3464                                 {
3465                                         for(int i = 0; i < expanders.total; i++)
3466                                         {
3467                                                 expanders.values[i]->cursor_motion_event(
3468                                                         &redraw_toggles);
3469                                         }
3470 //printf("BC_ListBox::cursor_motion_event %d\n", redraw_toggles);
3471                                 }
3473 // Test if cursor moved over an item
3474                                 if(highlighted_division < 0 && 
3475                                         highlighted_title < 0)
3476                                 {
3477                                         highlighted_item = get_cursor_item(data, 
3478                                                 cursor_x, 
3479                                                 cursor_y,
3480                                                 &highlighted_ptr);
3481                                 }
3484 // Clear title highlighting if moved over division
3485                                 if(old_highlighted_title != highlighted_title)
3486                                 {
3487                                         redraw_titles = 1;
3488                                 }
3490 // Highlight list border
3491                                 if(old_list_highlighted != list_highlighted)
3492                                 {
3493                                         redraw_border = 1;
3494                                 }
3496 // Moved out of item area
3497                                 if(old_highlighted_item != highlighted_item)
3498                                 {
3499                                         redraw_items = 1;
3500                                 }
3502 //printf("BC_ListBox::cursor_motion_event 1 %d\n", highlighted_item);
3504 // Change cursor to title division adjustment
3505                                 reset_cursor(new_cursor);
3507                                 if(redraw_items)
3508                                 {
3509                                         draw_items(0);
3510                                 }
3511                                 else
3512                                 {
3513                                         if(redraw_titles)
3514                                                 draw_titles(0);
3515                                         if(redraw_border)
3516                                                 draw_border(0);
3517                                         if(redraw_toggles)
3518                                                 draw_toggles(0);
3519                                 }
3521                                 if(redraw_items || 
3522                                         redraw_titles || 
3523                                         redraw_border || 
3524                                         redraw_toggles)
3525                                 {
3526                                         gui->flash();
3527                                         gui->flush();
3528                                 }
3529                         }
3532                         if(!result && list_highlighted)
3533                         {
3534                                 list_highlighted = 0;
3535                                 highlighted_item = -1;
3536                                 highlighted_ptr = 0;
3537                                 highlighted_title = -1;
3538                                 highlighted_division = -1;
3539                                 draw_items(1);
3540                                 result = 0;
3541                         }
3542                         break;
3543                 }
3544         }
3547         return result;
3550 int BC_ListBox::drag_start_event()
3552         switch(current_operation)
3553         {
3554                 case SELECT:
3555                         if(gui && 
3556                                 gui->is_event_win() && 
3557                                 allow_drag)
3558                         {
3559                                 BC_ListBoxItem *item_return = 0;
3560                                 selection_number = get_cursor_item(data, 
3561                                         top_level->cursor_x, 
3562                                         top_level->cursor_y,
3563                                         &item_return);
3565                                 if(selection_number >= 0)
3566                                 {
3567                                         
3568                                         if (item_return->icon_vframe)
3569                                         {
3570                                                 drag_popup = new BC_DragWindow(this, 
3571                                                         item_return->icon_vframe, 
3572                                                         get_abs_cursor_x(0) - item_return->icon_vframe->get_w() / 2,
3573                                                         get_abs_cursor_y(0) - item_return->icon_vframe->get_h() / 2);
3574                                         }
3575                                         else    
3576 // this probably works not!
3577                                         if (item_return->icon)  
3578                                                 drag_popup = new BC_DragWindow(this, 
3579                                                         item_return->icon, 
3580                                                         get_abs_cursor_x(0) - item_return->icon->get_w() / 2,
3581                                                         get_abs_cursor_y(0) - item_return->icon->get_h() / 2);
3582                                         else
3583                                                 drag_popup = new BC_DragWindow(this, 
3584                                                         drag_icon_vframe, 
3585                                                         get_abs_cursor_x(0) - drag_icon_vframe->get_w() / 2,
3586                                                         get_abs_cursor_y(0) - drag_icon_vframe->get_h() / 2);
3587                                         current_operation = DRAG_ITEM;
3588                                         return 1;
3589                                 }
3590                         }
3591                         break;
3593                 case COLUMN_DN:
3594                         if(gui && gui->is_event_win() && allow_drag_column)
3595                         {
3596                                 drag_popup = new BC_DragWindow(this, 
3597                                         drag_column_icon_vframe, 
3598                                         get_abs_cursor_x(0) - drag_column_icon_vframe->get_w() / 2,
3599                                         get_abs_cursor_y(0) - drag_column_icon_vframe->get_h() / 2);
3600                                 dragged_title = highlighted_title;
3601                                 current_operation = COLUMN_DRAG;
3602                                 draw_titles(1);
3603                                 return 1;
3604                         }
3605                         break;
3606         }
3608         return 0;
3611 int BC_ListBox::drag_motion_event()
3613 //printf("BC_ListBox::drag_motion_event 1 %d\n", current_operation);
3614         switch(current_operation)
3615         {
3616                 case DRAG_ITEM:
3617                 {
3618                         int redraw = 0;
3620                         int new_highlighted_item = -1;
3621                         BC_ListBoxItem *new_highlighted_ptr = 0;
3622                         int new_highlight = new_highlighted_item = get_cursor_item(data,
3623                                 top_level->cursor_x, 
3624                                 top_level->cursor_y,
3625                                 &new_highlighted_ptr);
3627                         if(new_highlighted_item != highlighted_item)
3628                         {
3629                                 redraw = 1;
3630                         }
3632 // Always update highlighted value for drag_stop
3633                         highlighted_item = new_highlighted_item;
3634                         highlighted_ptr = new_highlighted_ptr;
3635 //printf("BC_ListBox::drag_motion_event 1 %p\n", highlighted_ptr);
3636                         if(redraw)
3637                         {
3638                                 clamp_positions();
3639                                 draw_items(1);
3640                                 update_scrollbars();
3641                         }
3643                         return drag_popup->cursor_motion_event();
3644                         break;
3645                 }
3647                 case COLUMN_DRAG:
3648                 {
3649                         int old_highlighted_title = highlighted_title;
3650                         test_column_titles(get_cursor_x(), get_cursor_y());
3651                         if(old_highlighted_title != highlighted_title)
3652                         {
3653                                 draw_titles(1);
3654                         }
3655                         return drag_popup->cursor_motion_event();
3656                         break;
3657                 }
3658         }
3659         return 0;
3662 int BC_ListBox::drag_stop_event()
3664         switch(current_operation)
3665         {
3666                 case DRAG_ITEM:
3667 // Inside window boundary
3668                         if(top_level->cursor_x > 0 && 
3669                                 top_level->cursor_x < gui->get_w() - drag_popup->get_w() / 2 && 
3670                                 top_level->cursor_y > 0 &&
3671                                 top_level->cursor_y < gui->get_h() - drag_popup->get_h() / 2)
3672                         {
3673 // Move icon
3676                                 if(display_format == LISTBOX_ICONS)
3677                                 {
3678                                         reposition_item(data, 
3679                                                 selection_number, 
3680                                                 top_level->cursor_x + 
3681                                                         drag_popup->get_offset_x() - 
3682                                                         LISTBOX_MARGIN - 
3683                                                         2 + 
3684                                                         xposition,
3685                                                 top_level->cursor_y + 
3686                                                         drag_popup->get_offset_y() - 
3687                                                         LISTBOX_MARGIN - 
3688                                                         2 + 
3689                                                         yposition);
3690                                 }
3691                                 else
3692 // Move rows
3693                                 if(process_drag)
3694                                 {
3695 // Get destination
3696                                         int destination = highlighted_item = item_to_index(data,
3697                                                 highlighted_ptr);
3698 //printf("BC_ListBox::drag_stop_event 1 %p %d\n", highlighted_ptr, destination);
3700 // Move selected items from data to temporary
3701                                         ArrayList<BC_ListBoxItem*> *src_items = 
3702                                                 new ArrayList<BC_ListBoxItem*>[columns];
3704                                         move_selection(src_items, data);
3706 // Insert items from temporary to data
3707                                         put_selection(data,
3708                                                 src_items,
3709                                                 destination);
3712                                         delete [] src_items;                            
3713                                         set_autoplacement(data, 0, 1);
3714                                 }
3716                         
3717                                 draw_items(1);
3718                         }
3719                         else
3720                                 drag_popup->drag_failure_event();
3722                         delete drag_popup;
3723                         drag_popup = 0;
3724                         current_operation = NO_OPERATION;
3725                         new_value = 0;
3726                         return 1;
3727                         break;
3729                 case COLUMN_DRAG:
3730                         if(dragged_title != highlighted_title)
3731                         {
3732                                 if(highlighted_title >= 0)
3733                                 {
3734                                         if(!move_column_event()) draw_titles(1);
3735                                 }
3736                                 else
3737                                         drag_popup->drag_failure_event();
3738                         }
3739                         current_operation = NO_OPERATION;
3740                         delete drag_popup;
3741                         drag_popup = 0;
3742                         return 1;
3743                         break;
3744         }
3745         return 0;
3748 BC_DragWindow* BC_ListBox::get_drag_popup()
3750         return drag_popup;
3753 int BC_ListBox::translation_event()
3755         if(is_popup && gui)
3756         {
3757                 int new_x = gui->get_x() + 
3758                         (top_level->last_translate_x - 
3759                                 top_level->prev_x - 
3760                                 top_level->get_resources()->get_left_border());
3761                 int new_y = gui->get_y() + 
3762                         (top_level->last_translate_y - 
3763                                 top_level->prev_y -
3764                                 top_level->get_resources()->get_top_border());
3766                 gui->reposition_window(new_x, new_y);
3767                 
3768         }
3769         return 0;
3772 int BC_ListBox::reposition_window(int x, int y, int w, int h)
3774         if(w != -1)
3775         {
3776                 if(w != -1) popup_w = w;
3777                 if(h != -1) popup_h = h;
3778 //printf("BC_ListBox::reposition_window %d %d\n", popup_w, popup_h);
3780                 if(!is_popup)
3781                 {
3782                         if(w != -1) popup_w = w;
3783                         if(h != -1) popup_h = h;
3784                         if(xscrollbar)
3785                                 xscrollbar->reposition_window(get_xscroll_x(), 
3786                                         get_xscroll_y(), 
3787                                         get_xscroll_width());
3788                         if(yscrollbar)
3789                                 yscrollbar->reposition_window(get_yscroll_x(), 
3790                                         get_yscroll_y(), 
3791                                         get_yscroll_height());
3792                 }
3793         }
3796         BC_WindowBase::reposition_window(x, y, w, h);
3797         draw_button();
3798         draw_items(1);
3799         return 0;
3802 int BC_ListBox::deactivate()
3804         if(active)
3805         {
3806                 active = 0;
3807                 if(is_popup)
3808                 {
3809                         if(gui) delete gui;
3810                         xscrollbar = 0;
3811                         yscrollbar = 0;
3812                         gui = 0;
3813                         highlighted_item = -1;
3814                         highlighted_ptr = 0;
3815                 }
3816                 top_level->active_subwindow = 0;
3817         }
3818         return 0;
3821 int BC_ListBox::activate()
3823         if(!active)
3824         {
3825                 top_level->active_subwindow = this;
3826                 active = 1;
3827                 button_releases = 0;
3829                 if(is_popup)
3830                 {
3831                         Window tempwin;
3832                         int x, y;
3833                         int new_x, new_y;
3834                         y = get_y() + get_h();
3835                         if(justify == LISTBOX_RIGHT)
3836                         {
3837                                 x = get_x() - popup_w + get_w();
3838                         }
3839                         else
3840                         {
3841                                 x = get_x();
3842                         }
3844                         
3845                         XTranslateCoordinates(top_level->display, 
3846                                 parent_window->win, 
3847                                 top_level->rootwin, 
3848                                 x, 
3849                                 y, 
3850                                 &new_x, 
3851                                 &new_y, 
3852                                 &tempwin);
3854                         if(new_x < 0) new_x = 0;
3855                         if(new_y + popup_h > top_level->get_root_h(0)) 
3856                                 new_y -= get_h() + popup_h;
3858 //printf("BC_ListBox::activate %d %d\n", popup_w, popup_h);
3859                         add_subwindow(gui = new BC_Popup(this, 
3860                                 new_x, 
3861                                 new_y, 
3862                                 popup_w, 
3863                                 popup_h, 
3864                                 -1,
3865                                 0,
3866                                 0));
3867                         draw_items(1);
3868                 }
3869         }
3870         return 0;
3873 int BC_ListBox::keypress_event()
3875         if(!active) return 0;
3876         
3877         int result = 0, redraw = 0, done, view_items = view_h / get_text_height(MEDIUMFONT);
3878         int new_item = -1, new_selection = 0;
3880         switch(top_level->get_keypress())
3881         {
3882                 case ESC:
3883                 case RETURN:
3884                         top_level->deactivate();
3885                         result = 0;
3886                         break;
3888                 case UP:
3889                         new_selection = new_item = select_previous(0);
3891 //printf("BC_ListBox::keypress_event 1 %d\n", new_item);
3892                         if(new_item >= 0)
3893                         {
3894                                 center_selection(new_item);
3895                                 redraw = 1;
3896                         }
3897                         result = 1;
3898                         break;
3900                 case DOWN:
3901                         new_selection = new_item = select_next(0);
3903                         if(new_item >= 0)
3904                         {
3905                                 center_selection(new_item);
3906                                 redraw = 1;
3907                         }
3908                         result = 1;
3909                         break;
3911                 case PGUP:
3912                         new_selection = new_item = select_previous(view_items - 1);
3914                         if(new_item >= 0)
3915                         {
3916                                 center_selection(new_item);
3917                                 redraw = 1;
3918                         }
3919                         result = 1;
3920                         break;
3922                 case PGDN:
3923                         new_selection = new_item = select_next(view_items - 1);
3925                         if(new_item >= 0)
3926                         {
3927                                 center_selection(new_item);
3928                                 redraw = 1;
3929                         }
3930                         result = 1;
3931                         break;
3933                 case LEFT:
3934                         xposition -= 10;
3935                         redraw = 1;
3936                         result = 1;
3937                         break;
3939                 case RIGHT:
3940                         xposition += 10;
3941                         redraw = 1;
3942                         result = 1;
3943                         break;
3945                 default:
3946                         if(!ctrl_down())
3947                         {
3948                                 if(top_level->get_keypress() > 30 && 
3949                                         top_level->get_keypress() < 127)
3950                                 {
3951                                         int query_len = strlen(query);
3952                                         query[query_len++] = top_level->get_keypress();
3953                                         query[query_len] = 0;
3954                                         new_selection = query_list();
3955                                 }
3956                                 else
3957                                 if(top_level->get_keypress() == BACKSPACE)
3958                                 {
3959                                         int query_len = strlen(query);
3960                                         if(query_len > 0) query[--query_len] = 0;
3961                                         new_selection = query_list();
3962                                 }
3964                                 redraw = 1;
3965                                 result = 1;
3966                         }
3967                         break;
3968         }
3970         if(redraw)
3971         {
3972                 clamp_positions();
3973                 draw_items(1);
3974                 update_scrollbars();
3975         }
3976         
3977         if(new_selection >= 0)
3978         {
3979                 selection_changed();
3980         }
3982         return result;
3986 BC_Pixmap* BC_ListBox::get_bg_surface()
3988         return bg_surface;
3992 void BC_ListBox::draw_background()
3994 // White background pixmap
3995         set_color(top_level->get_resources()->listbox_inactive);
3996         draw_box(0, 0, bg_surface->get_w(), bg_surface->get_h(), bg_surface);
3998 // Optional heroine pixmap
3999         if(bg_pixmap)
4000                 bg_surface->draw_pixmap(bg_pixmap,
4001                         bg_surface->get_w() - top_level->get_resources()->listbox_bg->get_w(),
4002                         0);
4005 void BC_ListBox::clear_listbox(int x, int y, int w, int h)
4007         gui->draw_pixmap(bg_surface, 
4008                 x, 
4009                 y, 
4010                 w, 
4011                 h,
4012                 x,
4013                 y - title_h);
4016 void BC_ListBox::update_format(int display_format, int redraw)
4018         this->display_format = display_format;
4019         if(redraw)
4020         {
4021                 if(gui) draw_items(1);
4022         }
4025 int BC_ListBox::get_format()
4027         return display_format;
4032 int BC_ListBox::draw_items(int flash)
4034         if(gui)
4035         {
4036                 BC_Resources *resources = get_resources();
4038 //dump(data, columns);
4040 // Calculate items width 
4041                 calculate_item_coords();
4044 // Create and destroy scrollbars as needed
4045                 get_scrollbars();
4049 //              draw_background();
4051 // Icon display
4052                 if(display_format == LISTBOX_ICONS)
4053                 {
4054                         clear_listbox(2, 2 + title_h, view_w, view_h);
4056                         set_font(MEDIUMFONT);
4057                         for(int i = 0; i < data[master_column].total; i++)
4058                         {
4059                                 BC_ListBoxItem *item = data[master_column].values[i];
4060                                 if(get_item_x(item) >= -get_item_w(item) && 
4061                                         get_item_x(item) < view_w &&
4062                                         get_item_y(item) >= -get_item_h(item) + title_h &&
4063                                         get_item_y(item) < view_h + title_h)
4064                                 {
4065                                         int item_color = get_item_highlight(data, 0, i);
4066                                         int icon_x, icon_y, icon_w, icon_h;
4067                                         int text_x, text_y, text_w, text_h;
4069 // Draw highlights
4070                                         get_icon_mask(item, icon_x, icon_y, icon_w, icon_h);
4071                                         get_text_mask(item, text_x, text_y, text_w, text_h);
4074                                         if(item_color != resources->listbox_inactive)
4075                                         {
4076                                                 gui->set_color(BLACK);
4077                                                 gui->draw_rectangle(icon_x, icon_y, icon_w, icon_h);
4078                                                 gui->set_color(item_color);
4079                                                 gui->draw_box(icon_x + 1, icon_y + 1, icon_w - 2, icon_h - 2);
4080                                                 gui->set_color(BLACK);
4081                                                 gui->draw_rectangle(text_x, text_y, text_w, text_h);
4082                                                 gui->set_color(item_color);
4083                                                 gui->draw_box(text_x + 1, text_y + 1, text_w - 2, text_h - 2);
4085                                                 if(icon_position == ICON_LEFT)
4086                                                         gui->draw_box(text_x - 1, text_y + 1, 2, text_h - 2);
4087                                                 else
4088                                                 if(icon_position == ICON_TOP)
4089                                                         gui->draw_line(text_x + 1, text_y, text_x + icon_w - 2, text_y);
4090                                                 if(text_x + text_w < icon_x + icon_w)
4091                                                 {
4092                                                         gui->set_color(BLACK);
4093                                                         gui->draw_line(text_x + text_w, 
4094                                                                 icon_y + icon_h,
4095                                                                 icon_x + icon_w,
4096                                                                 icon_y + icon_h);
4097                                                 }
4098                                         }
4100 // Draw icons
4101                                         gui->set_color(get_item_color(data, 0, i));
4102                                         if(item->icon)
4103                                                 item->icon->write_drawable(gui->pixmap, 
4104                                                         icon_x + ICON_MARGIN, 
4105                                                         icon_y + ICON_MARGIN);
4106                                         gui->draw_text(text_x + ICON_MARGIN, 
4107                                                 text_y + ICON_MARGIN + get_text_ascent(MEDIUMFONT), 
4108                                                 item->text);
4109                                 }
4110                         }
4111                 }
4112                 else
4113 // Text display
4114                 if(display_format == LISTBOX_TEXT)
4115                 {
4116 // Draw one column at a time so text overruns don't go into the next column
4117 // clear column backgrounds
4118                         int current_toggle = 0;
4119                         for(int j = 0; j < columns; j++)
4120                         {
4121                                 clear_listbox(LISTBOX_BORDER + get_column_offset(j) - xposition, 
4122                                         LISTBOX_BORDER + title_h, 
4123                                         get_column_width(j, 1), 
4124                                         view_h);
4126 // Draw rows in the column recursively
4127                                 draw_text_recursive(data, j, 0, &current_toggle);
4128                         }
4130 // Delete excess expanders
4131                         while(expanders.total > current_toggle)
4132                         {
4133                                 expanders.remove_object();
4134                         }
4135                 }
4137 // Draw titles on top of rows for superposition effect
4138                 draw_titles(0);
4140 // Clear garbage from bottom right corner
4141                 if(xscrollbar && yscrollbar && is_popup)
4142                 {
4143                         gui->draw_top_background(parent_window, 
4144                                 popup_w - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w(), 
4145                                 popup_h - get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h(), 
4146                                 get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w(),
4147                                 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h());
4148                 }
4150 // Draw borders
4151                 draw_border(0);
4154                 if(current_operation == SELECT_RECT)
4155                         draw_rectangle(0);
4157                 if(flash)
4158                 {
4159                         gui->flash();
4160                         gui->flush();
4161                 }
4162         }
4164         return 0;
4168 void BC_ListBox::draw_text_recursive(ArrayList<BC_ListBoxItem*> *data, 
4169         int column,
4170         int indent,
4171         int *current_toggle)
4173         if(!data) return;
4176         BC_Resources *resources = get_resources();
4178         set_font(MEDIUMFONT);
4179         int subindent = 0;
4181 // Search for a branch and make room for toggle if there is one
4182         if(column == 0)
4183         {
4184                 for(int i = 0; i < data[column].total; i++)
4185                 {
4186                         if(data[column].values[i]->get_sublist())
4187                         {
4188                                 subindent = BC_WindowBase::get_resources()->listbox_expand[0]->get_w();
4189                                 break;
4190                         }
4191                 }
4192         }
4194         for(int i = 0; i < data[column].total; i++)
4195         {
4196 // Draw a row
4197                 BC_ListBoxItem *item = data[column].values[i];
4198                 BC_ListBoxItem *first_item = data[master_column].values[i];
4200                 if(get_item_y(item) >= -get_item_h(item) + title_h &&
4201                         get_item_y(item) < view_h + title_h)
4202                 {
4203                         int row_color = get_item_highlight(data, 0, i);
4204                         int x, y, w, h, column_width;
4206                         get_text_mask(item, x, y, w, h);
4207                         column_width = get_column_width(column, 1);
4208                         if(x + column_width > view_w + LISTBOX_BORDER * 2)
4209                                 column_width = view_w + LISTBOX_BORDER * 2 - x;
4211                         if(row_color != resources->listbox_inactive)
4212                         {
4213                                 gui->set_color(row_color);
4214                                 gui->draw_box(x, 
4215                                         y, 
4216                                         column_width, 
4217                                         h);
4218                                 gui->set_color(BLACK);
4219                                 gui->draw_line(x, 
4220                                         y, 
4221                                         x + column_width - 1, 
4222                                         y);
4223                                 gui->draw_line(x, 
4224                                         y + get_text_height(MEDIUMFONT), 
4225                                         x + column_width - 1, 
4226                                         y + get_text_height(MEDIUMFONT));
4227                         }
4229                         gui->set_color(get_item_color(data, column, i));
4232 // Indent only applies to first column
4233                         gui->draw_text(
4234                                 x + 
4235                                         LISTBOX_BORDER + 
4236                                         LISTBOX_MARGIN + 
4237                                         (column == 0 ? indent + subindent : 0), 
4238                                 y + get_text_ascent(MEDIUMFONT), 
4239                                 item->text);
4242 // Update expander
4243                         if(column == 0 &&
4244                                 item->get_sublist() && 
4245                                 item->get_columns())
4246                         {
4247 // Create new expander
4248                                 if(*current_toggle >= expanders.total)
4249                                 {
4250                                         BC_ListBoxToggle *toggle = 
4251                                                 new BC_ListBoxToggle(this, 
4252                                                         item, 
4253                                                         x + LISTBOX_BORDER + LISTBOX_MARGIN + indent,
4254                                                         y);
4255                                         toggle->draw(0);
4256                                         expanders.append(toggle);
4257                                 }
4258                                 else
4259 // Reposition existing expander
4260                                 {
4261                                         BC_ListBoxToggle *toggle = expanders.values[*current_toggle];
4262 //printf("BC_ListBox::draw_text_recursive 1 %d\n", *current_toggle);
4263                                         toggle->update(item, 
4264                                                 x + LISTBOX_BORDER + LISTBOX_MARGIN + indent,
4265                                                 y,
4266                                                 0);
4267                                 }
4268                                 (*current_toggle)++;
4269                         }
4273                 }
4275 // Descend into sublist
4276                 if(first_item->get_expand())
4277                 {
4278                         draw_text_recursive(first_item->get_sublist(), 
4279                                 column, 
4280                                 indent + LISTBOX_INDENT, 
4281                                 current_toggle);
4282                 }
4283         }
4290 int BC_ListBox::draw_border(int flash)
4292         BC_Resources *resources = top_level->get_resources();
4293         gui->draw_3d_border(0, 
4294                 0, 
4295                 view_w + LISTBOX_BORDER * 2, 
4296                 view_h + title_h + LISTBOX_BORDER * 2, 
4297                 resources->listbox_border1, 
4298                 list_highlighted ? 
4299                         resources->listbox_border2_hi : 
4300                         resources->listbox_border2, 
4301                 list_highlighted ? 
4302                         resources->listbox_border3_hi : 
4303                         resources->listbox_border3, 
4304                 resources->listbox_border4);
4306         if(flash)
4307         {
4308                 gui->flash();
4309                 gui->flush();
4310         }
4311         return 0;
4314 int BC_ListBox::draw_titles(int flash)
4316         if(column_titles && display_format == LISTBOX_TEXT)
4317         {
4318 //printf("BC_ListBox::draw_titles 1 %d\n", highlighted_title);
4319                 for(int i = 0; i < columns; i++)
4320                 {
4323 // Column title background
4324                         int image_number = 0;
4325                         if(i == highlighted_title)
4326                         {
4327                                 image_number = 1;
4328                                 if(current_operation == COLUMN_DN)
4329                                         image_number = 2;
4330                         }
4332                         int column_offset = get_column_offset(i) - xposition + LISTBOX_BORDER;
4333                         int column_width = get_column_width(i, 1);
4334                         gui->draw_3segmenth(get_column_offset(i) - xposition + LISTBOX_BORDER,
4335                                 LISTBOX_BORDER,
4336                                 get_column_width(i, 1),
4337                                 column_bg[image_number]);
4339 // Column title sort order
4340                         if(i == sort_column)
4341                         {
4342                                 BC_Pixmap *src;
4343                                 if(sort_order == SORT_ASCENDING) 
4344                                         src = column_sort_dn;
4345                                 else
4346                                         src = column_sort_up;
4348                                 int x = column_offset + 
4349                                         column_width - 
4350                                         LISTBOX_BORDER;
4351                                 if(x > items_w) x = items_w;
4352                                 x -= 5 + src->get_w();
4353                                 gui->draw_pixmap(src,
4354                                         x,
4355                                         title_h / 2 - src->get_h() / 2 + LISTBOX_BORDER);
4356                         }
4359                         int x = -xposition + 
4360                                 get_column_offset(i) + 
4361                                 LISTBOX_MARGIN + 
4362                                 LISTBOX_BORDER;
4363                         x += get_resources()->listbox_title_margin;
4365                         gui->set_color(get_resources()->listbox_title_color);
4366                         gui->draw_text(x, 
4367                                 LISTBOX_MARGIN + LISTBOX_BORDER + get_text_ascent(MEDIUMFONT), 
4368                                 _(column_titles[i]));
4369                 }
4370                 draw_border(0);
4371         }
4373         if(flash)
4374         {
4375                 gui->flash();
4376                 gui->flush();
4377         }
4380 void BC_ListBox::draw_toggles(int flash)
4382         for(int i = 0; i < expanders.total; i++)
4383                 expanders.values[i]->draw(0);
4385 //printf("BC_ListBox::draw_toggles 1 %d\n", flash);
4386         if(flash && expanders.total)
4387         {
4388                 gui->flash();
4389                 gui->flush();
4390         }
4393 int BC_ListBox::draw_rectangle(int flash)
4395         int x1 = MIN(rect_x1, rect_x2);
4396         int x2 = MAX(rect_x1, rect_x2);
4397         int y1 = MIN(rect_y1, rect_y2);
4398         int y2 = MAX(rect_y1, rect_y2);
4400         if(x1 == x2 || y1 == y2) return 0;
4402         gui->set_inverse();
4403         gui->set_color(WHITE);
4404         gui->draw_rectangle(x1, y1, x2 - x1, y2 - y1);
4405         gui->set_opaque();
4408         if(flash)
4409         {
4410                 gui->flash();
4411                 gui->flush();
4412         }
4413         return 0;
4416 void BC_ListBox::dump(ArrayList<BC_ListBoxItem*> *data, 
4417         int columns, 
4418         int indent,
4419         int master_column)
4421         if(!indent)
4422         {
4423                 printf("BC_ListBox::dump 1\n");
4424         }
4426         for(int i = 0; i < data[master_column].total; i++)
4427         {
4428                 for(int k = 0; k < indent; k++)
4429                         printf(" ");
4430                 for(int j = 0; j < columns; j++)
4431                 {
4432                         BC_ListBoxItem *item = data[j].values[i];
4433                         printf("%d,%d,%d=%s ", 
4434                                 item->get_text_x(), 
4435                                 item->get_text_y(),
4436                                 item->autoplace_text, 
4437                                 item->get_text());
4438                 }
4439                 printf("\n");
4441                 if(data[master_column].values[i]->get_sublist())
4442                 {
4443                         dump(data[master_column].values[i]->get_sublist(),
4444                                 data[master_column].values[i]->get_columns(),
4445                                 indent + 4,
4446                                 master_column);
4447                 }
4448         }
4450