3 * Copyright (C) 2010-2014 Adam Williams <broadcast at earthling dot net>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "bcdisplayinfo.h"
22 #include "bcdragwindow.h"
23 #include "bclistbox.h"
24 #include "bclistboxitem.h"
26 #include "bcresources.h"
27 #include "bcsignals.h"
39 // ====================================================== scrollbars
41 BC_ListBoxYScroll::BC_ListBoxYScroll(BC_ListBox *listbox)
42 : BC_ScrollBar(listbox->get_yscroll_x(), listbox->get_yscroll_y(),
43 listbox->yscroll_orientation, listbox->get_yscroll_height(),
44 listbox->items_h, listbox->yposition, listbox->view_h)
46 this->listbox = listbox;
49 BC_ListBoxYScroll::~BC_ListBoxYScroll()
53 int BC_ListBoxYScroll::handle_event()
55 listbox->set_yposition(get_value());
59 BC_ListBoxXScroll::BC_ListBoxXScroll(BC_ListBox *listbox)
60 : BC_ScrollBar(listbox->get_xscroll_x(), listbox->get_xscroll_y(),
61 listbox->xscroll_orientation, listbox->get_xscroll_width(),
62 listbox->items_w, listbox->xposition, listbox->view_w)
64 this->listbox = listbox;
67 BC_ListBoxXScroll::~BC_ListBoxXScroll()
71 int BC_ListBoxXScroll::handle_event()
73 listbox->set_xposition(get_value());
78 BC_ListBoxToggle::BC_ListBoxToggle(BC_ListBox *listbox,
83 this->listbox = listbox;
87 this->value = item->get_expand();
89 state = BC_Toggle::TOGGLE_CHECKED;
91 state = BC_Toggle::TOGGLE_UP;
94 void BC_ListBoxToggle::update(BC_ListBoxItem *item,
99 this->value = item->get_expand();
109 state = TOGGLE_CHECKED;
114 state = TOGGLE_CHECKEDHI;
125 case TOGGLE_CHECKEDHI:
130 case TOGGLE_DOWN_EXIT:
138 int BC_ListBoxToggle::cursor_motion_event(int *redraw_toggles)
140 int w = listbox->toggle_images[0]->get_w();
141 int h = listbox->toggle_images[0]->get_h();
142 int cursor_inside = listbox->get_cursor_x() >= x &&
143 listbox->get_cursor_x() < x + w &&
144 listbox->get_cursor_y() >= y &&
145 listbox->get_cursor_y() < y + h;
150 case BC_ListBoxToggle::TOGGLE_UPHI:
153 state = BC_ListBoxToggle::TOGGLE_UP;
158 case BC_ListBoxToggle::TOGGLE_CHECKEDHI:
161 state = BC_ListBoxToggle::TOGGLE_CHECKED;
166 case BC_ListBoxToggle::TOGGLE_DOWN:
169 state = BC_ListBoxToggle::TOGGLE_DOWN_EXIT;
175 case BC_ListBoxToggle::TOGGLE_DOWN_EXIT:
178 state = BC_ListBoxToggle::TOGGLE_DOWN;
188 state = BC_ListBoxToggle::TOGGLE_CHECKEDHI;
190 state = BC_ListBoxToggle::TOGGLE_UPHI;
198 int BC_ListBoxToggle::cursor_leave_event(int *redraw_toggles)
201 state = BC_ListBoxToggle::TOGGLE_CHECKED;
203 state = BC_ListBoxToggle::TOGGLE_UP;
207 int BC_ListBoxToggle::button_press_event()
209 int w = listbox->toggle_images[0]->get_w();
210 int h = listbox->toggle_images[0]->get_h();
212 if(listbox->gui->get_cursor_x() >= x &&
213 listbox->gui->get_cursor_x() < x + w &&
214 listbox->gui->get_cursor_y() >= y &&
215 listbox->gui->get_cursor_y() < y + h)
217 state = BC_ListBoxToggle::TOGGLE_DOWN;
223 int BC_ListBoxToggle::button_release_event(int *redraw_toggles)
229 case BC_ListBoxToggle::TOGGLE_DOWN:
232 state = BC_ListBoxToggle::TOGGLE_CHECKEDHI;
234 state = BC_ListBoxToggle::TOGGLE_UPHI;
235 listbox->expand_item(item, value);
239 case BC_ListBoxToggle::TOGGLE_DOWN_EXIT:
241 state = BC_ListBoxToggle::TOGGLE_CHECKED;
243 state = BC_ListBoxToggle::TOGGLE_UP;
251 void BC_ListBoxToggle::draw(int flash)
255 int image_number = 0;
256 int w = listbox->toggle_images[0]->get_w();
257 int h = listbox->toggle_images[0]->get_h();
261 case BC_ListBoxToggle::TOGGLE_UP: image_number = 0; break;
262 case BC_ListBoxToggle::TOGGLE_UPHI: image_number = 1; break;
263 case BC_ListBoxToggle::TOGGLE_CHECKED: image_number = 2; break;
264 case BC_ListBoxToggle::TOGGLE_DOWN: image_number = 3; break;
265 case BC_ListBoxToggle::TOGGLE_CHECKEDHI: image_number = 4; break;
266 case BC_ListBoxToggle::TOGGLE_DOWN_EXIT:
274 //printf("BC_ListBoxToggle::draw 1 %d\n", state);
275 listbox->gui->draw_pixmap(listbox->toggle_images[image_number],
282 listbox->gui->flash(x, y, w, h);
283 listbox->gui->flush();
301 // ====================================================== box
303 BC_ListBox::BC_ListBox(int x,
308 ArrayList<BC_ListBoxItem*> *data,
309 const char **column_titles,
317 : BC_SubWindow(x, y, w, h, -1)
319 justify = LISTBOX_RIGHT;
321 highlighted_item = -1;
322 highlighted_title = -1;
323 highlighted_division = -1;
327 current_cursor = ARROW_CURSOR;
337 xscroll_orientation = SCROLL_HORIZ;
338 yscroll_orientation = SCROLL_VERT;
342 selection_number1 = -1;
343 selection_number2 = -1;
346 row_height = row_ascent = row_descent = 0;
349 current_operation = NO_OPERATION;
350 button_highlighted = 0;
351 list_highlighted = 0;
354 allow_drag_scroll = 1;
360 allow_drag_column = 0;
367 for(int i = 0; i < 3; i++) column_bg[i] = 0;
368 for(int i = 0; i < 4; i++) button_images[i] = 0;
369 for(int i = 0; i < 5; i++) toggle_images[i] = 0;
374 //printf("BC_ListBox::BC_ListBox 1\n");
376 this->columns = columns;
377 this->yposition = yposition;
378 this->is_popup = is_popup;
379 this->use_button = 1;
380 this->display_format = display_format;
381 this->selection_mode = selection_mode;
382 this->icon_position = icon_position;
383 this->allow_drag = allow_drag;
384 this->column_titles = 0;
385 this->column_width = 0;
386 this->first_in_view = -1;
387 this->last_in_view = 0;
388 //printf("BC_ListBox::BC_ListBox 1\n");
390 if((!column_titles && column_width) ||
391 (column_titles && !column_width))
393 printf("BC_ListBox::BC_ListBox either column_titles or column_widths == NULL but not both.\n");
395 //printf("BC_ListBox::BC_ListBox 2 %p %p\n", column_titles, column_width);
397 set_columns(column_titles,
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");
412 //printf("BC_ListBox::BC_ListBox 5\n");
415 BC_ListBox::~BC_ListBox()
417 expanders.remove_all_objects();
418 if(bg_surface) delete bg_surface;
419 if(bg_pixmap) delete bg_pixmap;
420 if(xscrollbar) delete xscrollbar;
421 if(yscrollbar) delete yscrollbar;
422 for(int i = 0; i < 3; i++) delete column_bg[i];
423 for(int i = 0; i < 4; i++) delete button_images[i];
424 for(int i = 0; i < 5; i++) delete toggle_images[i];
425 if(column_sort_up) delete column_sort_up;
426 if(column_sort_dn) delete column_sort_dn;
429 if(drag_popup) delete drag_popup;
432 int BC_ListBox::enable()
439 int BC_ListBox::disable()
446 void BC_ListBox::reset_query()
448 query[0] = 0; // reset query
451 int BC_ListBox::evaluate_query(char *string)
453 for(int i = 0; i < data[search_column].size(); i++)
455 if(strcmp(string, data[search_column].get(i)->text) <= 0 &&
456 data[search_column].get(i)->searchable)
465 int BC_ListBox::query_list()
467 if(query[0] == 0) return 0;
471 int selection_changed = 0;
472 int prev_selection = -1;
473 result = evaluate_query(query);
474 if(result >= 0) done = 1;
479 for(int i = 0; i < data[0].total; i++)
481 for(int j = 0; j < columns; j++)
483 if(data[j].values[i]->selected) prev_selection = i;
484 data[j].values[i]->selected = 0;
489 if(prev_selection != result)
490 selection_changed = 1;
491 for(int j = 0; j < columns; j++)
493 data[j].values[result]->selected = 1;
495 center_selection(result);
498 return selection_changed;
501 void BC_ListBox::init_column_width()
503 if(!column_width && data)
506 for(int i = 0; i < data[0].total; i++)
508 wd = get_text_w(data[0].values[i]);
509 if( wd > widest ) widest = wd;
511 default_column_width[0] = widest + 2 * LISTBOX_MARGIN;
515 int BC_ListBox::initialize()
521 for( int i = 0; i < 4; ++i )
523 button_images[i] = new BC_Pixmap(parent_window,
524 BC_WindowBase::get_resources()->listbox_button[i],
527 w = button_images[0]->get_w();
528 h = button_images[0]->get_h();
532 current_operation = NO_OPERATION;
538 current_operation = NO_OPERATION;
541 for(int i = 0; i < 3; i++)
543 column_bg[i] = new BC_Pixmap(parent_window,
544 get_resources()->listbox_column[i],
547 for(int i = 0; i < 5; i++)
549 toggle_images[i] = new BC_Pixmap(parent_window,
550 get_resources()->listbox_expand[i],
554 column_sort_up = new BC_Pixmap(parent_window,
555 BC_WindowBase::get_resources()->listbox_up,
557 column_sort_dn = new BC_Pixmap(parent_window,
558 BC_WindowBase::get_resources()->listbox_dn,
561 //printf("BC_ListBox::initialize 10\n");
562 drag_icon_vframe = get_resources()->type_to_icon[ICON_UNKNOWN];
563 drag_column_icon_vframe = get_resources()->type_to_icon[ICON_COLUMN];
564 // = new BC_Pixmap(parent_window,
565 // get_resources()->type_to_icon[ICON_UNKNOWN],
567 // drag_column_icon = new BC_Pixmap(parent_window,
568 // get_resources()->type_to_icon[ICON_COLUMN],
570 BC_SubWindow::initialize();
574 if(top_level->get_resources()->listbox_bg)
575 bg_pixmap = new BC_Pixmap(this,
576 get_resources()->listbox_bg,
582 if(!use_button && is_popup)
591 void BC_ListBox::deactivate_selection()
593 current_operation = NO_OPERATION;
596 int BC_ListBox::draw_button(int flush)
598 // Draw the button for a popup listbox
599 if(use_button && is_popup)
601 int image_number = 0;
603 draw_top_background(parent_window, 0, 0, w, h);
605 if(button_highlighted)
607 if(current_operation == BUTTON_DN)
613 pixmap->draw_pixmap(button_images[image_number],
625 int BC_ListBox::calculate_item_coords()
633 // Change the display_format to get the right item dimensions for both
635 temp_display_format = display_format;
638 // Scan the first column for lowest y coord of all text
639 // and lowest right x and y coord for all icons which aren't auto placable
640 calculate_last_coords_recursive(data,
647 // Reset last column width. It's recalculated based on text width.
649 calculate_item_coords_recursive(data,
658 display_format = temp_display_format;
663 void BC_ListBox::calculate_last_coords_recursive(
664 ArrayList<BC_ListBoxItem*> *data,
671 for(int i = 0; i < data[0].size(); i++)
673 int current_text_y = 0;
674 int current_icon_x = 0;
675 int current_icon_y = 0;
676 BC_ListBoxItem *item = data[0].get(i);
679 if(!item->autoplace_text)
681 // Lowest text coordinate
682 display_format = LISTBOX_TEXT;
683 current_text_y = item->text_y + get_text_h(item);
684 if(current_text_y > *next_text_y)
685 *next_text_y = current_text_y;
687 // Add sublist depth if it is expanded
688 if(item->get_sublist() &&
689 item->get_columns() &&
692 calculate_last_coords_recursive(item->get_sublist(),
701 // Get next_icon coordinate
704 BC_ListBoxItem *item = data[master_column].get(i);
705 if(!item->autoplace_icon)
707 display_format = LISTBOX_ICONS;
708 // Lowest right icon coordinate.
709 current_icon_x = item->icon_x;
710 if(current_icon_x > *icon_x) *icon_x = current_icon_x;
711 if(current_icon_x + get_item_w(item) > *next_icon_x) {
712 *next_icon_x = current_icon_x + get_item_w(item);
715 current_icon_y = item->icon_y + get_item_h(item);
716 if(current_icon_y > *next_icon_y)
717 *next_icon_y = current_icon_y;
724 void BC_ListBox::calculate_item_coords_recursive(
725 ArrayList<BC_ListBoxItem*> *data,
732 // get maximum height of an icon
733 row_height = get_text_height(MEDIUMFONT);
734 if(temp_display_format == LISTBOX_ICON_LIST)
736 for(int i = 0; i < data[0].size(); i++)
738 if(data[0].get(i)->icon)
740 if(data[0].get(i)->icon->get_h() > row_height)
741 row_height = data[0].get(i)->icon->get_h();
747 // Set up items which need autoplacement.
748 // Should fill icons down and then across
749 for(int i = 0; i < data[0].size(); i++)
751 // Don't increase y unless the row requires autoplacing.
752 int total_autoplaced_columns = 0;
754 // Set up icons in first column
757 BC_ListBoxItem *item = data[master_column].get(i);
758 if(item->autoplace_icon)
760 // 1 column only if icons are used
761 display_format = LISTBOX_ICONS;
764 if(*next_icon_y + get_item_h(item) >= get_h() &&
767 *icon_x = *next_icon_x;
771 if(*icon_x + get_item_w(item) > *next_icon_x)
772 *next_icon_x = *icon_x + get_item_w(item);
775 item->set_icon_x(*icon_x);
776 item->set_icon_y(*next_icon_y);
778 *next_icon_y += get_item_h(item);
786 row_ascent = row_descent = 0;
787 // row_height still holds icon max height
788 for(int j = 0; j < columns; j++)
790 BC_ListBoxItem *item = data[j].get(i);
791 if(item->autoplace_text)
793 display_format = LISTBOX_TEXT;
794 item->set_text_x(next_text_x);
795 item->set_text_y(*next_text_y);
796 int ht = get_text_h(item);
797 if( ht > row_height ) row_height = ht;
798 int bl = get_baseline(item);
799 if( bl > row_ascent ) row_ascent = bl;
801 if( dt > row_descent ) row_ascent = bl;
803 // printf("BC_ListBox::calculate_item_coords_recursive %p %d %d %d %d %s \n",
804 // item->get_sublist(),
805 // item->get_columns(),
806 // item->get_expand(),
809 // item->get_text());
810 // Increment position of next column
813 next_text_x += (column_width ?
815 default_column_width[j]);
818 // Set last column width based on text width
820 int new_w = get_item_w(item);
822 int *previous_w = (column_width ?
824 &default_column_width[j]);
825 if(new_w > *previous_w)
827 //printf("BC_ListBox::calculate_item_coords_recursive 1 %d\n", new_w);
829 total_autoplaced_columns++;
833 // Increase the text vertical position
834 if(total_autoplaced_columns)
836 display_format = LISTBOX_TEXT;
837 *next_text_y += row_height;
841 BC_ListBoxItem *item = data[master_column].values[i];
842 if(item->get_sublist() &&
843 item->get_columns() &&
846 calculate_item_coords_recursive(
857 void BC_ListBox::set_is_suggestions(int value)
859 this->is_suggestions = value;
862 void BC_ListBox::set_use_button(int value)
864 this->use_button = value;
867 void BC_ListBox::set_justify(int value)
869 this->justify = value;
872 void BC_ListBox::set_allow_drag_column(int value)
874 this->allow_drag_column = value;
877 void BC_ListBox::set_process_drag(int value)
879 this->process_drag = value;
882 void BC_ListBox::set_master_column(int value, int redraw)
884 this->master_column = value;
891 void BC_ListBox::set_search_column(int value)
893 this->search_column = value;
896 int BC_ListBox::get_sort_column()
901 void BC_ListBox::set_sort_column(int value, int redraw)
910 int BC_ListBox::get_sort_order()
915 void BC_ListBox::set_sort_order(int value, int redraw)
928 int BC_ListBox::get_display_mode()
930 return display_format;
933 int BC_ListBox::get_yposition()
938 int BC_ListBox::get_xposition()
943 int BC_ListBox::get_highlighted_item()
945 return highlighted_item;
949 int BC_ListBox::get_item_x(BC_ListBoxItem *item)
951 if(display_format == LISTBOX_TEXT)
953 return item->text_x - xposition + 2;
956 if(display_format == LISTBOX_ICON_LIST)
958 return item->text_x - xposition + 2;
962 return item->icon_x - xposition + 2;
966 int BC_ListBox::get_item_y(BC_ListBoxItem *item)
969 if(display_format == LISTBOX_TEXT)
971 result = item->text_y - yposition + title_h + 2;
974 if(display_format == LISTBOX_ICON_LIST)
976 result = item->text_y - yposition + title_h + 2;
980 result = item->icon_y - yposition + title_h + 2;
986 int BC_ListBox::get_item_w(BC_ListBoxItem *item)
988 if(display_format == LISTBOX_ICONS)
991 get_icon_mask(item, x, y, w, h);
993 get_text_mask(item, x, y, w, h);
996 return icon_position == ICON_LEFT ? icon_w + text_w :
997 icon_w > text_w ? icon_w : text_w;
999 return get_text_w(item) + 2 * LISTBOX_MARGIN;
1002 int BC_ListBox::get_item_h(BC_ListBoxItem *item)
1004 if(display_format == LISTBOX_ICONS)
1007 get_icon_mask(item, x, y, w, h);
1009 get_text_mask(item, x, y, w, h);
1012 return icon_position != ICON_LEFT ? icon_h + text_h :
1013 icon_h > text_h ? icon_h : text_h;
1015 return get_text_h(item);
1019 int BC_ListBox::get_icon_w(BC_ListBoxItem *item)
1021 return item->get_icon_w();
1024 int BC_ListBox::get_icon_h(BC_ListBoxItem *item)
1026 return item->get_icon_h();
1029 int BC_ListBox::get_text_w(BC_ListBoxItem *item)
1031 int w = item->get_text_w();
1032 if( w < 0 ) item->set_text_w(w = get_text_width(MEDIUMFONT, item->get_text()));
1036 int BC_ListBox::get_text_h(BC_ListBoxItem *item)
1038 int h = item->get_text_h();
1039 if( h < 0 ) item->set_text_h(h = get_text_height(MEDIUMFONT, item->get_text()));
1043 int BC_ListBox::get_baseline(BC_ListBoxItem *item)
1045 int b = item->get_baseline();
1046 if( b < 0 ) item->set_baseline(b = get_text_ascent(MEDIUMFONT));
1050 int BC_ListBox::get_items_width()
1054 if(display_format == LISTBOX_ICONS)
1056 for(int i = 0; i < columns; i++)
1058 for(int j = 0; j < data[i].total; j++)
1061 BC_ListBoxItem *item = data[i].values[j];
1064 get_icon_mask(item, x, y, w, h);
1065 if(x1 + w > widest) widest = x1 + w;
1067 if(display_format == LISTBOX_ICONS && icon_position == ICON_LEFT)
1070 get_text_mask(item, x, y, w, h);
1071 if(x1 + w > widest) widest = x1 + w;
1076 if(display_format == LISTBOX_TEXT)
1078 return get_column_offset(columns);
1082 return get_column_offset(columns);
1087 int BC_ListBox::get_items_height(ArrayList<BC_ListBoxItem*> *data,
1104 for(int j = 0; j < (data ? data[master_column].total : 0); j++)
1107 BC_ListBoxItem *item = data[master_column].values[j];
1109 if( display_format == LISTBOX_ICONS ||
1110 display_format == LISTBOX_ICON_LIST ) {
1111 get_icon_mask(item, x, y, w, h);
1112 if(y + h + yposition > highest) highest = y + h + yposition;
1114 get_text_mask(item, x, y, w, h);
1115 if(y + h + yposition > highest) highest = y + h + yposition;
1119 get_text_mask(item, x, y, w, h);
1121 // Descend into sublist
1122 if(item->get_sublist() &&
1125 get_items_height(item->get_sublist(),
1126 item->get_columns(),
1132 if( display_format == LISTBOX_TEXT && top_level )
1134 highest = LISTBOX_MARGIN + *result;
1141 int BC_ListBox::set_yposition(int position, int draw_items)
1143 this->yposition = position;
1146 this->draw_items(1);
1151 int BC_ListBox::set_xposition(int position)
1153 this->xposition = position;
1158 void BC_ListBox::expand_item(BC_ListBoxItem *item, int expand)
1162 item->expand = expand;
1163 // Collapse sublists if this is collapsed to make it easier to calculate
1165 if(item->get_sublist())
1166 collapse_recursive(item->get_sublist(), master_column);
1169 // Set everything for autoplacement
1171 set_autoplacement(data, 0, 1);
1177 void BC_ListBox::collapse_recursive(ArrayList<BC_ListBoxItem*> *data,
1180 for(int i = 0; i < data[master_column].total; i++)
1182 BC_ListBoxItem *item = data[master_column].values[i];
1183 if(item->get_sublist() && item->expand)
1186 collapse_recursive(item->get_sublist(), master_column);
1191 void BC_ListBox::set_autoplacement(ArrayList<BC_ListBoxItem*> *data,
1195 for(int i = 0; i < data[0].total; i++)
1197 for(int j = 0; j < columns; j++)
1199 if(do_icons) data[j].values[i]->autoplace_icon = 1;
1200 if(do_text) data[j].values[i]->autoplace_text = 1;
1203 BC_ListBoxItem *item = data[master_column].values[i];
1204 if(item->get_sublist())
1206 set_autoplacement(item->get_sublist(), do_icons, do_text);
1212 void BC_ListBox::set_scroll_stretch(int xv, int yv)
1214 if( xv >= 0 ) xscroll_orientation =
1215 !xv ? SCROLL_HORIZ : SCROLL_HORIZ + SCROLL_STRETCH;
1216 if( yv >= 0 ) yscroll_orientation =
1217 !yv ? SCROLL_VERT : SCROLL_VERT + SCROLL_STRETCH;
1220 int BC_ListBox::get_yscroll_x()
1223 return popup_w - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w();
1227 get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w();
1230 int BC_ListBox::get_yscroll_y()
1238 int BC_ListBox::get_yscroll_height()
1240 return popup_h - (need_xscroll ?
1241 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h() :
1245 int BC_ListBox::get_xscroll_x()
1253 int BC_ListBox::get_xscroll_y()
1257 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h();
1261 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h();
1264 int BC_ListBox::get_xscroll_width()
1266 return popup_w - (need_yscroll ?
1267 get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w() :
1271 int BC_ListBox::get_column_offset(int column)
1277 column_width[--column] :
1278 default_column_width[--column];
1283 void BC_ListBox::column_width_boundaries()
1286 for(int i = 0; i < columns; i++) {
1287 if(column_width[i] < MIN_COLUMN_WIDTH)
1288 column_width[i] = MIN_COLUMN_WIDTH;
1292 for(int i = 0; i < columns; i++) {
1293 if(default_column_width[i] < MIN_COLUMN_WIDTH)
1294 default_column_width[i] = MIN_COLUMN_WIDTH;
1299 int BC_ListBox::get_column_width(int column, int clamp_right)
1301 if(column < columns - 1 || !clamp_right)
1302 return column_width ? column_width[column] : default_column_width[column];
1303 return popup_w + xposition - get_column_offset(column);
1306 int BC_ListBox::get_icon_mask(BC_ListBoxItem *item,
1307 int &x, int &y, int &w, int &h)
1309 if( display_format == LISTBOX_ICONS ) {
1310 x = get_item_x(item);
1311 y = get_item_y(item);
1312 w = get_icon_w(item) + ICON_MARGIN * 2;
1313 h = get_icon_h(item) + ICON_MARGIN * 2;
1320 int BC_ListBox::get_text_mask(BC_ListBoxItem *item,
1321 int &x, int &y, int &w, int &h)
1323 x = get_item_x(item);
1324 y = get_item_y(item);
1326 if(display_format == LISTBOX_ICONS) {
1327 if(icon_position == ICON_LEFT) {
1328 x += get_icon_w(item) + ICON_MARGIN * 2;
1329 y += get_icon_h(item) - get_text_h(item);
1332 y += get_icon_h(item) + ICON_MARGIN;
1335 w = get_text_w(item) + ICON_MARGIN * 2;
1336 h = get_text_h(item) + ICON_MARGIN * 2;
1339 if(display_format == LISTBOX_TEXT) {
1340 w = get_text_w(item) + LISTBOX_MARGIN * 2;
1341 h = get_text_h(item);
1345 w = get_text_width(MEDIUMFONT, item->text) + LISTBOX_MARGIN * 2;
1347 int ih = get_icon_h(item);
1348 if( h < ih ) h = ih;
1353 int BC_ListBox::get_item_highlight(ArrayList<BC_ListBoxItem*> *data,
1357 BC_Resources *resources = get_resources();
1358 if(data[column].values[item]->selected)
1359 return resources->listbox_selected;
1360 else if(highlighted_item >= 0 &&
1361 highlighted_ptr == data[master_column].values[item])
1362 return resources->listbox_highlighted;
1363 return resources->listbox_inactive;
1366 int BC_ListBox::get_item_color(ArrayList<BC_ListBoxItem*> *data,
1370 int color = data[column].values[item]->color;
1371 if( color == -1 ) color = get_resources()->listbox_text;
1372 if( get_item_highlight(data, column, item) == color )
1377 int BC_ListBox::get_from_column()
1379 return dragged_title;
1382 int BC_ListBox::get_to_column()
1384 return highlighted_title;
1388 BC_ListBoxItem* BC_ListBox::get_selection(int column,
1389 int selection_number)
1391 return get_selection_recursive(data,
1396 BC_ListBoxItem* BC_ListBox::get_selection_recursive(
1397 ArrayList<BC_ListBoxItem*> *data,
1399 int selection_number)
1403 for(int i = 0; i < data[master_column].total; i++)
1405 BC_ListBoxItem *item = data[master_column].values[i];
1408 //printf("BC_ListBox::get_selection_recursive %d\n", __LINE__);
1410 if(selection_number < 0)
1413 return data[column].values[i];
1417 if(item->get_sublist())
1419 BC_ListBoxItem *result = get_selection_recursive(item->get_sublist(),
1422 if(result) return result;
1430 int BC_ListBox::get_selection_number(int column,
1431 int selection_number)
1433 return get_selection_number_recursive(data,
1438 int BC_ListBox::get_selection_number_recursive(
1439 ArrayList<BC_ListBoxItem*> *data,
1441 int selection_number,
1446 if(!counter) counter = &temp;
1448 for(int i = 0; i < data[master_column].total; i++)
1451 BC_ListBoxItem *item = data[master_column].values[i];
1455 if(selection_number < 0)
1460 if(item->get_sublist())
1462 int result = get_selection_number_recursive(
1463 item->get_sublist(),
1467 if(result >= 0) return result;
1474 int BC_ListBox::set_selection_mode(int mode)
1476 this->selection_mode = mode;
1480 void BC_ListBox::delete_columns()
1484 for(int i = 0; i < columns; i++)
1486 delete [] column_titles[i];
1488 delete [] column_titles;
1491 if(column_width) delete [] column_width;
1497 // Need to copy titles so EDL can change
1498 void BC_ListBox::set_columns(const char **column_titles,
1502 if((!column_titles && column_width) ||
1503 (column_titles && !column_width))
1505 printf("BC_ListBox::set_columns either column_titles or column_width == NULL but not both.\n");
1514 this->column_titles = new char*[columns];
1515 for(int i = 0; i < columns; i++)
1517 this->column_titles[i] = new char[strlen(column_titles[i]) + 1];
1518 strcpy(this->column_titles[i], column_titles[i]);
1524 this->column_width = new int[columns];
1525 for(int i = 0; i < columns; i++)
1527 this->column_width[i] = column_width[i];
1531 this->columns = columns;
1536 int BC_ListBox::update(ArrayList<BC_ListBoxItem*> *data,
1537 const char **column_titles,
1542 int highlighted_number,
1543 int recalc_positions,
1546 set_columns(column_titles,
1552 this->yposition = yposition;
1553 this->xposition = xposition;
1554 this->highlighted_item = highlighted_number;
1555 this->highlighted_ptr = index_to_item(data, highlighted_number, 0);
1557 if(recalc_positions)
1558 set_autoplacement(data, 1, 1);
1560 init_column_width();
1565 update_scrollbars(1);
1571 void BC_ListBox::center_selection()
1573 int selection = get_selection_number(0, 0);
1575 calculate_item_coords();
1576 center_selection(selection);
1582 update_scrollbars(0);
1583 gui->show_window(1);
1587 void BC_ListBox::move_vertical(int pixels)
1591 void BC_ListBox::move_horizontal(int pixels)
1595 int BC_ListBox::select_previous(int skip,
1596 BC_ListBoxItem *selected_item,
1598 ArrayList<BC_ListBoxItem*> *data,
1604 selected_item = get_selection(0, 0);
1616 got_second = &temp3;
1620 // Scan backwards to item pointer. Then count visible items to get
1621 // destination. No wraparound.
1624 for(int i = data[master_column].total - 1; i >= 0; i--)
1626 BC_ListBoxItem *current_item = data[master_column].values[i];
1627 if(current_item->get_sublist() &&
1628 current_item->get_expand())
1630 int result = select_previous(skip,
1633 current_item->get_sublist(),
1645 if((*counter) >= skip)
1647 for(int j = 0; j < columns; j++)
1648 data[j].values[i]->selected = 1;
1650 return item_to_index(this->data, current_item);
1655 if(current_item->selected)
1657 for(int j = 0; j < columns; j++)
1658 data[j].values[i]->selected = 0;
1665 // Hit top of top level without finding a selected item.
1668 // Select first item in top level and quit
1669 BC_ListBoxItem *current_item;
1671 current_item = data[master_column].values[0];
1673 for(int j = 0; j < columns; j++)
1674 data[j].values[0]->selected = 1;
1676 return item_to_index(this->data, current_item);
1678 }while(top_level && data[master_column].total);
1682 int BC_ListBox::select_next(int skip,
1683 BC_ListBoxItem *selected_item,
1685 ArrayList<BC_ListBoxItem*> *data,
1691 selected_item = get_selection(0, 0);
1703 got_second = &temp3;
1707 // Scan forwards to currently selected item pointer.
1708 // Then count visible items to get destination. No wraparound.
1711 for(int i = 0; i < data[master_column].total; i++)
1713 BC_ListBoxItem *current_item = data[master_column].values[i];
1715 // Select next item once the number items after the currently selected item
1716 // have been passed.
1720 if((*counter) >= skip)
1722 for(int j = 0; j < columns; j++)
1723 data[j].values[i]->selected = 1;
1725 return item_to_index(this->data, current_item);
1730 // Got currently selected item. Deselect it.
1731 if(current_item->selected)
1733 for(int j = 0; j < columns; j++)
1734 data[j].values[i]->selected = 0;
1740 // Descend into expanded level
1741 if(current_item->get_sublist() &&
1742 current_item->get_expand())
1744 int result = select_next(skip,
1747 current_item->get_sublist(),
1757 // Hit bottom of top level without finding the next item.
1760 BC_ListBoxItem *current_item;
1761 // Select first item in top level and quit
1765 current_item = data[master_column].values[0];
1767 for(int j = 0; j < columns; j++)
1768 data[j].values[0]->selected = 1;
1773 // Select last item in top level and quit
1775 int current_row = data[master_column].total - 1;
1776 current_item = data[master_column].values[current_row];
1778 for(int j = 0; j < columns; j++)
1779 data[j].values[current_row]->selected = 1;
1783 return item_to_index(this->data, current_item);
1785 }while(top_level && data[master_column].total);
1791 void BC_ListBox::clamp_positions()
1793 items_w = get_items_width();
1794 if( xscroll_orientation & SCROLL_STRETCH )
1795 items_w += view_w / 4;
1796 items_h = get_items_height(data, columns);
1797 if( yscroll_orientation & SCROLL_STRETCH )
1798 items_h += view_h / 4;
1800 if(yposition < 0) yposition = 0;
1802 if(yposition > items_h - view_h)
1803 yposition = items_h - view_h;
1805 if(yposition < 0) yposition = 0;
1807 if(xposition < 0) xposition = 0;
1809 if(xposition >= items_w - view_w)
1810 xposition = items_w - view_w;
1812 if(xposition < 0) xposition = 0;
1815 int BC_ListBox::center_selection(int selection,
1816 ArrayList<BC_ListBoxItem*> *data,
1820 if(!data) data = this->data;
1821 if(!counter) counter = &temp;
1823 for(int i = 0; i < data[master_column].total; i++)
1828 BC_ListBoxItem *item = data[master_column].values[i];
1829 if((*counter) == selection)
1831 BC_ListBoxItem *top_item = this->data[master_column].values[0];
1834 if(display_format == LISTBOX_ICONS)
1836 // Icon is out of window
1837 if( item->icon_y-yposition > view_h-get_text_h(item) ||
1838 item->icon_y-yposition < 0 ) {
1839 yposition = item->icon_y - view_h / 2;
1842 if(data[master_column].values[selection]->icon_x - xposition > view_w ||
1843 data[master_column].values[selection]->icon_x - xposition < 0)
1845 xposition = item->icon_x - view_w / 2;
1850 // Text coordinate is out of window
1851 if( item->text_y-yposition > view_h-get_text_h(item) ||
1852 item->text_y-yposition < 0 ) {
1853 yposition = item->text_y -
1862 if(item->get_sublist())
1864 int result = center_selection(selection,
1865 item->get_sublist(),
1867 if(result) return result;
1873 void BC_ListBox::update_scrollbars(int flush)
1875 int h_needed = items_h = get_items_height(data, columns);
1876 int w_needed = items_w = get_items_width();
1878 // if(columns > 0 && column_width)
1879 // printf("BC_ListBox::update_scrollbars 1 %d %d\n", column_width[columns - 1], w_needed);
1883 if(xposition != xscrollbar->get_value())
1884 xscrollbar->update_value(xposition);
1886 if(w_needed != xscrollbar->get_length() ||
1887 view_w != xscrollbar->get_handlelength())
1888 xscrollbar->update_length(w_needed, xposition, view_w, 0);
1893 if(yposition != yscrollbar->get_value())
1894 yscrollbar->update_value(yposition);
1896 if(h_needed != yscrollbar->get_length() || view_h != yscrollbar->get_handlelength())
1897 yscrollbar->update_length(h_needed, yposition, view_h, 0);
1900 if(flush) this->flush();
1903 int BC_ListBox::get_scrollbars()
1905 int h_needed = items_h = get_items_height(data, columns);
1906 int w_needed = items_w = get_items_width();
1910 title_h = get_title_h();
1912 view_h = popup_h - title_h - 4;
1913 view_w = popup_w - 4;
1915 // Create scrollbars as needed
1916 for(int i = 0; i < 2; i++)
1918 if(w_needed > view_w)
1923 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h() -
1931 if(h_needed > view_h)
1935 get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w() -
1944 // Update subwindow size
1945 int new_w = popup_w;
1946 int new_h = popup_h;
1947 if(need_xscroll) new_h -= get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h();
1948 if(need_yscroll) new_w -= get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w();
1951 if(new_w != BC_WindowBase::get_w() || new_h != BC_WindowBase::get_h())
1952 gui->resize_window(new_w, new_h);
1954 BC_WindowBase *destination = (is_popup ? gui : parent_window);
1959 xscrollbar = new BC_ListBoxXScroll(this);
1960 destination->add_subwindow(xscrollbar);
1961 xscrollbar->show_window(0);
1962 xscrollbar->bound_to = this;
1966 xscrollbar->update_length(w_needed, xposition, view_w, flush);
1967 xscrollbar->reposition_window(get_xscroll_x(),
1969 get_xscroll_width());
1974 if(xscrollbar) delete xscrollbar;
1983 yscrollbar = new BC_ListBoxYScroll(this);
1984 destination->add_subwindow(yscrollbar);
1985 yscrollbar->show_window(0);
1986 yscrollbar->bound_to = this;
1990 yscrollbar->update_length(h_needed, yposition, view_h, flush);
1991 yscrollbar->reposition_window(get_yscroll_x(),
1993 get_yscroll_height());
1998 if(yscrollbar) delete yscrollbar;
2004 view_w + 4 != bg_surface->get_w() ||
2005 view_h + 4 != bg_surface->get_h())
2007 if(bg_surface) delete bg_surface;
2008 bg_surface = new BC_Pixmap(gui, view_w + 4, view_h + 4);
2018 void BC_ListBox::set_drag_scroll(int value)
2020 allow_drag_scroll = value;
2024 // Test for scrolling by dragging
2026 int BC_ListBox::test_drag_scroll(int cursor_x, int cursor_y)
2029 if(allow_drag_scroll ||
2030 current_operation == SELECT_RECT)
2033 int top_boundary = get_title_h();
2035 if(cursor_y < top_boundary ||
2036 cursor_y >= view_h + title_h + LISTBOX_BORDER * 2 ||
2037 cursor_x < LISTBOX_BORDER ||
2038 cursor_x >= view_w + LISTBOX_BORDER)
2046 int BC_ListBox::drag_scroll_event()
2048 int top_boundary = get_title_h();
2051 if(get_cursor_y() < top_boundary)
2053 yposition -= top_boundary - get_cursor_y();
2057 if(get_cursor_y() >= view_h + title_h + 4)
2059 yposition += get_cursor_y() - (view_h + title_h + 4);
2063 if(get_cursor_x() < 2)
2065 xposition -= 2 - get_cursor_x();
2069 if(get_cursor_x() >= view_w + 2)
2071 xposition += get_cursor_x() - (view_w + 2);
2074 if(result) clamp_positions();
2078 int BC_ListBox::rectangle_scroll_event()
2080 int old_xposition = xposition;
2081 int old_yposition = yposition;
2082 int result = drag_scroll_event();
2086 rect_x1 += old_xposition - xposition;
2087 rect_y1 += old_yposition - yposition;
2088 rect_x2 = get_cursor_x();
2089 rect_y2 = get_cursor_y();
2091 int x1 = MIN(rect_x1, rect_x2);
2092 int x2 = MAX(rect_x1, rect_x2);
2093 int y1 = MIN(rect_y1, rect_y2);
2094 int y2 = MAX(rect_y1, rect_y2);
2096 if(select_rectangle(data,
2102 selection_changed();
2107 update_scrollbars(1);
2112 int BC_ListBox::select_scroll_event()
2114 int result = drag_scroll_event();
2118 highlighted_item = selection_number = get_cursor_item(data,
2124 update_scrollbars(1);
2125 selection_changed();
2130 int BC_ListBox::select_rectangle(ArrayList<BC_ListBoxItem*> *data,
2137 for(int i = 0; i < data[master_column].total; i++)
2139 for(int j = 0; j < columns; j++)
2141 BC_ListBoxItem *item = data[j].values[i];
2142 if(display_format == LISTBOX_ICONS)
2144 int icon_x, icon_y, icon_w, icon_h;
2145 int text_x, text_y, text_w, text_h;
2146 get_icon_mask(item, icon_x, icon_y, icon_w, icon_h);
2147 get_text_mask(item, text_x, text_y, text_w, text_h);
2149 if((x2 >= icon_x && x1 < icon_x + icon_w &&
2150 y2 >= icon_y && y1 < icon_y + icon_h) ||
2151 (x2 >= text_x && x1 < text_x + text_w &&
2152 y2 >= text_y && y1 < text_y + text_h))
2173 gui->get_w() - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w() :
2176 y1 < gui->get_h() &&
2177 y2 >= get_item_y(item) &&
2178 y1 < get_item_y(item) + get_item_h(item))
2197 BC_ListBoxItem *item = data[master_column].values[i];
2198 if(item->get_sublist() &&
2200 result |= select_rectangle(item->get_sublist(),
2209 int BC_ListBox::reposition_item(ArrayList<BC_ListBoxItem*> *data,
2210 int selection_number,
2216 if(!counter) counter = &temp;
2219 for(int i = 0; i < data[master_column].total; i++)
2221 BC_ListBoxItem *item = data[master_column].values[i];
2223 if((*counter) == selection_number)
2229 // Not recursive because it's only used for icons
2234 void BC_ListBox::move_selection(ArrayList<BC_ListBoxItem*> *dst,
2235 ArrayList<BC_ListBoxItem*> *src)
2237 for(int i = 0; i < src[master_column].total; )
2239 BC_ListBoxItem *item = src[master_column].values[i];
2244 for(int j = 0; j < columns; j++)
2246 dst[j].append(src[j].values[i]);
2247 src[j].remove_number(i);
2251 // Descend into sublist
2252 if(item->get_sublist())
2255 item->get_sublist());
2261 int BC_ListBox::put_selection(ArrayList<BC_ListBoxItem*> *data,
2262 ArrayList<BC_ListBoxItem*> *src,
2267 if(!counter) counter = &temp;
2269 if(destination < 0 || destination >= data[master_column].total)
2271 for(int j = 0; j < columns; j++)
2273 for(int i = 0; i < src[j].total; i++)
2275 data[j].append(src[j].values[i]);
2281 for(int i = 0; i < data[master_column].total; i++)
2284 if((*counter) == destination)
2286 for(int j = 0; j < columns; j++)
2288 for(int k = 0; k < src[j].total; k++)
2290 data[j].insert(src[j].values[k], destination + k);
2296 BC_ListBoxItem *item = data[master_column].values[i];
2297 if(item->get_sublist())
2299 if(put_selection(item->get_sublist(),
2311 int BC_ListBox::item_to_index(ArrayList<BC_ListBoxItem*> *data,
2312 BC_ListBoxItem *item,
2316 if(!counter) counter = &temp;
2318 for(int i = 0; i < data[master_column].total; i++)
2321 for(int j = 0; j < columns; j++)
2323 BC_ListBoxItem *new_item = data[j].values[i];
2324 //printf("BC_ListBox::item_to_index 1 %d %d %p\n", j, i, new_item);
2325 if(new_item == item)
2331 BC_ListBoxItem *new_item = data[master_column].values[i];
2332 if(new_item->get_sublist())
2334 if(item_to_index(new_item->get_sublist(),
2344 BC_ListBoxItem* BC_ListBox::index_to_item(ArrayList<BC_ListBoxItem*> *data,
2350 if(!counter) counter = &temp;
2351 for(int i = 0; i < data[master_column].total; i++)
2354 if((*counter) == number)
2356 return data[column].values[i];
2358 BC_ListBoxItem *item = data[master_column].values[i];
2359 if(item->get_sublist())
2361 BC_ListBoxItem *result = index_to_item(item->get_sublist(),
2365 if(result) return result;
2371 int BC_ListBox::get_cursor_item(ArrayList<BC_ListBoxItem*> *data,
2374 BC_ListBoxItem **item_return,
2379 if(!data) return -1;
2380 if(!counter) counter = &temp;
2382 // Icons are not treed
2383 if(display_format == LISTBOX_ICONS)
2385 for(int j = data[master_column].total - 1; j >= 0; j--)
2387 int icon_x, icon_y, icon_w, icon_h;
2388 int text_x, text_y, text_w, text_h;
2389 BC_ListBoxItem *item = data[master_column].values[j];
2390 get_icon_mask(item, icon_x, icon_y, icon_w, icon_h);
2391 get_text_mask(item, text_x, text_y, text_w, text_h);
2393 if((cursor_x >= icon_x && cursor_x < icon_x + icon_w &&
2394 cursor_y >= icon_y && cursor_y < icon_y + icon_h) ||
2395 (cursor_x >= text_x && cursor_x < text_x + text_w &&
2396 cursor_y >= text_y && cursor_y < text_y + text_h))
2398 if(item_return) (*item_return) = item;
2405 // Cursor is inside items rectangle
2407 cursor_x < (yscrollbar ?
2408 gui->get_w() - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w() :
2410 // Only clamp y if we're not in a SELECT operation.
2411 (current_operation == BC_ListBox::SELECT ||
2412 (cursor_y > get_title_h() + LISTBOX_BORDER &&
2413 cursor_y < gui->get_h())))
2415 // Search table for cursor obstruction
2416 for(int i = 0; i < data[master_column].total; i++)
2418 BC_ListBoxItem *item = data[master_column].values[i];
2421 // Cursor is inside item on current level
2424 cursor_y >= get_item_y(item) &&
2425 cursor_y < get_item_y(item) + get_item_h(item))
2427 //printf("BC_ListBox::get_cursor_item %d %d %p\n", master_column, i, item);
2428 if(item_return) (*item_return) = item;
2432 // Descend into sublist
2433 if(item->get_sublist())
2435 if(get_cursor_item(item->get_sublist(),
2440 item->get_expand()) >= 0)
2449 int BC_ListBox::repeat_event(int64_t duration)
2451 switch(current_operation)
2453 // Repeat out of bounds selection
2455 if(duration == get_resources()->scroll_repeat)
2456 return rectangle_scroll_event();
2461 if(duration == get_resources()->scroll_repeat)
2462 return select_scroll_event();
2467 if(button_highlighted && is_popup &&
2468 tooltip_text && tooltip_text[0] != 0 &&
2469 duration == get_resources()->tooltip_delay)
2480 int BC_ListBox::cursor_enter_event()
2484 switch(current_operation)
2486 // Cursor moved over button, pressed, and exited.
2487 case BUTTON_DOWN_SELECT:
2488 if(top_level->event_win == win)
2490 current_operation = BUTTON_DN;
2492 button_highlighted = 1;
2498 // Cursor entered button
2499 if(is_popup && top_level->event_win == win)
2501 button_highlighted = 1;
2506 // TODO: Need to get the highlighted column title or item
2507 if(gui && top_level->event_win == gui->win)
2509 list_highlighted = 1;
2519 int BC_ListBox::cursor_leave_event()
2521 if(current_operation == COLUMN_DRAG) return 0;
2524 if(button_highlighted)
2526 button_highlighted = 0;
2531 if(list_highlighted)
2533 list_highlighted = 0;
2534 highlighted_item = -1;
2535 highlighted_ptr = 0;
2536 highlighted_title = -1;
2537 int redraw_toggles = 0;
2538 for(int i = 0; i < expanders.total; i++)
2539 expanders.values[i]->cursor_leave_event(&redraw_toggles);
2547 int BC_ListBox::get_first_selection(ArrayList<BC_ListBoxItem*> *data, int *result)
2550 if(!result) result = &temp;
2552 for(int i = 0; i < data[master_column].total; i++)
2554 BC_ListBoxItem *item = data[master_column].values[i];
2556 if(item->selected) return (*result);
2557 if(item->get_sublist())
2559 if(get_first_selection(item->get_sublist(), result) >= 0)
2566 int BC_ListBox::get_total_items(ArrayList<BC_ListBoxItem*> *data,
2571 if(!result) result = &temp;
2573 for(int i = 0; i < data[master_column].total; i++)
2576 if(data[master_column].values[i]->get_sublist())
2577 get_total_items(data[master_column].values[i]->get_sublist(),
2586 int BC_ListBox::get_last_selection(ArrayList<BC_ListBoxItem*> *data,
2597 for(int i = data[master_column].total - 1; i >= 0; i--)
2599 BC_ListBoxItem *item = data[master_column].values[i];
2604 return get_total_items(data, 0, master_column) - (*result) /* - 1 */;
2609 if(item->get_sublist())
2611 if(get_last_selection(item->get_sublist(), result) >= 0)
2614 return get_total_items(data, 0, master_column) - (*result) /* - 1 */;
2623 void BC_ListBox::select_range(ArrayList<BC_ListBoxItem*> *data,
2629 if(!current) current = &temp;
2631 for(int i = 0; i < data[master_column].total; i++)
2634 if((*current) >= start && (*current) < end)
2636 for(int j = 0; j < columns; j++)
2637 data[j].values[i]->selected = 1;
2639 BC_ListBoxItem *item = data[master_column].values[i];
2640 if(item->get_sublist())
2641 select_range(item->get_sublist(),
2649 // Fill items between current selection and new selection
2650 int BC_ListBox::expand_selection(int button_press, int selection_number)
2652 int old_selection_start = selection_start;
2653 int old_selection_end = selection_end;
2655 // printf("BC_ListBox::expand_selection %d %d\n",
2656 // selection_center,
2657 // selection_number);
2659 // Calculate the range to select based on selection_center and selection_number
2660 if(selection_number < selection_center)
2662 selection_start = selection_number;
2666 selection_end = selection_number + 1;
2669 //printf("BC_ListBox::expand_selection %d %d %d %d\n", old_selection_start, old_selection_end, selection_start, selection_end);
2670 // Recurse through all the items and select the desired range
2671 select_range(data, selection_start, selection_end);
2674 return (old_selection_start != selection_start ||
2675 old_selection_end != selection_end);
2678 int BC_ListBox::toggle_item_selection(ArrayList<BC_ListBoxItem*> *data,
2679 int selection_number,
2683 if(!counter) counter = &temp;
2685 for(int i = 0; i < data[master_column].total; i++)
2687 BC_ListBoxItem *item = data[master_column].values[i];
2689 if((*counter) == selection_number)
2691 // Get new value for selection
2692 int selected = !item->selected;
2694 for(int j = 0; j < columns; j++)
2695 data[j].values[i]->selected = selected;
2699 // Descend into sublist
2700 if(item->get_sublist())
2702 if(toggle_item_selection(item->get_sublist(),
2713 void BC_ListBox::set_all_selected(ArrayList<BC_ListBoxItem*> *data, int value)
2715 for(int i = 0; i < data[master_column].total; i++)
2717 for(int j = 0; j < columns; j++)
2719 BC_ListBoxItem *item = data[j].values[i];
2720 item->selected = value;
2722 BC_ListBoxItem *item = data[master_column].values[i];
2723 if(item->get_sublist())
2725 set_all_selected(item->get_sublist(), value);
2730 void BC_ListBox::set_selected(ArrayList<BC_ListBoxItem*> *data,
2736 if(!counter) counter = &temp;
2737 for(int i = 0; i < data[master_column].total && (*counter) != item_number; i++)
2740 if((*counter) == item_number)
2742 for(int j = 0; j < columns; j++)
2744 BC_ListBoxItem *item = data[j].values[i];
2745 item->selected = value;
2750 BC_ListBoxItem *item = data[master_column].values[i];
2751 if(item->get_sublist())
2753 set_selected(item->get_sublist(),
2761 int BC_ListBox::update_selection(ArrayList<BC_ListBoxItem*> *data,
2762 int selection_number,
2767 if(!counter) counter = &temp;
2769 for(int i = 0; i < data[master_column].total; i++)
2771 BC_ListBoxItem *item = data[master_column].values[i];
2773 if((*counter) == selection_number && !item->selected)
2776 for(int j = 0; j < columns; j++)
2777 data[j].values[i]->selected = 1;
2780 if((*counter) != selection_number && item->selected)
2783 for(int j = 0; j < columns; j++)
2784 data[j].values[i]->selected = 0;
2786 if(item->get_sublist())
2787 result |= update_selection(item->get_sublist(),
2794 void BC_ListBox::promote_selections(ArrayList<BC_ListBoxItem*> *data,
2798 for(int i = 0; i < data[master_column].total; i++)
2800 for(int j = 0; j < columns; j++)
2802 BC_ListBoxItem *item = data[j].values[i];
2803 if(item->selected == old_value) item->selected = new_value;
2805 BC_ListBoxItem *item = data[master_column].values[i];
2806 if(item->get_sublist())
2807 promote_selections(item->get_sublist(), old_value, new_value);
2811 int BC_ListBox::focus_out_event()
2817 int BC_ListBox::button_press_event()
2820 BC_ListBoxItem *current_item = 0;
2822 int do_selection_change = 0;
2823 const int debug = 0;
2826 if(debug) printf("BC_ListBox::button_press_event %d this=%p event_win=%p %p %p %p\n",
2829 (void*)top_level->event_win,
2830 (void*)(gui ? gui->win : 0),
2832 (void*)parent_window->win);
2834 // Pressed in button
2835 if(is_popup && top_level->event_win == win)
2837 if(debug) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2838 current_operation = BUTTON_DN;
2842 if(!active && !disabled)
2844 top_level->deactivate();
2851 // Pressed in scrollbar
2852 if((xscrollbar && top_level->event_win == xscrollbar->win) ||
2853 (yscrollbar && top_level->event_win == yscrollbar->win))
2855 if(debug) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2860 if(gui && top_level->event_win == gui->win)
2862 if(debug) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2864 // Activate list items
2865 // If it is a suggestion popup, it is visible without being active
2868 if(debug) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2869 if(!is_suggestions) top_level->deactivate();
2870 if(debug) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2872 if(debug) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2875 // Wheel mouse pressed
2876 if(get_buttonpress() == 4)
2878 if(current_operation == NO_OPERATION)
2880 current_operation = WHEEL;
2883 set_yposition(yposition - gui->get_h() / 10, 0);
2885 update_scrollbars(0);
2886 highlighted_ptr = 0;
2887 highlighted_item = get_cursor_item(data,
2888 top_level->cursor_x,
2889 top_level->cursor_y,
2897 if(get_buttonpress() == 5)
2899 if(current_operation == NO_OPERATION)
2901 current_operation = WHEEL;
2904 set_yposition(yposition + gui->get_h() / 10, 0);
2906 update_scrollbars(0);
2907 highlighted_ptr = 0;
2908 highlighted_item = get_cursor_item(data,
2909 top_level->cursor_x,
2910 top_level->cursor_y,
2918 // Pressed over column title division
2919 if(test_column_divisions(gui->get_cursor_x(),
2920 gui->get_cursor_y(),
2923 drag_cursor_x = gui->get_cursor_x() + xposition;
2925 drag_column_w = column_width[highlighted_division - 1];
2927 drag_column_w = default_column_width[highlighted_division - 1];
2929 current_operation = DRAG_DIVISION;
2933 // Pressed in column title
2934 if(test_column_titles(gui->get_cursor_x(), gui->get_cursor_y()))
2936 current_operation = COLUMN_DN;
2937 button_highlighted = 0;
2938 list_highlighted = 1;
2943 // Pressed in expander
2944 if(test_expanders())
2946 current_operation = EXPAND_DN;
2947 // Need to redraw items because of alpha
2952 // Pressed over item
2953 if((selection_number = get_cursor_item(data,
2954 gui->get_cursor_x(),
2955 gui->get_cursor_y(),
2956 ¤t_item)) >= 0)
2958 if(debug) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2960 // Get item button was pressed over
2961 selection_number2 = selection_number1;
2962 selection_number1 = selection_number;
2964 selection_start = -1;
2968 // Multiple item selection is possible
2969 if(selection_mode == LISTBOX_MULTIPLE &&
2970 (ctrl_down() || shift_down()))
2972 // Expand text selection.
2973 // Fill items between selected region and current item.
2975 (display_format == LISTBOX_TEXT ||
2976 display_format == LISTBOX_ICON_LIST))
2978 // Get first item selected
2979 selection_start = get_first_selection(data);
2980 // Get last item selected
2981 selection_end = get_last_selection(data);
2982 // Get center of selected region
2983 if(selection_end > selection_start)
2985 selection_center = (selection_end + selection_start) >> 1;
2989 selection_center = selection_number;
2993 // Deselect everything.
2994 set_all_selected(data, 0);
2995 // Select just the items
2996 expand_selection(1, selection_number);
3000 // Toggle a single item on or off
3002 toggle_item_selection(data, selection_number);
3003 new_value = current_item->selected;
3007 // Select single item
3009 if(!current_item->selected)
3011 set_all_selected(data, 0);
3020 current_operation = SELECT;
3021 highlighted_item = selection_number;
3022 highlighted_ptr = current_item;
3023 button_highlighted = 0;
3024 list_highlighted = 1;
3027 do_selection_change = 1;
3032 // Pressed over nothing. Start rectangle selection.
3034 if(get_buttonpress() == 1 &&
3035 selection_mode == LISTBOX_MULTIPLE)
3039 // Deselect all and redraw if anything was selected
3040 if(get_selection_number(0, 0) >= 0)
3042 set_all_selected(data, 0);
3044 do_selection_change = 1;
3050 // Promote selections to protect from a rectangle selection
3051 promote_selections(data, 1, 2);
3054 // Start rectangle selection
3055 current_operation = SELECT_RECT;
3056 rect_x1 = rect_x2 = get_cursor_x();
3057 rect_y1 = rect_y2 = get_cursor_y();
3065 // Suggestion box is not active but visible, so lie to get it to deactivate
3066 if(is_popup && (active || (is_suggestions && gui)))
3069 if(debug) printf("BC_ListBox::button_press_event %d\n", __LINE__);
3075 if(do_selection_change) selection_changed();
3076 if(debug) printf("BC_ListBox::button_press_event %d %d\n",
3083 int BC_ListBox::button_release_event()
3086 int cursor_x, cursor_y;
3090 //printf("BC_ListBox::button_release_event 1 %d\n", current_operation);
3091 switch(current_operation)
3094 current_operation = NO_OPERATION;
3099 current_operation = NO_OPERATION;
3103 // Release item selection
3104 case BUTTON_DOWN_SELECT:
3106 //printf("BC_ListBox::button_release_event 10\n");
3107 unset_repeat(get_resources()->scroll_repeat);
3108 current_operation = NO_OPERATION;
3110 translate_coordinates(top_level->event_win, gui->win,
3111 gui->get_cursor_x(), gui->get_cursor_y(),
3112 &cursor_x, &cursor_y);
3113 selection_number1 = selection_number =
3114 get_cursor_item(data, cursor_x, cursor_y);
3115 //printf("BC_ListBox::button_release_event %d %d\n", selection_number2, selection_number1);
3121 if(selection_number >= 0)
3127 // Second button release outside button
3128 if(button_releases > 1)
3135 if(top_level->get_double_click() &&
3136 selection_number2 == selection_number1 &&
3137 selection_number2 >= 0 &&
3138 selection_number1 >= 0)
3148 unset_repeat(get_resources()->scroll_repeat);
3151 // Demote selections from rectangle selection
3152 promote_selections(data, 2, 1);
3155 // Hide rectangle overlay
3157 current_operation = NO_OPERATION;
3161 // Release popup button
3164 current_operation = NO_OPERATION;
3168 // Second button release inside button
3169 if(button_releases > 1)
3177 current_operation = NO_OPERATION;
3178 // Update the sort column and the sort order for the user only if the existing
3179 // sort column is valid.
3180 if(sort_column >= 0)
3182 // Invert order only if column is the same
3183 if(highlighted_title == sort_column)
3185 (sort_order == SORT_ASCENDING) ?
3188 // Set the new sort column
3189 sort_column = highlighted_title;
3190 if(!sort_order_event())
3196 // Sorting not enabled. Redraw the title state.
3205 int redraw_toggles = 0;
3206 for(int i = 0; i < expanders.total && !result; i++)
3208 if(expanders.values[i]->button_release_event(&redraw_toggles))
3213 // Need to redraw items because of alpha
3214 if(redraw_toggles) draw_items(1);
3215 current_operation = NO_OPERATION;
3220 // Can't default to NO_OPERATION because it may be used in a drag event.
3225 if(do_event) handle_event();
3227 //printf("BC_ListBox::button_release_event %d %d\n", __LINE__, get_window_lock());
3231 int BC_ListBox::get_title_h()
3233 if(display_format == LISTBOX_TEXT ||
3234 display_format == LISTBOX_ICON_LIST)
3235 return column_titles ? column_bg[0]->get_h() : 0;
3240 void BC_ListBox::reset_cursor(int new_cursor)
3244 if(gui->get_cursor() != new_cursor)
3246 gui->set_cursor(new_cursor, 0, 0);
3250 if(get_cursor() != new_cursor)
3252 set_cursor(new_cursor, 0, 0);
3256 int BC_ListBox::test_column_divisions(int cursor_x, int cursor_y, int &new_cursor)
3261 cursor_y < get_title_h() &&
3263 cursor_x < gui->get_w())
3265 for(int i = 1; i < columns; i++)
3267 if(cursor_x >= -xposition + get_column_offset(i) - 5 &&
3268 cursor_x < -xposition + get_column_offset(i) +
3269 get_resources()->listbox_title_hotspot)
3271 highlighted_item = -1;
3272 highlighted_ptr = 0;
3273 highlighted_division = i;
3274 highlighted_title = -1;
3275 list_highlighted = 1;
3276 new_cursor = HSEPARATE_CURSOR;
3281 highlighted_division = -1;
3285 int BC_ListBox::test_column_titles(int cursor_x, int cursor_y)
3290 cursor_y < get_title_h() &&
3292 cursor_x < gui->get_w())
3294 for(int i = 0; i < columns; i++)
3296 if(cursor_x >= -xposition + get_column_offset(i) &&
3297 (cursor_x < -xposition + get_column_offset(i + 1) ||
3300 highlighted_item = -1;
3301 highlighted_ptr = 0;
3302 highlighted_division = -1;
3303 highlighted_title = i;
3304 list_highlighted = 1;
3309 highlighted_title = -1;
3313 int BC_ListBox::test_expanders()
3315 for(int i = 0; i < expanders.total; i++)
3317 if(expanders.values[i]->button_press_event())
3319 current_operation = EXPAND_DN;
3327 int BC_ListBox::cursor_motion_event()
3329 int redraw = 0, result = 0;
3330 int new_cursor = ARROW_CURSOR;
3332 selection_number = -1;
3335 switch(current_operation)
3338 // Button pressed and slid off button
3339 if(!cursor_inside())
3341 current_operation = BUTTON_DOWN_SELECT;
3349 // int new_w = get_cursor_x() +
3351 // get_column_offset(highlighted_division - 1);
3352 int difference = get_cursor_x() + xposition - drag_cursor_x;
3353 int new_w = drag_column_w + difference;
3355 new_cursor = HSEPARATE_CURSOR;
3359 column_width[highlighted_division - 1] = new_w;
3363 default_column_width[highlighted_division - 1] = new_w;
3366 column_width_boundaries();
3368 // Force update of coords
3369 set_autoplacement(data, 0, 1);
3370 column_resize_event();
3374 update_scrollbars(1);
3381 if(test_drag_scroll(get_cursor_x(), get_cursor_y()))
3383 set_repeat(get_resources()->scroll_repeat);
3386 int old_x1 = MIN(rect_x1, rect_x2);
3387 int old_x2 = MAX(rect_x1, rect_x2);
3388 int old_y1 = MIN(rect_y1, rect_y2);
3389 int old_y2 = MAX(rect_y1, rect_y2);
3391 int new_rect_x2 = get_cursor_x();
3392 int new_rect_y2 = get_cursor_y();
3394 int x1 = MIN(rect_x1, new_rect_x2);
3395 int x2 = MAX(rect_x1, new_rect_x2);
3396 int y1 = MIN(rect_y1, new_rect_y2);
3397 int y2 = MAX(rect_y1, new_rect_y2);
3399 // Adjust rectangle coverage
3407 redraw = select_rectangle(data,
3417 //printf("BC_ListBox::cursor_motion_event %d\n", __LINE__);
3422 rect_x2 = get_cursor_x();
3423 rect_y2 = get_cursor_y();
3428 update_scrollbars(1);
3429 selection_changed();
3430 //printf("BC_ListBox::cursor_motion_event %d\n", __LINE__);
3438 //printf("BC_ListBox::cursor_motion_event %d\n", __LINE__);
3448 int old_highlighted_item = highlighted_item;
3450 if(test_drag_scroll(get_cursor_x(),
3453 set_repeat(get_resources()->scroll_repeat);
3457 highlighted_item = selection_number = get_cursor_item(data,
3463 // Deselect all items and select just the one we're over
3464 if(selection_number >= 0 &&
3468 selection_mode == LISTBOX_SINGLE))
3470 redraw = update_selection(data, selection_number);
3473 if(selection_mode == LISTBOX_MULTIPLE &&
3474 (shift_down() || ctrl_down()))
3475 // Expand multiple selection
3477 // Expand selected region in text mode centered around initial range
3478 if((display_format == LISTBOX_TEXT ||
3479 display_format == LISTBOX_ICON_LIST) &&
3482 // Deselect everything.
3483 set_all_selected(data, 0);
3485 // Select just the items
3486 redraw = expand_selection(0, selection_number);
3489 // Set the one item we're over to the selection value determined in
3490 // button_press_event.
3498 if(highlighted_item != old_highlighted_item)
3502 update_scrollbars(1);
3503 //printf("BC_ListBox::cursor_motion_event %d %d\n", highlighted_item, old_highlighted_item);
3504 selection_changed();
3509 case BUTTON_DOWN_SELECT:
3510 // Went back into button area
3513 current_operation = BUTTON_DN;
3518 // Went into item area
3521 int cursor_x = 0, cursor_y = 0;
3522 translate_coordinates(top_level->event_win,
3524 top_level->cursor_x,
3525 top_level->cursor_y,
3528 int old_highlighted_item = highlighted_item;
3529 highlighted_item = selection_number = get_cursor_item(data,
3534 if(highlighted_item != old_highlighted_item)
3536 update_selection(data, selection_number);
3538 selection_changed();
3545 int redraw_toggles = 0;
3546 for(int i = 0; i < expanders.total && !result; i++)
3548 result = expanders.values[i]->cursor_motion_event(
3553 // Need to redraw items because of the alpha
3561 int cursor_x = get_cursor_x(), cursor_y = get_cursor_y();
3562 if(gui && top_level->event_win == gui->win)
3564 int old_highlighted_title = highlighted_title;
3565 int old_list_highlighted = list_highlighted;
3566 int old_highlighted_item = highlighted_item;
3567 int redraw_titles = 0;
3568 int redraw_border = 0;
3569 int redraw_items = 0;
3570 int redraw_toggles = 0;
3574 // Test if cursor moved over a title division
3575 test_column_divisions(cursor_x, cursor_y, new_cursor);
3577 // Test if cursor moved over a title
3578 if(highlighted_division < 0)
3580 test_column_titles(cursor_x, cursor_y);
3583 // Test if cursor moved over expander
3584 if(highlighted_division < 0 &&
3585 highlighted_title < 0 &&
3586 (display_format == LISTBOX_TEXT ||
3587 display_format == LISTBOX_ICON_LIST))
3589 for(int i = 0; i < expanders.total; i++)
3591 expanders.values[i]->cursor_motion_event(
3594 //printf("BC_ListBox::cursor_motion_event %d\n", redraw_toggles);
3597 // Test if cursor moved over an item
3598 if(highlighted_division < 0 &&
3599 highlighted_title < 0)
3601 highlighted_item = get_cursor_item(data,
3608 // Clear title highlighting if moved over division
3609 if(old_highlighted_title != highlighted_title)
3614 // Highlight list border
3615 if(old_list_highlighted != list_highlighted)
3620 // Moved out of item area
3621 if(old_highlighted_item != highlighted_item)
3626 //printf("BC_ListBox::cursor_motion_event 1 %d\n", highlighted_item);
3628 // Change cursor to title division adjustment
3629 reset_cursor(new_cursor);
3656 if(!result && list_highlighted)
3658 list_highlighted = 0;
3659 highlighted_item = -1;
3660 highlighted_ptr = 0;
3661 highlighted_title = -1;
3662 highlighted_division = -1;
3674 int BC_ListBox::drag_start_event()
3676 switch(current_operation)
3680 gui->is_event_win() &&
3683 BC_ListBoxItem *item_return = 0;
3684 selection_number = get_cursor_item(data,
3685 top_level->cursor_x,
3686 top_level->cursor_y,
3689 if(selection_number >= 0)
3692 if (item_return->icon_vframe)
3694 drag_popup = new BC_DragWindow(this,
3695 item_return->icon_vframe /*,
3696 get_abs_cursor_x(0) - item_return->icon_vframe->get_w() / 2,
3697 get_abs_cursor_y(0) - item_return->icon_vframe->get_h() / 2 */);
3700 // this probably works not!
3701 if (item_return->icon)
3703 drag_popup = new BC_DragWindow(this,
3704 item_return->icon /*,
3705 get_abs_cursor_x(0) - item_return->icon->get_w() / 2,
3706 get_abs_cursor_y(0) - item_return->icon->get_h() / 2 */);
3710 drag_popup = new BC_DragWindow(this,
3711 drag_icon_vframe /*,
3712 get_abs_cursor_x(0) - drag_icon_vframe->get_w() / 2,
3713 get_abs_cursor_y(0) - drag_icon_vframe->get_h() / 2 */);
3716 current_operation = DRAG_ITEM;
3717 set_repeat(get_resources()->scroll_repeat);
3724 if(gui && gui->is_event_win() && allow_drag_column)
3726 drag_popup = new BC_DragWindow(this,
3727 drag_column_icon_vframe /*,
3728 get_abs_cursor_x(0) - drag_column_icon_vframe->get_w() / 2,
3729 get_abs_cursor_y(0) - drag_column_icon_vframe->get_h() / 2 */);
3730 dragged_title = highlighted_title;
3731 current_operation = COLUMN_DRAG;
3741 int BC_ListBox::drag_motion_event()
3743 //printf("BC_ListBox::drag_motion_event 1 %d\n", current_operation);
3744 switch(current_operation)
3749 int new_highlighted_item = -1;
3750 BC_ListBoxItem *new_highlighted_ptr = 0;
3751 new_highlighted_item = get_cursor_item(data,
3752 top_level->cursor_x, top_level->cursor_y,
3753 &new_highlighted_ptr);
3755 if(new_highlighted_item != highlighted_item)
3760 // Always update highlighted value for drag_stop
3761 highlighted_item = new_highlighted_item;
3762 highlighted_ptr = new_highlighted_ptr;
3763 //printf("BC_ListBox::drag_motion_event 1 %p\n", highlighted_ptr);
3768 update_scrollbars(1);
3771 return drag_popup->cursor_motion_event();
3777 int old_highlighted_title = highlighted_title;
3778 test_column_titles(get_cursor_x(), get_cursor_y());
3779 if(old_highlighted_title != highlighted_title)
3783 return drag_popup->cursor_motion_event();
3790 int BC_ListBox::drag_stop_event()
3792 switch(current_operation)
3795 unset_repeat(get_resources()->scroll_repeat);
3796 // Inside window boundary
3797 if(top_level->cursor_x > 0 &&
3798 top_level->cursor_x < gui->get_w() - drag_popup->get_w() / 2 &&
3799 top_level->cursor_y > 0 &&
3800 top_level->cursor_y < gui->get_h() - drag_popup->get_h() / 2)
3805 if(display_format == LISTBOX_ICONS)
3807 reposition_item(data,
3809 top_level->cursor_x +
3810 drag_popup->get_offset_x() -
3814 top_level->cursor_y +
3815 drag_popup->get_offset_y() -
3824 // Move selected items from data to temporary
3825 ArrayList<BC_ListBoxItem*> *src_items =
3826 new ArrayList<BC_ListBoxItem*>[columns];
3827 move_selection(src_items, data);
3829 int destination = highlighted_item = item_to_index(data,
3831 // Insert items from temporary to data
3832 put_selection(data, src_items, destination);
3834 delete [] src_items;
3835 set_autoplacement(data, 0, 1);
3842 drag_popup->drag_failure_event();
3847 current_operation = NO_OPERATION;
3853 if(dragged_title != highlighted_title)
3855 if(highlighted_title >= 0)
3857 if(!move_column_event()) draw_titles(1);
3860 drag_popup->drag_failure_event();
3862 current_operation = NO_OPERATION;
3872 BC_DragWindow* BC_ListBox::get_drag_popup()
3877 int BC_ListBox::translation_event()
3881 int new_x = gui->get_x() +
3882 (top_level->last_translate_x - top_level->prev_x -
3883 BC_DisplayInfo::get_left_border());
3884 int new_y = gui->get_y() +
3885 (top_level->last_translate_y - top_level->prev_y -
3886 BC_DisplayInfo::get_top_border());
3888 gui->reposition_window(new_x, new_y);
3894 int BC_ListBox::reposition_window(int x, int y, int w, int h, int flush)
3898 if(w != -1) popup_w = w;
3899 if(h != -1) popup_h = h;
3900 //printf("BC_ListBox::reposition_window %d %d\n", popup_w, popup_h);
3905 xscrollbar->reposition_window(get_xscroll_x(),
3907 get_xscroll_width());
3909 yscrollbar->reposition_window(get_yscroll_x(),
3911 get_yscroll_height());
3916 BC_WindowBase::reposition_window(x, y, w, h);
3922 int BC_ListBox::deactivate()
3925 // printf("BC_ListBox::deactivate %d this=%p gui=%p active=%d\n",
3935 //printf("BC_ListBox::deactivate %d this=%p gui=%p\n", __LINE__, this, gui);
3944 highlighted_item = -1;
3945 highlighted_ptr = 0;
3950 //printf("BC_ListBox::deactivate %d this=%p\n", __LINE__, this);
3952 top_level->active_subwindow = 0;
3958 int BC_ListBox::activate(int take_focus)
3960 if( active ) return 0;
3963 set_active_subwindow(this);
3964 button_releases = 0;
3965 if( !is_popup || gui ) return 0;
3966 int wx = get_x(), wy = get_y() + get_h();
3967 if( justify == LISTBOX_RIGHT ) wx += get_w() - popup_w;
3970 XTranslateCoordinates(top_level->display,
3971 parent_window->win, top_level->rootwin,
3972 wx, wy, &abs_x, &abs_y, &xwin);
3975 return activate(abs_x, abs_y);
3978 int BC_ListBox::activate(int x, int y, int w, int h)
3980 if( !is_popup || gui ) return 0;
3982 if(w != -1) popup_w = w;
3983 if(h != -1) popup_h = h;
3985 if( y + popup_h > top_level->get_root_h(0) )
3986 y -= get_h() + popup_h;
3987 add_subwindow(gui = new BC_Popup(this,
3988 x, y, popup_w, popup_h, -1, 0, 0));
3990 gui->show_window(1);
3994 int BC_ListBox::is_active()
3999 int BC_ListBox::keypress_event()
4001 if(!active) return 0;
4003 //printf("BC_ListBox::keypress_event %d\n", __LINE__);
4005 int result = 0, redraw = 0;
4006 int view_items = last_in_view - first_in_view + 1;
4007 if( view_items <= 0 ) view_items = view_h / get_text_height(MEDIUMFONT);
4008 int new_item = -1, new_selection = -1;
4010 switch(top_level->get_keypress())
4014 top_level->deactivate();
4016 // If user is manipulating popup with keyboard, don't pass on event.
4019 //printf("BC_ListBox::keypress_event %d %p\n", __LINE__, get_selection(0, 0));
4020 if(top_level->get_keypress() == RETURN)
4022 //printf("BC_ListBox::keypress_event %d %p\n", __LINE__, get_selection(0, 0));
4030 new_selection = new_item = select_previous(0);
4032 //printf("BC_ListBox::keypress_event 1 %d\n", new_item);
4035 center_selection(new_item);
4043 new_selection = new_item = select_next(0);
4047 center_selection(new_item);
4055 new_selection = new_item = select_previous(view_items - 1);
4059 center_selection(new_item);
4067 new_selection = new_item = select_next(view_items - 1);
4071 center_selection(new_item);
4099 int query_len = strlen(query);
4100 if( query_len < (int)sizeof(query)-1 &&
4101 top_level->get_keypress() > 30 &&
4102 top_level->get_keypress() < 127)
4104 query[query_len++] = top_level->get_keypress();
4105 query[query_len] = 0;
4106 new_selection = query_list();
4109 if(top_level->get_keypress() == BACKSPACE)
4111 if(query_len > 0) query[--query_len] = 0;
4112 new_selection = query_list();
4116 show_tooltip(query);
4130 update_scrollbars(1);
4133 //printf("BC_ListBox::keypress_event %d new_selection=%d\n", __LINE__, new_selection);
4134 if(new_selection >= 0 && !is_suggestions)
4136 //printf("BC_ListBox::keypress_event %d\n", __LINE__);
4137 selection_changed();
4138 //printf("BC_ListBox::keypress_event %d\n", __LINE__);
4145 BC_Pixmap* BC_ListBox::get_bg_surface()
4151 void BC_ListBox::draw_background()
4153 if( !bg_draw ) return;
4155 // White background pixmap
4156 set_color(top_level->get_resources()->listbox_inactive);
4157 draw_box(0, 0, bg_surface->get_w(), bg_surface->get_h(), bg_surface);
4159 // Optional heroine pixmap
4161 bg_surface->draw_pixmap(bg_pixmap,
4162 bg_surface->get_w() - top_level->get_resources()->listbox_bg->get_w(),
4166 void BC_ListBox::clear_listbox(int x, int y, int w, int h)
4168 gui->draw_pixmap(bg_surface, x, y, w, h, x, y - title_h);
4171 void BC_ListBox::update_format(int display_format, int redraw)
4173 this->display_format = display_format;
4174 xposition = 0; yposition = 0;
4175 if( redraw && gui ) draw_items(1, 1);
4178 int BC_ListBox::get_format()
4180 return display_format;
4185 int BC_ListBox::draw_items(int flush, int draw_bg)
4189 BC_Resources *resources = get_resources();
4191 //dump(data, columns);
4193 // Calculate items width
4194 calculate_item_coords();
4197 // Create and destroy scrollbars as needed
4202 if( bg_draw ) this->bg_draw = 1;
4208 if(display_format == LISTBOX_ICONS)
4210 clear_listbox(2, 2 + title_h, view_w, view_h);
4212 set_font(MEDIUMFONT);
4213 for(int i = 0; i < data[master_column].size(); i++)
4215 BC_ListBoxItem *item = data[master_column].get(i);
4216 if(get_item_x(item) >= -get_item_w(item) &&
4217 get_item_x(item) < view_w &&
4218 get_item_y(item) >= -get_item_h(item) + title_h &&
4219 get_item_y(item) < view_h + title_h)
4221 item->set_in_view(1);
4222 if( first_in_view < 0 ) first_in_view = i;
4224 int item_color = get_item_highlight(data, 0, i);
4225 int icon_x, icon_y, icon_w, icon_h;
4226 int text_x, text_y, text_w, text_h;
4229 get_icon_mask(item, icon_x, icon_y, icon_w, icon_h);
4230 get_text_mask(item, text_x, text_y, text_w, text_h);
4233 if(item_color != resources->listbox_inactive)
4235 gui->set_color(BLACK);
4236 gui->draw_rectangle(icon_x, icon_y, icon_w, icon_h);
4237 gui->set_color(item_color);
4238 gui->draw_box(icon_x + 1, icon_y + 1, icon_w - 2, icon_h - 2);
4239 gui->set_color(BLACK);
4240 gui->draw_rectangle(text_x, text_y, text_w, text_h);
4241 gui->set_color(item_color);
4242 gui->draw_box(text_x + 1, text_y + 1, text_w - 2, text_h - 2);
4244 if(icon_position == ICON_LEFT)
4245 gui->draw_box(text_x - 1, text_y + 1, 2, text_h - 2);
4247 if(icon_position == ICON_TOP)
4248 gui->draw_line(text_x + 1, text_y, text_x + icon_w - 2, text_y);
4249 if(text_x + text_w < icon_x + icon_w)
4251 gui->set_color(BLACK);
4252 gui->draw_line(text_x + text_w,
4260 gui->set_color(get_item_color(data, 0, i));
4262 gui->pixmap->draw_pixmap(item->icon,
4263 icon_x + ICON_MARGIN,
4264 icon_y + ICON_MARGIN);
4267 gui->draw_text(text_x + ICON_MARGIN,
4268 text_y + ICON_MARGIN + get_baseline(item),
4272 item->set_in_view(0);
4278 // Draw one column at a time so text overruns don't go into the next column
4279 // clear column backgrounds
4280 int current_toggle = 0;
4281 for(int j = 0; j < columns; j++)
4283 clear_listbox(LISTBOX_BORDER + get_column_offset(j) - xposition,
4284 LISTBOX_BORDER + title_h,
4285 get_column_width(j, 1),
4287 // Draw rows in the column recursively
4288 draw_text_recursive(data, j, 0, ¤t_toggle);
4291 // Delete excess expanders
4292 while(expanders.total > current_toggle)
4294 expanders.remove_object();
4298 // draw user images if available
4300 // Draw titles on top of rows for superposition effect
4303 // Clear garbage from bottom right corner
4304 if(xscrollbar && yscrollbar && is_popup)
4306 gui->draw_top_background(parent_window,
4307 popup_w - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w(),
4308 popup_h - get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h(),
4309 get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w(),
4310 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h());
4317 if(current_operation == SELECT_RECT)
4327 void BC_ListBox::draw_text_recursive(ArrayList<BC_ListBoxItem*> *data,
4330 int *current_toggle)
4335 BC_Resources *resources = get_resources();
4337 set_font(MEDIUMFONT);
4340 // Search for a branch and make room for toggle if there is one
4343 for(int i = 0; i < data[column].size(); i++)
4345 if(data[column].get(i)->get_sublist())
4347 subindent = BC_WindowBase::get_resources()->listbox_expand[0]->get_w();
4353 row_height = row_ascent = row_descent = 0;
4354 for(int i = 0; i < data[column].total; i++)
4356 BC_ListBoxItem *item = data[column].values[i];
4357 int ht = get_text_h(item);
4358 if( ht > row_height ) row_height = ht;
4359 int bl = get_baseline(item);
4360 if( bl > row_ascent ) row_ascent = bl;
4362 if( dt > row_descent ) row_ascent = bl;
4365 for(int i = 0; i < data[column].size(); i++)
4368 BC_ListBoxItem *item = data[column].values[i];
4369 BC_ListBoxItem *first_item = data[master_column].values[i];
4371 if(get_item_y(item) >= -get_item_h(item) + title_h &&
4372 get_item_y(item) < view_h + title_h)
4374 int row_color = get_item_highlight(data, 0, i);
4375 int x, y, w, h, column_width;
4377 get_text_mask(item, x, y, w, h);
4378 column_width = get_column_width(column, 1);
4379 if(x + column_width > view_w + LISTBOX_BORDER * 2)
4380 column_width = view_w + LISTBOX_BORDER * 2 - x;
4382 if(row_color != resources->listbox_inactive)
4384 gui->set_color(row_color);
4385 gui->draw_box(x, y, column_width, h);
4386 gui->set_color(BLACK);
4387 int xx = x + column_width-1;
4388 gui->draw_line(x, y, xx, y);
4389 int hh = row_height;
4390 if( display_format == LISTBOX_ICON_LIST ) {
4391 int ih = get_icon_h(item);
4392 if( ih > hh ) hh = ih;
4395 gui->draw_line(x, yy, xx, yy);
4398 gui->set_color(get_item_color(data, column, i));
4401 if(column == 0 && display_format == LISTBOX_ICON_LIST)
4405 gui->pixmap->draw_pixmap(item->icon,
4408 x += item->icon->get_w() + ICON_MARGIN;
4413 // Indent only applies to first column
4415 x + LISTBOX_BORDER + LISTBOX_MARGIN +
4416 (column == 0 ? indent + subindent : 0),
4417 y + get_baseline(item), item->text);
4418 item->set_in_view(1);
4420 if( first_in_view < 0 ) first_in_view = i;
4426 item->get_sublist() &&
4427 item->get_columns())
4429 // Create new expander
4430 if(*current_toggle >= expanders.total)
4432 BC_ListBoxToggle *toggle =
4433 new BC_ListBoxToggle(this,
4435 x + LISTBOX_BORDER + LISTBOX_MARGIN + indent,
4438 expanders.append(toggle);
4441 // Reposition existing expander
4443 BC_ListBoxToggle *toggle = expanders.values[*current_toggle];
4444 //printf("BC_ListBox::draw_text_recursive 1 %d\n", *current_toggle);
4445 toggle->update(item,
4446 x + LISTBOX_BORDER + LISTBOX_MARGIN + indent,
4450 (*current_toggle)++;
4457 item->set_in_view(0);
4459 // Descend into sublist
4460 if(first_item->get_expand())
4462 draw_text_recursive(first_item->get_sublist(),
4464 indent + LISTBOX_INDENT,
4473 int BC_ListBox::draw_border(int flash)
4475 BC_Resources *resources = top_level->get_resources();
4476 gui->draw_3d_border(0,
4478 view_w + LISTBOX_BORDER * 2,
4479 view_h + title_h + LISTBOX_BORDER * 2,
4480 resources->listbox_border1,
4482 resources->listbox_border2_hi :
4483 resources->listbox_border2,
4485 resources->listbox_border3_hi :
4486 resources->listbox_border3,
4487 resources->listbox_border4);
4497 void BC_ListBox::draw_title(int number)
4499 // Column title background
4500 int image_number = 0;
4501 if(number == highlighted_title)
4504 if(current_operation == COLUMN_DN)
4508 int column_offset = get_column_offset(number) - xposition + LISTBOX_BORDER;
4509 int column_width = get_column_width(number, 1);
4510 gui->draw_3segmenth(get_column_offset(number) - xposition + LISTBOX_BORDER,
4512 get_column_width(number, 1) + get_resources()->listbox_title_overlap,
4513 column_bg[image_number]);
4515 // Column title sort order
4516 if(number == sort_column)
4519 if(sort_order == SORT_ASCENDING)
4520 src = column_sort_dn;
4522 src = column_sort_up;
4524 int x = column_offset +
4527 if(x > items_w) x = items_w;
4528 x -= 5 + src->get_w();
4529 gui->draw_pixmap(src,
4531 title_h / 2 - src->get_h() / 2 + LISTBOX_BORDER);
4535 int x = -xposition +
4536 get_column_offset(number) +
4539 x += get_resources()->listbox_title_margin;
4541 gui->set_color(get_resources()->listbox_title_color);
4543 LISTBOX_MARGIN + LISTBOX_BORDER + get_text_ascent(MEDIUMFONT),
4544 _(column_titles[number]));
4547 int BC_ListBox::draw_titles(int flash)
4550 (display_format == LISTBOX_TEXT ||
4551 display_format == LISTBOX_ICON_LIST))
4553 //printf("BC_ListBox::draw_titles 1 %d\n", highlighted_title);
4554 for(int i = 0; i < columns; i++)
4556 if(i != highlighted_title)
4560 if(highlighted_title >= 0) draw_title(highlighted_title);
4571 void BC_ListBox::draw_toggles(int flash)
4573 for(int i = 0; i < expanders.total; i++)
4574 expanders.values[i]->draw(0);
4576 //printf("BC_ListBox::draw_toggles 1 %d\n", flash);
4577 if(flash && expanders.total)
4584 int BC_ListBox::draw_rectangle(int flash)
4586 int x1 = MIN(rect_x1, rect_x2);
4587 int x2 = MAX(rect_x1, rect_x2);
4588 int y1 = MIN(rect_y1, rect_y2);
4589 int y2 = MAX(rect_y1, rect_y2);
4591 if(x1 == x2 || y1 == y2) return 0;
4594 gui->set_color(WHITE);
4595 gui->draw_rectangle(x1, y1, x2 - x1, y2 - y1);
4606 void BC_ListBox::dump(ArrayList<BC_ListBoxItem*> *data,
4613 printf("BC_ListBox::dump 1\n");
4616 for(int i = 0; i < data[master_column].total; i++)
4618 for(int k = 0; k < indent; k++)
4620 for(int j = 0; j < columns; j++)
4622 BC_ListBoxItem *item = data[j].values[i];
4623 printf("%d,%d,%d=%s ",
4626 item->autoplace_text,
4631 if(data[master_column].values[i]->get_sublist())
4633 dump(data[master_column].values[i]->get_sublist(),
4634 data[master_column].values[i]->get_columns(),