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++)
394 button_images[i] = 0;
397 for(int i = 0; i < 5; i++)
398 toggle_images[i] = 0;
403 //printf("BC_ListBox::BC_ListBox 1\n");
405 this->columns = columns;
406 this->yposition = yposition;
407 this->is_popup = is_popup;
408 this->use_button = 1;
409 this->display_format = display_format;
410 this->selection_mode = selection_mode;
411 this->icon_position = icon_position;
412 this->allow_drag = allow_drag;
413 this->column_titles = 0;
414 this->column_width = 0;
415 this->first_in_view = -1;
416 this->last_in_view = 0;
417 //printf("BC_ListBox::BC_ListBox 1\n");
419 if((!column_titles && column_width) ||
420 (column_titles && !column_width))
422 printf("BC_ListBox::BC_ListBox either column_titles or column_widths == NULL but not both.\n");
424 //printf("BC_ListBox::BC_ListBox 2 %p %p\n", column_titles, column_width);
426 set_columns(column_titles,
430 //printf("BC_ListBox::BC_ListBox 3\n");
432 drag_icon_vframe = 0;
433 drag_column_icon_vframe = 0;
437 // reset the search engine
438 //printf("BC_ListBox::BC_ListBox 4\n");
440 //printf("BC_ListBox::BC_ListBox 5\n");
443 BC_ListBox::~BC_ListBox()
445 expanders.remove_all_objects();
446 if(bg_surface) delete bg_surface;
447 if(bg_pixmap) delete bg_pixmap;
448 if(xscrollbar) delete xscrollbar;
449 if(yscrollbar) delete yscrollbar;
450 for(int i = 0; i < 3; i++)
452 if(button_images[i]) delete button_images[i];
453 if(column_bg[i]) delete column_bg[i];
455 for(int i = 0; i < 5; i++)
456 if(toggle_images[i]) delete toggle_images[i];
457 if(column_sort_up) delete column_sort_up;
458 if(column_sort_dn) delete column_sort_dn;
461 if(drag_popup) delete drag_popup;
464 int BC_ListBox::enable()
471 int BC_ListBox::disable()
478 void BC_ListBox::reset_query()
480 query[0] = 0; // reset query
483 int BC_ListBox::evaluate_query(char *string)
485 for(int i = 0; i < data[search_column].size(); i++)
487 if(strcmp(string, data[search_column].get(i)->text) <= 0 &&
488 data[search_column].get(i)->searchable)
497 int BC_ListBox::query_list()
499 if(query[0] == 0) return 0;
503 int selection_changed = 0;
504 int prev_selection = -1;
505 result = evaluate_query(query);
506 if(result >= 0) done = 1;
511 for(int i = 0; i < data[0].total; i++)
513 for(int j = 0; j < columns; j++)
515 if(data[j].values[i]->selected) prev_selection = i;
516 data[j].values[i]->selected = 0;
521 if(prev_selection != result)
522 selection_changed = 1;
523 for(int j = 0; j < columns; j++)
525 data[j].values[result]->selected = 1;
527 center_selection(result);
530 return selection_changed;
533 void BC_ListBox::init_column_width()
535 if(!column_width && data)
538 for(int i = 0; i < data[0].total; i++)
540 wd = get_text_w(data[0].values[i]);
541 if( wd > widest ) widest = wd;
543 default_column_width[0] = widest + 2 * LISTBOX_MARGIN;
547 int BC_ListBox::initialize()
553 for( volatile int i = 0; i < 4; ++i ) // volatile due to cplr bug
555 button_images[i] = new BC_Pixmap(parent_window,
556 BC_WindowBase::get_resources()->listbox_button[i],
559 w = button_images[0]->get_w();
560 h = button_images[0]->get_h();
564 current_operation = NO_OPERATION;
570 current_operation = NO_OPERATION;
573 for(int i = 0; i < 3; i++)
575 column_bg[i] = new BC_Pixmap(parent_window,
576 get_resources()->listbox_column[i],
579 for(int i = 0; i < 5; i++)
581 toggle_images[i] = new BC_Pixmap(parent_window,
582 get_resources()->listbox_expand[i],
586 column_sort_up = new BC_Pixmap(parent_window,
587 BC_WindowBase::get_resources()->listbox_up,
589 column_sort_dn = new BC_Pixmap(parent_window,
590 BC_WindowBase::get_resources()->listbox_dn,
593 //printf("BC_ListBox::initialize 10\n");
594 drag_icon_vframe = get_resources()->type_to_icon[ICON_UNKNOWN];
595 drag_column_icon_vframe = get_resources()->type_to_icon[ICON_COLUMN];
596 // = new BC_Pixmap(parent_window,
597 // get_resources()->type_to_icon[ICON_UNKNOWN],
599 // drag_column_icon = new BC_Pixmap(parent_window,
600 // get_resources()->type_to_icon[ICON_COLUMN],
602 BC_SubWindow::initialize();
606 if(top_level->get_resources()->listbox_bg)
607 bg_pixmap = new BC_Pixmap(this,
608 get_resources()->listbox_bg,
614 if(!use_button && is_popup)
623 void BC_ListBox::deactivate_selection()
625 current_operation = NO_OPERATION;
628 int BC_ListBox::draw_button(int flush)
630 // Draw the button for a popup listbox
631 if(use_button && is_popup)
633 int image_number = 0;
635 draw_top_background(parent_window, 0, 0, w, h);
637 if(button_highlighted)
639 if(current_operation == BUTTON_DN)
645 pixmap->draw_pixmap(button_images[image_number],
657 int BC_ListBox::calculate_item_coords()
665 // Change the display_format to get the right item dimensions for both
667 temp_display_format = display_format;
670 // Scan the first column for lowest y coord of all text
671 // and lowest right x and y coord for all icons which aren't auto placable
672 calculate_last_coords_recursive(data,
679 // Reset last column width. It's recalculated based on text width.
681 calculate_item_coords_recursive(data,
690 display_format = temp_display_format;
695 void BC_ListBox::calculate_last_coords_recursive(
696 ArrayList<BC_ListBoxItem*> *data,
703 for(int i = 0; i < data[0].size(); i++)
705 int current_text_y = 0;
706 int current_icon_x = 0;
707 int current_icon_y = 0;
708 BC_ListBoxItem *item = data[0].get(i);
711 if(!item->autoplace_text)
713 // Lowest text coordinate
714 display_format = LISTBOX_TEXT;
715 current_text_y = item->text_y + get_text_h(item);
716 if(current_text_y > *next_text_y)
717 *next_text_y = current_text_y;
719 // Add sublist depth if it is expanded
720 if(item->get_sublist() &&
721 item->get_columns() &&
724 calculate_last_coords_recursive(item->get_sublist(),
733 // Get next_icon coordinate
736 BC_ListBoxItem *item = data[master_column].get(i);
737 if(!item->autoplace_icon)
739 display_format = LISTBOX_ICONS;
740 // Lowest right icon coordinate.
741 current_icon_x = item->icon_x;
742 if(current_icon_x > *icon_x) *icon_x = current_icon_x;
743 if(current_icon_x + get_item_w(item) > *next_icon_x)
744 *next_icon_x = current_icon_x + get_item_w(item);
746 current_icon_y = item->icon_y + get_item_h(item);
747 if(current_icon_y > *next_icon_y)
748 *next_icon_y = current_icon_y;
755 void BC_ListBox::calculate_item_coords_recursive(
756 ArrayList<BC_ListBoxItem*> *data,
763 // get maximum height of an icon
764 row_height = get_text_height(MEDIUMFONT);
765 if(temp_display_format == LISTBOX_ICON_LIST)
767 for(int i = 0; i < data[0].size(); i++)
769 if(data[0].get(i)->icon)
771 if(data[0].get(i)->icon->get_h() > row_height)
772 row_height = data[0].get(i)->icon->get_h();
778 // Set up items which need autoplacement.
779 // Should fill icons down and then across
780 for(int i = 0; i < data[0].size(); i++)
782 // Don't increase y unless the row requires autoplacing.
783 int total_autoplaced_columns = 0;
785 // Set up icons in first column
788 BC_ListBoxItem *item = data[master_column].get(i);
789 if(item->autoplace_icon)
791 // 1 column only if icons are used
792 display_format = LISTBOX_ICONS;
795 if(*next_icon_y + get_item_h(item) >= get_h() &&
798 *icon_x = *next_icon_x;
802 if(*icon_x + get_item_w(item) > *next_icon_x)
803 *next_icon_x = *icon_x + get_item_w(item);
806 item->set_icon_x(*icon_x);
807 item->set_icon_y(*next_icon_y);
809 *next_icon_y += get_item_h(item);
817 row_ascent = row_descent = 0;
818 // row_height still holds icon max height
819 for(int j = 0; j < columns; j++)
821 BC_ListBoxItem *item = data[j].get(i);
822 if(item->autoplace_text)
824 display_format = LISTBOX_TEXT;
825 item->set_text_x(next_text_x);
826 item->set_text_y(*next_text_y);
827 int ht = get_text_h(item);
828 if( ht > row_height ) row_height = ht;
829 int bl = get_baseline(item);
830 if( bl > row_ascent ) row_ascent = bl;
832 if( dt > row_descent ) row_ascent = bl;
834 // printf("BC_ListBox::calculate_item_coords_recursive %p %d %d %d %d %s \n",
835 // item->get_sublist(),
836 // item->get_columns(),
837 // item->get_expand(),
840 // item->get_text());
841 // Increment position of next column
844 next_text_x += (column_width ?
846 default_column_width[j]);
849 // Set last column width based on text width
851 int new_w = get_item_w(item);
853 int *previous_w = (column_width ?
855 &default_column_width[j]);
856 if(new_w > *previous_w)
858 //printf("BC_ListBox::calculate_item_coords_recursive 1 %d\n", new_w);
860 total_autoplaced_columns++;
864 // Increase the text vertical position
865 if(total_autoplaced_columns)
867 display_format = LISTBOX_TEXT;
868 *next_text_y += row_height;
872 BC_ListBoxItem *item = data[master_column].values[i];
873 if(item->get_sublist() &&
874 item->get_columns() &&
877 calculate_item_coords_recursive(
888 void BC_ListBox::set_is_suggestions(int value)
890 this->is_suggestions = value;
893 void BC_ListBox::set_use_button(int value)
895 this->use_button = value;
898 void BC_ListBox::set_justify(int value)
900 this->justify = value;
903 void BC_ListBox::set_allow_drag_column(int value)
905 this->allow_drag_column = value;
908 void BC_ListBox::set_process_drag(int value)
910 this->process_drag = value;
913 void BC_ListBox::set_master_column(int value, int redraw)
915 this->master_column = value;
922 void BC_ListBox::set_search_column(int value)
924 this->search_column = value;
927 int BC_ListBox::get_sort_column()
932 void BC_ListBox::set_sort_column(int value, int redraw)
941 int BC_ListBox::get_sort_order()
946 void BC_ListBox::set_sort_order(int value, int redraw)
959 int BC_ListBox::get_display_mode()
961 return display_format;
964 int BC_ListBox::get_yposition()
969 int BC_ListBox::get_xposition()
974 int BC_ListBox::get_highlighted_item()
976 return highlighted_item;
980 int BC_ListBox::get_item_x(BC_ListBoxItem *item)
982 if(display_format == LISTBOX_TEXT)
984 return item->text_x - xposition + 2;
987 if(display_format == LISTBOX_ICON_LIST)
989 return item->text_x - xposition + 2;
993 return item->icon_x - xposition + 2;
997 int BC_ListBox::get_item_y(BC_ListBoxItem *item)
1000 if(display_format == LISTBOX_TEXT)
1002 result = item->text_y - yposition + title_h + 2;
1005 if(display_format == LISTBOX_ICON_LIST)
1007 result = item->text_y - yposition + title_h + 2;
1011 result = item->icon_y - yposition + title_h + 2;
1017 int BC_ListBox::get_item_w(BC_ListBoxItem *item)
1019 if(display_format == LISTBOX_ICONS)
1022 get_icon_mask(item, x, y, w, h);
1024 get_text_mask(item, x, y, w, h);
1027 return icon_position == ICON_LEFT ? icon_w + text_w :
1028 icon_w > text_w ? icon_w : text_w;
1030 return get_text_w(item) + 2 * LISTBOX_MARGIN;
1033 int BC_ListBox::get_item_h(BC_ListBoxItem *item)
1035 if(display_format == LISTBOX_ICONS)
1038 get_icon_mask(item, x, y, w, h);
1040 get_text_mask(item, x, y, w, h);
1043 return icon_position != ICON_LEFT ? icon_h + text_h :
1044 icon_h > text_h ? icon_h : text_h;
1046 return get_text_h(item);
1050 int BC_ListBox::get_icon_w(BC_ListBoxItem *item)
1052 return item->get_icon_w();
1055 int BC_ListBox::get_icon_h(BC_ListBoxItem *item)
1057 return item->get_icon_h();
1060 int BC_ListBox::get_text_w(BC_ListBoxItem *item)
1062 int w = item->get_text_w();
1063 if( w < 0 ) item->set_text_w(w = get_text_width(MEDIUMFONT, item->get_text()));
1067 int BC_ListBox::get_text_h(BC_ListBoxItem *item)
1069 int h = item->get_text_h();
1070 if( h < 0 ) item->set_text_h(h = get_text_height(MEDIUMFONT));
1074 int BC_ListBox::get_baseline(BC_ListBoxItem *item)
1076 int b = item->get_baseline();
1077 if( b < 0 ) item->set_baseline(b = get_text_ascent(MEDIUMFONT));
1081 int BC_ListBox::get_items_width()
1085 if(display_format == LISTBOX_ICONS)
1087 for(int i = 0; i < columns; i++)
1089 for(int j = 0; j < data[i].total; j++)
1092 BC_ListBoxItem *item = data[i].values[j];
1095 get_icon_mask(item, x, y, w, h);
1096 if(x1 + w > widest) widest = x1 + w;
1098 if(display_format == LISTBOX_ICONS && icon_position == ICON_LEFT)
1101 get_text_mask(item, x, y, w, h);
1102 if(x1 + w > widest) widest = x1 + w;
1107 if(display_format == LISTBOX_TEXT)
1109 return get_column_offset(columns);
1113 return get_column_offset(columns);
1118 int BC_ListBox::get_items_height(ArrayList<BC_ListBoxItem*> *data,
1135 for(int j = 0; j < (data ? data[master_column].total : 0); j++)
1138 BC_ListBoxItem *item = data[master_column].values[j];
1140 if(display_format == LISTBOX_ICONS)
1142 get_icon_mask(item, x, y, w, h);
1143 if(y + h + yposition > highest) highest = y + h + yposition;
1145 get_text_mask(item, x, y, w, h);
1146 if(y + h + yposition > highest) highest = y + h + yposition;
1150 get_text_mask(item, x, y, w, h);
1154 // Descend into sublist
1155 if(item->get_sublist() &&
1158 get_items_height(item->get_sublist(),
1159 item->get_columns(),
1165 if((display_format == LISTBOX_TEXT ||
1166 display_format == LISTBOX_ICON_LIST) &&
1169 highest = LISTBOX_MARGIN + *result;
1176 int BC_ListBox::set_yposition(int position, int draw_items)
1178 this->yposition = position;
1181 this->draw_items(1);
1186 int BC_ListBox::set_xposition(int position)
1188 this->xposition = position;
1193 void BC_ListBox::expand_item(BC_ListBoxItem *item, int expand)
1197 item->expand = expand;
1198 // Collapse sublists if this is collapsed to make it easier to calculate
1200 if(item->get_sublist())
1201 collapse_recursive(item->get_sublist(), master_column);
1204 // Set everything for autoplacement
1206 set_autoplacement(data, 0, 1);
1212 void BC_ListBox::collapse_recursive(ArrayList<BC_ListBoxItem*> *data,
1215 for(int i = 0; i < data[master_column].total; i++)
1217 BC_ListBoxItem *item = data[master_column].values[i];
1218 if(item->get_sublist() && item->expand)
1221 collapse_recursive(item->get_sublist(), master_column);
1226 void BC_ListBox::set_autoplacement(ArrayList<BC_ListBoxItem*> *data,
1230 for(int i = 0; i < data[0].total; i++)
1232 for(int j = 0; j < columns; j++)
1234 if(do_icons) data[j].values[i]->autoplace_icon = 1;
1235 if(do_text) data[j].values[i]->autoplace_text = 1;
1238 BC_ListBoxItem *item = data[master_column].values[i];
1239 if(item->get_sublist())
1241 set_autoplacement(item->get_sublist(), do_icons, do_text);
1248 int BC_ListBox::get_yscroll_x()
1251 return popup_w - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w();
1255 get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w();
1258 int BC_ListBox::get_yscroll_y()
1266 int BC_ListBox::get_yscroll_height()
1268 return popup_h - (need_xscroll ?
1269 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h() :
1273 int BC_ListBox::get_xscroll_x()
1281 int BC_ListBox::get_xscroll_y()
1285 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h();
1289 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h();
1292 int BC_ListBox::get_xscroll_width()
1294 return popup_w - (need_yscroll ?
1295 get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w() :
1299 int BC_ListBox::get_column_offset(int column)
1305 column_width[--column] :
1306 default_column_width[--column];
1311 void BC_ListBox::column_width_boundaries()
1314 for(int i = 0; i < columns; i++) {
1315 if(column_width[i] < MIN_COLUMN_WIDTH)
1316 column_width[i] = MIN_COLUMN_WIDTH;
1320 for(int i = 0; i < columns; i++) {
1321 if(default_column_width[i] < MIN_COLUMN_WIDTH)
1322 default_column_width[i] = MIN_COLUMN_WIDTH;
1327 int BC_ListBox::get_column_width(int column, int clamp_right)
1329 if(column < columns - 1 || !clamp_right)
1330 return column_width ? column_width[column] : default_column_width[column];
1331 return popup_w + xposition - get_column_offset(column);
1334 int BC_ListBox::get_icon_mask(BC_ListBoxItem *item,
1335 int &x, int &y, int &w, int &h)
1337 if( display_format == LISTBOX_ICONS ) {
1338 x = get_item_x(item);
1339 y = get_item_y(item);
1340 w = get_icon_w(item) + ICON_MARGIN * 2;
1341 h = get_icon_h(item) + ICON_MARGIN * 2;
1348 int BC_ListBox::get_text_mask(BC_ListBoxItem *item,
1349 int &x, int &y, int &w, int &h)
1351 x = get_item_x(item);
1352 y = get_item_y(item);
1354 if(display_format == LISTBOX_ICONS) {
1355 if(icon_position == ICON_LEFT) {
1356 x += get_icon_w(item) + ICON_MARGIN * 2;
1357 y += get_icon_h(item) - get_text_h(item);
1360 y += get_icon_h(item) + ICON_MARGIN;
1363 w = get_text_w(item) + ICON_MARGIN * 2;
1364 h = get_text_h(item) + ICON_MARGIN * 2;
1367 if(display_format == LISTBOX_TEXT) {
1368 w = get_text_w(item) + LISTBOX_MARGIN * 2;
1369 h = get_text_h(item);
1373 w = get_text_width(MEDIUMFONT, item->text) + LISTBOX_MARGIN * 2;
1379 int BC_ListBox::get_item_highlight(ArrayList<BC_ListBoxItem*> *data,
1383 BC_Resources *resources = get_resources();
1384 if(data[column].values[item]->selected)
1385 return resources->listbox_selected;
1386 else if(highlighted_item >= 0 &&
1387 highlighted_ptr == data[master_column].values[item])
1388 return resources->listbox_highlighted;
1389 return resources->listbox_inactive;
1392 int BC_ListBox::get_item_color(ArrayList<BC_ListBoxItem*> *data,
1396 int color = data[column].values[item]->color;
1397 if( color == -1 ) color = get_resources()->listbox_text;
1398 if( get_item_highlight(data, column, item) == color )
1403 int BC_ListBox::get_from_column()
1405 return dragged_title;
1408 int BC_ListBox::get_to_column()
1410 return highlighted_title;
1414 BC_ListBoxItem* BC_ListBox::get_selection(int column,
1415 int selection_number)
1417 return get_selection_recursive(data,
1422 BC_ListBoxItem* BC_ListBox::get_selection_recursive(
1423 ArrayList<BC_ListBoxItem*> *data,
1425 int selection_number)
1429 for(int i = 0; i < data[master_column].total; i++)
1431 BC_ListBoxItem *item = data[master_column].values[i];
1434 //printf("BC_ListBox::get_selection_recursive %d\n", __LINE__);
1436 if(selection_number < 0)
1439 return data[column].values[i];
1443 if(item->get_sublist())
1445 BC_ListBoxItem *result = get_selection_recursive(item->get_sublist(),
1448 if(result) return result;
1456 int BC_ListBox::get_selection_number(int column,
1457 int selection_number)
1459 return get_selection_number_recursive(data,
1464 int BC_ListBox::get_selection_number_recursive(
1465 ArrayList<BC_ListBoxItem*> *data,
1467 int selection_number,
1472 if(!counter) counter = &temp;
1474 for(int i = 0; i < data[master_column].total; i++)
1477 BC_ListBoxItem *item = data[master_column].values[i];
1481 if(selection_number < 0)
1486 if(item->get_sublist())
1488 int result = get_selection_number_recursive(
1489 item->get_sublist(),
1493 if(result >= 0) return result;
1500 int BC_ListBox::set_selection_mode(int mode)
1502 this->selection_mode = mode;
1506 void BC_ListBox::delete_columns()
1510 for(int i = 0; i < columns; i++)
1512 delete [] column_titles[i];
1514 delete [] column_titles;
1517 if(column_width) delete [] column_width;
1523 // Need to copy titles so EDL can change
1524 void BC_ListBox::set_columns(const char **column_titles,
1528 if((!column_titles && column_width) ||
1529 (column_titles && !column_width))
1531 printf("BC_ListBox::set_columns either column_titles or column_width == NULL but not both.\n");
1540 this->column_titles = new char*[columns];
1541 for(int i = 0; i < columns; i++)
1543 this->column_titles[i] = new char[strlen(column_titles[i]) + 1];
1544 strcpy(this->column_titles[i], column_titles[i]);
1550 this->column_width = new int[columns];
1551 for(int i = 0; i < columns; i++)
1553 this->column_width[i] = column_width[i];
1557 this->columns = columns;
1562 int BC_ListBox::update(ArrayList<BC_ListBoxItem*> *data,
1563 const char **column_titles,
1568 int highlighted_number,
1569 int recalc_positions,
1572 set_columns(column_titles,
1578 this->yposition = yposition;
1579 this->xposition = xposition;
1580 this->highlighted_item = highlighted_number;
1581 this->highlighted_ptr = index_to_item(data, highlighted_number, 0);
1583 if(recalc_positions)
1584 set_autoplacement(data, 1, 1);
1586 init_column_width();
1591 update_scrollbars(1);
1597 void BC_ListBox::center_selection()
1599 int selection = get_selection_number(0, 0);
1601 calculate_item_coords();
1602 center_selection(selection);
1608 update_scrollbars(0);
1609 gui->show_window(1);
1613 void BC_ListBox::move_vertical(int pixels)
1617 void BC_ListBox::move_horizontal(int pixels)
1621 int BC_ListBox::select_previous(int skip,
1622 BC_ListBoxItem *selected_item,
1624 ArrayList<BC_ListBoxItem*> *data,
1630 selected_item = get_selection(0, 0);
1642 got_second = &temp3;
1646 // Scan backwards to item pointer. Then count visible items to get
1647 // destination. No wraparound.
1650 for(int i = data[master_column].total - 1; i >= 0; i--)
1652 BC_ListBoxItem *current_item = data[master_column].values[i];
1653 if(current_item->get_sublist() &&
1654 current_item->get_expand())
1656 int result = select_previous(skip,
1659 current_item->get_sublist(),
1671 if((*counter) >= skip)
1673 for(int j = 0; j < columns; j++)
1674 data[j].values[i]->selected = 1;
1676 return item_to_index(this->data, current_item);
1681 if(current_item->selected)
1683 for(int j = 0; j < columns; j++)
1684 data[j].values[i]->selected = 0;
1691 // Hit top of top level without finding a selected item.
1694 // Select first item in top level and quit
1695 BC_ListBoxItem *current_item;
1697 current_item = data[master_column].values[0];
1699 for(int j = 0; j < columns; j++)
1700 data[j].values[0]->selected = 1;
1702 return item_to_index(this->data, current_item);
1704 }while(top_level && data[master_column].total);
1708 int BC_ListBox::select_next(int skip,
1709 BC_ListBoxItem *selected_item,
1711 ArrayList<BC_ListBoxItem*> *data,
1717 selected_item = get_selection(0, 0);
1729 got_second = &temp3;
1733 // Scan forwards to currently selected item pointer.
1734 // Then count visible items to get destination. No wraparound.
1737 for(int i = 0; i < data[master_column].total; i++)
1739 BC_ListBoxItem *current_item = data[master_column].values[i];
1741 // Select next item once the number items after the currently selected item
1742 // have been passed.
1746 if((*counter) >= skip)
1748 for(int j = 0; j < columns; j++)
1749 data[j].values[i]->selected = 1;
1751 return item_to_index(this->data, current_item);
1756 // Got currently selected item. Deselect it.
1757 if(current_item->selected)
1759 for(int j = 0; j < columns; j++)
1760 data[j].values[i]->selected = 0;
1766 // Descend into expanded level
1767 if(current_item->get_sublist() &&
1768 current_item->get_expand())
1770 int result = select_next(skip,
1773 current_item->get_sublist(),
1783 // Hit bottom of top level without finding the next item.
1786 BC_ListBoxItem *current_item;
1787 // Select first item in top level and quit
1791 current_item = data[master_column].values[0];
1793 for(int j = 0; j < columns; j++)
1794 data[j].values[0]->selected = 1;
1799 // Select last item in top level and quit
1801 int current_row = data[master_column].total - 1;
1802 current_item = data[master_column].values[current_row];
1804 for(int j = 0; j < columns; j++)
1805 data[j].values[current_row]->selected = 1;
1809 return item_to_index(this->data, current_item);
1811 }while(top_level && data[master_column].total);
1817 void BC_ListBox::clamp_positions()
1819 items_w = get_items_width();
1820 items_h = get_items_height(data, columns);
1822 if(yposition < 0) yposition = 0;
1824 if(yposition > items_h - view_h)
1825 yposition = items_h - view_h;
1827 if(yposition < 0) yposition = 0;
1829 if(xposition < 0) xposition = 0;
1831 if(xposition >= items_w - view_w)
1832 xposition = items_w - view_w;
1834 if(xposition < 0) xposition = 0;
1837 int BC_ListBox::center_selection(int selection,
1838 ArrayList<BC_ListBoxItem*> *data,
1842 if(!data) data = this->data;
1843 if(!counter) counter = &temp;
1845 for(int i = 0; i < data[master_column].total; i++)
1850 BC_ListBoxItem *item = data[master_column].values[i];
1851 if((*counter) == selection)
1853 BC_ListBoxItem *top_item = this->data[master_column].values[0];
1856 if(display_format == LISTBOX_ICONS)
1858 // Icon is out of window
1859 if( item->icon_y-yposition > view_h-get_text_h(item) ||
1860 item->icon_y-yposition < 0 ) {
1861 yposition = item->icon_y - view_h / 2;
1864 if(data[master_column].values[selection]->icon_x - xposition > view_w ||
1865 data[master_column].values[selection]->icon_x - xposition < 0)
1867 xposition = item->icon_x - view_w / 2;
1872 // Text coordinate is out of window
1873 if( item->text_y-yposition > view_h-get_text_h(item) ||
1874 item->text_y-yposition < 0 ) {
1875 yposition = item->text_y -
1884 if(item->get_sublist())
1886 int result = center_selection(selection,
1887 item->get_sublist(),
1889 if(result) return result;
1895 void BC_ListBox::update_scrollbars(int flush)
1897 int h_needed = items_h = get_items_height(data, columns);
1898 int w_needed = items_w = get_items_width();
1900 // if(columns > 0 && column_width)
1901 // printf("BC_ListBox::update_scrollbars 1 %d %d\n", column_width[columns - 1], w_needed);
1905 if(xposition != xscrollbar->get_value())
1906 xscrollbar->update_value(xposition);
1908 if(w_needed != xscrollbar->get_length() ||
1909 view_w != xscrollbar->get_handlelength())
1910 xscrollbar->update_length(w_needed, xposition, view_w, 0);
1915 if(yposition != yscrollbar->get_value())
1916 yscrollbar->update_value(yposition);
1918 if(h_needed != yscrollbar->get_length() || view_h != yscrollbar->get_handlelength())
1919 yscrollbar->update_length(h_needed, yposition, view_h, 0);
1922 if(flush) this->flush();
1925 int BC_ListBox::get_scrollbars()
1927 int h_needed = items_h = get_items_height(data, columns);
1928 int w_needed = items_w = get_items_width();
1932 title_h = get_title_h();
1934 view_h = popup_h - title_h - 4;
1935 view_w = popup_w - 4;
1937 // Create scrollbars as needed
1938 for(int i = 0; i < 2; i++)
1940 if(w_needed > view_w)
1945 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h() -
1953 if(h_needed > view_h)
1957 get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w() -
1966 // Update subwindow size
1967 int new_w = popup_w;
1968 int new_h = popup_h;
1969 if(need_xscroll) new_h -= get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h();
1970 if(need_yscroll) new_w -= get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w();
1973 if(new_w != BC_WindowBase::get_w() || new_h != BC_WindowBase::get_h())
1974 gui->resize_window(new_w, new_h);
1976 BC_WindowBase *destination = (is_popup ? gui : parent_window);
1981 destination->add_subwindow(xscrollbar =
1982 new BC_ListBoxXScroll(this,
1986 xscrollbar->show_window(0);
1987 xscrollbar->bound_to = this;
1991 xscrollbar->update_length(w_needed, xposition, view_w, flush);
1992 xscrollbar->reposition_window(get_xscroll_x(),
1994 get_xscroll_width());
1999 if(xscrollbar) delete xscrollbar;
2008 destination->add_subwindow(yscrollbar =
2009 new BC_ListBoxYScroll(this,
2013 yscrollbar->show_window(0);
2014 yscrollbar->bound_to = this;
2018 yscrollbar->update_length(h_needed, yposition, view_h, flush);
2019 yscrollbar->reposition_window(get_yscroll_x(),
2021 get_yscroll_height());
2026 if(yscrollbar) delete yscrollbar;
2032 view_w + 4 != bg_surface->get_w() ||
2033 view_h + 4 != bg_surface->get_h())
2035 if(bg_surface) delete bg_surface;
2036 bg_surface = new BC_Pixmap(gui, view_w + 4, view_h + 4);
2046 void BC_ListBox::set_drag_scroll(int value)
2048 allow_drag_scroll = value;
2052 // Test for scrolling by dragging
2054 int BC_ListBox::test_drag_scroll(int cursor_x, int cursor_y)
2057 if(allow_drag_scroll ||
2058 current_operation == SELECT_RECT)
2061 int top_boundary = get_title_h();
2063 if(cursor_y < top_boundary ||
2064 cursor_y >= view_h + title_h + LISTBOX_BORDER * 2 ||
2065 cursor_x < LISTBOX_BORDER ||
2066 cursor_x >= view_w + LISTBOX_BORDER)
2074 int BC_ListBox::drag_scroll_event()
2076 int top_boundary = get_title_h();
2079 if(get_cursor_y() < top_boundary)
2081 yposition -= top_boundary - get_cursor_y();
2085 if(get_cursor_y() >= view_h + title_h + 4)
2087 yposition += get_cursor_y() - (view_h + title_h + 4);
2091 if(get_cursor_x() < 2)
2093 xposition -= 2 - get_cursor_x();
2097 if(get_cursor_x() >= view_w + 2)
2099 xposition += get_cursor_x() - (view_w + 2);
2102 if(result) clamp_positions();
2106 int BC_ListBox::rectangle_scroll_event()
2108 int old_xposition = xposition;
2109 int old_yposition = yposition;
2110 int result = drag_scroll_event();
2114 rect_x1 += old_xposition - xposition;
2115 rect_y1 += old_yposition - yposition;
2116 rect_x2 = get_cursor_x();
2117 rect_y2 = get_cursor_y();
2119 int x1 = MIN(rect_x1, rect_x2);
2120 int x2 = MAX(rect_x1, rect_x2);
2121 int y1 = MIN(rect_y1, rect_y2);
2122 int y2 = MAX(rect_y1, rect_y2);
2124 if(select_rectangle(data,
2130 selection_changed();
2135 update_scrollbars(1);
2140 int BC_ListBox::select_scroll_event()
2142 int result = drag_scroll_event();
2146 highlighted_item = selection_number = get_cursor_item(data,
2152 update_scrollbars(1);
2153 selection_changed();
2158 int BC_ListBox::select_rectangle(ArrayList<BC_ListBoxItem*> *data,
2165 for(int i = 0; i < data[master_column].total; i++)
2167 for(int j = 0; j < columns; j++)
2169 BC_ListBoxItem *item = data[j].values[i];
2170 if(display_format == LISTBOX_ICONS)
2172 int icon_x, icon_y, icon_w, icon_h;
2173 int text_x, text_y, text_w, text_h;
2174 get_icon_mask(item, icon_x, icon_y, icon_w, icon_h);
2175 get_text_mask(item, text_x, text_y, text_w, text_h);
2177 if((x2 >= icon_x && x1 < icon_x + icon_w &&
2178 y2 >= icon_y && y1 < icon_y + icon_h) ||
2179 (x2 >= text_x && x1 < text_x + text_w &&
2180 y2 >= text_y && y1 < text_y + text_h))
2201 gui->get_w() - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w() :
2204 y1 < gui->get_h() &&
2205 y2 >= get_item_y(item) &&
2206 y1 < get_item_y(item) + get_item_h(item))
2225 BC_ListBoxItem *item = data[master_column].values[i];
2226 if(item->get_sublist() &&
2228 result |= select_rectangle(item->get_sublist(),
2237 int BC_ListBox::reposition_item(ArrayList<BC_ListBoxItem*> *data,
2238 int selection_number,
2244 if(!counter) counter = &temp;
2247 for(int i = 0; i < data[master_column].total; i++)
2249 BC_ListBoxItem *item = data[master_column].values[i];
2251 if((*counter) == selection_number)
2257 // Not recursive because it's only used for icons
2262 void BC_ListBox::move_selection(ArrayList<BC_ListBoxItem*> *dst,
2263 ArrayList<BC_ListBoxItem*> *src)
2265 for(int i = 0; i < src[master_column].total; i++)
2267 BC_ListBoxItem *item = src[master_column].values[i];
2272 for(int j = 0; j < columns; j++)
2274 dst[j].append(src[j].values[i]);
2275 src[j].remove_number(i);
2279 // Descend into sublist
2280 if(item->get_sublist())
2283 item->get_sublist());
2288 int BC_ListBox::put_selection(ArrayList<BC_ListBoxItem*> *data,
2289 ArrayList<BC_ListBoxItem*> *src,
2294 if(!counter) counter = &temp;
2298 for(int j = 0; j < columns; j++)
2300 for(int i = 0; i < src[j].total; i++)
2302 data[j].append(src[j].values[i]);
2308 for(int i = 0; i < data[master_column].total; i++)
2311 if((*counter) == destination)
2313 for(int j = 0; j < columns; j++)
2315 for(int k = 0; k < src[j].total; k++)
2317 data[j].insert(src[j].values[k], destination + k);
2323 BC_ListBoxItem *item = data[master_column].values[i];
2324 if(item->get_sublist())
2326 if(put_selection(item->get_sublist(),
2338 int BC_ListBox::item_to_index(ArrayList<BC_ListBoxItem*> *data,
2339 BC_ListBoxItem *item,
2343 if(!counter) counter = &temp;
2345 for(int i = 0; i < data[master_column].total; i++)
2348 for(int j = 0; j < columns; j++)
2350 BC_ListBoxItem *new_item = data[j].values[i];
2351 //printf("BC_ListBox::item_to_index 1 %d %d %p\n", j, i, new_item);
2352 if(new_item == item)
2358 BC_ListBoxItem *new_item = data[master_column].values[i];
2359 if(new_item->get_sublist())
2361 if(item_to_index(new_item->get_sublist(),
2371 BC_ListBoxItem* BC_ListBox::index_to_item(ArrayList<BC_ListBoxItem*> *data,
2377 if(!counter) counter = &temp;
2378 for(int i = 0; i < data[master_column].total; i++)
2381 if((*counter) == number)
2383 return data[column].values[i];
2385 BC_ListBoxItem *item = data[master_column].values[i];
2386 if(item->get_sublist())
2388 BC_ListBoxItem *result = index_to_item(item->get_sublist(),
2392 if(result) return result;
2398 int BC_ListBox::get_cursor_item(ArrayList<BC_ListBoxItem*> *data,
2401 BC_ListBoxItem **item_return,
2406 if(!data) return -1;
2407 if(!counter) counter = &temp;
2409 // Icons are not treed
2410 if(display_format == LISTBOX_ICONS)
2412 for(int j = data[master_column].total - 1; j >= 0; j--)
2414 int icon_x, icon_y, icon_w, icon_h;
2415 int text_x, text_y, text_w, text_h;
2416 BC_ListBoxItem *item = data[master_column].values[j];
2417 get_icon_mask(item, icon_x, icon_y, icon_w, icon_h);
2418 get_text_mask(item, text_x, text_y, text_w, text_h);
2420 if((cursor_x >= icon_x && cursor_x < icon_x + icon_w &&
2421 cursor_y >= icon_y && cursor_y < icon_y + icon_h) ||
2422 (cursor_x >= text_x && cursor_x < text_x + text_w &&
2423 cursor_y >= text_y && cursor_y < text_y + text_h))
2425 if(item_return) (*item_return) = item;
2433 // Cursor is inside items rectangle
2435 cursor_x < (yscrollbar ?
2436 gui->get_w() - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w() :
2438 // Only clamp y if we're not in a SELECT operation.
2439 (current_operation == BC_ListBox::SELECT ||
2440 (cursor_y > get_title_h() + LISTBOX_BORDER &&
2441 cursor_y < gui->get_h())))
2443 // Search table for cursor obstruction
2444 for(int i = 0; i < data[master_column].total; i++)
2446 BC_ListBoxItem *item = data[master_column].values[i];
2449 // Cursor is inside item on current level
2452 cursor_y >= get_item_y(item) &&
2453 cursor_y < get_item_y(item) + get_item_h(item))
2455 //printf("BC_ListBox::get_cursor_item %d %d %p\n", master_column, i, item);
2456 if(item_return) (*item_return) = item;
2460 // Descend into sublist
2461 if(item->get_sublist())
2463 if(get_cursor_item(item->get_sublist(),
2468 item->get_expand()) >= 0)
2477 int BC_ListBox::repeat_event(int64_t duration)
2479 switch(current_operation)
2481 // Repeat out of bounds selection
2483 if(duration == get_resources()->scroll_repeat)
2484 return rectangle_scroll_event();
2488 if(duration == get_resources()->scroll_repeat)
2489 return select_scroll_event();
2494 if(button_highlighted && is_popup && !tooltip_done &&
2495 tooltip_text && tooltip_text[0] != 0 &&
2496 duration == get_resources()->tooltip_delay)
2508 int BC_ListBox::cursor_enter_event()
2512 switch(current_operation)
2514 // Cursor moved over button, pressed, and exited.
2515 case BUTTON_DOWN_SELECT:
2516 if(top_level->event_win == win)
2518 current_operation = BUTTON_DN;
2520 button_highlighted = 1;
2526 // Cursor entered button
2527 if(is_popup && top_level->event_win == win)
2529 button_highlighted = 1;
2534 // TODO: Need to get the highlighted column title or item
2535 if(gui && top_level->event_win == gui->win)
2537 list_highlighted = 1;
2547 int BC_ListBox::cursor_leave_event()
2549 if(current_operation == COLUMN_DRAG) return 0;
2552 if(button_highlighted)
2554 button_highlighted = 0;
2559 if(list_highlighted)
2561 list_highlighted = 0;
2562 highlighted_item = -1;
2563 highlighted_ptr = 0;
2564 highlighted_title = -1;
2565 int redraw_toggles = 0;
2566 for(int i = 0; i < expanders.total; i++)
2567 expanders.values[i]->cursor_leave_event(&redraw_toggles);
2575 int BC_ListBox::get_first_selection(ArrayList<BC_ListBoxItem*> *data, int *result)
2578 if(!result) result = &temp;
2580 for(int i = 0; i < data[master_column].total; i++)
2582 BC_ListBoxItem *item = data[master_column].values[i];
2584 if(item->selected) return (*result);
2585 if(item->get_sublist())
2587 if(get_first_selection(item->get_sublist(), result) >= 0)
2594 int BC_ListBox::get_total_items(ArrayList<BC_ListBoxItem*> *data,
2599 if(!result) result = &temp;
2601 for(int i = 0; i < data[master_column].total; i++)
2604 if(data[master_column].values[i]->get_sublist())
2605 get_total_items(data[master_column].values[i]->get_sublist(),
2614 int BC_ListBox::get_last_selection(ArrayList<BC_ListBoxItem*> *data,
2625 for(int i = data[master_column].total - 1; i >= 0; i--)
2627 BC_ListBoxItem *item = data[master_column].values[i];
2632 return get_total_items(data, 0, master_column) - (*result) /* - 1 */;
2637 if(item->get_sublist())
2639 if(get_last_selection(item->get_sublist(), result) >= 0)
2642 return get_total_items(data, 0, master_column) - (*result) /* - 1 */;
2651 void BC_ListBox::select_range(ArrayList<BC_ListBoxItem*> *data,
2657 if(!current) current = &temp;
2659 for(int i = 0; i < data[master_column].total; i++)
2662 if((*current) >= start && (*current) < end)
2664 for(int j = 0; j < columns; j++)
2665 data[j].values[i]->selected = 1;
2667 BC_ListBoxItem *item = data[master_column].values[i];
2668 if(item->get_sublist())
2669 select_range(item->get_sublist(),
2677 // Fill items between current selection and new selection
2678 int BC_ListBox::expand_selection(int button_press, int selection_number)
2680 int old_selection_start = selection_start;
2681 int old_selection_end = selection_end;
2683 // printf("BC_ListBox::expand_selection %d %d\n",
2684 // selection_center,
2685 // selection_number);
2687 // Calculate the range to select based on selection_center and selection_number
2688 if(selection_number < selection_center)
2690 selection_start = selection_number;
2694 selection_end = selection_number + 1;
2697 //printf("BC_ListBox::expand_selection %d %d %d %d\n", old_selection_start, old_selection_end, selection_start, selection_end);
2698 // Recurse through all the items and select the desired range
2699 select_range(data, selection_start, selection_end);
2702 return (old_selection_start != selection_start ||
2703 old_selection_end != selection_end);
2706 int BC_ListBox::toggle_item_selection(ArrayList<BC_ListBoxItem*> *data,
2707 int selection_number,
2711 if(!counter) counter = &temp;
2713 for(int i = 0; i < data[master_column].total; i++)
2715 BC_ListBoxItem *item = data[master_column].values[i];
2717 if((*counter) == selection_number)
2719 // Get new value for selection
2720 int selected = !item->selected;
2722 for(int j = 0; j < columns; j++)
2723 data[j].values[i]->selected = selected;
2727 // Descend into sublist
2728 if(item->get_sublist())
2730 if(toggle_item_selection(item->get_sublist(),
2741 void BC_ListBox::set_all_selected(ArrayList<BC_ListBoxItem*> *data, int value)
2743 for(int i = 0; i < data[master_column].total; i++)
2745 for(int j = 0; j < columns; j++)
2747 BC_ListBoxItem *item = data[j].values[i];
2748 item->selected = value;
2750 BC_ListBoxItem *item = data[master_column].values[i];
2751 if(item->get_sublist())
2753 set_all_selected(item->get_sublist(), value);
2758 void BC_ListBox::set_selected(ArrayList<BC_ListBoxItem*> *data,
2764 if(!counter) counter = &temp;
2765 for(int i = 0; i < data[master_column].total && (*counter) != item_number; i++)
2768 if((*counter) == item_number)
2770 for(int j = 0; j < columns; j++)
2772 BC_ListBoxItem *item = data[j].values[i];
2773 item->selected = value;
2778 BC_ListBoxItem *item = data[master_column].values[i];
2779 if(item->get_sublist())
2781 set_selected(item->get_sublist(),
2789 int BC_ListBox::update_selection(ArrayList<BC_ListBoxItem*> *data,
2790 int selection_number,
2795 if(!counter) counter = &temp;
2797 for(int i = 0; i < data[master_column].total; i++)
2799 BC_ListBoxItem *item = data[master_column].values[i];
2801 if((*counter) == selection_number && !item->selected)
2804 for(int j = 0; j < columns; j++)
2805 data[j].values[i]->selected = 1;
2808 if((*counter) != selection_number && item->selected)
2811 for(int j = 0; j < columns; j++)
2812 data[j].values[i]->selected = 0;
2814 if(item->get_sublist())
2815 result |= update_selection(item->get_sublist(),
2822 void BC_ListBox::promote_selections(ArrayList<BC_ListBoxItem*> *data,
2826 for(int i = 0; i < data[master_column].total; i++)
2828 for(int j = 0; j < columns; j++)
2830 BC_ListBoxItem *item = data[j].values[i];
2831 if(item->selected == old_value) item->selected = new_value;
2833 BC_ListBoxItem *item = data[master_column].values[i];
2834 if(item->get_sublist())
2835 promote_selections(item->get_sublist(), old_value, new_value);
2839 int BC_ListBox::focus_out_event()
2845 int BC_ListBox::button_press_event()
2848 BC_ListBoxItem *current_item = 0;
2850 int do_selection_change = 0;
2851 const int debug = 0;
2854 if(debug) printf("BC_ListBox::button_press_event %d this=%p event_win=%p %p %p %p\n",
2857 (void*)top_level->event_win,
2858 (void*)(gui ? gui->win : 0),
2860 (void*)parent_window->win);
2862 // Pressed in button
2863 if(is_popup && top_level->event_win == win)
2865 if(debug) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2866 current_operation = BUTTON_DN;
2870 if(!active && !disabled)
2872 top_level->deactivate();
2879 // Pressed in scrollbar
2880 if((xscrollbar && top_level->event_win == xscrollbar->win) ||
2881 (yscrollbar && top_level->event_win == yscrollbar->win))
2883 if(debug) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2888 if(gui && top_level->event_win == gui->win)
2890 if(debug) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2892 // Activate list items
2893 // If it is a suggestion popup, it is visible without being active
2896 if(debug) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2897 if(!is_suggestions) top_level->deactivate();
2898 if(debug) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2900 if(debug) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2903 // Wheel mouse pressed
2904 if(get_buttonpress() == 4)
2906 if(current_operation == NO_OPERATION)
2908 current_operation = WHEEL;
2911 set_yposition(yposition - gui->get_h() / 10, 0);
2913 update_scrollbars(0);
2914 highlighted_ptr = 0;
2915 highlighted_item = get_cursor_item(data,
2916 top_level->cursor_x,
2917 top_level->cursor_y,
2925 if(get_buttonpress() == 5)
2927 if(current_operation == NO_OPERATION)
2929 current_operation = WHEEL;
2932 set_yposition(yposition + gui->get_h() / 10, 0);
2934 update_scrollbars(0);
2935 highlighted_ptr = 0;
2936 highlighted_item = get_cursor_item(data,
2937 top_level->cursor_x,
2938 top_level->cursor_y,
2946 // Pressed over column title division
2947 if(test_column_divisions(gui->get_cursor_x(),
2948 gui->get_cursor_y(),
2951 drag_cursor_x = gui->get_cursor_x() + xposition;
2953 drag_column_w = column_width[highlighted_division - 1];
2955 drag_column_w = default_column_width[highlighted_division - 1];
2957 current_operation = DRAG_DIVISION;
2961 // Pressed in column title
2962 if(test_column_titles(gui->get_cursor_x(), gui->get_cursor_y()))
2964 current_operation = COLUMN_DN;
2965 button_highlighted = 0;
2966 list_highlighted = 1;
2971 // Pressed in expander
2972 if(test_expanders())
2974 current_operation = EXPAND_DN;
2975 // Need to redraw items because of alpha
2980 // Pressed over item
2981 if((selection_number = get_cursor_item(data,
2982 gui->get_cursor_x(),
2983 gui->get_cursor_y(),
2984 ¤t_item)) >= 0)
2986 if(debug) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2988 // Get item button was pressed over
2989 selection_number2 = selection_number1;
2990 selection_number1 = selection_number;
2992 selection_start = -1;
2996 // Multiple item selection is possible
2997 if(selection_mode == LISTBOX_MULTIPLE &&
2998 (ctrl_down() || shift_down()))
3000 // Expand text selection.
3001 // Fill items between selected region and current item.
3003 (display_format == LISTBOX_TEXT ||
3004 display_format == LISTBOX_ICON_LIST))
3006 // Get first item selected
3007 selection_start = get_first_selection(data);
3008 // Get last item selected
3009 selection_end = get_last_selection(data);
3010 // Get center of selected region
3011 if(selection_end > selection_start)
3013 selection_center = (selection_end + selection_start) >> 1;
3017 selection_center = selection_number;
3021 // Deselect everything.
3022 set_all_selected(data, 0);
3023 // Select just the items
3024 expand_selection(1, selection_number);
3028 // Toggle a single item on or off
3030 toggle_item_selection(data, selection_number);
3031 new_value = current_item->selected;
3035 // Select single item
3037 if(!current_item->selected)
3039 set_all_selected(data, 0);
3048 current_operation = SELECT;
3049 highlighted_item = selection_number;
3050 highlighted_ptr = current_item;
3051 button_highlighted = 0;
3052 list_highlighted = 1;
3055 do_selection_change = 1;
3060 // Pressed over nothing. Start rectangle selection.
3062 if(get_buttonpress() == 1 &&
3063 selection_mode == LISTBOX_MULTIPLE)
3067 // Deselect all and redraw if anything was selected
3068 if(get_selection_number(0, 0) >= 0)
3070 set_all_selected(data, 0);
3072 do_selection_change = 1;
3078 // Promote selections to protect from a rectangle selection
3079 promote_selections(data, 1, 2);
3082 // Start rectangle selection
3083 current_operation = SELECT_RECT;
3084 rect_x1 = rect_x2 = get_cursor_x();
3085 rect_y1 = rect_y2 = get_cursor_y();
3093 // Suggestion box is not active but visible, so lie to get it to deactivate
3094 if(is_popup && (active || (is_suggestions && gui)))
3097 if(debug) printf("BC_ListBox::button_press_event %d\n", __LINE__);
3103 if(do_selection_change) selection_changed();
3104 if(debug) printf("BC_ListBox::button_press_event %d %d\n",
3111 int BC_ListBox::button_release_event()
3114 int cursor_x, cursor_y;
3118 //printf("BC_ListBox::button_release_event 1 %d\n", current_operation);
3119 switch(current_operation)
3122 current_operation = NO_OPERATION;
3127 current_operation = NO_OPERATION;
3131 // Release item selection
3132 case BUTTON_DOWN_SELECT:
3134 //printf("BC_ListBox::button_release_event 10\n");
3135 unset_repeat(get_resources()->scroll_repeat);
3136 current_operation = NO_OPERATION;
3137 translate_coordinates(top_level->event_win,
3139 gui->get_cursor_x(),
3140 gui->get_cursor_y(),
3146 get_cursor_item(data, cursor_x, cursor_y);
3147 //printf("BC_ListBox::button_release_event %d %d\n", selection_number2, selection_number1);
3152 if(selection_number >= 0)
3158 // Second button release outside button
3159 if(button_releases > 1)
3166 if(top_level->get_double_click() &&
3167 selection_number2 == selection_number1 &&
3168 selection_number2 >= 0 &&
3169 selection_number1 >= 0)
3179 unset_repeat(get_resources()->scroll_repeat);
3182 // Demote selections from rectangle selection
3183 promote_selections(data, 2, 1);
3186 // Hide rectangle overlay
3188 current_operation = NO_OPERATION;
3192 // Release popup button
3195 current_operation = NO_OPERATION;
3199 // Second button release inside button
3200 if(button_releases > 1)
3208 current_operation = NO_OPERATION;
3209 // Update the sort column and the sort order for the user only if the existing
3210 // sort column is valid.
3211 if(sort_column >= 0)
3213 // Invert order only if column is the same
3214 if(highlighted_title == sort_column)
3216 (sort_order == SORT_ASCENDING) ?
3219 // Set the new sort column
3220 sort_column = highlighted_title;
3221 if(!sort_order_event())
3227 // Sorting not enabled. Redraw the title state.
3236 int redraw_toggles = 0;
3237 for(int i = 0; i < expanders.total && !result; i++)
3239 if(expanders.values[i]->button_release_event(&redraw_toggles))
3244 // Need to redraw items because of alpha
3245 if(redraw_toggles) draw_items(1);
3246 current_operation = NO_OPERATION;
3251 // Can't default to NO_OPERATION because it may be used in a drag event.
3256 if(do_event) handle_event();
3258 //printf("BC_ListBox::button_release_event %d %d\n", __LINE__, get_window_lock());
3262 int BC_ListBox::get_title_h()
3264 if(display_format == LISTBOX_TEXT ||
3265 display_format == LISTBOX_ICON_LIST)
3266 return column_titles ? column_bg[0]->get_h() : 0;
3271 void BC_ListBox::reset_cursor(int new_cursor)
3275 if(gui->get_cursor() != new_cursor)
3277 gui->set_cursor(new_cursor, 0, 0);
3281 if(get_cursor() != new_cursor)
3283 set_cursor(new_cursor, 0, 0);
3287 int BC_ListBox::test_column_divisions(int cursor_x, int cursor_y, int &new_cursor)
3292 cursor_y < get_title_h() &&
3294 cursor_x < gui->get_w())
3296 for(int i = 1; i < columns; i++)
3298 if(cursor_x >= -xposition + get_column_offset(i) - 5 &&
3299 cursor_x < -xposition + get_column_offset(i) +
3300 get_resources()->listbox_title_hotspot)
3302 highlighted_item = -1;
3303 highlighted_ptr = 0;
3304 highlighted_division = i;
3305 highlighted_title = -1;
3306 list_highlighted = 1;
3307 new_cursor = HSEPARATE_CURSOR;
3312 highlighted_division = -1;
3316 int BC_ListBox::test_column_titles(int cursor_x, int cursor_y)
3321 cursor_y < get_title_h() &&
3323 cursor_x < gui->get_w())
3325 for(int i = 0; i < columns; i++)
3327 if(cursor_x >= -xposition + get_column_offset(i) &&
3328 (cursor_x < -xposition + get_column_offset(i + 1) ||
3331 highlighted_item = -1;
3332 highlighted_ptr = 0;
3333 highlighted_division = -1;
3334 highlighted_title = i;
3335 list_highlighted = 1;
3340 highlighted_title = -1;
3344 int BC_ListBox::test_expanders()
3346 for(int i = 0; i < expanders.total; i++)
3348 if(expanders.values[i]->button_press_event())
3350 current_operation = EXPAND_DN;
3358 int BC_ListBox::cursor_motion_event()
3360 int redraw = 0, result = 0;
3361 int new_cursor = ARROW_CURSOR;
3363 selection_number = -1;
3366 switch(current_operation)
3369 // Button pressed and slid off button
3370 if(!cursor_inside())
3372 current_operation = BUTTON_DOWN_SELECT;
3380 // int new_w = get_cursor_x() +
3382 // get_column_offset(highlighted_division - 1);
3383 int difference = get_cursor_x() + xposition - drag_cursor_x;
3384 int new_w = drag_column_w + difference;
3386 new_cursor = HSEPARATE_CURSOR;
3390 column_width[highlighted_division - 1] = new_w;
3394 default_column_width[highlighted_division - 1] = new_w;
3397 column_width_boundaries();
3399 // Force update of coords
3400 set_autoplacement(data, 0, 1);
3401 column_resize_event();
3405 update_scrollbars(1);
3412 if(test_drag_scroll(get_cursor_x(), get_cursor_y()))
3414 set_repeat(get_resources()->scroll_repeat);
3417 int old_x1 = MIN(rect_x1, rect_x2);
3418 int old_x2 = MAX(rect_x1, rect_x2);
3419 int old_y1 = MIN(rect_y1, rect_y2);
3420 int old_y2 = MAX(rect_y1, rect_y2);
3422 int new_rect_x2 = get_cursor_x();
3423 int new_rect_y2 = get_cursor_y();
3425 int x1 = MIN(rect_x1, new_rect_x2);
3426 int x2 = MAX(rect_x1, new_rect_x2);
3427 int y1 = MIN(rect_y1, new_rect_y2);
3428 int y2 = MAX(rect_y1, new_rect_y2);
3430 // Adjust rectangle coverage
3438 redraw = select_rectangle(data,
3448 //printf("BC_ListBox::cursor_motion_event %d\n", __LINE__);
3453 rect_x2 = get_cursor_x();
3454 rect_y2 = get_cursor_y();
3459 update_scrollbars(1);
3460 selection_changed();
3461 //printf("BC_ListBox::cursor_motion_event %d\n", __LINE__);
3469 //printf("BC_ListBox::cursor_motion_event %d\n", __LINE__);
3479 int old_highlighted_item = highlighted_item;
3481 if(test_drag_scroll(get_cursor_x(),
3484 set_repeat(get_resources()->scroll_repeat);
3488 highlighted_item = selection_number = get_cursor_item(data,
3494 // Deselect all items and select just the one we're over
3495 if(selection_number >= 0 &&
3499 selection_mode == LISTBOX_SINGLE))
3501 redraw = update_selection(data, selection_number);
3504 if(selection_mode == LISTBOX_MULTIPLE &&
3505 (shift_down() || ctrl_down()))
3506 // Expand multiple selection
3508 // Expand selected region in text mode centered around initial range
3509 if((display_format == LISTBOX_TEXT ||
3510 display_format == LISTBOX_ICON_LIST) &&
3513 // Deselect everything.
3514 set_all_selected(data, 0);
3516 // Select just the items
3517 redraw = expand_selection(0, selection_number);
3520 // Set the one item we're over to the selection value determined in
3521 // button_press_event.
3529 if(highlighted_item != old_highlighted_item)
3533 update_scrollbars(1);
3534 //printf("BC_ListBox::cursor_motion_event %d %d\n", highlighted_item, old_highlighted_item);
3535 selection_changed();
3540 case BUTTON_DOWN_SELECT:
3541 // Went back into button area
3544 current_operation = BUTTON_DN;
3549 // Went into item area
3552 int cursor_x = 0, cursor_y = 0;
3553 translate_coordinates(top_level->event_win,
3555 top_level->cursor_x,
3556 top_level->cursor_y,
3559 int old_highlighted_item = highlighted_item;
3560 highlighted_item = selection_number = get_cursor_item(data,
3565 if(highlighted_item != old_highlighted_item)
3567 update_selection(data, selection_number);
3569 selection_changed();
3576 int redraw_toggles = 0;
3577 for(int i = 0; i < expanders.total && !result; i++)
3579 result = expanders.values[i]->cursor_motion_event(
3584 // Need to redraw items because of the alpha
3592 int cursor_x = get_cursor_x(), cursor_y = get_cursor_y();
3593 if(gui && top_level->event_win == gui->win)
3595 int old_highlighted_title = highlighted_title;
3596 int old_list_highlighted = list_highlighted;
3597 int old_highlighted_item = highlighted_item;
3598 int redraw_titles = 0;
3599 int redraw_border = 0;
3600 int redraw_items = 0;
3601 int redraw_toggles = 0;
3605 // Test if cursor moved over a title division
3606 test_column_divisions(cursor_x, cursor_y, new_cursor);
3608 // Test if cursor moved over a title
3609 if(highlighted_division < 0)
3611 test_column_titles(cursor_x, cursor_y);
3614 // Test if cursor moved over expander
3615 if(highlighted_division < 0 &&
3616 highlighted_title < 0 &&
3617 (display_format == LISTBOX_TEXT ||
3618 display_format == LISTBOX_ICON_LIST))
3620 for(int i = 0; i < expanders.total; i++)
3622 expanders.values[i]->cursor_motion_event(
3625 //printf("BC_ListBox::cursor_motion_event %d\n", redraw_toggles);
3628 // Test if cursor moved over an item
3629 if(highlighted_division < 0 &&
3630 highlighted_title < 0)
3632 highlighted_item = get_cursor_item(data,
3639 // Clear title highlighting if moved over division
3640 if(old_highlighted_title != highlighted_title)
3645 // Highlight list border
3646 if(old_list_highlighted != list_highlighted)
3651 // Moved out of item area
3652 if(old_highlighted_item != highlighted_item)
3657 //printf("BC_ListBox::cursor_motion_event 1 %d\n", highlighted_item);
3659 // Change cursor to title division adjustment
3660 reset_cursor(new_cursor);
3687 if(!result && list_highlighted)
3689 list_highlighted = 0;
3690 highlighted_item = -1;
3691 highlighted_ptr = 0;
3692 highlighted_title = -1;
3693 highlighted_division = -1;
3705 int BC_ListBox::drag_start_event()
3707 switch(current_operation)
3711 gui->is_event_win() &&
3714 BC_ListBoxItem *item_return = 0;
3715 selection_number = get_cursor_item(data,
3716 top_level->cursor_x,
3717 top_level->cursor_y,
3720 if(selection_number >= 0)
3723 if (item_return->icon_vframe)
3725 drag_popup = new BC_DragWindow(this,
3726 item_return->icon_vframe /*,
3727 get_abs_cursor_x(0) - item_return->icon_vframe->get_w() / 2,
3728 get_abs_cursor_y(0) - item_return->icon_vframe->get_h() / 2 */);
3731 // this probably works not!
3732 if (item_return->icon)
3734 drag_popup = new BC_DragWindow(this,
3735 item_return->icon /*,
3736 get_abs_cursor_x(0) - item_return->icon->get_w() / 2,
3737 get_abs_cursor_y(0) - item_return->icon->get_h() / 2 */);
3741 drag_popup = new BC_DragWindow(this,
3742 drag_icon_vframe /*,
3743 get_abs_cursor_x(0) - drag_icon_vframe->get_w() / 2,
3744 get_abs_cursor_y(0) - drag_icon_vframe->get_h() / 2 */);
3747 current_operation = DRAG_ITEM;
3754 if(gui && gui->is_event_win() && allow_drag_column)
3756 drag_popup = new BC_DragWindow(this,
3757 drag_column_icon_vframe /*,
3758 get_abs_cursor_x(0) - drag_column_icon_vframe->get_w() / 2,
3759 get_abs_cursor_y(0) - drag_column_icon_vframe->get_h() / 2 */);
3760 dragged_title = highlighted_title;
3761 current_operation = COLUMN_DRAG;
3771 int BC_ListBox::drag_motion_event()
3773 //printf("BC_ListBox::drag_motion_event 1 %d\n", current_operation);
3774 switch(current_operation)
3779 int new_highlighted_item = -1;
3780 BC_ListBoxItem *new_highlighted_ptr = 0;
3781 new_highlighted_item = get_cursor_item(data,
3782 top_level->cursor_x, top_level->cursor_y,
3783 &new_highlighted_ptr);
3785 if(new_highlighted_item != highlighted_item)
3790 // Always update highlighted value for drag_stop
3791 highlighted_item = new_highlighted_item;
3792 highlighted_ptr = new_highlighted_ptr;
3793 //printf("BC_ListBox::drag_motion_event 1 %p\n", highlighted_ptr);
3798 update_scrollbars(1);
3801 return drag_popup->cursor_motion_event();
3807 int old_highlighted_title = highlighted_title;
3808 test_column_titles(get_cursor_x(), get_cursor_y());
3809 if(old_highlighted_title != highlighted_title)
3813 return drag_popup->cursor_motion_event();
3820 int BC_ListBox::drag_stop_event()
3822 switch(current_operation)
3825 // Inside window boundary
3826 if(top_level->cursor_x > 0 &&
3827 top_level->cursor_x < gui->get_w() - drag_popup->get_w() / 2 &&
3828 top_level->cursor_y > 0 &&
3829 top_level->cursor_y < gui->get_h() - drag_popup->get_h() / 2)
3834 if(display_format == LISTBOX_ICONS)
3836 reposition_item(data,
3838 top_level->cursor_x +
3839 drag_popup->get_offset_x() -
3843 top_level->cursor_y +
3844 drag_popup->get_offset_y() -
3854 int destination = highlighted_item = item_to_index(data,
3856 //printf("BC_ListBox::drag_stop_event 1 %p %d\n", highlighted_ptr, destination);
3858 // Move selected items from data to temporary
3859 ArrayList<BC_ListBoxItem*> *src_items =
3860 new ArrayList<BC_ListBoxItem*>[columns];
3862 move_selection(src_items, data);
3864 // Insert items from temporary to data
3870 delete [] src_items;
3871 set_autoplacement(data, 0, 1);
3878 drag_popup->drag_failure_event();
3883 current_operation = NO_OPERATION;
3889 if(dragged_title != highlighted_title)
3891 if(highlighted_title >= 0)
3893 if(!move_column_event()) draw_titles(1);
3896 drag_popup->drag_failure_event();
3898 current_operation = NO_OPERATION;
3908 BC_DragWindow* BC_ListBox::get_drag_popup()
3913 int BC_ListBox::translation_event()
3917 int new_x = gui->get_x() +
3918 (top_level->last_translate_x - top_level->prev_x -
3919 BC_DisplayInfo::get_left_border());
3920 int new_y = gui->get_y() +
3921 (top_level->last_translate_y - top_level->prev_y -
3922 BC_DisplayInfo::get_top_border());
3924 gui->reposition_window(new_x, new_y);
3930 int BC_ListBox::reposition_window(int x, int y, int w, int h, int flush)
3934 if(w != -1) popup_w = w;
3935 if(h != -1) popup_h = h;
3936 //printf("BC_ListBox::reposition_window %d %d\n", popup_w, popup_h);
3940 if(w != -1) popup_w = w;
3941 if(h != -1) popup_h = h;
3943 xscrollbar->reposition_window(get_xscroll_x(),
3945 get_xscroll_width());
3947 yscrollbar->reposition_window(get_yscroll_x(),
3949 get_yscroll_height());
3954 BC_WindowBase::reposition_window(x, y, w, h);
3960 int BC_ListBox::deactivate()
3962 // printf("BC_ListBox::deactivate %d this=%p gui=%p active=%d\n",
3972 //printf("BC_ListBox::deactivate %d this=%p gui=%p\n", __LINE__, this, gui);
3981 highlighted_item = -1;
3982 highlighted_ptr = 0;
3987 //printf("BC_ListBox::deactivate %d this=%p\n", __LINE__, this);
3989 top_level->active_subwindow = 0;
3995 int BC_ListBox::activate(int take_focus)
3997 //printf("BC_ListBox::activate %d %p\n", __LINE__, this);
4002 top_level->active_subwindow = this;
4006 button_releases = 0;
4008 // Test for existence of GUI in case this was previously called without
4009 // take_focus & again with take_focus
4010 if(is_popup && !gui)
4015 y = get_y() + get_h();
4016 if(justify == LISTBOX_RIGHT)
4018 x = get_x() - popup_w + get_w();
4026 XTranslateCoordinates(top_level->display,
4035 if(new_x < 0) new_x = 0;
4036 if(new_y + popup_h > top_level->get_root_h(0))
4037 new_y -= get_h() + popup_h;
4039 add_subwindow(gui = new BC_Popup(this,
4047 // Avoid top going out of screen
4050 //printf("BC_ListBox::activate %d this=%p %p\n", __LINE__, this, gui->win);
4052 gui->show_window(1);
4054 //printf("BC_ListBox::activate %d %p\n", __LINE__, this);
4060 int BC_ListBox::keypress_event()
4062 if(!active) return 0;
4064 //printf("BC_ListBox::keypress_event %d\n", __LINE__);
4066 int result = 0, redraw = 0;
4067 int view_items = last_in_view - first_in_view + 1;
4068 if( view_items <= 0 ) view_items = view_h / get_text_height(MEDIUMFONT);
4069 int new_item = -1, new_selection = -1;
4071 switch(top_level->get_keypress())
4076 top_level->deactivate();
4078 // If user is manipulating popup with keyboard, don't pass on event.
4081 //printf("BC_ListBox::keypress_event %d %p\n", __LINE__, get_selection(0, 0));
4082 if(top_level->get_keypress() == RETURN)
4084 //printf("BC_ListBox::keypress_event %d %p\n", __LINE__, get_selection(0, 0));
4092 new_selection = new_item = select_previous(0);
4094 //printf("BC_ListBox::keypress_event 1 %d\n", new_item);
4097 center_selection(new_item);
4105 new_selection = new_item = select_next(0);
4109 center_selection(new_item);
4117 new_selection = new_item = select_previous(view_items - 1);
4121 center_selection(new_item);
4129 new_selection = new_item = select_next(view_items - 1);
4133 center_selection(new_item);
4161 int query_len = strlen(query);
4162 if( query_len < (int)sizeof(query)-1 &&
4163 top_level->get_keypress() > 30 &&
4164 top_level->get_keypress() < 127)
4166 query[query_len++] = top_level->get_keypress();
4167 query[query_len] = 0;
4168 new_selection = query_list();
4171 if(top_level->get_keypress() == BACKSPACE)
4173 if(query_len > 0) query[--query_len] = 0;
4174 new_selection = query_list();
4187 update_scrollbars(1);
4190 //printf("BC_ListBox::keypress_event %d new_selection=%d\n", __LINE__, new_selection);
4191 if(new_selection >= 0 && !is_suggestions)
4193 //printf("BC_ListBox::keypress_event %d\n", __LINE__);
4194 selection_changed();
4195 //printf("BC_ListBox::keypress_event %d\n", __LINE__);
4202 BC_Pixmap* BC_ListBox::get_bg_surface()
4208 void BC_ListBox::draw_background()
4210 if( !bg_draw ) return;
4212 // White background pixmap
4213 set_color(top_level->get_resources()->listbox_inactive);
4214 draw_box(0, 0, bg_surface->get_w(), bg_surface->get_h(), bg_surface);
4216 // Optional heroine pixmap
4218 bg_surface->draw_pixmap(bg_pixmap,
4219 bg_surface->get_w() - top_level->get_resources()->listbox_bg->get_w(),
4223 void BC_ListBox::clear_listbox(int x, int y, int w, int h)
4225 gui->draw_pixmap(bg_surface, x, y, w, h, x, y - title_h);
4228 void BC_ListBox::update_format(int display_format, int redraw)
4230 this->display_format = display_format;
4231 if( redraw && gui ) draw_items(1, 1);
4234 int BC_ListBox::get_format()
4236 return display_format;
4241 int BC_ListBox::draw_items(int flush, int draw_bg)
4245 BC_Resources *resources = get_resources();
4247 //dump(data, columns);
4249 // Calculate items width
4250 calculate_item_coords();
4253 // Create and destroy scrollbars as needed
4258 if( bg_draw ) this->bg_draw = 1;
4264 if(display_format == LISTBOX_ICONS)
4266 clear_listbox(2, 2 + title_h, view_w, view_h);
4268 set_font(MEDIUMFONT);
4269 for(int i = 0; i < data[master_column].size(); i++)
4271 BC_ListBoxItem *item = data[master_column].get(i);
4272 if(get_item_x(item) >= -get_item_w(item) &&
4273 get_item_x(item) < view_w &&
4274 get_item_y(item) >= -get_item_h(item) + title_h &&
4275 get_item_y(item) < view_h + title_h)
4277 item->set_in_view(1);
4278 if( first_in_view < 0 ) first_in_view = i;
4280 int item_color = get_item_highlight(data, 0, i);
4281 int icon_x, icon_y, icon_w, icon_h;
4282 int text_x, text_y, text_w, text_h;
4285 get_icon_mask(item, icon_x, icon_y, icon_w, icon_h);
4286 get_text_mask(item, text_x, text_y, text_w, text_h);
4289 if(item_color != resources->listbox_inactive)
4291 gui->set_color(BLACK);
4292 gui->draw_rectangle(icon_x, icon_y, icon_w, icon_h);
4293 gui->set_color(item_color);
4294 gui->draw_box(icon_x + 1, icon_y + 1, icon_w - 2, icon_h - 2);
4295 gui->set_color(BLACK);
4296 gui->draw_rectangle(text_x, text_y, text_w, text_h);
4297 gui->set_color(item_color);
4298 gui->draw_box(text_x + 1, text_y + 1, text_w - 2, text_h - 2);
4300 if(icon_position == ICON_LEFT)
4301 gui->draw_box(text_x - 1, text_y + 1, 2, text_h - 2);
4303 if(icon_position == ICON_TOP)
4304 gui->draw_line(text_x + 1, text_y, text_x + icon_w - 2, text_y);
4305 if(text_x + text_w < icon_x + icon_w)
4307 gui->set_color(BLACK);
4308 gui->draw_line(text_x + text_w,
4316 gui->set_color(get_item_color(data, 0, i));
4318 gui->pixmap->draw_pixmap(item->icon,
4319 icon_x + ICON_MARGIN,
4320 icon_y + ICON_MARGIN);
4323 gui->draw_text(text_x + ICON_MARGIN,
4324 text_y + ICON_MARGIN + get_baseline(item),
4328 item->set_in_view(0);
4334 // Draw one column at a time so text overruns don't go into the next column
4335 // clear column backgrounds
4336 int current_toggle = 0;
4337 for(int j = 0; j < columns; j++)
4339 clear_listbox(LISTBOX_BORDER + get_column_offset(j) - xposition,
4340 LISTBOX_BORDER + title_h,
4341 get_column_width(j, 1),
4343 // Draw rows in the column recursively
4344 draw_text_recursive(data, j, 0, ¤t_toggle);
4347 // Delete excess expanders
4348 while(expanders.total > current_toggle)
4350 expanders.remove_object();
4354 // draw user images if available
4356 // Draw titles on top of rows for superposition effect
4359 // Clear garbage from bottom right corner
4360 if(xscrollbar && yscrollbar && is_popup)
4362 gui->draw_top_background(parent_window,
4363 popup_w - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w(),
4364 popup_h - get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h(),
4365 get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w(),
4366 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h());
4373 if(current_operation == SELECT_RECT)
4383 void BC_ListBox::draw_text_recursive(ArrayList<BC_ListBoxItem*> *data,
4386 int *current_toggle)
4391 BC_Resources *resources = get_resources();
4393 set_font(MEDIUMFONT);
4396 // Search for a branch and make room for toggle if there is one
4399 for(int i = 0; i < data[column].size(); i++)
4401 if(data[column].get(i)->get_sublist())
4403 subindent = BC_WindowBase::get_resources()->listbox_expand[0]->get_w();
4409 row_height = row_ascent = row_descent = 0;
4410 for(int i = 0; i < data[column].total; i++)
4412 BC_ListBoxItem *item = data[column].values[i];
4413 int ht = get_text_h(item);
4414 if( ht > row_height ) row_height = ht;
4415 int bl = get_baseline(item);
4416 if( bl > row_ascent ) row_ascent = bl;
4418 if( dt > row_descent ) row_ascent = bl;
4421 for(int i = 0; i < data[column].size(); i++)
4424 BC_ListBoxItem *item = data[column].values[i];
4425 BC_ListBoxItem *first_item = data[master_column].values[i];
4427 if(get_item_y(item) >= -get_item_h(item) + title_h &&
4428 get_item_y(item) < view_h + title_h)
4430 int row_color = get_item_highlight(data, 0, i);
4431 int x, y, w, h, column_width;
4433 get_text_mask(item, x, y, w, h);
4434 column_width = get_column_width(column, 1);
4435 if(x + column_width > view_w + LISTBOX_BORDER * 2)
4436 column_width = view_w + LISTBOX_BORDER * 2 - x;
4438 if(row_color != resources->listbox_inactive)
4440 gui->set_color(row_color);
4441 gui->draw_box(x, y, column_width, h);
4442 gui->set_color(BLACK);
4443 int yy = y, xx = x + column_width-1;
4444 gui->draw_line(x, yy, xx, yy);
4445 yy = y + row_height;
4446 gui->draw_line(x, yy, xx, yy);
4449 gui->set_color(get_item_color(data, column, i));
4452 if(column == 0 && display_format == LISTBOX_ICON_LIST)
4456 gui->pixmap->draw_pixmap(item->icon,
4459 x += item->icon->get_w() + ICON_MARGIN;
4464 // Indent only applies to first column
4466 x + LISTBOX_BORDER + LISTBOX_MARGIN +
4467 (column == 0 ? indent + subindent : 0),
4468 y + get_baseline(item), item->text);
4469 item->set_in_view(1);
4471 if( first_in_view < 0 ) first_in_view = i;
4477 item->get_sublist() &&
4478 item->get_columns())
4480 // Create new expander
4481 if(*current_toggle >= expanders.total)
4483 BC_ListBoxToggle *toggle =
4484 new BC_ListBoxToggle(this,
4486 x + LISTBOX_BORDER + LISTBOX_MARGIN + indent,
4489 expanders.append(toggle);
4492 // Reposition existing expander
4494 BC_ListBoxToggle *toggle = expanders.values[*current_toggle];
4495 //printf("BC_ListBox::draw_text_recursive 1 %d\n", *current_toggle);
4496 toggle->update(item,
4497 x + LISTBOX_BORDER + LISTBOX_MARGIN + indent,
4501 (*current_toggle)++;
4508 item->set_in_view(0);
4510 // Descend into sublist
4511 if(first_item->get_expand())
4513 draw_text_recursive(first_item->get_sublist(),
4515 indent + LISTBOX_INDENT,
4524 int BC_ListBox::draw_border(int flash)
4526 BC_Resources *resources = top_level->get_resources();
4527 gui->draw_3d_border(0,
4529 view_w + LISTBOX_BORDER * 2,
4530 view_h + title_h + LISTBOX_BORDER * 2,
4531 resources->listbox_border1,
4533 resources->listbox_border2_hi :
4534 resources->listbox_border2,
4536 resources->listbox_border3_hi :
4537 resources->listbox_border3,
4538 resources->listbox_border4);
4548 void BC_ListBox::draw_title(int number)
4550 // Column title background
4551 int image_number = 0;
4552 if(number == highlighted_title)
4555 if(current_operation == COLUMN_DN)
4559 int column_offset = get_column_offset(number) - xposition + LISTBOX_BORDER;
4560 int column_width = get_column_width(number, 1);
4561 gui->draw_3segmenth(get_column_offset(number) - xposition + LISTBOX_BORDER,
4563 get_column_width(number, 1) + get_resources()->listbox_title_overlap,
4564 column_bg[image_number]);
4566 // Column title sort order
4567 if(number == sort_column)
4570 if(sort_order == SORT_ASCENDING)
4571 src = column_sort_dn;
4573 src = column_sort_up;
4575 int x = column_offset +
4578 if(x > items_w) x = items_w;
4579 x -= 5 + src->get_w();
4580 gui->draw_pixmap(src,
4582 title_h / 2 - src->get_h() / 2 + LISTBOX_BORDER);
4586 int x = -xposition +
4587 get_column_offset(number) +
4590 x += get_resources()->listbox_title_margin;
4592 gui->set_color(get_resources()->listbox_title_color);
4594 LISTBOX_MARGIN + LISTBOX_BORDER + get_text_ascent(MEDIUMFONT),
4595 _(column_titles[number]));
4598 int BC_ListBox::draw_titles(int flash)
4601 (display_format == LISTBOX_TEXT ||
4602 display_format == LISTBOX_ICON_LIST))
4604 //printf("BC_ListBox::draw_titles 1 %d\n", highlighted_title);
4605 for(int i = 0; i < columns; i++)
4607 if(i != highlighted_title)
4611 if(highlighted_title >= 0) draw_title(highlighted_title);
4622 void BC_ListBox::draw_toggles(int flash)
4624 for(int i = 0; i < expanders.total; i++)
4625 expanders.values[i]->draw(0);
4627 //printf("BC_ListBox::draw_toggles 1 %d\n", flash);
4628 if(flash && expanders.total)
4635 int BC_ListBox::draw_rectangle(int flash)
4637 int x1 = MIN(rect_x1, rect_x2);
4638 int x2 = MAX(rect_x1, rect_x2);
4639 int y1 = MIN(rect_y1, rect_y2);
4640 int y2 = MAX(rect_y1, rect_y2);
4642 if(x1 == x2 || y1 == y2) return 0;
4645 gui->set_color(WHITE);
4646 gui->draw_rectangle(x1, y1, x2 - x1, y2 - y1);
4657 void BC_ListBox::dump(ArrayList<BC_ListBoxItem*> *data,
4664 printf("BC_ListBox::dump 1\n");
4667 for(int i = 0; i < data[master_column].total; i++)
4669 for(int k = 0; k < indent; k++)
4671 for(int j = 0; j < columns; j++)
4673 BC_ListBoxItem *item = data[j].values[i];
4674 printf("%d,%d,%d=%s ",
4677 item->autoplace_text,
4682 if(data[master_column].values[i]->get_sublist())
4684 dump(data[master_column].values[i]->get_sublist(),
4685 data[master_column].values[i]->get_columns(),