1 #include "bcdragwindow.h"
3 #include "bclistboxitem.h"
5 #include "bcresources.h"
16 // ====================================================== scrollbars
19 BC_ListBoxYScroll::BC_ListBoxYScroll(BC_ListBox *listbox,
23 : BC_ScrollBar(listbox->get_yscroll_x(),
24 listbox->get_yscroll_y(),
26 listbox->get_yscroll_height(),
31 this->listbox = listbox;
34 BC_ListBoxYScroll::~BC_ListBoxYScroll()
38 int BC_ListBoxYScroll::handle_event()
40 listbox->set_yposition(get_value());
50 BC_ListBoxXScroll::BC_ListBoxXScroll(BC_ListBox *listbox,
54 : BC_ScrollBar(listbox->get_xscroll_x(),
55 listbox->get_xscroll_y(),
57 listbox->get_xscroll_width(),
62 this->listbox = listbox;
65 BC_ListBoxXScroll::~BC_ListBoxXScroll()
69 int BC_ListBoxXScroll::handle_event()
71 listbox->set_xposition(get_value());
82 BC_ListBoxToggle::BC_ListBoxToggle(BC_ListBox *listbox,
88 BC_WindowBase::get_resources()->listbox_expand,
91 this->listbox = listbox;
95 void BC_ListBoxToggle::update(BC_ListBoxItem *item, int x, int y)
98 if(item && item->get_expand() != get_value())
100 BC_Toggle::update(item->get_expand(), 0);
102 reposition_window(x, y);
105 int BC_ListBoxToggle::handle_event()
107 listbox->expand_item(item, get_value());
125 // ====================================================== box
127 BC_ListBox::BC_ListBox(int x,
132 ArrayList<BC_ListBoxItem*> *data,
133 char **column_titles,
141 : BC_SubWindow(x, y, w, h, -1)
145 highlighted_item = -1;
150 highlighted_division = 0;
151 current_cursor = ARROW_CURSOR;
162 selection_number1 = -1;
163 selection_number2 = -1;
165 // GCC 3.0.2 optimization fails if bg_surface is zeroed.
166 // printf("malloc 5\n");
167 // unsigned char *test3 = (unsigned char*)malloc(4628);
168 // printf("malloc 6\n");
170 current_operation = BCLISTBOX_NO_OPERATION;
171 allow_drag_scroll = 1;
176 //printf("BC_ListBox::BC_ListBox 1\n");
178 this->columns = columns;
179 this->yposition = yposition;
181 this->display_format = display_format;
182 this->selection_mode = selection_mode;
183 this->icon_position = icon_position;
184 this->allow_drag = allow_drag;
185 this->column_titles = 0;
186 this->column_width = 0;
187 //printf("BC_ListBox::BC_ListBox 1\n");
189 if((!column_titles && column_width) ||
190 (column_titles && !column_width))
192 printf("BC_ListBox::BC_ListBox either column_titles or column_widths == NULL but not both.\n");
194 //printf("BC_ListBox::BC_ListBox 2 %p %p\n", column_titles, column_width);
195 set_columns(column_titles,
199 //printf("BC_ListBox::BC_ListBox 3\n");
205 // reset the search engine
206 //printf("BC_ListBox::BC_ListBox 4\n");
208 //printf("BC_ListBox::BC_ListBox 5\n");
211 BC_ListBox::~BC_ListBox()
213 expanders.remove_all_objects();
214 if(bg_surface) delete bg_surface;
215 if(bg_pixmap) delete bg_pixmap;
216 if(xscrollbar) delete xscrollbar;
217 if(yscrollbar) delete yscrollbar;
229 void BC_ListBox::reset_query()
231 query[0] = 0; // reset query
234 int BC_ListBox::evaluate_query(int list_item, char *string)
236 return(strcmp(string, data[0].values[list_item]->text) <= 0 &&
237 data[0].values[list_item]->searchable);
240 int BC_ListBox::query_list()
242 if(query[0] == 0) return 0;
246 int selection_changed = 0;
247 int prev_selection = -1;
248 for(int i = 0; !done && i < data[0].total; i++)
250 if(evaluate_query(i, query))
260 for(int i = 0; i < data[0].total; i++)
262 for(int j = 0; j < columns; j++)
264 if(data[j].values[i]->selected) prev_selection = i;
265 data[j].values[i]->selected = 0;
270 if(prev_selection != result)
271 selection_changed = 1;
272 for(int j = 0; j < columns; j++)
274 data[j].values[result]->selected = 1;
276 center_selection(result);
279 return selection_changed;
282 void BC_ListBox::init_column_width()
284 if(!column_width && data)
287 for(int i = 0; i < data[0].total; i++)
289 w = get_text_width(MEDIUMFONT, data[0].values[i]->get_text()) + 2 * LISTBOX_MARGIN;
290 if(w > widest) widest = w;
292 // if(widest < popup_w - 4) widest = popup_w - 4;
293 default_column_width[0] = widest;
297 int BC_ListBox::initialize()
301 images[0] = new BC_Pixmap(parent_window, BC_WindowBase::get_resources()->listbox_button[0], PIXMAP_ALPHA);
302 images[1] = new BC_Pixmap(parent_window, BC_WindowBase::get_resources()->listbox_button[1], PIXMAP_ALPHA);
303 images[2] = new BC_Pixmap(parent_window, BC_WindowBase::get_resources()->listbox_button[2], PIXMAP_ALPHA);
304 w = images[0]->get_w();
305 h = images[0]->get_h();
314 drag_icon = new BC_Pixmap(parent_window,
315 BC_WindowBase::get_resources()->type_to_icon[ICON_UNKNOWN],
317 BC_SubWindow::initialize();
321 if(top_level->get_resources()->listbox_bg)
322 bg_pixmap = new BC_Pixmap(this,
323 get_resources()->listbox_bg,
328 if(!popup) gui->flash();
332 void BC_ListBox::deactivate_selection()
334 current_operation = BCLISTBOX_NO_OPERATION;
337 int BC_ListBox::draw_face()
339 // Draw the button for a popup listbox
342 draw_top_background(parent_window, 0, 0, w, h);
343 images[status]->write_drawable(pixmap,
355 int BC_ListBox::calculate_item_coords()
363 // Change the display_format to get the right item dimensions for both
365 int display_format_temp = display_format;
368 // Scan the first column for lowest y coord of all text
369 // and lowest right x and y coord for all icons which aren't auto placable
370 calculate_last_coords_recursive(data,
377 // Reset last column width. It's recalculated based on text width.
378 int *last_column_w = (column_width ?
379 &column_width[columns - 1] :
380 &default_column_width[columns - 1]);
381 if(this->column_titles)
384 get_text_width(MEDIUMFONT, this->column_titles[this->columns - 1]) +
390 *last_column_w = MIN_COLUMN_WIDTH;
393 calculate_item_coords_recursive(data,
402 display_format = display_format_temp;
407 void BC_ListBox::calculate_last_coords_recursive(
408 ArrayList<BC_ListBoxItem*> *data,
415 for(int i = 0; i < data[0].total; i++)
417 int current_text_y = 0;
418 int current_icon_x = 0;
419 int current_icon_y = 0;
420 BC_ListBoxItem *item = data[0].values[i];
422 if(!item->autoplace_text)
424 // Lowest text coordinate
425 display_format = LISTBOX_TEXT;
426 current_text_y = item->text_y +
427 get_text_height(MEDIUMFONT);
428 if(current_text_y > *next_text_y)
429 *next_text_y = current_text_y;
431 // Add sublist depth if it is expanded
432 if(item->get_sublist() &&
433 item->get_columns() &&
436 calculate_last_coords_recursive(item->get_sublist(),
448 BC_ListBoxItem *item = data[0].values[i];
449 if(!item->autoplace_icon)
451 display_format = LISTBOX_ICONS;
452 // Lowest right icon coordinate.
453 current_icon_x = item->icon_x;
454 if(current_icon_x > *icon_x) *icon_x = current_icon_x;
455 if(current_icon_x + get_item_w(item) > *next_icon_x)
456 *next_icon_x = current_icon_x + get_item_w(item);
458 current_icon_y = item->icon_y + get_item_h(item);
459 if(current_icon_y > *next_icon_y)
460 *next_icon_y = current_icon_y;
467 void BC_ListBox::calculate_item_coords_recursive(
468 ArrayList<BC_ListBoxItem*> *data,
478 // Set up items which need autoplacement.
479 // Should fill icons down and then across
480 for(int i = 0; i < data[0].total; i++)
482 // Don't increase y unless the row requires autoplacing.
483 int total_autoplaced_columns = 0;
485 // Set up icons in first column
488 BC_ListBoxItem *item = data[0].values[i];
489 if(item->autoplace_icon)
491 // 1 column only if icons are used
492 display_format = LISTBOX_ICONS;
495 if(*next_icon_y + get_item_h(item) >= get_h() &&
498 *icon_x = *next_icon_x;
502 if(*icon_x + get_item_w(item) > *next_icon_x)
503 *next_icon_x = *icon_x + get_item_w(item);
506 item->set_icon_x(*icon_x);
507 item->set_icon_y(*next_icon_y);
509 *next_icon_y += get_item_h(item);
517 for(int j = 0; j < columns; j++)
519 BC_ListBoxItem *item = data[j].values[i];
520 if(item->autoplace_text)
522 display_format = LISTBOX_TEXT;
523 item->set_text_x(next_text_x);
524 item->set_text_y(*next_text_y);
526 // printf("BC_ListBox::calculate_item_coords_recursive %p %d %d %d %d %s \n",
527 // item->get_sublist(),
528 // item->get_columns(),
529 // item->get_expand(),
532 // item->get_text());
533 // Increment position of next column
535 next_text_x += (column_width ?
537 default_column_width[j]);
539 // Set last column width based on text width
541 int new_w = get_item_w(item);
543 int *previous_w = (column_width ?
545 &default_column_width[j]);
546 if(new_w > *previous_w)
549 total_autoplaced_columns++;
553 // Increase the text vertical position
554 if(total_autoplaced_columns)
556 display_format = LISTBOX_TEXT;
557 *next_text_y += get_text_height(MEDIUMFONT);
561 BC_ListBoxItem *item = data[0].values[i];
562 if(item->get_sublist() &&
563 item->get_columns() &&
566 calculate_item_coords_recursive(
577 int BC_ListBox::get_display_mode()
579 return display_format;
582 int BC_ListBox::get_yposition()
587 int BC_ListBox::get_xposition()
592 int BC_ListBox::get_highlighted_item()
594 return highlighted_item;
598 int BC_ListBox::get_item_x(BC_ListBoxItem *item)
600 if(display_format == LISTBOX_TEXT)
601 return item->text_x - xposition + 2;
603 return item->icon_x - xposition + 2;
606 int BC_ListBox::get_item_y(BC_ListBoxItem *item)
609 if(display_format == LISTBOX_TEXT)
610 result = item->text_y - yposition + title_h + 2;
612 result = item->icon_y - yposition + title_h + 2;
616 int BC_ListBox::get_item_w(BC_ListBoxItem *item)
618 if(display_format == LISTBOX_ICONS)
621 get_icon_mask(item, x, y, w, h);
623 get_text_mask(item, x, y, w, h);
626 if(icon_position == ICON_LEFT)
627 return icon_w + text_w;
629 return (icon_w > text_w) ? icon_w : text_w;
633 return get_text_width(MEDIUMFONT, item->text) + 2 * LISTBOX_MARGIN;
637 int BC_ListBox::get_item_h(BC_ListBoxItem *item)
639 if(display_format == LISTBOX_ICONS)
642 get_icon_mask(item, x, y, w, h);
644 get_text_mask(item, x, y, w, h);
647 if(icon_position == ICON_LEFT)
648 return (icon_h > text_h) ? icon_h : text_h;
650 return icon_h + text_h;
654 return get_text_height(MEDIUMFONT);
660 int BC_ListBox::get_icon_w(BC_ListBoxItem *item)
662 BC_Pixmap *icon = item->icon;
663 if(icon) return icon->get_w();
667 int BC_ListBox::get_icon_h(BC_ListBoxItem *item)
669 BC_Pixmap *icon = item->icon;
670 if(icon) return icon->get_h();
674 int BC_ListBox::get_items_width()
678 if(display_format == LISTBOX_ICONS)
680 for(int i = 0; i < columns; i++)
682 for(int j = 0; j < data[i].total; j++)
685 BC_ListBoxItem *item = data[i].values[j];
688 get_icon_mask(item, x, y, w, h);
689 if(x1 + w > widest) widest = x1 + w;
691 if(display_format == LISTBOX_ICONS && icon_position == ICON_LEFT)
694 get_text_mask(item, x, y, w, h);
695 if(x1 + w > widest) widest = x1 + w;
700 if(display_format == LISTBOX_TEXT)
702 return get_column_offset(columns);
707 int BC_ListBox::get_items_height(ArrayList<BC_ListBoxItem*> *data,
724 for(int j = 0; j < (data ? data[0].total : 0); j++)
727 BC_ListBoxItem *item = data[0].values[j];
729 if(display_format == LISTBOX_ICONS)
731 get_icon_mask(item, x, y, w, h);
732 if(y + h > highest) highest = y + h;
734 get_text_mask(item, x, y, w, h);
735 if(y + h > highest) highest = y + h;
739 get_text_mask(item, x, y, w, h);
743 // Descend into sublist
744 if(item->get_sublist() &&
747 get_items_height(item->get_sublist(),
753 if(display_format == LISTBOX_TEXT && top_level)
755 highest = LISTBOX_MARGIN + *result;
762 int BC_ListBox::set_yposition(int position, int draw_items)
764 this->yposition = position;
773 int BC_ListBox::set_xposition(int position)
775 this->xposition = position;
781 void BC_ListBox::expand_item(BC_ListBoxItem *item, int expand)
785 item->expand = expand;
786 // Collapse sublists if this is collapsed to make it easier to calculate
788 if(item->get_sublist())
789 collapse_recursive(item->get_sublist());
792 // Set everything for autoplacement
794 set_autoplacement(data, 0, 1);
801 void BC_ListBox::collapse_recursive(ArrayList<BC_ListBoxItem*> *data)
803 for(int i = 0; i < data[0].total; i++)
805 BC_ListBoxItem *item = data[0].values[i];
806 if(item->get_sublist() && item->expand)
809 collapse_recursive(item->get_sublist());
814 void BC_ListBox::set_autoplacement(ArrayList<BC_ListBoxItem*> *data,
818 for(int i = 0; i < data[0].total; i++)
820 for(int j = 0; j < columns; j++)
822 if(do_icons) data[j].values[i]->autoplace_icon = 1;
823 if(do_text) data[j].values[i]->autoplace_text = 1;
826 BC_ListBoxItem *item = data[0].values[i];
827 if(item->get_sublist())
829 set_autoplacement(item->get_sublist(), do_icons, do_text);
836 int BC_ListBox::get_w()
839 return BCPOPUPLISTBOX_W;
844 int BC_ListBox::get_h()
847 return BCPOPUPLISTBOX_H;
852 int BC_ListBox::get_yscroll_x()
855 return popup_w - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w();
859 get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w();
862 int BC_ListBox::get_yscroll_y()
870 int BC_ListBox::get_yscroll_height()
872 return popup_h - (need_xscroll ?
873 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h() :
877 int BC_ListBox::get_xscroll_x()
885 int BC_ListBox::get_xscroll_y()
889 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h();
893 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h();
896 int BC_ListBox::get_xscroll_width()
898 return popup_w - (need_yscroll ?
899 get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w() :
903 int BC_ListBox::get_column_offset(int column)
909 column_width[--column] :
910 default_column_width[--column];
915 void BC_ListBox::column_width_boundaries()
919 for(int i = 0; i < columns; i++)
921 if(column_width[i] < MIN_COLUMN_WIDTH) column_width[i] = MIN_COLUMN_WIDTH;
926 for(int i = 0; i < columns; i++)
928 if(default_column_width[i] < MIN_COLUMN_WIDTH) default_column_width[i] = MIN_COLUMN_WIDTH;
933 int BC_ListBox::get_column_width(int column, int clamp_right)
935 if(column < columns - 1 || !clamp_right)
936 return column_width ?
937 column_width[column] :
938 default_column_width[column];
942 get_column_offset(column);
945 int BC_ListBox::get_icon_mask(BC_ListBoxItem *item,
951 if(display_format == LISTBOX_ICONS)
953 x = get_item_x(item);
954 y = get_item_y(item);
955 w = get_icon_w(item) + ICON_MARGIN * 2;
956 h = get_icon_h(item) + ICON_MARGIN * 2;
959 if(display_format == LISTBOX_TEXT)
966 int BC_ListBox::get_text_mask(BC_ListBoxItem *item,
972 x = get_item_x(item);
973 y = get_item_y(item);
975 if(display_format == LISTBOX_ICONS)
977 if(icon_position == ICON_LEFT)
979 x += get_icon_w(item) + ICON_MARGIN * 2;
980 y += get_icon_h(item) - get_text_height(MEDIUMFONT);
984 y += get_icon_h(item) + ICON_MARGIN;
987 w = get_text_width(MEDIUMFONT, item->text) + ICON_MARGIN * 2;
988 h = get_text_height(MEDIUMFONT) + ICON_MARGIN * 2;
991 if(display_format == LISTBOX_TEXT)
993 w = get_text_width(MEDIUMFONT, item->text) + LISTBOX_MARGIN * 2;
994 h = get_text_height(MEDIUMFONT);
999 int BC_ListBox::get_item_highlight(ArrayList<BC_ListBoxItem*> *data,
1003 if(data[column].values[item]->selected)
1006 if(highlighted_ptr == data[0].values[item])
1012 int BC_ListBox::get_item_color(ArrayList<BC_ListBoxItem*> *data,
1016 int color = data[column].values[item]->color;
1017 if(get_item_highlight(data, column, item) == color)
1024 BC_ListBoxItem* BC_ListBox::get_selection(int column,
1025 int selection_number)
1027 return get_selection_recursive(data,
1032 BC_ListBoxItem* BC_ListBox::get_selection_recursive(
1033 ArrayList<BC_ListBoxItem*> *data,
1035 int selection_number)
1039 for(int i = 0; i < data[0].total; i++)
1041 BC_ListBoxItem *item = data[0].values[i];
1045 if(selection_number < 0)
1048 return data[column].values[i];
1052 if(item->get_sublist())
1054 BC_ListBoxItem *result = get_selection_recursive(item->get_sublist(),
1057 if(result) return result;
1064 int BC_ListBox::get_selection_number(int column,
1065 int selection_number)
1067 return get_selection_number_recursive(data,
1072 int BC_ListBox::get_selection_number_recursive(
1073 ArrayList<BC_ListBoxItem*> *data,
1075 int selection_number,
1080 if(!counter) counter = &temp;
1082 for(int i = 0; i < data[0].total; i++)
1085 BC_ListBoxItem *item = data[0].values[i];
1089 if(selection_number < 0)
1094 if(item->get_sublist())
1096 int result = get_selection_number_recursive(
1097 item->get_sublist(),
1101 if(result >= 0) return result;
1108 int BC_ListBox::set_selection_mode(int mode)
1110 this->selection_mode = mode;
1114 void BC_ListBox::delete_columns()
1118 for(int i = 0; i < columns; i++)
1120 delete [] column_titles[i];
1122 delete [] column_titles;
1125 if(column_width) delete [] column_width;
1131 // Need to copy titles so EDL can change
1132 void BC_ListBox::set_columns(char **column_titles,
1136 if((!column_titles && column_width) ||
1137 (column_titles && !column_width))
1139 printf("BC_ListBox::set_columns either column_titles or column_width == NULL but not both.\n");
1148 this->column_titles = new char*[columns];
1149 for(int i = 0; i < columns; i++)
1151 this->column_titles[i] = new char[strlen(column_titles[i]) + 1];
1152 strcpy(this->column_titles[i], column_titles[i]);
1158 this->column_width = new int[columns];
1159 for(int i = 0; i < columns; i++)
1161 this->column_width[i] = column_width[i];
1165 this->columns = columns;
1170 int BC_ListBox::update(ArrayList<BC_ListBoxItem*> *data,
1171 char **column_titles,
1176 int highlighted_number,
1177 int recalc_positions,
1181 set_columns(column_titles,
1187 this->yposition = yposition;
1188 this->xposition = xposition;
1189 this->highlighted_item = highlighted_number;
1190 this->highlighted_ptr = index_to_item(data, highlighted_number, 0);
1192 if(recalc_positions)
1193 set_autoplacement(data, 1, 1);
1195 init_column_width();
1201 update_scrollbars();
1208 void BC_ListBox::center_selection()
1210 int selection = get_selection_number(0, 0);
1212 calculate_item_coords();
1213 center_selection(selection);
1220 update_scrollbars();
1225 void BC_ListBox::move_vertical(int pixels)
1229 void BC_ListBox::move_horizontal(int pixels)
1233 int BC_ListBox::select_previous(int skip,
1234 BC_ListBoxItem *selected_item,
1236 ArrayList<BC_ListBoxItem*> *data,
1242 selected_item = get_selection(0, 0);
1254 got_second = &temp3;
1259 // Scan backwards to item pointer. Then count visible items to get
1260 // destination. Repeat to get wraparound.
1263 for(int i = data[0].total - 1; i >= 0; i--)
1265 BC_ListBoxItem *current_item = data[0].values[i];
1266 if(current_item->get_sublist() &&
1267 current_item->get_expand())
1269 int result = select_previous(skip,
1272 current_item->get_sublist(),
1284 if((*counter) >= skip)
1286 for(int j = 0; j < columns; j++)
1287 data[j].values[i]->selected = 1;
1289 return item_to_index(this->data, current_item);
1294 if(current_item->selected)
1296 for(int j = 0; j < columns; j++)
1297 data[j].values[i]->selected = 0;
1304 // Hit bottom of top level without finding a selected item.
1305 if(top_level && !(*got_first)) (*got_first) = 1;
1306 }while(top_level && data[0].total);
1310 int BC_ListBox::select_next(int skip,
1311 BC_ListBoxItem *selected_item,
1313 ArrayList<BC_ListBoxItem*> *data,
1319 selected_item = get_selection(0, 0);
1331 got_second = &temp3;
1336 // Scan backwards to item pointer. Then count visible items to get
1337 // destination. Repeat to get wraparound.
1340 for(int i = 0; i < data[0].total; i++)
1342 BC_ListBoxItem *current_item = data[0].values[i];
1346 if((*counter) >= skip)
1348 for(int j = 0; j < columns; j++)
1349 data[j].values[i]->selected = 1;
1351 return item_to_index(this->data, current_item);
1356 if(current_item->selected)
1358 for(int j = 0; j < columns; j++)
1359 data[j].values[i]->selected = 0;
1365 if(current_item->get_sublist() &&
1366 current_item->get_expand())
1368 int result = select_next(skip,
1371 current_item->get_sublist(),
1381 // Hit bottom of top level without finding a selected item.
1382 if(top_level && !(*got_first)) (*got_first) = 1;
1383 }while(top_level && data[0].total);
1388 void BC_ListBox::fix_positions()
1390 if(yposition < 0) yposition = 0;
1392 if(yposition > get_items_height(data, columns) - view_h)
1393 yposition = get_items_height(data, columns) - view_h;
1395 if(yposition < 0) yposition = 0;
1397 if(xposition < 0) xposition = 0;
1399 if(xposition >= get_items_width() - view_w)
1400 xposition = get_items_width() - view_w;
1402 if(xposition < 0) xposition = 0;
1405 int BC_ListBox::center_selection(int selection,
1406 ArrayList<BC_ListBoxItem*> *data,
1410 if(!data) data = this->data;
1411 if(!counter) counter = &temp;
1413 for(int i = 0; i < data[0].total; i++)
1418 BC_ListBoxItem *item = data[0].values[i];
1419 if((*counter) == selection)
1421 BC_ListBoxItem *top_item = this->data[0].values[0];
1424 if(display_format == LISTBOX_ICONS)
1426 // Icon is out of window
1427 if(item->icon_y - yposition >
1428 view_h - get_text_height(MEDIUMFONT) ||
1429 item->icon_y - yposition < 0)
1431 yposition = item->icon_y - view_h / 2;
1434 if(data[0].values[selection]->icon_x - xposition > view_w ||
1435 data[0].values[selection]->icon_x - xposition < 0)
1437 xposition = item->icon_x - view_w / 2;
1441 if(display_format == LISTBOX_TEXT)
1443 // Text coordinate is out of window
1444 if(item->text_y - yposition >
1445 view_h - get_text_height(MEDIUMFONT) ||
1446 item->text_y - yposition < 0)
1448 yposition = item->text_y -
1457 if(item->get_sublist())
1459 int result = center_selection(selection,
1460 item->get_sublist(),
1462 if(result) return result;
1468 void BC_ListBox::update_scrollbars()
1470 int h_needed = get_items_height(data, columns);
1471 int w_needed = get_items_width();
1475 if(xposition != xscrollbar->get_value())
1476 xscrollbar->update_value(xposition);
1478 if(w_needed != xscrollbar->get_length() || view_w != xscrollbar->get_handlelength())
1479 xscrollbar->update_length(w_needed, xposition, view_w);
1484 if(yposition != yscrollbar->get_value())
1485 yscrollbar->update_value(yposition);
1487 if(h_needed != yscrollbar->get_length() || view_h != yscrollbar->get_handlelength())
1488 yscrollbar->update_length(h_needed, yposition, view_h);
1494 void BC_ListBox::set_drag_scroll(int value)
1496 allow_drag_scroll = value;
1500 // Test for scrolling by dragging
1502 void BC_ListBox::test_drag_scroll(int &redraw, int cursor_x, int cursor_y)
1504 int top_boundary = 2;
1505 if(display_format == LISTBOX_TEXT && column_titles)
1506 top_boundary += title_h;
1508 if(!allow_drag_scroll) return;
1510 if(current_operation == BCLISTBOX_DRAG_DIVISION) return;
1512 if(cursor_y < top_boundary)
1514 yposition -= top_boundary - cursor_y;
1518 if(cursor_y >= view_h + title_h + 4)
1520 yposition += cursor_y - (view_h + title_h + 4);
1526 xposition -= 2 - cursor_x;
1530 if(cursor_x >= view_w + 2)
1532 xposition += cursor_x - (view_w + 2);
1539 int BC_ListBox::select_rectangle(ArrayList<BC_ListBoxItem*> *data,
1546 for(int i = 0; i < data[0].total; i++)
1548 for(int j = 0; j < columns; j++)
1550 BC_ListBoxItem *item = data[j].values[i];
1551 if(display_format == LISTBOX_ICONS)
1553 int icon_x, icon_y, icon_w, icon_h;
1554 int text_x, text_y, text_w, text_h;
1555 get_icon_mask(item, icon_x, icon_y, icon_w, icon_h);
1556 get_text_mask(item, text_x, text_y, text_w, text_h);
1558 if((x2 >= icon_x && x1 < icon_x + icon_w &&
1559 y2 >= icon_y && y1 < icon_y + icon_h) ||
1560 (x2 >= text_x && x1 < text_x + text_w &&
1561 y2 >= text_y && y1 < text_y + text_h))
1582 gui->get_w() - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w() :
1585 y1 < gui->get_h() &&
1586 y2 >= get_item_y(item) &&
1587 y1 < get_item_y(item) + get_item_h(item))
1606 BC_ListBoxItem *item = data[0].values[i];
1607 if(item->get_sublist() &&
1609 result |= select_rectangle(item->get_sublist(),
1618 int BC_ListBox::reposition_item(ArrayList<BC_ListBoxItem*> *data,
1619 int selection_number,
1625 if(!counter) counter = &temp;
1628 for(int i = 0; i < data[0].total; i++)
1630 BC_ListBoxItem *item = data[0].values[i];
1632 if((*counter) == selection_number)
1638 // Not recursive because it's only used for icons
1643 void BC_ListBox::move_selection(ArrayList<BC_ListBoxItem*> *dst,
1644 ArrayList<BC_ListBoxItem*> *src)
1646 for(int i = 0; i < src[0].total; i++)
1648 BC_ListBoxItem *item = src[0].values[i];
1653 for(int j = 0; j < columns; j++)
1655 dst[j].append(src[j].values[i]);
1656 src[j].remove_number(i);
1660 // Descend into sublist
1661 if(item->get_sublist())
1664 item->get_sublist());
1669 int BC_ListBox::put_selection(ArrayList<BC_ListBoxItem*> *data,
1670 ArrayList<BC_ListBoxItem*> *src,
1675 if(!counter) counter = &temp;
1679 for(int j = 0; j < columns; j++)
1681 for(int i = 0; i < src[0].total; i++)
1683 data[j].append(src[j].values[i]);
1689 for(int i = 0; i < data[0].total; i++)
1692 if((*counter) == destination)
1694 for(int j = 0; j < columns; j++)
1696 for(int k = 0; k < src[0].total; k++)
1698 data[j].insert(src[j].values[k], destination + k);
1704 BC_ListBoxItem *item = data[0].values[i];
1705 if(item->get_sublist())
1707 if(put_selection(item->get_sublist(),
1719 int BC_ListBox::item_to_index(ArrayList<BC_ListBoxItem*> *data,
1720 BC_ListBoxItem *item,
1724 if(!counter) counter = &temp;
1726 for(int i = 0; i < data[0].total; i++)
1729 for(int j = 0; j < columns; j++)
1731 BC_ListBoxItem *new_item = data[j].values[i];
1732 if(new_item == item)
1738 BC_ListBoxItem *new_item = data[0].values[i];
1739 if(new_item->get_sublist())
1741 if(item_to_index(new_item->get_sublist(),
1750 BC_ListBoxItem* BC_ListBox::index_to_item(ArrayList<BC_ListBoxItem*> *data,
1756 if(!counter) counter = &temp;
1757 for(int i = 0; i < data[0].total; i++)
1760 if((*counter) == number)
1762 return data[column].values[i];
1764 BC_ListBoxItem *item = data[0].values[i];
1765 if(item->get_sublist())
1767 BC_ListBoxItem *result = index_to_item(item->get_sublist(),
1771 if(result) return result;
1777 int BC_ListBox::cursor_item(ArrayList<BC_ListBoxItem*> *data,
1780 BC_ListBoxItem **item_return,
1785 if(!data) return -1;
1786 if(!counter) counter = &temp;
1788 // Icons are not treed
1789 if(display_format == LISTBOX_ICONS)
1791 for(int j = data[0].total - 1; j >= 0; j--)
1793 int icon_x, icon_y, icon_w, icon_h;
1794 int text_x, text_y, text_w, text_h;
1795 BC_ListBoxItem *item = data[0].values[j];
1796 get_icon_mask(item, icon_x, icon_y, icon_w, icon_h);
1797 get_text_mask(item, text_x, text_y, text_w, text_h);
1799 if((cursor_x >= icon_x && cursor_x < icon_x + icon_w &&
1800 cursor_y >= icon_y && cursor_y < icon_y + icon_h) ||
1801 (cursor_x >= text_x && cursor_x < text_x + text_w &&
1802 cursor_y >= text_y && cursor_y < text_y + text_h))
1804 if(item_return) (*item_return) = item;
1811 if(display_format == LISTBOX_TEXT)
1813 // Cursor is inside item rectangle
1815 cursor_x < (yscrollbar ?
1816 gui->get_w() - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w() :
1819 cursor_y < gui->get_h())
1821 // Search table for cursor obstruction
1822 for(int i = 0; i < data[0].total; i++)
1824 BC_ListBoxItem *item = data[0].values[i];
1827 // Cursor is inside item on current level
1830 cursor_y >= get_item_y(item) &&
1831 cursor_y < get_item_y(item) + get_item_h(item))
1833 if(item_return) (*item_return) = item;
1837 // Descend into sublist
1838 if(item->get_sublist())
1840 if(cursor_item(item->get_sublist(),
1845 item->get_expand()) >= 0)
1854 int BC_ListBox::repeat_event(int64_t duration)
1856 if(duration == top_level->get_resources()->tooltip_delay &&
1857 tooltip_text[0] != 0 &&
1859 status == LISTBOX_HIGH &&
1870 int BC_ListBox::cursor_enter_event()
1874 // if(active) result = 1;
1878 if(top_level->event_win == win)
1881 if(top_level->button_down)
1883 status = LISTBOX_DN;
1886 if(status == LISTBOX_UP)
1888 status = LISTBOX_HIGH;
1890 //printf("BC_ListBox::cursor_enter_event 1\n");
1896 if(gui && top_level->event_win == gui->win)
1900 //printf("BC_ListBox::cursor_enter_event 2\n");
1910 int BC_ListBox::cursor_leave_event()
1915 if(status == LISTBOX_HIGH)
1917 status = LISTBOX_UP;
1922 if(gui && highlighted)
1927 highlighted_ptr = 0;
1928 highlighted_item = -1;
1938 int BC_ListBox::get_first_selection(ArrayList<BC_ListBoxItem*> *data, int *result)
1941 if(!result) result = &temp;
1943 for(int i = 0; i < data[0].total; i++)
1945 BC_ListBoxItem *item = data[0].values[i];
1947 if(item->selected) return (*result);
1948 if(item->get_sublist())
1950 if(get_first_selection(item->get_sublist(), result) >= 0)
1957 int BC_ListBox::get_total_items(ArrayList<BC_ListBoxItem*> *data, int *result)
1960 if(!result) result = &temp;
1962 for(int i = 0; i < data[0].total; i++)
1965 if(data[0].values[i]->get_sublist())
1966 get_total_items(data[0].values[i]->get_sublist(), result);
1973 int BC_ListBox::get_last_selection(ArrayList<BC_ListBoxItem*> *data, int *result)
1983 for(int i = data[0].total - 1; i >= 0; i--)
1985 BC_ListBoxItem *item = data[0].values[i];
1990 return get_total_items(data) - (*result) /* - 1 */;
1995 if(item->get_sublist())
1997 if(get_last_selection(item->get_sublist(), result) >= 0)
2000 return get_total_items(data) - (*result) /* - 1 */;
2009 void BC_ListBox::select_range(ArrayList<BC_ListBoxItem*> *data,
2015 if(!current) current = &temp;
2017 for(int i = 0; i < data[0].total; i++)
2020 if((*current) >= start && (*current) < end)
2022 for(int j = 0; j < columns; j++)
2023 data[j].values[i]->selected = 1;
2025 BC_ListBoxItem *item = data[0].values[i];
2026 if(item->get_sublist())
2027 select_range(item->get_sublist(),
2035 // Fill items between current selection and new selection
2036 int BC_ListBox::expand_selection(int button_press, int selection_number)
2038 int old_selection_start = selection_start;
2039 int old_selection_end = selection_end;
2041 //printf("BC_ListBox::expand_selection %d %d\n", selection_center, selection_number);
2043 // Calculate the range to select based on selection_center and selection_number
2044 if(selection_number < selection_center)
2046 selection_start = selection_number;
2050 selection_end = selection_number + 1;
2053 //printf("BC_ListBox::expand_selection %d %d %d %d\n", old_selection_start, old_selection_end, selection_start, selection_end);
2054 // Recurse through all the items and select the desired range
2055 select_range(data, selection_start, selection_end);
2058 return (old_selection_start != selection_start ||
2059 old_selection_end != selection_end);
2062 int BC_ListBox::toggle_item_selection(ArrayList<BC_ListBoxItem*> *data,
2063 int selection_number,
2067 if(!counter) counter = &temp;
2069 for(int i = 0; i < data[0].total; i++)
2071 BC_ListBoxItem *item = data[0].values[i];
2073 if((*counter) == selection_number)
2075 // Get new value for selection
2076 int selected = !item->selected;
2078 for(int j = 0; j < columns; j++)
2079 data[j].values[i]->selected = selected;
2083 // Descend into sublist
2084 if(item->get_sublist())
2086 if(toggle_item_selection(item->get_sublist(),
2097 void BC_ListBox::set_all_selected(ArrayList<BC_ListBoxItem*> *data, int value)
2099 for(int i = 0; i < data[0].total; i++)
2101 for(int j = 0; j < columns; j++)
2103 BC_ListBoxItem *item = data[j].values[i];
2104 item->selected = value;
2106 BC_ListBoxItem *item = data[0].values[i];
2107 if(item->get_sublist())
2109 set_all_selected(item->get_sublist(), value);
2114 void BC_ListBox::set_selected(ArrayList<BC_ListBoxItem*> *data,
2120 if(!counter) counter = &temp;
2121 for(int i = 0; i < data[0].total && (*counter) != item_number; i++)
2124 if((*counter) == item_number)
2126 for(int j = 0; j < columns; j++)
2128 BC_ListBoxItem *item = data[j].values[i];
2129 item->selected = value;
2134 BC_ListBoxItem *item = data[0].values[i];
2135 if(item->get_sublist())
2137 set_selected(item->get_sublist(),
2145 int BC_ListBox::update_selection(ArrayList<BC_ListBoxItem*> *data,
2146 int selection_number,
2151 if(!counter) counter = &temp;
2153 for(int i = 0; i < data[0].total; i++)
2155 BC_ListBoxItem *item = data[0].values[i];
2157 if((*counter) == selection_number && !item->selected)
2160 for(int j = 0; j < columns; j++)
2161 data[j].values[i]->selected = 1;
2164 if((*counter) != selection_number && item->selected)
2167 for(int j = 0; j < columns; j++)
2168 data[j].values[i]->selected = 0;
2170 if(item->get_sublist())
2171 result |= update_selection(item->get_sublist(),
2178 void BC_ListBox::promote_selections(ArrayList<BC_ListBoxItem*> *data,
2182 for(int i = 0; i < data[0].total; i++)
2184 for(int j = 0; j < columns; j++)
2186 BC_ListBoxItem *item = data[j].values[i];
2187 if(item->selected == old_value) item->selected = new_value;
2189 BC_ListBoxItem *item = data[0].values[i];
2190 if(item->get_sublist())
2191 promote_selections(item->get_sublist(), old_value, new_value);
2195 int BC_ListBox::button_press_event()
2200 selection_number = -1;
2204 if(top_level->event_win == win)
2206 status = LISTBOX_DN;
2211 top_level->deactivate();
2218 if((xscrollbar && top_level->event_win == xscrollbar->win) ||
2219 (yscrollbar && top_level->event_win == yscrollbar->win) ||
2220 (gui && top_level->event_win == gui->win))
2232 if(gui && top_level->event_win == gui->win)
2236 top_level->deactivate();
2240 // Wheel mouse behavior
2241 if(get_buttonpress() == 4)
2243 current_operation = BCLISTBOX_WHEEL;
2246 set_yposition(yposition - gui->get_h() / 10, 0);
2248 update_scrollbars();
2249 highlighted_ptr = 0;
2250 highlighted_item = cursor_item(data,
2251 top_level->cursor_x,
2252 top_level->cursor_y,
2260 if(get_buttonpress() == 5)
2262 current_operation = BCLISTBOX_WHEEL;
2265 set_yposition(yposition + gui->get_h() / 10, 0);
2267 update_scrollbars();
2268 highlighted_ptr = 0;
2269 highlighted_item = cursor_item(data,
2270 top_level->cursor_x,
2271 top_level->cursor_y,
2280 // Get item button was pressed over
2282 BC_ListBoxItem *current_item = 0;
2283 selection_number2 = selection_number1;
2284 selection_number1 = selection_number = cursor_item(data,
2285 top_level->cursor_x,
2286 top_level->cursor_y,
2289 // Pressed over a title division
2290 if(test_divisions(gui->get_cursor_x(),
2291 gui->get_cursor_y(),
2294 current_operation = BCLISTBOX_DRAG_DIVISION;
2298 // Pressed over an item
2301 selection_start = -1;
2305 // Multiple item selection is possible
2306 if(selection_mode == LISTBOX_MULTIPLE &&
2307 (ctrl_down() || shift_down()))
2309 // Expand text selection.
2310 // Fill items between selected region and current item.
2311 if(shift_down() && display_format == LISTBOX_TEXT)
2313 // Get first item selected
2314 selection_start = get_first_selection(data);
2315 // Get last item selected
2316 selection_end = get_last_selection(data);
2317 // Get center of selected region
2318 if(selection_end > selection_start)
2320 selection_center = (selection_end + selection_start) >> 1;
2324 selection_center = selection_number;
2328 // Deselect everything.
2329 set_all_selected(data, 0);
2330 // Select just the items
2331 expand_selection(1, selection_number);
2335 // Toggle a single item on or off
2337 toggle_item_selection(data, selection_number);
2338 new_value = current_item->selected;
2340 current_operation = BCLISTBOX_SELECT;
2343 // Select single item
2345 if(!current_item->selected)
2347 set_all_selected(data, 0);
2352 current_operation = BCLISTBOX_SELECT;
2357 highlighted_item = -1;
2358 highlighted_ptr = 0;
2365 // Pressed over nothing
2367 if(get_buttonpress() == 1 &&
2368 selection_mode == LISTBOX_MULTIPLE)
2372 // Deselect all and redraw if anything was selected
2373 if(get_selection_number(0, 0) >= 0)
2375 set_all_selected(data, 0);
2382 // Promote selections to protect from a rectangle selection
2383 promote_selections(data, 1, 2);
2386 // Start rectangle selection
2387 current_operation = BCLISTBOX_SELECT_RECT;
2388 rect_x1 = rect_x2 = get_cursor_x();
2389 rect_y1 = rect_y2 = get_cursor_y();
2396 if(!popup && active)
2406 selection_changed();
2412 int BC_ListBox::button_release_event()
2415 int cursor_x, cursor_y;
2418 if(current_operation == BCLISTBOX_WHEEL)
2420 current_operation = BCLISTBOX_NO_OPERATION;
2424 if(current_operation == BCLISTBOX_SELECT_RECT)
2428 // Demote selections from rectangle selection
2429 promote_selections(data, 2, 1);
2432 // Hide rectangle overlay
2438 current_operation = BCLISTBOX_NO_OPERATION;
2445 if(status == LISTBOX_DN)
2447 status = LISTBOX_HIGH;
2452 // Second button release inside button
2453 if(top_level->event_win == win &&
2455 button_releases > 1)
2460 // First button release inside button
2462 if(top_level->event_win == win && cursor_inside())
2466 // Button released in popup window
2469 (top_level->event_win == win || top_level->event_win == gui->win))
2472 XTranslateCoordinates(top_level->display,
2473 top_level->event_win,
2475 top_level->cursor_x,
2476 top_level->cursor_y,
2481 selection_number = cursor_item(data,
2485 if(selection_number >= 0)
2492 // Button release outside all ranges
2503 top_level->event_win == gui->win &&
2504 top_level->get_double_click() &&
2505 selection_number2 == selection_number1 &&
2506 selection_number2 >= 0 &&
2507 selection_number1 >= 0)
2516 int BC_ListBox::get_title_h()
2518 if(display_format != LISTBOX_ICONS)
2519 return column_titles ? (get_text_height(MEDIUMFONT) + 4) : 0;
2524 void BC_ListBox::reset_cursor(int new_cursor)
2528 if(gui->get_cursor() != new_cursor)
2530 gui->set_cursor(new_cursor);
2534 if(get_cursor() != new_cursor)
2536 set_cursor(new_cursor);
2540 int BC_ListBox::test_divisions(int cursor_x, int cursor_y, int &new_cursor)
2542 if(column_titles && cursor_y < get_title_h())
2544 for(int i = 1; i < columns; i++)
2546 if(cursor_x > -xposition + get_column_offset(i) - 5 &&
2547 cursor_x < -xposition + get_column_offset(i) + 5)
2549 highlighted_division = i;
2550 new_cursor = HSEPARATE_CURSOR;
2558 int BC_ListBox::cursor_motion_event()
2560 int redraw = 0, result = 0;
2561 int cursor_x = 0, cursor_y = 0;
2562 int new_cursor = ARROW_CURSOR;
2564 selection_number = -1;
2567 top_level->event_win == win &&
2568 status == LISTBOX_DN &&
2571 status = LISTBOX_UP;
2576 (top_level->event_win == win ||
2577 (popup && top_level->event_win == gui->win)))
2580 // For some reason XTranslateCoordinates can take a long time to return.
2581 // We work around this by only calling it when the event windows are different.
2582 translate_coordinates(top_level->event_win,
2584 top_level->cursor_x,
2585 top_level->cursor_y,
2590 int old_highlighted_item = highlighted_item;
2591 BC_ListBoxItem *old_highlighted_ptr = highlighted_ptr;
2592 highlighted_item = -1;
2593 highlighted_ptr = 0;
2594 highlighted_item = selection_number = cursor_item(data,
2599 //printf("BC_ListBox::cursor_motion_event %p %p\n", old_highlighted_item, highlighted_item);
2601 // Cursor just moved in after pressing popup button
2603 top_level->get_button_down() &&
2604 selection_number >= 0 && current_operation != BCLISTBOX_SELECT)
2605 current_operation = BCLISTBOX_SELECT;
2607 // Moving column division
2608 if(current_operation == BCLISTBOX_DRAG_DIVISION &&
2609 top_level->get_button_down())
2611 new_cursor = HSEPARATE_CURSOR;
2612 int new_w = cursor_x + xposition - get_column_offset(highlighted_division - 1);
2613 //printf("BC_ListBox::cursor_motion_event 1 %d\n", new_w);
2617 column_width[highlighted_division - 1] = new_w;
2621 default_column_width[highlighted_division - 1] = new_w;
2624 column_width_boundaries();
2626 // Force update of coords
2627 set_autoplacement(data, 0, 1);
2628 column_resize_event();
2633 // Cursor is inside and selecting an item
2634 if(selection_number >= 0 &&
2635 current_operation == BCLISTBOX_SELECT &&
2638 // Deselect all items and select just the one we're over
2639 if(selection_mode == LISTBOX_SINGLE ||
2643 redraw = update_selection(data, selection_number);
2646 // Expand multiple selection
2648 // Expand selected region in text mode centered around initial range
2649 if(display_format == LISTBOX_TEXT && shift_down())
2651 // Deselect everything.
2652 set_all_selected(data, 0);
2653 // Select just the items
2655 redraw = expand_selection(0, selection_number);
2658 // Set the one item we're over to the selection value determined in
2659 // button_press_event.
2668 if(current_operation == BCLISTBOX_SELECT_RECT)
2671 rect_x2 = get_cursor_x();
2672 rect_y2 = get_cursor_y();
2673 // Adjust rectangle coverage
2676 int x1 = MIN(rect_x1, rect_x2);
2677 int x2 = MAX(rect_x1, rect_x2);
2678 int y1 = MIN(rect_y1, rect_y2);
2679 int y2 = MAX(rect_y1, rect_y2);
2681 redraw = select_rectangle(data,
2689 // Refresh just rectangle
2698 // Test if cursor moved over a title division
2700 test_divisions(cursor_x, cursor_y, new_cursor);
2703 if(top_level->get_button_down() &&
2704 current_operation == BCLISTBOX_SELECT)
2706 test_drag_scroll(redraw, cursor_x, cursor_y);
2709 if(highlighted_item != old_highlighted_item)
2715 // Change cursor to title division adjustment
2716 reset_cursor(new_cursor);
2721 //printf("BC_ListBox::cursor_motion_event 50 %d %d %p\n", redraw, result, highlighted_item);
2728 update_scrollbars();
2731 if(current_operation == BCLISTBOX_SELECT) selection_changed();
2735 if(!result && highlighted_item >= 0)
2737 highlighted_item = -1;
2738 highlighted_ptr = 0;
2745 //printf("BC_ListBox::cursor_motion_event 100\n");
2749 int BC_ListBox::drag_start_event()
2752 top_level->event_win == gui->win &&
2754 current_operation != BCLISTBOX_DRAG_DIVISION)
2756 BC_ListBoxItem *item_return = 0;
2757 selection_number = cursor_item(data,
2758 top_level->cursor_x,
2759 top_level->cursor_y,
2762 if(selection_number >= 0)
2764 BC_Pixmap *pixmap = item_return->icon ?
2767 drag_popup = new BC_DragWindow(this,
2769 get_abs_cursor_x() - pixmap->get_w() / 2,
2770 get_abs_cursor_y() - pixmap->get_h() / 2);
2777 int BC_ListBox::drag_motion_event()
2782 test_drag_scroll(redraw,
2783 top_level->cursor_x,
2784 top_level->cursor_y);
2786 int new_highlighted_item = -1;
2787 BC_ListBoxItem *new_highlighted_ptr = 0;
2788 int new_highlight = new_highlighted_item = cursor_item(data,
2789 top_level->cursor_x,
2790 top_level->cursor_y,
2791 &new_highlighted_ptr);
2793 //printf("BC_ListBox::drag_motion_event %d %d %d\n",
2794 // top_level->cursor_x, top_level->cursor_y, new_highlight);
2795 if(new_highlighted_item != highlighted_item)
2798 highlighted_item = new_highlighted_item;
2799 highlighted_ptr = new_highlighted_ptr;
2806 update_scrollbars();
2810 return drag_popup->cursor_motion_event();
2816 int BC_ListBox::drag_stop_event()
2820 // Inside window boundary
2821 if(top_level->cursor_x > 0 &&
2822 top_level->cursor_x < gui->get_w() - drag_popup->get_w() / 2 &&
2823 top_level->cursor_y > 0 &&
2824 top_level->cursor_y < gui->get_h() - drag_popup->get_h() / 2)
2829 if(display_format == LISTBOX_ICONS)
2831 reposition_item(data,
2833 top_level->cursor_x +
2834 drag_popup->get_offset_x() -
2838 top_level->cursor_y +
2839 drag_popup->get_offset_y() -
2847 // Move selected items from data to temporary
2848 ArrayList<BC_ListBoxItem*> *src_items =
2849 new ArrayList<BC_ListBoxItem*>[columns];
2850 move_selection(src_items, data);
2852 // Insert items from temporary to data
2853 int destination = highlighted_item = item_to_index(data,
2860 delete [] src_items;
2861 set_autoplacement(data, 0, 1);
2869 drag_popup->drag_failure_event();
2873 current_operation = BCLISTBOX_NO_OPERATION;
2880 BC_DragWindow* BC_ListBox::get_drag_popup()
2885 int BC_ListBox::translation_event()
2889 int new_x = gui->get_x() +
2890 (top_level->last_translate_x -
2892 top_level->get_resources()->get_left_border());
2893 int new_y = gui->get_y() +
2894 (top_level->last_translate_y -
2896 top_level->get_resources()->get_top_border());
2898 gui->reposition_window(new_x, new_y);
2904 int BC_ListBox::reposition_window(int x, int y, int w, int h)
2908 if(w != -1) popup_w = w;
2909 if(h != -1) popup_h = h;
2910 //printf("BC_ListBox::reposition_window %d %d\n", popup_w, popup_h);
2914 if(w != -1) popup_w = w;
2915 if(h != -1) popup_h = h;
2917 xscrollbar->reposition_window(get_xscroll_x(),
2919 get_xscroll_width());
2921 yscrollbar->reposition_window(get_yscroll_x(),
2923 get_yscroll_height());
2928 BC_WindowBase::reposition_window(x, y, w, h);
2935 int BC_ListBox::deactivate()
2946 highlighted_item = -1;
2947 highlighted_ptr = 0;
2949 top_level->active_subwindow = 0;
2954 int BC_ListBox::activate()
2958 top_level->active_subwindow = this;
2960 button_releases = 0;
2966 XTranslateCoordinates(top_level->display,
2969 get_x() - popup_w + get_w(),
2975 if(new_x < 0) new_x = 0;
2976 if(new_y + popup_h > top_level->get_root_h()) new_y -= get_h() + popup_h;
2978 //printf("BC_ListBox::activate %d %d\n", popup_w, popup_h);
2979 add_subwindow(gui = new BC_Popup(this,
2988 //printf("BC_ListBox::activate 1\n");
2995 int BC_ListBox::keypress_event()
2997 if(!active) return 0;
2999 int result = 0, redraw = 0, done, view_items = view_h / get_text_height(MEDIUMFONT);
3000 int new_item = -1, new_selection = 0;
3002 switch(top_level->get_keypress())
3006 top_level->deactivate();
3011 new_selection = new_item = select_previous(0);
3013 //printf("BC_ListBox::keypress_event 1 %d\n", new_item);
3016 center_selection(new_item);
3023 new_selection = new_item = select_next(0);
3027 center_selection(new_item);
3034 new_selection = new_item = select_previous(view_items - 1);
3038 center_selection(new_item);
3045 new_selection = new_item = select_next(view_items - 1);
3049 center_selection(new_item);
3070 if(top_level->get_keypress() > 30 &&
3071 top_level->get_keypress() < 127)
3073 int query_len = strlen(query);
3074 query[query_len++] = top_level->get_keypress();
3075 query[query_len] = 0;
3076 new_selection = query_list();
3079 if(top_level->get_keypress() == BACKSPACE)
3081 int query_len = strlen(query);
3082 if(query_len > 0) query[--query_len] = 0;
3083 new_selection = query_list();
3096 update_scrollbars();
3100 if(new_selection >= 0)
3102 selection_changed();
3108 int BC_ListBox::get_scrollbars()
3110 int h_needed = get_items_height(data, columns);
3111 int w_needed = get_items_width();
3115 title_h = get_title_h();
3117 view_h = popup_h - title_h - 4;
3118 view_w = popup_w - 4;
3120 // Create scrollbars as needed
3121 for(int i = 0; i < 2; i++)
3123 if(w_needed > view_w)
3128 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h() -
3136 if(h_needed > view_h)
3140 get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w() -
3149 // Update subwindow size
3150 int new_w = popup_w;
3151 int new_h = popup_h;
3152 if(need_xscroll) new_h -= get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h();
3153 if(need_yscroll) new_w -= get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w();
3156 if(new_w != BC_WindowBase::get_w() || new_h != BC_WindowBase::get_h())
3157 gui->resize_window(new_w, new_h);
3159 BC_WindowBase *destination = (popup ? gui : parent_window);
3164 destination->add_subwindow(xscrollbar =
3165 new BC_ListBoxXScroll(this,
3169 xscrollbar->bound_to = this;
3172 xscrollbar->reposition_window(get_xscroll_x(),
3174 get_xscroll_width());
3178 if(xscrollbar) delete xscrollbar;
3187 destination->add_subwindow(yscrollbar =
3188 new BC_ListBoxYScroll(this,
3192 yscrollbar->bound_to = this;
3195 yscrollbar->reposition_window(get_yscroll_x(),
3197 get_yscroll_height());
3201 if(yscrollbar) delete yscrollbar;
3207 view_w + 4 != bg_surface->get_w() ||
3208 view_h + 4 != bg_surface->get_h())
3210 if(bg_surface) delete bg_surface;
3211 bg_surface = new BC_Pixmap(gui, view_w + 4, view_h + 4);
3218 BC_Pixmap* BC_ListBox::get_bg_surface()
3224 void BC_ListBox::draw_background()
3226 // White background pixmap
3228 draw_box(0, 0, bg_surface->get_w(), bg_surface->get_h(), bg_surface);
3230 // Optional heroine pixmap
3232 bg_surface->draw_pixmap(bg_pixmap,
3233 bg_surface->get_w() - top_level->get_resources()->listbox_bg->get_w(),
3237 void BC_ListBox::clear_listbox(int x, int y, int w, int h)
3239 gui->draw_pixmap(bg_surface,
3248 void BC_ListBox::update_format(int display_format, int redraw)
3250 this->display_format = display_format;
3254 if(gui) gui->flash();
3258 int BC_ListBox::get_format()
3260 return display_format;
3265 int BC_ListBox::draw_items()
3269 //dump(data, columns);
3271 // Calculate items width
3272 calculate_item_coords();
3275 // Create and destroy scrollbars as needed
3280 // draw_background();
3283 if(display_format == LISTBOX_ICONS)
3285 clear_listbox(2, 2 + title_h, view_w, view_h);
3287 set_font(MEDIUMFONT);
3288 for(int i = 0; i < data[0].total; i++)
3290 BC_ListBoxItem *item = data[0].values[i];
3291 if(get_item_x(item) >= -get_item_w(item) &&
3292 get_item_x(item) < view_w &&
3293 get_item_y(item) >= -get_item_h(item) + title_h &&
3294 get_item_y(item) < view_h + title_h)
3296 int item_color = get_item_highlight(data, 0, i);
3297 int icon_x, icon_y, icon_w, icon_h;
3298 int text_x, text_y, text_w, text_h;
3301 get_icon_mask(item, icon_x, icon_y, icon_w, icon_h);
3302 get_text_mask(item, text_x, text_y, text_w, text_h);
3304 if(item_color != WHITE)
3306 gui->set_color(BLACK);
3307 gui->draw_rectangle(icon_x, icon_y, icon_w, icon_h);
3308 gui->set_color(item_color);
3309 gui->draw_box(icon_x + 1, icon_y + 1, icon_w - 2, icon_h - 2);
3310 gui->set_color(BLACK);
3311 gui->draw_rectangle(text_x, text_y, text_w, text_h);
3312 gui->set_color(item_color);
3313 gui->draw_box(text_x + 1, text_y + 1, text_w - 2, text_h - 2);
3315 if(icon_position == ICON_LEFT)
3316 gui->draw_box(text_x - 1, text_y + 1, 2, text_h - 2);
3318 if(icon_position == ICON_TOP)
3319 gui->draw_line(text_x + 1, text_y, text_x + icon_w - 2, text_y);
3323 gui->set_color(get_item_color(data, 0, i));
3325 item->icon->write_drawable(gui->pixmap,
3326 icon_x + ICON_MARGIN,
3327 icon_y + ICON_MARGIN);
3328 gui->draw_text(text_x + ICON_MARGIN,
3329 text_y + ICON_MARGIN + get_text_ascent(MEDIUMFONT),
3336 if(display_format == LISTBOX_TEXT)
3338 // Draw one column at a time so text overruns don't go into the next column
3339 // clear column backgrounds
3340 int current_toggle = 0;
3341 for(int j = 0; j < columns; j++)
3343 clear_listbox(LISTBOX_BORDER + get_column_offset(j) - xposition,
3344 LISTBOX_BORDER + title_h,
3345 get_column_width(j, 1),
3348 // Draw rows in the column recursively
3349 draw_text_recursive(data, j, 0, ¤t_toggle);
3352 // Delete excess expanders
3353 while(expanders.total > current_toggle)
3355 expanders.remove_object();
3359 // Draw titles on top of rows for superposition effect
3360 if(column_titles && display_format != LISTBOX_ICONS)
3362 for(int i = 0; i < columns; i++)
3364 gui->draw_3d_box(get_column_offset(i) - xposition + 2,
3366 get_column_width(i, 1),
3368 top_level->get_resources()->button_light,
3369 top_level->get_resources()->button_up,
3370 top_level->get_resources()->button_up,
3371 top_level->get_resources()->button_shadow,
3374 gui->set_color(BLACK);
3375 gui->draw_text(-xposition + get_column_offset(i) + LISTBOX_MARGIN + 2,
3376 2 + get_text_ascent(MEDIUMFONT), column_titles[i]);
3380 // Clear garbage from bottom right corner
3381 if(xscrollbar && yscrollbar && popup)
3383 gui->draw_top_background(parent_window,
3384 popup_w - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w(),
3385 popup_h - get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h(),
3386 get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w(),
3387 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h());
3394 if(current_operation == BCLISTBOX_SELECT_RECT)
3402 void BC_ListBox::draw_text_recursive(ArrayList<BC_ListBoxItem*> *data,
3405 int *current_toggle)
3409 set_font(MEDIUMFONT);
3412 // Search for a branch and make room for toggle if there is one
3415 for(int i = 0; i < data[column].total; i++)
3417 if(data[column].values[i]->get_sublist())
3419 subindent = BC_WindowBase::get_resources()->listbox_expand[0]->get_w();
3425 for(int i = 0; i < data[column].total; i++)
3428 BC_ListBoxItem *item = data[column].values[i];
3429 BC_ListBoxItem *first_item = data[0].values[i];
3431 if(get_item_y(item) >= -get_item_h(item) + title_h &&
3432 get_item_y(item) < view_h + title_h)
3434 int row_color = get_item_highlight(data, 0, i);
3435 int x, y, w, h, column_width;
3437 get_text_mask(item, x, y, w, h);
3438 column_width = get_column_width(column, 1);
3439 if(x + column_width > view_w + LISTBOX_BORDER * 2)
3440 column_width = view_w + LISTBOX_BORDER * 2 - x;
3442 if(row_color != WHITE)
3444 gui->set_color(row_color);
3449 gui->set_color(BLACK);
3452 x + column_width - 1,
3455 y + get_text_height(MEDIUMFONT),
3456 x + column_width - 1,
3457 y + get_text_height(MEDIUMFONT));
3460 gui->set_color(get_item_color(data, column, i));
3463 // Indent only applies to first column
3468 (column == 0 ? indent + subindent : 0),
3469 y + get_text_ascent(MEDIUMFONT),
3475 item->get_sublist() &&
3476 item->get_columns())
3478 // Must be below column titles
3479 if(!column_titles || y > get_text_height(MEDIUMFONT))
3484 // Create new expander
3485 if(*current_toggle >= expanders.total)
3487 BC_ListBoxToggle *toggle =
3488 new BC_ListBoxToggle(this,
3490 x + LISTBOX_BORDER + LISTBOX_MARGIN + indent,
3492 gui->add_subwindow(toggle);
3493 expanders.append(toggle);
3496 // Reposition existing expander
3498 BC_ListBoxToggle *toggle = expanders.values[*current_toggle];
3499 toggle->update(item,
3500 x + LISTBOX_BORDER + LISTBOX_MARGIN + indent,
3503 (*current_toggle)++;
3511 // Descend into sublist
3512 if(first_item->get_expand())
3514 draw_text_recursive(first_item->get_sublist(),
3516 indent + LISTBOX_INDENT,
3526 int BC_ListBox::draw_border()
3528 gui->draw_3d_border(0,
3530 view_w + LISTBOX_BORDER * 2,
3531 view_h + title_h + LISTBOX_BORDER * 2,
3532 top_level->get_resources()->button_shadow,
3533 highlighted ? RED : BLACK,
3534 highlighted ? RED : top_level->get_resources()->button_up,
3535 top_level->get_resources()->button_light);
3539 int BC_ListBox::draw_rectangle()
3541 int x1 = MIN(rect_x1, rect_x2);
3542 int x2 = MAX(rect_x1, rect_x2);
3543 int y1 = MIN(rect_y1, rect_y2);
3544 int y2 = MAX(rect_y1, rect_y2);
3546 if(x1 == x2 || y1 == y2) return 0;
3549 gui->set_color(WHITE);
3550 gui->draw_rectangle(x1, y1, x2 - x1, y2 - y1);
3555 void BC_ListBox::dump(ArrayList<BC_ListBoxItem*> *data, int columns, int indent)
3559 printf("BC_ListBox::dump 1\n");
3562 for(int i = 0; i < data[0].total; i++)
3564 for(int k = 0; k < indent; k++)
3566 for(int j = 0; j < columns; j++)
3568 BC_ListBoxItem *item = data[j].values[i];
3569 printf("%d,%d,%d=%s ",
3572 item->autoplace_text,
3577 if(data[0].values[i]->get_sublist())
3579 dump(data[0].values[i]->get_sublist(),
3580 data[0].values[i]->get_columns(),