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 "bcdragwindow.h"
22 #include "bclistbox.h"
23 #include "bclistboxitem.h"
25 #include "bcresources.h"
26 #include "bcsignals.h"
38 // ====================================================== scrollbars
41 BC_ListBoxYScroll::BC_ListBoxYScroll(BC_ListBox *listbox,
45 : BC_ScrollBar(listbox->get_yscroll_x(),
46 listbox->get_yscroll_y(),
48 listbox->get_yscroll_height(),
53 this->listbox = listbox;
56 BC_ListBoxYScroll::~BC_ListBoxYScroll()
60 int BC_ListBoxYScroll::handle_event()
62 listbox->set_yposition(get_value());
72 BC_ListBoxXScroll::BC_ListBoxXScroll(BC_ListBox *listbox,
76 : BC_ScrollBar(listbox->get_xscroll_x(),
77 listbox->get_xscroll_y(),
79 listbox->get_xscroll_width(),
84 this->listbox = listbox;
87 BC_ListBoxXScroll::~BC_ListBoxXScroll()
91 int BC_ListBoxXScroll::handle_event()
93 listbox->set_xposition(get_value());
104 BC_ListBoxToggle::BC_ListBoxToggle(BC_ListBox *listbox,
105 BC_ListBoxItem *item,
109 this->listbox = listbox;
113 this->value = item->get_expand();
115 state = BC_Toggle::TOGGLE_CHECKED;
117 state = BC_Toggle::TOGGLE_UP;
120 void BC_ListBoxToggle::update(BC_ListBoxItem *item,
125 this->value = item->get_expand();
135 state = TOGGLE_CHECKED;
140 state = TOGGLE_CHECKEDHI;
151 case TOGGLE_CHECKEDHI:
156 case TOGGLE_DOWN_EXIT:
164 int BC_ListBoxToggle::cursor_motion_event(int *redraw_toggles)
166 int w = listbox->toggle_images[0]->get_w();
167 int h = listbox->toggle_images[0]->get_h();
168 int cursor_inside = listbox->get_cursor_x() >= x &&
169 listbox->get_cursor_x() < x + w &&
170 listbox->get_cursor_y() >= y &&
171 listbox->get_cursor_y() < y + h;
176 case BC_ListBoxToggle::TOGGLE_UPHI:
179 state = BC_ListBoxToggle::TOGGLE_UP;
184 case BC_ListBoxToggle::TOGGLE_CHECKEDHI:
187 state = BC_ListBoxToggle::TOGGLE_CHECKED;
192 case BC_ListBoxToggle::TOGGLE_DOWN:
195 state = BC_ListBoxToggle::TOGGLE_DOWN_EXIT;
201 case BC_ListBoxToggle::TOGGLE_DOWN_EXIT:
204 state = BC_ListBoxToggle::TOGGLE_DOWN;
214 state = BC_ListBoxToggle::TOGGLE_CHECKEDHI;
216 state = BC_ListBoxToggle::TOGGLE_UPHI;
224 int BC_ListBoxToggle::cursor_leave_event(int *redraw_toggles)
227 state = BC_ListBoxToggle::TOGGLE_CHECKED;
229 state = BC_ListBoxToggle::TOGGLE_UP;
233 int BC_ListBoxToggle::button_press_event()
235 int w = listbox->toggle_images[0]->get_w();
236 int h = listbox->toggle_images[0]->get_h();
238 if(listbox->gui->get_cursor_x() >= x &&
239 listbox->gui->get_cursor_x() < x + w &&
240 listbox->gui->get_cursor_y() >= y &&
241 listbox->gui->get_cursor_y() < y + h)
243 state = BC_ListBoxToggle::TOGGLE_DOWN;
249 int BC_ListBoxToggle::button_release_event(int *redraw_toggles)
255 case BC_ListBoxToggle::TOGGLE_DOWN:
258 state = BC_ListBoxToggle::TOGGLE_CHECKEDHI;
260 state = BC_ListBoxToggle::TOGGLE_UPHI;
261 listbox->expand_item(item, value);
265 case BC_ListBoxToggle::TOGGLE_DOWN_EXIT:
267 state = BC_ListBoxToggle::TOGGLE_CHECKED;
269 state = BC_ListBoxToggle::TOGGLE_UP;
277 void BC_ListBoxToggle::draw(int flash)
281 int image_number = 0;
282 int w = listbox->toggle_images[0]->get_w();
283 int h = listbox->toggle_images[0]->get_h();
287 case BC_ListBoxToggle::TOGGLE_UP: image_number = 0; break;
288 case BC_ListBoxToggle::TOGGLE_UPHI: image_number = 1; break;
289 case BC_ListBoxToggle::TOGGLE_CHECKED: image_number = 2; break;
290 case BC_ListBoxToggle::TOGGLE_DOWN: image_number = 3; break;
291 case BC_ListBoxToggle::TOGGLE_CHECKEDHI: image_number = 4; break;
292 case BC_ListBoxToggle::TOGGLE_DOWN_EXIT:
300 //printf("BC_ListBoxToggle::draw 1 %d\n", state);
301 listbox->gui->draw_pixmap(listbox->toggle_images[image_number],
308 listbox->gui->flash(x, y, w, h);
309 listbox->gui->flush();
327 // ====================================================== box
329 BC_ListBox::BC_ListBox(int x,
334 ArrayList<BC_ListBoxItem*> *data,
335 const char **column_titles,
343 : BC_SubWindow(x, y, w, h, -1)
345 justify = LISTBOX_RIGHT;
347 highlighted_item = -1;
348 highlighted_title = -1;
349 highlighted_division = -1;
353 current_cursor = ARROW_CURSOR;
366 selection_number1 = -1;
367 selection_number2 = -1;
370 row_height = row_ascent = row_descent = 0;
373 current_operation = NO_OPERATION;
374 button_highlighted = 0;
375 list_highlighted = 0;
378 allow_drag_scroll = 1;
384 allow_drag_column = 0;
391 for(int i = 0; i < 3; i++)
393 button_images[i] = 0;
396 for(int i = 0; i < 5; i++)
397 toggle_images[i] = 0;
402 //printf("BC_ListBox::BC_ListBox 1\n");
404 this->columns = columns;
405 this->yposition = yposition;
406 this->is_popup = is_popup;
407 this->use_button = 1;
408 this->display_format = display_format;
409 this->selection_mode = selection_mode;
410 this->icon_position = icon_position;
411 this->allow_drag = allow_drag;
412 this->column_titles = 0;
413 this->column_width = 0;
414 this->first_in_view = -1;
415 this->last_in_view = 0;
416 //printf("BC_ListBox::BC_ListBox 1\n");
418 if((!column_titles && column_width) ||
419 (column_titles && !column_width))
421 printf("BC_ListBox::BC_ListBox either column_titles or column_widths == NULL but not both.\n");
423 //printf("BC_ListBox::BC_ListBox 2 %p %p\n", column_titles, column_width);
425 set_columns(column_titles,
429 //printf("BC_ListBox::BC_ListBox 3\n");
431 drag_icon_vframe = 0;
432 drag_column_icon_vframe = 0;
436 // reset the search engine
437 //printf("BC_ListBox::BC_ListBox 4\n");
439 //printf("BC_ListBox::BC_ListBox 5\n");
442 BC_ListBox::~BC_ListBox()
444 expanders.remove_all_objects();
445 if(bg_surface) delete bg_surface;
446 if(bg_pixmap) delete bg_pixmap;
447 if(xscrollbar) delete xscrollbar;
448 if(yscrollbar) delete yscrollbar;
449 for(int i = 0; i < 3; i++)
451 if(button_images[i]) delete button_images[i];
452 if(column_bg[i]) delete column_bg[i];
454 for(int i = 0; i < 5; i++)
455 if(toggle_images[i]) delete toggle_images[i];
456 if(column_sort_up) delete column_sort_up;
457 if(column_sort_dn) delete column_sort_dn;
460 if(drag_popup) delete drag_popup;
463 int BC_ListBox::enable()
470 int BC_ListBox::disable()
477 void BC_ListBox::reset_query()
479 query[0] = 0; // reset query
482 int BC_ListBox::evaluate_query(char *string)
484 for(int i = 0; i < data[search_column].size(); i++)
486 if(strcmp(string, data[search_column].get(i)->text) <= 0 &&
487 data[search_column].get(i)->searchable)
496 int BC_ListBox::query_list()
498 if(query[0] == 0) return 0;
502 int selection_changed = 0;
503 int prev_selection = -1;
504 result = evaluate_query(query);
505 if(result >= 0) done = 1;
510 for(int i = 0; i < data[0].total; i++)
512 for(int j = 0; j < columns; j++)
514 if(data[j].values[i]->selected) prev_selection = i;
515 data[j].values[i]->selected = 0;
520 if(prev_selection != result)
521 selection_changed = 1;
522 for(int j = 0; j < columns; j++)
524 data[j].values[result]->selected = 1;
526 center_selection(result);
529 return selection_changed;
532 void BC_ListBox::init_column_width()
534 if(!column_width && data)
537 for(int i = 0; i < data[0].total; i++)
539 wd = get_text_w(data[0].values[i]);
540 if( wd > widest ) widest = wd;
542 default_column_width[0] = widest + 2 * LISTBOX_MARGIN;
546 int BC_ListBox::initialize()
552 for( volatile int i = 0; i < 4; ++i ) // volatile due to cplr bug
554 button_images[i] = new BC_Pixmap(parent_window,
555 BC_WindowBase::get_resources()->listbox_button[i],
558 w = button_images[0]->get_w();
559 h = button_images[0]->get_h();
563 current_operation = NO_OPERATION;
569 current_operation = NO_OPERATION;
572 for(int i = 0; i < 3; i++)
574 column_bg[i] = new BC_Pixmap(parent_window,
575 get_resources()->listbox_column[i],
578 for(int i = 0; i < 5; i++)
580 toggle_images[i] = new BC_Pixmap(parent_window,
581 get_resources()->listbox_expand[i],
585 column_sort_up = new BC_Pixmap(parent_window,
586 BC_WindowBase::get_resources()->listbox_up,
588 column_sort_dn = new BC_Pixmap(parent_window,
589 BC_WindowBase::get_resources()->listbox_dn,
592 //printf("BC_ListBox::initialize 10\n");
593 drag_icon_vframe = get_resources()->type_to_icon[ICON_UNKNOWN];
594 drag_column_icon_vframe = get_resources()->type_to_icon[ICON_COLUMN];
595 // = new BC_Pixmap(parent_window,
596 // get_resources()->type_to_icon[ICON_UNKNOWN],
598 // drag_column_icon = new BC_Pixmap(parent_window,
599 // get_resources()->type_to_icon[ICON_COLUMN],
601 BC_SubWindow::initialize();
605 if(top_level->get_resources()->listbox_bg)
606 bg_pixmap = new BC_Pixmap(this,
607 get_resources()->listbox_bg,
613 if(!use_button && is_popup)
622 void BC_ListBox::deactivate_selection()
624 current_operation = NO_OPERATION;
627 int BC_ListBox::draw_button(int flush)
629 // Draw the button for a popup listbox
630 if(use_button && is_popup)
632 int image_number = 0;
634 draw_top_background(parent_window, 0, 0, w, h);
636 if(button_highlighted)
638 if(current_operation == BUTTON_DN)
644 pixmap->draw_pixmap(button_images[image_number],
656 int BC_ListBox::calculate_item_coords()
664 // Change the display_format to get the right item dimensions for both
666 temp_display_format = display_format;
669 // Scan the first column for lowest y coord of all text
670 // and lowest right x and y coord for all icons which aren't auto placable
671 calculate_last_coords_recursive(data,
678 // Reset last column width. It's recalculated based on text width.
680 calculate_item_coords_recursive(data,
689 display_format = temp_display_format;
694 void BC_ListBox::calculate_last_coords_recursive(
695 ArrayList<BC_ListBoxItem*> *data,
702 for(int i = 0; i < data[0].size(); i++)
704 int current_text_y = 0;
705 int current_icon_x = 0;
706 int current_icon_y = 0;
707 BC_ListBoxItem *item = data[0].get(i);
710 if(!item->autoplace_text)
712 // Lowest text coordinate
713 display_format = LISTBOX_TEXT;
714 current_text_y = item->text_y + get_text_h(item);
715 if(current_text_y > *next_text_y)
716 *next_text_y = current_text_y;
718 // Add sublist depth if it is expanded
719 if(item->get_sublist() &&
720 item->get_columns() &&
723 calculate_last_coords_recursive(item->get_sublist(),
732 // Get next_icon coordinate
735 BC_ListBoxItem *item = data[master_column].get(i);
736 if(!item->autoplace_icon)
738 display_format = LISTBOX_ICONS;
739 // Lowest right icon coordinate.
740 current_icon_x = item->icon_x;
741 if(current_icon_x > *icon_x) *icon_x = current_icon_x;
742 if(current_icon_x + get_item_w(item) > *next_icon_x)
743 *next_icon_x = current_icon_x + get_item_w(item);
745 current_icon_y = item->icon_y + get_item_h(item);
746 if(current_icon_y > *next_icon_y)
747 *next_icon_y = current_icon_y;
754 void BC_ListBox::calculate_item_coords_recursive(
755 ArrayList<BC_ListBoxItem*> *data,
762 // get maximum height of an icon
763 row_height = get_text_height(MEDIUMFONT);
764 if(temp_display_format == LISTBOX_ICON_LIST)
766 for(int i = 0; i < data[0].size(); i++)
768 if(data[0].get(i)->icon)
770 if(data[0].get(i)->icon->get_h() > row_height)
771 row_height = data[0].get(i)->icon->get_h();
777 // Set up items which need autoplacement.
778 // Should fill icons down and then across
779 for(int i = 0; i < data[0].size(); i++)
781 // Don't increase y unless the row requires autoplacing.
782 int total_autoplaced_columns = 0;
784 // Set up icons in first column
787 BC_ListBoxItem *item = data[master_column].get(i);
788 if(item->autoplace_icon)
790 // 1 column only if icons are used
791 display_format = LISTBOX_ICONS;
794 if(*next_icon_y + get_item_h(item) >= get_h() &&
797 *icon_x = *next_icon_x;
801 if(*icon_x + get_item_w(item) > *next_icon_x)
802 *next_icon_x = *icon_x + get_item_w(item);
805 item->set_icon_x(*icon_x);
806 item->set_icon_y(*next_icon_y);
808 *next_icon_y += get_item_h(item);
816 row_ascent = row_descent = 0;
817 // row_height still holds icon max height
818 for(int j = 0; j < columns; j++)
820 BC_ListBoxItem *item = data[j].get(i);
821 if(item->autoplace_text)
823 display_format = LISTBOX_TEXT;
824 item->set_text_x(next_text_x);
825 item->set_text_y(*next_text_y);
826 int ht = get_text_h(item);
827 if( ht > row_height ) row_height = ht;
828 int bl = get_baseline(item);
829 if( bl > row_ascent ) row_ascent = bl;
831 if( dt > row_descent ) row_ascent = bl;
833 // printf("BC_ListBox::calculate_item_coords_recursive %p %d %d %d %d %s \n",
834 // item->get_sublist(),
835 // item->get_columns(),
836 // item->get_expand(),
839 // item->get_text());
840 // Increment position of next column
843 next_text_x += (column_width ?
845 default_column_width[j]);
848 // Set last column width based on text width
850 int new_w = get_item_w(item);
852 int *previous_w = (column_width ?
854 &default_column_width[j]);
855 if(new_w > *previous_w)
857 //printf("BC_ListBox::calculate_item_coords_recursive 1 %d\n", new_w);
859 total_autoplaced_columns++;
863 // Increase the text vertical position
864 if(total_autoplaced_columns)
866 display_format = LISTBOX_TEXT;
867 *next_text_y += row_height;
871 BC_ListBoxItem *item = data[master_column].values[i];
872 if(item->get_sublist() &&
873 item->get_columns() &&
876 calculate_item_coords_recursive(
887 void BC_ListBox::set_is_suggestions(int value)
889 this->is_suggestions = value;
892 void BC_ListBox::set_use_button(int value)
894 this->use_button = value;
897 void BC_ListBox::set_justify(int value)
899 this->justify = value;
902 void BC_ListBox::set_allow_drag_column(int value)
904 this->allow_drag_column = value;
907 void BC_ListBox::set_process_drag(int value)
909 this->process_drag = value;
912 void BC_ListBox::set_master_column(int value, int redraw)
914 this->master_column = value;
921 void BC_ListBox::set_search_column(int value)
923 this->search_column = value;
926 int BC_ListBox::get_sort_column()
931 void BC_ListBox::set_sort_column(int value, int redraw)
940 int BC_ListBox::get_sort_order()
945 void BC_ListBox::set_sort_order(int value, int redraw)
958 int BC_ListBox::get_display_mode()
960 return display_format;
963 int BC_ListBox::get_yposition()
968 int BC_ListBox::get_xposition()
973 int BC_ListBox::get_highlighted_item()
975 return highlighted_item;
979 int BC_ListBox::get_item_x(BC_ListBoxItem *item)
981 if(display_format == LISTBOX_TEXT)
983 return item->text_x - xposition + 2;
986 if(display_format == LISTBOX_ICON_LIST)
988 return item->text_x - xposition + 2;
992 return item->icon_x - xposition + 2;
996 int BC_ListBox::get_item_y(BC_ListBoxItem *item)
999 if(display_format == LISTBOX_TEXT)
1001 result = item->text_y - yposition + title_h + 2;
1004 if(display_format == LISTBOX_ICON_LIST)
1006 result = item->text_y - yposition + title_h + 2;
1010 result = item->icon_y - yposition + title_h + 2;
1016 int BC_ListBox::get_item_w(BC_ListBoxItem *item)
1018 if(display_format == LISTBOX_ICONS)
1021 get_icon_mask(item, x, y, w, h);
1023 get_text_mask(item, x, y, w, h);
1026 return icon_position == ICON_LEFT ? icon_w + text_w :
1027 icon_w > text_w ? icon_w : text_w;
1029 return get_text_w(item) + 2 * LISTBOX_MARGIN;
1032 int BC_ListBox::get_item_h(BC_ListBoxItem *item)
1034 if(display_format == LISTBOX_ICONS)
1037 get_icon_mask(item, x, y, w, h);
1039 get_text_mask(item, x, y, w, h);
1042 return icon_position != ICON_LEFT ? icon_h + text_h :
1043 icon_h > text_h ? icon_h : text_h;
1045 return get_text_h(item);
1049 int BC_ListBox::get_icon_w(BC_ListBoxItem *item)
1051 return item->get_icon_w();
1054 int BC_ListBox::get_icon_h(BC_ListBoxItem *item)
1056 return item->get_icon_h();
1059 int BC_ListBox::get_text_w(BC_ListBoxItem *item)
1061 int w = item->get_text_w();
1062 if( w < 0 ) item->set_text_w(w = get_text_width(MEDIUMFONT, item->get_text()));
1066 int BC_ListBox::get_text_h(BC_ListBoxItem *item)
1068 int h = item->get_text_h();
1069 if( h < 0 ) item->set_text_h(h = get_text_height(MEDIUMFONT));
1073 int BC_ListBox::get_baseline(BC_ListBoxItem *item)
1075 int b = item->get_baseline();
1076 if( b < 0 ) item->set_baseline(b = get_text_ascent(MEDIUMFONT));
1080 int BC_ListBox::get_items_width()
1084 if(display_format == LISTBOX_ICONS)
1086 for(int i = 0; i < columns; i++)
1088 for(int j = 0; j < data[i].total; j++)
1091 BC_ListBoxItem *item = data[i].values[j];
1094 get_icon_mask(item, x, y, w, h);
1095 if(x1 + w > widest) widest = x1 + w;
1097 if(display_format == LISTBOX_ICONS && icon_position == ICON_LEFT)
1100 get_text_mask(item, x, y, w, h);
1101 if(x1 + w > widest) widest = x1 + w;
1106 if(display_format == LISTBOX_TEXT)
1108 return get_column_offset(columns);
1112 return get_column_offset(columns);
1117 int BC_ListBox::get_items_height(ArrayList<BC_ListBoxItem*> *data,
1134 for(int j = 0; j < (data ? data[master_column].total : 0); j++)
1137 BC_ListBoxItem *item = data[master_column].values[j];
1139 if(display_format == LISTBOX_ICONS)
1141 get_icon_mask(item, x, y, w, h);
1142 if(y + h + yposition > highest) highest = y + h + yposition;
1144 get_text_mask(item, x, y, w, h);
1145 if(y + h + yposition > highest) highest = y + h + yposition;
1149 get_text_mask(item, x, y, w, h);
1153 // Descend into sublist
1154 if(item->get_sublist() &&
1157 get_items_height(item->get_sublist(),
1158 item->get_columns(),
1164 if((display_format == LISTBOX_TEXT ||
1165 display_format == LISTBOX_ICON_LIST) &&
1168 highest = LISTBOX_MARGIN + *result;
1175 int BC_ListBox::set_yposition(int position, int draw_items)
1177 this->yposition = position;
1180 this->draw_items(1);
1185 int BC_ListBox::set_xposition(int position)
1187 this->xposition = position;
1192 void BC_ListBox::expand_item(BC_ListBoxItem *item, int expand)
1196 item->expand = expand;
1197 // Collapse sublists if this is collapsed to make it easier to calculate
1199 if(item->get_sublist())
1200 collapse_recursive(item->get_sublist(), master_column);
1203 // Set everything for autoplacement
1205 set_autoplacement(data, 0, 1);
1211 void BC_ListBox::collapse_recursive(ArrayList<BC_ListBoxItem*> *data,
1214 for(int i = 0; i < data[master_column].total; i++)
1216 BC_ListBoxItem *item = data[master_column].values[i];
1217 if(item->get_sublist() && item->expand)
1220 collapse_recursive(item->get_sublist(), master_column);
1225 void BC_ListBox::set_autoplacement(ArrayList<BC_ListBoxItem*> *data,
1229 for(int i = 0; i < data[0].total; i++)
1231 for(int j = 0; j < columns; j++)
1233 if(do_icons) data[j].values[i]->autoplace_icon = 1;
1234 if(do_text) data[j].values[i]->autoplace_text = 1;
1237 BC_ListBoxItem *item = data[master_column].values[i];
1238 if(item->get_sublist())
1240 set_autoplacement(item->get_sublist(), do_icons, do_text);
1247 int BC_ListBox::get_yscroll_x()
1250 return popup_w - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w();
1254 get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w();
1257 int BC_ListBox::get_yscroll_y()
1265 int BC_ListBox::get_yscroll_height()
1267 return popup_h - (need_xscroll ?
1268 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h() :
1272 int BC_ListBox::get_xscroll_x()
1280 int BC_ListBox::get_xscroll_y()
1284 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h();
1288 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h();
1291 int BC_ListBox::get_xscroll_width()
1293 return popup_w - (need_yscroll ?
1294 get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w() :
1298 int BC_ListBox::get_column_offset(int column)
1304 column_width[--column] :
1305 default_column_width[--column];
1310 void BC_ListBox::column_width_boundaries()
1313 for(int i = 0; i < columns; i++) {
1314 if(column_width[i] < MIN_COLUMN_WIDTH)
1315 column_width[i] = MIN_COLUMN_WIDTH;
1319 for(int i = 0; i < columns; i++) {
1320 if(default_column_width[i] < MIN_COLUMN_WIDTH)
1321 default_column_width[i] = MIN_COLUMN_WIDTH;
1326 int BC_ListBox::get_column_width(int column, int clamp_right)
1328 if(column < columns - 1 || !clamp_right)
1329 return column_width ? column_width[column] : default_column_width[column];
1330 return popup_w + xposition - get_column_offset(column);
1333 int BC_ListBox::get_icon_mask(BC_ListBoxItem *item,
1334 int &x, int &y, int &w, int &h)
1336 if( display_format == LISTBOX_ICONS ) {
1337 x = get_item_x(item);
1338 y = get_item_y(item);
1339 w = get_icon_w(item) + ICON_MARGIN * 2;
1340 h = get_icon_h(item) + ICON_MARGIN * 2;
1347 int BC_ListBox::get_text_mask(BC_ListBoxItem *item,
1348 int &x, int &y, int &w, int &h)
1350 x = get_item_x(item);
1351 y = get_item_y(item);
1353 if(display_format == LISTBOX_ICONS) {
1354 if(icon_position == ICON_LEFT) {
1355 x += get_icon_w(item) + ICON_MARGIN * 2;
1356 y += get_icon_h(item) - get_text_h(item);
1359 y += get_icon_h(item) + ICON_MARGIN;
1362 w = get_text_w(item) + ICON_MARGIN * 2;
1363 h = get_text_h(item) + ICON_MARGIN * 2;
1366 if(display_format == LISTBOX_TEXT) {
1367 w = get_text_w(item) + LISTBOX_MARGIN * 2;
1368 h = get_text_h(item);
1372 w = get_text_width(MEDIUMFONT, item->text) + LISTBOX_MARGIN * 2;
1378 int BC_ListBox::get_item_highlight(ArrayList<BC_ListBoxItem*> *data,
1382 BC_Resources *resources = get_resources();
1383 if(data[column].values[item]->selected)
1384 return resources->listbox_selected;
1385 else if(highlighted_item >= 0 &&
1386 highlighted_ptr == data[master_column].values[item])
1387 return resources->listbox_highlighted;
1388 return resources->listbox_inactive;
1391 int BC_ListBox::get_item_color(ArrayList<BC_ListBoxItem*> *data,
1395 int color = data[column].values[item]->color;
1396 if( color == -1 ) color = get_resources()->listbox_text;
1397 if( get_item_highlight(data, column, item) == color )
1402 int BC_ListBox::get_from_column()
1404 return dragged_title;
1407 int BC_ListBox::get_to_column()
1409 return highlighted_title;
1413 BC_ListBoxItem* BC_ListBox::get_selection(int column,
1414 int selection_number)
1416 return get_selection_recursive(data,
1421 BC_ListBoxItem* BC_ListBox::get_selection_recursive(
1422 ArrayList<BC_ListBoxItem*> *data,
1424 int selection_number)
1428 for(int i = 0; i < data[master_column].total; i++)
1430 BC_ListBoxItem *item = data[master_column].values[i];
1433 //printf("BC_ListBox::get_selection_recursive %d\n", __LINE__);
1435 if(selection_number < 0)
1438 return data[column].values[i];
1442 if(item->get_sublist())
1444 BC_ListBoxItem *result = get_selection_recursive(item->get_sublist(),
1447 if(result) return result;
1455 int BC_ListBox::get_selection_number(int column,
1456 int selection_number)
1458 return get_selection_number_recursive(data,
1463 int BC_ListBox::get_selection_number_recursive(
1464 ArrayList<BC_ListBoxItem*> *data,
1466 int selection_number,
1471 if(!counter) counter = &temp;
1473 for(int i = 0; i < data[master_column].total; i++)
1476 BC_ListBoxItem *item = data[master_column].values[i];
1480 if(selection_number < 0)
1485 if(item->get_sublist())
1487 int result = get_selection_number_recursive(
1488 item->get_sublist(),
1492 if(result >= 0) return result;
1499 int BC_ListBox::set_selection_mode(int mode)
1501 this->selection_mode = mode;
1505 void BC_ListBox::delete_columns()
1509 for(int i = 0; i < columns; i++)
1511 delete [] column_titles[i];
1513 delete [] column_titles;
1516 if(column_width) delete [] column_width;
1522 // Need to copy titles so EDL can change
1523 void BC_ListBox::set_columns(const char **column_titles,
1527 if((!column_titles && column_width) ||
1528 (column_titles && !column_width))
1530 printf("BC_ListBox::set_columns either column_titles or column_width == NULL but not both.\n");
1539 this->column_titles = new char*[columns];
1540 for(int i = 0; i < columns; i++)
1542 this->column_titles[i] = new char[strlen(column_titles[i]) + 1];
1543 strcpy(this->column_titles[i], column_titles[i]);
1549 this->column_width = new int[columns];
1550 for(int i = 0; i < columns; i++)
1552 this->column_width[i] = column_width[i];
1556 this->columns = columns;
1561 int BC_ListBox::update(ArrayList<BC_ListBoxItem*> *data,
1562 const char **column_titles,
1567 int highlighted_number,
1568 int recalc_positions,
1571 set_columns(column_titles,
1577 this->yposition = yposition;
1578 this->xposition = xposition;
1579 this->highlighted_item = highlighted_number;
1580 this->highlighted_ptr = index_to_item(data, highlighted_number, 0);
1582 if(recalc_positions)
1583 set_autoplacement(data, 1, 1);
1585 init_column_width();
1590 update_scrollbars(1);
1596 void BC_ListBox::center_selection()
1598 int selection = get_selection_number(0, 0);
1600 calculate_item_coords();
1601 center_selection(selection);
1607 update_scrollbars(0);
1608 gui->show_window(1);
1612 void BC_ListBox::move_vertical(int pixels)
1616 void BC_ListBox::move_horizontal(int pixels)
1620 int BC_ListBox::select_previous(int skip,
1621 BC_ListBoxItem *selected_item,
1623 ArrayList<BC_ListBoxItem*> *data,
1629 selected_item = get_selection(0, 0);
1641 got_second = &temp3;
1645 // Scan backwards to item pointer. Then count visible items to get
1646 // destination. No wraparound.
1649 for(int i = data[master_column].total - 1; i >= 0; i--)
1651 BC_ListBoxItem *current_item = data[master_column].values[i];
1652 if(current_item->get_sublist() &&
1653 current_item->get_expand())
1655 int result = select_previous(skip,
1658 current_item->get_sublist(),
1670 if((*counter) >= skip)
1672 for(int j = 0; j < columns; j++)
1673 data[j].values[i]->selected = 1;
1675 return item_to_index(this->data, current_item);
1680 if(current_item->selected)
1682 for(int j = 0; j < columns; j++)
1683 data[j].values[i]->selected = 0;
1690 // Hit top of top level without finding a selected item.
1693 // Select first item in top level and quit
1694 BC_ListBoxItem *current_item;
1696 current_item = data[master_column].values[0];
1698 for(int j = 0; j < columns; j++)
1699 data[j].values[0]->selected = 1;
1701 return item_to_index(this->data, current_item);
1703 }while(top_level && data[master_column].total);
1707 int BC_ListBox::select_next(int skip,
1708 BC_ListBoxItem *selected_item,
1710 ArrayList<BC_ListBoxItem*> *data,
1716 selected_item = get_selection(0, 0);
1728 got_second = &temp3;
1732 // Scan forwards to currently selected item pointer.
1733 // Then count visible items to get destination. No wraparound.
1736 for(int i = 0; i < data[master_column].total; i++)
1738 BC_ListBoxItem *current_item = data[master_column].values[i];
1740 // Select next item once the number items after the currently selected item
1741 // have been passed.
1745 if((*counter) >= skip)
1747 for(int j = 0; j < columns; j++)
1748 data[j].values[i]->selected = 1;
1750 return item_to_index(this->data, current_item);
1755 // Got currently selected item. Deselect it.
1756 if(current_item->selected)
1758 for(int j = 0; j < columns; j++)
1759 data[j].values[i]->selected = 0;
1765 // Descend into expanded level
1766 if(current_item->get_sublist() &&
1767 current_item->get_expand())
1769 int result = select_next(skip,
1772 current_item->get_sublist(),
1782 // Hit bottom of top level without finding the next item.
1785 BC_ListBoxItem *current_item;
1786 // Select first item in top level and quit
1790 current_item = data[master_column].values[0];
1792 for(int j = 0; j < columns; j++)
1793 data[j].values[0]->selected = 1;
1798 // Select last item in top level and quit
1800 int current_row = data[master_column].total - 1;
1801 current_item = data[master_column].values[current_row];
1803 for(int j = 0; j < columns; j++)
1804 data[j].values[current_row]->selected = 1;
1808 return item_to_index(this->data, current_item);
1810 }while(top_level && data[master_column].total);
1816 void BC_ListBox::clamp_positions()
1818 items_w = get_items_width();
1819 items_h = get_items_height(data, columns);
1821 if(yposition < 0) yposition = 0;
1823 if(yposition > items_h - view_h)
1824 yposition = items_h - view_h;
1826 if(yposition < 0) yposition = 0;
1828 if(xposition < 0) xposition = 0;
1830 if(xposition >= items_w - view_w)
1831 xposition = items_w - view_w;
1833 if(xposition < 0) xposition = 0;
1836 int BC_ListBox::center_selection(int selection,
1837 ArrayList<BC_ListBoxItem*> *data,
1841 if(!data) data = this->data;
1842 if(!counter) counter = &temp;
1844 for(int i = 0; i < data[master_column].total; i++)
1849 BC_ListBoxItem *item = data[master_column].values[i];
1850 if((*counter) == selection)
1852 BC_ListBoxItem *top_item = this->data[master_column].values[0];
1855 if(display_format == LISTBOX_ICONS)
1857 // Icon is out of window
1858 if( item->icon_y-yposition > view_h-get_text_h(item) ||
1859 item->icon_y-yposition < 0 ) {
1860 yposition = item->icon_y - view_h / 2;
1863 if(data[master_column].values[selection]->icon_x - xposition > view_w ||
1864 data[master_column].values[selection]->icon_x - xposition < 0)
1866 xposition = item->icon_x - view_w / 2;
1871 // Text coordinate is out of window
1872 if( item->text_y-yposition > view_h-get_text_h(item) ||
1873 item->text_y-yposition < 0 ) {
1874 yposition = item->text_y -
1883 if(item->get_sublist())
1885 int result = center_selection(selection,
1886 item->get_sublist(),
1888 if(result) return result;
1894 void BC_ListBox::update_scrollbars(int flush)
1896 int h_needed = items_h = get_items_height(data, columns);
1897 int w_needed = items_w = get_items_width();
1899 // if(columns > 0 && column_width)
1900 // printf("BC_ListBox::update_scrollbars 1 %d %d\n", column_width[columns - 1], w_needed);
1904 if(xposition != xscrollbar->get_value())
1905 xscrollbar->update_value(xposition);
1907 if(w_needed != xscrollbar->get_length() ||
1908 view_w != xscrollbar->get_handlelength())
1909 xscrollbar->update_length(w_needed, xposition, view_w, 0);
1914 if(yposition != yscrollbar->get_value())
1915 yscrollbar->update_value(yposition);
1917 if(h_needed != yscrollbar->get_length() || view_h != yscrollbar->get_handlelength())
1918 yscrollbar->update_length(h_needed, yposition, view_h, 0);
1921 if(flush) this->flush();
1924 int BC_ListBox::get_scrollbars()
1926 int h_needed = items_h = get_items_height(data, columns);
1927 int w_needed = items_w = get_items_width();
1931 title_h = get_title_h();
1933 view_h = popup_h - title_h - 4;
1934 view_w = popup_w - 4;
1936 // Create scrollbars as needed
1937 for(int i = 0; i < 2; i++)
1939 if(w_needed > view_w)
1944 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h() -
1952 if(h_needed > view_h)
1956 get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w() -
1965 // Update subwindow size
1966 int new_w = popup_w;
1967 int new_h = popup_h;
1968 if(need_xscroll) new_h -= get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h();
1969 if(need_yscroll) new_w -= get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w();
1972 if(new_w != BC_WindowBase::get_w() || new_h != BC_WindowBase::get_h())
1973 gui->resize_window(new_w, new_h);
1975 BC_WindowBase *destination = (is_popup ? gui : parent_window);
1980 destination->add_subwindow(xscrollbar =
1981 new BC_ListBoxXScroll(this,
1985 xscrollbar->show_window(0);
1986 xscrollbar->bound_to = this;
1990 xscrollbar->update_length(w_needed, xposition, view_w, flush);
1991 xscrollbar->reposition_window(get_xscroll_x(),
1993 get_xscroll_width());
1998 if(xscrollbar) delete xscrollbar;
2007 destination->add_subwindow(yscrollbar =
2008 new BC_ListBoxYScroll(this,
2012 yscrollbar->show_window(0);
2013 yscrollbar->bound_to = this;
2017 yscrollbar->update_length(h_needed, yposition, view_h, flush);
2018 yscrollbar->reposition_window(get_yscroll_x(),
2020 get_yscroll_height());
2025 if(yscrollbar) delete yscrollbar;
2031 view_w + 4 != bg_surface->get_w() ||
2032 view_h + 4 != bg_surface->get_h())
2034 if(bg_surface) delete bg_surface;
2035 bg_surface = new BC_Pixmap(gui, view_w + 4, view_h + 4);
2045 void BC_ListBox::set_drag_scroll(int value)
2047 allow_drag_scroll = value;
2051 // Test for scrolling by dragging
2053 int BC_ListBox::test_drag_scroll(int cursor_x, int cursor_y)
2056 if(allow_drag_scroll ||
2057 current_operation == SELECT_RECT)
2060 int top_boundary = get_title_h();
2062 if(cursor_y < top_boundary ||
2063 cursor_y >= view_h + title_h + LISTBOX_BORDER * 2 ||
2064 cursor_x < LISTBOX_BORDER ||
2065 cursor_x >= view_w + LISTBOX_BORDER)
2073 int BC_ListBox::drag_scroll_event()
2075 int top_boundary = get_title_h();
2078 if(get_cursor_y() < top_boundary)
2080 yposition -= top_boundary - get_cursor_y();
2084 if(get_cursor_y() >= view_h + title_h + 4)
2086 yposition += get_cursor_y() - (view_h + title_h + 4);
2090 if(get_cursor_x() < 2)
2092 xposition -= 2 - get_cursor_x();
2096 if(get_cursor_x() >= view_w + 2)
2098 xposition += get_cursor_x() - (view_w + 2);
2101 if(result) clamp_positions();
2105 int BC_ListBox::rectangle_scroll_event()
2107 int old_xposition = xposition;
2108 int old_yposition = yposition;
2109 int result = drag_scroll_event();
2113 rect_x1 += old_xposition - xposition;
2114 rect_y1 += old_yposition - yposition;
2115 rect_x2 = get_cursor_x();
2116 rect_y2 = get_cursor_y();
2118 int x1 = MIN(rect_x1, rect_x2);
2119 int x2 = MAX(rect_x1, rect_x2);
2120 int y1 = MIN(rect_y1, rect_y2);
2121 int y2 = MAX(rect_y1, rect_y2);
2123 if(select_rectangle(data,
2129 selection_changed();
2134 update_scrollbars(1);
2139 int BC_ListBox::select_scroll_event()
2141 int result = drag_scroll_event();
2145 highlighted_item = selection_number = get_cursor_item(data,
2151 update_scrollbars(1);
2152 selection_changed();
2157 int BC_ListBox::select_rectangle(ArrayList<BC_ListBoxItem*> *data,
2164 for(int i = 0; i < data[master_column].total; i++)
2166 for(int j = 0; j < columns; j++)
2168 BC_ListBoxItem *item = data[j].values[i];
2169 if(display_format == LISTBOX_ICONS)
2171 int icon_x, icon_y, icon_w, icon_h;
2172 int text_x, text_y, text_w, text_h;
2173 get_icon_mask(item, icon_x, icon_y, icon_w, icon_h);
2174 get_text_mask(item, text_x, text_y, text_w, text_h);
2176 if((x2 >= icon_x && x1 < icon_x + icon_w &&
2177 y2 >= icon_y && y1 < icon_y + icon_h) ||
2178 (x2 >= text_x && x1 < text_x + text_w &&
2179 y2 >= text_y && y1 < text_y + text_h))
2200 gui->get_w() - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w() :
2203 y1 < gui->get_h() &&
2204 y2 >= get_item_y(item) &&
2205 y1 < get_item_y(item) + get_item_h(item))
2224 BC_ListBoxItem *item = data[master_column].values[i];
2225 if(item->get_sublist() &&
2227 result |= select_rectangle(item->get_sublist(),
2236 int BC_ListBox::reposition_item(ArrayList<BC_ListBoxItem*> *data,
2237 int selection_number,
2243 if(!counter) counter = &temp;
2246 for(int i = 0; i < data[master_column].total; i++)
2248 BC_ListBoxItem *item = data[master_column].values[i];
2250 if((*counter) == selection_number)
2256 // Not recursive because it's only used for icons
2261 void BC_ListBox::move_selection(ArrayList<BC_ListBoxItem*> *dst,
2262 ArrayList<BC_ListBoxItem*> *src)
2264 for(int i = 0; i < src[master_column].total; i++)
2266 BC_ListBoxItem *item = src[master_column].values[i];
2271 for(int j = 0; j < columns; j++)
2273 dst[j].append(src[j].values[i]);
2274 src[j].remove_number(i);
2278 // Descend into sublist
2279 if(item->get_sublist())
2282 item->get_sublist());
2287 int BC_ListBox::put_selection(ArrayList<BC_ListBoxItem*> *data,
2288 ArrayList<BC_ListBoxItem*> *src,
2293 if(!counter) counter = &temp;
2297 for(int j = 0; j < columns; j++)
2299 for(int i = 0; i < src[j].total; i++)
2301 data[j].append(src[j].values[i]);
2307 for(int i = 0; i < data[master_column].total; i++)
2310 if((*counter) == destination)
2312 for(int j = 0; j < columns; j++)
2314 for(int k = 0; k < src[j].total; k++)
2316 data[j].insert(src[j].values[k], destination + k);
2322 BC_ListBoxItem *item = data[master_column].values[i];
2323 if(item->get_sublist())
2325 if(put_selection(item->get_sublist(),
2337 int BC_ListBox::item_to_index(ArrayList<BC_ListBoxItem*> *data,
2338 BC_ListBoxItem *item,
2342 if(!counter) counter = &temp;
2344 for(int i = 0; i < data[master_column].total; i++)
2347 for(int j = 0; j < columns; j++)
2349 BC_ListBoxItem *new_item = data[j].values[i];
2350 //printf("BC_ListBox::item_to_index 1 %d %d %p\n", j, i, new_item);
2351 if(new_item == item)
2357 BC_ListBoxItem *new_item = data[master_column].values[i];
2358 if(new_item->get_sublist())
2360 if(item_to_index(new_item->get_sublist(),
2370 BC_ListBoxItem* BC_ListBox::index_to_item(ArrayList<BC_ListBoxItem*> *data,
2376 if(!counter) counter = &temp;
2377 for(int i = 0; i < data[master_column].total; i++)
2380 if((*counter) == number)
2382 return data[column].values[i];
2384 BC_ListBoxItem *item = data[master_column].values[i];
2385 if(item->get_sublist())
2387 BC_ListBoxItem *result = index_to_item(item->get_sublist(),
2391 if(result) return result;
2397 int BC_ListBox::get_cursor_item(ArrayList<BC_ListBoxItem*> *data,
2400 BC_ListBoxItem **item_return,
2405 if(!data) return -1;
2406 if(!counter) counter = &temp;
2408 // Icons are not treed
2409 if(display_format == LISTBOX_ICONS)
2411 for(int j = data[master_column].total - 1; j >= 0; j--)
2413 int icon_x, icon_y, icon_w, icon_h;
2414 int text_x, text_y, text_w, text_h;
2415 BC_ListBoxItem *item = data[master_column].values[j];
2416 get_icon_mask(item, icon_x, icon_y, icon_w, icon_h);
2417 get_text_mask(item, text_x, text_y, text_w, text_h);
2419 if((cursor_x >= icon_x && cursor_x < icon_x + icon_w &&
2420 cursor_y >= icon_y && cursor_y < icon_y + icon_h) ||
2421 (cursor_x >= text_x && cursor_x < text_x + text_w &&
2422 cursor_y >= text_y && cursor_y < text_y + text_h))
2424 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 && !tooltip_done &&
2494 tooltip_text && tooltip_text[0] != 0 &&
2495 duration == get_resources()->tooltip_delay)
2507 int BC_ListBox::cursor_enter_event()
2511 switch(current_operation)
2513 // Cursor moved over button, pressed, and exited.
2514 case BUTTON_DOWN_SELECT:
2515 if(top_level->event_win == win)
2517 current_operation = BUTTON_DN;
2519 button_highlighted = 1;
2525 // Cursor entered button
2526 if(is_popup && top_level->event_win == win)
2528 button_highlighted = 1;
2533 // TODO: Need to get the highlighted column title or item
2534 if(gui && top_level->event_win == gui->win)
2536 list_highlighted = 1;
2546 int BC_ListBox::cursor_leave_event()
2548 if(current_operation == COLUMN_DRAG) return 0;
2551 if(button_highlighted)
2553 button_highlighted = 0;
2558 if(list_highlighted)
2560 list_highlighted = 0;
2561 highlighted_item = -1;
2562 highlighted_ptr = 0;
2563 highlighted_title = -1;
2564 int redraw_toggles = 0;
2565 for(int i = 0; i < expanders.total; i++)
2566 expanders.values[i]->cursor_leave_event(&redraw_toggles);
2574 int BC_ListBox::get_first_selection(ArrayList<BC_ListBoxItem*> *data, int *result)
2577 if(!result) result = &temp;
2579 for(int i = 0; i < data[master_column].total; i++)
2581 BC_ListBoxItem *item = data[master_column].values[i];
2583 if(item->selected) return (*result);
2584 if(item->get_sublist())
2586 if(get_first_selection(item->get_sublist(), result) >= 0)
2593 int BC_ListBox::get_total_items(ArrayList<BC_ListBoxItem*> *data,
2598 if(!result) result = &temp;
2600 for(int i = 0; i < data[master_column].total; i++)
2603 if(data[master_column].values[i]->get_sublist())
2604 get_total_items(data[master_column].values[i]->get_sublist(),
2613 int BC_ListBox::get_last_selection(ArrayList<BC_ListBoxItem*> *data,
2624 for(int i = data[master_column].total - 1; i >= 0; i--)
2626 BC_ListBoxItem *item = data[master_column].values[i];
2631 return get_total_items(data, 0, master_column) - (*result) /* - 1 */;
2636 if(item->get_sublist())
2638 if(get_last_selection(item->get_sublist(), result) >= 0)
2641 return get_total_items(data, 0, master_column) - (*result) /* - 1 */;
2650 void BC_ListBox::select_range(ArrayList<BC_ListBoxItem*> *data,
2656 if(!current) current = &temp;
2658 for(int i = 0; i < data[master_column].total; i++)
2661 if((*current) >= start && (*current) < end)
2663 for(int j = 0; j < columns; j++)
2664 data[j].values[i]->selected = 1;
2666 BC_ListBoxItem *item = data[master_column].values[i];
2667 if(item->get_sublist())
2668 select_range(item->get_sublist(),
2676 // Fill items between current selection and new selection
2677 int BC_ListBox::expand_selection(int button_press, int selection_number)
2679 int old_selection_start = selection_start;
2680 int old_selection_end = selection_end;
2682 // printf("BC_ListBox::expand_selection %d %d\n",
2683 // selection_center,
2684 // selection_number);
2686 // Calculate the range to select based on selection_center and selection_number
2687 if(selection_number < selection_center)
2689 selection_start = selection_number;
2693 selection_end = selection_number + 1;
2696 //printf("BC_ListBox::expand_selection %d %d %d %d\n", old_selection_start, old_selection_end, selection_start, selection_end);
2697 // Recurse through all the items and select the desired range
2698 select_range(data, selection_start, selection_end);
2701 return (old_selection_start != selection_start ||
2702 old_selection_end != selection_end);
2705 int BC_ListBox::toggle_item_selection(ArrayList<BC_ListBoxItem*> *data,
2706 int selection_number,
2710 if(!counter) counter = &temp;
2712 for(int i = 0; i < data[master_column].total; i++)
2714 BC_ListBoxItem *item = data[master_column].values[i];
2716 if((*counter) == selection_number)
2718 // Get new value for selection
2719 int selected = !item->selected;
2721 for(int j = 0; j < columns; j++)
2722 data[j].values[i]->selected = selected;
2726 // Descend into sublist
2727 if(item->get_sublist())
2729 if(toggle_item_selection(item->get_sublist(),
2740 void BC_ListBox::set_all_selected(ArrayList<BC_ListBoxItem*> *data, int value)
2742 for(int i = 0; i < data[master_column].total; i++)
2744 for(int j = 0; j < columns; j++)
2746 BC_ListBoxItem *item = data[j].values[i];
2747 item->selected = value;
2749 BC_ListBoxItem *item = data[master_column].values[i];
2750 if(item->get_sublist())
2752 set_all_selected(item->get_sublist(), value);
2757 void BC_ListBox::set_selected(ArrayList<BC_ListBoxItem*> *data,
2763 if(!counter) counter = &temp;
2764 for(int i = 0; i < data[master_column].total && (*counter) != item_number; i++)
2767 if((*counter) == item_number)
2769 for(int j = 0; j < columns; j++)
2771 BC_ListBoxItem *item = data[j].values[i];
2772 item->selected = value;
2777 BC_ListBoxItem *item = data[master_column].values[i];
2778 if(item->get_sublist())
2780 set_selected(item->get_sublist(),
2788 int BC_ListBox::update_selection(ArrayList<BC_ListBoxItem*> *data,
2789 int selection_number,
2794 if(!counter) counter = &temp;
2796 for(int i = 0; i < data[master_column].total; i++)
2798 BC_ListBoxItem *item = data[master_column].values[i];
2800 if((*counter) == selection_number && !item->selected)
2803 for(int j = 0; j < columns; j++)
2804 data[j].values[i]->selected = 1;
2807 if((*counter) != selection_number && item->selected)
2810 for(int j = 0; j < columns; j++)
2811 data[j].values[i]->selected = 0;
2813 if(item->get_sublist())
2814 result |= update_selection(item->get_sublist(),
2821 void BC_ListBox::promote_selections(ArrayList<BC_ListBoxItem*> *data,
2825 for(int i = 0; i < data[master_column].total; i++)
2827 for(int j = 0; j < columns; j++)
2829 BC_ListBoxItem *item = data[j].values[i];
2830 if(item->selected == old_value) item->selected = new_value;
2832 BC_ListBoxItem *item = data[master_column].values[i];
2833 if(item->get_sublist())
2834 promote_selections(item->get_sublist(), old_value, new_value);
2838 int BC_ListBox::focus_out_event()
2844 int BC_ListBox::button_press_event()
2847 BC_ListBoxItem *current_item = 0;
2849 int do_selection_change = 0;
2850 const int debug = 0;
2853 if(debug) printf("BC_ListBox::button_press_event %d this=%p event_win=%p %p %p %p\n",
2856 (void*)top_level->event_win,
2857 (void*)(gui ? gui->win : 0),
2859 (void*)parent_window->win);
2861 // Pressed in button
2862 if(is_popup && top_level->event_win == win)
2864 if(debug) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2865 current_operation = BUTTON_DN;
2869 if(!active && !disabled)
2871 top_level->deactivate();
2878 // Pressed in scrollbar
2879 if((xscrollbar && top_level->event_win == xscrollbar->win) ||
2880 (yscrollbar && top_level->event_win == yscrollbar->win))
2882 if(debug) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2887 if(gui && top_level->event_win == gui->win)
2889 if(debug) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2891 // Activate list items
2892 // If it is a suggestion popup, it is visible without being active
2895 if(debug) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2896 if(!is_suggestions) top_level->deactivate();
2897 if(debug) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2899 if(debug) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2902 // Wheel mouse pressed
2903 if(get_buttonpress() == 4)
2905 if(current_operation == NO_OPERATION)
2907 current_operation = WHEEL;
2910 set_yposition(yposition - gui->get_h() / 10, 0);
2912 update_scrollbars(0);
2913 highlighted_ptr = 0;
2914 highlighted_item = get_cursor_item(data,
2915 top_level->cursor_x,
2916 top_level->cursor_y,
2924 if(get_buttonpress() == 5)
2926 if(current_operation == NO_OPERATION)
2928 current_operation = WHEEL;
2931 set_yposition(yposition + gui->get_h() / 10, 0);
2933 update_scrollbars(0);
2934 highlighted_ptr = 0;
2935 highlighted_item = get_cursor_item(data,
2936 top_level->cursor_x,
2937 top_level->cursor_y,
2945 // Pressed over column title division
2946 if(test_column_divisions(gui->get_cursor_x(),
2947 gui->get_cursor_y(),
2950 drag_cursor_x = gui->get_cursor_x() + xposition;
2952 drag_column_w = column_width[highlighted_division - 1];
2954 drag_column_w = default_column_width[highlighted_division - 1];
2956 current_operation = DRAG_DIVISION;
2960 // Pressed in column title
2961 if(test_column_titles(gui->get_cursor_x(), gui->get_cursor_y()))
2963 current_operation = COLUMN_DN;
2964 button_highlighted = 0;
2965 list_highlighted = 1;
2970 // Pressed in expander
2971 if(test_expanders())
2973 current_operation = EXPAND_DN;
2974 // Need to redraw items because of alpha
2979 // Pressed over item
2980 if((selection_number = get_cursor_item(data,
2981 gui->get_cursor_x(),
2982 gui->get_cursor_y(),
2983 ¤t_item)) >= 0)
2985 if(debug) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2987 // Get item button was pressed over
2988 selection_number2 = selection_number1;
2989 selection_number1 = selection_number;
2991 selection_start = -1;
2995 // Multiple item selection is possible
2996 if(selection_mode == LISTBOX_MULTIPLE &&
2997 (ctrl_down() || shift_down()))
2999 // Expand text selection.
3000 // Fill items between selected region and current item.
3002 (display_format == LISTBOX_TEXT ||
3003 display_format == LISTBOX_ICON_LIST))
3005 // Get first item selected
3006 selection_start = get_first_selection(data);
3007 // Get last item selected
3008 selection_end = get_last_selection(data);
3009 // Get center of selected region
3010 if(selection_end > selection_start)
3012 selection_center = (selection_end + selection_start) >> 1;
3016 selection_center = selection_number;
3020 // Deselect everything.
3021 set_all_selected(data, 0);
3022 // Select just the items
3023 expand_selection(1, selection_number);
3027 // Toggle a single item on or off
3029 toggle_item_selection(data, selection_number);
3030 new_value = current_item->selected;
3034 // Select single item
3036 if(!current_item->selected)
3038 set_all_selected(data, 0);
3047 current_operation = SELECT;
3048 highlighted_item = selection_number;
3049 highlighted_ptr = current_item;
3050 button_highlighted = 0;
3051 list_highlighted = 1;
3054 do_selection_change = 1;
3059 // Pressed over nothing. Start rectangle selection.
3061 if(get_buttonpress() == 1 &&
3062 selection_mode == LISTBOX_MULTIPLE)
3066 // Deselect all and redraw if anything was selected
3067 if(get_selection_number(0, 0) >= 0)
3069 set_all_selected(data, 0);
3071 do_selection_change = 1;
3077 // Promote selections to protect from a rectangle selection
3078 promote_selections(data, 1, 2);
3081 // Start rectangle selection
3082 current_operation = SELECT_RECT;
3083 rect_x1 = rect_x2 = get_cursor_x();
3084 rect_y1 = rect_y2 = get_cursor_y();
3092 // Suggestion box is not active but visible, so lie to get it to deactivate
3093 if(is_popup && (active || (is_suggestions && gui)))
3096 if(debug) printf("BC_ListBox::button_press_event %d\n", __LINE__);
3102 if(do_selection_change) selection_changed();
3103 if(debug) printf("BC_ListBox::button_press_event %d %d\n",
3110 int BC_ListBox::button_release_event()
3113 int cursor_x, cursor_y;
3117 //printf("BC_ListBox::button_release_event 1 %d\n", current_operation);
3118 switch(current_operation)
3121 current_operation = NO_OPERATION;
3126 current_operation = NO_OPERATION;
3130 // Release item selection
3131 case BUTTON_DOWN_SELECT:
3133 //printf("BC_ListBox::button_release_event 10\n");
3134 unset_repeat(get_resources()->scroll_repeat);
3135 current_operation = NO_OPERATION;
3136 translate_coordinates(top_level->event_win,
3138 gui->get_cursor_x(),
3139 gui->get_cursor_y(),
3145 get_cursor_item(data, cursor_x, cursor_y);
3146 //printf("BC_ListBox::button_release_event %d %d\n", selection_number2, selection_number1);
3151 if(selection_number >= 0)
3157 // Second button release outside button
3158 if(button_releases > 1)
3165 if(top_level->get_double_click() &&
3166 selection_number2 == selection_number1 &&
3167 selection_number2 >= 0 &&
3168 selection_number1 >= 0)
3178 unset_repeat(get_resources()->scroll_repeat);
3181 // Demote selections from rectangle selection
3182 promote_selections(data, 2, 1);
3185 // Hide rectangle overlay
3187 current_operation = NO_OPERATION;
3191 // Release popup button
3194 current_operation = NO_OPERATION;
3198 // Second button release inside button
3199 if(button_releases > 1)
3207 current_operation = NO_OPERATION;
3208 // Update the sort column and the sort order for the user only if the existing
3209 // sort column is valid.
3210 if(sort_column >= 0)
3212 // Invert order only if column is the same
3213 if(highlighted_title == sort_column)
3215 (sort_order == SORT_ASCENDING) ?
3218 // Set the new sort column
3219 sort_column = highlighted_title;
3220 if(!sort_order_event())
3226 // Sorting not enabled. Redraw the title state.
3235 int redraw_toggles = 0;
3236 for(int i = 0; i < expanders.total && !result; i++)
3238 if(expanders.values[i]->button_release_event(&redraw_toggles))
3243 // Need to redraw items because of alpha
3244 if(redraw_toggles) draw_items(1);
3245 current_operation = NO_OPERATION;
3250 // Can't default to NO_OPERATION because it may be used in a drag event.
3255 if(do_event) handle_event();
3257 //printf("BC_ListBox::button_release_event %d %d\n", __LINE__, get_window_lock());
3261 int BC_ListBox::get_title_h()
3263 if(display_format == LISTBOX_TEXT ||
3264 display_format == LISTBOX_ICON_LIST)
3265 return column_titles ? column_bg[0]->get_h() : 0;
3270 void BC_ListBox::reset_cursor(int new_cursor)
3274 if(gui->get_cursor() != new_cursor)
3276 gui->set_cursor(new_cursor, 0, 0);
3280 if(get_cursor() != new_cursor)
3282 set_cursor(new_cursor, 0, 0);
3286 int BC_ListBox::test_column_divisions(int cursor_x, int cursor_y, int &new_cursor)
3291 cursor_y < get_title_h() &&
3293 cursor_x < gui->get_w())
3295 for(int i = 1; i < columns; i++)
3297 if(cursor_x >= -xposition + get_column_offset(i) - 5 &&
3298 cursor_x < -xposition + get_column_offset(i) +
3299 get_resources()->listbox_title_hotspot)
3301 highlighted_item = -1;
3302 highlighted_ptr = 0;
3303 highlighted_division = i;
3304 highlighted_title = -1;
3305 list_highlighted = 1;
3306 new_cursor = HSEPARATE_CURSOR;
3311 highlighted_division = -1;
3315 int BC_ListBox::test_column_titles(int cursor_x, int cursor_y)
3320 cursor_y < get_title_h() &&
3322 cursor_x < gui->get_w())
3324 for(int i = 0; i < columns; i++)
3326 if(cursor_x >= -xposition + get_column_offset(i) &&
3327 (cursor_x < -xposition + get_column_offset(i + 1) ||
3330 highlighted_item = -1;
3331 highlighted_ptr = 0;
3332 highlighted_division = -1;
3333 highlighted_title = i;
3334 list_highlighted = 1;
3339 highlighted_title = -1;
3343 int BC_ListBox::test_expanders()
3345 for(int i = 0; i < expanders.total; i++)
3347 if(expanders.values[i]->button_press_event())
3349 current_operation = EXPAND_DN;
3357 int BC_ListBox::cursor_motion_event()
3359 int redraw = 0, result = 0;
3360 int new_cursor = ARROW_CURSOR;
3362 selection_number = -1;
3365 switch(current_operation)
3368 // Button pressed and slid off button
3369 if(!cursor_inside())
3371 current_operation = BUTTON_DOWN_SELECT;
3379 // int new_w = get_cursor_x() +
3381 // get_column_offset(highlighted_division - 1);
3382 int difference = get_cursor_x() + xposition - drag_cursor_x;
3383 int new_w = drag_column_w + difference;
3385 new_cursor = HSEPARATE_CURSOR;
3389 column_width[highlighted_division - 1] = new_w;
3393 default_column_width[highlighted_division - 1] = new_w;
3396 column_width_boundaries();
3398 // Force update of coords
3399 set_autoplacement(data, 0, 1);
3400 column_resize_event();
3404 update_scrollbars(1);
3411 if(test_drag_scroll(get_cursor_x(), get_cursor_y()))
3413 set_repeat(get_resources()->scroll_repeat);
3416 int old_x1 = MIN(rect_x1, rect_x2);
3417 int old_x2 = MAX(rect_x1, rect_x2);
3418 int old_y1 = MIN(rect_y1, rect_y2);
3419 int old_y2 = MAX(rect_y1, rect_y2);
3421 int new_rect_x2 = get_cursor_x();
3422 int new_rect_y2 = get_cursor_y();
3424 int x1 = MIN(rect_x1, new_rect_x2);
3425 int x2 = MAX(rect_x1, new_rect_x2);
3426 int y1 = MIN(rect_y1, new_rect_y2);
3427 int y2 = MAX(rect_y1, new_rect_y2);
3429 // Adjust rectangle coverage
3437 redraw = select_rectangle(data,
3447 //printf("BC_ListBox::cursor_motion_event %d\n", __LINE__);
3452 rect_x2 = get_cursor_x();
3453 rect_y2 = get_cursor_y();
3458 update_scrollbars(1);
3459 selection_changed();
3460 //printf("BC_ListBox::cursor_motion_event %d\n", __LINE__);
3468 //printf("BC_ListBox::cursor_motion_event %d\n", __LINE__);
3478 int old_highlighted_item = highlighted_item;
3480 if(test_drag_scroll(get_cursor_x(),
3483 set_repeat(get_resources()->scroll_repeat);
3487 highlighted_item = selection_number = get_cursor_item(data,
3493 // Deselect all items and select just the one we're over
3494 if(selection_number >= 0 &&
3498 selection_mode == LISTBOX_SINGLE))
3500 redraw = update_selection(data, selection_number);
3503 if(selection_mode == LISTBOX_MULTIPLE &&
3504 (shift_down() || ctrl_down()))
3505 // Expand multiple selection
3507 // Expand selected region in text mode centered around initial range
3508 if((display_format == LISTBOX_TEXT ||
3509 display_format == LISTBOX_ICON_LIST) &&
3512 // Deselect everything.
3513 set_all_selected(data, 0);
3515 // Select just the items
3516 redraw = expand_selection(0, selection_number);
3519 // Set the one item we're over to the selection value determined in
3520 // button_press_event.
3528 if(highlighted_item != old_highlighted_item)
3532 update_scrollbars(1);
3533 //printf("BC_ListBox::cursor_motion_event %d %d\n", highlighted_item, old_highlighted_item);
3534 selection_changed();
3539 case BUTTON_DOWN_SELECT:
3540 // Went back into button area
3543 current_operation = BUTTON_DN;
3548 // Went into item area
3551 int cursor_x = 0, cursor_y = 0;
3552 translate_coordinates(top_level->event_win,
3554 top_level->cursor_x,
3555 top_level->cursor_y,
3558 int old_highlighted_item = highlighted_item;
3559 highlighted_item = selection_number = get_cursor_item(data,
3564 if(highlighted_item != old_highlighted_item)
3566 update_selection(data, selection_number);
3568 selection_changed();
3575 int redraw_toggles = 0;
3576 for(int i = 0; i < expanders.total && !result; i++)
3578 result = expanders.values[i]->cursor_motion_event(
3583 // Need to redraw items because of the alpha
3591 int cursor_x = get_cursor_x(), cursor_y = get_cursor_y();
3592 if(gui && top_level->event_win == gui->win)
3594 int old_highlighted_title = highlighted_title;
3595 int old_list_highlighted = list_highlighted;
3596 int old_highlighted_item = highlighted_item;
3597 int redraw_titles = 0;
3598 int redraw_border = 0;
3599 int redraw_items = 0;
3600 int redraw_toggles = 0;
3604 // Test if cursor moved over a title division
3605 test_column_divisions(cursor_x, cursor_y, new_cursor);
3607 // Test if cursor moved over a title
3608 if(highlighted_division < 0)
3610 test_column_titles(cursor_x, cursor_y);
3613 // Test if cursor moved over expander
3614 if(highlighted_division < 0 &&
3615 highlighted_title < 0 &&
3616 (display_format == LISTBOX_TEXT ||
3617 display_format == LISTBOX_ICON_LIST))
3619 for(int i = 0; i < expanders.total; i++)
3621 expanders.values[i]->cursor_motion_event(
3624 //printf("BC_ListBox::cursor_motion_event %d\n", redraw_toggles);
3627 // Test if cursor moved over an item
3628 if(highlighted_division < 0 &&
3629 highlighted_title < 0)
3631 highlighted_item = get_cursor_item(data,
3638 // Clear title highlighting if moved over division
3639 if(old_highlighted_title != highlighted_title)
3644 // Highlight list border
3645 if(old_list_highlighted != list_highlighted)
3650 // Moved out of item area
3651 if(old_highlighted_item != highlighted_item)
3656 //printf("BC_ListBox::cursor_motion_event 1 %d\n", highlighted_item);
3658 // Change cursor to title division adjustment
3659 reset_cursor(new_cursor);
3686 if(!result && list_highlighted)
3688 list_highlighted = 0;
3689 highlighted_item = -1;
3690 highlighted_ptr = 0;
3691 highlighted_title = -1;
3692 highlighted_division = -1;
3704 int BC_ListBox::drag_start_event()
3706 switch(current_operation)
3710 gui->is_event_win() &&
3713 BC_ListBoxItem *item_return = 0;
3714 selection_number = get_cursor_item(data,
3715 top_level->cursor_x,
3716 top_level->cursor_y,
3719 if(selection_number >= 0)
3722 if (item_return->icon_vframe)
3724 drag_popup = new BC_DragWindow(this,
3725 item_return->icon_vframe /*,
3726 get_abs_cursor_x(0) - item_return->icon_vframe->get_w() / 2,
3727 get_abs_cursor_y(0) - item_return->icon_vframe->get_h() / 2 */);
3730 // this probably works not!
3731 if (item_return->icon)
3733 drag_popup = new BC_DragWindow(this,
3734 item_return->icon /*,
3735 get_abs_cursor_x(0) - item_return->icon->get_w() / 2,
3736 get_abs_cursor_y(0) - item_return->icon->get_h() / 2 */);
3740 drag_popup = new BC_DragWindow(this,
3741 drag_icon_vframe /*,
3742 get_abs_cursor_x(0) - drag_icon_vframe->get_w() / 2,
3743 get_abs_cursor_y(0) - drag_icon_vframe->get_h() / 2 */);
3746 current_operation = DRAG_ITEM;
3753 if(gui && gui->is_event_win() && allow_drag_column)
3755 drag_popup = new BC_DragWindow(this,
3756 drag_column_icon_vframe /*,
3757 get_abs_cursor_x(0) - drag_column_icon_vframe->get_w() / 2,
3758 get_abs_cursor_y(0) - drag_column_icon_vframe->get_h() / 2 */);
3759 dragged_title = highlighted_title;
3760 current_operation = COLUMN_DRAG;
3770 int BC_ListBox::drag_motion_event()
3772 //printf("BC_ListBox::drag_motion_event 1 %d\n", current_operation);
3773 switch(current_operation)
3778 int new_highlighted_item = -1;
3779 BC_ListBoxItem *new_highlighted_ptr = 0;
3780 new_highlighted_item = get_cursor_item(data,
3781 top_level->cursor_x, top_level->cursor_y,
3782 &new_highlighted_ptr);
3784 if(new_highlighted_item != highlighted_item)
3789 // Always update highlighted value for drag_stop
3790 highlighted_item = new_highlighted_item;
3791 highlighted_ptr = new_highlighted_ptr;
3792 //printf("BC_ListBox::drag_motion_event 1 %p\n", highlighted_ptr);
3797 update_scrollbars(1);
3800 return drag_popup->cursor_motion_event();
3806 int old_highlighted_title = highlighted_title;
3807 test_column_titles(get_cursor_x(), get_cursor_y());
3808 if(old_highlighted_title != highlighted_title)
3812 return drag_popup->cursor_motion_event();
3819 int BC_ListBox::drag_stop_event()
3821 switch(current_operation)
3824 // Inside window boundary
3825 if(top_level->cursor_x > 0 &&
3826 top_level->cursor_x < gui->get_w() - drag_popup->get_w() / 2 &&
3827 top_level->cursor_y > 0 &&
3828 top_level->cursor_y < gui->get_h() - drag_popup->get_h() / 2)
3833 if(display_format == LISTBOX_ICONS)
3835 reposition_item(data,
3837 top_level->cursor_x +
3838 drag_popup->get_offset_x() -
3842 top_level->cursor_y +
3843 drag_popup->get_offset_y() -
3853 int destination = highlighted_item = item_to_index(data,
3855 //printf("BC_ListBox::drag_stop_event 1 %p %d\n", highlighted_ptr, destination);
3857 // Move selected items from data to temporary
3858 ArrayList<BC_ListBoxItem*> *src_items =
3859 new ArrayList<BC_ListBoxItem*>[columns];
3861 move_selection(src_items, data);
3863 // Insert items from temporary to data
3869 delete [] src_items;
3870 set_autoplacement(data, 0, 1);
3877 drag_popup->drag_failure_event();
3882 current_operation = NO_OPERATION;
3888 if(dragged_title != highlighted_title)
3890 if(highlighted_title >= 0)
3892 if(!move_column_event()) draw_titles(1);
3895 drag_popup->drag_failure_event();
3897 current_operation = NO_OPERATION;
3907 BC_DragWindow* BC_ListBox::get_drag_popup()
3912 int BC_ListBox::translation_event()
3916 int new_x = gui->get_x() +
3917 (top_level->last_translate_x -
3919 top_level->get_resources()->get_left_border());
3920 int new_y = gui->get_y() +
3921 (top_level->last_translate_y -
3923 top_level->get_resources()->get_top_border());
3925 gui->reposition_window(new_x, new_y);
3931 int BC_ListBox::reposition_window(int x, int y, int w, int h, int flush)
3935 if(w != -1) popup_w = w;
3936 if(h != -1) popup_h = h;
3937 //printf("BC_ListBox::reposition_window %d %d\n", popup_w, popup_h);
3941 if(w != -1) popup_w = w;
3942 if(h != -1) popup_h = h;
3944 xscrollbar->reposition_window(get_xscroll_x(),
3946 get_xscroll_width());
3948 yscrollbar->reposition_window(get_yscroll_x(),
3950 get_yscroll_height());
3955 BC_WindowBase::reposition_window(x, y, w, h);
3961 int BC_ListBox::deactivate()
3963 // printf("BC_ListBox::deactivate %d this=%p gui=%p active=%d\n",
3973 //printf("BC_ListBox::deactivate %d this=%p gui=%p\n", __LINE__, this, gui);
3982 highlighted_item = -1;
3983 highlighted_ptr = 0;
3988 //printf("BC_ListBox::deactivate %d this=%p\n", __LINE__, this);
3990 top_level->active_subwindow = 0;
3996 int BC_ListBox::activate(int take_focus)
3998 //printf("BC_ListBox::activate %d %p\n", __LINE__, this);
4003 top_level->active_subwindow = this;
4007 button_releases = 0;
4009 // Test for existence of GUI in case this was previously called without
4010 // take_focus & again with take_focus
4011 if(is_popup && !gui)
4016 y = get_y() + get_h();
4017 if(justify == LISTBOX_RIGHT)
4019 x = get_x() - popup_w + get_w();
4027 XTranslateCoordinates(top_level->display,
4036 if(new_x < 0) new_x = 0;
4037 if(new_y + popup_h > top_level->get_root_h(0))
4038 new_y -= get_h() + popup_h;
4040 add_subwindow(gui = new BC_Popup(this,
4048 // Avoid top going out of screen
4051 //printf("BC_ListBox::activate %d this=%p %p\n", __LINE__, this, gui->win);
4053 gui->show_window(1);
4055 //printf("BC_ListBox::activate %d %p\n", __LINE__, this);
4061 int BC_ListBox::keypress_event()
4063 if(!active) return 0;
4065 //printf("BC_ListBox::keypress_event %d\n", __LINE__);
4067 int result = 0, redraw = 0;
4068 int view_items = last_in_view - first_in_view + 1;
4069 if( view_items <= 0 ) view_items = view_h / get_text_height(MEDIUMFONT);
4070 int new_item = -1, new_selection = -1;
4072 switch(top_level->get_keypress())
4077 top_level->deactivate();
4079 // If user is manipulating popup with keyboard, don't pass on event.
4082 //printf("BC_ListBox::keypress_event %d %p\n", __LINE__, get_selection(0, 0));
4083 if(top_level->get_keypress() == RETURN)
4085 //printf("BC_ListBox::keypress_event %d %p\n", __LINE__, get_selection(0, 0));
4093 new_selection = new_item = select_previous(0);
4095 //printf("BC_ListBox::keypress_event 1 %d\n", new_item);
4098 center_selection(new_item);
4106 new_selection = new_item = select_next(0);
4110 center_selection(new_item);
4118 new_selection = new_item = select_previous(view_items - 1);
4122 center_selection(new_item);
4130 new_selection = new_item = select_next(view_items - 1);
4134 center_selection(new_item);
4162 int query_len = strlen(query);
4163 if( query_len < (int)sizeof(query)-1 &&
4164 top_level->get_keypress() > 30 &&
4165 top_level->get_keypress() < 127)
4167 query[query_len++] = top_level->get_keypress();
4168 query[query_len] = 0;
4169 new_selection = query_list();
4172 if(top_level->get_keypress() == BACKSPACE)
4174 if(query_len > 0) query[--query_len] = 0;
4175 new_selection = query_list();
4188 update_scrollbars(1);
4191 //printf("BC_ListBox::keypress_event %d new_selection=%d\n", __LINE__, new_selection);
4192 if(new_selection >= 0 && !is_suggestions)
4194 //printf("BC_ListBox::keypress_event %d\n", __LINE__);
4195 selection_changed();
4196 //printf("BC_ListBox::keypress_event %d\n", __LINE__);
4203 BC_Pixmap* BC_ListBox::get_bg_surface()
4209 void BC_ListBox::draw_background()
4211 if( !bg_draw ) return;
4213 // White background pixmap
4214 set_color(top_level->get_resources()->listbox_inactive);
4215 draw_box(0, 0, bg_surface->get_w(), bg_surface->get_h(), bg_surface);
4217 // Optional heroine pixmap
4219 bg_surface->draw_pixmap(bg_pixmap,
4220 bg_surface->get_w() - top_level->get_resources()->listbox_bg->get_w(),
4224 void BC_ListBox::clear_listbox(int x, int y, int w, int h)
4226 gui->draw_pixmap(bg_surface, x, y, w, h, x, y - title_h);
4229 void BC_ListBox::update_format(int display_format, int redraw)
4231 this->display_format = display_format;
4232 if( redraw && gui ) draw_items(1, 1);
4235 int BC_ListBox::get_format()
4237 return display_format;
4242 int BC_ListBox::draw_items(int flush, int draw_bg)
4246 BC_Resources *resources = get_resources();
4248 //dump(data, columns);
4250 // Calculate items width
4251 calculate_item_coords();
4254 // Create and destroy scrollbars as needed
4259 if( bg_draw ) this->bg_draw = 1;
4265 if(display_format == LISTBOX_ICONS)
4267 clear_listbox(2, 2 + title_h, view_w, view_h);
4269 set_font(MEDIUMFONT);
4270 for(int i = 0; i < data[master_column].size(); i++)
4272 BC_ListBoxItem *item = data[master_column].get(i);
4273 if(get_item_x(item) >= -get_item_w(item) &&
4274 get_item_x(item) < view_w &&
4275 get_item_y(item) >= -get_item_h(item) + title_h &&
4276 get_item_y(item) < view_h + title_h)
4278 item->set_in_view(1);
4279 if( first_in_view < 0 ) first_in_view = i;
4281 int item_color = get_item_highlight(data, 0, i);
4282 int icon_x, icon_y, icon_w, icon_h;
4283 int text_x, text_y, text_w, text_h;
4286 get_icon_mask(item, icon_x, icon_y, icon_w, icon_h);
4287 get_text_mask(item, text_x, text_y, text_w, text_h);
4290 if(item_color != resources->listbox_inactive)
4292 gui->set_color(BLACK);
4293 gui->draw_rectangle(icon_x, icon_y, icon_w, icon_h);
4294 gui->set_color(item_color);
4295 gui->draw_box(icon_x + 1, icon_y + 1, icon_w - 2, icon_h - 2);
4296 gui->set_color(BLACK);
4297 gui->draw_rectangle(text_x, text_y, text_w, text_h);
4298 gui->set_color(item_color);
4299 gui->draw_box(text_x + 1, text_y + 1, text_w - 2, text_h - 2);
4301 if(icon_position == ICON_LEFT)
4302 gui->draw_box(text_x - 1, text_y + 1, 2, text_h - 2);
4304 if(icon_position == ICON_TOP)
4305 gui->draw_line(text_x + 1, text_y, text_x + icon_w - 2, text_y);
4306 if(text_x + text_w < icon_x + icon_w)
4308 gui->set_color(BLACK);
4309 gui->draw_line(text_x + text_w,
4317 gui->set_color(get_item_color(data, 0, i));
4319 gui->pixmap->draw_pixmap(item->icon,
4320 icon_x + ICON_MARGIN,
4321 icon_y + ICON_MARGIN);
4324 gui->draw_text(text_x + ICON_MARGIN,
4325 text_y + ICON_MARGIN + get_baseline(item),
4329 item->set_in_view(0);
4335 // Draw one column at a time so text overruns don't go into the next column
4336 // clear column backgrounds
4337 int current_toggle = 0;
4338 for(int j = 0; j < columns; j++)
4340 clear_listbox(LISTBOX_BORDER + get_column_offset(j) - xposition,
4341 LISTBOX_BORDER + title_h,
4342 get_column_width(j, 1),
4344 // Draw rows in the column recursively
4345 draw_text_recursive(data, j, 0, ¤t_toggle);
4348 // Delete excess expanders
4349 while(expanders.total > current_toggle)
4351 expanders.remove_object();
4355 // draw user images if available
4357 // Draw titles on top of rows for superposition effect
4360 // Clear garbage from bottom right corner
4361 if(xscrollbar && yscrollbar && is_popup)
4363 gui->draw_top_background(parent_window,
4364 popup_w - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w(),
4365 popup_h - get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h(),
4366 get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w(),
4367 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h());
4374 if(current_operation == SELECT_RECT)
4384 void BC_ListBox::draw_text_recursive(ArrayList<BC_ListBoxItem*> *data,
4387 int *current_toggle)
4392 BC_Resources *resources = get_resources();
4394 set_font(MEDIUMFONT);
4397 // Search for a branch and make room for toggle if there is one
4400 for(int i = 0; i < data[column].size(); i++)
4402 if(data[column].get(i)->get_sublist())
4404 subindent = BC_WindowBase::get_resources()->listbox_expand[0]->get_w();
4410 row_height = row_ascent = row_descent = 0;
4411 for(int i = 0; i < data[column].total; i++)
4413 BC_ListBoxItem *item = data[column].values[i];
4414 int ht = get_text_h(item);
4415 if( ht > row_height ) row_height = ht;
4416 int bl = get_baseline(item);
4417 if( bl > row_ascent ) row_ascent = bl;
4419 if( dt > row_descent ) row_ascent = bl;
4422 for(int i = 0; i < data[column].size(); i++)
4425 BC_ListBoxItem *item = data[column].values[i];
4426 BC_ListBoxItem *first_item = data[master_column].values[i];
4428 if(get_item_y(item) >= -get_item_h(item) + title_h &&
4429 get_item_y(item) < view_h + title_h)
4431 int row_color = get_item_highlight(data, 0, i);
4432 int x, y, w, h, column_width;
4434 get_text_mask(item, x, y, w, h);
4435 column_width = get_column_width(column, 1);
4436 if(x + column_width > view_w + LISTBOX_BORDER * 2)
4437 column_width = view_w + LISTBOX_BORDER * 2 - x;
4439 if(row_color != resources->listbox_inactive)
4441 gui->set_color(row_color);
4442 gui->draw_box(x, y, column_width, h);
4443 gui->set_color(BLACK);
4444 int yy = y, xx = x + column_width-1;
4445 gui->draw_line(x, yy, xx, yy);
4446 yy = y + row_height;
4447 gui->draw_line(x, yy, xx, yy);
4450 gui->set_color(get_item_color(data, column, i));
4453 if(column == 0 && display_format == LISTBOX_ICON_LIST)
4457 gui->pixmap->draw_pixmap(item->icon,
4460 x += item->icon->get_w() + ICON_MARGIN;
4465 // Indent only applies to first column
4467 x + LISTBOX_BORDER + LISTBOX_MARGIN +
4468 (column == 0 ? indent + subindent : 0),
4469 y + get_baseline(item), item->text);
4470 item->set_in_view(1);
4472 if( first_in_view < 0 ) first_in_view = i;
4478 item->get_sublist() &&
4479 item->get_columns())
4481 // Create new expander
4482 if(*current_toggle >= expanders.total)
4484 BC_ListBoxToggle *toggle =
4485 new BC_ListBoxToggle(this,
4487 x + LISTBOX_BORDER + LISTBOX_MARGIN + indent,
4490 expanders.append(toggle);
4493 // Reposition existing expander
4495 BC_ListBoxToggle *toggle = expanders.values[*current_toggle];
4496 //printf("BC_ListBox::draw_text_recursive 1 %d\n", *current_toggle);
4497 toggle->update(item,
4498 x + LISTBOX_BORDER + LISTBOX_MARGIN + indent,
4502 (*current_toggle)++;
4509 item->set_in_view(0);
4511 // Descend into sublist
4512 if(first_item->get_expand())
4514 draw_text_recursive(first_item->get_sublist(),
4516 indent + LISTBOX_INDENT,
4525 int BC_ListBox::draw_border(int flash)
4527 BC_Resources *resources = top_level->get_resources();
4528 gui->draw_3d_border(0,
4530 view_w + LISTBOX_BORDER * 2,
4531 view_h + title_h + LISTBOX_BORDER * 2,
4532 resources->listbox_border1,
4534 resources->listbox_border2_hi :
4535 resources->listbox_border2,
4537 resources->listbox_border3_hi :
4538 resources->listbox_border3,
4539 resources->listbox_border4);
4549 void BC_ListBox::draw_title(int number)
4551 // Column title background
4552 int image_number = 0;
4553 if(number == highlighted_title)
4556 if(current_operation == COLUMN_DN)
4560 int column_offset = get_column_offset(number) - xposition + LISTBOX_BORDER;
4561 int column_width = get_column_width(number, 1);
4562 gui->draw_3segmenth(get_column_offset(number) - xposition + LISTBOX_BORDER,
4564 get_column_width(number, 1) + get_resources()->listbox_title_overlap,
4565 column_bg[image_number]);
4567 // Column title sort order
4568 if(number == sort_column)
4571 if(sort_order == SORT_ASCENDING)
4572 src = column_sort_dn;
4574 src = column_sort_up;
4576 int x = column_offset +
4579 if(x > items_w) x = items_w;
4580 x -= 5 + src->get_w();
4581 gui->draw_pixmap(src,
4583 title_h / 2 - src->get_h() / 2 + LISTBOX_BORDER);
4587 int x = -xposition +
4588 get_column_offset(number) +
4591 x += get_resources()->listbox_title_margin;
4593 gui->set_color(get_resources()->listbox_title_color);
4595 LISTBOX_MARGIN + LISTBOX_BORDER + get_text_ascent(MEDIUMFONT),
4596 _(column_titles[number]));
4599 int BC_ListBox::draw_titles(int flash)
4602 (display_format == LISTBOX_TEXT ||
4603 display_format == LISTBOX_ICON_LIST))
4605 //printf("BC_ListBox::draw_titles 1 %d\n", highlighted_title);
4606 for(int i = 0; i < columns; i++)
4608 if(i != highlighted_title)
4612 if(highlighted_title >= 0) draw_title(highlighted_title);
4623 void BC_ListBox::draw_toggles(int flash)
4625 for(int i = 0; i < expanders.total; i++)
4626 expanders.values[i]->draw(0);
4628 //printf("BC_ListBox::draw_toggles 1 %d\n", flash);
4629 if(flash && expanders.total)
4636 int BC_ListBox::draw_rectangle(int flash)
4638 int x1 = MIN(rect_x1, rect_x2);
4639 int x2 = MAX(rect_x1, rect_x2);
4640 int y1 = MIN(rect_y1, rect_y2);
4641 int y2 = MAX(rect_y1, rect_y2);
4643 if(x1 == x2 || y1 == y2) return 0;
4646 gui->set_color(WHITE);
4647 gui->draw_rectangle(x1, y1, x2 - x1, y2 - y1);
4658 void BC_ListBox::dump(ArrayList<BC_ListBoxItem*> *data,
4665 printf("BC_ListBox::dump 1\n");
4668 for(int i = 0; i < data[master_column].total; i++)
4670 for(int k = 0; k < indent; k++)
4672 for(int j = 0; j < columns; j++)
4674 BC_ListBoxItem *item = data[j].values[i];
4675 printf("%d,%d,%d=%s ",
4678 item->autoplace_text,
4683 if(data[master_column].values[i]->get_sublist())
4685 dump(data[master_column].values[i]->get_sublist(),
4686 data[master_column].values[i]->get_columns(),