3 * Copyright (C) 2010-2014 Adam Williams <broadcast at earthling dot net>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "bcdisplayinfo.h"
22 #include "bcdragwindow.h"
23 #include "bclistbox.h"
24 #include "bclistboxitem.h"
26 #include "bcresources.h"
27 #include "bcsignals.h"
39 // ====================================================== scrollbars
42 BC_ListBoxYScroll::BC_ListBoxYScroll(BC_ListBox *listbox,
46 : BC_ScrollBar(listbox->get_yscroll_x(),
47 listbox->get_yscroll_y(),
49 listbox->get_yscroll_height(),
54 this->listbox = listbox;
57 BC_ListBoxYScroll::~BC_ListBoxYScroll()
61 int BC_ListBoxYScroll::handle_event()
63 listbox->set_yposition(get_value());
73 BC_ListBoxXScroll::BC_ListBoxXScroll(BC_ListBox *listbox,
77 : BC_ScrollBar(listbox->get_xscroll_x(),
78 listbox->get_xscroll_y(),
80 listbox->get_xscroll_width(),
85 this->listbox = listbox;
88 BC_ListBoxXScroll::~BC_ListBoxXScroll()
92 int BC_ListBoxXScroll::handle_event()
94 listbox->set_xposition(get_value());
105 BC_ListBoxToggle::BC_ListBoxToggle(BC_ListBox *listbox,
106 BC_ListBoxItem *item,
110 this->listbox = listbox;
114 this->value = item->get_expand();
116 state = BC_Toggle::TOGGLE_CHECKED;
118 state = BC_Toggle::TOGGLE_UP;
121 void BC_ListBoxToggle::update(BC_ListBoxItem *item,
126 this->value = item->get_expand();
136 state = TOGGLE_CHECKED;
141 state = TOGGLE_CHECKEDHI;
152 case TOGGLE_CHECKEDHI:
157 case TOGGLE_DOWN_EXIT:
165 int BC_ListBoxToggle::cursor_motion_event(int *redraw_toggles)
167 int w = listbox->toggle_images[0]->get_w();
168 int h = listbox->toggle_images[0]->get_h();
169 int cursor_inside = listbox->get_cursor_x() >= x &&
170 listbox->get_cursor_x() < x + w &&
171 listbox->get_cursor_y() >= y &&
172 listbox->get_cursor_y() < y + h;
177 case BC_ListBoxToggle::TOGGLE_UPHI:
180 state = BC_ListBoxToggle::TOGGLE_UP;
185 case BC_ListBoxToggle::TOGGLE_CHECKEDHI:
188 state = BC_ListBoxToggle::TOGGLE_CHECKED;
193 case BC_ListBoxToggle::TOGGLE_DOWN:
196 state = BC_ListBoxToggle::TOGGLE_DOWN_EXIT;
202 case BC_ListBoxToggle::TOGGLE_DOWN_EXIT:
205 state = BC_ListBoxToggle::TOGGLE_DOWN;
215 state = BC_ListBoxToggle::TOGGLE_CHECKEDHI;
217 state = BC_ListBoxToggle::TOGGLE_UPHI;
225 int BC_ListBoxToggle::cursor_leave_event(int *redraw_toggles)
228 state = BC_ListBoxToggle::TOGGLE_CHECKED;
230 state = BC_ListBoxToggle::TOGGLE_UP;
234 int BC_ListBoxToggle::button_press_event()
236 int w = listbox->toggle_images[0]->get_w();
237 int h = listbox->toggle_images[0]->get_h();
239 if(listbox->gui->get_cursor_x() >= x &&
240 listbox->gui->get_cursor_x() < x + w &&
241 listbox->gui->get_cursor_y() >= y &&
242 listbox->gui->get_cursor_y() < y + h)
244 state = BC_ListBoxToggle::TOGGLE_DOWN;
250 int BC_ListBoxToggle::button_release_event(int *redraw_toggles)
256 case BC_ListBoxToggle::TOGGLE_DOWN:
259 state = BC_ListBoxToggle::TOGGLE_CHECKEDHI;
261 state = BC_ListBoxToggle::TOGGLE_UPHI;
262 listbox->expand_item(item, value);
266 case BC_ListBoxToggle::TOGGLE_DOWN_EXIT:
268 state = BC_ListBoxToggle::TOGGLE_CHECKED;
270 state = BC_ListBoxToggle::TOGGLE_UP;
278 void BC_ListBoxToggle::draw(int flash)
282 int image_number = 0;
283 int w = listbox->toggle_images[0]->get_w();
284 int h = listbox->toggle_images[0]->get_h();
288 case BC_ListBoxToggle::TOGGLE_UP: image_number = 0; break;
289 case BC_ListBoxToggle::TOGGLE_UPHI: image_number = 1; break;
290 case BC_ListBoxToggle::TOGGLE_CHECKED: image_number = 2; break;
291 case BC_ListBoxToggle::TOGGLE_DOWN: image_number = 3; break;
292 case BC_ListBoxToggle::TOGGLE_CHECKEDHI: image_number = 4; break;
293 case BC_ListBoxToggle::TOGGLE_DOWN_EXIT:
301 //printf("BC_ListBoxToggle::draw 1 %d\n", state);
302 listbox->gui->draw_pixmap(listbox->toggle_images[image_number],
309 listbox->gui->flash(x, y, w, h);
310 listbox->gui->flush();
328 // ====================================================== box
330 BC_ListBox::BC_ListBox(int x,
335 ArrayList<BC_ListBoxItem*> *data,
336 const char **column_titles,
344 : BC_SubWindow(x, y, w, h, -1)
346 justify = LISTBOX_RIGHT;
348 highlighted_item = -1;
349 highlighted_title = -1;
350 highlighted_division = -1;
354 current_cursor = ARROW_CURSOR;
367 selection_number1 = -1;
368 selection_number2 = -1;
371 row_height = row_ascent = row_descent = 0;
374 current_operation = NO_OPERATION;
375 button_highlighted = 0;
376 list_highlighted = 0;
379 allow_drag_scroll = 1;
385 allow_drag_column = 0;
392 for(int i = 0; i < 3; i++) column_bg[i] = 0;
393 for(int i = 0; i < 4; i++) button_images[i] = 0;
394 for(int i = 0; i < 5; i++) toggle_images[i] = 0;
399 //printf("BC_ListBox::BC_ListBox 1\n");
401 this->columns = columns;
402 this->yposition = yposition;
403 this->is_popup = is_popup;
404 this->use_button = 1;
405 this->display_format = display_format;
406 this->selection_mode = selection_mode;
407 this->icon_position = icon_position;
408 this->allow_drag = allow_drag;
409 this->column_titles = 0;
410 this->column_width = 0;
411 this->first_in_view = -1;
412 this->last_in_view = 0;
413 //printf("BC_ListBox::BC_ListBox 1\n");
415 if((!column_titles && column_width) ||
416 (column_titles && !column_width))
418 printf("BC_ListBox::BC_ListBox either column_titles or column_widths == NULL but not both.\n");
420 //printf("BC_ListBox::BC_ListBox 2 %p %p\n", column_titles, column_width);
422 set_columns(column_titles,
426 //printf("BC_ListBox::BC_ListBox 3\n");
428 drag_icon_vframe = 0;
429 drag_column_icon_vframe = 0;
433 // reset the search engine
434 //printf("BC_ListBox::BC_ListBox 4\n");
437 //printf("BC_ListBox::BC_ListBox 5\n");
440 BC_ListBox::~BC_ListBox()
442 expanders.remove_all_objects();
443 if(bg_surface) delete bg_surface;
444 if(bg_pixmap) delete bg_pixmap;
445 if(xscrollbar) delete xscrollbar;
446 if(yscrollbar) delete yscrollbar;
447 for(int i = 0; i < 3; i++) delete column_bg[i];
448 for(int i = 0; i < 4; i++) delete button_images[i];
449 for(int i = 0; i < 5; i++) delete toggle_images[i];
450 if(column_sort_up) delete column_sort_up;
451 if(column_sort_dn) delete column_sort_dn;
454 if(drag_popup) delete drag_popup;
457 int BC_ListBox::enable()
464 int BC_ListBox::disable()
471 void BC_ListBox::reset_query()
473 query[0] = 0; // reset query
476 int BC_ListBox::evaluate_query(char *string)
478 for(int i = 0; i < data[search_column].size(); i++)
480 if(strcmp(string, data[search_column].get(i)->text) <= 0 &&
481 data[search_column].get(i)->searchable)
490 int BC_ListBox::query_list()
492 if(query[0] == 0) return 0;
496 int selection_changed = 0;
497 int prev_selection = -1;
498 result = evaluate_query(query);
499 if(result >= 0) done = 1;
504 for(int i = 0; i < data[0].total; i++)
506 for(int j = 0; j < columns; j++)
508 if(data[j].values[i]->selected) prev_selection = i;
509 data[j].values[i]->selected = 0;
514 if(prev_selection != result)
515 selection_changed = 1;
516 for(int j = 0; j < columns; j++)
518 data[j].values[result]->selected = 1;
520 center_selection(result);
523 return selection_changed;
526 void BC_ListBox::init_column_width()
528 if(!column_width && data)
531 for(int i = 0; i < data[0].total; i++)
533 wd = get_text_w(data[0].values[i]);
534 if( wd > widest ) widest = wd;
536 default_column_width[0] = widest + 2 * LISTBOX_MARGIN;
540 int BC_ListBox::initialize()
546 for( int i = 0; i < 4; ++i )
548 button_images[i] = new BC_Pixmap(parent_window,
549 BC_WindowBase::get_resources()->listbox_button[i],
552 w = button_images[0]->get_w();
553 h = button_images[0]->get_h();
557 current_operation = NO_OPERATION;
563 current_operation = NO_OPERATION;
566 for(int i = 0; i < 3; i++)
568 column_bg[i] = new BC_Pixmap(parent_window,
569 get_resources()->listbox_column[i],
572 for(int i = 0; i < 5; i++)
574 toggle_images[i] = new BC_Pixmap(parent_window,
575 get_resources()->listbox_expand[i],
579 column_sort_up = new BC_Pixmap(parent_window,
580 BC_WindowBase::get_resources()->listbox_up,
582 column_sort_dn = new BC_Pixmap(parent_window,
583 BC_WindowBase::get_resources()->listbox_dn,
586 //printf("BC_ListBox::initialize 10\n");
587 drag_icon_vframe = get_resources()->type_to_icon[ICON_UNKNOWN];
588 drag_column_icon_vframe = get_resources()->type_to_icon[ICON_COLUMN];
589 // = new BC_Pixmap(parent_window,
590 // get_resources()->type_to_icon[ICON_UNKNOWN],
592 // drag_column_icon = new BC_Pixmap(parent_window,
593 // get_resources()->type_to_icon[ICON_COLUMN],
595 BC_SubWindow::initialize();
599 if(top_level->get_resources()->listbox_bg)
600 bg_pixmap = new BC_Pixmap(this,
601 get_resources()->listbox_bg,
607 if(!use_button && is_popup)
616 void BC_ListBox::deactivate_selection()
618 current_operation = NO_OPERATION;
621 int BC_ListBox::draw_button(int flush)
623 // Draw the button for a popup listbox
624 if(use_button && is_popup)
626 int image_number = 0;
628 draw_top_background(parent_window, 0, 0, w, h);
630 if(button_highlighted)
632 if(current_operation == BUTTON_DN)
638 pixmap->draw_pixmap(button_images[image_number],
650 int BC_ListBox::calculate_item_coords()
658 // Change the display_format to get the right item dimensions for both
660 temp_display_format = display_format;
663 // Scan the first column for lowest y coord of all text
664 // and lowest right x and y coord for all icons which aren't auto placable
665 calculate_last_coords_recursive(data,
672 // Reset last column width. It's recalculated based on text width.
674 calculate_item_coords_recursive(data,
683 display_format = temp_display_format;
688 void BC_ListBox::calculate_last_coords_recursive(
689 ArrayList<BC_ListBoxItem*> *data,
696 for(int i = 0; i < data[0].size(); i++)
698 int current_text_y = 0;
699 int current_icon_x = 0;
700 int current_icon_y = 0;
701 BC_ListBoxItem *item = data[0].get(i);
704 if(!item->autoplace_text)
706 // Lowest text coordinate
707 display_format = LISTBOX_TEXT;
708 current_text_y = item->text_y + get_text_h(item);
709 if(current_text_y > *next_text_y)
710 *next_text_y = current_text_y;
712 // Add sublist depth if it is expanded
713 if(item->get_sublist() &&
714 item->get_columns() &&
717 calculate_last_coords_recursive(item->get_sublist(),
726 // Get next_icon coordinate
729 BC_ListBoxItem *item = data[master_column].get(i);
730 if(!item->autoplace_icon)
732 display_format = LISTBOX_ICONS;
733 // Lowest right icon coordinate.
734 current_icon_x = item->icon_x;
735 if(current_icon_x > *icon_x) *icon_x = current_icon_x;
736 if(current_icon_x + get_item_w(item) > *next_icon_x) {
737 *next_icon_x = current_icon_x + get_item_w(item);
740 current_icon_y = item->icon_y + get_item_h(item);
741 if(current_icon_y > *next_icon_y)
742 *next_icon_y = current_icon_y;
749 void BC_ListBox::calculate_item_coords_recursive(
750 ArrayList<BC_ListBoxItem*> *data,
757 // get maximum height of an icon
758 row_height = get_text_height(MEDIUMFONT);
759 if(temp_display_format == LISTBOX_ICON_LIST)
761 for(int i = 0; i < data[0].size(); i++)
763 if(data[0].get(i)->icon)
765 if(data[0].get(i)->icon->get_h() > row_height)
766 row_height = data[0].get(i)->icon->get_h();
772 // Set up items which need autoplacement.
773 // Should fill icons down and then across
774 for(int i = 0; i < data[0].size(); i++)
776 // Don't increase y unless the row requires autoplacing.
777 int total_autoplaced_columns = 0;
779 // Set up icons in first column
782 BC_ListBoxItem *item = data[master_column].get(i);
783 if(item->autoplace_icon)
785 // 1 column only if icons are used
786 display_format = LISTBOX_ICONS;
789 if(*next_icon_y + get_item_h(item) >= get_h() &&
792 *icon_x = *next_icon_x;
796 if(*icon_x + get_item_w(item) > *next_icon_x)
797 *next_icon_x = *icon_x + get_item_w(item);
800 item->set_icon_x(*icon_x);
801 item->set_icon_y(*next_icon_y);
803 *next_icon_y += get_item_h(item);
811 row_ascent = row_descent = 0;
812 // row_height still holds icon max height
813 for(int j = 0; j < columns; j++)
815 BC_ListBoxItem *item = data[j].get(i);
816 if(item->autoplace_text)
818 display_format = LISTBOX_TEXT;
819 item->set_text_x(next_text_x);
820 item->set_text_y(*next_text_y);
821 int ht = get_text_h(item);
822 if( ht > row_height ) row_height = ht;
823 int bl = get_baseline(item);
824 if( bl > row_ascent ) row_ascent = bl;
826 if( dt > row_descent ) row_ascent = bl;
828 // printf("BC_ListBox::calculate_item_coords_recursive %p %d %d %d %d %s \n",
829 // item->get_sublist(),
830 // item->get_columns(),
831 // item->get_expand(),
834 // item->get_text());
835 // Increment position of next column
838 next_text_x += (column_width ?
840 default_column_width[j]);
843 // Set last column width based on text width
845 int new_w = get_item_w(item);
847 int *previous_w = (column_width ?
849 &default_column_width[j]);
850 if(new_w > *previous_w)
852 //printf("BC_ListBox::calculate_item_coords_recursive 1 %d\n", new_w);
854 total_autoplaced_columns++;
858 // Increase the text vertical position
859 if(total_autoplaced_columns)
861 display_format = LISTBOX_TEXT;
862 *next_text_y += row_height;
866 BC_ListBoxItem *item = data[master_column].values[i];
867 if(item->get_sublist() &&
868 item->get_columns() &&
871 calculate_item_coords_recursive(
882 void BC_ListBox::set_is_suggestions(int value)
884 this->is_suggestions = value;
887 void BC_ListBox::set_use_button(int value)
889 this->use_button = value;
892 void BC_ListBox::set_justify(int value)
894 this->justify = value;
897 void BC_ListBox::set_allow_drag_column(int value)
899 this->allow_drag_column = value;
902 void BC_ListBox::set_process_drag(int value)
904 this->process_drag = value;
907 void BC_ListBox::set_master_column(int value, int redraw)
909 this->master_column = value;
916 void BC_ListBox::set_search_column(int value)
918 this->search_column = value;
921 int BC_ListBox::get_sort_column()
926 void BC_ListBox::set_sort_column(int value, int redraw)
935 int BC_ListBox::get_sort_order()
940 void BC_ListBox::set_sort_order(int value, int redraw)
953 int BC_ListBox::get_display_mode()
955 return display_format;
958 int BC_ListBox::get_yposition()
963 int BC_ListBox::get_xposition()
968 int BC_ListBox::get_highlighted_item()
970 return highlighted_item;
974 int BC_ListBox::get_item_x(BC_ListBoxItem *item)
976 if(display_format == LISTBOX_TEXT)
978 return item->text_x - xposition + 2;
981 if(display_format == LISTBOX_ICON_LIST)
983 return item->text_x - xposition + 2;
987 return item->icon_x - xposition + 2;
991 int BC_ListBox::get_item_y(BC_ListBoxItem *item)
994 if(display_format == LISTBOX_TEXT)
996 result = item->text_y - yposition + title_h + 2;
999 if(display_format == LISTBOX_ICON_LIST)
1001 result = item->text_y - yposition + title_h + 2;
1005 result = item->icon_y - yposition + title_h + 2;
1011 int BC_ListBox::get_item_w(BC_ListBoxItem *item)
1013 if(display_format == LISTBOX_ICONS)
1016 get_icon_mask(item, x, y, w, h);
1018 get_text_mask(item, x, y, w, h);
1021 return icon_position == ICON_LEFT ? icon_w + text_w :
1022 icon_w > text_w ? icon_w : text_w;
1024 return get_text_w(item) + 2 * LISTBOX_MARGIN;
1027 int BC_ListBox::get_item_h(BC_ListBoxItem *item)
1029 if(display_format == LISTBOX_ICONS)
1032 get_icon_mask(item, x, y, w, h);
1034 get_text_mask(item, x, y, w, h);
1037 return icon_position != ICON_LEFT ? icon_h + text_h :
1038 icon_h > text_h ? icon_h : text_h;
1040 return get_text_h(item);
1044 int BC_ListBox::get_icon_w(BC_ListBoxItem *item)
1046 return item->get_icon_w();
1049 int BC_ListBox::get_icon_h(BC_ListBoxItem *item)
1051 return item->get_icon_h();
1054 int BC_ListBox::get_text_w(BC_ListBoxItem *item)
1056 int w = item->get_text_w();
1057 if( w < 0 ) item->set_text_w(w = get_text_width(MEDIUMFONT, item->get_text()));
1061 int BC_ListBox::get_text_h(BC_ListBoxItem *item)
1063 int h = item->get_text_h();
1064 if( h < 0 ) item->set_text_h(h = get_text_height(MEDIUMFONT));
1068 int BC_ListBox::get_baseline(BC_ListBoxItem *item)
1070 int b = item->get_baseline();
1071 if( b < 0 ) item->set_baseline(b = get_text_ascent(MEDIUMFONT));
1075 int BC_ListBox::get_items_width()
1079 if(display_format == LISTBOX_ICONS)
1081 for(int i = 0; i < columns; i++)
1083 for(int j = 0; j < data[i].total; j++)
1086 BC_ListBoxItem *item = data[i].values[j];
1089 get_icon_mask(item, x, y, w, h);
1090 if(x1 + w > widest) widest = x1 + w;
1092 if(display_format == LISTBOX_ICONS && icon_position == ICON_LEFT)
1095 get_text_mask(item, x, y, w, h);
1096 if(x1 + w > widest) widest = x1 + w;
1101 if(display_format == LISTBOX_TEXT)
1103 return get_column_offset(columns);
1107 return get_column_offset(columns);
1112 int BC_ListBox::get_items_height(ArrayList<BC_ListBoxItem*> *data,
1129 for(int j = 0; j < (data ? data[master_column].total : 0); j++)
1132 BC_ListBoxItem *item = data[master_column].values[j];
1134 if( display_format == LISTBOX_ICONS ||
1135 display_format == LISTBOX_ICON_LIST ) {
1136 get_icon_mask(item, x, y, w, h);
1137 if(y + h + yposition > highest) highest = y + h + yposition;
1139 get_text_mask(item, x, y, w, h);
1140 if(y + h + yposition > highest) highest = y + h + yposition;
1144 get_text_mask(item, x, y, w, h);
1146 // Descend into sublist
1147 if(item->get_sublist() &&
1150 get_items_height(item->get_sublist(),
1151 item->get_columns(),
1157 if( display_format == LISTBOX_TEXT && top_level )
1159 highest = LISTBOX_MARGIN + *result;
1166 int BC_ListBox::set_yposition(int position, int draw_items)
1168 this->yposition = position;
1171 this->draw_items(1);
1176 int BC_ListBox::set_xposition(int position)
1178 this->xposition = position;
1183 void BC_ListBox::expand_item(BC_ListBoxItem *item, int expand)
1187 item->expand = expand;
1188 // Collapse sublists if this is collapsed to make it easier to calculate
1190 if(item->get_sublist())
1191 collapse_recursive(item->get_sublist(), master_column);
1194 // Set everything for autoplacement
1196 set_autoplacement(data, 0, 1);
1202 void BC_ListBox::collapse_recursive(ArrayList<BC_ListBoxItem*> *data,
1205 for(int i = 0; i < data[master_column].total; i++)
1207 BC_ListBoxItem *item = data[master_column].values[i];
1208 if(item->get_sublist() && item->expand)
1211 collapse_recursive(item->get_sublist(), master_column);
1216 void BC_ListBox::set_autoplacement(ArrayList<BC_ListBoxItem*> *data,
1220 for(int i = 0; i < data[0].total; i++)
1222 for(int j = 0; j < columns; j++)
1224 if(do_icons) data[j].values[i]->autoplace_icon = 1;
1225 if(do_text) data[j].values[i]->autoplace_text = 1;
1228 BC_ListBoxItem *item = data[master_column].values[i];
1229 if(item->get_sublist())
1231 set_autoplacement(item->get_sublist(), do_icons, do_text);
1238 int BC_ListBox::get_yscroll_x()
1241 return popup_w - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w();
1245 get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w();
1248 int BC_ListBox::get_yscroll_y()
1256 int BC_ListBox::get_yscroll_height()
1258 return popup_h - (need_xscroll ?
1259 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h() :
1263 int BC_ListBox::get_xscroll_x()
1271 int BC_ListBox::get_xscroll_y()
1275 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h();
1279 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h();
1282 int BC_ListBox::get_xscroll_width()
1284 return popup_w - (need_yscroll ?
1285 get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w() :
1289 int BC_ListBox::get_column_offset(int column)
1295 column_width[--column] :
1296 default_column_width[--column];
1301 void BC_ListBox::column_width_boundaries()
1304 for(int i = 0; i < columns; i++) {
1305 if(column_width[i] < MIN_COLUMN_WIDTH)
1306 column_width[i] = MIN_COLUMN_WIDTH;
1310 for(int i = 0; i < columns; i++) {
1311 if(default_column_width[i] < MIN_COLUMN_WIDTH)
1312 default_column_width[i] = MIN_COLUMN_WIDTH;
1317 int BC_ListBox::get_column_width(int column, int clamp_right)
1319 if(column < columns - 1 || !clamp_right)
1320 return column_width ? column_width[column] : default_column_width[column];
1321 return popup_w + xposition - get_column_offset(column);
1324 int BC_ListBox::get_icon_mask(BC_ListBoxItem *item,
1325 int &x, int &y, int &w, int &h)
1327 if( display_format == LISTBOX_ICONS ) {
1328 x = get_item_x(item);
1329 y = get_item_y(item);
1330 w = get_icon_w(item) + ICON_MARGIN * 2;
1331 h = get_icon_h(item) + ICON_MARGIN * 2;
1338 int BC_ListBox::get_text_mask(BC_ListBoxItem *item,
1339 int &x, int &y, int &w, int &h)
1341 x = get_item_x(item);
1342 y = get_item_y(item);
1344 if(display_format == LISTBOX_ICONS) {
1345 if(icon_position == ICON_LEFT) {
1346 x += get_icon_w(item) + ICON_MARGIN * 2;
1347 y += get_icon_h(item) - get_text_h(item);
1350 y += get_icon_h(item) + ICON_MARGIN;
1353 w = get_text_w(item) + ICON_MARGIN * 2;
1354 h = get_text_h(item) + ICON_MARGIN * 2;
1357 if(display_format == LISTBOX_TEXT) {
1358 w = get_text_w(item) + LISTBOX_MARGIN * 2;
1359 h = get_text_h(item);
1363 w = get_text_width(MEDIUMFONT, item->text) + LISTBOX_MARGIN * 2;
1369 int BC_ListBox::get_item_highlight(ArrayList<BC_ListBoxItem*> *data,
1373 BC_Resources *resources = get_resources();
1374 if(data[column].values[item]->selected)
1375 return resources->listbox_selected;
1376 else if(highlighted_item >= 0 &&
1377 highlighted_ptr == data[master_column].values[item])
1378 return resources->listbox_highlighted;
1379 return resources->listbox_inactive;
1382 int BC_ListBox::get_item_color(ArrayList<BC_ListBoxItem*> *data,
1386 int color = data[column].values[item]->color;
1387 if( color == -1 ) color = get_resources()->listbox_text;
1388 if( get_item_highlight(data, column, item) == color )
1393 int BC_ListBox::get_from_column()
1395 return dragged_title;
1398 int BC_ListBox::get_to_column()
1400 return highlighted_title;
1404 BC_ListBoxItem* BC_ListBox::get_selection(int column,
1405 int selection_number)
1407 return get_selection_recursive(data,
1412 BC_ListBoxItem* BC_ListBox::get_selection_recursive(
1413 ArrayList<BC_ListBoxItem*> *data,
1415 int selection_number)
1419 for(int i = 0; i < data[master_column].total; i++)
1421 BC_ListBoxItem *item = data[master_column].values[i];
1424 //printf("BC_ListBox::get_selection_recursive %d\n", __LINE__);
1426 if(selection_number < 0)
1429 return data[column].values[i];
1433 if(item->get_sublist())
1435 BC_ListBoxItem *result = get_selection_recursive(item->get_sublist(),
1438 if(result) return result;
1446 int BC_ListBox::get_selection_number(int column,
1447 int selection_number)
1449 return get_selection_number_recursive(data,
1454 int BC_ListBox::get_selection_number_recursive(
1455 ArrayList<BC_ListBoxItem*> *data,
1457 int selection_number,
1462 if(!counter) counter = &temp;
1464 for(int i = 0; i < data[master_column].total; i++)
1467 BC_ListBoxItem *item = data[master_column].values[i];
1471 if(selection_number < 0)
1476 if(item->get_sublist())
1478 int result = get_selection_number_recursive(
1479 item->get_sublist(),
1483 if(result >= 0) return result;
1490 int BC_ListBox::set_selection_mode(int mode)
1492 this->selection_mode = mode;
1496 void BC_ListBox::delete_columns()
1500 for(int i = 0; i < columns; i++)
1502 delete [] column_titles[i];
1504 delete [] column_titles;
1507 if(column_width) delete [] column_width;
1513 // Need to copy titles so EDL can change
1514 void BC_ListBox::set_columns(const char **column_titles,
1518 if((!column_titles && column_width) ||
1519 (column_titles && !column_width))
1521 printf("BC_ListBox::set_columns either column_titles or column_width == NULL but not both.\n");
1530 this->column_titles = new char*[columns];
1531 for(int i = 0; i < columns; i++)
1533 this->column_titles[i] = new char[strlen(column_titles[i]) + 1];
1534 strcpy(this->column_titles[i], column_titles[i]);
1540 this->column_width = new int[columns];
1541 for(int i = 0; i < columns; i++)
1543 this->column_width[i] = column_width[i];
1547 this->columns = columns;
1552 int BC_ListBox::update(ArrayList<BC_ListBoxItem*> *data,
1553 const char **column_titles,
1558 int highlighted_number,
1559 int recalc_positions,
1562 set_columns(column_titles,
1568 this->yposition = yposition;
1569 this->xposition = xposition;
1570 this->highlighted_item = highlighted_number;
1571 this->highlighted_ptr = index_to_item(data, highlighted_number, 0);
1573 if(recalc_positions)
1574 set_autoplacement(data, 1, 1);
1576 init_column_width();
1581 update_scrollbars(1);
1587 void BC_ListBox::center_selection()
1589 int selection = get_selection_number(0, 0);
1591 calculate_item_coords();
1592 center_selection(selection);
1598 update_scrollbars(0);
1599 gui->show_window(1);
1603 void BC_ListBox::move_vertical(int pixels)
1607 void BC_ListBox::move_horizontal(int pixels)
1611 int BC_ListBox::select_previous(int skip,
1612 BC_ListBoxItem *selected_item,
1614 ArrayList<BC_ListBoxItem*> *data,
1620 selected_item = get_selection(0, 0);
1632 got_second = &temp3;
1636 // Scan backwards to item pointer. Then count visible items to get
1637 // destination. No wraparound.
1640 for(int i = data[master_column].total - 1; i >= 0; i--)
1642 BC_ListBoxItem *current_item = data[master_column].values[i];
1643 if(current_item->get_sublist() &&
1644 current_item->get_expand())
1646 int result = select_previous(skip,
1649 current_item->get_sublist(),
1661 if((*counter) >= skip)
1663 for(int j = 0; j < columns; j++)
1664 data[j].values[i]->selected = 1;
1666 return item_to_index(this->data, current_item);
1671 if(current_item->selected)
1673 for(int j = 0; j < columns; j++)
1674 data[j].values[i]->selected = 0;
1681 // Hit top of top level without finding a selected item.
1684 // Select first item in top level and quit
1685 BC_ListBoxItem *current_item;
1687 current_item = data[master_column].values[0];
1689 for(int j = 0; j < columns; j++)
1690 data[j].values[0]->selected = 1;
1692 return item_to_index(this->data, current_item);
1694 }while(top_level && data[master_column].total);
1698 int BC_ListBox::select_next(int skip,
1699 BC_ListBoxItem *selected_item,
1701 ArrayList<BC_ListBoxItem*> *data,
1707 selected_item = get_selection(0, 0);
1719 got_second = &temp3;
1723 // Scan forwards to currently selected item pointer.
1724 // Then count visible items to get destination. No wraparound.
1727 for(int i = 0; i < data[master_column].total; i++)
1729 BC_ListBoxItem *current_item = data[master_column].values[i];
1731 // Select next item once the number items after the currently selected item
1732 // have been passed.
1736 if((*counter) >= skip)
1738 for(int j = 0; j < columns; j++)
1739 data[j].values[i]->selected = 1;
1741 return item_to_index(this->data, current_item);
1746 // Got currently selected item. Deselect it.
1747 if(current_item->selected)
1749 for(int j = 0; j < columns; j++)
1750 data[j].values[i]->selected = 0;
1756 // Descend into expanded level
1757 if(current_item->get_sublist() &&
1758 current_item->get_expand())
1760 int result = select_next(skip,
1763 current_item->get_sublist(),
1773 // Hit bottom of top level without finding the next item.
1776 BC_ListBoxItem *current_item;
1777 // Select first item in top level and quit
1781 current_item = data[master_column].values[0];
1783 for(int j = 0; j < columns; j++)
1784 data[j].values[0]->selected = 1;
1789 // Select last item in top level and quit
1791 int current_row = data[master_column].total - 1;
1792 current_item = data[master_column].values[current_row];
1794 for(int j = 0; j < columns; j++)
1795 data[j].values[current_row]->selected = 1;
1799 return item_to_index(this->data, current_item);
1801 }while(top_level && data[master_column].total);
1807 void BC_ListBox::clamp_positions()
1809 items_w = get_items_width();
1810 items_h = get_items_height(data, columns);
1812 if(yposition < 0) yposition = 0;
1814 if(yposition > items_h - view_h)
1815 yposition = items_h - view_h;
1817 if(yposition < 0) yposition = 0;
1819 if(xposition < 0) xposition = 0;
1821 if(xposition >= items_w - view_w)
1822 xposition = items_w - view_w;
1824 if(xposition < 0) xposition = 0;
1827 int BC_ListBox::center_selection(int selection,
1828 ArrayList<BC_ListBoxItem*> *data,
1832 if(!data) data = this->data;
1833 if(!counter) counter = &temp;
1835 for(int i = 0; i < data[master_column].total; i++)
1840 BC_ListBoxItem *item = data[master_column].values[i];
1841 if((*counter) == selection)
1843 BC_ListBoxItem *top_item = this->data[master_column].values[0];
1846 if(display_format == LISTBOX_ICONS)
1848 // Icon is out of window
1849 if( item->icon_y-yposition > view_h-get_text_h(item) ||
1850 item->icon_y-yposition < 0 ) {
1851 yposition = item->icon_y - view_h / 2;
1854 if(data[master_column].values[selection]->icon_x - xposition > view_w ||
1855 data[master_column].values[selection]->icon_x - xposition < 0)
1857 xposition = item->icon_x - view_w / 2;
1862 // Text coordinate is out of window
1863 if( item->text_y-yposition > view_h-get_text_h(item) ||
1864 item->text_y-yposition < 0 ) {
1865 yposition = item->text_y -
1874 if(item->get_sublist())
1876 int result = center_selection(selection,
1877 item->get_sublist(),
1879 if(result) return result;
1885 void BC_ListBox::update_scrollbars(int flush)
1887 int h_needed = items_h = get_items_height(data, columns);
1888 int w_needed = items_w = get_items_width();
1890 // if(columns > 0 && column_width)
1891 // printf("BC_ListBox::update_scrollbars 1 %d %d\n", column_width[columns - 1], w_needed);
1895 if(xposition != xscrollbar->get_value())
1896 xscrollbar->update_value(xposition);
1898 if(w_needed != xscrollbar->get_length() ||
1899 view_w != xscrollbar->get_handlelength())
1900 xscrollbar->update_length(w_needed, xposition, view_w, 0);
1905 if(yposition != yscrollbar->get_value())
1906 yscrollbar->update_value(yposition);
1908 if(h_needed != yscrollbar->get_length() || view_h != yscrollbar->get_handlelength())
1909 yscrollbar->update_length(h_needed, yposition, view_h, 0);
1912 if(flush) this->flush();
1915 int BC_ListBox::get_scrollbars()
1917 int h_needed = items_h = get_items_height(data, columns);
1918 int w_needed = items_w = get_items_width();
1922 title_h = get_title_h();
1924 view_h = popup_h - title_h - 4;
1925 view_w = popup_w - 4;
1927 // Create scrollbars as needed
1928 for(int i = 0; i < 2; i++)
1930 if(w_needed > view_w)
1935 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h() -
1943 if(h_needed > view_h)
1947 get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w() -
1956 // Update subwindow size
1957 int new_w = popup_w;
1958 int new_h = popup_h;
1959 if(need_xscroll) new_h -= get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h();
1960 if(need_yscroll) new_w -= get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w();
1963 if(new_w != BC_WindowBase::get_w() || new_h != BC_WindowBase::get_h())
1964 gui->resize_window(new_w, new_h);
1966 BC_WindowBase *destination = (is_popup ? gui : parent_window);
1971 destination->add_subwindow(xscrollbar =
1972 new BC_ListBoxXScroll(this,
1976 xscrollbar->show_window(0);
1977 xscrollbar->bound_to = this;
1981 xscrollbar->update_length(w_needed, xposition, view_w, flush);
1982 xscrollbar->reposition_window(get_xscroll_x(),
1984 get_xscroll_width());
1989 if(xscrollbar) delete xscrollbar;
1998 destination->add_subwindow(yscrollbar =
1999 new BC_ListBoxYScroll(this,
2003 yscrollbar->show_window(0);
2004 yscrollbar->bound_to = this;
2008 yscrollbar->update_length(h_needed, yposition, view_h, flush);
2009 yscrollbar->reposition_window(get_yscroll_x(),
2011 get_yscroll_height());
2016 if(yscrollbar) delete yscrollbar;
2022 view_w + 4 != bg_surface->get_w() ||
2023 view_h + 4 != bg_surface->get_h())
2025 if(bg_surface) delete bg_surface;
2026 bg_surface = new BC_Pixmap(gui, view_w + 4, view_h + 4);
2036 void BC_ListBox::set_drag_scroll(int value)
2038 allow_drag_scroll = value;
2042 // Test for scrolling by dragging
2044 int BC_ListBox::test_drag_scroll(int cursor_x, int cursor_y)
2047 if(allow_drag_scroll ||
2048 current_operation == SELECT_RECT)
2051 int top_boundary = get_title_h();
2053 if(cursor_y < top_boundary ||
2054 cursor_y >= view_h + title_h + LISTBOX_BORDER * 2 ||
2055 cursor_x < LISTBOX_BORDER ||
2056 cursor_x >= view_w + LISTBOX_BORDER)
2064 int BC_ListBox::drag_scroll_event()
2066 int top_boundary = get_title_h();
2069 if(get_cursor_y() < top_boundary)
2071 yposition -= top_boundary - get_cursor_y();
2075 if(get_cursor_y() >= view_h + title_h + 4)
2077 yposition += get_cursor_y() - (view_h + title_h + 4);
2081 if(get_cursor_x() < 2)
2083 xposition -= 2 - get_cursor_x();
2087 if(get_cursor_x() >= view_w + 2)
2089 xposition += get_cursor_x() - (view_w + 2);
2092 if(result) clamp_positions();
2096 int BC_ListBox::rectangle_scroll_event()
2098 int old_xposition = xposition;
2099 int old_yposition = yposition;
2100 int result = drag_scroll_event();
2104 rect_x1 += old_xposition - xposition;
2105 rect_y1 += old_yposition - yposition;
2106 rect_x2 = get_cursor_x();
2107 rect_y2 = get_cursor_y();
2109 int x1 = MIN(rect_x1, rect_x2);
2110 int x2 = MAX(rect_x1, rect_x2);
2111 int y1 = MIN(rect_y1, rect_y2);
2112 int y2 = MAX(rect_y1, rect_y2);
2114 if(select_rectangle(data,
2120 selection_changed();
2125 update_scrollbars(1);
2130 int BC_ListBox::select_scroll_event()
2132 int result = drag_scroll_event();
2136 highlighted_item = selection_number = get_cursor_item(data,
2142 update_scrollbars(1);
2143 selection_changed();
2148 int BC_ListBox::select_rectangle(ArrayList<BC_ListBoxItem*> *data,
2155 for(int i = 0; i < data[master_column].total; i++)
2157 for(int j = 0; j < columns; j++)
2159 BC_ListBoxItem *item = data[j].values[i];
2160 if(display_format == LISTBOX_ICONS)
2162 int icon_x, icon_y, icon_w, icon_h;
2163 int text_x, text_y, text_w, text_h;
2164 get_icon_mask(item, icon_x, icon_y, icon_w, icon_h);
2165 get_text_mask(item, text_x, text_y, text_w, text_h);
2167 if((x2 >= icon_x && x1 < icon_x + icon_w &&
2168 y2 >= icon_y && y1 < icon_y + icon_h) ||
2169 (x2 >= text_x && x1 < text_x + text_w &&
2170 y2 >= text_y && y1 < text_y + text_h))
2191 gui->get_w() - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w() :
2194 y1 < gui->get_h() &&
2195 y2 >= get_item_y(item) &&
2196 y1 < get_item_y(item) + get_item_h(item))
2215 BC_ListBoxItem *item = data[master_column].values[i];
2216 if(item->get_sublist() &&
2218 result |= select_rectangle(item->get_sublist(),
2227 int BC_ListBox::reposition_item(ArrayList<BC_ListBoxItem*> *data,
2228 int selection_number,
2234 if(!counter) counter = &temp;
2237 for(int i = 0; i < data[master_column].total; i++)
2239 BC_ListBoxItem *item = data[master_column].values[i];
2241 if((*counter) == selection_number)
2247 // Not recursive because it's only used for icons
2252 void BC_ListBox::move_selection(ArrayList<BC_ListBoxItem*> *dst,
2253 ArrayList<BC_ListBoxItem*> *src)
2255 for(int i = 0; i < src[master_column].total; i++)
2257 BC_ListBoxItem *item = src[master_column].values[i];
2262 for(int j = 0; j < columns; j++)
2264 dst[j].append(src[j].values[i]);
2265 src[j].remove_number(i);
2269 // Descend into sublist
2270 if(item->get_sublist())
2273 item->get_sublist());
2278 int BC_ListBox::put_selection(ArrayList<BC_ListBoxItem*> *data,
2279 ArrayList<BC_ListBoxItem*> *src,
2284 if(!counter) counter = &temp;
2288 for(int j = 0; j < columns; j++)
2290 for(int i = 0; i < src[j].total; i++)
2292 data[j].append(src[j].values[i]);
2298 for(int i = 0; i < data[master_column].total; i++)
2301 if((*counter) == destination)
2303 for(int j = 0; j < columns; j++)
2305 for(int k = 0; k < src[j].total; k++)
2307 data[j].insert(src[j].values[k], destination + k);
2313 BC_ListBoxItem *item = data[master_column].values[i];
2314 if(item->get_sublist())
2316 if(put_selection(item->get_sublist(),
2328 int BC_ListBox::item_to_index(ArrayList<BC_ListBoxItem*> *data,
2329 BC_ListBoxItem *item,
2333 if(!counter) counter = &temp;
2335 for(int i = 0; i < data[master_column].total; i++)
2338 for(int j = 0; j < columns; j++)
2340 BC_ListBoxItem *new_item = data[j].values[i];
2341 //printf("BC_ListBox::item_to_index 1 %d %d %p\n", j, i, new_item);
2342 if(new_item == item)
2348 BC_ListBoxItem *new_item = data[master_column].values[i];
2349 if(new_item->get_sublist())
2351 if(item_to_index(new_item->get_sublist(),
2361 BC_ListBoxItem* BC_ListBox::index_to_item(ArrayList<BC_ListBoxItem*> *data,
2367 if(!counter) counter = &temp;
2368 for(int i = 0; i < data[master_column].total; i++)
2371 if((*counter) == number)
2373 return data[column].values[i];
2375 BC_ListBoxItem *item = data[master_column].values[i];
2376 if(item->get_sublist())
2378 BC_ListBoxItem *result = index_to_item(item->get_sublist(),
2382 if(result) return result;
2388 int BC_ListBox::get_cursor_item(ArrayList<BC_ListBoxItem*> *data,
2391 BC_ListBoxItem **item_return,
2396 if(!data) return -1;
2397 if(!counter) counter = &temp;
2399 // Icons are not treed
2400 if(display_format == LISTBOX_ICONS)
2402 for(int j = data[master_column].total - 1; j >= 0; j--)
2404 int icon_x, icon_y, icon_w, icon_h;
2405 int text_x, text_y, text_w, text_h;
2406 BC_ListBoxItem *item = data[master_column].values[j];
2407 get_icon_mask(item, icon_x, icon_y, icon_w, icon_h);
2408 get_text_mask(item, text_x, text_y, text_w, text_h);
2410 if((cursor_x >= icon_x && cursor_x < icon_x + icon_w &&
2411 cursor_y >= icon_y && cursor_y < icon_y + icon_h) ||
2412 (cursor_x >= text_x && cursor_x < text_x + text_w &&
2413 cursor_y >= text_y && cursor_y < text_y + text_h))
2415 if(item_return) (*item_return) = item;
2422 // Cursor is inside items rectangle
2424 cursor_x < (yscrollbar ?
2425 gui->get_w() - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w() :
2427 // Only clamp y if we're not in a SELECT operation.
2428 (current_operation == BC_ListBox::SELECT ||
2429 (cursor_y > get_title_h() + LISTBOX_BORDER &&
2430 cursor_y < gui->get_h())))
2432 // Search table for cursor obstruction
2433 for(int i = 0; i < data[master_column].total; i++)
2435 BC_ListBoxItem *item = data[master_column].values[i];
2438 // Cursor is inside item on current level
2441 cursor_y >= get_item_y(item) &&
2442 cursor_y < get_item_y(item) + get_item_h(item))
2444 //printf("BC_ListBox::get_cursor_item %d %d %p\n", master_column, i, item);
2445 if(item_return) (*item_return) = item;
2449 // Descend into sublist
2450 if(item->get_sublist())
2452 if(get_cursor_item(item->get_sublist(),
2457 item->get_expand()) >= 0)
2466 int BC_ListBox::repeat_event(int64_t duration)
2468 switch(current_operation)
2470 // Repeat out of bounds selection
2472 if(duration == get_resources()->scroll_repeat)
2473 return rectangle_scroll_event();
2477 if(duration == get_resources()->scroll_repeat)
2478 return select_scroll_event();
2483 if(button_highlighted && is_popup &&
2484 tooltip_text && tooltip_text[0] != 0 &&
2485 duration == get_resources()->tooltip_delay)
2496 int BC_ListBox::cursor_enter_event()
2500 switch(current_operation)
2502 // Cursor moved over button, pressed, and exited.
2503 case BUTTON_DOWN_SELECT:
2504 if(top_level->event_win == win)
2506 current_operation = BUTTON_DN;
2508 button_highlighted = 1;
2514 // Cursor entered button
2515 if(is_popup && top_level->event_win == win)
2517 button_highlighted = 1;
2522 // TODO: Need to get the highlighted column title or item
2523 if(gui && top_level->event_win == gui->win)
2525 list_highlighted = 1;
2535 int BC_ListBox::cursor_leave_event()
2537 if(current_operation == COLUMN_DRAG) return 0;
2540 if(button_highlighted)
2542 button_highlighted = 0;
2547 if(list_highlighted)
2549 list_highlighted = 0;
2550 highlighted_item = -1;
2551 highlighted_ptr = 0;
2552 highlighted_title = -1;
2553 int redraw_toggles = 0;
2554 for(int i = 0; i < expanders.total; i++)
2555 expanders.values[i]->cursor_leave_event(&redraw_toggles);
2563 int BC_ListBox::get_first_selection(ArrayList<BC_ListBoxItem*> *data, int *result)
2566 if(!result) result = &temp;
2568 for(int i = 0; i < data[master_column].total; i++)
2570 BC_ListBoxItem *item = data[master_column].values[i];
2572 if(item->selected) return (*result);
2573 if(item->get_sublist())
2575 if(get_first_selection(item->get_sublist(), result) >= 0)
2582 int BC_ListBox::get_total_items(ArrayList<BC_ListBoxItem*> *data,
2587 if(!result) result = &temp;
2589 for(int i = 0; i < data[master_column].total; i++)
2592 if(data[master_column].values[i]->get_sublist())
2593 get_total_items(data[master_column].values[i]->get_sublist(),
2602 int BC_ListBox::get_last_selection(ArrayList<BC_ListBoxItem*> *data,
2613 for(int i = data[master_column].total - 1; i >= 0; i--)
2615 BC_ListBoxItem *item = data[master_column].values[i];
2620 return get_total_items(data, 0, master_column) - (*result) /* - 1 */;
2625 if(item->get_sublist())
2627 if(get_last_selection(item->get_sublist(), result) >= 0)
2630 return get_total_items(data, 0, master_column) - (*result) /* - 1 */;
2639 void BC_ListBox::select_range(ArrayList<BC_ListBoxItem*> *data,
2645 if(!current) current = &temp;
2647 for(int i = 0; i < data[master_column].total; i++)
2650 if((*current) >= start && (*current) < end)
2652 for(int j = 0; j < columns; j++)
2653 data[j].values[i]->selected = 1;
2655 BC_ListBoxItem *item = data[master_column].values[i];
2656 if(item->get_sublist())
2657 select_range(item->get_sublist(),
2665 // Fill items between current selection and new selection
2666 int BC_ListBox::expand_selection(int button_press, int selection_number)
2668 int old_selection_start = selection_start;
2669 int old_selection_end = selection_end;
2671 // printf("BC_ListBox::expand_selection %d %d\n",
2672 // selection_center,
2673 // selection_number);
2675 // Calculate the range to select based on selection_center and selection_number
2676 if(selection_number < selection_center)
2678 selection_start = selection_number;
2682 selection_end = selection_number + 1;
2685 //printf("BC_ListBox::expand_selection %d %d %d %d\n", old_selection_start, old_selection_end, selection_start, selection_end);
2686 // Recurse through all the items and select the desired range
2687 select_range(data, selection_start, selection_end);
2690 return (old_selection_start != selection_start ||
2691 old_selection_end != selection_end);
2694 int BC_ListBox::toggle_item_selection(ArrayList<BC_ListBoxItem*> *data,
2695 int selection_number,
2699 if(!counter) counter = &temp;
2701 for(int i = 0; i < data[master_column].total; i++)
2703 BC_ListBoxItem *item = data[master_column].values[i];
2705 if((*counter) == selection_number)
2707 // Get new value for selection
2708 int selected = !item->selected;
2710 for(int j = 0; j < columns; j++)
2711 data[j].values[i]->selected = selected;
2715 // Descend into sublist
2716 if(item->get_sublist())
2718 if(toggle_item_selection(item->get_sublist(),
2729 void BC_ListBox::set_all_selected(ArrayList<BC_ListBoxItem*> *data, int value)
2731 for(int i = 0; i < data[master_column].total; i++)
2733 for(int j = 0; j < columns; j++)
2735 BC_ListBoxItem *item = data[j].values[i];
2736 item->selected = value;
2738 BC_ListBoxItem *item = data[master_column].values[i];
2739 if(item->get_sublist())
2741 set_all_selected(item->get_sublist(), value);
2746 void BC_ListBox::set_selected(ArrayList<BC_ListBoxItem*> *data,
2752 if(!counter) counter = &temp;
2753 for(int i = 0; i < data[master_column].total && (*counter) != item_number; i++)
2756 if((*counter) == item_number)
2758 for(int j = 0; j < columns; j++)
2760 BC_ListBoxItem *item = data[j].values[i];
2761 item->selected = value;
2766 BC_ListBoxItem *item = data[master_column].values[i];
2767 if(item->get_sublist())
2769 set_selected(item->get_sublist(),
2777 int BC_ListBox::update_selection(ArrayList<BC_ListBoxItem*> *data,
2778 int selection_number,
2783 if(!counter) counter = &temp;
2785 for(int i = 0; i < data[master_column].total; i++)
2787 BC_ListBoxItem *item = data[master_column].values[i];
2789 if((*counter) == selection_number && !item->selected)
2792 for(int j = 0; j < columns; j++)
2793 data[j].values[i]->selected = 1;
2796 if((*counter) != selection_number && item->selected)
2799 for(int j = 0; j < columns; j++)
2800 data[j].values[i]->selected = 0;
2802 if(item->get_sublist())
2803 result |= update_selection(item->get_sublist(),
2810 void BC_ListBox::promote_selections(ArrayList<BC_ListBoxItem*> *data,
2814 for(int i = 0; i < data[master_column].total; i++)
2816 for(int j = 0; j < columns; j++)
2818 BC_ListBoxItem *item = data[j].values[i];
2819 if(item->selected == old_value) item->selected = new_value;
2821 BC_ListBoxItem *item = data[master_column].values[i];
2822 if(item->get_sublist())
2823 promote_selections(item->get_sublist(), old_value, new_value);
2827 int BC_ListBox::focus_out_event()
2833 int BC_ListBox::button_press_event()
2836 BC_ListBoxItem *current_item = 0;
2838 int do_selection_change = 0;
2839 const int debug = 0;
2842 if(debug) printf("BC_ListBox::button_press_event %d this=%p event_win=%p %p %p %p\n",
2845 (void*)top_level->event_win,
2846 (void*)(gui ? gui->win : 0),
2848 (void*)parent_window->win);
2850 // Pressed in button
2851 if(is_popup && top_level->event_win == win)
2853 if(debug) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2854 current_operation = BUTTON_DN;
2858 if(!active && !disabled)
2860 top_level->deactivate();
2867 // Pressed in scrollbar
2868 if((xscrollbar && top_level->event_win == xscrollbar->win) ||
2869 (yscrollbar && top_level->event_win == yscrollbar->win))
2871 if(debug) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2876 if(gui && top_level->event_win == gui->win)
2878 if(debug) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2880 // Activate list items
2881 // If it is a suggestion popup, it is visible without being active
2884 if(debug) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2885 if(!is_suggestions) top_level->deactivate();
2886 if(debug) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2888 if(debug) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2891 // Wheel mouse pressed
2892 if(get_buttonpress() == 4)
2894 if(current_operation == NO_OPERATION)
2896 current_operation = WHEEL;
2899 set_yposition(yposition - gui->get_h() / 10, 0);
2901 update_scrollbars(0);
2902 highlighted_ptr = 0;
2903 highlighted_item = get_cursor_item(data,
2904 top_level->cursor_x,
2905 top_level->cursor_y,
2913 if(get_buttonpress() == 5)
2915 if(current_operation == NO_OPERATION)
2917 current_operation = WHEEL;
2920 set_yposition(yposition + gui->get_h() / 10, 0);
2922 update_scrollbars(0);
2923 highlighted_ptr = 0;
2924 highlighted_item = get_cursor_item(data,
2925 top_level->cursor_x,
2926 top_level->cursor_y,
2934 // Pressed over column title division
2935 if(test_column_divisions(gui->get_cursor_x(),
2936 gui->get_cursor_y(),
2939 drag_cursor_x = gui->get_cursor_x() + xposition;
2941 drag_column_w = column_width[highlighted_division - 1];
2943 drag_column_w = default_column_width[highlighted_division - 1];
2945 current_operation = DRAG_DIVISION;
2949 // Pressed in column title
2950 if(test_column_titles(gui->get_cursor_x(), gui->get_cursor_y()))
2952 current_operation = COLUMN_DN;
2953 button_highlighted = 0;
2954 list_highlighted = 1;
2959 // Pressed in expander
2960 if(test_expanders())
2962 current_operation = EXPAND_DN;
2963 // Need to redraw items because of alpha
2968 // Pressed over item
2969 if((selection_number = get_cursor_item(data,
2970 gui->get_cursor_x(),
2971 gui->get_cursor_y(),
2972 ¤t_item)) >= 0)
2974 if(debug) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2976 // Get item button was pressed over
2977 selection_number2 = selection_number1;
2978 selection_number1 = selection_number;
2980 selection_start = -1;
2984 // Multiple item selection is possible
2985 if(selection_mode == LISTBOX_MULTIPLE &&
2986 (ctrl_down() || shift_down()))
2988 // Expand text selection.
2989 // Fill items between selected region and current item.
2991 (display_format == LISTBOX_TEXT ||
2992 display_format == LISTBOX_ICON_LIST))
2994 // Get first item selected
2995 selection_start = get_first_selection(data);
2996 // Get last item selected
2997 selection_end = get_last_selection(data);
2998 // Get center of selected region
2999 if(selection_end > selection_start)
3001 selection_center = (selection_end + selection_start) >> 1;
3005 selection_center = selection_number;
3009 // Deselect everything.
3010 set_all_selected(data, 0);
3011 // Select just the items
3012 expand_selection(1, selection_number);
3016 // Toggle a single item on or off
3018 toggle_item_selection(data, selection_number);
3019 new_value = current_item->selected;
3023 // Select single item
3025 if(!current_item->selected)
3027 set_all_selected(data, 0);
3036 current_operation = SELECT;
3037 highlighted_item = selection_number;
3038 highlighted_ptr = current_item;
3039 button_highlighted = 0;
3040 list_highlighted = 1;
3043 do_selection_change = 1;
3048 // Pressed over nothing. Start rectangle selection.
3050 if(get_buttonpress() == 1 &&
3051 selection_mode == LISTBOX_MULTIPLE)
3055 // Deselect all and redraw if anything was selected
3056 if(get_selection_number(0, 0) >= 0)
3058 set_all_selected(data, 0);
3060 do_selection_change = 1;
3066 // Promote selections to protect from a rectangle selection
3067 promote_selections(data, 1, 2);
3070 // Start rectangle selection
3071 current_operation = SELECT_RECT;
3072 rect_x1 = rect_x2 = get_cursor_x();
3073 rect_y1 = rect_y2 = get_cursor_y();
3081 // Suggestion box is not active but visible, so lie to get it to deactivate
3082 if(is_popup && (active || (is_suggestions && gui)))
3085 if(debug) printf("BC_ListBox::button_press_event %d\n", __LINE__);
3091 if(do_selection_change) selection_changed();
3092 if(debug) printf("BC_ListBox::button_press_event %d %d\n",
3099 int BC_ListBox::button_release_event()
3102 int cursor_x, cursor_y;
3106 //printf("BC_ListBox::button_release_event 1 %d\n", current_operation);
3107 switch(current_operation)
3110 current_operation = NO_OPERATION;
3115 current_operation = NO_OPERATION;
3119 // Release item selection
3120 case BUTTON_DOWN_SELECT:
3122 //printf("BC_ListBox::button_release_event 10\n");
3123 unset_repeat(get_resources()->scroll_repeat);
3124 current_operation = NO_OPERATION;
3126 translate_coordinates(top_level->event_win, gui->win,
3127 gui->get_cursor_x(), gui->get_cursor_y(),
3128 &cursor_x, &cursor_y);
3129 selection_number1 = selection_number =
3130 get_cursor_item(data, cursor_x, cursor_y);
3131 //printf("BC_ListBox::button_release_event %d %d\n", selection_number2, selection_number1);
3137 if(selection_number >= 0)
3143 // Second button release outside button
3144 if(button_releases > 1)
3151 if(top_level->get_double_click() &&
3152 selection_number2 == selection_number1 &&
3153 selection_number2 >= 0 &&
3154 selection_number1 >= 0)
3164 unset_repeat(get_resources()->scroll_repeat);
3167 // Demote selections from rectangle selection
3168 promote_selections(data, 2, 1);
3171 // Hide rectangle overlay
3173 current_operation = NO_OPERATION;
3177 // Release popup button
3180 current_operation = NO_OPERATION;
3184 // Second button release inside button
3185 if(button_releases > 1)
3193 current_operation = NO_OPERATION;
3194 // Update the sort column and the sort order for the user only if the existing
3195 // sort column is valid.
3196 if(sort_column >= 0)
3198 // Invert order only if column is the same
3199 if(highlighted_title == sort_column)
3201 (sort_order == SORT_ASCENDING) ?
3204 // Set the new sort column
3205 sort_column = highlighted_title;
3206 if(!sort_order_event())
3212 // Sorting not enabled. Redraw the title state.
3221 int redraw_toggles = 0;
3222 for(int i = 0; i < expanders.total && !result; i++)
3224 if(expanders.values[i]->button_release_event(&redraw_toggles))
3229 // Need to redraw items because of alpha
3230 if(redraw_toggles) draw_items(1);
3231 current_operation = NO_OPERATION;
3236 // Can't default to NO_OPERATION because it may be used in a drag event.
3241 if(do_event) handle_event();
3243 //printf("BC_ListBox::button_release_event %d %d\n", __LINE__, get_window_lock());
3247 int BC_ListBox::get_title_h()
3249 if(display_format == LISTBOX_TEXT ||
3250 display_format == LISTBOX_ICON_LIST)
3251 return column_titles ? column_bg[0]->get_h() : 0;
3256 void BC_ListBox::reset_cursor(int new_cursor)
3260 if(gui->get_cursor() != new_cursor)
3262 gui->set_cursor(new_cursor, 0, 0);
3266 if(get_cursor() != new_cursor)
3268 set_cursor(new_cursor, 0, 0);
3272 int BC_ListBox::test_column_divisions(int cursor_x, int cursor_y, int &new_cursor)
3277 cursor_y < get_title_h() &&
3279 cursor_x < gui->get_w())
3281 for(int i = 1; i < columns; i++)
3283 if(cursor_x >= -xposition + get_column_offset(i) - 5 &&
3284 cursor_x < -xposition + get_column_offset(i) +
3285 get_resources()->listbox_title_hotspot)
3287 highlighted_item = -1;
3288 highlighted_ptr = 0;
3289 highlighted_division = i;
3290 highlighted_title = -1;
3291 list_highlighted = 1;
3292 new_cursor = HSEPARATE_CURSOR;
3297 highlighted_division = -1;
3301 int BC_ListBox::test_column_titles(int cursor_x, int cursor_y)
3306 cursor_y < get_title_h() &&
3308 cursor_x < gui->get_w())
3310 for(int i = 0; i < columns; i++)
3312 if(cursor_x >= -xposition + get_column_offset(i) &&
3313 (cursor_x < -xposition + get_column_offset(i + 1) ||
3316 highlighted_item = -1;
3317 highlighted_ptr = 0;
3318 highlighted_division = -1;
3319 highlighted_title = i;
3320 list_highlighted = 1;
3325 highlighted_title = -1;
3329 int BC_ListBox::test_expanders()
3331 for(int i = 0; i < expanders.total; i++)
3333 if(expanders.values[i]->button_press_event())
3335 current_operation = EXPAND_DN;
3343 int BC_ListBox::cursor_motion_event()
3345 int redraw = 0, result = 0;
3346 int new_cursor = ARROW_CURSOR;
3348 selection_number = -1;
3351 switch(current_operation)
3354 // Button pressed and slid off button
3355 if(!cursor_inside())
3357 current_operation = BUTTON_DOWN_SELECT;
3365 // int new_w = get_cursor_x() +
3367 // get_column_offset(highlighted_division - 1);
3368 int difference = get_cursor_x() + xposition - drag_cursor_x;
3369 int new_w = drag_column_w + difference;
3371 new_cursor = HSEPARATE_CURSOR;
3375 column_width[highlighted_division - 1] = new_w;
3379 default_column_width[highlighted_division - 1] = new_w;
3382 column_width_boundaries();
3384 // Force update of coords
3385 set_autoplacement(data, 0, 1);
3386 column_resize_event();
3390 update_scrollbars(1);
3397 if(test_drag_scroll(get_cursor_x(), get_cursor_y()))
3399 set_repeat(get_resources()->scroll_repeat);
3402 int old_x1 = MIN(rect_x1, rect_x2);
3403 int old_x2 = MAX(rect_x1, rect_x2);
3404 int old_y1 = MIN(rect_y1, rect_y2);
3405 int old_y2 = MAX(rect_y1, rect_y2);
3407 int new_rect_x2 = get_cursor_x();
3408 int new_rect_y2 = get_cursor_y();
3410 int x1 = MIN(rect_x1, new_rect_x2);
3411 int x2 = MAX(rect_x1, new_rect_x2);
3412 int y1 = MIN(rect_y1, new_rect_y2);
3413 int y2 = MAX(rect_y1, new_rect_y2);
3415 // Adjust rectangle coverage
3423 redraw = select_rectangle(data,
3433 //printf("BC_ListBox::cursor_motion_event %d\n", __LINE__);
3438 rect_x2 = get_cursor_x();
3439 rect_y2 = get_cursor_y();
3444 update_scrollbars(1);
3445 selection_changed();
3446 //printf("BC_ListBox::cursor_motion_event %d\n", __LINE__);
3454 //printf("BC_ListBox::cursor_motion_event %d\n", __LINE__);
3464 int old_highlighted_item = highlighted_item;
3466 if(test_drag_scroll(get_cursor_x(),
3469 set_repeat(get_resources()->scroll_repeat);
3473 highlighted_item = selection_number = get_cursor_item(data,
3479 // Deselect all items and select just the one we're over
3480 if(selection_number >= 0 &&
3484 selection_mode == LISTBOX_SINGLE))
3486 redraw = update_selection(data, selection_number);
3489 if(selection_mode == LISTBOX_MULTIPLE &&
3490 (shift_down() || ctrl_down()))
3491 // Expand multiple selection
3493 // Expand selected region in text mode centered around initial range
3494 if((display_format == LISTBOX_TEXT ||
3495 display_format == LISTBOX_ICON_LIST) &&
3498 // Deselect everything.
3499 set_all_selected(data, 0);
3501 // Select just the items
3502 redraw = expand_selection(0, selection_number);
3505 // Set the one item we're over to the selection value determined in
3506 // button_press_event.
3514 if(highlighted_item != old_highlighted_item)
3518 update_scrollbars(1);
3519 //printf("BC_ListBox::cursor_motion_event %d %d\n", highlighted_item, old_highlighted_item);
3520 selection_changed();
3525 case BUTTON_DOWN_SELECT:
3526 // Went back into button area
3529 current_operation = BUTTON_DN;
3534 // Went into item area
3537 int cursor_x = 0, cursor_y = 0;
3538 translate_coordinates(top_level->event_win,
3540 top_level->cursor_x,
3541 top_level->cursor_y,
3544 int old_highlighted_item = highlighted_item;
3545 highlighted_item = selection_number = get_cursor_item(data,
3550 if(highlighted_item != old_highlighted_item)
3552 update_selection(data, selection_number);
3554 selection_changed();
3561 int redraw_toggles = 0;
3562 for(int i = 0; i < expanders.total && !result; i++)
3564 result = expanders.values[i]->cursor_motion_event(
3569 // Need to redraw items because of the alpha
3577 int cursor_x = get_cursor_x(), cursor_y = get_cursor_y();
3578 if(gui && top_level->event_win == gui->win)
3580 int old_highlighted_title = highlighted_title;
3581 int old_list_highlighted = list_highlighted;
3582 int old_highlighted_item = highlighted_item;
3583 int redraw_titles = 0;
3584 int redraw_border = 0;
3585 int redraw_items = 0;
3586 int redraw_toggles = 0;
3590 // Test if cursor moved over a title division
3591 test_column_divisions(cursor_x, cursor_y, new_cursor);
3593 // Test if cursor moved over a title
3594 if(highlighted_division < 0)
3596 test_column_titles(cursor_x, cursor_y);
3599 // Test if cursor moved over expander
3600 if(highlighted_division < 0 &&
3601 highlighted_title < 0 &&
3602 (display_format == LISTBOX_TEXT ||
3603 display_format == LISTBOX_ICON_LIST))
3605 for(int i = 0; i < expanders.total; i++)
3607 expanders.values[i]->cursor_motion_event(
3610 //printf("BC_ListBox::cursor_motion_event %d\n", redraw_toggles);
3613 // Test if cursor moved over an item
3614 if(highlighted_division < 0 &&
3615 highlighted_title < 0)
3617 highlighted_item = get_cursor_item(data,
3624 // Clear title highlighting if moved over division
3625 if(old_highlighted_title != highlighted_title)
3630 // Highlight list border
3631 if(old_list_highlighted != list_highlighted)
3636 // Moved out of item area
3637 if(old_highlighted_item != highlighted_item)
3642 //printf("BC_ListBox::cursor_motion_event 1 %d\n", highlighted_item);
3644 // Change cursor to title division adjustment
3645 reset_cursor(new_cursor);
3672 if(!result && list_highlighted)
3674 list_highlighted = 0;
3675 highlighted_item = -1;
3676 highlighted_ptr = 0;
3677 highlighted_title = -1;
3678 highlighted_division = -1;
3690 int BC_ListBox::drag_start_event()
3692 switch(current_operation)
3696 gui->is_event_win() &&
3699 BC_ListBoxItem *item_return = 0;
3700 selection_number = get_cursor_item(data,
3701 top_level->cursor_x,
3702 top_level->cursor_y,
3705 if(selection_number >= 0)
3708 if (item_return->icon_vframe)
3710 drag_popup = new BC_DragWindow(this,
3711 item_return->icon_vframe /*,
3712 get_abs_cursor_x(0) - item_return->icon_vframe->get_w() / 2,
3713 get_abs_cursor_y(0) - item_return->icon_vframe->get_h() / 2 */);
3716 // this probably works not!
3717 if (item_return->icon)
3719 drag_popup = new BC_DragWindow(this,
3720 item_return->icon /*,
3721 get_abs_cursor_x(0) - item_return->icon->get_w() / 2,
3722 get_abs_cursor_y(0) - item_return->icon->get_h() / 2 */);
3726 drag_popup = new BC_DragWindow(this,
3727 drag_icon_vframe /*,
3728 get_abs_cursor_x(0) - drag_icon_vframe->get_w() / 2,
3729 get_abs_cursor_y(0) - drag_icon_vframe->get_h() / 2 */);
3732 current_operation = DRAG_ITEM;
3739 if(gui && gui->is_event_win() && allow_drag_column)
3741 drag_popup = new BC_DragWindow(this,
3742 drag_column_icon_vframe /*,
3743 get_abs_cursor_x(0) - drag_column_icon_vframe->get_w() / 2,
3744 get_abs_cursor_y(0) - drag_column_icon_vframe->get_h() / 2 */);
3745 dragged_title = highlighted_title;
3746 current_operation = COLUMN_DRAG;
3756 int BC_ListBox::drag_motion_event()
3758 //printf("BC_ListBox::drag_motion_event 1 %d\n", current_operation);
3759 switch(current_operation)
3764 int new_highlighted_item = -1;
3765 BC_ListBoxItem *new_highlighted_ptr = 0;
3766 new_highlighted_item = get_cursor_item(data,
3767 top_level->cursor_x, top_level->cursor_y,
3768 &new_highlighted_ptr);
3770 if(new_highlighted_item != highlighted_item)
3775 // Always update highlighted value for drag_stop
3776 highlighted_item = new_highlighted_item;
3777 highlighted_ptr = new_highlighted_ptr;
3778 //printf("BC_ListBox::drag_motion_event 1 %p\n", highlighted_ptr);
3783 update_scrollbars(1);
3786 return drag_popup->cursor_motion_event();
3792 int old_highlighted_title = highlighted_title;
3793 test_column_titles(get_cursor_x(), get_cursor_y());
3794 if(old_highlighted_title != highlighted_title)
3798 return drag_popup->cursor_motion_event();
3805 int BC_ListBox::drag_stop_event()
3807 switch(current_operation)
3810 // Inside window boundary
3811 if(top_level->cursor_x > 0 &&
3812 top_level->cursor_x < gui->get_w() - drag_popup->get_w() / 2 &&
3813 top_level->cursor_y > 0 &&
3814 top_level->cursor_y < gui->get_h() - drag_popup->get_h() / 2)
3819 if(display_format == LISTBOX_ICONS)
3821 reposition_item(data,
3823 top_level->cursor_x +
3824 drag_popup->get_offset_x() -
3828 top_level->cursor_y +
3829 drag_popup->get_offset_y() -
3839 int destination = highlighted_item = item_to_index(data,
3841 //printf("BC_ListBox::drag_stop_event 1 %p %d\n", highlighted_ptr, destination);
3843 // Move selected items from data to temporary
3844 ArrayList<BC_ListBoxItem*> *src_items =
3845 new ArrayList<BC_ListBoxItem*>[columns];
3847 move_selection(src_items, data);
3849 // Insert items from temporary to data
3855 delete [] src_items;
3856 set_autoplacement(data, 0, 1);
3863 drag_popup->drag_failure_event();
3868 current_operation = NO_OPERATION;
3874 if(dragged_title != highlighted_title)
3876 if(highlighted_title >= 0)
3878 if(!move_column_event()) draw_titles(1);
3881 drag_popup->drag_failure_event();
3883 current_operation = NO_OPERATION;
3893 BC_DragWindow* BC_ListBox::get_drag_popup()
3898 int BC_ListBox::translation_event()
3902 int new_x = gui->get_x() +
3903 (top_level->last_translate_x - top_level->prev_x -
3904 BC_DisplayInfo::get_left_border());
3905 int new_y = gui->get_y() +
3906 (top_level->last_translate_y - top_level->prev_y -
3907 BC_DisplayInfo::get_top_border());
3909 gui->reposition_window(new_x, new_y);
3915 int BC_ListBox::reposition_window(int x, int y, int w, int h, int flush)
3919 if(w != -1) popup_w = w;
3920 if(h != -1) popup_h = h;
3921 //printf("BC_ListBox::reposition_window %d %d\n", popup_w, popup_h);
3926 xscrollbar->reposition_window(get_xscroll_x(),
3928 get_xscroll_width());
3930 yscrollbar->reposition_window(get_yscroll_x(),
3932 get_yscroll_height());
3937 BC_WindowBase::reposition_window(x, y, w, h);
3943 int BC_ListBox::deactivate()
3946 // printf("BC_ListBox::deactivate %d this=%p gui=%p active=%d\n",
3956 //printf("BC_ListBox::deactivate %d this=%p gui=%p\n", __LINE__, this, gui);
3965 highlighted_item = -1;
3966 highlighted_ptr = 0;
3971 //printf("BC_ListBox::deactivate %d this=%p\n", __LINE__, this);
3973 top_level->active_subwindow = 0;
3979 int BC_ListBox::activate(int take_focus)
3981 if( active ) return 0;
3984 set_active_subwindow(this);
3985 button_releases = 0;
3986 if( !is_popup || gui ) return 0;
3987 int wx = get_x(), wy = get_y() + get_h();
3988 if( justify == LISTBOX_RIGHT ) wx += get_w() - popup_w;
3991 XTranslateCoordinates(top_level->display,
3992 parent_window->win, top_level->rootwin,
3993 wx, wy, &abs_x, &abs_y, &xwin);
3996 return activate(abs_x, abs_y);
3999 int BC_ListBox::activate(int x, int y, int w, int h)
4001 if( !is_popup || gui ) return 0;
4003 if(w != -1) popup_w = w;
4004 if(h != -1) popup_h = h;
4006 if( y + popup_h > top_level->get_root_h(0) )
4007 y -= get_h() + popup_h;
4008 add_subwindow(gui = new BC_Popup(this,
4009 x, y, popup_w, popup_h, -1, 0, 0));
4011 gui->show_window(1);
4015 int BC_ListBox::is_active()
4020 int BC_ListBox::keypress_event()
4022 if(!active) return 0;
4024 //printf("BC_ListBox::keypress_event %d\n", __LINE__);
4026 int result = 0, redraw = 0;
4027 int view_items = last_in_view - first_in_view + 1;
4028 if( view_items <= 0 ) view_items = view_h / get_text_height(MEDIUMFONT);
4029 int new_item = -1, new_selection = -1;
4031 switch(top_level->get_keypress())
4035 top_level->deactivate();
4037 // If user is manipulating popup with keyboard, don't pass on event.
4040 //printf("BC_ListBox::keypress_event %d %p\n", __LINE__, get_selection(0, 0));
4041 if(top_level->get_keypress() == RETURN)
4043 //printf("BC_ListBox::keypress_event %d %p\n", __LINE__, get_selection(0, 0));
4051 new_selection = new_item = select_previous(0);
4053 //printf("BC_ListBox::keypress_event 1 %d\n", new_item);
4056 center_selection(new_item);
4064 new_selection = new_item = select_next(0);
4068 center_selection(new_item);
4076 new_selection = new_item = select_previous(view_items - 1);
4080 center_selection(new_item);
4088 new_selection = new_item = select_next(view_items - 1);
4092 center_selection(new_item);
4120 int query_len = strlen(query);
4121 if( query_len < (int)sizeof(query)-1 &&
4122 top_level->get_keypress() > 30 &&
4123 top_level->get_keypress() < 127)
4125 query[query_len++] = top_level->get_keypress();
4126 query[query_len] = 0;
4127 new_selection = query_list();
4130 if(top_level->get_keypress() == BACKSPACE)
4132 if(query_len > 0) query[--query_len] = 0;
4133 new_selection = query_list();
4137 show_tooltip(query);
4151 update_scrollbars(1);
4154 //printf("BC_ListBox::keypress_event %d new_selection=%d\n", __LINE__, new_selection);
4155 if(new_selection >= 0 && !is_suggestions)
4157 //printf("BC_ListBox::keypress_event %d\n", __LINE__);
4158 selection_changed();
4159 //printf("BC_ListBox::keypress_event %d\n", __LINE__);
4166 BC_Pixmap* BC_ListBox::get_bg_surface()
4172 void BC_ListBox::draw_background()
4174 if( !bg_draw ) return;
4176 // White background pixmap
4177 set_color(top_level->get_resources()->listbox_inactive);
4178 draw_box(0, 0, bg_surface->get_w(), bg_surface->get_h(), bg_surface);
4180 // Optional heroine pixmap
4182 bg_surface->draw_pixmap(bg_pixmap,
4183 bg_surface->get_w() - top_level->get_resources()->listbox_bg->get_w(),
4187 void BC_ListBox::clear_listbox(int x, int y, int w, int h)
4189 gui->draw_pixmap(bg_surface, x, y, w, h, x, y - title_h);
4192 void BC_ListBox::update_format(int display_format, int redraw)
4194 this->display_format = display_format;
4195 if( redraw && gui ) draw_items(1, 1);
4198 int BC_ListBox::get_format()
4200 return display_format;
4205 int BC_ListBox::draw_items(int flush, int draw_bg)
4209 BC_Resources *resources = get_resources();
4211 //dump(data, columns);
4213 // Calculate items width
4214 calculate_item_coords();
4217 // Create and destroy scrollbars as needed
4222 if( bg_draw ) this->bg_draw = 1;
4228 if(display_format == LISTBOX_ICONS)
4230 clear_listbox(2, 2 + title_h, view_w, view_h);
4232 set_font(MEDIUMFONT);
4233 for(int i = 0; i < data[master_column].size(); i++)
4235 BC_ListBoxItem *item = data[master_column].get(i);
4236 if(get_item_x(item) >= -get_item_w(item) &&
4237 get_item_x(item) < view_w &&
4238 get_item_y(item) >= -get_item_h(item) + title_h &&
4239 get_item_y(item) < view_h + title_h)
4241 item->set_in_view(1);
4242 if( first_in_view < 0 ) first_in_view = i;
4244 int item_color = get_item_highlight(data, 0, i);
4245 int icon_x, icon_y, icon_w, icon_h;
4246 int text_x, text_y, text_w, text_h;
4249 get_icon_mask(item, icon_x, icon_y, icon_w, icon_h);
4250 get_text_mask(item, text_x, text_y, text_w, text_h);
4253 if(item_color != resources->listbox_inactive)
4255 gui->set_color(BLACK);
4256 gui->draw_rectangle(icon_x, icon_y, icon_w, icon_h);
4257 gui->set_color(item_color);
4258 gui->draw_box(icon_x + 1, icon_y + 1, icon_w - 2, icon_h - 2);
4259 gui->set_color(BLACK);
4260 gui->draw_rectangle(text_x, text_y, text_w, text_h);
4261 gui->set_color(item_color);
4262 gui->draw_box(text_x + 1, text_y + 1, text_w - 2, text_h - 2);
4264 if(icon_position == ICON_LEFT)
4265 gui->draw_box(text_x - 1, text_y + 1, 2, text_h - 2);
4267 if(icon_position == ICON_TOP)
4268 gui->draw_line(text_x + 1, text_y, text_x + icon_w - 2, text_y);
4269 if(text_x + text_w < icon_x + icon_w)
4271 gui->set_color(BLACK);
4272 gui->draw_line(text_x + text_w,
4280 gui->set_color(get_item_color(data, 0, i));
4282 gui->pixmap->draw_pixmap(item->icon,
4283 icon_x + ICON_MARGIN,
4284 icon_y + ICON_MARGIN);
4287 gui->draw_text(text_x + ICON_MARGIN,
4288 text_y + ICON_MARGIN + get_baseline(item),
4292 item->set_in_view(0);
4298 // Draw one column at a time so text overruns don't go into the next column
4299 // clear column backgrounds
4300 int current_toggle = 0;
4301 for(int j = 0; j < columns; j++)
4303 clear_listbox(LISTBOX_BORDER + get_column_offset(j) - xposition,
4304 LISTBOX_BORDER + title_h,
4305 get_column_width(j, 1),
4307 // Draw rows in the column recursively
4308 draw_text_recursive(data, j, 0, ¤t_toggle);
4311 // Delete excess expanders
4312 while(expanders.total > current_toggle)
4314 expanders.remove_object();
4318 // draw user images if available
4320 // Draw titles on top of rows for superposition effect
4323 // Clear garbage from bottom right corner
4324 if(xscrollbar && yscrollbar && is_popup)
4326 gui->draw_top_background(parent_window,
4327 popup_w - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w(),
4328 popup_h - get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h(),
4329 get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w(),
4330 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h());
4337 if(current_operation == SELECT_RECT)
4347 void BC_ListBox::draw_text_recursive(ArrayList<BC_ListBoxItem*> *data,
4350 int *current_toggle)
4355 BC_Resources *resources = get_resources();
4357 set_font(MEDIUMFONT);
4360 // Search for a branch and make room for toggle if there is one
4363 for(int i = 0; i < data[column].size(); i++)
4365 if(data[column].get(i)->get_sublist())
4367 subindent = BC_WindowBase::get_resources()->listbox_expand[0]->get_w();
4373 row_height = row_ascent = row_descent = 0;
4374 for(int i = 0; i < data[column].total; i++)
4376 BC_ListBoxItem *item = data[column].values[i];
4377 int ht = get_text_h(item);
4378 if( ht > row_height ) row_height = ht;
4379 int bl = get_baseline(item);
4380 if( bl > row_ascent ) row_ascent = bl;
4382 if( dt > row_descent ) row_ascent = bl;
4385 for(int i = 0; i < data[column].size(); i++)
4388 BC_ListBoxItem *item = data[column].values[i];
4389 BC_ListBoxItem *first_item = data[master_column].values[i];
4391 if(get_item_y(item) >= -get_item_h(item) + title_h &&
4392 get_item_y(item) < view_h + title_h)
4394 int row_color = get_item_highlight(data, 0, i);
4395 int x, y, w, h, column_width;
4397 get_text_mask(item, x, y, w, h);
4398 column_width = get_column_width(column, 1);
4399 if(x + column_width > view_w + LISTBOX_BORDER * 2)
4400 column_width = view_w + LISTBOX_BORDER * 2 - x;
4402 if(row_color != resources->listbox_inactive)
4404 gui->set_color(row_color);
4405 gui->draw_box(x, y, column_width, h);
4406 gui->set_color(BLACK);
4407 int yy = y, xx = x + column_width-1;
4408 gui->draw_line(x, yy, xx, yy);
4409 yy = y + row_height;
4410 gui->draw_line(x, yy, xx, yy);
4413 gui->set_color(get_item_color(data, column, i));
4416 if(column == 0 && display_format == LISTBOX_ICON_LIST)
4420 gui->pixmap->draw_pixmap(item->icon,
4423 x += item->icon->get_w() + ICON_MARGIN;
4428 // Indent only applies to first column
4430 x + LISTBOX_BORDER + LISTBOX_MARGIN +
4431 (column == 0 ? indent + subindent : 0),
4432 y + get_baseline(item), item->text);
4433 item->set_in_view(1);
4435 if( first_in_view < 0 ) first_in_view = i;
4441 item->get_sublist() &&
4442 item->get_columns())
4444 // Create new expander
4445 if(*current_toggle >= expanders.total)
4447 BC_ListBoxToggle *toggle =
4448 new BC_ListBoxToggle(this,
4450 x + LISTBOX_BORDER + LISTBOX_MARGIN + indent,
4453 expanders.append(toggle);
4456 // Reposition existing expander
4458 BC_ListBoxToggle *toggle = expanders.values[*current_toggle];
4459 //printf("BC_ListBox::draw_text_recursive 1 %d\n", *current_toggle);
4460 toggle->update(item,
4461 x + LISTBOX_BORDER + LISTBOX_MARGIN + indent,
4465 (*current_toggle)++;
4472 item->set_in_view(0);
4474 // Descend into sublist
4475 if(first_item->get_expand())
4477 draw_text_recursive(first_item->get_sublist(),
4479 indent + LISTBOX_INDENT,
4488 int BC_ListBox::draw_border(int flash)
4490 BC_Resources *resources = top_level->get_resources();
4491 gui->draw_3d_border(0,
4493 view_w + LISTBOX_BORDER * 2,
4494 view_h + title_h + LISTBOX_BORDER * 2,
4495 resources->listbox_border1,
4497 resources->listbox_border2_hi :
4498 resources->listbox_border2,
4500 resources->listbox_border3_hi :
4501 resources->listbox_border3,
4502 resources->listbox_border4);
4512 void BC_ListBox::draw_title(int number)
4514 // Column title background
4515 int image_number = 0;
4516 if(number == highlighted_title)
4519 if(current_operation == COLUMN_DN)
4523 int column_offset = get_column_offset(number) - xposition + LISTBOX_BORDER;
4524 int column_width = get_column_width(number, 1);
4525 gui->draw_3segmenth(get_column_offset(number) - xposition + LISTBOX_BORDER,
4527 get_column_width(number, 1) + get_resources()->listbox_title_overlap,
4528 column_bg[image_number]);
4530 // Column title sort order
4531 if(number == sort_column)
4534 if(sort_order == SORT_ASCENDING)
4535 src = column_sort_dn;
4537 src = column_sort_up;
4539 int x = column_offset +
4542 if(x > items_w) x = items_w;
4543 x -= 5 + src->get_w();
4544 gui->draw_pixmap(src,
4546 title_h / 2 - src->get_h() / 2 + LISTBOX_BORDER);
4550 int x = -xposition +
4551 get_column_offset(number) +
4554 x += get_resources()->listbox_title_margin;
4556 gui->set_color(get_resources()->listbox_title_color);
4558 LISTBOX_MARGIN + LISTBOX_BORDER + get_text_ascent(MEDIUMFONT),
4559 _(column_titles[number]));
4562 int BC_ListBox::draw_titles(int flash)
4565 (display_format == LISTBOX_TEXT ||
4566 display_format == LISTBOX_ICON_LIST))
4568 //printf("BC_ListBox::draw_titles 1 %d\n", highlighted_title);
4569 for(int i = 0; i < columns; i++)
4571 if(i != highlighted_title)
4575 if(highlighted_title >= 0) draw_title(highlighted_title);
4586 void BC_ListBox::draw_toggles(int flash)
4588 for(int i = 0; i < expanders.total; i++)
4589 expanders.values[i]->draw(0);
4591 //printf("BC_ListBox::draw_toggles 1 %d\n", flash);
4592 if(flash && expanders.total)
4599 int BC_ListBox::draw_rectangle(int flash)
4601 int x1 = MIN(rect_x1, rect_x2);
4602 int x2 = MAX(rect_x1, rect_x2);
4603 int y1 = MIN(rect_y1, rect_y2);
4604 int y2 = MAX(rect_y1, rect_y2);
4606 if(x1 == x2 || y1 == y2) return 0;
4609 gui->set_color(WHITE);
4610 gui->draw_rectangle(x1, y1, x2 - x1, y2 - y1);
4621 void BC_ListBox::dump(ArrayList<BC_ListBoxItem*> *data,
4628 printf("BC_ListBox::dump 1\n");
4631 for(int i = 0; i < data[master_column].total; i++)
4633 for(int k = 0; k < indent; k++)
4635 for(int j = 0; j < columns; j++)
4637 BC_ListBoxItem *item = data[j].values[i];
4638 printf("%d,%d,%d=%s ",
4641 item->autoplace_text,
4646 if(data[master_column].values[i]->get_sublist())
4648 dump(data[master_column].values[i]->get_sublist(),
4649 data[master_column].values[i]->get_columns(),