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
42 BC_ListBoxYScroll::BC_ListBoxYScroll(BC_ListBox *listbox,
46 : BC_ScrollBar(listbox->get_yscroll_x(),
47 listbox->get_yscroll_y(),
49 listbox->get_yscroll_height(),
54 this->listbox = listbox;
57 BC_ListBoxYScroll::~BC_ListBoxYScroll()
61 int BC_ListBoxYScroll::handle_event()
63 listbox->set_yposition(get_value());
73 BC_ListBoxXScroll::BC_ListBoxXScroll(BC_ListBox *listbox,
77 : BC_ScrollBar(listbox->get_xscroll_x(),
78 listbox->get_xscroll_y(),
80 listbox->get_xscroll_width(),
85 this->listbox = listbox;
88 BC_ListBoxXScroll::~BC_ListBoxXScroll()
92 int BC_ListBoxXScroll::handle_event()
94 listbox->set_xposition(get_value());
105 BC_ListBoxToggle::BC_ListBoxToggle(BC_ListBox *listbox,
106 BC_ListBoxItem *item,
110 this->listbox = listbox;
114 this->value = item->get_expand();
116 state = BC_Toggle::TOGGLE_CHECKED;
118 state = BC_Toggle::TOGGLE_UP;
121 void BC_ListBoxToggle::update(BC_ListBoxItem *item,
126 this->value = item->get_expand();
136 state = TOGGLE_CHECKED;
141 state = TOGGLE_CHECKEDHI;
152 case TOGGLE_CHECKEDHI:
157 case TOGGLE_DOWN_EXIT:
165 int BC_ListBoxToggle::cursor_motion_event(int *redraw_toggles)
167 int w = listbox->toggle_images[0]->get_w();
168 int h = listbox->toggle_images[0]->get_h();
169 int cursor_inside = listbox->get_cursor_x() >= x &&
170 listbox->get_cursor_x() < x + w &&
171 listbox->get_cursor_y() >= y &&
172 listbox->get_cursor_y() < y + h;
177 case BC_ListBoxToggle::TOGGLE_UPHI:
180 state = BC_ListBoxToggle::TOGGLE_UP;
185 case BC_ListBoxToggle::TOGGLE_CHECKEDHI:
188 state = BC_ListBoxToggle::TOGGLE_CHECKED;
193 case BC_ListBoxToggle::TOGGLE_DOWN:
196 state = BC_ListBoxToggle::TOGGLE_DOWN_EXIT;
202 case BC_ListBoxToggle::TOGGLE_DOWN_EXIT:
205 state = BC_ListBoxToggle::TOGGLE_DOWN;
215 state = BC_ListBoxToggle::TOGGLE_CHECKEDHI;
217 state = BC_ListBoxToggle::TOGGLE_UPHI;
225 int BC_ListBoxToggle::cursor_leave_event(int *redraw_toggles)
228 state = BC_ListBoxToggle::TOGGLE_CHECKED;
230 state = BC_ListBoxToggle::TOGGLE_UP;
234 int BC_ListBoxToggle::button_press_event()
236 int w = listbox->toggle_images[0]->get_w();
237 int h = listbox->toggle_images[0]->get_h();
239 if(listbox->gui->get_cursor_x() >= x &&
240 listbox->gui->get_cursor_x() < x + w &&
241 listbox->gui->get_cursor_y() >= y &&
242 listbox->gui->get_cursor_y() < y + h)
244 state = BC_ListBoxToggle::TOGGLE_DOWN;
250 int BC_ListBoxToggle::button_release_event(int *redraw_toggles)
256 case BC_ListBoxToggle::TOGGLE_DOWN:
259 state = BC_ListBoxToggle::TOGGLE_CHECKEDHI;
261 state = BC_ListBoxToggle::TOGGLE_UPHI;
262 listbox->expand_item(item, value);
266 case BC_ListBoxToggle::TOGGLE_DOWN_EXIT:
268 state = BC_ListBoxToggle::TOGGLE_CHECKED;
270 state = BC_ListBoxToggle::TOGGLE_UP;
278 void BC_ListBoxToggle::draw(int flash)
282 int image_number = 0;
283 int w = listbox->toggle_images[0]->get_w();
284 int h = listbox->toggle_images[0]->get_h();
288 case BC_ListBoxToggle::TOGGLE_UP: image_number = 0; break;
289 case BC_ListBoxToggle::TOGGLE_UPHI: image_number = 1; break;
290 case BC_ListBoxToggle::TOGGLE_CHECKED: image_number = 2; break;
291 case BC_ListBoxToggle::TOGGLE_DOWN: image_number = 3; break;
292 case BC_ListBoxToggle::TOGGLE_CHECKEDHI: image_number = 4; break;
293 case BC_ListBoxToggle::TOGGLE_DOWN_EXIT:
301 //printf("BC_ListBoxToggle::draw 1 %d\n", state);
302 listbox->gui->draw_pixmap(listbox->toggle_images[image_number],
309 listbox->gui->flash(x, y, w, h);
310 listbox->gui->flush();
328 // ====================================================== box
330 BC_ListBox::BC_ListBox(int x,
335 ArrayList<BC_ListBoxItem*> *data,
336 const char **column_titles,
344 : BC_SubWindow(x, y, w, h, -1)
346 justify = LISTBOX_RIGHT;
348 highlighted_item = -1;
349 highlighted_title = -1;
350 highlighted_division = -1;
354 current_cursor = ARROW_CURSOR;
367 selection_number1 = -1;
368 selection_number2 = -1;
371 row_height = row_ascent = row_descent = 0;
374 current_operation = NO_OPERATION;
375 button_highlighted = 0;
376 list_highlighted = 0;
379 allow_drag_scroll = 1;
385 allow_drag_column = 0;
392 for(int i = 0; i < 3; i++) column_bg[i] = 0;
393 for(int i = 0; i < 4; i++) button_images[i] = 0;
394 for(int i = 0; i < 5; i++) toggle_images[i] = 0;
399 //printf("BC_ListBox::BC_ListBox 1\n");
401 this->columns = columns;
402 this->yposition = yposition;
403 this->is_popup = is_popup;
404 this->use_button = 1;
405 this->display_format = display_format;
406 this->selection_mode = selection_mode;
407 this->icon_position = icon_position;
408 this->allow_drag = allow_drag;
409 this->column_titles = 0;
410 this->column_width = 0;
411 this->first_in_view = -1;
412 this->last_in_view = 0;
413 //printf("BC_ListBox::BC_ListBox 1\n");
415 if((!column_titles && column_width) ||
416 (column_titles && !column_width))
418 printf("BC_ListBox::BC_ListBox either column_titles or column_widths == NULL but not both.\n");
420 //printf("BC_ListBox::BC_ListBox 2 %p %p\n", column_titles, column_width);
422 set_columns(column_titles,
426 //printf("BC_ListBox::BC_ListBox 3\n");
428 drag_icon_vframe = 0;
429 drag_column_icon_vframe = 0;
433 // reset the search engine
434 //printf("BC_ListBox::BC_ListBox 4\n");
436 //printf("BC_ListBox::BC_ListBox 5\n");
439 BC_ListBox::~BC_ListBox()
441 expanders.remove_all_objects();
442 if(bg_surface) delete bg_surface;
443 if(bg_pixmap) delete bg_pixmap;
444 if(xscrollbar) delete xscrollbar;
445 if(yscrollbar) delete yscrollbar;
446 for(int i = 0; i < 3; i++) delete column_bg[i];
447 for(int i = 0; i < 4; i++) delete button_images[i];
448 for(int i = 0; i < 5; i++) delete toggle_images[i];
449 if(column_sort_up) delete column_sort_up;
450 if(column_sort_dn) delete column_sort_dn;
453 if(drag_popup) delete drag_popup;
456 int BC_ListBox::enable()
463 int BC_ListBox::disable()
470 void BC_ListBox::reset_query()
472 query[0] = 0; // reset query
475 int BC_ListBox::evaluate_query(char *string)
477 for(int i = 0; i < data[search_column].size(); i++)
479 if(strcmp(string, data[search_column].get(i)->text) <= 0 &&
480 data[search_column].get(i)->searchable)
489 int BC_ListBox::query_list()
491 if(query[0] == 0) return 0;
495 int selection_changed = 0;
496 int prev_selection = -1;
497 result = evaluate_query(query);
498 if(result >= 0) done = 1;
503 for(int i = 0; i < data[0].total; i++)
505 for(int j = 0; j < columns; j++)
507 if(data[j].values[i]->selected) prev_selection = i;
508 data[j].values[i]->selected = 0;
513 if(prev_selection != result)
514 selection_changed = 1;
515 for(int j = 0; j < columns; j++)
517 data[j].values[result]->selected = 1;
519 center_selection(result);
522 return selection_changed;
525 void BC_ListBox::init_column_width()
527 if(!column_width && data)
530 for(int i = 0; i < data[0].total; i++)
532 wd = get_text_w(data[0].values[i]);
533 if( wd > widest ) widest = wd;
535 default_column_width[0] = widest + 2 * LISTBOX_MARGIN;
539 int BC_ListBox::initialize()
545 for( int i = 0; i < 4; ++i )
547 button_images[i] = new BC_Pixmap(parent_window,
548 BC_WindowBase::get_resources()->listbox_button[i],
551 w = button_images[0]->get_w();
552 h = button_images[0]->get_h();
556 current_operation = NO_OPERATION;
562 current_operation = NO_OPERATION;
565 for(int i = 0; i < 3; i++)
567 column_bg[i] = new BC_Pixmap(parent_window,
568 get_resources()->listbox_column[i],
571 for(int i = 0; i < 5; i++)
573 toggle_images[i] = new BC_Pixmap(parent_window,
574 get_resources()->listbox_expand[i],
578 column_sort_up = new BC_Pixmap(parent_window,
579 BC_WindowBase::get_resources()->listbox_up,
581 column_sort_dn = new BC_Pixmap(parent_window,
582 BC_WindowBase::get_resources()->listbox_dn,
585 //printf("BC_ListBox::initialize 10\n");
586 drag_icon_vframe = get_resources()->type_to_icon[ICON_UNKNOWN];
587 drag_column_icon_vframe = get_resources()->type_to_icon[ICON_COLUMN];
588 // = new BC_Pixmap(parent_window,
589 // get_resources()->type_to_icon[ICON_UNKNOWN],
591 // drag_column_icon = new BC_Pixmap(parent_window,
592 // get_resources()->type_to_icon[ICON_COLUMN],
594 BC_SubWindow::initialize();
598 if(top_level->get_resources()->listbox_bg)
599 bg_pixmap = new BC_Pixmap(this,
600 get_resources()->listbox_bg,
606 if(!use_button && is_popup)
615 void BC_ListBox::deactivate_selection()
617 current_operation = NO_OPERATION;
620 int BC_ListBox::draw_button(int flush)
622 // Draw the button for a popup listbox
623 if(use_button && is_popup)
625 int image_number = 0;
627 draw_top_background(parent_window, 0, 0, w, h);
629 if(button_highlighted)
631 if(current_operation == BUTTON_DN)
637 pixmap->draw_pixmap(button_images[image_number],
649 int BC_ListBox::calculate_item_coords()
657 // Change the display_format to get the right item dimensions for both
659 temp_display_format = display_format;
662 // Scan the first column for lowest y coord of all text
663 // and lowest right x and y coord for all icons which aren't auto placable
664 calculate_last_coords_recursive(data,
671 // Reset last column width. It's recalculated based on text width.
673 calculate_item_coords_recursive(data,
682 display_format = temp_display_format;
687 void BC_ListBox::calculate_last_coords_recursive(
688 ArrayList<BC_ListBoxItem*> *data,
695 for(int i = 0; i < data[0].size(); i++)
697 int current_text_y = 0;
698 int current_icon_x = 0;
699 int current_icon_y = 0;
700 BC_ListBoxItem *item = data[0].get(i);
703 if(!item->autoplace_text)
705 // Lowest text coordinate
706 display_format = LISTBOX_TEXT;
707 current_text_y = item->text_y + get_text_h(item);
708 if(current_text_y > *next_text_y)
709 *next_text_y = current_text_y;
711 // Add sublist depth if it is expanded
712 if(item->get_sublist() &&
713 item->get_columns() &&
716 calculate_last_coords_recursive(item->get_sublist(),
725 // Get next_icon coordinate
728 BC_ListBoxItem *item = data[master_column].get(i);
729 if(!item->autoplace_icon)
731 display_format = LISTBOX_ICONS;
732 // Lowest right icon coordinate.
733 current_icon_x = item->icon_x;
734 if(current_icon_x > *icon_x) *icon_x = current_icon_x;
735 if(current_icon_x + get_item_w(item) > *next_icon_x) {
736 *next_icon_x = current_icon_x + get_item_w(item);
739 current_icon_y = item->icon_y + get_item_h(item);
740 if(current_icon_y > *next_icon_y)
741 *next_icon_y = current_icon_y;
748 void BC_ListBox::calculate_item_coords_recursive(
749 ArrayList<BC_ListBoxItem*> *data,
756 // get maximum height of an icon
757 row_height = get_text_height(MEDIUMFONT);
758 if(temp_display_format == LISTBOX_ICON_LIST)
760 for(int i = 0; i < data[0].size(); i++)
762 if(data[0].get(i)->icon)
764 if(data[0].get(i)->icon->get_h() > row_height)
765 row_height = data[0].get(i)->icon->get_h();
771 // Set up items which need autoplacement.
772 // Should fill icons down and then across
773 for(int i = 0; i < data[0].size(); i++)
775 // Don't increase y unless the row requires autoplacing.
776 int total_autoplaced_columns = 0;
778 // Set up icons in first column
781 BC_ListBoxItem *item = data[master_column].get(i);
782 if(item->autoplace_icon)
784 // 1 column only if icons are used
785 display_format = LISTBOX_ICONS;
788 if(*next_icon_y + get_item_h(item) >= get_h() &&
791 *icon_x = *next_icon_x;
795 if(*icon_x + get_item_w(item) > *next_icon_x)
796 *next_icon_x = *icon_x + get_item_w(item);
799 item->set_icon_x(*icon_x);
800 item->set_icon_y(*next_icon_y);
802 *next_icon_y += get_item_h(item);
810 row_ascent = row_descent = 0;
811 // row_height still holds icon max height
812 for(int j = 0; j < columns; j++)
814 BC_ListBoxItem *item = data[j].get(i);
815 if(item->autoplace_text)
817 display_format = LISTBOX_TEXT;
818 item->set_text_x(next_text_x);
819 item->set_text_y(*next_text_y);
820 int ht = get_text_h(item);
821 if( ht > row_height ) row_height = ht;
822 int bl = get_baseline(item);
823 if( bl > row_ascent ) row_ascent = bl;
825 if( dt > row_descent ) row_ascent = bl;
827 // printf("BC_ListBox::calculate_item_coords_recursive %p %d %d %d %d %s \n",
828 // item->get_sublist(),
829 // item->get_columns(),
830 // item->get_expand(),
833 // item->get_text());
834 // Increment position of next column
837 next_text_x += (column_width ?
839 default_column_width[j]);
842 // Set last column width based on text width
844 int new_w = get_item_w(item);
846 int *previous_w = (column_width ?
848 &default_column_width[j]);
849 if(new_w > *previous_w)
851 //printf("BC_ListBox::calculate_item_coords_recursive 1 %d\n", new_w);
853 total_autoplaced_columns++;
857 // Increase the text vertical position
858 if(total_autoplaced_columns)
860 display_format = LISTBOX_TEXT;
861 *next_text_y += row_height;
865 BC_ListBoxItem *item = data[master_column].values[i];
866 if(item->get_sublist() &&
867 item->get_columns() &&
870 calculate_item_coords_recursive(
881 void BC_ListBox::set_is_suggestions(int value)
883 this->is_suggestions = value;
886 void BC_ListBox::set_use_button(int value)
888 this->use_button = value;
891 void BC_ListBox::set_justify(int value)
893 this->justify = value;
896 void BC_ListBox::set_allow_drag_column(int value)
898 this->allow_drag_column = value;
901 void BC_ListBox::set_process_drag(int value)
903 this->process_drag = value;
906 void BC_ListBox::set_master_column(int value, int redraw)
908 this->master_column = value;
915 void BC_ListBox::set_search_column(int value)
917 this->search_column = value;
920 int BC_ListBox::get_sort_column()
925 void BC_ListBox::set_sort_column(int value, int redraw)
934 int BC_ListBox::get_sort_order()
939 void BC_ListBox::set_sort_order(int value, int redraw)
952 int BC_ListBox::get_display_mode()
954 return display_format;
957 int BC_ListBox::get_yposition()
962 int BC_ListBox::get_xposition()
967 int BC_ListBox::get_highlighted_item()
969 return highlighted_item;
973 int BC_ListBox::get_item_x(BC_ListBoxItem *item)
975 if(display_format == LISTBOX_TEXT)
977 return item->text_x - xposition + 2;
980 if(display_format == LISTBOX_ICON_LIST)
982 return item->text_x - xposition + 2;
986 return item->icon_x - xposition + 2;
990 int BC_ListBox::get_item_y(BC_ListBoxItem *item)
993 if(display_format == LISTBOX_TEXT)
995 result = item->text_y - yposition + title_h + 2;
998 if(display_format == LISTBOX_ICON_LIST)
1000 result = item->text_y - yposition + title_h + 2;
1004 result = item->icon_y - yposition + title_h + 2;
1010 int BC_ListBox::get_item_w(BC_ListBoxItem *item)
1012 if(display_format == LISTBOX_ICONS)
1015 get_icon_mask(item, x, y, w, h);
1017 get_text_mask(item, x, y, w, h);
1020 return icon_position == ICON_LEFT ? icon_w + text_w :
1021 icon_w > text_w ? icon_w : text_w;
1023 return get_text_w(item) + 2 * LISTBOX_MARGIN;
1026 int BC_ListBox::get_item_h(BC_ListBoxItem *item)
1028 if(display_format == LISTBOX_ICONS)
1031 get_icon_mask(item, x, y, w, h);
1033 get_text_mask(item, x, y, w, h);
1036 return icon_position != ICON_LEFT ? icon_h + text_h :
1037 icon_h > text_h ? icon_h : text_h;
1039 return get_text_h(item);
1043 int BC_ListBox::get_icon_w(BC_ListBoxItem *item)
1045 return item->get_icon_w();
1048 int BC_ListBox::get_icon_h(BC_ListBoxItem *item)
1050 return item->get_icon_h();
1053 int BC_ListBox::get_text_w(BC_ListBoxItem *item)
1055 int w = item->get_text_w();
1056 if( w < 0 ) item->set_text_w(w = get_text_width(MEDIUMFONT, item->get_text()));
1060 int BC_ListBox::get_text_h(BC_ListBoxItem *item)
1062 int h = item->get_text_h();
1063 if( h < 0 ) item->set_text_h(h = get_text_height(MEDIUMFONT));
1067 int BC_ListBox::get_baseline(BC_ListBoxItem *item)
1069 int b = item->get_baseline();
1070 if( b < 0 ) item->set_baseline(b = get_text_ascent(MEDIUMFONT));
1074 int BC_ListBox::get_items_width()
1078 if(display_format == LISTBOX_ICONS)
1080 for(int i = 0; i < columns; i++)
1082 for(int j = 0; j < data[i].total; j++)
1085 BC_ListBoxItem *item = data[i].values[j];
1088 get_icon_mask(item, x, y, w, h);
1089 if(x1 + w > widest) widest = x1 + w;
1091 if(display_format == LISTBOX_ICONS && icon_position == ICON_LEFT)
1094 get_text_mask(item, x, y, w, h);
1095 if(x1 + w > widest) widest = x1 + w;
1100 if(display_format == LISTBOX_TEXT)
1102 return get_column_offset(columns);
1106 return get_column_offset(columns);
1111 int BC_ListBox::get_items_height(ArrayList<BC_ListBoxItem*> *data,
1128 for(int j = 0; j < (data ? data[master_column].total : 0); j++)
1131 BC_ListBoxItem *item = data[master_column].values[j];
1133 if(display_format == LISTBOX_ICONS)
1135 get_icon_mask(item, x, y, w, h);
1136 if(y + h + yposition > highest) highest = y + h + yposition;
1138 get_text_mask(item, x, y, w, h);
1139 if(y + h + yposition > highest) highest = y + h + yposition;
1143 get_text_mask(item, x, y, w, h);
1147 // Descend into sublist
1148 if(item->get_sublist() &&
1151 get_items_height(item->get_sublist(),
1152 item->get_columns(),
1158 if((display_format == LISTBOX_TEXT ||
1159 display_format == LISTBOX_ICON_LIST) &&
1162 highest = LISTBOX_MARGIN + *result;
1169 int BC_ListBox::set_yposition(int position, int draw_items)
1171 this->yposition = position;
1174 this->draw_items(1);
1179 int BC_ListBox::set_xposition(int position)
1181 this->xposition = position;
1186 void BC_ListBox::expand_item(BC_ListBoxItem *item, int expand)
1190 item->expand = expand;
1191 // Collapse sublists if this is collapsed to make it easier to calculate
1193 if(item->get_sublist())
1194 collapse_recursive(item->get_sublist(), master_column);
1197 // Set everything for autoplacement
1199 set_autoplacement(data, 0, 1);
1205 void BC_ListBox::collapse_recursive(ArrayList<BC_ListBoxItem*> *data,
1208 for(int i = 0; i < data[master_column].total; i++)
1210 BC_ListBoxItem *item = data[master_column].values[i];
1211 if(item->get_sublist() && item->expand)
1214 collapse_recursive(item->get_sublist(), master_column);
1219 void BC_ListBox::set_autoplacement(ArrayList<BC_ListBoxItem*> *data,
1223 for(int i = 0; i < data[0].total; i++)
1225 for(int j = 0; j < columns; j++)
1227 if(do_icons) data[j].values[i]->autoplace_icon = 1;
1228 if(do_text) data[j].values[i]->autoplace_text = 1;
1231 BC_ListBoxItem *item = data[master_column].values[i];
1232 if(item->get_sublist())
1234 set_autoplacement(item->get_sublist(), do_icons, do_text);
1241 int BC_ListBox::get_yscroll_x()
1244 return popup_w - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w();
1248 get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w();
1251 int BC_ListBox::get_yscroll_y()
1259 int BC_ListBox::get_yscroll_height()
1261 return popup_h - (need_xscroll ?
1262 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h() :
1266 int BC_ListBox::get_xscroll_x()
1274 int BC_ListBox::get_xscroll_y()
1278 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h();
1282 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h();
1285 int BC_ListBox::get_xscroll_width()
1287 return popup_w - (need_yscroll ?
1288 get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w() :
1292 int BC_ListBox::get_column_offset(int column)
1298 column_width[--column] :
1299 default_column_width[--column];
1304 void BC_ListBox::column_width_boundaries()
1307 for(int i = 0; i < columns; i++) {
1308 if(column_width[i] < MIN_COLUMN_WIDTH)
1309 column_width[i] = MIN_COLUMN_WIDTH;
1313 for(int i = 0; i < columns; i++) {
1314 if(default_column_width[i] < MIN_COLUMN_WIDTH)
1315 default_column_width[i] = MIN_COLUMN_WIDTH;
1320 int BC_ListBox::get_column_width(int column, int clamp_right)
1322 if(column < columns - 1 || !clamp_right)
1323 return column_width ? column_width[column] : default_column_width[column];
1324 return popup_w + xposition - get_column_offset(column);
1327 int BC_ListBox::get_icon_mask(BC_ListBoxItem *item,
1328 int &x, int &y, int &w, int &h)
1330 if( display_format == LISTBOX_ICONS ) {
1331 x = get_item_x(item);
1332 y = get_item_y(item);
1333 w = get_icon_w(item) + ICON_MARGIN * 2;
1334 h = get_icon_h(item) + ICON_MARGIN * 2;
1341 int BC_ListBox::get_text_mask(BC_ListBoxItem *item,
1342 int &x, int &y, int &w, int &h)
1344 x = get_item_x(item);
1345 y = get_item_y(item);
1347 if(display_format == LISTBOX_ICONS) {
1348 if(icon_position == ICON_LEFT) {
1349 x += get_icon_w(item) + ICON_MARGIN * 2;
1350 y += get_icon_h(item) - get_text_h(item);
1353 y += get_icon_h(item) + ICON_MARGIN;
1356 w = get_text_w(item) + ICON_MARGIN * 2;
1357 h = get_text_h(item) + ICON_MARGIN * 2;
1360 if(display_format == LISTBOX_TEXT) {
1361 w = get_text_w(item) + LISTBOX_MARGIN * 2;
1362 h = get_text_h(item);
1366 w = get_text_width(MEDIUMFONT, item->text) + LISTBOX_MARGIN * 2;
1372 int BC_ListBox::get_item_highlight(ArrayList<BC_ListBoxItem*> *data,
1376 BC_Resources *resources = get_resources();
1377 if(data[column].values[item]->selected)
1378 return resources->listbox_selected;
1379 else if(highlighted_item >= 0 &&
1380 highlighted_ptr == data[master_column].values[item])
1381 return resources->listbox_highlighted;
1382 return resources->listbox_inactive;
1385 int BC_ListBox::get_item_color(ArrayList<BC_ListBoxItem*> *data,
1389 int color = data[column].values[item]->color;
1390 if( color == -1 ) color = get_resources()->listbox_text;
1391 if( get_item_highlight(data, column, item) == color )
1396 int BC_ListBox::get_from_column()
1398 return dragged_title;
1401 int BC_ListBox::get_to_column()
1403 return highlighted_title;
1407 BC_ListBoxItem* BC_ListBox::get_selection(int column,
1408 int selection_number)
1410 return get_selection_recursive(data,
1415 BC_ListBoxItem* BC_ListBox::get_selection_recursive(
1416 ArrayList<BC_ListBoxItem*> *data,
1418 int selection_number)
1422 for(int i = 0; i < data[master_column].total; i++)
1424 BC_ListBoxItem *item = data[master_column].values[i];
1427 //printf("BC_ListBox::get_selection_recursive %d\n", __LINE__);
1429 if(selection_number < 0)
1432 return data[column].values[i];
1436 if(item->get_sublist())
1438 BC_ListBoxItem *result = get_selection_recursive(item->get_sublist(),
1441 if(result) return result;
1449 int BC_ListBox::get_selection_number(int column,
1450 int selection_number)
1452 return get_selection_number_recursive(data,
1457 int BC_ListBox::get_selection_number_recursive(
1458 ArrayList<BC_ListBoxItem*> *data,
1460 int selection_number,
1465 if(!counter) counter = &temp;
1467 for(int i = 0; i < data[master_column].total; i++)
1470 BC_ListBoxItem *item = data[master_column].values[i];
1474 if(selection_number < 0)
1479 if(item->get_sublist())
1481 int result = get_selection_number_recursive(
1482 item->get_sublist(),
1486 if(result >= 0) return result;
1493 int BC_ListBox::set_selection_mode(int mode)
1495 this->selection_mode = mode;
1499 void BC_ListBox::delete_columns()
1503 for(int i = 0; i < columns; i++)
1505 delete [] column_titles[i];
1507 delete [] column_titles;
1510 if(column_width) delete [] column_width;
1516 // Need to copy titles so EDL can change
1517 void BC_ListBox::set_columns(const char **column_titles,
1521 if((!column_titles && column_width) ||
1522 (column_titles && !column_width))
1524 printf("BC_ListBox::set_columns either column_titles or column_width == NULL but not both.\n");
1533 this->column_titles = new char*[columns];
1534 for(int i = 0; i < columns; i++)
1536 this->column_titles[i] = new char[strlen(column_titles[i]) + 1];
1537 strcpy(this->column_titles[i], column_titles[i]);
1543 this->column_width = new int[columns];
1544 for(int i = 0; i < columns; i++)
1546 this->column_width[i] = column_width[i];
1550 this->columns = columns;
1555 int BC_ListBox::update(ArrayList<BC_ListBoxItem*> *data,
1556 const char **column_titles,
1561 int highlighted_number,
1562 int recalc_positions,
1565 set_columns(column_titles,
1571 this->yposition = yposition;
1572 this->xposition = xposition;
1573 this->highlighted_item = highlighted_number;
1574 this->highlighted_ptr = index_to_item(data, highlighted_number, 0);
1576 if(recalc_positions)
1577 set_autoplacement(data, 1, 1);
1579 init_column_width();
1584 update_scrollbars(1);
1590 void BC_ListBox::center_selection()
1592 int selection = get_selection_number(0, 0);
1594 calculate_item_coords();
1595 center_selection(selection);
1601 update_scrollbars(0);
1602 gui->show_window(1);
1606 void BC_ListBox::move_vertical(int pixels)
1610 void BC_ListBox::move_horizontal(int pixels)
1614 int BC_ListBox::select_previous(int skip,
1615 BC_ListBoxItem *selected_item,
1617 ArrayList<BC_ListBoxItem*> *data,
1623 selected_item = get_selection(0, 0);
1635 got_second = &temp3;
1639 // Scan backwards to item pointer. Then count visible items to get
1640 // destination. No wraparound.
1643 for(int i = data[master_column].total - 1; i >= 0; i--)
1645 BC_ListBoxItem *current_item = data[master_column].values[i];
1646 if(current_item->get_sublist() &&
1647 current_item->get_expand())
1649 int result = select_previous(skip,
1652 current_item->get_sublist(),
1664 if((*counter) >= skip)
1666 for(int j = 0; j < columns; j++)
1667 data[j].values[i]->selected = 1;
1669 return item_to_index(this->data, current_item);
1674 if(current_item->selected)
1676 for(int j = 0; j < columns; j++)
1677 data[j].values[i]->selected = 0;
1684 // Hit top of top level without finding a selected item.
1687 // Select first item in top level and quit
1688 BC_ListBoxItem *current_item;
1690 current_item = data[master_column].values[0];
1692 for(int j = 0; j < columns; j++)
1693 data[j].values[0]->selected = 1;
1695 return item_to_index(this->data, current_item);
1697 }while(top_level && data[master_column].total);
1701 int BC_ListBox::select_next(int skip,
1702 BC_ListBoxItem *selected_item,
1704 ArrayList<BC_ListBoxItem*> *data,
1710 selected_item = get_selection(0, 0);
1722 got_second = &temp3;
1726 // Scan forwards to currently selected item pointer.
1727 // Then count visible items to get destination. No wraparound.
1730 for(int i = 0; i < data[master_column].total; i++)
1732 BC_ListBoxItem *current_item = data[master_column].values[i];
1734 // Select next item once the number items after the currently selected item
1735 // have been passed.
1739 if((*counter) >= skip)
1741 for(int j = 0; j < columns; j++)
1742 data[j].values[i]->selected = 1;
1744 return item_to_index(this->data, current_item);
1749 // Got currently selected item. Deselect it.
1750 if(current_item->selected)
1752 for(int j = 0; j < columns; j++)
1753 data[j].values[i]->selected = 0;
1759 // Descend into expanded level
1760 if(current_item->get_sublist() &&
1761 current_item->get_expand())
1763 int result = select_next(skip,
1766 current_item->get_sublist(),
1776 // Hit bottom of top level without finding the next item.
1779 BC_ListBoxItem *current_item;
1780 // Select first item in top level and quit
1784 current_item = data[master_column].values[0];
1786 for(int j = 0; j < columns; j++)
1787 data[j].values[0]->selected = 1;
1792 // Select last item in top level and quit
1794 int current_row = data[master_column].total - 1;
1795 current_item = data[master_column].values[current_row];
1797 for(int j = 0; j < columns; j++)
1798 data[j].values[current_row]->selected = 1;
1802 return item_to_index(this->data, current_item);
1804 }while(top_level && data[master_column].total);
1810 void BC_ListBox::clamp_positions()
1812 items_w = get_items_width();
1813 items_h = get_items_height(data, columns);
1815 if(yposition < 0) yposition = 0;
1817 if(yposition > items_h - view_h)
1818 yposition = items_h - view_h;
1820 if(yposition < 0) yposition = 0;
1822 if(xposition < 0) xposition = 0;
1824 if(xposition >= items_w - view_w)
1825 xposition = items_w - view_w;
1827 if(xposition < 0) xposition = 0;
1830 int BC_ListBox::center_selection(int selection,
1831 ArrayList<BC_ListBoxItem*> *data,
1835 if(!data) data = this->data;
1836 if(!counter) counter = &temp;
1838 for(int i = 0; i < data[master_column].total; i++)
1843 BC_ListBoxItem *item = data[master_column].values[i];
1844 if((*counter) == selection)
1846 BC_ListBoxItem *top_item = this->data[master_column].values[0];
1849 if(display_format == LISTBOX_ICONS)
1851 // Icon is out of window
1852 if( item->icon_y-yposition > view_h-get_text_h(item) ||
1853 item->icon_y-yposition < 0 ) {
1854 yposition = item->icon_y - view_h / 2;
1857 if(data[master_column].values[selection]->icon_x - xposition > view_w ||
1858 data[master_column].values[selection]->icon_x - xposition < 0)
1860 xposition = item->icon_x - view_w / 2;
1865 // Text coordinate is out of window
1866 if( item->text_y-yposition > view_h-get_text_h(item) ||
1867 item->text_y-yposition < 0 ) {
1868 yposition = item->text_y -
1877 if(item->get_sublist())
1879 int result = center_selection(selection,
1880 item->get_sublist(),
1882 if(result) return result;
1888 void BC_ListBox::update_scrollbars(int flush)
1890 int h_needed = items_h = get_items_height(data, columns);
1891 int w_needed = items_w = get_items_width();
1893 // if(columns > 0 && column_width)
1894 // printf("BC_ListBox::update_scrollbars 1 %d %d\n", column_width[columns - 1], w_needed);
1898 if(xposition != xscrollbar->get_value())
1899 xscrollbar->update_value(xposition);
1901 if(w_needed != xscrollbar->get_length() ||
1902 view_w != xscrollbar->get_handlelength())
1903 xscrollbar->update_length(w_needed, xposition, view_w, 0);
1908 if(yposition != yscrollbar->get_value())
1909 yscrollbar->update_value(yposition);
1911 if(h_needed != yscrollbar->get_length() || view_h != yscrollbar->get_handlelength())
1912 yscrollbar->update_length(h_needed, yposition, view_h, 0);
1915 if(flush) this->flush();
1918 int BC_ListBox::get_scrollbars()
1920 int h_needed = items_h = get_items_height(data, columns);
1921 int w_needed = items_w = get_items_width();
1925 title_h = get_title_h();
1927 view_h = popup_h - title_h - 4;
1928 view_w = popup_w - 4;
1930 // Create scrollbars as needed
1931 for(int i = 0; i < 2; i++)
1933 if(w_needed > view_w)
1938 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h() -
1946 if(h_needed > view_h)
1950 get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w() -
1959 // Update subwindow size
1960 int new_w = popup_w;
1961 int new_h = popup_h;
1962 if(need_xscroll) new_h -= get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h();
1963 if(need_yscroll) new_w -= get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w();
1966 if(new_w != BC_WindowBase::get_w() || new_h != BC_WindowBase::get_h())
1967 gui->resize_window(new_w, new_h);
1969 BC_WindowBase *destination = (is_popup ? gui : parent_window);
1974 destination->add_subwindow(xscrollbar =
1975 new BC_ListBoxXScroll(this,
1979 xscrollbar->show_window(0);
1980 xscrollbar->bound_to = this;
1984 xscrollbar->update_length(w_needed, xposition, view_w, flush);
1985 xscrollbar->reposition_window(get_xscroll_x(),
1987 get_xscroll_width());
1992 if(xscrollbar) delete xscrollbar;
2001 destination->add_subwindow(yscrollbar =
2002 new BC_ListBoxYScroll(this,
2006 yscrollbar->show_window(0);
2007 yscrollbar->bound_to = this;
2011 yscrollbar->update_length(h_needed, yposition, view_h, flush);
2012 yscrollbar->reposition_window(get_yscroll_x(),
2014 get_yscroll_height());
2019 if(yscrollbar) delete yscrollbar;
2025 view_w + 4 != bg_surface->get_w() ||
2026 view_h + 4 != bg_surface->get_h())
2028 if(bg_surface) delete bg_surface;
2029 bg_surface = new BC_Pixmap(gui, view_w + 4, view_h + 4);
2039 void BC_ListBox::set_drag_scroll(int value)
2041 allow_drag_scroll = value;
2045 // Test for scrolling by dragging
2047 int BC_ListBox::test_drag_scroll(int cursor_x, int cursor_y)
2050 if(allow_drag_scroll ||
2051 current_operation == SELECT_RECT)
2054 int top_boundary = get_title_h();
2056 if(cursor_y < top_boundary ||
2057 cursor_y >= view_h + title_h + LISTBOX_BORDER * 2 ||
2058 cursor_x < LISTBOX_BORDER ||
2059 cursor_x >= view_w + LISTBOX_BORDER)
2067 int BC_ListBox::drag_scroll_event()
2069 int top_boundary = get_title_h();
2072 if(get_cursor_y() < top_boundary)
2074 yposition -= top_boundary - get_cursor_y();
2078 if(get_cursor_y() >= view_h + title_h + 4)
2080 yposition += get_cursor_y() - (view_h + title_h + 4);
2084 if(get_cursor_x() < 2)
2086 xposition -= 2 - get_cursor_x();
2090 if(get_cursor_x() >= view_w + 2)
2092 xposition += get_cursor_x() - (view_w + 2);
2095 if(result) clamp_positions();
2099 int BC_ListBox::rectangle_scroll_event()
2101 int old_xposition = xposition;
2102 int old_yposition = yposition;
2103 int result = drag_scroll_event();
2107 rect_x1 += old_xposition - xposition;
2108 rect_y1 += old_yposition - yposition;
2109 rect_x2 = get_cursor_x();
2110 rect_y2 = get_cursor_y();
2112 int x1 = MIN(rect_x1, rect_x2);
2113 int x2 = MAX(rect_x1, rect_x2);
2114 int y1 = MIN(rect_y1, rect_y2);
2115 int y2 = MAX(rect_y1, rect_y2);
2117 if(select_rectangle(data,
2123 selection_changed();
2128 update_scrollbars(1);
2133 int BC_ListBox::select_scroll_event()
2135 int result = drag_scroll_event();
2139 highlighted_item = selection_number = get_cursor_item(data,
2145 update_scrollbars(1);
2146 selection_changed();
2151 int BC_ListBox::select_rectangle(ArrayList<BC_ListBoxItem*> *data,
2158 for(int i = 0; i < data[master_column].total; i++)
2160 for(int j = 0; j < columns; j++)
2162 BC_ListBoxItem *item = data[j].values[i];
2163 if(display_format == LISTBOX_ICONS)
2165 int icon_x, icon_y, icon_w, icon_h;
2166 int text_x, text_y, text_w, text_h;
2167 get_icon_mask(item, icon_x, icon_y, icon_w, icon_h);
2168 get_text_mask(item, text_x, text_y, text_w, text_h);
2170 if((x2 >= icon_x && x1 < icon_x + icon_w &&
2171 y2 >= icon_y && y1 < icon_y + icon_h) ||
2172 (x2 >= text_x && x1 < text_x + text_w &&
2173 y2 >= text_y && y1 < text_y + text_h))
2194 gui->get_w() - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w() :
2197 y1 < gui->get_h() &&
2198 y2 >= get_item_y(item) &&
2199 y1 < get_item_y(item) + get_item_h(item))
2218 BC_ListBoxItem *item = data[master_column].values[i];
2219 if(item->get_sublist() &&
2221 result |= select_rectangle(item->get_sublist(),
2230 int BC_ListBox::reposition_item(ArrayList<BC_ListBoxItem*> *data,
2231 int selection_number,
2237 if(!counter) counter = &temp;
2240 for(int i = 0; i < data[master_column].total; i++)
2242 BC_ListBoxItem *item = data[master_column].values[i];
2244 if((*counter) == selection_number)
2250 // Not recursive because it's only used for icons
2255 void BC_ListBox::move_selection(ArrayList<BC_ListBoxItem*> *dst,
2256 ArrayList<BC_ListBoxItem*> *src)
2258 for(int i = 0; i < src[master_column].total; i++)
2260 BC_ListBoxItem *item = src[master_column].values[i];
2265 for(int j = 0; j < columns; j++)
2267 dst[j].append(src[j].values[i]);
2268 src[j].remove_number(i);
2272 // Descend into sublist
2273 if(item->get_sublist())
2276 item->get_sublist());
2281 int BC_ListBox::put_selection(ArrayList<BC_ListBoxItem*> *data,
2282 ArrayList<BC_ListBoxItem*> *src,
2287 if(!counter) counter = &temp;
2291 for(int j = 0; j < columns; j++)
2293 for(int i = 0; i < src[j].total; i++)
2295 data[j].append(src[j].values[i]);
2301 for(int i = 0; i < data[master_column].total; i++)
2304 if((*counter) == destination)
2306 for(int j = 0; j < columns; j++)
2308 for(int k = 0; k < src[j].total; k++)
2310 data[j].insert(src[j].values[k], destination + k);
2316 BC_ListBoxItem *item = data[master_column].values[i];
2317 if(item->get_sublist())
2319 if(put_selection(item->get_sublist(),
2331 int BC_ListBox::item_to_index(ArrayList<BC_ListBoxItem*> *data,
2332 BC_ListBoxItem *item,
2336 if(!counter) counter = &temp;
2338 for(int i = 0; i < data[master_column].total; i++)
2341 for(int j = 0; j < columns; j++)
2343 BC_ListBoxItem *new_item = data[j].values[i];
2344 //printf("BC_ListBox::item_to_index 1 %d %d %p\n", j, i, new_item);
2345 if(new_item == item)
2351 BC_ListBoxItem *new_item = data[master_column].values[i];
2352 if(new_item->get_sublist())
2354 if(item_to_index(new_item->get_sublist(),
2364 BC_ListBoxItem* BC_ListBox::index_to_item(ArrayList<BC_ListBoxItem*> *data,
2370 if(!counter) counter = &temp;
2371 for(int i = 0; i < data[master_column].total; i++)
2374 if((*counter) == number)
2376 return data[column].values[i];
2378 BC_ListBoxItem *item = data[master_column].values[i];
2379 if(item->get_sublist())
2381 BC_ListBoxItem *result = index_to_item(item->get_sublist(),
2385 if(result) return result;
2391 int BC_ListBox::get_cursor_item(ArrayList<BC_ListBoxItem*> *data,
2394 BC_ListBoxItem **item_return,
2399 if(!data) return -1;
2400 if(!counter) counter = &temp;
2402 // Icons are not treed
2403 if(display_format == LISTBOX_ICONS)
2405 for(int j = data[master_column].total - 1; j >= 0; j--)
2407 int icon_x, icon_y, icon_w, icon_h;
2408 int text_x, text_y, text_w, text_h;
2409 BC_ListBoxItem *item = data[master_column].values[j];
2410 get_icon_mask(item, icon_x, icon_y, icon_w, icon_h);
2411 get_text_mask(item, text_x, text_y, text_w, text_h);
2413 if((cursor_x >= icon_x && cursor_x < icon_x + icon_w &&
2414 cursor_y >= icon_y && cursor_y < icon_y + icon_h) ||
2415 (cursor_x >= text_x && cursor_x < text_x + text_w &&
2416 cursor_y >= text_y && cursor_y < text_y + text_h))
2418 if(item_return) (*item_return) = item;
2425 // Cursor is inside items rectangle
2427 cursor_x < (yscrollbar ?
2428 gui->get_w() - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w() :
2430 // Only clamp y if we're not in a SELECT operation.
2431 (current_operation == BC_ListBox::SELECT ||
2432 (cursor_y > get_title_h() + LISTBOX_BORDER &&
2433 cursor_y < gui->get_h())))
2435 // Search table for cursor obstruction
2436 for(int i = 0; i < data[master_column].total; i++)
2438 BC_ListBoxItem *item = data[master_column].values[i];
2441 // Cursor is inside item on current level
2444 cursor_y >= get_item_y(item) &&
2445 cursor_y < get_item_y(item) + get_item_h(item))
2447 //printf("BC_ListBox::get_cursor_item %d %d %p\n", master_column, i, item);
2448 if(item_return) (*item_return) = item;
2452 // Descend into sublist
2453 if(item->get_sublist())
2455 if(get_cursor_item(item->get_sublist(),
2460 item->get_expand()) >= 0)
2469 int BC_ListBox::repeat_event(int64_t duration)
2471 switch(current_operation)
2473 // Repeat out of bounds selection
2475 if(duration == get_resources()->scroll_repeat)
2476 return rectangle_scroll_event();
2480 if(duration == get_resources()->scroll_repeat)
2481 return select_scroll_event();
2486 if(button_highlighted && is_popup && !tooltip_done &&
2487 tooltip_text && tooltip_text[0] != 0 &&
2488 duration == get_resources()->tooltip_delay)
2500 int BC_ListBox::cursor_enter_event()
2504 switch(current_operation)
2506 // Cursor moved over button, pressed, and exited.
2507 case BUTTON_DOWN_SELECT:
2508 if(top_level->event_win == win)
2510 current_operation = BUTTON_DN;
2512 button_highlighted = 1;
2518 // Cursor entered button
2519 if(is_popup && top_level->event_win == win)
2521 button_highlighted = 1;
2526 // TODO: Need to get the highlighted column title or item
2527 if(gui && top_level->event_win == gui->win)
2529 list_highlighted = 1;
2539 int BC_ListBox::cursor_leave_event()
2541 if(current_operation == COLUMN_DRAG) return 0;
2544 if(button_highlighted)
2546 button_highlighted = 0;
2551 if(list_highlighted)
2553 list_highlighted = 0;
2554 highlighted_item = -1;
2555 highlighted_ptr = 0;
2556 highlighted_title = -1;
2557 int redraw_toggles = 0;
2558 for(int i = 0; i < expanders.total; i++)
2559 expanders.values[i]->cursor_leave_event(&redraw_toggles);
2567 int BC_ListBox::get_first_selection(ArrayList<BC_ListBoxItem*> *data, int *result)
2570 if(!result) result = &temp;
2572 for(int i = 0; i < data[master_column].total; i++)
2574 BC_ListBoxItem *item = data[master_column].values[i];
2576 if(item->selected) return (*result);
2577 if(item->get_sublist())
2579 if(get_first_selection(item->get_sublist(), result) >= 0)
2586 int BC_ListBox::get_total_items(ArrayList<BC_ListBoxItem*> *data,
2591 if(!result) result = &temp;
2593 for(int i = 0; i < data[master_column].total; i++)
2596 if(data[master_column].values[i]->get_sublist())
2597 get_total_items(data[master_column].values[i]->get_sublist(),
2606 int BC_ListBox::get_last_selection(ArrayList<BC_ListBoxItem*> *data,
2617 for(int i = data[master_column].total - 1; i >= 0; i--)
2619 BC_ListBoxItem *item = data[master_column].values[i];
2624 return get_total_items(data, 0, master_column) - (*result) /* - 1 */;
2629 if(item->get_sublist())
2631 if(get_last_selection(item->get_sublist(), result) >= 0)
2634 return get_total_items(data, 0, master_column) - (*result) /* - 1 */;
2643 void BC_ListBox::select_range(ArrayList<BC_ListBoxItem*> *data,
2649 if(!current) current = &temp;
2651 for(int i = 0; i < data[master_column].total; i++)
2654 if((*current) >= start && (*current) < end)
2656 for(int j = 0; j < columns; j++)
2657 data[j].values[i]->selected = 1;
2659 BC_ListBoxItem *item = data[master_column].values[i];
2660 if(item->get_sublist())
2661 select_range(item->get_sublist(),
2669 // Fill items between current selection and new selection
2670 int BC_ListBox::expand_selection(int button_press, int selection_number)
2672 int old_selection_start = selection_start;
2673 int old_selection_end = selection_end;
2675 // printf("BC_ListBox::expand_selection %d %d\n",
2676 // selection_center,
2677 // selection_number);
2679 // Calculate the range to select based on selection_center and selection_number
2680 if(selection_number < selection_center)
2682 selection_start = selection_number;
2686 selection_end = selection_number + 1;
2689 //printf("BC_ListBox::expand_selection %d %d %d %d\n", old_selection_start, old_selection_end, selection_start, selection_end);
2690 // Recurse through all the items and select the desired range
2691 select_range(data, selection_start, selection_end);
2694 return (old_selection_start != selection_start ||
2695 old_selection_end != selection_end);
2698 int BC_ListBox::toggle_item_selection(ArrayList<BC_ListBoxItem*> *data,
2699 int selection_number,
2703 if(!counter) counter = &temp;
2705 for(int i = 0; i < data[master_column].total; i++)
2707 BC_ListBoxItem *item = data[master_column].values[i];
2709 if((*counter) == selection_number)
2711 // Get new value for selection
2712 int selected = !item->selected;
2714 for(int j = 0; j < columns; j++)
2715 data[j].values[i]->selected = selected;
2719 // Descend into sublist
2720 if(item->get_sublist())
2722 if(toggle_item_selection(item->get_sublist(),
2733 void BC_ListBox::set_all_selected(ArrayList<BC_ListBoxItem*> *data, int value)
2735 for(int i = 0; i < data[master_column].total; i++)
2737 for(int j = 0; j < columns; j++)
2739 BC_ListBoxItem *item = data[j].values[i];
2740 item->selected = value;
2742 BC_ListBoxItem *item = data[master_column].values[i];
2743 if(item->get_sublist())
2745 set_all_selected(item->get_sublist(), value);
2750 void BC_ListBox::set_selected(ArrayList<BC_ListBoxItem*> *data,
2756 if(!counter) counter = &temp;
2757 for(int i = 0; i < data[master_column].total && (*counter) != item_number; i++)
2760 if((*counter) == item_number)
2762 for(int j = 0; j < columns; j++)
2764 BC_ListBoxItem *item = data[j].values[i];
2765 item->selected = value;
2770 BC_ListBoxItem *item = data[master_column].values[i];
2771 if(item->get_sublist())
2773 set_selected(item->get_sublist(),
2781 int BC_ListBox::update_selection(ArrayList<BC_ListBoxItem*> *data,
2782 int selection_number,
2787 if(!counter) counter = &temp;
2789 for(int i = 0; i < data[master_column].total; i++)
2791 BC_ListBoxItem *item = data[master_column].values[i];
2793 if((*counter) == selection_number && !item->selected)
2796 for(int j = 0; j < columns; j++)
2797 data[j].values[i]->selected = 1;
2800 if((*counter) != selection_number && item->selected)
2803 for(int j = 0; j < columns; j++)
2804 data[j].values[i]->selected = 0;
2806 if(item->get_sublist())
2807 result |= update_selection(item->get_sublist(),
2814 void BC_ListBox::promote_selections(ArrayList<BC_ListBoxItem*> *data,
2818 for(int i = 0; i < data[master_column].total; i++)
2820 for(int j = 0; j < columns; j++)
2822 BC_ListBoxItem *item = data[j].values[i];
2823 if(item->selected == old_value) item->selected = new_value;
2825 BC_ListBoxItem *item = data[master_column].values[i];
2826 if(item->get_sublist())
2827 promote_selections(item->get_sublist(), old_value, new_value);
2831 int BC_ListBox::focus_out_event()
2837 int BC_ListBox::button_press_event()
2840 BC_ListBoxItem *current_item = 0;
2842 int do_selection_change = 0;
2843 const int debug = 0;
2846 if(debug) printf("BC_ListBox::button_press_event %d this=%p event_win=%p %p %p %p\n",
2849 (void*)top_level->event_win,
2850 (void*)(gui ? gui->win : 0),
2852 (void*)parent_window->win);
2854 // Pressed in button
2855 if(is_popup && top_level->event_win == win)
2857 if(debug) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2858 current_operation = BUTTON_DN;
2862 if(!active && !disabled)
2864 top_level->deactivate();
2871 // Pressed in scrollbar
2872 if((xscrollbar && top_level->event_win == xscrollbar->win) ||
2873 (yscrollbar && top_level->event_win == yscrollbar->win))
2875 if(debug) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2880 if(gui && top_level->event_win == gui->win)
2882 if(debug) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2884 // Activate list items
2885 // If it is a suggestion popup, it is visible without being active
2888 if(debug) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2889 if(!is_suggestions) top_level->deactivate();
2890 if(debug) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2892 if(debug) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2895 // Wheel mouse pressed
2896 if(get_buttonpress() == 4)
2898 if(current_operation == NO_OPERATION)
2900 current_operation = WHEEL;
2903 set_yposition(yposition - gui->get_h() / 10, 0);
2905 update_scrollbars(0);
2906 highlighted_ptr = 0;
2907 highlighted_item = get_cursor_item(data,
2908 top_level->cursor_x,
2909 top_level->cursor_y,
2917 if(get_buttonpress() == 5)
2919 if(current_operation == NO_OPERATION)
2921 current_operation = WHEEL;
2924 set_yposition(yposition + gui->get_h() / 10, 0);
2926 update_scrollbars(0);
2927 highlighted_ptr = 0;
2928 highlighted_item = get_cursor_item(data,
2929 top_level->cursor_x,
2930 top_level->cursor_y,
2938 // Pressed over column title division
2939 if(test_column_divisions(gui->get_cursor_x(),
2940 gui->get_cursor_y(),
2943 drag_cursor_x = gui->get_cursor_x() + xposition;
2945 drag_column_w = column_width[highlighted_division - 1];
2947 drag_column_w = default_column_width[highlighted_division - 1];
2949 current_operation = DRAG_DIVISION;
2953 // Pressed in column title
2954 if(test_column_titles(gui->get_cursor_x(), gui->get_cursor_y()))
2956 current_operation = COLUMN_DN;
2957 button_highlighted = 0;
2958 list_highlighted = 1;
2963 // Pressed in expander
2964 if(test_expanders())
2966 current_operation = EXPAND_DN;
2967 // Need to redraw items because of alpha
2972 // Pressed over item
2973 if((selection_number = get_cursor_item(data,
2974 gui->get_cursor_x(),
2975 gui->get_cursor_y(),
2976 ¤t_item)) >= 0)
2978 if(debug) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2980 // Get item button was pressed over
2981 selection_number2 = selection_number1;
2982 selection_number1 = selection_number;
2984 selection_start = -1;
2988 // Multiple item selection is possible
2989 if(selection_mode == LISTBOX_MULTIPLE &&
2990 (ctrl_down() || shift_down()))
2992 // Expand text selection.
2993 // Fill items between selected region and current item.
2995 (display_format == LISTBOX_TEXT ||
2996 display_format == LISTBOX_ICON_LIST))
2998 // Get first item selected
2999 selection_start = get_first_selection(data);
3000 // Get last item selected
3001 selection_end = get_last_selection(data);
3002 // Get center of selected region
3003 if(selection_end > selection_start)
3005 selection_center = (selection_end + selection_start) >> 1;
3009 selection_center = selection_number;
3013 // Deselect everything.
3014 set_all_selected(data, 0);
3015 // Select just the items
3016 expand_selection(1, selection_number);
3020 // Toggle a single item on or off
3022 toggle_item_selection(data, selection_number);
3023 new_value = current_item->selected;
3027 // Select single item
3029 if(!current_item->selected)
3031 set_all_selected(data, 0);
3040 current_operation = SELECT;
3041 highlighted_item = selection_number;
3042 highlighted_ptr = current_item;
3043 button_highlighted = 0;
3044 list_highlighted = 1;
3047 do_selection_change = 1;
3052 // Pressed over nothing. Start rectangle selection.
3054 if(get_buttonpress() == 1 &&
3055 selection_mode == LISTBOX_MULTIPLE)
3059 // Deselect all and redraw if anything was selected
3060 if(get_selection_number(0, 0) >= 0)
3062 set_all_selected(data, 0);
3064 do_selection_change = 1;
3070 // Promote selections to protect from a rectangle selection
3071 promote_selections(data, 1, 2);
3074 // Start rectangle selection
3075 current_operation = SELECT_RECT;
3076 rect_x1 = rect_x2 = get_cursor_x();
3077 rect_y1 = rect_y2 = get_cursor_y();
3085 // Suggestion box is not active but visible, so lie to get it to deactivate
3086 if(is_popup && (active || (is_suggestions && gui)))
3089 if(debug) printf("BC_ListBox::button_press_event %d\n", __LINE__);
3095 if(do_selection_change) selection_changed();
3096 if(debug) printf("BC_ListBox::button_press_event %d %d\n",
3103 int BC_ListBox::button_release_event()
3106 int cursor_x, cursor_y;
3110 //printf("BC_ListBox::button_release_event 1 %d\n", current_operation);
3111 switch(current_operation)
3114 current_operation = NO_OPERATION;
3119 current_operation = NO_OPERATION;
3123 // Release item selection
3124 case BUTTON_DOWN_SELECT:
3126 //printf("BC_ListBox::button_release_event 10\n");
3127 unset_repeat(get_resources()->scroll_repeat);
3128 current_operation = NO_OPERATION;
3130 translate_coordinates(top_level->event_win, gui->win,
3131 gui->get_cursor_x(), gui->get_cursor_y(),
3132 &cursor_x, &cursor_y);
3133 selection_number1 = selection_number =
3134 get_cursor_item(data, cursor_x, cursor_y);
3135 //printf("BC_ListBox::button_release_event %d %d\n", selection_number2, selection_number1);
3141 if(selection_number >= 0)
3147 // Second button release outside button
3148 if(button_releases > 1)
3155 if(top_level->get_double_click() &&
3156 selection_number2 == selection_number1 &&
3157 selection_number2 >= 0 &&
3158 selection_number1 >= 0)
3168 unset_repeat(get_resources()->scroll_repeat);
3171 // Demote selections from rectangle selection
3172 promote_selections(data, 2, 1);
3175 // Hide rectangle overlay
3177 current_operation = NO_OPERATION;
3181 // Release popup button
3184 current_operation = NO_OPERATION;
3188 // Second button release inside button
3189 if(button_releases > 1)
3197 current_operation = NO_OPERATION;
3198 // Update the sort column and the sort order for the user only if the existing
3199 // sort column is valid.
3200 if(sort_column >= 0)
3202 // Invert order only if column is the same
3203 if(highlighted_title == sort_column)
3205 (sort_order == SORT_ASCENDING) ?
3208 // Set the new sort column
3209 sort_column = highlighted_title;
3210 if(!sort_order_event())
3216 // Sorting not enabled. Redraw the title state.
3225 int redraw_toggles = 0;
3226 for(int i = 0; i < expanders.total && !result; i++)
3228 if(expanders.values[i]->button_release_event(&redraw_toggles))
3233 // Need to redraw items because of alpha
3234 if(redraw_toggles) draw_items(1);
3235 current_operation = NO_OPERATION;
3240 // Can't default to NO_OPERATION because it may be used in a drag event.
3245 if(do_event) handle_event();
3247 //printf("BC_ListBox::button_release_event %d %d\n", __LINE__, get_window_lock());
3251 int BC_ListBox::get_title_h()
3253 if(display_format == LISTBOX_TEXT ||
3254 display_format == LISTBOX_ICON_LIST)
3255 return column_titles ? column_bg[0]->get_h() : 0;
3260 void BC_ListBox::reset_cursor(int new_cursor)
3264 if(gui->get_cursor() != new_cursor)
3266 gui->set_cursor(new_cursor, 0, 0);
3270 if(get_cursor() != new_cursor)
3272 set_cursor(new_cursor, 0, 0);
3276 int BC_ListBox::test_column_divisions(int cursor_x, int cursor_y, int &new_cursor)
3281 cursor_y < get_title_h() &&
3283 cursor_x < gui->get_w())
3285 for(int i = 1; i < columns; i++)
3287 if(cursor_x >= -xposition + get_column_offset(i) - 5 &&
3288 cursor_x < -xposition + get_column_offset(i) +
3289 get_resources()->listbox_title_hotspot)
3291 highlighted_item = -1;
3292 highlighted_ptr = 0;
3293 highlighted_division = i;
3294 highlighted_title = -1;
3295 list_highlighted = 1;
3296 new_cursor = HSEPARATE_CURSOR;
3301 highlighted_division = -1;
3305 int BC_ListBox::test_column_titles(int cursor_x, int cursor_y)
3310 cursor_y < get_title_h() &&
3312 cursor_x < gui->get_w())
3314 for(int i = 0; i < columns; i++)
3316 if(cursor_x >= -xposition + get_column_offset(i) &&
3317 (cursor_x < -xposition + get_column_offset(i + 1) ||
3320 highlighted_item = -1;
3321 highlighted_ptr = 0;
3322 highlighted_division = -1;
3323 highlighted_title = i;
3324 list_highlighted = 1;
3329 highlighted_title = -1;
3333 int BC_ListBox::test_expanders()
3335 for(int i = 0; i < expanders.total; i++)
3337 if(expanders.values[i]->button_press_event())
3339 current_operation = EXPAND_DN;
3347 int BC_ListBox::cursor_motion_event()
3349 int redraw = 0, result = 0;
3350 int new_cursor = ARROW_CURSOR;
3352 selection_number = -1;
3355 switch(current_operation)
3358 // Button pressed and slid off button
3359 if(!cursor_inside())
3361 current_operation = BUTTON_DOWN_SELECT;
3369 // int new_w = get_cursor_x() +
3371 // get_column_offset(highlighted_division - 1);
3372 int difference = get_cursor_x() + xposition - drag_cursor_x;
3373 int new_w = drag_column_w + difference;
3375 new_cursor = HSEPARATE_CURSOR;
3379 column_width[highlighted_division - 1] = new_w;
3383 default_column_width[highlighted_division - 1] = new_w;
3386 column_width_boundaries();
3388 // Force update of coords
3389 set_autoplacement(data, 0, 1);
3390 column_resize_event();
3394 update_scrollbars(1);
3401 if(test_drag_scroll(get_cursor_x(), get_cursor_y()))
3403 set_repeat(get_resources()->scroll_repeat);
3406 int old_x1 = MIN(rect_x1, rect_x2);
3407 int old_x2 = MAX(rect_x1, rect_x2);
3408 int old_y1 = MIN(rect_y1, rect_y2);
3409 int old_y2 = MAX(rect_y1, rect_y2);
3411 int new_rect_x2 = get_cursor_x();
3412 int new_rect_y2 = get_cursor_y();
3414 int x1 = MIN(rect_x1, new_rect_x2);
3415 int x2 = MAX(rect_x1, new_rect_x2);
3416 int y1 = MIN(rect_y1, new_rect_y2);
3417 int y2 = MAX(rect_y1, new_rect_y2);
3419 // Adjust rectangle coverage
3427 redraw = select_rectangle(data,
3437 //printf("BC_ListBox::cursor_motion_event %d\n", __LINE__);
3442 rect_x2 = get_cursor_x();
3443 rect_y2 = get_cursor_y();
3448 update_scrollbars(1);
3449 selection_changed();
3450 //printf("BC_ListBox::cursor_motion_event %d\n", __LINE__);
3458 //printf("BC_ListBox::cursor_motion_event %d\n", __LINE__);
3468 int old_highlighted_item = highlighted_item;
3470 if(test_drag_scroll(get_cursor_x(),
3473 set_repeat(get_resources()->scroll_repeat);
3477 highlighted_item = selection_number = get_cursor_item(data,
3483 // Deselect all items and select just the one we're over
3484 if(selection_number >= 0 &&
3488 selection_mode == LISTBOX_SINGLE))
3490 redraw = update_selection(data, selection_number);
3493 if(selection_mode == LISTBOX_MULTIPLE &&
3494 (shift_down() || ctrl_down()))
3495 // Expand multiple selection
3497 // Expand selected region in text mode centered around initial range
3498 if((display_format == LISTBOX_TEXT ||
3499 display_format == LISTBOX_ICON_LIST) &&
3502 // Deselect everything.
3503 set_all_selected(data, 0);
3505 // Select just the items
3506 redraw = expand_selection(0, selection_number);
3509 // Set the one item we're over to the selection value determined in
3510 // button_press_event.
3518 if(highlighted_item != old_highlighted_item)
3522 update_scrollbars(1);
3523 //printf("BC_ListBox::cursor_motion_event %d %d\n", highlighted_item, old_highlighted_item);
3524 selection_changed();
3529 case BUTTON_DOWN_SELECT:
3530 // Went back into button area
3533 current_operation = BUTTON_DN;
3538 // Went into item area
3541 int cursor_x = 0, cursor_y = 0;
3542 translate_coordinates(top_level->event_win,
3544 top_level->cursor_x,
3545 top_level->cursor_y,
3548 int old_highlighted_item = highlighted_item;
3549 highlighted_item = selection_number = get_cursor_item(data,
3554 if(highlighted_item != old_highlighted_item)
3556 update_selection(data, selection_number);
3558 selection_changed();
3565 int redraw_toggles = 0;
3566 for(int i = 0; i < expanders.total && !result; i++)
3568 result = expanders.values[i]->cursor_motion_event(
3573 // Need to redraw items because of the alpha
3581 int cursor_x = get_cursor_x(), cursor_y = get_cursor_y();
3582 if(gui && top_level->event_win == gui->win)
3584 int old_highlighted_title = highlighted_title;
3585 int old_list_highlighted = list_highlighted;
3586 int old_highlighted_item = highlighted_item;
3587 int redraw_titles = 0;
3588 int redraw_border = 0;
3589 int redraw_items = 0;
3590 int redraw_toggles = 0;
3594 // Test if cursor moved over a title division
3595 test_column_divisions(cursor_x, cursor_y, new_cursor);
3597 // Test if cursor moved over a title
3598 if(highlighted_division < 0)
3600 test_column_titles(cursor_x, cursor_y);
3603 // Test if cursor moved over expander
3604 if(highlighted_division < 0 &&
3605 highlighted_title < 0 &&
3606 (display_format == LISTBOX_TEXT ||
3607 display_format == LISTBOX_ICON_LIST))
3609 for(int i = 0; i < expanders.total; i++)
3611 expanders.values[i]->cursor_motion_event(
3614 //printf("BC_ListBox::cursor_motion_event %d\n", redraw_toggles);
3617 // Test if cursor moved over an item
3618 if(highlighted_division < 0 &&
3619 highlighted_title < 0)
3621 highlighted_item = get_cursor_item(data,
3628 // Clear title highlighting if moved over division
3629 if(old_highlighted_title != highlighted_title)
3634 // Highlight list border
3635 if(old_list_highlighted != list_highlighted)
3640 // Moved out of item area
3641 if(old_highlighted_item != highlighted_item)
3646 //printf("BC_ListBox::cursor_motion_event 1 %d\n", highlighted_item);
3648 // Change cursor to title division adjustment
3649 reset_cursor(new_cursor);
3676 if(!result && list_highlighted)
3678 list_highlighted = 0;
3679 highlighted_item = -1;
3680 highlighted_ptr = 0;
3681 highlighted_title = -1;
3682 highlighted_division = -1;
3694 int BC_ListBox::drag_start_event()
3696 switch(current_operation)
3700 gui->is_event_win() &&
3703 BC_ListBoxItem *item_return = 0;
3704 selection_number = get_cursor_item(data,
3705 top_level->cursor_x,
3706 top_level->cursor_y,
3709 if(selection_number >= 0)
3712 if (item_return->icon_vframe)
3714 drag_popup = new BC_DragWindow(this,
3715 item_return->icon_vframe /*,
3716 get_abs_cursor_x(0) - item_return->icon_vframe->get_w() / 2,
3717 get_abs_cursor_y(0) - item_return->icon_vframe->get_h() / 2 */);
3720 // this probably works not!
3721 if (item_return->icon)
3723 drag_popup = new BC_DragWindow(this,
3724 item_return->icon /*,
3725 get_abs_cursor_x(0) - item_return->icon->get_w() / 2,
3726 get_abs_cursor_y(0) - item_return->icon->get_h() / 2 */);
3730 drag_popup = new BC_DragWindow(this,
3731 drag_icon_vframe /*,
3732 get_abs_cursor_x(0) - drag_icon_vframe->get_w() / 2,
3733 get_abs_cursor_y(0) - drag_icon_vframe->get_h() / 2 */);
3736 current_operation = DRAG_ITEM;
3743 if(gui && gui->is_event_win() && allow_drag_column)
3745 drag_popup = new BC_DragWindow(this,
3746 drag_column_icon_vframe /*,
3747 get_abs_cursor_x(0) - drag_column_icon_vframe->get_w() / 2,
3748 get_abs_cursor_y(0) - drag_column_icon_vframe->get_h() / 2 */);
3749 dragged_title = highlighted_title;
3750 current_operation = COLUMN_DRAG;
3760 int BC_ListBox::drag_motion_event()
3762 //printf("BC_ListBox::drag_motion_event 1 %d\n", current_operation);
3763 switch(current_operation)
3768 int new_highlighted_item = -1;
3769 BC_ListBoxItem *new_highlighted_ptr = 0;
3770 new_highlighted_item = get_cursor_item(data,
3771 top_level->cursor_x, top_level->cursor_y,
3772 &new_highlighted_ptr);
3774 if(new_highlighted_item != highlighted_item)
3779 // Always update highlighted value for drag_stop
3780 highlighted_item = new_highlighted_item;
3781 highlighted_ptr = new_highlighted_ptr;
3782 //printf("BC_ListBox::drag_motion_event 1 %p\n", highlighted_ptr);
3787 update_scrollbars(1);
3790 return drag_popup->cursor_motion_event();
3796 int old_highlighted_title = highlighted_title;
3797 test_column_titles(get_cursor_x(), get_cursor_y());
3798 if(old_highlighted_title != highlighted_title)
3802 return drag_popup->cursor_motion_event();
3809 int BC_ListBox::drag_stop_event()
3811 switch(current_operation)
3814 // Inside window boundary
3815 if(top_level->cursor_x > 0 &&
3816 top_level->cursor_x < gui->get_w() - drag_popup->get_w() / 2 &&
3817 top_level->cursor_y > 0 &&
3818 top_level->cursor_y < gui->get_h() - drag_popup->get_h() / 2)
3823 if(display_format == LISTBOX_ICONS)
3825 reposition_item(data,
3827 top_level->cursor_x +
3828 drag_popup->get_offset_x() -
3832 top_level->cursor_y +
3833 drag_popup->get_offset_y() -
3843 int destination = highlighted_item = item_to_index(data,
3845 //printf("BC_ListBox::drag_stop_event 1 %p %d\n", highlighted_ptr, destination);
3847 // Move selected items from data to temporary
3848 ArrayList<BC_ListBoxItem*> *src_items =
3849 new ArrayList<BC_ListBoxItem*>[columns];
3851 move_selection(src_items, data);
3853 // Insert items from temporary to data
3859 delete [] src_items;
3860 set_autoplacement(data, 0, 1);
3867 drag_popup->drag_failure_event();
3872 current_operation = NO_OPERATION;
3878 if(dragged_title != highlighted_title)
3880 if(highlighted_title >= 0)
3882 if(!move_column_event()) draw_titles(1);
3885 drag_popup->drag_failure_event();
3887 current_operation = NO_OPERATION;
3897 BC_DragWindow* BC_ListBox::get_drag_popup()
3902 int BC_ListBox::translation_event()
3906 int new_x = gui->get_x() +
3907 (top_level->last_translate_x - top_level->prev_x -
3908 BC_DisplayInfo::get_left_border());
3909 int new_y = gui->get_y() +
3910 (top_level->last_translate_y - top_level->prev_y -
3911 BC_DisplayInfo::get_top_border());
3913 gui->reposition_window(new_x, new_y);
3919 int BC_ListBox::reposition_window(int x, int y, int w, int h, int flush)
3923 if(w != -1) popup_w = w;
3924 if(h != -1) popup_h = h;
3925 //printf("BC_ListBox::reposition_window %d %d\n", popup_w, popup_h);
3929 if(w != -1) popup_w = w;
3930 if(h != -1) popup_h = h;
3932 xscrollbar->reposition_window(get_xscroll_x(),
3934 get_xscroll_width());
3936 yscrollbar->reposition_window(get_yscroll_x(),
3938 get_yscroll_height());
3943 BC_WindowBase::reposition_window(x, y, w, h);
3949 int BC_ListBox::deactivate()
3951 // printf("BC_ListBox::deactivate %d this=%p gui=%p active=%d\n",
3961 //printf("BC_ListBox::deactivate %d this=%p gui=%p\n", __LINE__, this, gui);
3970 highlighted_item = -1;
3971 highlighted_ptr = 0;
3976 //printf("BC_ListBox::deactivate %d this=%p\n", __LINE__, this);
3978 top_level->active_subwindow = 0;
3984 int BC_ListBox::activate(int take_focus)
3986 //printf("BC_ListBox::activate %d %p\n", __LINE__, this);
3991 top_level->active_subwindow = this;
3995 button_releases = 0;
3997 // Test for existence of GUI in case this was previously called without
3998 // take_focus & again with take_focus
3999 if(is_popup && !gui)
4004 y = get_y() + get_h();
4005 if(justify == LISTBOX_RIGHT)
4007 x = get_x() - popup_w + get_w();
4015 XTranslateCoordinates(top_level->display,
4024 if(new_x < 0) new_x = 0;
4025 if(new_y + popup_h > top_level->get_root_h(0))
4026 new_y -= get_h() + popup_h;
4028 add_subwindow(gui = new BC_Popup(this,
4036 // Avoid top going out of screen
4039 //printf("BC_ListBox::activate %d this=%p %p\n", __LINE__, this, gui->win);
4041 gui->show_window(1);
4043 //printf("BC_ListBox::activate %d %p\n", __LINE__, this);
4049 int BC_ListBox::keypress_event()
4051 if(!active) return 0;
4053 //printf("BC_ListBox::keypress_event %d\n", __LINE__);
4055 int result = 0, redraw = 0;
4056 int view_items = last_in_view - first_in_view + 1;
4057 if( view_items <= 0 ) view_items = view_h / get_text_height(MEDIUMFONT);
4058 int new_item = -1, new_selection = -1;
4060 switch(top_level->get_keypress())
4065 top_level->deactivate();
4067 // If user is manipulating popup with keyboard, don't pass on event.
4070 //printf("BC_ListBox::keypress_event %d %p\n", __LINE__, get_selection(0, 0));
4071 if(top_level->get_keypress() == RETURN)
4073 //printf("BC_ListBox::keypress_event %d %p\n", __LINE__, get_selection(0, 0));
4081 new_selection = new_item = select_previous(0);
4083 //printf("BC_ListBox::keypress_event 1 %d\n", new_item);
4086 center_selection(new_item);
4094 new_selection = new_item = select_next(0);
4098 center_selection(new_item);
4106 new_selection = new_item = select_previous(view_items - 1);
4110 center_selection(new_item);
4118 new_selection = new_item = select_next(view_items - 1);
4122 center_selection(new_item);
4150 int query_len = strlen(query);
4151 if( query_len < (int)sizeof(query)-1 &&
4152 top_level->get_keypress() > 30 &&
4153 top_level->get_keypress() < 127)
4155 query[query_len++] = top_level->get_keypress();
4156 query[query_len] = 0;
4157 new_selection = query_list();
4160 if(top_level->get_keypress() == BACKSPACE)
4162 if(query_len > 0) query[--query_len] = 0;
4163 new_selection = query_list();
4176 update_scrollbars(1);
4179 //printf("BC_ListBox::keypress_event %d new_selection=%d\n", __LINE__, new_selection);
4180 if(new_selection >= 0 && !is_suggestions)
4182 //printf("BC_ListBox::keypress_event %d\n", __LINE__);
4183 selection_changed();
4184 //printf("BC_ListBox::keypress_event %d\n", __LINE__);
4191 BC_Pixmap* BC_ListBox::get_bg_surface()
4197 void BC_ListBox::draw_background()
4199 if( !bg_draw ) return;
4201 // White background pixmap
4202 set_color(top_level->get_resources()->listbox_inactive);
4203 draw_box(0, 0, bg_surface->get_w(), bg_surface->get_h(), bg_surface);
4205 // Optional heroine pixmap
4207 bg_surface->draw_pixmap(bg_pixmap,
4208 bg_surface->get_w() - top_level->get_resources()->listbox_bg->get_w(),
4212 void BC_ListBox::clear_listbox(int x, int y, int w, int h)
4214 gui->draw_pixmap(bg_surface, x, y, w, h, x, y - title_h);
4217 void BC_ListBox::update_format(int display_format, int redraw)
4219 this->display_format = display_format;
4220 if( redraw && gui ) draw_items(1, 1);
4223 int BC_ListBox::get_format()
4225 return display_format;
4230 int BC_ListBox::draw_items(int flush, int draw_bg)
4234 BC_Resources *resources = get_resources();
4236 //dump(data, columns);
4238 // Calculate items width
4239 calculate_item_coords();
4242 // Create and destroy scrollbars as needed
4247 if( bg_draw ) this->bg_draw = 1;
4253 if(display_format == LISTBOX_ICONS)
4255 clear_listbox(2, 2 + title_h, view_w, view_h);
4257 set_font(MEDIUMFONT);
4258 for(int i = 0; i < data[master_column].size(); i++)
4260 BC_ListBoxItem *item = data[master_column].get(i);
4261 if(get_item_x(item) >= -get_item_w(item) &&
4262 get_item_x(item) < view_w &&
4263 get_item_y(item) >= -get_item_h(item) + title_h &&
4264 get_item_y(item) < view_h + title_h)
4266 item->set_in_view(1);
4267 if( first_in_view < 0 ) first_in_view = i;
4269 int item_color = get_item_highlight(data, 0, i);
4270 int icon_x, icon_y, icon_w, icon_h;
4271 int text_x, text_y, text_w, text_h;
4274 get_icon_mask(item, icon_x, icon_y, icon_w, icon_h);
4275 get_text_mask(item, text_x, text_y, text_w, text_h);
4278 if(item_color != resources->listbox_inactive)
4280 gui->set_color(BLACK);
4281 gui->draw_rectangle(icon_x, icon_y, icon_w, icon_h);
4282 gui->set_color(item_color);
4283 gui->draw_box(icon_x + 1, icon_y + 1, icon_w - 2, icon_h - 2);
4284 gui->set_color(BLACK);
4285 gui->draw_rectangle(text_x, text_y, text_w, text_h);
4286 gui->set_color(item_color);
4287 gui->draw_box(text_x + 1, text_y + 1, text_w - 2, text_h - 2);
4289 if(icon_position == ICON_LEFT)
4290 gui->draw_box(text_x - 1, text_y + 1, 2, text_h - 2);
4292 if(icon_position == ICON_TOP)
4293 gui->draw_line(text_x + 1, text_y, text_x + icon_w - 2, text_y);
4294 if(text_x + text_w < icon_x + icon_w)
4296 gui->set_color(BLACK);
4297 gui->draw_line(text_x + text_w,
4305 gui->set_color(get_item_color(data, 0, i));
4307 gui->pixmap->draw_pixmap(item->icon,
4308 icon_x + ICON_MARGIN,
4309 icon_y + ICON_MARGIN);
4312 gui->draw_text(text_x + ICON_MARGIN,
4313 text_y + ICON_MARGIN + get_baseline(item),
4317 item->set_in_view(0);
4323 // Draw one column at a time so text overruns don't go into the next column
4324 // clear column backgrounds
4325 int current_toggle = 0;
4326 for(int j = 0; j < columns; j++)
4328 clear_listbox(LISTBOX_BORDER + get_column_offset(j) - xposition,
4329 LISTBOX_BORDER + title_h,
4330 get_column_width(j, 1),
4332 // Draw rows in the column recursively
4333 draw_text_recursive(data, j, 0, ¤t_toggle);
4336 // Delete excess expanders
4337 while(expanders.total > current_toggle)
4339 expanders.remove_object();
4343 // draw user images if available
4345 // Draw titles on top of rows for superposition effect
4348 // Clear garbage from bottom right corner
4349 if(xscrollbar && yscrollbar && is_popup)
4351 gui->draw_top_background(parent_window,
4352 popup_w - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w(),
4353 popup_h - get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h(),
4354 get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w(),
4355 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h());
4362 if(current_operation == SELECT_RECT)
4372 void BC_ListBox::draw_text_recursive(ArrayList<BC_ListBoxItem*> *data,
4375 int *current_toggle)
4380 BC_Resources *resources = get_resources();
4382 set_font(MEDIUMFONT);
4385 // Search for a branch and make room for toggle if there is one
4388 for(int i = 0; i < data[column].size(); i++)
4390 if(data[column].get(i)->get_sublist())
4392 subindent = BC_WindowBase::get_resources()->listbox_expand[0]->get_w();
4398 row_height = row_ascent = row_descent = 0;
4399 for(int i = 0; i < data[column].total; i++)
4401 BC_ListBoxItem *item = data[column].values[i];
4402 int ht = get_text_h(item);
4403 if( ht > row_height ) row_height = ht;
4404 int bl = get_baseline(item);
4405 if( bl > row_ascent ) row_ascent = bl;
4407 if( dt > row_descent ) row_ascent = bl;
4410 for(int i = 0; i < data[column].size(); i++)
4413 BC_ListBoxItem *item = data[column].values[i];
4414 BC_ListBoxItem *first_item = data[master_column].values[i];
4416 if(get_item_y(item) >= -get_item_h(item) + title_h &&
4417 get_item_y(item) < view_h + title_h)
4419 int row_color = get_item_highlight(data, 0, i);
4420 int x, y, w, h, column_width;
4422 get_text_mask(item, x, y, w, h);
4423 column_width = get_column_width(column, 1);
4424 if(x + column_width > view_w + LISTBOX_BORDER * 2)
4425 column_width = view_w + LISTBOX_BORDER * 2 - x;
4427 if(row_color != resources->listbox_inactive)
4429 gui->set_color(row_color);
4430 gui->draw_box(x, y, column_width, h);
4431 gui->set_color(BLACK);
4432 int yy = y, xx = x + column_width-1;
4433 gui->draw_line(x, yy, xx, yy);
4434 yy = y + row_height;
4435 gui->draw_line(x, yy, xx, yy);
4438 gui->set_color(get_item_color(data, column, i));
4441 if(column == 0 && display_format == LISTBOX_ICON_LIST)
4445 gui->pixmap->draw_pixmap(item->icon,
4448 x += item->icon->get_w() + ICON_MARGIN;
4453 // Indent only applies to first column
4455 x + LISTBOX_BORDER + LISTBOX_MARGIN +
4456 (column == 0 ? indent + subindent : 0),
4457 y + get_baseline(item), item->text);
4458 item->set_in_view(1);
4460 if( first_in_view < 0 ) first_in_view = i;
4466 item->get_sublist() &&
4467 item->get_columns())
4469 // Create new expander
4470 if(*current_toggle >= expanders.total)
4472 BC_ListBoxToggle *toggle =
4473 new BC_ListBoxToggle(this,
4475 x + LISTBOX_BORDER + LISTBOX_MARGIN + indent,
4478 expanders.append(toggle);
4481 // Reposition existing expander
4483 BC_ListBoxToggle *toggle = expanders.values[*current_toggle];
4484 //printf("BC_ListBox::draw_text_recursive 1 %d\n", *current_toggle);
4485 toggle->update(item,
4486 x + LISTBOX_BORDER + LISTBOX_MARGIN + indent,
4490 (*current_toggle)++;
4497 item->set_in_view(0);
4499 // Descend into sublist
4500 if(first_item->get_expand())
4502 draw_text_recursive(first_item->get_sublist(),
4504 indent + LISTBOX_INDENT,
4513 int BC_ListBox::draw_border(int flash)
4515 BC_Resources *resources = top_level->get_resources();
4516 gui->draw_3d_border(0,
4518 view_w + LISTBOX_BORDER * 2,
4519 view_h + title_h + LISTBOX_BORDER * 2,
4520 resources->listbox_border1,
4522 resources->listbox_border2_hi :
4523 resources->listbox_border2,
4525 resources->listbox_border3_hi :
4526 resources->listbox_border3,
4527 resources->listbox_border4);
4537 void BC_ListBox::draw_title(int number)
4539 // Column title background
4540 int image_number = 0;
4541 if(number == highlighted_title)
4544 if(current_operation == COLUMN_DN)
4548 int column_offset = get_column_offset(number) - xposition + LISTBOX_BORDER;
4549 int column_width = get_column_width(number, 1);
4550 gui->draw_3segmenth(get_column_offset(number) - xposition + LISTBOX_BORDER,
4552 get_column_width(number, 1) + get_resources()->listbox_title_overlap,
4553 column_bg[image_number]);
4555 // Column title sort order
4556 if(number == sort_column)
4559 if(sort_order == SORT_ASCENDING)
4560 src = column_sort_dn;
4562 src = column_sort_up;
4564 int x = column_offset +
4567 if(x > items_w) x = items_w;
4568 x -= 5 + src->get_w();
4569 gui->draw_pixmap(src,
4571 title_h / 2 - src->get_h() / 2 + LISTBOX_BORDER);
4575 int x = -xposition +
4576 get_column_offset(number) +
4579 x += get_resources()->listbox_title_margin;
4581 gui->set_color(get_resources()->listbox_title_color);
4583 LISTBOX_MARGIN + LISTBOX_BORDER + get_text_ascent(MEDIUMFONT),
4584 _(column_titles[number]));
4587 int BC_ListBox::draw_titles(int flash)
4590 (display_format == LISTBOX_TEXT ||
4591 display_format == LISTBOX_ICON_LIST))
4593 //printf("BC_ListBox::draw_titles 1 %d\n", highlighted_title);
4594 for(int i = 0; i < columns; i++)
4596 if(i != highlighted_title)
4600 if(highlighted_title >= 0) draw_title(highlighted_title);
4611 void BC_ListBox::draw_toggles(int flash)
4613 for(int i = 0; i < expanders.total; i++)
4614 expanders.values[i]->draw(0);
4616 //printf("BC_ListBox::draw_toggles 1 %d\n", flash);
4617 if(flash && expanders.total)
4624 int BC_ListBox::draw_rectangle(int flash)
4626 int x1 = MIN(rect_x1, rect_x2);
4627 int x2 = MAX(rect_x1, rect_x2);
4628 int y1 = MIN(rect_y1, rect_y2);
4629 int y2 = MAX(rect_y1, rect_y2);
4631 if(x1 == x2 || y1 == y2) return 0;
4634 gui->set_color(WHITE);
4635 gui->draw_rectangle(x1, y1, x2 - x1, y2 - y1);
4646 void BC_ListBox::dump(ArrayList<BC_ListBoxItem*> *data,
4653 printf("BC_ListBox::dump 1\n");
4656 for(int i = 0; i < data[master_column].total; i++)
4658 for(int k = 0; k < indent; k++)
4660 for(int j = 0; j < columns; j++)
4662 BC_ListBoxItem *item = data[j].values[i];
4663 printf("%d,%d,%d=%s ",
4666 item->autoplace_text,
4671 if(data[master_column].values[i]->get_sublist())
4673 dump(data[master_column].values[i]->get_sublist(),
4674 data[master_column].values[i]->get_columns(),