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());
67 int BC_ListBoxYScroll::update_length(int64_t length, int64_t position, int64_t handlelength, int flush)
69 return BC_ScrollBar::update_length(length+handlelength/4, position, handlelength, flush);
77 BC_ListBoxXScroll::BC_ListBoxXScroll(BC_ListBox *listbox,
81 : BC_ScrollBar(listbox->get_xscroll_x(),
82 listbox->get_xscroll_y(),
84 listbox->get_xscroll_width(),
89 this->listbox = listbox;
92 BC_ListBoxXScroll::~BC_ListBoxXScroll()
96 int BC_ListBoxXScroll::handle_event()
98 listbox->set_xposition(get_value());
102 int BC_ListBoxXScroll::update_length(int64_t length, int64_t position, int64_t handlelength, int flush)
104 return BC_ScrollBar::update_length(length+handlelength/4, position, handlelength, flush);
113 BC_ListBoxToggle::BC_ListBoxToggle(BC_ListBox *listbox,
114 BC_ListBoxItem *item,
118 this->listbox = listbox;
122 this->value = item->get_expand();
124 state = BC_Toggle::TOGGLE_CHECKED;
126 state = BC_Toggle::TOGGLE_UP;
129 void BC_ListBoxToggle::update(BC_ListBoxItem *item,
134 this->value = item->get_expand();
144 state = TOGGLE_CHECKED;
149 state = TOGGLE_CHECKEDHI;
160 case TOGGLE_CHECKEDHI:
165 case TOGGLE_DOWN_EXIT:
173 int BC_ListBoxToggle::cursor_motion_event(int *redraw_toggles)
175 int w = listbox->toggle_images[0]->get_w();
176 int h = listbox->toggle_images[0]->get_h();
177 int cursor_inside = listbox->get_cursor_x() >= x &&
178 listbox->get_cursor_x() < x + w &&
179 listbox->get_cursor_y() >= y &&
180 listbox->get_cursor_y() < y + h;
185 case BC_ListBoxToggle::TOGGLE_UPHI:
188 state = BC_ListBoxToggle::TOGGLE_UP;
193 case BC_ListBoxToggle::TOGGLE_CHECKEDHI:
196 state = BC_ListBoxToggle::TOGGLE_CHECKED;
201 case BC_ListBoxToggle::TOGGLE_DOWN:
204 state = BC_ListBoxToggle::TOGGLE_DOWN_EXIT;
210 case BC_ListBoxToggle::TOGGLE_DOWN_EXIT:
213 state = BC_ListBoxToggle::TOGGLE_DOWN;
223 state = BC_ListBoxToggle::TOGGLE_CHECKEDHI;
225 state = BC_ListBoxToggle::TOGGLE_UPHI;
233 int BC_ListBoxToggle::cursor_leave_event(int *redraw_toggles)
236 state = BC_ListBoxToggle::TOGGLE_CHECKED;
238 state = BC_ListBoxToggle::TOGGLE_UP;
242 int BC_ListBoxToggle::button_press_event()
244 int w = listbox->toggle_images[0]->get_w();
245 int h = listbox->toggle_images[0]->get_h();
247 if(listbox->gui->get_cursor_x() >= x &&
248 listbox->gui->get_cursor_x() < x + w &&
249 listbox->gui->get_cursor_y() >= y &&
250 listbox->gui->get_cursor_y() < y + h)
252 state = BC_ListBoxToggle::TOGGLE_DOWN;
258 int BC_ListBoxToggle::button_release_event(int *redraw_toggles)
264 case BC_ListBoxToggle::TOGGLE_DOWN:
267 state = BC_ListBoxToggle::TOGGLE_CHECKEDHI;
269 state = BC_ListBoxToggle::TOGGLE_UPHI;
270 listbox->expand_item(item, value);
274 case BC_ListBoxToggle::TOGGLE_DOWN_EXIT:
276 state = BC_ListBoxToggle::TOGGLE_CHECKED;
278 state = BC_ListBoxToggle::TOGGLE_UP;
286 void BC_ListBoxToggle::draw(int flash)
290 int image_number = 0;
291 int w = listbox->toggle_images[0]->get_w();
292 int h = listbox->toggle_images[0]->get_h();
296 case BC_ListBoxToggle::TOGGLE_UP: image_number = 0; break;
297 case BC_ListBoxToggle::TOGGLE_UPHI: image_number = 1; break;
298 case BC_ListBoxToggle::TOGGLE_CHECKED: image_number = 2; break;
299 case BC_ListBoxToggle::TOGGLE_DOWN: image_number = 3; break;
300 case BC_ListBoxToggle::TOGGLE_CHECKEDHI: image_number = 4; break;
301 case BC_ListBoxToggle::TOGGLE_DOWN_EXIT:
309 //printf("BC_ListBoxToggle::draw 1 %d\n", state);
310 listbox->gui->draw_pixmap(listbox->toggle_images[image_number],
317 listbox->gui->flash(x, y, w, h);
318 listbox->gui->flush();
336 // ====================================================== box
338 BC_ListBox::BC_ListBox(int x,
343 ArrayList<BC_ListBoxItem*> *data,
344 const char **column_titles,
352 : BC_SubWindow(x, y, w, h, -1)
354 justify = LISTBOX_RIGHT;
356 highlighted_item = -1;
357 highlighted_title = -1;
358 highlighted_division = -1;
362 current_cursor = ARROW_CURSOR;
375 selection_number1 = -1;
376 selection_number2 = -1;
379 row_height = row_ascent = row_descent = 0;
382 current_operation = NO_OPERATION;
383 button_highlighted = 0;
384 list_highlighted = 0;
387 allow_drag_scroll = 1;
393 allow_drag_column = 0;
400 for(int i = 0; i < 3; i++) column_bg[i] = 0;
401 for(int i = 0; i < 4; i++) button_images[i] = 0;
402 for(int i = 0; i < 5; i++) toggle_images[i] = 0;
407 //printf("BC_ListBox::BC_ListBox 1\n");
409 this->columns = columns;
410 this->yposition = yposition;
411 this->is_popup = is_popup;
412 this->use_button = 1;
413 this->display_format = display_format;
414 this->selection_mode = selection_mode;
415 this->icon_position = icon_position;
416 this->allow_drag = allow_drag;
417 this->column_titles = 0;
418 this->column_width = 0;
419 this->first_in_view = -1;
420 this->last_in_view = 0;
421 //printf("BC_ListBox::BC_ListBox 1\n");
423 if((!column_titles && column_width) ||
424 (column_titles && !column_width))
426 printf("BC_ListBox::BC_ListBox either column_titles or column_widths == NULL but not both.\n");
428 //printf("BC_ListBox::BC_ListBox 2 %p %p\n", column_titles, column_width);
430 set_columns(column_titles,
434 //printf("BC_ListBox::BC_ListBox 3\n");
436 drag_icon_vframe = 0;
437 drag_column_icon_vframe = 0;
441 // reset the search engine
442 //printf("BC_ListBox::BC_ListBox 4\n");
445 //printf("BC_ListBox::BC_ListBox 5\n");
448 BC_ListBox::~BC_ListBox()
450 expanders.remove_all_objects();
451 if(bg_surface) delete bg_surface;
452 if(bg_pixmap) delete bg_pixmap;
453 if(xscrollbar) delete xscrollbar;
454 if(yscrollbar) delete yscrollbar;
455 for(int i = 0; i < 3; i++) delete column_bg[i];
456 for(int i = 0; i < 4; i++) delete button_images[i];
457 for(int i = 0; i < 5; i++) delete toggle_images[i];
458 if(column_sort_up) delete column_sort_up;
459 if(column_sort_dn) delete column_sort_dn;
462 if(drag_popup) delete drag_popup;
465 int BC_ListBox::enable()
472 int BC_ListBox::disable()
479 void BC_ListBox::reset_query()
481 query[0] = 0; // reset query
484 int BC_ListBox::evaluate_query(char *string)
486 for(int i = 0; i < data[search_column].size(); i++)
488 if(strcmp(string, data[search_column].get(i)->text) <= 0 &&
489 data[search_column].get(i)->searchable)
498 int BC_ListBox::query_list()
500 if(query[0] == 0) return 0;
504 int selection_changed = 0;
505 int prev_selection = -1;
506 result = evaluate_query(query);
507 if(result >= 0) done = 1;
512 for(int i = 0; i < data[0].total; i++)
514 for(int j = 0; j < columns; j++)
516 if(data[j].values[i]->selected) prev_selection = i;
517 data[j].values[i]->selected = 0;
522 if(prev_selection != result)
523 selection_changed = 1;
524 for(int j = 0; j < columns; j++)
526 data[j].values[result]->selected = 1;
528 center_selection(result);
531 return selection_changed;
534 void BC_ListBox::init_column_width()
536 if(!column_width && data)
539 for(int i = 0; i < data[0].total; i++)
541 wd = get_text_w(data[0].values[i]);
542 if( wd > widest ) widest = wd;
544 default_column_width[0] = widest + 2 * LISTBOX_MARGIN;
548 int BC_ListBox::initialize()
554 for( int i = 0; i < 4; ++i )
556 button_images[i] = new BC_Pixmap(parent_window,
557 BC_WindowBase::get_resources()->listbox_button[i],
560 w = button_images[0]->get_w();
561 h = button_images[0]->get_h();
565 current_operation = NO_OPERATION;
571 current_operation = NO_OPERATION;
574 for(int i = 0; i < 3; i++)
576 column_bg[i] = new BC_Pixmap(parent_window,
577 get_resources()->listbox_column[i],
580 for(int i = 0; i < 5; i++)
582 toggle_images[i] = new BC_Pixmap(parent_window,
583 get_resources()->listbox_expand[i],
587 column_sort_up = new BC_Pixmap(parent_window,
588 BC_WindowBase::get_resources()->listbox_up,
590 column_sort_dn = new BC_Pixmap(parent_window,
591 BC_WindowBase::get_resources()->listbox_dn,
594 //printf("BC_ListBox::initialize 10\n");
595 drag_icon_vframe = get_resources()->type_to_icon[ICON_UNKNOWN];
596 drag_column_icon_vframe = get_resources()->type_to_icon[ICON_COLUMN];
597 // = new BC_Pixmap(parent_window,
598 // get_resources()->type_to_icon[ICON_UNKNOWN],
600 // drag_column_icon = new BC_Pixmap(parent_window,
601 // get_resources()->type_to_icon[ICON_COLUMN],
603 BC_SubWindow::initialize();
607 if(top_level->get_resources()->listbox_bg)
608 bg_pixmap = new BC_Pixmap(this,
609 get_resources()->listbox_bg,
615 if(!use_button && is_popup)
624 void BC_ListBox::deactivate_selection()
626 current_operation = NO_OPERATION;
629 int BC_ListBox::draw_button(int flush)
631 // Draw the button for a popup listbox
632 if(use_button && is_popup)
634 int image_number = 0;
636 draw_top_background(parent_window, 0, 0, w, h);
638 if(button_highlighted)
640 if(current_operation == BUTTON_DN)
646 pixmap->draw_pixmap(button_images[image_number],
658 int BC_ListBox::calculate_item_coords()
666 // Change the display_format to get the right item dimensions for both
668 temp_display_format = display_format;
671 // Scan the first column for lowest y coord of all text
672 // and lowest right x and y coord for all icons which aren't auto placable
673 calculate_last_coords_recursive(data,
680 // Reset last column width. It's recalculated based on text width.
682 calculate_item_coords_recursive(data,
691 display_format = temp_display_format;
696 void BC_ListBox::calculate_last_coords_recursive(
697 ArrayList<BC_ListBoxItem*> *data,
704 for(int i = 0; i < data[0].size(); i++)
706 int current_text_y = 0;
707 int current_icon_x = 0;
708 int current_icon_y = 0;
709 BC_ListBoxItem *item = data[0].get(i);
712 if(!item->autoplace_text)
714 // Lowest text coordinate
715 display_format = LISTBOX_TEXT;
716 current_text_y = item->text_y + get_text_h(item);
717 if(current_text_y > *next_text_y)
718 *next_text_y = current_text_y;
720 // Add sublist depth if it is expanded
721 if(item->get_sublist() &&
722 item->get_columns() &&
725 calculate_last_coords_recursive(item->get_sublist(),
734 // Get next_icon coordinate
737 BC_ListBoxItem *item = data[master_column].get(i);
738 if(!item->autoplace_icon)
740 display_format = LISTBOX_ICONS;
741 // Lowest right icon coordinate.
742 current_icon_x = item->icon_x;
743 if(current_icon_x > *icon_x) *icon_x = current_icon_x;
744 if(current_icon_x + get_item_w(item) > *next_icon_x) {
745 *next_icon_x = current_icon_x + get_item_w(item);
748 current_icon_y = item->icon_y + get_item_h(item);
749 if(current_icon_y > *next_icon_y)
750 *next_icon_y = current_icon_y;
757 void BC_ListBox::calculate_item_coords_recursive(
758 ArrayList<BC_ListBoxItem*> *data,
765 // get maximum height of an icon
766 row_height = get_text_height(MEDIUMFONT);
767 if(temp_display_format == LISTBOX_ICON_LIST)
769 for(int i = 0; i < data[0].size(); i++)
771 if(data[0].get(i)->icon)
773 if(data[0].get(i)->icon->get_h() > row_height)
774 row_height = data[0].get(i)->icon->get_h();
780 // Set up items which need autoplacement.
781 // Should fill icons down and then across
782 for(int i = 0; i < data[0].size(); i++)
784 // Don't increase y unless the row requires autoplacing.
785 int total_autoplaced_columns = 0;
787 // Set up icons in first column
790 BC_ListBoxItem *item = data[master_column].get(i);
791 if(item->autoplace_icon)
793 // 1 column only if icons are used
794 display_format = LISTBOX_ICONS;
797 if(*next_icon_y + get_item_h(item) >= get_h() &&
800 *icon_x = *next_icon_x;
804 if(*icon_x + get_item_w(item) > *next_icon_x)
805 *next_icon_x = *icon_x + get_item_w(item);
808 item->set_icon_x(*icon_x);
809 item->set_icon_y(*next_icon_y);
811 *next_icon_y += get_item_h(item);
819 row_ascent = row_descent = 0;
820 // row_height still holds icon max height
821 for(int j = 0; j < columns; j++)
823 BC_ListBoxItem *item = data[j].get(i);
824 if(item->autoplace_text)
826 display_format = LISTBOX_TEXT;
827 item->set_text_x(next_text_x);
828 item->set_text_y(*next_text_y);
829 int ht = get_text_h(item);
830 if( ht > row_height ) row_height = ht;
831 int bl = get_baseline(item);
832 if( bl > row_ascent ) row_ascent = bl;
834 if( dt > row_descent ) row_ascent = bl;
836 // printf("BC_ListBox::calculate_item_coords_recursive %p %d %d %d %d %s \n",
837 // item->get_sublist(),
838 // item->get_columns(),
839 // item->get_expand(),
842 // item->get_text());
843 // Increment position of next column
846 next_text_x += (column_width ?
848 default_column_width[j]);
851 // Set last column width based on text width
853 int new_w = get_item_w(item);
855 int *previous_w = (column_width ?
857 &default_column_width[j]);
858 if(new_w > *previous_w)
860 //printf("BC_ListBox::calculate_item_coords_recursive 1 %d\n", new_w);
862 total_autoplaced_columns++;
866 // Increase the text vertical position
867 if(total_autoplaced_columns)
869 display_format = LISTBOX_TEXT;
870 *next_text_y += row_height;
874 BC_ListBoxItem *item = data[master_column].values[i];
875 if(item->get_sublist() &&
876 item->get_columns() &&
879 calculate_item_coords_recursive(
890 void BC_ListBox::set_is_suggestions(int value)
892 this->is_suggestions = value;
895 void BC_ListBox::set_use_button(int value)
897 this->use_button = value;
900 void BC_ListBox::set_justify(int value)
902 this->justify = value;
905 void BC_ListBox::set_allow_drag_column(int value)
907 this->allow_drag_column = value;
910 void BC_ListBox::set_process_drag(int value)
912 this->process_drag = value;
915 void BC_ListBox::set_master_column(int value, int redraw)
917 this->master_column = value;
924 void BC_ListBox::set_search_column(int value)
926 this->search_column = value;
929 int BC_ListBox::get_sort_column()
934 void BC_ListBox::set_sort_column(int value, int redraw)
943 int BC_ListBox::get_sort_order()
948 void BC_ListBox::set_sort_order(int value, int redraw)
961 int BC_ListBox::get_display_mode()
963 return display_format;
966 int BC_ListBox::get_yposition()
971 int BC_ListBox::get_xposition()
976 int BC_ListBox::get_highlighted_item()
978 return highlighted_item;
982 int BC_ListBox::get_item_x(BC_ListBoxItem *item)
984 if(display_format == LISTBOX_TEXT)
986 return item->text_x - xposition + 2;
989 if(display_format == LISTBOX_ICON_LIST)
991 return item->text_x - xposition + 2;
995 return item->icon_x - xposition + 2;
999 int BC_ListBox::get_item_y(BC_ListBoxItem *item)
1002 if(display_format == LISTBOX_TEXT)
1004 result = item->text_y - yposition + title_h + 2;
1007 if(display_format == LISTBOX_ICON_LIST)
1009 result = item->text_y - yposition + title_h + 2;
1013 result = item->icon_y - yposition + title_h + 2;
1019 int BC_ListBox::get_item_w(BC_ListBoxItem *item)
1021 if(display_format == LISTBOX_ICONS)
1024 get_icon_mask(item, x, y, w, h);
1026 get_text_mask(item, x, y, w, h);
1029 return icon_position == ICON_LEFT ? icon_w + text_w :
1030 icon_w > text_w ? icon_w : text_w;
1032 return get_text_w(item) + 2 * LISTBOX_MARGIN;
1035 int BC_ListBox::get_item_h(BC_ListBoxItem *item)
1037 if(display_format == LISTBOX_ICONS)
1040 get_icon_mask(item, x, y, w, h);
1042 get_text_mask(item, x, y, w, h);
1045 return icon_position != ICON_LEFT ? icon_h + text_h :
1046 icon_h > text_h ? icon_h : text_h;
1048 return get_text_h(item);
1052 int BC_ListBox::get_icon_w(BC_ListBoxItem *item)
1054 return item->get_icon_w();
1057 int BC_ListBox::get_icon_h(BC_ListBoxItem *item)
1059 return item->get_icon_h();
1062 int BC_ListBox::get_text_w(BC_ListBoxItem *item)
1064 int w = item->get_text_w();
1065 if( w < 0 ) item->set_text_w(w = get_text_width(MEDIUMFONT, item->get_text()));
1069 int BC_ListBox::get_text_h(BC_ListBoxItem *item)
1071 int h = item->get_text_h();
1072 if( h < 0 ) item->set_text_h(h = get_text_height(MEDIUMFONT, item->get_text()));
1076 int BC_ListBox::get_baseline(BC_ListBoxItem *item)
1078 int b = item->get_baseline();
1079 if( b < 0 ) item->set_baseline(b = get_text_ascent(MEDIUMFONT));
1083 int BC_ListBox::get_items_width()
1087 if(display_format == LISTBOX_ICONS)
1089 for(int i = 0; i < columns; i++)
1091 for(int j = 0; j < data[i].total; j++)
1094 BC_ListBoxItem *item = data[i].values[j];
1097 get_icon_mask(item, x, y, w, h);
1098 if(x1 + w > widest) widest = x1 + w;
1100 if(display_format == LISTBOX_ICONS && icon_position == ICON_LEFT)
1103 get_text_mask(item, x, y, w, h);
1104 if(x1 + w > widest) widest = x1 + w;
1109 if(display_format == LISTBOX_TEXT)
1111 return get_column_offset(columns);
1115 return get_column_offset(columns);
1120 int BC_ListBox::get_items_height(ArrayList<BC_ListBoxItem*> *data,
1137 for(int j = 0; j < (data ? data[master_column].total : 0); j++)
1140 BC_ListBoxItem *item = data[master_column].values[j];
1142 if( display_format == LISTBOX_ICONS ||
1143 display_format == LISTBOX_ICON_LIST ) {
1144 get_icon_mask(item, x, y, w, h);
1145 if(y + h + yposition > highest) highest = y + h + yposition;
1147 get_text_mask(item, x, y, w, h);
1148 if(y + h + yposition > highest) highest = y + h + yposition;
1152 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 && top_level )
1167 highest = LISTBOX_MARGIN + *result;
1174 int BC_ListBox::set_yposition(int position, int draw_items)
1176 this->yposition = position;
1179 this->draw_items(1);
1184 int BC_ListBox::set_xposition(int position)
1186 this->xposition = position;
1191 void BC_ListBox::expand_item(BC_ListBoxItem *item, int expand)
1195 item->expand = expand;
1196 // Collapse sublists if this is collapsed to make it easier to calculate
1198 if(item->get_sublist())
1199 collapse_recursive(item->get_sublist(), master_column);
1202 // Set everything for autoplacement
1204 set_autoplacement(data, 0, 1);
1210 void BC_ListBox::collapse_recursive(ArrayList<BC_ListBoxItem*> *data,
1213 for(int i = 0; i < data[master_column].total; i++)
1215 BC_ListBoxItem *item = data[master_column].values[i];
1216 if(item->get_sublist() && item->expand)
1219 collapse_recursive(item->get_sublist(), master_column);
1224 void BC_ListBox::set_autoplacement(ArrayList<BC_ListBoxItem*> *data,
1228 for(int i = 0; i < data[0].total; i++)
1230 for(int j = 0; j < columns; j++)
1232 if(do_icons) data[j].values[i]->autoplace_icon = 1;
1233 if(do_text) data[j].values[i]->autoplace_text = 1;
1236 BC_ListBoxItem *item = data[master_column].values[i];
1237 if(item->get_sublist())
1239 set_autoplacement(item->get_sublist(), do_icons, do_text);
1246 int BC_ListBox::get_yscroll_x()
1249 return popup_w - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w();
1253 get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w();
1256 int BC_ListBox::get_yscroll_y()
1264 int BC_ListBox::get_yscroll_height()
1266 return popup_h - (need_xscroll ?
1267 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h() :
1271 int BC_ListBox::get_xscroll_x()
1279 int BC_ListBox::get_xscroll_y()
1283 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h();
1287 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h();
1290 int BC_ListBox::get_xscroll_width()
1292 return popup_w - (need_yscroll ?
1293 get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w() :
1297 int BC_ListBox::get_column_offset(int column)
1303 column_width[--column] :
1304 default_column_width[--column];
1309 void BC_ListBox::column_width_boundaries()
1312 for(int i = 0; i < columns; i++) {
1313 if(column_width[i] < MIN_COLUMN_WIDTH)
1314 column_width[i] = MIN_COLUMN_WIDTH;
1318 for(int i = 0; i < columns; i++) {
1319 if(default_column_width[i] < MIN_COLUMN_WIDTH)
1320 default_column_width[i] = MIN_COLUMN_WIDTH;
1325 int BC_ListBox::get_column_width(int column, int clamp_right)
1327 if(column < columns - 1 || !clamp_right)
1328 return column_width ? column_width[column] : default_column_width[column];
1329 return popup_w + xposition - get_column_offset(column);
1332 int BC_ListBox::get_icon_mask(BC_ListBoxItem *item,
1333 int &x, int &y, int &w, int &h)
1335 if( display_format == LISTBOX_ICONS ) {
1336 x = get_item_x(item);
1337 y = get_item_y(item);
1338 w = get_icon_w(item) + ICON_MARGIN * 2;
1339 h = get_icon_h(item) + ICON_MARGIN * 2;
1346 int BC_ListBox::get_text_mask(BC_ListBoxItem *item,
1347 int &x, int &y, int &w, int &h)
1349 x = get_item_x(item);
1350 y = get_item_y(item);
1352 if(display_format == LISTBOX_ICONS) {
1353 if(icon_position == ICON_LEFT) {
1354 x += get_icon_w(item) + ICON_MARGIN * 2;
1355 y += get_icon_h(item) - get_text_h(item);
1358 y += get_icon_h(item) + ICON_MARGIN;
1361 w = get_text_w(item) + ICON_MARGIN * 2;
1362 h = get_text_h(item) + ICON_MARGIN * 2;
1365 if(display_format == LISTBOX_TEXT) {
1366 w = get_text_w(item) + LISTBOX_MARGIN * 2;
1367 h = get_text_h(item);
1371 w = get_text_width(MEDIUMFONT, item->text) + LISTBOX_MARGIN * 2;
1373 int ih = get_icon_h(item);
1374 if( h < ih ) h = ih;
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;
2432 // Cursor is inside items rectangle
2434 cursor_x < (yscrollbar ?
2435 gui->get_w() - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w() :
2437 // Only clamp y if we're not in a SELECT operation.
2438 (current_operation == BC_ListBox::SELECT ||
2439 (cursor_y > get_title_h() + LISTBOX_BORDER &&
2440 cursor_y < gui->get_h())))
2442 // Search table for cursor obstruction
2443 for(int i = 0; i < data[master_column].total; i++)
2445 BC_ListBoxItem *item = data[master_column].values[i];
2448 // Cursor is inside item on current level
2451 cursor_y >= get_item_y(item) &&
2452 cursor_y < get_item_y(item) + get_item_h(item))
2454 //printf("BC_ListBox::get_cursor_item %d %d %p\n", master_column, i, item);
2455 if(item_return) (*item_return) = item;
2459 // Descend into sublist
2460 if(item->get_sublist())
2462 if(get_cursor_item(item->get_sublist(),
2467 item->get_expand()) >= 0)
2476 int BC_ListBox::repeat_event(int64_t duration)
2478 switch(current_operation)
2480 // Repeat out of bounds selection
2482 if(duration == get_resources()->scroll_repeat)
2483 return rectangle_scroll_event();
2487 if(duration == get_resources()->scroll_repeat)
2488 return select_scroll_event();
2493 if(button_highlighted && is_popup &&
2494 tooltip_text && tooltip_text[0] != 0 &&
2495 duration == get_resources()->tooltip_delay)
2506 int BC_ListBox::cursor_enter_event()
2510 switch(current_operation)
2512 // Cursor moved over button, pressed, and exited.
2513 case BUTTON_DOWN_SELECT:
2514 if(top_level->event_win == win)
2516 current_operation = BUTTON_DN;
2518 button_highlighted = 1;
2524 // Cursor entered button
2525 if(is_popup && top_level->event_win == win)
2527 button_highlighted = 1;
2532 // TODO: Need to get the highlighted column title or item
2533 if(gui && top_level->event_win == gui->win)
2535 list_highlighted = 1;
2545 int BC_ListBox::cursor_leave_event()
2547 if(current_operation == COLUMN_DRAG) return 0;
2550 if(button_highlighted)
2552 button_highlighted = 0;
2557 if(list_highlighted)
2559 list_highlighted = 0;
2560 highlighted_item = -1;
2561 highlighted_ptr = 0;
2562 highlighted_title = -1;
2563 int redraw_toggles = 0;
2564 for(int i = 0; i < expanders.total; i++)
2565 expanders.values[i]->cursor_leave_event(&redraw_toggles);
2573 int BC_ListBox::get_first_selection(ArrayList<BC_ListBoxItem*> *data, int *result)
2576 if(!result) result = &temp;
2578 for(int i = 0; i < data[master_column].total; i++)
2580 BC_ListBoxItem *item = data[master_column].values[i];
2582 if(item->selected) return (*result);
2583 if(item->get_sublist())
2585 if(get_first_selection(item->get_sublist(), result) >= 0)
2592 int BC_ListBox::get_total_items(ArrayList<BC_ListBoxItem*> *data,
2597 if(!result) result = &temp;
2599 for(int i = 0; i < data[master_column].total; i++)
2602 if(data[master_column].values[i]->get_sublist())
2603 get_total_items(data[master_column].values[i]->get_sublist(),
2612 int BC_ListBox::get_last_selection(ArrayList<BC_ListBoxItem*> *data,
2623 for(int i = data[master_column].total - 1; i >= 0; i--)
2625 BC_ListBoxItem *item = data[master_column].values[i];
2630 return get_total_items(data, 0, master_column) - (*result) /* - 1 */;
2635 if(item->get_sublist())
2637 if(get_last_selection(item->get_sublist(), result) >= 0)
2640 return get_total_items(data, 0, master_column) - (*result) /* - 1 */;
2649 void BC_ListBox::select_range(ArrayList<BC_ListBoxItem*> *data,
2655 if(!current) current = &temp;
2657 for(int i = 0; i < data[master_column].total; i++)
2660 if((*current) >= start && (*current) < end)
2662 for(int j = 0; j < columns; j++)
2663 data[j].values[i]->selected = 1;
2665 BC_ListBoxItem *item = data[master_column].values[i];
2666 if(item->get_sublist())
2667 select_range(item->get_sublist(),
2675 // Fill items between current selection and new selection
2676 int BC_ListBox::expand_selection(int button_press, int selection_number)
2678 int old_selection_start = selection_start;
2679 int old_selection_end = selection_end;
2681 // printf("BC_ListBox::expand_selection %d %d\n",
2682 // selection_center,
2683 // selection_number);
2685 // Calculate the range to select based on selection_center and selection_number
2686 if(selection_number < selection_center)
2688 selection_start = selection_number;
2692 selection_end = selection_number + 1;
2695 //printf("BC_ListBox::expand_selection %d %d %d %d\n", old_selection_start, old_selection_end, selection_start, selection_end);
2696 // Recurse through all the items and select the desired range
2697 select_range(data, selection_start, selection_end);
2700 return (old_selection_start != selection_start ||
2701 old_selection_end != selection_end);
2704 int BC_ListBox::toggle_item_selection(ArrayList<BC_ListBoxItem*> *data,
2705 int selection_number,
2709 if(!counter) counter = &temp;
2711 for(int i = 0; i < data[master_column].total; i++)
2713 BC_ListBoxItem *item = data[master_column].values[i];
2715 if((*counter) == selection_number)
2717 // Get new value for selection
2718 int selected = !item->selected;
2720 for(int j = 0; j < columns; j++)
2721 data[j].values[i]->selected = selected;
2725 // Descend into sublist
2726 if(item->get_sublist())
2728 if(toggle_item_selection(item->get_sublist(),
2739 void BC_ListBox::set_all_selected(ArrayList<BC_ListBoxItem*> *data, int value)
2741 for(int i = 0; i < data[master_column].total; i++)
2743 for(int j = 0; j < columns; j++)
2745 BC_ListBoxItem *item = data[j].values[i];
2746 item->selected = value;
2748 BC_ListBoxItem *item = data[master_column].values[i];
2749 if(item->get_sublist())
2751 set_all_selected(item->get_sublist(), value);
2756 void BC_ListBox::set_selected(ArrayList<BC_ListBoxItem*> *data,
2762 if(!counter) counter = &temp;
2763 for(int i = 0; i < data[master_column].total && (*counter) != item_number; i++)
2766 if((*counter) == item_number)
2768 for(int j = 0; j < columns; j++)
2770 BC_ListBoxItem *item = data[j].values[i];
2771 item->selected = value;
2776 BC_ListBoxItem *item = data[master_column].values[i];
2777 if(item->get_sublist())
2779 set_selected(item->get_sublist(),
2787 int BC_ListBox::update_selection(ArrayList<BC_ListBoxItem*> *data,
2788 int selection_number,
2793 if(!counter) counter = &temp;
2795 for(int i = 0; i < data[master_column].total; i++)
2797 BC_ListBoxItem *item = data[master_column].values[i];
2799 if((*counter) == selection_number && !item->selected)
2802 for(int j = 0; j < columns; j++)
2803 data[j].values[i]->selected = 1;
2806 if((*counter) != selection_number && item->selected)
2809 for(int j = 0; j < columns; j++)
2810 data[j].values[i]->selected = 0;
2812 if(item->get_sublist())
2813 result |= update_selection(item->get_sublist(),
2820 void BC_ListBox::promote_selections(ArrayList<BC_ListBoxItem*> *data,
2824 for(int i = 0; i < data[master_column].total; i++)
2826 for(int j = 0; j < columns; j++)
2828 BC_ListBoxItem *item = data[j].values[i];
2829 if(item->selected == old_value) item->selected = new_value;
2831 BC_ListBoxItem *item = data[master_column].values[i];
2832 if(item->get_sublist())
2833 promote_selections(item->get_sublist(), old_value, new_value);
2837 int BC_ListBox::focus_out_event()
2843 int BC_ListBox::button_press_event()
2846 BC_ListBoxItem *current_item = 0;
2848 int do_selection_change = 0;
2849 const int debug = 0;
2852 if(debug) printf("BC_ListBox::button_press_event %d this=%p event_win=%p %p %p %p\n",
2855 (void*)top_level->event_win,
2856 (void*)(gui ? gui->win : 0),
2858 (void*)parent_window->win);
2860 // Pressed in button
2861 if(is_popup && top_level->event_win == win)
2863 if(debug) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2864 current_operation = BUTTON_DN;
2868 if(!active && !disabled)
2870 top_level->deactivate();
2877 // Pressed in scrollbar
2878 if((xscrollbar && top_level->event_win == xscrollbar->win) ||
2879 (yscrollbar && top_level->event_win == yscrollbar->win))
2881 if(debug) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2886 if(gui && top_level->event_win == gui->win)
2888 if(debug) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2890 // Activate list items
2891 // If it is a suggestion popup, it is visible without being active
2894 if(debug) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2895 if(!is_suggestions) top_level->deactivate();
2896 if(debug) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2898 if(debug) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2901 // Wheel mouse pressed
2902 if(get_buttonpress() == 4)
2904 if(current_operation == NO_OPERATION)
2906 current_operation = WHEEL;
2909 set_yposition(yposition - gui->get_h() / 10, 0);
2911 update_scrollbars(0);
2912 highlighted_ptr = 0;
2913 highlighted_item = get_cursor_item(data,
2914 top_level->cursor_x,
2915 top_level->cursor_y,
2923 if(get_buttonpress() == 5)
2925 if(current_operation == NO_OPERATION)
2927 current_operation = WHEEL;
2930 set_yposition(yposition + gui->get_h() / 10, 0);
2932 update_scrollbars(0);
2933 highlighted_ptr = 0;
2934 highlighted_item = get_cursor_item(data,
2935 top_level->cursor_x,
2936 top_level->cursor_y,
2944 // Pressed over column title division
2945 if(test_column_divisions(gui->get_cursor_x(),
2946 gui->get_cursor_y(),
2949 drag_cursor_x = gui->get_cursor_x() + xposition;
2951 drag_column_w = column_width[highlighted_division - 1];
2953 drag_column_w = default_column_width[highlighted_division - 1];
2955 current_operation = DRAG_DIVISION;
2959 // Pressed in column title
2960 if(test_column_titles(gui->get_cursor_x(), gui->get_cursor_y()))
2962 current_operation = COLUMN_DN;
2963 button_highlighted = 0;
2964 list_highlighted = 1;
2969 // Pressed in expander
2970 if(test_expanders())
2972 current_operation = EXPAND_DN;
2973 // Need to redraw items because of alpha
2978 // Pressed over item
2979 if((selection_number = get_cursor_item(data,
2980 gui->get_cursor_x(),
2981 gui->get_cursor_y(),
2982 ¤t_item)) >= 0)
2984 if(debug) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2986 // Get item button was pressed over
2987 selection_number2 = selection_number1;
2988 selection_number1 = selection_number;
2990 selection_start = -1;
2994 // Multiple item selection is possible
2995 if(selection_mode == LISTBOX_MULTIPLE &&
2996 (ctrl_down() || shift_down()))
2998 // Expand text selection.
2999 // Fill items between selected region and current item.
3001 (display_format == LISTBOX_TEXT ||
3002 display_format == LISTBOX_ICON_LIST))
3004 // Get first item selected
3005 selection_start = get_first_selection(data);
3006 // Get last item selected
3007 selection_end = get_last_selection(data);
3008 // Get center of selected region
3009 if(selection_end > selection_start)
3011 selection_center = (selection_end + selection_start) >> 1;
3015 selection_center = selection_number;
3019 // Deselect everything.
3020 set_all_selected(data, 0);
3021 // Select just the items
3022 expand_selection(1, selection_number);
3026 // Toggle a single item on or off
3028 toggle_item_selection(data, selection_number);
3029 new_value = current_item->selected;
3033 // Select single item
3035 if(!current_item->selected)
3037 set_all_selected(data, 0);
3046 current_operation = SELECT;
3047 highlighted_item = selection_number;
3048 highlighted_ptr = current_item;
3049 button_highlighted = 0;
3050 list_highlighted = 1;
3053 do_selection_change = 1;
3058 // Pressed over nothing. Start rectangle selection.
3060 if(get_buttonpress() == 1 &&
3061 selection_mode == LISTBOX_MULTIPLE)
3065 // Deselect all and redraw if anything was selected
3066 if(get_selection_number(0, 0) >= 0)
3068 set_all_selected(data, 0);
3070 do_selection_change = 1;
3076 // Promote selections to protect from a rectangle selection
3077 promote_selections(data, 1, 2);
3080 // Start rectangle selection
3081 current_operation = SELECT_RECT;
3082 rect_x1 = rect_x2 = get_cursor_x();
3083 rect_y1 = rect_y2 = get_cursor_y();
3091 // Suggestion box is not active but visible, so lie to get it to deactivate
3092 if(is_popup && (active || (is_suggestions && gui)))
3095 if(debug) printf("BC_ListBox::button_press_event %d\n", __LINE__);
3101 if(do_selection_change) selection_changed();
3102 if(debug) printf("BC_ListBox::button_press_event %d %d\n",
3109 int BC_ListBox::button_release_event()
3112 int cursor_x, cursor_y;
3116 //printf("BC_ListBox::button_release_event 1 %d\n", current_operation);
3117 switch(current_operation)
3120 current_operation = NO_OPERATION;
3125 current_operation = NO_OPERATION;
3129 // Release item selection
3130 case BUTTON_DOWN_SELECT:
3132 //printf("BC_ListBox::button_release_event 10\n");
3133 unset_repeat(get_resources()->scroll_repeat);
3134 current_operation = NO_OPERATION;
3136 translate_coordinates(top_level->event_win, gui->win,
3137 gui->get_cursor_x(), gui->get_cursor_y(),
3138 &cursor_x, &cursor_y);
3139 selection_number1 = selection_number =
3140 get_cursor_item(data, cursor_x, cursor_y);
3141 //printf("BC_ListBox::button_release_event %d %d\n", selection_number2, selection_number1);
3147 if(selection_number >= 0)
3153 // Second button release outside button
3154 if(button_releases > 1)
3161 if(top_level->get_double_click() &&
3162 selection_number2 == selection_number1 &&
3163 selection_number2 >= 0 &&
3164 selection_number1 >= 0)
3174 unset_repeat(get_resources()->scroll_repeat);
3177 // Demote selections from rectangle selection
3178 promote_selections(data, 2, 1);
3181 // Hide rectangle overlay
3183 current_operation = NO_OPERATION;
3187 // Release popup button
3190 current_operation = NO_OPERATION;
3194 // Second button release inside button
3195 if(button_releases > 1)
3203 current_operation = NO_OPERATION;
3204 // Update the sort column and the sort order for the user only if the existing
3205 // sort column is valid.
3206 if(sort_column >= 0)
3208 // Invert order only if column is the same
3209 if(highlighted_title == sort_column)
3211 (sort_order == SORT_ASCENDING) ?
3214 // Set the new sort column
3215 sort_column = highlighted_title;
3216 if(!sort_order_event())
3222 // Sorting not enabled. Redraw the title state.
3231 int redraw_toggles = 0;
3232 for(int i = 0; i < expanders.total && !result; i++)
3234 if(expanders.values[i]->button_release_event(&redraw_toggles))
3239 // Need to redraw items because of alpha
3240 if(redraw_toggles) draw_items(1);
3241 current_operation = NO_OPERATION;
3246 // Can't default to NO_OPERATION because it may be used in a drag event.
3251 if(do_event) handle_event();
3253 //printf("BC_ListBox::button_release_event %d %d\n", __LINE__, get_window_lock());
3257 int BC_ListBox::get_title_h()
3259 if(display_format == LISTBOX_TEXT ||
3260 display_format == LISTBOX_ICON_LIST)
3261 return column_titles ? column_bg[0]->get_h() : 0;
3266 void BC_ListBox::reset_cursor(int new_cursor)
3270 if(gui->get_cursor() != new_cursor)
3272 gui->set_cursor(new_cursor, 0, 0);
3276 if(get_cursor() != new_cursor)
3278 set_cursor(new_cursor, 0, 0);
3282 int BC_ListBox::test_column_divisions(int cursor_x, int cursor_y, int &new_cursor)
3287 cursor_y < get_title_h() &&
3289 cursor_x < gui->get_w())
3291 for(int i = 1; i < columns; i++)
3293 if(cursor_x >= -xposition + get_column_offset(i) - 5 &&
3294 cursor_x < -xposition + get_column_offset(i) +
3295 get_resources()->listbox_title_hotspot)
3297 highlighted_item = -1;
3298 highlighted_ptr = 0;
3299 highlighted_division = i;
3300 highlighted_title = -1;
3301 list_highlighted = 1;
3302 new_cursor = HSEPARATE_CURSOR;
3307 highlighted_division = -1;
3311 int BC_ListBox::test_column_titles(int cursor_x, int cursor_y)
3316 cursor_y < get_title_h() &&
3318 cursor_x < gui->get_w())
3320 for(int i = 0; i < columns; i++)
3322 if(cursor_x >= -xposition + get_column_offset(i) &&
3323 (cursor_x < -xposition + get_column_offset(i + 1) ||
3326 highlighted_item = -1;
3327 highlighted_ptr = 0;
3328 highlighted_division = -1;
3329 highlighted_title = i;
3330 list_highlighted = 1;
3335 highlighted_title = -1;
3339 int BC_ListBox::test_expanders()
3341 for(int i = 0; i < expanders.total; i++)
3343 if(expanders.values[i]->button_press_event())
3345 current_operation = EXPAND_DN;
3353 int BC_ListBox::cursor_motion_event()
3355 int redraw = 0, result = 0;
3356 int new_cursor = ARROW_CURSOR;
3358 selection_number = -1;
3361 switch(current_operation)
3364 // Button pressed and slid off button
3365 if(!cursor_inside())
3367 current_operation = BUTTON_DOWN_SELECT;
3375 // int new_w = get_cursor_x() +
3377 // get_column_offset(highlighted_division - 1);
3378 int difference = get_cursor_x() + xposition - drag_cursor_x;
3379 int new_w = drag_column_w + difference;
3381 new_cursor = HSEPARATE_CURSOR;
3385 column_width[highlighted_division - 1] = new_w;
3389 default_column_width[highlighted_division - 1] = new_w;
3392 column_width_boundaries();
3394 // Force update of coords
3395 set_autoplacement(data, 0, 1);
3396 column_resize_event();
3400 update_scrollbars(1);
3407 if(test_drag_scroll(get_cursor_x(), get_cursor_y()))
3409 set_repeat(get_resources()->scroll_repeat);
3412 int old_x1 = MIN(rect_x1, rect_x2);
3413 int old_x2 = MAX(rect_x1, rect_x2);
3414 int old_y1 = MIN(rect_y1, rect_y2);
3415 int old_y2 = MAX(rect_y1, rect_y2);
3417 int new_rect_x2 = get_cursor_x();
3418 int new_rect_y2 = get_cursor_y();
3420 int x1 = MIN(rect_x1, new_rect_x2);
3421 int x2 = MAX(rect_x1, new_rect_x2);
3422 int y1 = MIN(rect_y1, new_rect_y2);
3423 int y2 = MAX(rect_y1, new_rect_y2);
3425 // Adjust rectangle coverage
3433 redraw = select_rectangle(data,
3443 //printf("BC_ListBox::cursor_motion_event %d\n", __LINE__);
3448 rect_x2 = get_cursor_x();
3449 rect_y2 = get_cursor_y();
3454 update_scrollbars(1);
3455 selection_changed();
3456 //printf("BC_ListBox::cursor_motion_event %d\n", __LINE__);
3464 //printf("BC_ListBox::cursor_motion_event %d\n", __LINE__);
3474 int old_highlighted_item = highlighted_item;
3476 if(test_drag_scroll(get_cursor_x(),
3479 set_repeat(get_resources()->scroll_repeat);
3483 highlighted_item = selection_number = get_cursor_item(data,
3489 // Deselect all items and select just the one we're over
3490 if(selection_number >= 0 &&
3494 selection_mode == LISTBOX_SINGLE))
3496 redraw = update_selection(data, selection_number);
3499 if(selection_mode == LISTBOX_MULTIPLE &&
3500 (shift_down() || ctrl_down()))
3501 // Expand multiple selection
3503 // Expand selected region in text mode centered around initial range
3504 if((display_format == LISTBOX_TEXT ||
3505 display_format == LISTBOX_ICON_LIST) &&
3508 // Deselect everything.
3509 set_all_selected(data, 0);
3511 // Select just the items
3512 redraw = expand_selection(0, selection_number);
3515 // Set the one item we're over to the selection value determined in
3516 // button_press_event.
3524 if(highlighted_item != old_highlighted_item)
3528 update_scrollbars(1);
3529 //printf("BC_ListBox::cursor_motion_event %d %d\n", highlighted_item, old_highlighted_item);
3530 selection_changed();
3535 case BUTTON_DOWN_SELECT:
3536 // Went back into button area
3539 current_operation = BUTTON_DN;
3544 // Went into item area
3547 int cursor_x = 0, cursor_y = 0;
3548 translate_coordinates(top_level->event_win,
3550 top_level->cursor_x,
3551 top_level->cursor_y,
3554 int old_highlighted_item = highlighted_item;
3555 highlighted_item = selection_number = get_cursor_item(data,
3560 if(highlighted_item != old_highlighted_item)
3562 update_selection(data, selection_number);
3564 selection_changed();
3571 int redraw_toggles = 0;
3572 for(int i = 0; i < expanders.total && !result; i++)
3574 result = expanders.values[i]->cursor_motion_event(
3579 // Need to redraw items because of the alpha
3587 int cursor_x = get_cursor_x(), cursor_y = get_cursor_y();
3588 if(gui && top_level->event_win == gui->win)
3590 int old_highlighted_title = highlighted_title;
3591 int old_list_highlighted = list_highlighted;
3592 int old_highlighted_item = highlighted_item;
3593 int redraw_titles = 0;
3594 int redraw_border = 0;
3595 int redraw_items = 0;
3596 int redraw_toggles = 0;
3600 // Test if cursor moved over a title division
3601 test_column_divisions(cursor_x, cursor_y, new_cursor);
3603 // Test if cursor moved over a title
3604 if(highlighted_division < 0)
3606 test_column_titles(cursor_x, cursor_y);
3609 // Test if cursor moved over expander
3610 if(highlighted_division < 0 &&
3611 highlighted_title < 0 &&
3612 (display_format == LISTBOX_TEXT ||
3613 display_format == LISTBOX_ICON_LIST))
3615 for(int i = 0; i < expanders.total; i++)
3617 expanders.values[i]->cursor_motion_event(
3620 //printf("BC_ListBox::cursor_motion_event %d\n", redraw_toggles);
3623 // Test if cursor moved over an item
3624 if(highlighted_division < 0 &&
3625 highlighted_title < 0)
3627 highlighted_item = get_cursor_item(data,
3634 // Clear title highlighting if moved over division
3635 if(old_highlighted_title != highlighted_title)
3640 // Highlight list border
3641 if(old_list_highlighted != list_highlighted)
3646 // Moved out of item area
3647 if(old_highlighted_item != highlighted_item)
3652 //printf("BC_ListBox::cursor_motion_event 1 %d\n", highlighted_item);
3654 // Change cursor to title division adjustment
3655 reset_cursor(new_cursor);
3682 if(!result && list_highlighted)
3684 list_highlighted = 0;
3685 highlighted_item = -1;
3686 highlighted_ptr = 0;
3687 highlighted_title = -1;
3688 highlighted_division = -1;
3700 int BC_ListBox::drag_start_event()
3702 switch(current_operation)
3706 gui->is_event_win() &&
3709 BC_ListBoxItem *item_return = 0;
3710 selection_number = get_cursor_item(data,
3711 top_level->cursor_x,
3712 top_level->cursor_y,
3715 if(selection_number >= 0)
3718 if (item_return->icon_vframe)
3720 drag_popup = new BC_DragWindow(this,
3721 item_return->icon_vframe /*,
3722 get_abs_cursor_x(0) - item_return->icon_vframe->get_w() / 2,
3723 get_abs_cursor_y(0) - item_return->icon_vframe->get_h() / 2 */);
3726 // this probably works not!
3727 if (item_return->icon)
3729 drag_popup = new BC_DragWindow(this,
3730 item_return->icon /*,
3731 get_abs_cursor_x(0) - item_return->icon->get_w() / 2,
3732 get_abs_cursor_y(0) - item_return->icon->get_h() / 2 */);
3736 drag_popup = new BC_DragWindow(this,
3737 drag_icon_vframe /*,
3738 get_abs_cursor_x(0) - drag_icon_vframe->get_w() / 2,
3739 get_abs_cursor_y(0) - drag_icon_vframe->get_h() / 2 */);
3742 current_operation = DRAG_ITEM;
3749 if(gui && gui->is_event_win() && allow_drag_column)
3751 drag_popup = new BC_DragWindow(this,
3752 drag_column_icon_vframe /*,
3753 get_abs_cursor_x(0) - drag_column_icon_vframe->get_w() / 2,
3754 get_abs_cursor_y(0) - drag_column_icon_vframe->get_h() / 2 */);
3755 dragged_title = highlighted_title;
3756 current_operation = COLUMN_DRAG;
3766 int BC_ListBox::drag_motion_event()
3768 //printf("BC_ListBox::drag_motion_event 1 %d\n", current_operation);
3769 switch(current_operation)
3774 int new_highlighted_item = -1;
3775 BC_ListBoxItem *new_highlighted_ptr = 0;
3776 new_highlighted_item = get_cursor_item(data,
3777 top_level->cursor_x, top_level->cursor_y,
3778 &new_highlighted_ptr);
3780 if(new_highlighted_item != highlighted_item)
3785 // Always update highlighted value for drag_stop
3786 highlighted_item = new_highlighted_item;
3787 highlighted_ptr = new_highlighted_ptr;
3788 //printf("BC_ListBox::drag_motion_event 1 %p\n", highlighted_ptr);
3793 update_scrollbars(1);
3796 return drag_popup->cursor_motion_event();
3802 int old_highlighted_title = highlighted_title;
3803 test_column_titles(get_cursor_x(), get_cursor_y());
3804 if(old_highlighted_title != highlighted_title)
3808 return drag_popup->cursor_motion_event();
3815 int BC_ListBox::drag_stop_event()
3817 switch(current_operation)
3820 // Inside window boundary
3821 if(top_level->cursor_x > 0 &&
3822 top_level->cursor_x < gui->get_w() - drag_popup->get_w() / 2 &&
3823 top_level->cursor_y > 0 &&
3824 top_level->cursor_y < gui->get_h() - drag_popup->get_h() / 2)
3829 if(display_format == LISTBOX_ICONS)
3831 reposition_item(data,
3833 top_level->cursor_x +
3834 drag_popup->get_offset_x() -
3838 top_level->cursor_y +
3839 drag_popup->get_offset_y() -
3849 int destination = highlighted_item = item_to_index(data,
3851 //printf("BC_ListBox::drag_stop_event 1 %p %d\n", highlighted_ptr, destination);
3853 // Move selected items from data to temporary
3854 ArrayList<BC_ListBoxItem*> *src_items =
3855 new ArrayList<BC_ListBoxItem*>[columns];
3857 move_selection(src_items, data);
3859 // Insert items from temporary to data
3865 delete [] src_items;
3866 set_autoplacement(data, 0, 1);
3873 drag_popup->drag_failure_event();
3878 current_operation = NO_OPERATION;
3884 if(dragged_title != highlighted_title)
3886 if(highlighted_title >= 0)
3888 if(!move_column_event()) draw_titles(1);
3891 drag_popup->drag_failure_event();
3893 current_operation = NO_OPERATION;
3903 BC_DragWindow* BC_ListBox::get_drag_popup()
3908 int BC_ListBox::translation_event()
3912 int new_x = gui->get_x() +
3913 (top_level->last_translate_x - top_level->prev_x -
3914 BC_DisplayInfo::get_left_border());
3915 int new_y = gui->get_y() +
3916 (top_level->last_translate_y - top_level->prev_y -
3917 BC_DisplayInfo::get_top_border());
3919 gui->reposition_window(new_x, new_y);
3925 int BC_ListBox::reposition_window(int x, int y, int w, int h, int flush)
3929 if(w != -1) popup_w = w;
3930 if(h != -1) popup_h = h;
3931 //printf("BC_ListBox::reposition_window %d %d\n", popup_w, popup_h);
3936 xscrollbar->reposition_window(get_xscroll_x(),
3938 get_xscroll_width());
3940 yscrollbar->reposition_window(get_yscroll_x(),
3942 get_yscroll_height());
3947 BC_WindowBase::reposition_window(x, y, w, h);
3953 int BC_ListBox::deactivate()
3956 // printf("BC_ListBox::deactivate %d this=%p gui=%p active=%d\n",
3966 //printf("BC_ListBox::deactivate %d this=%p gui=%p\n", __LINE__, this, gui);
3975 highlighted_item = -1;
3976 highlighted_ptr = 0;
3981 //printf("BC_ListBox::deactivate %d this=%p\n", __LINE__, this);
3983 top_level->active_subwindow = 0;
3989 int BC_ListBox::activate(int take_focus)
3991 if( active ) return 0;
3994 set_active_subwindow(this);
3995 button_releases = 0;
3996 if( !is_popup || gui ) return 0;
3997 int wx = get_x(), wy = get_y() + get_h();
3998 if( justify == LISTBOX_RIGHT ) wx += get_w() - popup_w;
4001 XTranslateCoordinates(top_level->display,
4002 parent_window->win, top_level->rootwin,
4003 wx, wy, &abs_x, &abs_y, &xwin);
4006 return activate(abs_x, abs_y);
4009 int BC_ListBox::activate(int x, int y, int w, int h)
4011 if( !is_popup || gui ) return 0;
4013 if(w != -1) popup_w = w;
4014 if(h != -1) popup_h = h;
4016 if( y + popup_h > top_level->get_root_h(0) )
4017 y -= get_h() + popup_h;
4018 add_subwindow(gui = new BC_Popup(this,
4019 x, y, popup_w, popup_h, -1, 0, 0));
4021 gui->show_window(1);
4025 int BC_ListBox::is_active()
4030 int BC_ListBox::keypress_event()
4032 if(!active) return 0;
4034 //printf("BC_ListBox::keypress_event %d\n", __LINE__);
4036 int result = 0, redraw = 0;
4037 int view_items = last_in_view - first_in_view + 1;
4038 if( view_items <= 0 ) view_items = view_h / get_text_height(MEDIUMFONT);
4039 int new_item = -1, new_selection = -1;
4041 switch(top_level->get_keypress())
4045 top_level->deactivate();
4047 // If user is manipulating popup with keyboard, don't pass on event.
4050 //printf("BC_ListBox::keypress_event %d %p\n", __LINE__, get_selection(0, 0));
4051 if(top_level->get_keypress() == RETURN)
4053 //printf("BC_ListBox::keypress_event %d %p\n", __LINE__, get_selection(0, 0));
4061 new_selection = new_item = select_previous(0);
4063 //printf("BC_ListBox::keypress_event 1 %d\n", new_item);
4066 center_selection(new_item);
4074 new_selection = new_item = select_next(0);
4078 center_selection(new_item);
4086 new_selection = new_item = select_previous(view_items - 1);
4090 center_selection(new_item);
4098 new_selection = new_item = select_next(view_items - 1);
4102 center_selection(new_item);
4130 int query_len = strlen(query);
4131 if( query_len < (int)sizeof(query)-1 &&
4132 top_level->get_keypress() > 30 &&
4133 top_level->get_keypress() < 127)
4135 query[query_len++] = top_level->get_keypress();
4136 query[query_len] = 0;
4137 new_selection = query_list();
4140 if(top_level->get_keypress() == BACKSPACE)
4142 if(query_len > 0) query[--query_len] = 0;
4143 new_selection = query_list();
4147 show_tooltip(query);
4161 update_scrollbars(1);
4164 //printf("BC_ListBox::keypress_event %d new_selection=%d\n", __LINE__, new_selection);
4165 if(new_selection >= 0 && !is_suggestions)
4167 //printf("BC_ListBox::keypress_event %d\n", __LINE__);
4168 selection_changed();
4169 //printf("BC_ListBox::keypress_event %d\n", __LINE__);
4176 BC_Pixmap* BC_ListBox::get_bg_surface()
4182 void BC_ListBox::draw_background()
4184 if( !bg_draw ) return;
4186 // White background pixmap
4187 set_color(top_level->get_resources()->listbox_inactive);
4188 draw_box(0, 0, bg_surface->get_w(), bg_surface->get_h(), bg_surface);
4190 // Optional heroine pixmap
4192 bg_surface->draw_pixmap(bg_pixmap,
4193 bg_surface->get_w() - top_level->get_resources()->listbox_bg->get_w(),
4197 void BC_ListBox::clear_listbox(int x, int y, int w, int h)
4199 gui->draw_pixmap(bg_surface, x, y, w, h, x, y - title_h);
4202 void BC_ListBox::update_format(int display_format, int redraw)
4204 this->display_format = display_format;
4205 if( redraw && gui ) draw_items(1, 1);
4208 int BC_ListBox::get_format()
4210 return display_format;
4215 int BC_ListBox::draw_items(int flush, int draw_bg)
4219 BC_Resources *resources = get_resources();
4221 //dump(data, columns);
4223 // Calculate items width
4224 calculate_item_coords();
4227 // Create and destroy scrollbars as needed
4232 if( bg_draw ) this->bg_draw = 1;
4238 if(display_format == LISTBOX_ICONS)
4240 clear_listbox(2, 2 + title_h, view_w, view_h);
4242 set_font(MEDIUMFONT);
4243 for(int i = 0; i < data[master_column].size(); i++)
4245 BC_ListBoxItem *item = data[master_column].get(i);
4246 if(get_item_x(item) >= -get_item_w(item) &&
4247 get_item_x(item) < view_w &&
4248 get_item_y(item) >= -get_item_h(item) + title_h &&
4249 get_item_y(item) < view_h + title_h)
4251 item->set_in_view(1);
4252 if( first_in_view < 0 ) first_in_view = i;
4254 int item_color = get_item_highlight(data, 0, i);
4255 int icon_x, icon_y, icon_w, icon_h;
4256 int text_x, text_y, text_w, text_h;
4259 get_icon_mask(item, icon_x, icon_y, icon_w, icon_h);
4260 get_text_mask(item, text_x, text_y, text_w, text_h);
4263 if(item_color != resources->listbox_inactive)
4265 gui->set_color(BLACK);
4266 gui->draw_rectangle(icon_x, icon_y, icon_w, icon_h);
4267 gui->set_color(item_color);
4268 gui->draw_box(icon_x + 1, icon_y + 1, icon_w - 2, icon_h - 2);
4269 gui->set_color(BLACK);
4270 gui->draw_rectangle(text_x, text_y, text_w, text_h);
4271 gui->set_color(item_color);
4272 gui->draw_box(text_x + 1, text_y + 1, text_w - 2, text_h - 2);
4274 if(icon_position == ICON_LEFT)
4275 gui->draw_box(text_x - 1, text_y + 1, 2, text_h - 2);
4277 if(icon_position == ICON_TOP)
4278 gui->draw_line(text_x + 1, text_y, text_x + icon_w - 2, text_y);
4279 if(text_x + text_w < icon_x + icon_w)
4281 gui->set_color(BLACK);
4282 gui->draw_line(text_x + text_w,
4290 gui->set_color(get_item_color(data, 0, i));
4292 gui->pixmap->draw_pixmap(item->icon,
4293 icon_x + ICON_MARGIN,
4294 icon_y + ICON_MARGIN);
4297 gui->draw_text(text_x + ICON_MARGIN,
4298 text_y + ICON_MARGIN + get_baseline(item),
4302 item->set_in_view(0);
4308 // Draw one column at a time so text overruns don't go into the next column
4309 // clear column backgrounds
4310 int current_toggle = 0;
4311 for(int j = 0; j < columns; j++)
4313 clear_listbox(LISTBOX_BORDER + get_column_offset(j) - xposition,
4314 LISTBOX_BORDER + title_h,
4315 get_column_width(j, 1),
4317 // Draw rows in the column recursively
4318 draw_text_recursive(data, j, 0, ¤t_toggle);
4321 // Delete excess expanders
4322 while(expanders.total > current_toggle)
4324 expanders.remove_object();
4328 // draw user images if available
4330 // Draw titles on top of rows for superposition effect
4333 // Clear garbage from bottom right corner
4334 if(xscrollbar && yscrollbar && is_popup)
4336 gui->draw_top_background(parent_window,
4337 popup_w - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w(),
4338 popup_h - get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h(),
4339 get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w(),
4340 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h());
4347 if(current_operation == SELECT_RECT)
4357 void BC_ListBox::draw_text_recursive(ArrayList<BC_ListBoxItem*> *data,
4360 int *current_toggle)
4365 BC_Resources *resources = get_resources();
4367 set_font(MEDIUMFONT);
4370 // Search for a branch and make room for toggle if there is one
4373 for(int i = 0; i < data[column].size(); i++)
4375 if(data[column].get(i)->get_sublist())
4377 subindent = BC_WindowBase::get_resources()->listbox_expand[0]->get_w();
4383 row_height = row_ascent = row_descent = 0;
4384 for(int i = 0; i < data[column].total; i++)
4386 BC_ListBoxItem *item = data[column].values[i];
4387 int ht = get_text_h(item);
4388 if( ht > row_height ) row_height = ht;
4389 int bl = get_baseline(item);
4390 if( bl > row_ascent ) row_ascent = bl;
4392 if( dt > row_descent ) row_ascent = bl;
4395 for(int i = 0; i < data[column].size(); i++)
4398 BC_ListBoxItem *item = data[column].values[i];
4399 BC_ListBoxItem *first_item = data[master_column].values[i];
4401 if(get_item_y(item) >= -get_item_h(item) + title_h &&
4402 get_item_y(item) < view_h + title_h)
4404 int row_color = get_item_highlight(data, 0, i);
4405 int x, y, w, h, column_width;
4407 get_text_mask(item, x, y, w, h);
4408 column_width = get_column_width(column, 1);
4409 if(x + column_width > view_w + LISTBOX_BORDER * 2)
4410 column_width = view_w + LISTBOX_BORDER * 2 - x;
4412 if(row_color != resources->listbox_inactive)
4414 gui->set_color(row_color);
4415 gui->draw_box(x, y, column_width, h);
4416 gui->set_color(BLACK);
4417 int xx = x + column_width-1;
4418 gui->draw_line(x, y, xx, y);
4419 int hh = row_height;
4420 if( display_format == LISTBOX_ICON_LIST ) {
4421 int ih = get_icon_h(item);
4422 if( ih > hh ) hh = ih;
4425 gui->draw_line(x, yy, xx, yy);
4428 gui->set_color(get_item_color(data, column, i));
4431 if(column == 0 && display_format == LISTBOX_ICON_LIST)
4435 gui->pixmap->draw_pixmap(item->icon,
4438 x += item->icon->get_w() + ICON_MARGIN;
4443 // Indent only applies to first column
4445 x + LISTBOX_BORDER + LISTBOX_MARGIN +
4446 (column == 0 ? indent + subindent : 0),
4447 y + get_baseline(item), item->text);
4448 item->set_in_view(1);
4450 if( first_in_view < 0 ) first_in_view = i;
4456 item->get_sublist() &&
4457 item->get_columns())
4459 // Create new expander
4460 if(*current_toggle >= expanders.total)
4462 BC_ListBoxToggle *toggle =
4463 new BC_ListBoxToggle(this,
4465 x + LISTBOX_BORDER + LISTBOX_MARGIN + indent,
4468 expanders.append(toggle);
4471 // Reposition existing expander
4473 BC_ListBoxToggle *toggle = expanders.values[*current_toggle];
4474 //printf("BC_ListBox::draw_text_recursive 1 %d\n", *current_toggle);
4475 toggle->update(item,
4476 x + LISTBOX_BORDER + LISTBOX_MARGIN + indent,
4480 (*current_toggle)++;
4487 item->set_in_view(0);
4489 // Descend into sublist
4490 if(first_item->get_expand())
4492 draw_text_recursive(first_item->get_sublist(),
4494 indent + LISTBOX_INDENT,
4503 int BC_ListBox::draw_border(int flash)
4505 BC_Resources *resources = top_level->get_resources();
4506 gui->draw_3d_border(0,
4508 view_w + LISTBOX_BORDER * 2,
4509 view_h + title_h + LISTBOX_BORDER * 2,
4510 resources->listbox_border1,
4512 resources->listbox_border2_hi :
4513 resources->listbox_border2,
4515 resources->listbox_border3_hi :
4516 resources->listbox_border3,
4517 resources->listbox_border4);
4527 void BC_ListBox::draw_title(int number)
4529 // Column title background
4530 int image_number = 0;
4531 if(number == highlighted_title)
4534 if(current_operation == COLUMN_DN)
4538 int column_offset = get_column_offset(number) - xposition + LISTBOX_BORDER;
4539 int column_width = get_column_width(number, 1);
4540 gui->draw_3segmenth(get_column_offset(number) - xposition + LISTBOX_BORDER,
4542 get_column_width(number, 1) + get_resources()->listbox_title_overlap,
4543 column_bg[image_number]);
4545 // Column title sort order
4546 if(number == sort_column)
4549 if(sort_order == SORT_ASCENDING)
4550 src = column_sort_dn;
4552 src = column_sort_up;
4554 int x = column_offset +
4557 if(x > items_w) x = items_w;
4558 x -= 5 + src->get_w();
4559 gui->draw_pixmap(src,
4561 title_h / 2 - src->get_h() / 2 + LISTBOX_BORDER);
4565 int x = -xposition +
4566 get_column_offset(number) +
4569 x += get_resources()->listbox_title_margin;
4571 gui->set_color(get_resources()->listbox_title_color);
4573 LISTBOX_MARGIN + LISTBOX_BORDER + get_text_ascent(MEDIUMFONT),
4574 _(column_titles[number]));
4577 int BC_ListBox::draw_titles(int flash)
4580 (display_format == LISTBOX_TEXT ||
4581 display_format == LISTBOX_ICON_LIST))
4583 //printf("BC_ListBox::draw_titles 1 %d\n", highlighted_title);
4584 for(int i = 0; i < columns; i++)
4586 if(i != highlighted_title)
4590 if(highlighted_title >= 0) draw_title(highlighted_title);
4601 void BC_ListBox::draw_toggles(int flash)
4603 for(int i = 0; i < expanders.total; i++)
4604 expanders.values[i]->draw(0);
4606 //printf("BC_ListBox::draw_toggles 1 %d\n", flash);
4607 if(flash && expanders.total)
4614 int BC_ListBox::draw_rectangle(int flash)
4616 int x1 = MIN(rect_x1, rect_x2);
4617 int x2 = MAX(rect_x1, rect_x2);
4618 int y1 = MIN(rect_y1, rect_y2);
4619 int y2 = MAX(rect_y1, rect_y2);
4621 if(x1 == x2 || y1 == y2) return 0;
4624 gui->set_color(WHITE);
4625 gui->draw_rectangle(x1, y1, x2 - x1, y2 - y1);
4636 void BC_ListBox::dump(ArrayList<BC_ListBoxItem*> *data,
4643 printf("BC_ListBox::dump 1\n");
4646 for(int i = 0; i < data[master_column].total; i++)
4648 for(int k = 0; k < indent; k++)
4650 for(int j = 0; j < columns; j++)
4652 BC_ListBoxItem *item = data[j].values[i];
4653 printf("%d,%d,%d=%s ",
4656 item->autoplace_text,
4661 if(data[master_column].values[i]->get_sublist())
4663 dump(data[master_column].values[i]->get_sublist(),
4664 data[master_column].values[i]->get_columns(),