3 * Copyright (C) 2010-2014 Adam Williams <broadcast at earthling dot net>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "bcdisplayinfo.h"
22 #include "bcdragwindow.h"
23 #include "bclistbox.h"
24 #include "bclistboxitem.h"
26 #include "bcresources.h"
27 #include "bcsignals.h"
39 // ====================================================== scrollbars
41 BC_ListBoxYScroll::BC_ListBoxYScroll(BC_ListBox *listbox)
42 : BC_ScrollBar(listbox->get_yscroll_x(), listbox->get_yscroll_y(),
43 listbox->yscroll_orientation, listbox->get_yscroll_height(),
44 listbox->items_h, listbox->yposition, listbox->view_h)
46 this->listbox = listbox;
49 BC_ListBoxYScroll::~BC_ListBoxYScroll()
53 int BC_ListBoxYScroll::handle_event()
55 listbox->set_yposition(get_value());
59 BC_ListBoxXScroll::BC_ListBoxXScroll(BC_ListBox *listbox)
60 : BC_ScrollBar(listbox->get_xscroll_x(), listbox->get_xscroll_y(),
61 listbox->xscroll_orientation, listbox->get_xscroll_width(),
62 listbox->items_w, listbox->xposition, listbox->view_w)
64 this->listbox = listbox;
67 BC_ListBoxXScroll::~BC_ListBoxXScroll()
71 int BC_ListBoxXScroll::handle_event()
73 listbox->set_xposition(get_value());
78 BC_ListBoxToggle::BC_ListBoxToggle(BC_ListBox *listbox,
83 this->listbox = listbox;
87 this->value = item->get_expand();
89 state = BC_Toggle::TOGGLE_CHECKED;
91 state = BC_Toggle::TOGGLE_UP;
94 void BC_ListBoxToggle::update(BC_ListBoxItem *item,
99 this->value = item->get_expand();
108 state = TOGGLE_CHECKED;
113 state = TOGGLE_CHECKEDHI;
124 case TOGGLE_CHECKEDHI:
129 case TOGGLE_DOWN_EXIT:
137 int BC_ListBoxToggle::cursor_motion_event(int *redraw_toggles)
139 int w = listbox->toggle_images[0]->get_w();
140 int h = listbox->toggle_images[0]->get_h();
141 int cursor_inside = listbox->get_cursor_x() >= x &&
142 listbox->get_cursor_x() < x + w &&
143 listbox->get_cursor_y() >= y &&
144 listbox->get_cursor_y() < y + h;
148 case BC_ListBoxToggle::TOGGLE_UPHI:
149 if( !cursor_inside ) {
150 state = BC_ListBoxToggle::TOGGLE_UP;
155 case BC_ListBoxToggle::TOGGLE_CHECKEDHI:
156 if( !cursor_inside ) {
157 state = BC_ListBoxToggle::TOGGLE_CHECKED;
162 case BC_ListBoxToggle::TOGGLE_DOWN:
163 if( !cursor_inside ) {
164 state = BC_ListBoxToggle::TOGGLE_DOWN_EXIT;
170 case BC_ListBoxToggle::TOGGLE_DOWN_EXIT:
171 if( cursor_inside ) {
172 state = BC_ListBoxToggle::TOGGLE_DOWN;
179 if( cursor_inside ) {
181 state = BC_ListBoxToggle::TOGGLE_CHECKEDHI;
183 state = BC_ListBoxToggle::TOGGLE_UPHI;
191 int BC_ListBoxToggle::cursor_leave_event(int *redraw_toggles)
194 state = BC_ListBoxToggle::TOGGLE_CHECKED;
196 state = BC_ListBoxToggle::TOGGLE_UP;
200 int BC_ListBoxToggle::button_press_event()
202 int w = listbox->toggle_images[0]->get_w();
203 int h = listbox->toggle_images[0]->get_h();
205 if( listbox->gui->get_cursor_x() >= x &&
206 listbox->gui->get_cursor_x() < x + w &&
207 listbox->gui->get_cursor_y() >= y &&
208 listbox->gui->get_cursor_y() < y + h ) {
209 state = BC_ListBoxToggle::TOGGLE_DOWN;
215 int BC_ListBoxToggle::button_release_event(int *redraw_toggles)
220 case BC_ListBoxToggle::TOGGLE_DOWN:
223 state = BC_ListBoxToggle::TOGGLE_CHECKEDHI;
225 state = BC_ListBoxToggle::TOGGLE_UPHI;
226 listbox->expand_item(item, value);
230 case BC_ListBoxToggle::TOGGLE_DOWN_EXIT:
232 state = BC_ListBoxToggle::TOGGLE_CHECKED;
234 state = BC_ListBoxToggle::TOGGLE_UP;
242 void BC_ListBoxToggle::draw(int flash)
245 int image_number = 0;
246 int w = listbox->toggle_images[0]->get_w();
247 int h = listbox->toggle_images[0]->get_h();
250 case BC_ListBoxToggle::TOGGLE_UP: image_number = 0; break;
251 case BC_ListBoxToggle::TOGGLE_UPHI: image_number = 1; break;
252 case BC_ListBoxToggle::TOGGLE_CHECKED: image_number = 2; break;
253 case BC_ListBoxToggle::TOGGLE_DOWN: image_number = 3; break;
254 case BC_ListBoxToggle::TOGGLE_CHECKEDHI: image_number = 4; break;
255 case BC_ListBoxToggle::TOGGLE_DOWN_EXIT:
256 image_number = value ? 2 : 0;
260 //printf("BC_ListBoxToggle::draw 1 %d\n", state);
261 listbox->gui->draw_pixmap(listbox->toggle_images[image_number], x, y);
264 listbox->gui->flash(x, y, w, h);
265 listbox->gui->flush();
271 // ====================================================== box
273 BC_ListBox::BC_ListBox(int x, int y, int w, int h,
274 int display_format, ArrayList<BC_ListBoxItem*> *data,
275 const char **column_titles, int *column_width, int columns,
276 int yposition, int is_popup, int selection_mode,
277 int icon_position, int allow_drag)
278 : BC_SubWindow(x, y, w, h, -1)
280 justify = LISTBOX_RIGHT;
282 highlighted_item = -1;
283 highlighted_title = -1;
284 highlighted_division = -1;
288 current_cursor = ARROW_CURSOR;
298 xscroll_orientation = SCROLL_HORIZ;
299 yscroll_orientation = SCROLL_VERT;
303 selection_number1 = -1;
304 selection_number2 = -1;
307 row_height = row_ascent = row_descent = 0;
309 current_operation = NO_OPERATION;
310 button_highlighted = 0;
311 list_highlighted = 0;
314 allow_drag_scroll = 1;
320 allow_drag_column = 0;
327 for( int i=0; i<3; ++i ) column_bg[i] = 0;
328 for( int i=0; i<4; ++i ) button_images[i] = 0;
329 for( int i=0; i<5; ++i ) toggle_images[i] = 0;
334 //printf("BC_ListBox::BC_ListBox 1\n");
336 this->columns = columns;
337 this->yposition = yposition;
338 this->is_popup = is_popup;
339 this->use_button = 1;
340 this->display_format = display_format;
341 this->selection_mode = selection_mode;
342 this->icon_position = icon_position;
343 this->allow_drag = allow_drag;
344 this->column_titles = 0;
345 this->column_width = 0;
346 this->first_in_view = -1;
347 this->last_in_view = 0;
348 //printf("BC_ListBox::BC_ListBox 1\n");
350 if( (!column_titles && column_width) ||
351 (column_titles && !column_width) ) {
352 printf("BC_ListBox::BC_ListBox either column_titles or column_widths == NULL but not both.\n");
354 //printf("BC_ListBox::BC_ListBox 2 %p %p\n", column_titles, column_width);
356 set_columns(column_titles, column_width, columns);
358 //printf("BC_ListBox::BC_ListBox 3\n");
360 drag_icon_vframe = 0;
361 drag_column_icon_vframe = 0;
365 // reset the search engine
366 //printf("BC_ListBox::BC_ListBox 4\n");
369 //printf("BC_ListBox::BC_ListBox 5\n");
372 BC_ListBox::~BC_ListBox()
374 expanders.remove_all_objects();
375 if( bg_surface ) delete bg_surface;
376 if( bg_pixmap ) delete bg_pixmap;
377 if( xscrollbar ) delete xscrollbar;
378 if( yscrollbar ) delete yscrollbar;
379 for( int i=0; i<3; ++i ) delete column_bg[i];
380 for( int i=0; i<4; ++i ) delete button_images[i];
381 for( int i=0; i<5; ++i ) delete toggle_images[i];
382 if( column_sort_up ) delete column_sort_up;
383 if( column_sort_dn ) delete column_sort_dn;
386 if( drag_popup ) delete drag_popup;
389 int BC_ListBox::enable()
396 int BC_ListBox::disable()
403 void BC_ListBox::reset_query()
405 query[0] = 0; // reset query
408 int BC_ListBox::evaluate_query(char *string)
410 for( int i=0; i<data[search_column].size(); ++i ) {
411 if( strcmp(string, data[search_column].get(i)->text) <= 0 &&
412 data[search_column].get(i)->searchable ) {
420 int BC_ListBox::query_list()
422 if( query[0] == 0 ) return 0;
426 int selection_changed = 0;
427 int prev_selection = -1;
428 result = evaluate_query(query);
429 if( result >= 0 ) done = 1;
433 for( int i=0; i<data[0].total; ++i ) {
434 for( int j=0; j<columns; ++j ) {
435 if( data[j].values[i]->selected ) prev_selection = i;
436 data[j].values[i]->selected = 0;
441 if( prev_selection != result )
442 selection_changed = 1;
443 for( int j=0; j<columns; ++j ) {
444 data[j].values[result]->selected = 1;
446 center_selection(result);
449 return selection_changed;
452 void BC_ListBox::init_column_width()
454 if( !column_width && data ) {
456 for( int i=0; i<data[0].total; ++i ) {
457 wd = get_text_w(data[0].values[i]);
458 if( wd > widest ) widest = wd;
460 default_column_width[0] = widest + 2 * LISTBOX_MARGIN;
464 int BC_ListBox::initialize()
468 for( int i=0; i<4; ++i ) {
469 button_images[i] = new BC_Pixmap(parent_window,
470 BC_WindowBase::get_resources()->listbox_button[i],
473 w = button_images[0]->get_w();
474 h = button_images[0]->get_h();
478 current_operation = NO_OPERATION;
483 current_operation = NO_OPERATION;
486 for( int i=0; i<3; ++i ) {
487 column_bg[i] = new BC_Pixmap(parent_window,
488 get_resources()->listbox_column[i],
491 for( int i=0; i<5; ++i ) {
492 toggle_images[i] = new BC_Pixmap(parent_window,
493 get_resources()->listbox_expand[i],
497 column_sort_up = new BC_Pixmap(parent_window,
498 BC_WindowBase::get_resources()->listbox_up,
500 column_sort_dn = new BC_Pixmap(parent_window,
501 BC_WindowBase::get_resources()->listbox_dn,
504 //printf("BC_ListBox::initialize 10\n");
505 drag_icon_vframe = get_resources()->type_to_icon[ICON_UNKNOWN];
506 drag_column_icon_vframe = get_resources()->type_to_icon[ICON_COLUMN];
507 // = new BC_Pixmap(parent_window,
508 // get_resources()->type_to_icon[ICON_UNKNOWN],
510 // drag_column_icon = new BC_Pixmap(parent_window,
511 // get_resources()->type_to_icon[ICON_COLUMN],
513 BC_SubWindow::initialize();
517 if( top_level->get_resources()->listbox_bg )
518 bg_pixmap = new BC_Pixmap(this,
519 get_resources()->listbox_bg,
525 if( !use_button && is_popup ) {
533 void BC_ListBox::deactivate_selection()
535 current_operation = NO_OPERATION;
538 int BC_ListBox::draw_button(int flush)
540 // Draw the button for a popup listbox
541 if( use_button && is_popup ) {
542 int image_number = 0;
544 draw_top_background(parent_window, 0, 0, w, h);
546 if( button_highlighted )
548 if( current_operation == BUTTON_DN )
553 pixmap->draw_pixmap(button_images[image_number],
560 int BC_ListBox::calculate_item_coords()
562 if( !data ) return 0;
568 // Change the display_format to get the right item dimensions for both
570 temp_display_format = display_format;
573 // Scan the first column for lowest y coord of all text
574 // and lowest right x and y coord for all icons which aren't auto placable
575 calculate_last_coords_recursive(data,
576 &icon_x, &next_icon_x, &next_icon_y, &next_text_y, 1);
578 // Reset last column width. It's recalculated based on text width.
579 calculate_item_coords_recursive(data,
580 &icon_x, &next_icon_x, &next_icon_y, &next_text_y, 1);
582 display_format = temp_display_format;
587 void BC_ListBox::calculate_last_coords_recursive(
588 ArrayList<BC_ListBoxItem*> *data,
595 for( int i=0; i<data[0].size(); ++i ) {
596 int current_text_y = 0;
597 int current_icon_x = 0;
598 int current_icon_y = 0;
599 BC_ListBoxItem *item = data[0].get(i);
602 if( !item->autoplace_text ) {
603 // Lowest text coordinate
604 display_format = LISTBOX_TEXT;
605 current_text_y = item->text_y + get_text_h(item);
606 if( current_text_y > *next_text_y )
607 *next_text_y = current_text_y;
609 // Add sublist depth if it is expanded
610 if( item->get_sublist() && item->get_columns() &&
611 item->get_expand() ) {
612 calculate_last_coords_recursive(item->get_sublist(),
613 icon_x, next_icon_x, next_icon_y, next_text_y, 0);
617 // Get next_icon coordinate
619 BC_ListBoxItem *item = data[master_column].get(i);
620 if( !item->autoplace_icon ) {
621 display_format = LISTBOX_ICONS;
622 // Lowest right icon coordinate.
623 current_icon_x = item->icon_x;
624 if( current_icon_x > *icon_x ) *icon_x = current_icon_x;
625 if( current_icon_x + get_item_w(item) > *next_icon_x ) {
626 *next_icon_x = current_icon_x + get_item_w(item);
629 current_icon_y = item->icon_y + get_item_h(item);
630 if( current_icon_y > *next_icon_y )
631 *next_icon_y = current_icon_y;
638 void BC_ListBox::calculate_item_coords_recursive(
639 ArrayList<BC_ListBoxItem*> *data,
640 int *icon_x, int *next_icon_x, int *next_icon_y, int *next_text_y,
643 // get maximum height of an icon
644 row_height = get_text_height(MEDIUMFONT);
645 if( temp_display_format == LISTBOX_ICON_LIST ) {
646 for( int i=0; i<data[0].size(); ++i ) {
647 if( data[0].get(i)->icon ) {
648 if( data[0].get(i)->icon->get_h() > row_height )
649 row_height = data[0].get(i)->icon->get_h();
655 // Set up items which need autoplacement.
656 // Should fill icons down and then across
657 for( int i=0; i<data[0].size(); ++i ) {
658 // Don't increase y unless the row requires autoplacing.
659 int total_autoplaced_columns = 0;
661 // Set up icons in first column
663 BC_ListBoxItem *item = data[master_column].get(i);
664 if( item->autoplace_icon ) {
665 // 1 column only if icons are used
666 display_format = LISTBOX_ICONS;
669 if( *next_icon_y + get_item_h(item) >= get_h() &&
671 *icon_x = *next_icon_x;
675 if( *icon_x + get_item_w(item) > *next_icon_x )
676 *next_icon_x = *icon_x + get_item_w(item);
679 item->set_icon_x(*icon_x);
680 item->set_icon_y(*next_icon_y);
682 *next_icon_y += get_item_h(item);
688 row_ascent = row_descent = 0;
689 // row_height still holds icon max height
690 for( int j=0; j<columns; ++j ) {
691 BC_ListBoxItem *item = data[j].get(i);
692 if( item->autoplace_text ) {
693 display_format = LISTBOX_TEXT;
694 item->set_text_x(next_text_x);
695 item->set_text_y(*next_text_y);
696 int ht = get_text_h(item);
697 if( ht > row_height ) row_height = ht;
698 int bl = get_baseline(item);
699 if( bl > row_ascent ) row_ascent = bl;
701 if( dt > row_descent ) row_ascent = bl;
703 // printf("BC_ListBox::calculate_item_coords_recursive %p %d %d %d %d %s \n",
704 // item->get_sublist(), item->get_columns(), item->get_expand(),
705 // next_text_x, *next_text_y, item->get_text());
706 // Increment position of next column
707 if( j < columns - 1 ) {
708 next_text_x += (column_width ?
710 default_column_width[j]);
712 // Set last column width based on text width
714 int new_w = get_item_w(item);
716 int *previous_w = (column_width ?
718 &default_column_width[j]);
719 if( new_w > *previous_w )
721 //printf("BC_ListBox::calculate_item_coords_recursive 1 %d\n", new_w);
723 total_autoplaced_columns++;
727 // Increase the text vertical position
728 if( total_autoplaced_columns ) {
729 display_format = LISTBOX_TEXT;
730 *next_text_y += row_height;
734 BC_ListBoxItem *item = data[master_column].values[i];
735 if( item->get_sublist() && item->get_columns() &&
736 item->get_expand() ) {
737 calculate_item_coords_recursive( item->get_sublist(),
738 icon_x, next_icon_x, next_icon_y, next_text_y, 0);
743 void BC_ListBox::set_is_suggestions(int value)
745 this->is_suggestions = value;
748 void BC_ListBox::set_use_button(int value)
750 this->use_button = value;
753 void BC_ListBox::set_justify(int value)
755 this->justify = value;
758 void BC_ListBox::set_allow_drag_column(int value)
760 this->allow_drag_column = value;
763 void BC_ListBox::set_process_drag(int value)
765 this->process_drag = value;
768 void BC_ListBox::set_master_column(int value, int redraw)
770 this->master_column = value;
776 void BC_ListBox::set_search_column(int value)
778 this->search_column = value;
781 int BC_ListBox::get_sort_column()
786 void BC_ListBox::set_sort_column(int value, int redraw)
794 int BC_ListBox::get_sort_order()
799 void BC_ListBox::set_sort_order(int value, int redraw)
808 int BC_ListBox::get_display_mode()
810 return display_format;
813 int BC_ListBox::get_yposition()
818 int BC_ListBox::get_xposition()
823 int BC_ListBox::get_highlighted_item()
825 return highlighted_item;
829 int BC_ListBox::get_item_x(BC_ListBoxItem *item)
831 if( display_format == LISTBOX_TEXT )
832 return item->text_x - xposition + 2;
833 if( display_format == LISTBOX_ICON_LIST )
834 return item->text_x - xposition + 2;
835 return item->icon_x - xposition + 2;
838 int BC_ListBox::get_item_y(BC_ListBoxItem *item)
840 if( display_format == LISTBOX_TEXT )
841 return item->text_y - yposition + title_h + 2;
842 if( display_format == LISTBOX_ICON_LIST )
843 return item->text_y - yposition + title_h + 2;
844 return item->icon_y - yposition + title_h + 2;
847 int BC_ListBox::get_item_w(BC_ListBoxItem *item)
849 if( display_format == LISTBOX_ICONS ) {
851 get_icon_mask(item, x, y, w, h);
853 get_text_mask(item, x, y, w, h);
856 return icon_position == ICON_LEFT ? icon_w + text_w :
857 icon_w > text_w ? icon_w : text_w;
859 return get_text_w(item) + 2 * LISTBOX_MARGIN;
862 int BC_ListBox::get_item_h(BC_ListBoxItem *item)
864 if( display_format == LISTBOX_ICONS ) {
866 get_icon_mask(item, x, y, w, h);
868 get_text_mask(item, x, y, w, h);
871 return icon_position != ICON_LEFT ? icon_h + text_h :
872 icon_h > text_h ? icon_h : text_h;
874 return get_text_h(item);
878 int BC_ListBox::get_icon_w(BC_ListBoxItem *item)
880 return item->get_icon_w();
883 int BC_ListBox::get_icon_h(BC_ListBoxItem *item)
885 return item->get_icon_h();
888 int BC_ListBox::get_text_w(BC_ListBoxItem *item)
890 int w = item->get_text_w();
891 if( w < 0 ) item->set_text_w(w = get_text_width(MEDIUMFONT, item->get_text()));
895 int BC_ListBox::get_text_h(BC_ListBoxItem *item)
897 int h = item->get_text_h();
898 if( h < 0 ) item->set_text_h(h = get_text_height(MEDIUMFONT, item->get_text()));
902 int BC_ListBox::get_baseline(BC_ListBoxItem *item)
904 int b = item->get_baseline();
905 if( b < 0 ) item->set_baseline(b = get_text_ascent(MEDIUMFONT));
909 int BC_ListBox::get_items_width()
913 if( display_format == LISTBOX_ICONS ) {
914 for( int i=0; i<columns; ++i ) {
915 for( int j=0; j<data[i].total; ++j ) {
917 BC_ListBoxItem *item = data[i].values[j];
920 get_icon_mask(item, x, y, w, h);
921 if( x1 + w > widest ) widest = x1 + w;
923 if( display_format == LISTBOX_ICONS && icon_position == ICON_LEFT )
926 get_text_mask(item, x, y, w, h);
927 if( x1 + w > widest ) widest = x1 + w;
932 if( display_format == LISTBOX_TEXT ) {
933 return get_column_offset(columns);
936 return get_column_offset(columns);
941 int BC_ListBox::get_items_height(ArrayList<BC_ListBoxItem*> *data, int columns,
952 for( int j=0; j<(data?data[master_column].total:0); ++j ) {
954 BC_ListBoxItem *item = data[master_column].values[j];
956 if( display_format == LISTBOX_ICONS ||
957 display_format == LISTBOX_ICON_LIST ) {
958 get_icon_mask(item, x, y, w, h);
959 if( y + h + yposition > highest ) highest = y + h + yposition;
961 get_text_mask(item, x, y, w, h);
962 if( y + h + yposition > highest ) highest = y + h + yposition;
965 get_text_mask(item, x, y, w, h);
967 // Descend into sublist
968 if( item->get_sublist() && item->get_expand() ) {
969 get_items_height(item->get_sublist(),
976 if( display_format == LISTBOX_TEXT && top_level ) {
977 highest = LISTBOX_MARGIN + *result;
983 int BC_ListBox::set_yposition(int position, int draw_items)
985 this->yposition = position;
992 int BC_ListBox::set_xposition(int position)
994 this->xposition = position;
999 void BC_ListBox::expand_item(BC_ListBoxItem *item, int expand)
1002 item->expand = expand;
1003 // Collapse sublists if this is collapsed to make it easier to calculate
1005 if( item->get_sublist() )
1006 collapse_recursive(item->get_sublist(), master_column);
1008 // Set everything for autoplacement
1009 set_autoplacement(data, 0, 1);
1014 void BC_ListBox::collapse_recursive(ArrayList<BC_ListBoxItem*> *data,
1017 for( int i=0; i<data[master_column].total; ++i ) {
1018 BC_ListBoxItem *item = data[master_column].values[i];
1019 if( item->get_sublist() && item->expand ) {
1021 collapse_recursive(item->get_sublist(), master_column);
1026 void BC_ListBox::set_autoplacement(ArrayList<BC_ListBoxItem*> *data,
1030 for( int i=0; i<data[0].total; ++i ) {
1031 for( int j=0; j<columns; ++j ) {
1032 if( do_icons ) data[j].values[i]->autoplace_icon = 1;
1033 if( do_text ) data[j].values[i]->autoplace_text = 1;
1036 BC_ListBoxItem *item = data[master_column].values[i];
1037 if( item->get_sublist() ) {
1038 set_autoplacement(item->get_sublist(), do_icons, do_text);
1044 void BC_ListBox::set_scroll_stretch(int xv, int yv)
1046 if( xv >= 0 ) xscroll_orientation =
1047 !xv ? SCROLL_HORIZ : SCROLL_HORIZ + SCROLL_STRETCH;
1048 if( yv >= 0 ) yscroll_orientation =
1049 !yv ? SCROLL_VERT : SCROLL_VERT + SCROLL_STRETCH;
1052 int BC_ListBox::get_yscroll_x()
1055 return popup_w - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w();
1057 return get_x() + popup_w -
1058 get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w();
1061 int BC_ListBox::get_yscroll_y()
1063 return is_popup ? 0 : get_y();
1066 int BC_ListBox::get_yscroll_height()
1068 return popup_h - (need_xscroll ?
1069 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h() :
1073 int BC_ListBox::get_xscroll_x()
1075 return is_popup ? 0 : get_x();
1078 int BC_ListBox::get_xscroll_y()
1080 return (is_popup ? popup_h : get_y() + popup_h) -
1081 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h();
1084 int BC_ListBox::get_xscroll_width()
1086 return popup_w - (need_yscroll ?
1087 get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w() : 0);
1090 int BC_ListBox::get_column_offset(int column)
1093 while( column > 0 ) {
1095 column_width[--column] :
1096 default_column_width[--column];
1101 void BC_ListBox::column_width_boundaries()
1103 if( column_width ) {
1104 for( int i=0; i<columns; ++i ) {
1105 if( column_width[i] < MIN_COLUMN_WIDTH )
1106 column_width[i] = MIN_COLUMN_WIDTH;
1110 for( int i=0; i<columns; ++i ) {
1111 if( default_column_width[i] < MIN_COLUMN_WIDTH )
1112 default_column_width[i] = MIN_COLUMN_WIDTH;
1117 int BC_ListBox::get_column_width(int column, int clamp_right)
1119 if( column < columns - 1 || !clamp_right )
1120 return column_width ? column_width[column] : default_column_width[column];
1121 return popup_w + xposition - get_column_offset(column);
1124 int BC_ListBox::get_icon_mask(BC_ListBoxItem *item,
1125 int &x, int &y, int &w, int &h)
1127 if( display_format == LISTBOX_ICONS ) {
1128 x = get_item_x(item);
1129 y = get_item_y(item);
1130 w = get_icon_w(item) + ICON_MARGIN * 2;
1131 h = get_icon_h(item) + ICON_MARGIN * 2;
1138 int BC_ListBox::get_text_mask(BC_ListBoxItem *item,
1139 int &x, int &y, int &w, int &h)
1141 x = get_item_x(item);
1142 y = get_item_y(item);
1144 if( display_format == LISTBOX_ICONS ) {
1145 if( icon_position == ICON_LEFT ) {
1146 x += get_icon_w(item) + ICON_MARGIN * 2;
1147 y += get_icon_h(item) - get_text_h(item);
1150 y += get_icon_h(item) + ICON_MARGIN;
1153 w = get_text_w(item) + ICON_MARGIN * 2;
1154 h = get_text_h(item) + ICON_MARGIN * 2;
1157 if( display_format == LISTBOX_TEXT ) {
1158 w = get_text_w(item) + LISTBOX_MARGIN * 2;
1159 h = get_text_h(item);
1162 w = get_text_width(MEDIUMFONT, item->text) + LISTBOX_MARGIN * 2;
1164 int ih = get_icon_h(item);
1165 if( h < ih ) h = ih;
1170 int BC_ListBox::get_item_highlight(ArrayList<BC_ListBoxItem*> *data,
1171 int column, int item)
1173 BC_Resources *resources = get_resources();
1174 if( data[column].values[item]->selected )
1175 return resources->listbox_selected;
1176 if( highlighted_item >= 0 &&
1177 highlighted_ptr == data[master_column].values[item] )
1178 return resources->listbox_highlighted;
1179 return resources->listbox_inactive;
1182 int BC_ListBox::get_item_color(ArrayList<BC_ListBoxItem*> *data,
1183 int column, int item)
1185 int color = data[column].values[item]->color;
1186 if( color == -1 ) color = get_resources()->listbox_text;
1187 if( get_item_highlight(data, column, item) == color )
1192 int BC_ListBox::get_from_column()
1194 return dragged_title;
1197 int BC_ListBox::get_to_column()
1199 return highlighted_title;
1203 BC_ListBoxItem* BC_ListBox::get_selection(int column, int selection_number)
1205 return get_selection_recursive(data,
1210 BC_ListBoxItem* BC_ListBox::get_selection_recursive(ArrayList<BC_ListBoxItem*> *data,
1211 int column, int selection_number)
1213 if( !data ) return 0;
1215 for( int i=0; i<data[master_column].total; ++i ) {
1216 BC_ListBoxItem *item = data[master_column].values[i];
1217 if( item->selected ) {
1218 //printf("BC_ListBox::get_selection_recursive %d\n", __LINE__);
1220 if( selection_number < 0 ) {
1222 return data[column].values[i];
1226 if( item->get_sublist() ) {
1227 BC_ListBoxItem *result = get_selection_recursive(item->get_sublist(),
1230 if( result ) return result;
1238 int BC_ListBox::get_selection_number(int column, int selection_number)
1240 return get_selection_number_recursive(data, column, selection_number);
1243 int BC_ListBox::get_selection_number_recursive(ArrayList<BC_ListBoxItem*> *data,
1244 int column, int selection_number, int *counter)
1247 if( !data ) return 0;
1248 if( !counter ) counter = &temp;
1250 for( int i=0; i<data[master_column].total; ++i ) {
1252 BC_ListBoxItem *item = data[master_column].values[i];
1253 if( item->selected ) {
1255 if( selection_number < 0 ) {
1259 if( item->get_sublist() ) {
1260 int result = get_selection_number_recursive(item->get_sublist(),
1261 column, selection_number, counter);
1262 if( result >= 0 ) return result;
1269 int BC_ListBox::set_selection_mode(int mode)
1271 this->selection_mode = mode;
1275 void BC_ListBox::delete_columns()
1277 if( column_titles ) {
1278 for( int i=0; i<columns; ++i ) {
1279 delete [] column_titles[i];
1281 delete [] column_titles;
1284 if( column_width ) delete [] column_width;
1290 // Need to copy titles so EDL can change
1291 void BC_ListBox::set_columns(const char **column_titles, int *column_width, int columns)
1293 if( (!column_titles && column_width) ||
1294 (column_titles && !column_width) ) {
1295 printf("BC_ListBox::set_columns either column_titles or column_width == NULL but not both.\n");
1300 if( column_titles ) {
1301 this->column_titles = new char*[columns];
1302 for( int i=0; i<columns; ++i ) {
1303 this->column_titles[i] = new char[strlen(column_titles[i]) + 1];
1304 strcpy(this->column_titles[i], column_titles[i]);
1307 if( column_width ) {
1308 this->column_width = new int[columns];
1309 for( int i=0; i<columns; ++i ) {
1310 this->column_width[i] = column_width[i];
1314 this->columns = columns;
1319 int BC_ListBox::update(ArrayList<BC_ListBoxItem*> *data,
1320 const char **column_titles, int *column_widths, int columns,
1321 int xposition, int yposition, int highlighted_number,
1322 int recalc_positions, int draw)
1324 set_columns(column_titles, column_widths, columns);
1326 this->yposition = yposition;
1327 this->xposition = xposition;
1328 this->highlighted_item = highlighted_number;
1329 this->highlighted_ptr = index_to_item(data, highlighted_number, 0);
1331 if( recalc_positions )
1332 set_autoplacement(data, 1, 1);
1334 init_column_width();
1338 update_scrollbars(1);
1344 void BC_ListBox::center_selection()
1346 int selection = get_selection_number(0, 0);
1347 calculate_item_coords();
1348 center_selection(selection);
1352 update_scrollbars(0);
1353 gui->show_window(1);
1357 void BC_ListBox::move_vertical(int pixels)
1361 void BC_ListBox::move_horizontal(int pixels)
1365 int BC_ListBox::select_previous(int skip, BC_ListBoxItem *selected_item, int *counter,
1366 ArrayList<BC_ListBoxItem*> *data, int *got_first, int *got_second)
1369 if( !selected_item )
1370 selected_item = get_selection(0, 0);
1381 got_second = &temp3;
1385 // Scan backwards to item pointer. Then count visible items to get
1386 // destination. No wraparound.
1388 for( int i=data[master_column].total-1; i>=0; --i ) {
1389 BC_ListBoxItem *current_item = data[master_column].values[i];
1390 if( current_item->get_sublist() &&
1391 current_item->get_expand() ) {
1392 int result = select_previous(skip, selected_item, counter,
1393 current_item->get_sublist(), got_first, got_second);
1400 if( (*counter) >= skip ) {
1401 for( int j=0; j<columns; ++j )
1402 data[j].values[i]->selected = 1;
1404 return item_to_index(this->data, current_item);
1408 if( current_item->selected ) {
1409 for( int j=0; j<columns; ++j )
1410 data[j].values[i]->selected = 0;
1417 // Hit top of top level without finding a selected item.
1419 // Select first item in top level and quit
1420 BC_ListBoxItem *current_item;
1422 current_item = data[master_column].values[0];
1424 for( int j=0; j<columns; ++j )
1425 data[j].values[0]->selected = 1;
1427 return item_to_index(this->data, current_item);
1429 } while( top_level && data[master_column].total );
1434 int BC_ListBox::select_next(int skip, BC_ListBoxItem *selected_item, int *counter,
1435 ArrayList<BC_ListBoxItem*> *data, int *got_first, int *got_second)
1438 if( !selected_item )
1439 selected_item = get_selection(0, 0);
1450 got_second = &temp3;
1454 // Scan forwards to currently selected item pointer.
1455 // Then count visible items to get destination. No wraparound.
1457 for( int i=0; i<data[master_column].total; ++i ) {
1458 BC_ListBoxItem *current_item = data[master_column].values[i];
1460 // Select next item once the number items after the currently selected item
1461 // have been passed.
1464 if( (*counter) >= skip ) {
1465 for( int j=0; j<columns; ++j )
1466 data[j].values[i]->selected = 1;
1468 return item_to_index(this->data, current_item);
1472 // Got currently selected item. Deselect it.
1473 if( current_item->selected ) {
1474 for( int j=0; j<columns; ++j )
1475 data[j].values[i]->selected = 0;
1481 // Descend into expanded level
1482 if( current_item->get_sublist() &&
1483 current_item->get_expand() ) {
1484 int result = select_next(skip, selected_item, counter,
1485 current_item->get_sublist(), got_first, got_second);
1492 // Hit bottom of top level without finding the next item.
1494 BC_ListBoxItem *current_item;
1495 // Select first item in top level and quit
1496 if( !(*got_first) ) {
1498 current_item = data[master_column].values[0];
1500 for( int j=0; j<columns; ++j )
1501 data[j].values[0]->selected = 1;
1505 // Select last item in top level and quit
1507 int current_row = data[master_column].total - 1;
1508 current_item = data[master_column].values[current_row];
1510 for( int j=0; j<columns; ++j )
1511 data[j].values[current_row]->selected = 1;
1515 return item_to_index(this->data, current_item);
1517 } while( top_level && data[master_column].total );
1523 void BC_ListBox::clamp_positions()
1525 items_w = get_items_width();
1526 if( xscroll_orientation & SCROLL_STRETCH )
1527 items_w += view_w / 4;
1528 items_h = get_items_height(data, columns);
1529 if( yscroll_orientation & SCROLL_STRETCH )
1530 items_h += view_h / 4;
1532 if( yposition < 0 ) yposition = 0;
1534 if( yposition > items_h - view_h )
1535 yposition = items_h - view_h;
1537 if( yposition < 0 ) yposition = 0;
1539 if( xposition < 0 ) xposition = 0;
1541 if( xposition >= items_w - view_w )
1542 xposition = items_w - view_w;
1544 if( xposition < 0 ) xposition = 0;
1547 int BC_ListBox::center_selection(int selection,
1548 ArrayList<BC_ListBoxItem*> *data, int *counter)
1551 if( !data ) data = this->data;
1552 if( !counter ) counter = &temp;
1554 for( int i=0; i<data[master_column].total; ++i ) {
1558 BC_ListBoxItem *item = data[master_column].values[i];
1559 if( (*counter) == selection ) {
1560 BC_ListBoxItem *top_item = this->data[master_column].values[0];
1563 if( display_format == LISTBOX_ICONS ) {
1564 // Icon is out of window
1565 if( item->icon_y-yposition > view_h-get_text_h(item) ||
1566 item->icon_y-yposition < 0 ) {
1567 yposition = item->icon_y - view_h / 2;
1570 if( data[master_column].values[selection]->icon_x - xposition > view_w ||
1571 data[master_column].values[selection]->icon_x - xposition < 0 ) {
1572 xposition = item->icon_x - view_w / 2;
1576 // Text coordinate is out of window
1577 if( item->text_y-yposition > view_h-get_text_h(item) ||
1578 item->text_y-yposition < 0 ) {
1579 yposition = item->text_y -
1588 if( item->get_sublist() ) {
1589 int result = center_selection(selection,
1590 item->get_sublist(),
1592 if( result ) return result;
1598 void BC_ListBox::update_scrollbars(int flush)
1600 int h_needed = items_h = get_items_height(data, columns);
1601 int w_needed = items_w = get_items_width();
1603 // if( columns > 0 && column_width )
1604 // printf("BC_ListBox::update_scrollbars 1 %d %d\n", column_width[columns - 1], w_needed);
1607 if( xposition != xscrollbar->get_value() )
1608 xscrollbar->update_value(xposition);
1610 if( w_needed != xscrollbar->get_length() ||
1611 view_w != xscrollbar->get_handlelength() )
1612 xscrollbar->update_length(w_needed, xposition, view_w, 0);
1616 if( yposition != yscrollbar->get_value() )
1617 yscrollbar->update_value(yposition);
1619 if( h_needed != yscrollbar->get_length() || view_h != yscrollbar->get_handlelength() )
1620 yscrollbar->update_length(h_needed, yposition, view_h, 0);
1623 if( flush ) this->flush();
1626 int BC_ListBox::get_scrollbars()
1628 int h_needed = items_h = get_items_height(data, columns);
1629 int w_needed = items_w = get_items_width();
1632 title_h = get_title_h();
1633 view_h = popup_h - title_h - 4;
1634 view_w = popup_w - 4;
1636 // Create scrollbars as needed
1637 for( int i=0; i<2; ++i ) {
1638 if( w_needed > view_w ) {
1642 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h() -
1649 if( h_needed > view_h ) {
1652 get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w() -
1660 // Update subwindow size
1661 int new_w = popup_w;
1662 int new_h = popup_h;
1663 if( need_xscroll ) new_h -= get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h();
1664 if( need_yscroll ) new_w -= get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w();
1667 if( new_w != BC_WindowBase::get_w() || new_h != BC_WindowBase::get_h() )
1668 gui->resize_window(new_w, new_h);
1670 BC_WindowBase *destination = (is_popup ? gui : parent_window);
1671 if( need_xscroll ) {
1673 xscrollbar = new BC_ListBoxXScroll(this);
1674 destination->add_subwindow(xscrollbar);
1675 xscrollbar->show_window(0);
1676 xscrollbar->bound_to = this;
1679 xscrollbar->update_length(w_needed, xposition, view_w, flush);
1680 xscrollbar->reposition_window(get_xscroll_x(),
1682 get_xscroll_width());
1686 if( xscrollbar ) delete xscrollbar;
1691 if( need_yscroll ) {
1693 yscrollbar = new BC_ListBoxYScroll(this);
1694 destination->add_subwindow(yscrollbar);
1695 yscrollbar->show_window(0);
1696 yscrollbar->bound_to = this;
1699 yscrollbar->update_length(h_needed, yposition, view_h, flush);
1700 yscrollbar->reposition_window(get_yscroll_x(),
1702 get_yscroll_height());
1706 if( yscrollbar ) delete yscrollbar;
1712 view_w + 4 != bg_surface->get_w() ||
1713 view_h + 4 != bg_surface->get_h() ) {
1714 if( bg_surface ) delete bg_surface;
1715 bg_surface = new BC_Pixmap(gui, view_w + 4, view_h + 4);
1724 void BC_ListBox::set_drag_scroll(int value)
1726 allow_drag_scroll = value;
1729 // Test for scrolling by dragging
1731 int BC_ListBox::test_drag_scroll(int cursor_x, int cursor_y)
1734 if( allow_drag_scroll ||
1735 current_operation == SELECT_RECT ) {
1737 int top_boundary = get_title_h();
1739 if( cursor_y < top_boundary ||
1740 cursor_y >= view_h + title_h + LISTBOX_BORDER * 2 ||
1741 cursor_x < LISTBOX_BORDER ||
1742 cursor_x >= view_w + LISTBOX_BORDER ) {
1749 int BC_ListBox::drag_scroll_event()
1751 int top_boundary = get_title_h();
1754 if( get_cursor_y() < top_boundary ) {
1755 yposition -= top_boundary - get_cursor_y();
1759 if( get_cursor_y() >= view_h + title_h + 4 ) {
1760 yposition += get_cursor_y() - (view_h + title_h + 4);
1764 if( get_cursor_x() < 2 ) {
1765 xposition -= 2 - get_cursor_x();
1769 if( get_cursor_x() >= view_w + 2 ) {
1770 xposition += get_cursor_x() - (view_w + 2);
1780 int BC_ListBox::rectangle_scroll_event()
1782 int old_xposition = xposition;
1783 int old_yposition = yposition;
1784 int result = drag_scroll_event();
1787 rect_x1 += old_xposition - xposition;
1788 rect_y1 += old_yposition - yposition;
1789 rect_x2 = get_cursor_x();
1790 rect_y2 = get_cursor_y();
1792 int x1 = MIN(rect_x1, rect_x2);
1793 int x2 = MAX(rect_x1, rect_x2);
1794 int y1 = MIN(rect_y1, rect_y2);
1795 int y2 = MAX(rect_y1, rect_y2);
1797 if( select_rectangle(data, x1, y1, x2, y2) ) {
1798 selection_changed();
1803 update_scrollbars(1);
1808 int BC_ListBox::select_scroll_event()
1810 int result = drag_scroll_event();
1812 highlighted_item = selection_number = get_cursor_item(data,
1813 get_cursor_x(), get_cursor_y(), &highlighted_ptr);
1816 update_scrollbars(1);
1817 selection_changed();
1822 int BC_ListBox::select_rectangle(ArrayList<BC_ListBoxItem*> *data,
1823 int x1, int y1, int x2, int y2)
1826 for( int i=0; i<data[master_column].total; ++i ) {
1827 for( int j=0; j<columns; ++j ) {
1828 BC_ListBoxItem *item = data[j].values[i];
1829 if( display_format == LISTBOX_ICONS ) {
1830 int icon_x, icon_y, icon_w, icon_h;
1831 int text_x, text_y, text_w, text_h;
1832 get_icon_mask(item, icon_x, icon_y, icon_w, icon_h);
1833 get_text_mask(item, text_x, text_y, text_w, text_h);
1835 if( (x2 >= icon_x && x1 < icon_x + icon_w &&
1836 y2 >= icon_y && y1 < icon_y + icon_h) ||
1837 (x2 >= text_x && x1 < text_x + text_w &&
1838 y2 >= text_y && y1 < text_y + text_h) ) {
1839 if( !item->selected ) {
1845 if( item->selected ) {
1854 gui->get_w() - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w() :
1855 gui->get_w()) && y2 > 0 &&
1856 y1 < gui->get_h() && y2 >= get_item_y(item) &&
1857 y1 < get_item_y(item) + get_item_h(item) ) {
1858 if( !item->selected ) {
1864 if( item->selected ) {
1872 BC_ListBoxItem *item = data[master_column].values[i];
1873 if( item->get_sublist() &&
1874 item->get_expand() )
1875 result |= select_rectangle(item->get_sublist(),
1881 int BC_ListBox::reposition_item(ArrayList<BC_ListBoxItem*> *data,
1882 int selection_number, int x, int y, int *counter)
1885 if( !counter ) counter = &temp;
1887 for( int i=0; i<data[master_column].total; ++i ) {
1888 BC_ListBoxItem *item = data[master_column].values[i];
1890 if( (*counter) == selection_number ) {
1895 // Not recursive because it's only used for icons
1900 void BC_ListBox::move_selection(ArrayList<BC_ListBoxItem*> *dst,
1901 ArrayList<BC_ListBoxItem*> *src)
1903 for( int i=0; i<src[master_column].total; ) {
1904 BC_ListBoxItem *item = src[master_column].values[i];
1907 if( item->selected ) {
1908 for( int j=0; j<columns; ++j ) {
1909 dst[j].append(src[j].values[i]);
1910 src[j].remove_number(i);
1914 // Descend into sublist
1915 if( item->get_sublist() ) {
1917 item->get_sublist());
1923 int BC_ListBox::put_selection(ArrayList<BC_ListBoxItem*> *data,
1924 ArrayList<BC_ListBoxItem*> *src, int destination, int *counter)
1927 if( !counter ) counter = &temp;
1929 if( destination < 0 || destination >= data[master_column].total ) {
1930 for( int j=0; j<columns; ++j ) {
1931 for( int i=0; i<src[j].total; ++i ) {
1932 data[j].append(src[j].values[i]);
1938 for( int i=0; i<data[master_column].total; ++i ) {
1940 if( (*counter) == destination ) {
1941 for( int j=0; j<columns; ++j ) {
1942 for( int k=0; k<src[j].total; ++k ) {
1943 data[j].insert(src[j].values[k], destination + k);
1949 BC_ListBoxItem *item = data[master_column].values[i];
1950 if( item->get_sublist() ) {
1951 if( put_selection(item->get_sublist(),
1963 int BC_ListBox::item_to_index(ArrayList<BC_ListBoxItem*> *data,
1964 BC_ListBoxItem *item, int *counter)
1967 if( !counter ) counter = &temp;
1969 for( int i=0; i<data[master_column].total; ++i ) {
1971 for( int j=0; j<columns; ++j ) {
1972 BC_ListBoxItem *new_item = data[j].values[i];
1973 //printf("BC_ListBox::item_to_index 1 %d %d %p\n", j, i, new_item);
1974 if( new_item == item ) {
1979 BC_ListBoxItem *new_item = data[master_column].values[i];
1980 if( new_item->get_sublist() ) {
1981 if( item_to_index(new_item->get_sublist(),
1991 BC_ListBoxItem* BC_ListBox::index_to_item(ArrayList<BC_ListBoxItem*> *data,
1992 int number, int column, int *counter)
1995 if( !counter ) counter = &temp;
1996 for( int i=0; i<data[master_column].total; ++i ) {
1998 if( (*counter) == number ) {
1999 return data[column].values[i];
2001 BC_ListBoxItem *item = data[master_column].values[i];
2002 if( item->get_sublist() ) {
2003 BC_ListBoxItem *result = index_to_item(item->get_sublist(),
2004 number, column, counter);
2005 if( result ) return result;
2011 int BC_ListBox::get_cursor_item(ArrayList<BC_ListBoxItem*> *data, int cursor_x, int cursor_y,
2012 BC_ListBoxItem **item_return, int *counter, int expanded)
2015 if( !data ) return -1;
2016 if( !counter ) counter = &temp;
2018 // Icons are not treed
2019 if( display_format == LISTBOX_ICONS ) {
2020 for( int j=data[master_column].total-1; j>=0; --j ) {
2021 int icon_x, icon_y, icon_w, icon_h;
2022 int text_x, text_y, text_w, text_h;
2023 BC_ListBoxItem *item = data[master_column].values[j];
2024 get_icon_mask(item, icon_x, icon_y, icon_w, icon_h);
2025 get_text_mask(item, text_x, text_y, text_w, text_h);
2027 if( (cursor_x >= icon_x && cursor_x < icon_x + icon_w &&
2028 cursor_y >= icon_y && cursor_y < icon_y + icon_h) ||
2029 (cursor_x >= text_x && cursor_x < text_x + text_w &&
2030 cursor_y >= text_y && cursor_y < text_y + text_h) ) {
2031 if( item_return ) (*item_return) = item;
2038 // Cursor is inside items rectangle
2039 if( cursor_x >= 0 &&
2040 cursor_x < (yscrollbar ?
2041 gui->get_w() - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w() :
2043 // Only clamp y if we're not in a SELECT operation.
2044 (current_operation == BC_ListBox::SELECT ||
2045 (cursor_y > get_title_h() + LISTBOX_BORDER &&
2046 cursor_y < gui->get_h())) ) {
2047 // Search table for cursor obstruction
2048 for( int i=0; i<data[master_column].total; ++i ) {
2049 BC_ListBoxItem *item = data[master_column].values[i];
2052 // Cursor is inside item on current level
2053 if( expanded && item->selectable &&
2054 cursor_y >= get_item_y(item) &&
2055 cursor_y < get_item_y(item) + get_item_h(item) ) {
2056 //printf("BC_ListBox::get_cursor_item %d %d %p\n", master_column, i, item);
2057 if( item_return ) (*item_return) = item;
2061 // Descend into sublist
2062 if( item->get_sublist() ) {
2063 if( get_cursor_item(item->get_sublist(),
2064 cursor_x, cursor_y, item_return, counter,
2065 item->get_expand()) >= 0 )
2075 int BC_ListBox::repeat_event(int64_t duration)
2077 switch( current_operation ) {
2078 // Repeat out of bounds selection
2080 if( duration != get_resources()->scroll_repeat ) break;
2081 return rectangle_scroll_event();
2084 if( duration != get_resources()->scroll_repeat ) break;
2085 if( !drag_scroll_event() ) break;
2088 update_scrollbars(1);
2092 if( duration != get_resources()->scroll_repeat ) break;
2093 return select_scroll_event();
2097 if( duration != get_resources()->tooltip_delay ) break;
2098 if( !button_highlighted || !is_popup ) break;
2099 if( !tooltip_text || !tooltip_text[0] ) break;
2107 int BC_ListBox::cursor_enter_event()
2111 switch( current_operation ) {
2112 // Cursor moved over button, pressed, and exited.
2113 case BUTTON_DOWN_SELECT:
2114 if( top_level->event_win == win ) {
2115 current_operation = BUTTON_DN;
2117 button_highlighted = 1;
2123 // Cursor entered button
2124 if( is_popup && top_level->event_win == win ) {
2125 button_highlighted = 1;
2130 // TODO: Need to get the highlighted column title or item
2131 if( gui && top_level->event_win == gui->win ) {
2132 list_highlighted = 1;
2142 int BC_ListBox::cursor_leave_event()
2144 if( current_operation == COLUMN_DRAG ) return 0;
2147 if( button_highlighted ) {
2148 button_highlighted = 0;
2153 if( list_highlighted ) {
2154 list_highlighted = 0;
2155 highlighted_item = -1;
2156 highlighted_ptr = 0;
2157 highlighted_title = -1;
2158 int redraw_toggles = 0;
2159 for( int i=0; i<expanders.total; ++i )
2160 expanders.values[i]->cursor_leave_event(&redraw_toggles);
2168 int BC_ListBox::get_first_selection(ArrayList<BC_ListBoxItem*> *data, int *result)
2171 if( !result ) result = &temp;
2173 for( int i=0; i<data[master_column].total; ++i ) {
2174 BC_ListBoxItem *item = data[master_column].values[i];
2176 if( item->selected ) return (*result);
2177 if( item->get_sublist() ) {
2178 if( get_first_selection(item->get_sublist(), result) >= 0 )
2185 int BC_ListBox::get_total_items(ArrayList<BC_ListBoxItem*> *data,
2190 if( !result ) result = &temp;
2192 for( int i=0; i<data[master_column].total; ++i ) {
2194 if( data[master_column].values[i]->get_sublist() )
2195 get_total_items(data[master_column].values[i]->get_sublist(),
2204 int BC_ListBox::get_last_selection(ArrayList<BC_ListBoxItem*> *data,
2214 for( int i=data[master_column].total-1; i>=0; --i ) {
2215 BC_ListBoxItem *item = data[master_column].values[i];
2217 if( item->selected ) {
2219 return get_total_items(data, 0, master_column) - (*result) /* - 1 */;
2224 if( item->get_sublist() ) {
2225 if( get_last_selection(item->get_sublist(), result) >= 0 ) {
2227 return get_total_items(data, 0, master_column) - (*result) /* - 1 */;
2236 void BC_ListBox::select_range(ArrayList<BC_ListBoxItem*> *data,
2237 int start, int end, int *current)
2240 if( !current ) current = &temp;
2242 for( int i=0; i<data[master_column].total; ++i ) {
2244 if( (*current) >= start && (*current) < end ) {
2245 for( int j=0; j<columns; ++j )
2246 data[j].values[i]->selected = 1;
2248 BC_ListBoxItem *item = data[master_column].values[i];
2249 if( item->get_sublist() )
2250 select_range(item->get_sublist(), start, end, current);
2255 // Fill items between current selection and new selection
2256 int BC_ListBox::expand_selection(int button_press, int selection_number)
2258 int old_selection_start = selection_start;
2259 int old_selection_end = selection_end;
2261 // printf("BC_ListBox::expand_selection %d %d\n",
2262 // selection_center,
2263 // selection_number);
2265 // Calculate the range to select based on selection_center and selection_number
2266 if( selection_number < selection_center ) {
2267 selection_start = selection_number;
2270 selection_end = selection_number + 1;
2273 //printf("BC_ListBox::expand_selection %d %d %d %d\n", old_selection_start, old_selection_end, selection_start, selection_end);
2274 // Recurse through all the items and select the desired range
2275 select_range(data, selection_start, selection_end);
2278 return (old_selection_start != selection_start ||
2279 old_selection_end != selection_end);
2282 int BC_ListBox::toggle_item_selection(ArrayList<BC_ListBoxItem*> *data,
2283 int selection_number, int *counter)
2286 if( !counter ) counter = &temp;
2288 for( int i=0; i<data[master_column].total; ++i ) {
2289 BC_ListBoxItem *item = data[master_column].values[i];
2291 if( (*counter) == selection_number ) {
2292 // Get new value for selection
2293 int selected = !item->selected;
2295 for( int j=0; j<columns; ++j )
2296 data[j].values[i]->selected = selected;
2300 // Descend into sublist
2301 if( item->get_sublist() ) {
2302 if( toggle_item_selection(item->get_sublist(),
2303 selection_number, counter) )
2312 void BC_ListBox::set_all_selected(ArrayList<BC_ListBoxItem*> *data, int value)
2314 for( int i=0; i<data[master_column].total; ++i ) {
2315 for( int j=0; j<columns; ++j ) {
2316 BC_ListBoxItem *item = data[j].values[i];
2317 item->selected = value;
2319 BC_ListBoxItem *item = data[master_column].values[i];
2320 if( item->get_sublist() ) {
2321 set_all_selected(item->get_sublist(), value);
2326 void BC_ListBox::set_selected(ArrayList<BC_ListBoxItem*> *data,
2327 int item_number, int value, int *counter)
2330 if( !counter ) counter = &temp;
2331 for( int i=0; i<data[master_column].total&&(*counter)!=item_number; ++i ) {
2333 if( (*counter) == item_number ) {
2334 for( int j=0; j<columns; ++j ) {
2335 BC_ListBoxItem *item = data[j].values[i];
2336 item->selected = value;
2341 BC_ListBoxItem *item = data[master_column].values[i];
2342 if( item->get_sublist() ) {
2343 set_selected(item->get_sublist(), item_number, value, counter);
2348 int BC_ListBox::update_selection(ArrayList<BC_ListBoxItem*> *data,
2349 int selection_number, int *counter)
2353 if( !counter ) counter = &temp;
2355 for( int i=0; i<data[master_column].total; ++i ) {
2356 BC_ListBoxItem *item = data[master_column].values[i];
2358 if( (*counter) == selection_number && !item->selected ) {
2360 for( int j=0; j<columns; ++j )
2361 data[j].values[i]->selected = 1;
2364 if( (*counter) != selection_number && item->selected ) {
2366 for( int j=0; j<columns; ++j )
2367 data[j].values[i]->selected = 0;
2369 if( item->get_sublist() )
2370 result |= update_selection(item->get_sublist(),
2377 void BC_ListBox::promote_selections(ArrayList<BC_ListBoxItem*> *data,
2378 int old_value, int new_value)
2380 for( int i=0; i<data[master_column].total; ++i ) {
2381 for( int j=0; j<columns; ++j ) {
2382 BC_ListBoxItem *item = data[j].values[i];
2383 if( item->selected == old_value ) item->selected = new_value;
2385 BC_ListBoxItem *item = data[master_column].values[i];
2386 if( item->get_sublist() )
2387 promote_selections(item->get_sublist(), old_value, new_value);
2391 int BC_ListBox::focus_out_event()
2397 int BC_ListBox::button_press_event()
2400 BC_ListBoxItem *current_item = 0;
2402 int do_selection_change = 0;
2403 const int debug = 0;
2406 if( debug ) printf("BC_ListBox::button_press_event %d this=%p event_win=%p %p %p %p\n",
2407 __LINE__, this, (void*)top_level->event_win,
2408 (void*)(gui ? gui->win : 0), (void*)win, (void*)parent_window->win);
2410 // Pressed in button
2411 if( is_popup && top_level->event_win == win ) {
2412 if( debug ) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2413 current_operation = BUTTON_DN;
2417 if( !active && !disabled ) {
2418 top_level->deactivate();
2425 // Pressed in scrollbar
2426 if( (xscrollbar && top_level->event_win == xscrollbar->win) ||
2427 (yscrollbar && top_level->event_win == yscrollbar->win) ) {
2428 if( debug ) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2433 if( gui && top_level->event_win == gui->win ) {
2434 if( debug ) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2436 // Activate list items
2437 // If it is a suggestion popup, it is visible without being active
2439 if( debug ) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2440 if( !is_suggestions ) top_level->deactivate();
2441 if( debug ) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2443 if( debug ) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2446 // Wheel mouse pressed
2447 if( get_buttonpress() == 4 ) {
2448 if( current_operation == NO_OPERATION ) {
2449 current_operation = WHEEL;
2451 set_yposition(yposition - gui->get_h() / 10, 0);
2453 update_scrollbars(0);
2454 highlighted_ptr = 0;
2455 highlighted_item = get_cursor_item(data,
2456 top_level->cursor_x, top_level->cursor_y,
2464 if( get_buttonpress() == 5 ) {
2465 if( current_operation == NO_OPERATION ) {
2466 current_operation = WHEEL;
2468 set_yposition(yposition + gui->get_h() / 10, 0);
2470 update_scrollbars(0);
2471 highlighted_ptr = 0;
2472 highlighted_item = get_cursor_item(data,
2473 top_level->cursor_x, top_level->cursor_y,
2481 // Pressed over column title division
2482 if( test_column_divisions(gui->get_cursor_x(),
2483 gui->get_cursor_y(),
2485 drag_cursor_x = gui->get_cursor_x() + xposition;
2487 drag_column_w = column_width[highlighted_division - 1];
2489 drag_column_w = default_column_width[highlighted_division - 1];
2491 current_operation = DRAG_DIVISION;
2495 // Pressed in column title
2496 if( test_column_titles(gui->get_cursor_x(), gui->get_cursor_y()) ) {
2497 current_operation = COLUMN_DN;
2498 button_highlighted = 0;
2499 list_highlighted = 1;
2504 // Pressed in expander
2505 if( test_expanders() ) {
2506 current_operation = EXPAND_DN;
2507 // Need to redraw items because of alpha
2512 // Pressed over item
2513 if( (selection_number = get_cursor_item(data,
2514 gui->get_cursor_x(), gui->get_cursor_y(),
2515 ¤t_item)) >= 0 ) {
2516 if( debug ) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2518 // Get item button was pressed over
2519 selection_number2 = selection_number1;
2520 selection_number1 = selection_number;
2522 selection_start = -1;
2526 // Multiple item selection is possible
2527 if( selection_mode == LISTBOX_MULTIPLE &&
2528 (ctrl_down() || shift_down()) ) {
2529 // Expand text selection.
2530 // Fill items between selected region and current item.
2532 (display_format == LISTBOX_TEXT ||
2533 display_format == LISTBOX_ICON_LIST) ) {
2534 // Get first item selected
2535 selection_start = get_first_selection(data);
2536 // Get last item selected
2537 selection_end = get_last_selection(data);
2538 // Get center of selected region
2539 if( selection_end > selection_start ) {
2540 selection_center = (selection_end + selection_start) >> 1;
2543 selection_center = selection_number;
2545 // Deselect everything.
2546 set_all_selected(data, 0);
2547 // Select just the items
2548 expand_selection(1, selection_number);
2551 // Toggle a single item on or off
2553 toggle_item_selection(data, selection_number);
2554 new_value = current_item->selected;
2557 // Select single item
2559 if( !current_item->selected ) {
2560 set_all_selected(data, 0);
2569 current_operation = SELECT;
2570 highlighted_item = selection_number;
2571 highlighted_ptr = current_item;
2572 button_highlighted = 0;
2573 list_highlighted = 1;
2576 do_selection_change = 1;
2580 // Pressed over nothing. Start rectangle selection.
2582 if( get_buttonpress() == 1 &&
2583 selection_mode == LISTBOX_MULTIPLE ) {
2584 if( !shift_down() ) {
2585 // Deselect all and redraw if anything was selected
2586 if( get_selection_number(0, 0) >= 0 ) {
2587 set_all_selected(data, 0);
2589 do_selection_change = 1;
2594 // Promote selections to protect from a rectangle selection
2595 promote_selections(data, 1, 2);
2598 // Start rectangle selection
2599 current_operation = SELECT_RECT;
2600 rect_x1 = rect_x2 = get_cursor_x();
2601 rect_y1 = rect_y2 = get_cursor_y();
2609 // Suggestion box is not active but visible, so lie to get it to deactivate
2610 if( is_popup && (active || (is_suggestions && gui)) ) {
2612 if( debug ) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2618 if( do_selection_change ) selection_changed();
2619 if( debug ) printf("BC_ListBox::button_press_event %d %d\n", __LINE__, result);
2624 int BC_ListBox::button_release_event()
2627 int cursor_x, cursor_y;
2631 //printf("BC_ListBox::button_release_event 1 %d\n", current_operation);
2632 switch( current_operation ) {
2634 current_operation = NO_OPERATION;
2639 current_operation = NO_OPERATION;
2643 // Release item selection
2644 case BUTTON_DOWN_SELECT:
2646 //printf("BC_ListBox::button_release_event 10\n");
2647 unset_repeat(get_resources()->scroll_repeat);
2648 current_operation = NO_OPERATION;
2650 translate_coordinates(top_level->event_win, gui->win,
2651 gui->get_cursor_x(), gui->get_cursor_y(),
2652 &cursor_x, &cursor_y);
2653 selection_number1 = selection_number =
2654 get_cursor_item(data, cursor_x, cursor_y);
2655 //printf("BC_ListBox::button_release_event %d %d\n", selection_number2, selection_number1);
2660 if( selection_number >= 0 ) {
2665 // Second button release outside button
2666 if( button_releases > 1 ) {
2671 if( top_level->get_double_click() &&
2672 selection_number2 == selection_number1 &&
2673 selection_number2 >= 0 && selection_number1 >= 0 ) {
2682 unset_repeat(get_resources()->scroll_repeat);
2684 // Demote selections from rectangle selection
2685 promote_selections(data, 2, 1);
2688 // Hide rectangle overlay
2690 current_operation = NO_OPERATION;
2694 // Release popup button
2697 current_operation = NO_OPERATION;
2701 // Second button release inside button
2702 if( button_releases > 1 ) {
2709 current_operation = NO_OPERATION;
2710 // Update the sort column and the sort order for the user only if the existing
2711 // sort column is valid.
2712 if( sort_column >= 0 ) {
2713 // Invert order only if column is the same
2714 if( highlighted_title == sort_column )
2715 sort_order = sort_order == SORT_ASCENDING ?
2716 SORT_DESCENDING : SORT_ASCENDING;
2717 // Set the new sort column
2718 sort_column = highlighted_title;
2719 if( !sort_order_event() ) {
2724 // Sorting not enabled. Redraw the title state.
2732 int redraw_toggles = 0;
2733 for( int i=0; i<expanders.total&&!result; ++i ) {
2734 if( expanders.values[i]->button_release_event(&redraw_toggles) ) {
2738 // Need to redraw items because of alpha
2739 if( redraw_toggles ) draw_items(1);
2740 current_operation = NO_OPERATION;
2744 // Can't default to NO_OPERATION because it may be used in a drag event.
2749 if( do_event ) handle_event();
2751 //printf("BC_ListBox::button_release_event %d %d\n", __LINE__, get_window_lock());
2755 int BC_ListBox::get_title_h()
2757 if( display_format == LISTBOX_TEXT ||
2758 display_format == LISTBOX_ICON_LIST )
2759 return column_titles ? column_bg[0]->get_h() : 0;
2763 void BC_ListBox::reset_cursor(int new_cursor)
2766 if( gui->get_cursor() != new_cursor ) {
2767 gui->set_cursor(new_cursor, 0, 0);
2771 if( get_cursor() != new_cursor ) {
2772 set_cursor(new_cursor, 0, 0);
2776 int BC_ListBox::test_column_divisions(int cursor_x, int cursor_y, int &new_cursor)
2778 if( gui && column_titles &&
2779 cursor_y >= 0 && cursor_y < get_title_h() &&
2780 cursor_x >= 0 && cursor_x < gui->get_w() ) {
2781 for( int i=1; i<columns; ++i ) {
2782 if( cursor_x >= -xposition + get_column_offset(i) - 5 &&
2783 cursor_x < -xposition + get_column_offset(i) +
2784 get_resources()->listbox_title_hotspot ) {
2785 highlighted_item = -1;
2786 highlighted_ptr = 0;
2787 highlighted_division = i;
2788 highlighted_title = -1;
2789 list_highlighted = 1;
2790 new_cursor = HSEPARATE_CURSOR;
2795 highlighted_division = -1;
2799 int BC_ListBox::test_column_titles(int cursor_x, int cursor_y)
2801 if( gui && column_titles &&
2802 cursor_y >= 0 && cursor_y < get_title_h() &&
2803 cursor_x >= 0 && cursor_x < gui->get_w() ) {
2804 for( int i=0; i<columns; ++i ) {
2805 if( cursor_x >= -xposition + get_column_offset(i) &&
2806 (cursor_x < -xposition + get_column_offset(i + 1) ||
2807 i == columns - 1) ) {
2808 highlighted_item = -1;
2809 highlighted_ptr = 0;
2810 highlighted_division = -1;
2811 highlighted_title = i;
2812 list_highlighted = 1;
2817 highlighted_title = -1;
2821 int BC_ListBox::test_expanders()
2823 for( int i=0; i<expanders.total; ++i ) {
2824 if( expanders.values[i]->button_press_event() ) {
2825 current_operation = EXPAND_DN;
2833 int BC_ListBox::cursor_motion_event()
2835 int redraw = 0, result = 0;
2836 int new_cursor = ARROW_CURSOR;
2838 selection_number = -1;
2841 switch( current_operation ) {
2843 // Button pressed and slid off button
2844 if( !cursor_inside() ) {
2845 current_operation = BUTTON_DOWN_SELECT;
2851 case DRAG_DIVISION: {
2852 // int new_w = get_cursor_x() +
2854 // get_column_offset(highlighted_division - 1);
2855 int difference = get_cursor_x() + xposition - drag_cursor_x;
2856 int new_w = drag_column_w + difference;
2858 new_cursor = HSEPARATE_CURSOR;
2860 if( column_width ) {
2861 column_width[highlighted_division - 1] = new_w;
2864 default_column_width[highlighted_division - 1] = new_w;
2867 column_width_boundaries();
2869 // Force update of coords
2870 set_autoplacement(data, 0, 1);
2871 column_resize_event();
2875 update_scrollbars(1);
2880 if( test_drag_scroll(get_cursor_x(), get_cursor_y()) ) {
2881 set_repeat(get_resources()->scroll_repeat);
2884 int old_x1 = MIN(rect_x1, rect_x2);
2885 int old_x2 = MAX(rect_x1, rect_x2);
2886 int old_y1 = MIN(rect_y1, rect_y2);
2887 int old_y2 = MAX(rect_y1, rect_y2);
2889 int new_rect_x2 = get_cursor_x();
2890 int new_rect_y2 = get_cursor_y();
2892 int x1 = MIN(rect_x1, new_rect_x2);
2893 int x2 = MAX(rect_x1, new_rect_x2);
2894 int y1 = MIN(rect_y1, new_rect_y2);
2895 int y2 = MAX(rect_y1, new_rect_y2);
2897 // Adjust rectangle coverage
2898 if( old_x1 != x1 || old_x2 != x2 ||
2899 old_y1 != y1 || old_y2 != y2 ) {
2901 redraw = select_rectangle(data, x1, y1, x2, y2);
2906 //printf("BC_ListBox::cursor_motion_event %d\n", __LINE__);
2911 rect_x2 = get_cursor_x();
2912 rect_y2 = get_cursor_y();
2916 update_scrollbars(1);
2917 selection_changed();
2918 //printf("BC_ListBox::cursor_motion_event %d\n", __LINE__);
2921 if( old_x1 != x1 || old_x2 != x2 ||
2922 old_y1 != y1 || old_y2 != y2 ) {
2923 //printf("BC_ListBox::cursor_motion_event %d\n", __LINE__);
2931 int old_highlighted_item = highlighted_item;
2933 if( test_drag_scroll(get_cursor_x(),
2935 set_repeat(get_resources()->scroll_repeat);
2939 highlighted_item = selection_number = get_cursor_item(data,
2940 get_cursor_x(), get_cursor_y(), &highlighted_ptr);
2943 // Deselect all items and select just the one we're over
2944 if( selection_number >= 0 && !allow_drag &&
2945 ((!shift_down() && !ctrl_down()) ||
2946 selection_mode == LISTBOX_SINGLE) ) {
2947 redraw = update_selection(data, selection_number);
2950 // Expand multiple selection
2951 if( selection_mode == LISTBOX_MULTIPLE &&
2952 (shift_down() || ctrl_down()) ) {
2953 // Expand selected region in text mode centered around initial range
2954 if( (display_format == LISTBOX_TEXT ||
2955 display_format == LISTBOX_ICON_LIST) &&
2957 // Deselect everything.
2958 set_all_selected(data, 0);
2960 // Select just the items
2961 redraw = expand_selection(0, selection_number);
2963 // Set the one item we're over to the selection value determined in
2964 // button_press_event.
2966 set_selected(data, selection_number, new_value);
2970 if( highlighted_item != old_highlighted_item ) {
2973 update_scrollbars(1);
2974 //printf("BC_ListBox::cursor_motion_event %d %d\n", highlighted_item, old_highlighted_item);
2975 selection_changed();
2979 case BUTTON_DOWN_SELECT:
2980 // Went back into button area
2981 if( cursor_inside() ) {
2982 current_operation = BUTTON_DN;
2987 // Went into item area
2989 int cursor_x = 0, cursor_y = 0;
2990 translate_coordinates(top_level->event_win, gui->win,
2991 top_level->cursor_x, top_level->cursor_y,
2992 &cursor_x, &cursor_y);
2993 int old_highlighted_item = highlighted_item;
2994 highlighted_item = selection_number = get_cursor_item(data,
2999 if( highlighted_item != old_highlighted_item ) {
3000 update_selection(data, selection_number);
3002 selection_changed();
3008 int redraw_toggles = 0;
3009 for( int i=0; i<expanders.total&&!result; ++i ) {
3010 result = expanders.values[i]->cursor_motion_event(
3013 if( redraw_toggles ) {
3014 // Need to redraw items because of the alpha
3019 case NO_OPERATION: {
3020 int cursor_x = get_cursor_x(), cursor_y = get_cursor_y();
3021 if( gui && top_level->event_win == gui->win ) {
3022 int old_highlighted_title = highlighted_title;
3023 int old_list_highlighted = list_highlighted;
3024 int old_highlighted_item = highlighted_item;
3025 int redraw_titles = 0;
3026 int redraw_border = 0;
3027 int redraw_items = 0;
3028 int redraw_toggles = 0;
3031 // Test if cursor moved over a title division
3032 test_column_divisions(cursor_x, cursor_y, new_cursor);
3034 // Test if cursor moved over a title
3035 if( highlighted_division < 0 ) {
3036 test_column_titles(cursor_x, cursor_y);
3039 // Test if cursor moved over expander
3040 if( highlighted_division < 0 && highlighted_title < 0 &&
3041 (display_format == LISTBOX_TEXT ||
3042 display_format == LISTBOX_ICON_LIST) ) {
3043 for( int i=0; i<expanders.total; ++i ) {
3044 expanders.values[i]->cursor_motion_event(
3047 //printf("BC_ListBox::cursor_motion_event %d\n", redraw_toggles);
3050 // Test if cursor moved over an item
3051 if( highlighted_division < 0 && highlighted_title < 0 ) {
3052 highlighted_item = get_cursor_item(data,
3059 // Clear title highlighting if moved over division
3060 if( old_highlighted_title != highlighted_title ) {
3064 // Highlight list border
3065 if( old_list_highlighted != list_highlighted ) {
3069 // Moved out of item area
3070 if( old_highlighted_item != highlighted_item ) {
3074 //printf("BC_ListBox::cursor_motion_event 1 %d\n", highlighted_item);
3076 // Change cursor to title division adjustment
3077 reset_cursor(new_cursor);
3079 if( redraw_items ) {
3087 if( redraw_toggles )
3091 if( redraw_items || redraw_titles ||
3092 redraw_border || redraw_toggles ) {
3099 if( !result && list_highlighted ) {
3100 list_highlighted = 0;
3101 highlighted_item = -1;
3102 highlighted_ptr = 0;
3103 highlighted_title = -1;
3104 highlighted_division = -1;
3114 int BC_ListBox::drag_start_event()
3116 switch( current_operation ) {
3118 if( gui && gui->is_event_win() && allow_drag ) {
3119 BC_ListBoxItem *item_return = 0;
3120 selection_number = get_cursor_item(data,
3121 top_level->cursor_x,
3122 top_level->cursor_y,
3125 if( selection_number >= 0 ) {
3127 get_abs_cursor(cx, cy);
3128 if( item_return->icon_vframe ) {
3129 drag_popup = new BC_DragWindow(this,
3130 item_return->icon_vframe, cx, cy);
3133 if( item_return->icon ) {
3134 drag_popup = new BC_DragWindow(this,
3135 item_return->icon, cx, cy);
3138 drag_popup = new BC_DragWindow(this,
3139 drag_icon_vframe, cx, cy);
3141 current_operation = DRAG_ITEM;
3142 // require shift down for scrolling
3143 if( allow_drag < 0 && shift_down() )
3144 set_repeat(get_resources()->scroll_repeat);
3151 if( gui && gui->is_event_win() && allow_drag_column ) {
3153 get_abs_cursor(cx, cy);
3154 cx -= drag_column_icon_vframe->get_w() / 2,
3155 cy -= drag_column_icon_vframe->get_h() / 2;
3156 drag_popup = new BC_DragWindow(this,
3157 drag_column_icon_vframe, cx, cy);
3158 dragged_title = highlighted_title;
3159 current_operation = COLUMN_DRAG;
3169 int BC_ListBox::drag_motion_event()
3171 //printf("BC_ListBox::drag_motion_event 1 %d\n", current_operation);
3172 switch( current_operation ) {
3175 int new_highlighted_item = -1;
3176 BC_ListBoxItem *new_highlighted_ptr = 0;
3177 new_highlighted_item = get_cursor_item(data,
3178 top_level->cursor_x, top_level->cursor_y,
3179 &new_highlighted_ptr);
3181 if( new_highlighted_item != highlighted_item ) {
3185 // Always update highlighted value for drag_stop
3186 highlighted_item = new_highlighted_item;
3187 highlighted_ptr = new_highlighted_ptr;
3188 //printf("BC_ListBox::drag_motion_event 1 %p\n", highlighted_ptr);
3192 update_scrollbars(1);
3195 return drag_popup->cursor_motion_event(); }
3198 int old_highlighted_title = highlighted_title;
3199 test_column_titles(get_cursor_x(), get_cursor_y());
3200 if( old_highlighted_title != highlighted_title ) {
3203 return drag_popup->cursor_motion_event(); }
3209 int BC_ListBox::drag_stop_event()
3211 switch( current_operation ) {
3213 unset_repeat(get_resources()->scroll_repeat);
3214 // Inside window boundary
3215 if( top_level->cursor_x > 0 &&
3216 top_level->cursor_x < gui->get_w() - drag_popup->get_w() / 2 &&
3217 top_level->cursor_y > 0 &&
3218 top_level->cursor_y < gui->get_h() - drag_popup->get_h() / 2 ) {
3222 if( display_format == LISTBOX_ICONS ) {
3223 reposition_item(data,
3225 top_level->cursor_x - drag_popup->get_w() / 2 -
3226 LISTBOX_MARGIN - 2 + xposition,
3227 top_level->cursor_y - drag_popup->get_h() / 2 -
3228 LISTBOX_MARGIN - 2 + yposition);
3232 if( process_drag ) {
3233 // Move selected items from data to temporary
3234 ArrayList<BC_ListBoxItem*> *src_items =
3235 new ArrayList<BC_ListBoxItem*>[columns];
3236 move_selection(src_items, data);
3238 int destination = highlighted_item = item_to_index(data,
3240 // Insert items from temporary to data
3241 put_selection(data, src_items, destination);
3243 delete [] src_items;
3244 set_autoplacement(data, 0, 1);
3250 drag_popup->drag_failure_event();
3255 current_operation = NO_OPERATION;
3260 if( dragged_title != highlighted_title ) {
3261 if( highlighted_title >= 0 ) {
3262 if( !move_column_event() ) draw_titles(1);
3265 drag_popup->drag_failure_event();
3267 current_operation = NO_OPERATION;
3276 BC_DragWindow* BC_ListBox::get_drag_popup()
3281 int BC_ListBox::translation_event()
3283 if( is_popup && gui ) {
3284 int new_x = gui->get_x() +
3285 (top_level->last_translate_x - top_level->prev_x -
3286 BC_DisplayInfo::get_left_border());
3287 int new_y = gui->get_y() +
3288 (top_level->last_translate_y - top_level->prev_y -
3289 BC_DisplayInfo::get_top_border());
3291 gui->reposition_window(new_x, new_y);
3297 int BC_ListBox::reposition_window(int x, int y, int w, int h, int flush)
3301 if( h != -1 ) popup_h = h;
3302 //printf("BC_ListBox::reposition_window %d %d\n", popup_w, popup_h);
3306 xscrollbar->reposition_window(get_xscroll_x(),
3308 get_xscroll_width());
3310 yscrollbar->reposition_window(get_yscroll_x(),
3312 get_yscroll_height());
3316 BC_WindowBase::reposition_window(x, y, w, h);
3322 int BC_ListBox::deactivate()
3325 // printf("BC_ListBox::deactivate %d this=%p gui=%p active=%d\n",
3326 // __LINE__, this, gui, active);
3329 //printf("BC_ListBox::deactivate %d this=%p gui=%p\n", __LINE__, this, gui);
3331 delete gui; gui = 0;
3336 highlighted_item = -1;
3337 highlighted_ptr = 0;
3340 //printf("BC_ListBox::deactivate %d this=%p\n", __LINE__, this);
3342 top_level->active_subwindow = 0;
3348 int BC_ListBox::activate(int take_focus)
3350 if( active ) return 0;
3353 set_active_subwindow(this);
3354 button_releases = 0;
3355 if( !is_popup || gui ) return 0;
3356 int wx = get_x(), wy = get_y() + get_h();
3357 if( justify == LISTBOX_RIGHT ) wx += get_w() - popup_w;
3360 XTranslateCoordinates(top_level->display,
3361 parent_window->win, top_level->rootwin,
3362 wx, wy, &abs_x, &abs_y, &xwin);
3365 return activate(abs_x, abs_y);
3368 int BC_ListBox::activate(int x, int y, int w, int h)
3370 if( !is_popup || gui ) return 0;
3372 if( w != -1 ) popup_w = w;
3373 if( h != -1 ) popup_h = h;
3375 if( y + popup_h > top_level->get_root_h(0) )
3376 y -= get_h() + popup_h;
3377 add_subwindow(gui = new BC_Popup(this,
3378 x, y, popup_w, popup_h, -1, 0, 0));
3380 gui->show_window(1);
3384 int BC_ListBox::is_active()
3389 int BC_ListBox::keypress_event()
3391 if( !active ) return 0;
3393 //printf("BC_ListBox::keypress_event %d\n", __LINE__);
3395 int result = 0, redraw = 0;
3396 int view_items = last_in_view - first_in_view + 1;
3397 if( view_items <= 0 ) view_items = view_h / get_text_height(MEDIUMFONT);
3398 int new_item = -1, new_selection = -1;
3400 switch( top_level->get_keypress() ) {
3403 top_level->deactivate();
3405 // If user is manipulating popup with keyboard, don't pass on event.
3407 //printf("BC_ListBox::keypress_event %d %p\n", __LINE__, get_selection(0, 0));
3408 if( top_level->get_keypress() == RETURN )
3410 //printf("BC_ListBox::keypress_event %d %p\n", __LINE__, get_selection(0, 0));
3418 new_selection = new_item = select_previous(0);
3420 //printf("BC_ListBox::keypress_event 1 %d\n", new_item);
3421 if( new_item >= 0 ) {
3422 center_selection(new_item);
3430 new_selection = new_item = select_next(0);
3432 if( new_item >= 0 ) {
3433 center_selection(new_item);
3441 new_selection = new_item = select_previous(view_items - 1);
3443 if( new_item >= 0 ) {
3444 center_selection(new_item);
3452 new_selection = new_item = select_next(view_items - 1);
3454 if( new_item >= 0 ) {
3455 center_selection(new_item);
3481 if( !ctrl_down() ) {
3482 int query_len = strlen(query);
3483 if( query_len < (int)sizeof(query)-1 &&
3484 top_level->get_keypress() > 30 &&
3485 top_level->get_keypress() < 127 ) {
3486 query[query_len++] = top_level->get_keypress();
3487 query[query_len] = 0;
3488 new_selection = query_list();
3491 if( top_level->get_keypress() == BACKSPACE ) {
3492 if( query_len > 0 ) query[--query_len] = 0;
3493 new_selection = query_list();
3497 show_tooltip(query);
3510 update_scrollbars(1);
3513 //printf("BC_ListBox::keypress_event %d new_selection=%d\n", __LINE__, new_selection);
3514 if( new_selection >= 0 && !is_suggestions ) {
3515 //printf("BC_ListBox::keypress_event %d\n", __LINE__);
3516 selection_changed();
3517 //printf("BC_ListBox::keypress_event %d\n", __LINE__);
3524 BC_Pixmap* BC_ListBox::get_bg_surface()
3530 void BC_ListBox::draw_background()
3532 if( !bg_draw ) return;
3534 // White background pixmap
3535 set_color(top_level->get_resources()->listbox_inactive);
3536 draw_box(0, 0, bg_surface->get_w(), bg_surface->get_h(), bg_surface);
3538 // Optional heroine pixmap
3540 bg_surface->draw_pixmap(bg_pixmap,
3541 bg_surface->get_w() - top_level->get_resources()->listbox_bg->get_w(),
3545 void BC_ListBox::clear_listbox(int x, int y, int w, int h)
3547 gui->draw_pixmap(bg_surface, x, y, w, h, x, y - title_h);
3550 void BC_ListBox::update_format(int display_format, int redraw)
3552 this->display_format = display_format;
3553 xposition = 0; yposition = 0;
3554 if( redraw && gui ) draw_items(1, 1);
3557 int BC_ListBox::get_format()
3559 return display_format;
3564 int BC_ListBox::draw_items(int flush, int draw_bg)
3567 BC_Resources *resources = get_resources();
3569 //dump(data, columns);
3571 // Calculate items width
3572 calculate_item_coords();
3573 // Create and destroy scrollbars as needed
3576 if( bg_draw ) this->bg_draw = 1;
3582 if( display_format == LISTBOX_ICONS ) {
3583 clear_listbox(2, 2 + title_h, view_w, view_h);
3585 set_font(MEDIUMFONT);
3586 for( int i=0; i<data[master_column].size(); ++i ) {
3587 BC_ListBoxItem *item = data[master_column].get(i);
3588 if( get_item_x(item) >= -get_item_w(item) &&
3589 get_item_x(item) < view_w &&
3590 get_item_y(item) >= -get_item_h(item) + title_h &&
3591 get_item_y(item) < view_h + title_h ) {
3592 item->set_in_view(1);
3593 if( first_in_view < 0 ) first_in_view = i;
3595 int item_color = get_item_highlight(data, 0, i);
3596 int icon_x, icon_y, icon_w, icon_h;
3597 int text_x, text_y, text_w, text_h;
3600 get_icon_mask(item, icon_x, icon_y, icon_w, icon_h);
3601 get_text_mask(item, text_x, text_y, text_w, text_h);
3603 if( item_color != resources->listbox_inactive ) {
3604 gui->set_color(BLACK);
3605 gui->draw_rectangle(icon_x, icon_y, icon_w, icon_h);
3606 gui->set_color(item_color);
3607 gui->draw_box(icon_x + 1, icon_y + 1, icon_w - 2, icon_h - 2);
3608 gui->set_color(BLACK);
3609 gui->draw_rectangle(text_x, text_y, text_w, text_h);
3610 gui->set_color(item_color);
3611 gui->draw_box(text_x + 1, text_y + 1, text_w - 2, text_h - 2);
3613 if( icon_position == ICON_LEFT )
3614 gui->draw_box(text_x - 1, text_y + 1, 2, text_h - 2);
3616 if( icon_position == ICON_TOP )
3617 gui->draw_line(text_x + 1, text_y, text_x + icon_w - 2, text_y);
3618 if( text_x + text_w < icon_x + icon_w ) {
3619 gui->set_color(BLACK);
3620 gui->draw_line(text_x + text_w, icon_y + icon_h,
3621 icon_x + icon_w, icon_y + icon_h);
3625 gui->set_color(get_item_color(data, 0, i));
3627 gui->pixmap->draw_pixmap(item->icon,
3628 icon_x + ICON_MARGIN, icon_y + ICON_MARGIN);
3630 gui->draw_text(text_x + ICON_MARGIN,
3631 text_y + ICON_MARGIN + get_baseline(item), item->text);
3634 item->set_in_view(0);
3639 // Draw one column at a time so text overruns don't go into the next column
3640 // clear column backgrounds
3641 int current_toggle = 0;
3642 for( int j=0; j<columns; ++j ) {
3643 clear_listbox(LISTBOX_BORDER + get_column_offset(j) - xposition,
3644 LISTBOX_BORDER + title_h,
3645 get_column_width(j, 1),
3647 // Draw rows in the column recursively
3648 draw_text_recursive(data, j, 0, ¤t_toggle);
3651 // Delete excess expanders
3652 while( expanders.total > current_toggle ) {
3653 expanders.remove_object();
3657 // draw user images if available
3659 // Draw titles on top of rows for superposition effect
3662 // Clear garbage from bottom right corner
3663 if( xscrollbar && yscrollbar && is_popup ) {
3664 gui->draw_top_background(parent_window,
3665 popup_w - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w(),
3666 popup_h - get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h(),
3667 get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w(),
3668 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h());
3675 if( current_operation == SELECT_RECT )
3685 void BC_ListBox::draw_text_recursive(ArrayList<BC_ListBoxItem*> *data,
3686 int column, int indent, int *current_toggle)
3689 BC_Resources *resources = get_resources();
3691 set_font(MEDIUMFONT);
3694 // Search for a branch and make room for toggle if there is one
3696 for( int i=0; i<data[column].size(); ++i ) {
3697 if( data[column].get(i)->get_sublist() ) {
3698 subindent = BC_WindowBase::get_resources()->listbox_expand[0]->get_w();
3704 row_height = row_ascent = row_descent = 0;
3705 for( int i=0; i<data[column].total; ++i ) {
3706 BC_ListBoxItem *item = data[column].values[i];
3707 int ht = get_text_h(item);
3708 if( ht > row_height ) row_height = ht;
3709 int bl = get_baseline(item);
3710 if( bl > row_ascent ) row_ascent = bl;
3712 if( dt > row_descent ) row_ascent = bl;
3715 for( int i=0; i<data[column].size(); ++i ) {
3717 BC_ListBoxItem *item = data[column].values[i];
3718 BC_ListBoxItem *first_item = data[master_column].values[i];
3720 if( get_item_y(item) >= -get_item_h(item) + title_h &&
3721 get_item_y(item) < view_h + title_h ) {
3722 int row_color = get_item_highlight(data, 0, i);
3723 int x, y, w, h, column_width;
3725 get_text_mask(item, x, y, w, h);
3726 column_width = get_column_width(column, 1);
3727 if( x + column_width > view_w + LISTBOX_BORDER * 2 )
3728 column_width = view_w + LISTBOX_BORDER * 2 - x;
3730 if( row_color != resources->listbox_inactive ) {
3731 gui->set_color(row_color);
3732 gui->draw_box(x, y, column_width, h);
3733 gui->set_color(BLACK);
3734 int xx = x + column_width-1;
3735 gui->draw_line(x, y, xx, y);
3737 if( display_format == LISTBOX_ICON_LIST ) {
3738 int ih = get_icon_h(item);
3739 if( ih > hh ) hh = ih;
3742 gui->draw_line(x, yy, xx, yy);
3745 gui->set_color(get_item_color(data, column, i));
3748 if( column == 0 && display_format == LISTBOX_ICON_LIST ) {
3750 gui->pixmap->draw_pixmap(item->icon, x, y);
3751 x += item->icon->get_w() + ICON_MARGIN;
3756 // Indent only applies to first column
3758 x + LISTBOX_BORDER + LISTBOX_MARGIN +
3759 (column == 0 ? indent + subindent : 0),
3760 y + get_baseline(item), item->text);
3761 item->set_in_view(1);
3763 if( first_in_view < 0 ) first_in_view = i;
3768 if( column == 0 && item->get_sublist() && item->get_columns() ) {
3769 // Create new expander
3770 if( *current_toggle >= expanders.total ) {
3771 BC_ListBoxToggle *toggle =
3772 new BC_ListBoxToggle(this, item,
3773 x + LISTBOX_BORDER + LISTBOX_MARGIN + indent, y);
3775 expanders.append(toggle);
3777 // Reposition existing expander
3779 BC_ListBoxToggle *toggle = expanders.values[*current_toggle];
3780 //printf("BC_ListBox::draw_text_recursive 1 %d\n", *current_toggle);
3781 toggle->update(item,
3782 x + LISTBOX_BORDER + LISTBOX_MARGIN + indent, y, 0);
3784 (*current_toggle)++;
3791 item->set_in_view(0);
3793 // Descend into sublist
3794 if( first_item->get_expand() ) {
3795 draw_text_recursive(first_item->get_sublist(),
3797 indent + LISTBOX_INDENT,
3803 int BC_ListBox::draw_border(int flash)
3805 BC_Resources *resources = top_level->get_resources();
3806 gui->draw_3d_border(0, 0,
3807 view_w + LISTBOX_BORDER * 2, view_h + title_h + LISTBOX_BORDER * 2,
3808 resources->listbox_border1,
3810 resources->listbox_border2_hi : resources->listbox_border2,
3812 resources->listbox_border3_hi : resources->listbox_border3,
3813 resources->listbox_border4);
3822 void BC_ListBox::draw_title(int number)
3824 // Column title background
3825 int image_number = 0;
3826 if( number == highlighted_title ) {
3828 if( current_operation == COLUMN_DN )
3832 gui->draw_3segmenth(get_column_offset(number) - xposition + LISTBOX_BORDER,
3834 get_column_width(number, 1) + get_resources()->listbox_title_overlap,
3835 column_bg[image_number]);
3837 int title_x = -xposition + get_column_offset(number) +
3838 LISTBOX_MARGIN + LISTBOX_BORDER;
3839 title_x += get_resources()->listbox_title_margin;
3841 gui->set_color(get_resources()->listbox_title_color);
3842 gui->draw_text(title_x,
3843 LISTBOX_MARGIN + LISTBOX_BORDER + get_text_ascent(MEDIUMFONT),
3844 column_titles[number]);
3846 // Column sort order
3847 if( number == sort_column ) {
3848 BC_Pixmap *src = sort_order == SORT_ASCENDING ?
3849 column_sort_dn : column_sort_up;
3851 // int column_offset = get_column_offset(number) - xposition + LISTBOX_BORDER;
3852 // int column_width = get_column_width(number, 1);
3853 // int toggle_x = column_offset + column_width - LISTBOX_BORDER;
3854 // if( toggle_x > items_w ) toggle_x = items_w;
3855 // toggle_x -= 5 + src->get_w();
3858 get_text_width(MEDIUMFONT, column_titles[number]) +
3861 gui->draw_pixmap(src,
3863 title_h / 2 - src->get_h() / 2 + LISTBOX_BORDER);
3867 int BC_ListBox::draw_titles(int flash)
3869 if( column_titles &&
3870 (display_format == LISTBOX_TEXT ||
3871 display_format == LISTBOX_ICON_LIST) ) {
3872 //printf("BC_ListBox::draw_titles 1 %d\n", highlighted_title);
3873 for( int i=0; i<columns; ++i ) {
3874 if( i != highlighted_title )
3878 if( highlighted_title >= 0 ) draw_title(highlighted_title);
3888 void BC_ListBox::draw_toggles(int flash)
3890 for( int i=0; i<expanders.total; ++i )
3891 expanders.values[i]->draw(0);
3893 //printf("BC_ListBox::draw_toggles 1 %d\n", flash);
3894 if( flash && expanders.total ) {
3899 int BC_ListBox::draw_rectangle(int flash)
3901 int x1 = MIN(rect_x1, rect_x2);
3902 int x2 = MAX(rect_x1, rect_x2);
3903 int y1 = MIN(rect_y1, rect_y2);
3904 int y2 = MAX(rect_y1, rect_y2);
3906 if( x1 == x2 || y1 == y2 ) return 0;
3909 gui->set_color(WHITE);
3910 gui->draw_rectangle(x1, y1, x2 - x1, y2 - y1);
3920 void BC_ListBox::dump(ArrayList<BC_ListBoxItem*> *data, int columns,
3921 int indent, int master_column)
3924 printf("BC_ListBox::dump 1\n");
3927 for( int i=0; i<data[master_column].total; ++i ) {
3928 for( int k=0; k<indent; ++k )
3930 for( int j=0; j<columns; ++j ) {
3931 BC_ListBoxItem *item = data[j].values[i];
3932 printf("%d,%d,%d=%s ",
3933 item->get_text_x(), item->get_text_y(),
3934 item->autoplace_text, item->get_text());
3938 if( data[master_column].values[i]->get_sublist() ) {
3939 dump(data[master_column].values[i]->get_sublist(),
3940 data[master_column].values[i]->get_columns(),