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 if( current_operation != NO_OPERATION ) {
2447 switch( current_operation ) {
2450 return drag_stop_event();
2454 // Wheel mouse pressed
2455 if( get_buttonpress() == 4 ) {
2456 if( current_operation == NO_OPERATION ) {
2457 current_operation = WHEEL;
2459 set_yposition(yposition - gui->get_h() / 10, 0);
2461 update_scrollbars(0);
2462 highlighted_ptr = 0;
2463 highlighted_item = get_cursor_item(data,
2464 top_level->cursor_x, top_level->cursor_y,
2472 if( get_buttonpress() == 5 ) {
2473 if( current_operation == NO_OPERATION ) {
2474 current_operation = WHEEL;
2476 set_yposition(yposition + gui->get_h() / 10, 0);
2478 update_scrollbars(0);
2479 highlighted_ptr = 0;
2480 highlighted_item = get_cursor_item(data,
2481 top_level->cursor_x, top_level->cursor_y,
2489 // Pressed over column title division
2490 if( test_column_divisions(gui->get_cursor_x(),
2491 gui->get_cursor_y(),
2493 drag_cursor_x = gui->get_cursor_x() + xposition;
2495 drag_column_w = column_width[highlighted_division - 1];
2497 drag_column_w = default_column_width[highlighted_division - 1];
2499 current_operation = DRAG_DIVISION;
2503 // Pressed in column title
2504 if( test_column_titles(gui->get_cursor_x(), gui->get_cursor_y()) ) {
2505 current_operation = COLUMN_DN;
2506 button_highlighted = 0;
2507 list_highlighted = 1;
2512 // Pressed in expander
2513 if( test_expanders() ) {
2514 current_operation = EXPAND_DN;
2515 // Need to redraw items because of alpha
2520 // Pressed over item
2521 if( (selection_number = get_cursor_item(data,
2522 gui->get_cursor_x(), gui->get_cursor_y(),
2523 ¤t_item)) >= 0 ) {
2524 if( debug ) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2526 // Get item button was pressed over
2527 selection_number2 = selection_number1;
2528 selection_number1 = selection_number;
2530 selection_start = -1;
2534 // Multiple item selection is possible
2535 if( selection_mode == LISTBOX_MULTIPLE &&
2536 (ctrl_down() || shift_down()) ) {
2537 // Expand text selection.
2538 // Fill items between selected region and current item.
2540 (display_format == LISTBOX_TEXT ||
2541 display_format == LISTBOX_ICON_LIST) ) {
2542 // Get first item selected
2543 selection_start = get_first_selection(data);
2544 // Get last item selected
2545 selection_end = get_last_selection(data);
2546 // Get center of selected region
2547 if( selection_end > selection_start ) {
2548 selection_center = (selection_end + selection_start) >> 1;
2551 selection_center = selection_number;
2553 // Deselect everything.
2554 set_all_selected(data, 0);
2555 // Select just the items
2556 expand_selection(1, selection_number);
2559 // Toggle a single item on or off
2561 toggle_item_selection(data, selection_number);
2562 new_value = current_item->selected;
2565 // Select single item
2567 if( !current_item->selected ) {
2568 set_all_selected(data, 0);
2577 current_operation = SELECT;
2578 highlighted_item = selection_number;
2579 highlighted_ptr = current_item;
2580 button_highlighted = 0;
2581 list_highlighted = 1;
2584 do_selection_change = 1;
2588 // Pressed over nothing. Start rectangle selection.
2590 if( get_buttonpress() == 1 &&
2591 selection_mode == LISTBOX_MULTIPLE ) {
2592 if( !shift_down() ) {
2593 // Deselect all and redraw if anything was selected
2594 if( get_selection_number(0, 0) >= 0 ) {
2595 set_all_selected(data, 0);
2597 do_selection_change = 1;
2602 // Promote selections to protect from a rectangle selection
2603 promote_selections(data, 1, 2);
2606 // Start rectangle selection
2607 current_operation = SELECT_RECT;
2608 rect_x1 = rect_x2 = get_cursor_x();
2609 rect_y1 = rect_y2 = get_cursor_y();
2617 // Suggestion box is not active but visible, so lie to get it to deactivate
2618 if( is_popup && (active || (is_suggestions && gui)) ) {
2620 if( debug ) printf("BC_ListBox::button_press_event %d\n", __LINE__);
2626 if( do_selection_change ) selection_changed();
2627 if( debug ) printf("BC_ListBox::button_press_event %d %d\n", __LINE__, result);
2632 int BC_ListBox::button_release_event()
2635 int cursor_x, cursor_y;
2639 //printf("BC_ListBox::button_release_event 1 %d\n", current_operation);
2640 switch( current_operation ) {
2642 current_operation = NO_OPERATION;
2647 current_operation = NO_OPERATION;
2651 // Release item selection
2652 case BUTTON_DOWN_SELECT:
2654 //printf("BC_ListBox::button_release_event 10\n");
2655 unset_repeat(get_resources()->scroll_repeat);
2656 current_operation = NO_OPERATION;
2658 translate_coordinates(top_level->event_win, gui->win,
2659 gui->get_cursor_x(), gui->get_cursor_y(),
2660 &cursor_x, &cursor_y);
2661 selection_number1 = selection_number =
2662 get_cursor_item(data, cursor_x, cursor_y);
2663 //printf("BC_ListBox::button_release_event %d %d\n", selection_number2, selection_number1);
2668 if( selection_number >= 0 ) {
2673 // Second button release outside button
2674 if( button_releases > 1 ) {
2679 if( top_level->get_double_click() &&
2680 selection_number2 == selection_number1 &&
2681 selection_number2 >= 0 && selection_number1 >= 0 ) {
2690 unset_repeat(get_resources()->scroll_repeat);
2692 // Demote selections from rectangle selection
2693 promote_selections(data, 2, 1);
2696 // Hide rectangle overlay
2698 current_operation = NO_OPERATION;
2702 // Release popup button
2705 current_operation = NO_OPERATION;
2709 // Second button release inside button
2710 if( button_releases > 1 ) {
2717 current_operation = NO_OPERATION;
2718 // Update the sort column and the sort order for the user only if the existing
2719 // sort column is valid.
2720 if( sort_column >= 0 ) {
2721 // Invert order only if column is the same
2722 if( highlighted_title == sort_column )
2723 sort_order = sort_order == SORT_ASCENDING ?
2724 SORT_DESCENDING : SORT_ASCENDING;
2725 // Set the new sort column
2726 sort_column = highlighted_title;
2727 if( !sort_order_event() ) {
2732 // Sorting not enabled. Redraw the title state.
2740 int redraw_toggles = 0;
2741 for( int i=0; i<expanders.total&&!result; ++i ) {
2742 if( expanders.values[i]->button_release_event(&redraw_toggles) ) {
2746 // Need to redraw items because of alpha
2747 if( redraw_toggles ) draw_items(1);
2748 current_operation = NO_OPERATION;
2752 // Can't default to NO_OPERATION because it may be used in a drag event.
2757 if( do_event ) handle_event();
2759 //printf("BC_ListBox::button_release_event %d %d\n", __LINE__, get_window_lock());
2763 int BC_ListBox::get_title_h()
2765 if( display_format == LISTBOX_TEXT ||
2766 display_format == LISTBOX_ICON_LIST )
2767 return column_titles ? column_bg[0]->get_h() : 0;
2771 void BC_ListBox::reset_cursor(int new_cursor)
2774 if( gui->get_cursor() != new_cursor ) {
2775 gui->set_cursor(new_cursor, 0, 0);
2779 if( get_cursor() != new_cursor ) {
2780 set_cursor(new_cursor, 0, 0);
2784 int BC_ListBox::test_column_divisions(int cursor_x, int cursor_y, int &new_cursor)
2786 if( gui && column_titles &&
2787 cursor_y >= 0 && cursor_y < get_title_h() &&
2788 cursor_x >= 0 && cursor_x < gui->get_w() ) {
2789 for( int i=1; i<columns; ++i ) {
2790 if( cursor_x >= -xposition + get_column_offset(i) - 5 &&
2791 cursor_x < -xposition + get_column_offset(i) +
2792 get_resources()->listbox_title_hotspot ) {
2793 highlighted_item = -1;
2794 highlighted_ptr = 0;
2795 highlighted_division = i;
2796 highlighted_title = -1;
2797 list_highlighted = 1;
2798 new_cursor = HSEPARATE_CURSOR;
2803 highlighted_division = -1;
2807 int BC_ListBox::test_column_titles(int cursor_x, int cursor_y)
2809 if( gui && column_titles &&
2810 cursor_y >= 0 && cursor_y < get_title_h() &&
2811 cursor_x >= 0 && cursor_x < gui->get_w() ) {
2812 for( int i=0; i<columns; ++i ) {
2813 if( cursor_x >= -xposition + get_column_offset(i) &&
2814 (cursor_x < -xposition + get_column_offset(i + 1) ||
2815 i == columns - 1) ) {
2816 highlighted_item = -1;
2817 highlighted_ptr = 0;
2818 highlighted_division = -1;
2819 highlighted_title = i;
2820 list_highlighted = 1;
2825 highlighted_title = -1;
2829 int BC_ListBox::test_expanders()
2831 for( int i=0; i<expanders.total; ++i ) {
2832 if( expanders.values[i]->button_press_event() ) {
2833 current_operation = EXPAND_DN;
2841 int BC_ListBox::cursor_motion_event()
2843 int redraw = 0, result = 0;
2844 int new_cursor = ARROW_CURSOR;
2846 selection_number = -1;
2849 switch( current_operation ) {
2851 // Button pressed and slid off button
2852 if( !cursor_inside() ) {
2853 current_operation = BUTTON_DOWN_SELECT;
2859 case DRAG_DIVISION: {
2860 // int new_w = get_cursor_x() +
2862 // get_column_offset(highlighted_division - 1);
2863 int difference = get_cursor_x() + xposition - drag_cursor_x;
2864 int new_w = drag_column_w + difference;
2866 new_cursor = HSEPARATE_CURSOR;
2868 if( column_width ) {
2869 column_width[highlighted_division - 1] = new_w;
2872 default_column_width[highlighted_division - 1] = new_w;
2875 column_width_boundaries();
2877 // Force update of coords
2878 set_autoplacement(data, 0, 1);
2879 column_resize_event();
2883 update_scrollbars(1);
2888 if( test_drag_scroll(get_cursor_x(), get_cursor_y()) ) {
2889 set_repeat(get_resources()->scroll_repeat);
2892 int old_x1 = MIN(rect_x1, rect_x2);
2893 int old_x2 = MAX(rect_x1, rect_x2);
2894 int old_y1 = MIN(rect_y1, rect_y2);
2895 int old_y2 = MAX(rect_y1, rect_y2);
2897 int new_rect_x2 = get_cursor_x();
2898 int new_rect_y2 = get_cursor_y();
2900 int x1 = MIN(rect_x1, new_rect_x2);
2901 int x2 = MAX(rect_x1, new_rect_x2);
2902 int y1 = MIN(rect_y1, new_rect_y2);
2903 int y2 = MAX(rect_y1, new_rect_y2);
2905 // Adjust rectangle coverage
2906 if( old_x1 != x1 || old_x2 != x2 ||
2907 old_y1 != y1 || old_y2 != y2 ) {
2909 redraw = select_rectangle(data, x1, y1, x2, y2);
2914 //printf("BC_ListBox::cursor_motion_event %d\n", __LINE__);
2919 rect_x2 = get_cursor_x();
2920 rect_y2 = get_cursor_y();
2924 update_scrollbars(1);
2925 selection_changed();
2926 //printf("BC_ListBox::cursor_motion_event %d\n", __LINE__);
2929 if( old_x1 != x1 || old_x2 != x2 ||
2930 old_y1 != y1 || old_y2 != y2 ) {
2931 //printf("BC_ListBox::cursor_motion_event %d\n", __LINE__);
2939 int old_highlighted_item = highlighted_item;
2941 if( test_drag_scroll(get_cursor_x(),
2943 set_repeat(get_resources()->scroll_repeat);
2947 highlighted_item = selection_number = get_cursor_item(data,
2948 get_cursor_x(), get_cursor_y(), &highlighted_ptr);
2951 // Deselect all items and select just the one we're over
2952 if( selection_number >= 0 && !allow_drag &&
2953 ((!shift_down() && !ctrl_down()) ||
2954 selection_mode == LISTBOX_SINGLE) ) {
2955 redraw = update_selection(data, selection_number);
2958 // Expand multiple selection
2959 if( selection_mode == LISTBOX_MULTIPLE &&
2960 (shift_down() || ctrl_down()) ) {
2961 // Expand selected region in text mode centered around initial range
2962 if( (display_format == LISTBOX_TEXT ||
2963 display_format == LISTBOX_ICON_LIST) &&
2965 // Deselect everything.
2966 set_all_selected(data, 0);
2968 // Select just the items
2969 redraw = expand_selection(0, selection_number);
2971 // Set the one item we're over to the selection value determined in
2972 // button_press_event.
2974 set_selected(data, selection_number, new_value);
2978 if( highlighted_item != old_highlighted_item ) {
2981 update_scrollbars(1);
2982 //printf("BC_ListBox::cursor_motion_event %d %d\n", highlighted_item, old_highlighted_item);
2983 selection_changed();
2987 case BUTTON_DOWN_SELECT:
2988 // Went back into button area
2989 if( cursor_inside() ) {
2990 current_operation = BUTTON_DN;
2995 // Went into item area
2997 int cursor_x = 0, cursor_y = 0;
2998 translate_coordinates(top_level->event_win, gui->win,
2999 top_level->cursor_x, top_level->cursor_y,
3000 &cursor_x, &cursor_y);
3001 int old_highlighted_item = highlighted_item;
3002 highlighted_item = selection_number = get_cursor_item(data,
3007 if( highlighted_item != old_highlighted_item ) {
3008 update_selection(data, selection_number);
3010 selection_changed();
3016 int redraw_toggles = 0;
3017 for( int i=0; i<expanders.total&&!result; ++i ) {
3018 result = expanders.values[i]->cursor_motion_event(
3021 if( redraw_toggles ) {
3022 // Need to redraw items because of the alpha
3027 case NO_OPERATION: {
3028 int cursor_x = get_cursor_x(), cursor_y = get_cursor_y();
3029 if( gui && top_level->event_win == gui->win ) {
3030 int old_highlighted_title = highlighted_title;
3031 int old_list_highlighted = list_highlighted;
3032 int old_highlighted_item = highlighted_item;
3033 int redraw_titles = 0;
3034 int redraw_border = 0;
3035 int redraw_items = 0;
3036 int redraw_toggles = 0;
3039 // Test if cursor moved over a title division
3040 test_column_divisions(cursor_x, cursor_y, new_cursor);
3042 // Test if cursor moved over a title
3043 if( highlighted_division < 0 ) {
3044 test_column_titles(cursor_x, cursor_y);
3047 // Test if cursor moved over expander
3048 if( highlighted_division < 0 && highlighted_title < 0 &&
3049 (display_format == LISTBOX_TEXT ||
3050 display_format == LISTBOX_ICON_LIST) ) {
3051 for( int i=0; i<expanders.total; ++i ) {
3052 expanders.values[i]->cursor_motion_event(
3055 //printf("BC_ListBox::cursor_motion_event %d\n", redraw_toggles);
3058 // Test if cursor moved over an item
3059 if( highlighted_division < 0 && highlighted_title < 0 ) {
3060 highlighted_item = get_cursor_item(data,
3067 // Clear title highlighting if moved over division
3068 if( old_highlighted_title != highlighted_title ) {
3072 // Highlight list border
3073 if( old_list_highlighted != list_highlighted ) {
3077 // Moved out of item area
3078 if( old_highlighted_item != highlighted_item ) {
3082 //printf("BC_ListBox::cursor_motion_event 1 %d\n", highlighted_item);
3084 // Change cursor to title division adjustment
3085 reset_cursor(new_cursor);
3087 if( redraw_items ) {
3095 if( redraw_toggles )
3099 if( redraw_items || redraw_titles ||
3100 redraw_border || redraw_toggles ) {
3107 if( !result && list_highlighted ) {
3108 list_highlighted = 0;
3109 highlighted_item = -1;
3110 highlighted_ptr = 0;
3111 highlighted_title = -1;
3112 highlighted_division = -1;
3122 int BC_ListBox::drag_start_event()
3124 switch( current_operation ) {
3126 if( gui && gui->is_event_win() && allow_drag ) {
3127 BC_ListBoxItem *item_return = 0;
3128 selection_number = get_cursor_item(data,
3129 top_level->cursor_x,
3130 top_level->cursor_y,
3133 if( selection_number >= 0 ) {
3135 get_abs_cursor(cx, cy);
3136 if( item_return->icon_vframe ) {
3137 drag_popup = new BC_DragWindow(this,
3138 item_return->icon_vframe, cx, cy);
3141 if( item_return->icon ) {
3142 drag_popup = new BC_DragWindow(this,
3143 item_return->icon, cx, cy);
3146 drag_popup = new BC_DragWindow(this,
3147 drag_icon_vframe, cx, cy);
3149 current_operation = DRAG_ITEM;
3150 // require shift down for scrolling
3151 if( allow_drag < 0 && shift_down() )
3152 set_repeat(get_resources()->scroll_repeat);
3159 if( gui && gui->is_event_win() && allow_drag_column ) {
3161 get_abs_cursor(cx, cy);
3162 cx -= drag_column_icon_vframe->get_w() / 2,
3163 cy -= drag_column_icon_vframe->get_h() / 2;
3164 drag_popup = new BC_DragWindow(this,
3165 drag_column_icon_vframe, cx, cy);
3166 dragged_title = highlighted_title;
3167 current_operation = COLUMN_DRAG;
3177 int BC_ListBox::drag_motion_event()
3179 //printf("BC_ListBox::drag_motion_event 1 %d\n", current_operation);
3180 switch( current_operation ) {
3183 int new_highlighted_item = -1;
3184 BC_ListBoxItem *new_highlighted_ptr = 0;
3185 new_highlighted_item = get_cursor_item(data,
3186 top_level->cursor_x, top_level->cursor_y,
3187 &new_highlighted_ptr);
3189 if( new_highlighted_item != highlighted_item ) {
3193 // Always update highlighted value for drag_stop
3194 highlighted_item = new_highlighted_item;
3195 highlighted_ptr = new_highlighted_ptr;
3196 //printf("BC_ListBox::drag_motion_event 1 %p\n", highlighted_ptr);
3200 update_scrollbars(1);
3203 return drag_popup->cursor_motion_event(); }
3206 int old_highlighted_title = highlighted_title;
3207 test_column_titles(get_cursor_x(), get_cursor_y());
3208 if( old_highlighted_title != highlighted_title ) {
3211 return drag_popup->cursor_motion_event(); }
3217 int BC_ListBox::drag_stop_event()
3220 switch( current_operation ) {
3222 unset_repeat(get_resources()->scroll_repeat);
3223 // Inside window boundary
3224 if( top_level->cursor_x > 0 &&
3225 top_level->cursor_x < gui->get_w() - drag_popup->get_w() / 2 &&
3226 top_level->cursor_y > 0 &&
3227 top_level->cursor_y < gui->get_h() - drag_popup->get_h() / 2 ) {
3231 if( display_format == LISTBOX_ICONS ) {
3232 reposition_item(data,
3234 top_level->cursor_x - drag_popup->get_w() / 2 -
3235 LISTBOX_MARGIN - 2 + xposition,
3236 top_level->cursor_y - drag_popup->get_h() / 2 -
3237 LISTBOX_MARGIN - 2 + yposition);
3241 if( process_drag ) {
3242 // Move selected items from data to temporary
3243 ArrayList<BC_ListBoxItem*> *src_items =
3244 new ArrayList<BC_ListBoxItem*>[columns];
3245 move_selection(src_items, data);
3247 int destination = highlighted_item = item_to_index(data,
3249 // Insert items from temporary to data
3250 put_selection(data, src_items, destination);
3252 delete [] src_items;
3253 set_autoplacement(data, 0, 1);
3259 drag_popup->drag_failure_event();
3264 if( dragged_title != highlighted_title ) {
3265 if( highlighted_title >= 0 ) {
3266 if( !move_column_event() ) draw_titles(1);
3269 drag_popup->drag_failure_event();
3275 current_operation = NO_OPERATION;
3285 BC_DragWindow* BC_ListBox::get_drag_popup()
3290 int BC_ListBox::translation_event()
3292 if( is_popup && gui ) {
3293 int new_x = gui->get_x() +
3294 (top_level->last_translate_x - top_level->prev_x -
3295 BC_DisplayInfo::get_left_border());
3296 int new_y = gui->get_y() +
3297 (top_level->last_translate_y - top_level->prev_y -
3298 BC_DisplayInfo::get_top_border());
3300 gui->reposition_window(new_x, new_y);
3306 int BC_ListBox::reposition_window(int x, int y, int w, int h, int flush)
3310 if( h != -1 ) popup_h = h;
3311 //printf("BC_ListBox::reposition_window %d %d\n", popup_w, popup_h);
3315 xscrollbar->reposition_window(get_xscroll_x(),
3317 get_xscroll_width());
3319 yscrollbar->reposition_window(get_yscroll_x(),
3321 get_yscroll_height());
3325 BC_WindowBase::reposition_window(x, y, w, h);
3331 int BC_ListBox::deactivate()
3334 // printf("BC_ListBox::deactivate %d this=%p gui=%p active=%d\n",
3335 // __LINE__, this, gui, active);
3338 //printf("BC_ListBox::deactivate %d this=%p gui=%p\n", __LINE__, this, gui);
3340 delete gui; gui = 0;
3345 highlighted_item = -1;
3346 highlighted_ptr = 0;
3349 //printf("BC_ListBox::deactivate %d this=%p\n", __LINE__, this);
3351 top_level->active_subwindow = 0;
3357 int BC_ListBox::activate(int take_focus)
3359 if( active ) return 0;
3362 set_active_subwindow(this);
3363 button_releases = 0;
3364 if( !is_popup || gui ) return 0;
3365 int wx = get_x(), wy = get_y() + get_h();
3366 if( justify == LISTBOX_RIGHT ) wx += get_w() - popup_w;
3369 XTranslateCoordinates(top_level->display,
3370 parent_window->win, top_level->rootwin,
3371 wx, wy, &abs_x, &abs_y, &xwin);
3374 return activate(abs_x, abs_y);
3377 int BC_ListBox::activate(int x, int y, int w, int h)
3379 if( !is_popup || gui ) return 0;
3381 if( w != -1 ) popup_w = w;
3382 if( h != -1 ) popup_h = h;
3384 if( y + popup_h > top_level->get_root_h(0) )
3385 y -= get_h() + popup_h;
3386 add_subwindow(gui = new BC_Popup(this,
3387 x, y, popup_w, popup_h, -1, 0, 0));
3389 gui->show_window(1);
3393 int BC_ListBox::is_active()
3398 int BC_ListBox::keypress_event()
3400 if( !active ) return 0;
3402 //printf("BC_ListBox::keypress_event %d\n", __LINE__);
3404 int result = 0, redraw = 0;
3405 int view_items = last_in_view - first_in_view + 1;
3406 if( view_items <= 0 ) view_items = view_h / get_text_height(MEDIUMFONT);
3407 int new_item = -1, new_selection = -1;
3409 switch( top_level->get_keypress() ) {
3412 top_level->deactivate();
3414 // If user is manipulating popup with keyboard, don't pass on event.
3416 //printf("BC_ListBox::keypress_event %d %p\n", __LINE__, get_selection(0, 0));
3417 if( top_level->get_keypress() == RETURN )
3419 //printf("BC_ListBox::keypress_event %d %p\n", __LINE__, get_selection(0, 0));
3427 new_selection = new_item = select_previous(0);
3429 //printf("BC_ListBox::keypress_event 1 %d\n", new_item);
3430 if( new_item >= 0 ) {
3431 center_selection(new_item);
3439 new_selection = new_item = select_next(0);
3441 if( new_item >= 0 ) {
3442 center_selection(new_item);
3450 new_selection = new_item = select_previous(view_items - 1);
3452 if( new_item >= 0 ) {
3453 center_selection(new_item);
3461 new_selection = new_item = select_next(view_items - 1);
3463 if( new_item >= 0 ) {
3464 center_selection(new_item);
3490 if( !ctrl_down() ) {
3491 int query_len = strlen(query);
3492 if( query_len < (int)sizeof(query)-1 &&
3493 top_level->get_keypress() > 30 &&
3494 top_level->get_keypress() < 127 ) {
3495 query[query_len++] = top_level->get_keypress();
3496 query[query_len] = 0;
3497 new_selection = query_list();
3500 if( top_level->get_keypress() == BACKSPACE ) {
3501 if( query_len > 0 ) query[--query_len] = 0;
3502 new_selection = query_list();
3506 show_tooltip(query);
3519 update_scrollbars(1);
3522 //printf("BC_ListBox::keypress_event %d new_selection=%d\n", __LINE__, new_selection);
3523 if( new_selection >= 0 && !is_suggestions ) {
3524 //printf("BC_ListBox::keypress_event %d\n", __LINE__);
3525 selection_changed();
3526 //printf("BC_ListBox::keypress_event %d\n", __LINE__);
3533 BC_Pixmap* BC_ListBox::get_bg_surface()
3539 void BC_ListBox::draw_background()
3541 if( !bg_draw ) return;
3543 // White background pixmap
3544 set_color(top_level->get_resources()->listbox_inactive);
3545 draw_box(0, 0, bg_surface->get_w(), bg_surface->get_h(), bg_surface);
3547 // Optional heroine pixmap
3549 bg_surface->draw_pixmap(bg_pixmap,
3550 bg_surface->get_w() - top_level->get_resources()->listbox_bg->get_w(),
3554 void BC_ListBox::clear_listbox(int x, int y, int w, int h)
3556 gui->draw_pixmap(bg_surface, x, y, w, h, x, y - title_h);
3559 void BC_ListBox::update_format(int display_format, int redraw)
3561 this->display_format = display_format;
3562 xposition = 0; yposition = 0;
3563 if( redraw && gui ) draw_items(1, 1);
3566 int BC_ListBox::get_format()
3568 return display_format;
3573 int BC_ListBox::draw_items(int flush, int draw_bg)
3576 BC_Resources *resources = get_resources();
3578 //dump(data, columns);
3580 // Calculate items width
3581 calculate_item_coords();
3582 // Create and destroy scrollbars as needed
3585 if( bg_draw ) this->bg_draw = 1;
3591 if( display_format == LISTBOX_ICONS ) {
3592 clear_listbox(2, 2 + title_h, view_w, view_h);
3594 set_font(MEDIUMFONT);
3595 for( int i=0; i<data[master_column].size(); ++i ) {
3596 BC_ListBoxItem *item = data[master_column].get(i);
3597 if( get_item_x(item) >= -get_item_w(item) &&
3598 get_item_x(item) < view_w &&
3599 get_item_y(item) >= -get_item_h(item) + title_h &&
3600 get_item_y(item) < view_h + title_h ) {
3601 item->set_in_view(1);
3602 if( first_in_view < 0 ) first_in_view = i;
3604 int item_color = get_item_highlight(data, 0, i);
3605 int icon_x, icon_y, icon_w, icon_h;
3606 int text_x, text_y, text_w, text_h;
3609 get_icon_mask(item, icon_x, icon_y, icon_w, icon_h);
3610 get_text_mask(item, text_x, text_y, text_w, text_h);
3612 if( item_color != resources->listbox_inactive ) {
3613 gui->set_color(BLACK);
3614 gui->draw_rectangle(icon_x, icon_y, icon_w, icon_h);
3615 gui->set_color(item_color);
3616 gui->draw_box(icon_x + 1, icon_y + 1, icon_w - 2, icon_h - 2);
3617 gui->set_color(BLACK);
3618 gui->draw_rectangle(text_x, text_y, text_w, text_h);
3619 gui->set_color(item_color);
3620 gui->draw_box(text_x + 1, text_y + 1, text_w - 2, text_h - 2);
3622 if( icon_position == ICON_LEFT )
3623 gui->draw_box(text_x - 1, text_y + 1, 2, text_h - 2);
3625 if( icon_position == ICON_TOP )
3626 gui->draw_line(text_x + 1, text_y, text_x + icon_w - 2, text_y);
3627 if( text_x + text_w < icon_x + icon_w ) {
3628 gui->set_color(BLACK);
3629 gui->draw_line(text_x + text_w, icon_y + icon_h,
3630 icon_x + icon_w, icon_y + icon_h);
3634 gui->set_color(get_item_color(data, 0, i));
3636 gui->pixmap->draw_pixmap(item->icon,
3637 icon_x + ICON_MARGIN, icon_y + ICON_MARGIN);
3639 gui->draw_text(text_x + ICON_MARGIN,
3640 text_y + ICON_MARGIN + get_baseline(item), item->text);
3643 item->set_in_view(0);
3648 // Draw one column at a time so text overruns don't go into the next column
3649 // clear column backgrounds
3650 int current_toggle = 0;
3651 for( int j=0; j<columns; ++j ) {
3652 clear_listbox(LISTBOX_BORDER + get_column_offset(j) - xposition,
3653 LISTBOX_BORDER + title_h,
3654 get_column_width(j, 1),
3656 // Draw rows in the column recursively
3657 draw_text_recursive(data, j, 0, ¤t_toggle);
3660 // Delete excess expanders
3661 while( expanders.total > current_toggle ) {
3662 expanders.remove_object();
3666 // draw user images if available
3668 // Draw titles on top of rows for superposition effect
3671 // Clear garbage from bottom right corner
3672 if( xscrollbar && yscrollbar && is_popup ) {
3673 gui->draw_top_background(parent_window,
3674 popup_w - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w(),
3675 popup_h - get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h(),
3676 get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w(),
3677 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h());
3684 if( current_operation == SELECT_RECT )
3694 void BC_ListBox::draw_text_recursive(ArrayList<BC_ListBoxItem*> *data,
3695 int column, int indent, int *current_toggle)
3698 BC_Resources *resources = get_resources();
3700 set_font(MEDIUMFONT);
3703 // Search for a branch and make room for toggle if there is one
3705 for( int i=0; i<data[column].size(); ++i ) {
3706 if( data[column].get(i)->get_sublist() ) {
3707 subindent = BC_WindowBase::get_resources()->listbox_expand[0]->get_w();
3713 row_height = row_ascent = row_descent = 0;
3714 for( int i=0; i<data[column].total; ++i ) {
3715 BC_ListBoxItem *item = data[column].values[i];
3716 int ht = get_text_h(item);
3717 if( ht > row_height ) row_height = ht;
3718 int bl = get_baseline(item);
3719 if( bl > row_ascent ) row_ascent = bl;
3721 if( dt > row_descent ) row_ascent = bl;
3724 for( int i=0; i<data[column].size(); ++i ) {
3726 BC_ListBoxItem *item = data[column].values[i];
3727 BC_ListBoxItem *first_item = data[master_column].values[i];
3729 if( get_item_y(item) >= -get_item_h(item) + title_h &&
3730 get_item_y(item) < view_h + title_h ) {
3731 int row_color = get_item_highlight(data, 0, i);
3732 int x, y, w, h, column_width;
3734 get_text_mask(item, x, y, w, h);
3735 column_width = get_column_width(column, 1);
3736 if( x + column_width > view_w + LISTBOX_BORDER * 2 )
3737 column_width = view_w + LISTBOX_BORDER * 2 - x;
3739 if( row_color != resources->listbox_inactive ) {
3740 gui->set_color(row_color);
3741 gui->draw_box(x, y, column_width, h);
3742 gui->set_color(BLACK);
3743 int xx = x + column_width-1;
3744 gui->draw_line(x, y, xx, y);
3746 if( display_format == LISTBOX_ICON_LIST ) {
3747 int ih = get_icon_h(item);
3748 if( ih > hh ) hh = ih;
3751 gui->draw_line(x, yy, xx, yy);
3754 gui->set_color(get_item_color(data, column, i));
3757 if( column == 0 && display_format == LISTBOX_ICON_LIST ) {
3759 gui->pixmap->draw_pixmap(item->icon, x, y);
3760 x += item->icon->get_w() + ICON_MARGIN;
3765 // Indent only applies to first column
3767 x + LISTBOX_BORDER + LISTBOX_MARGIN +
3768 (column == 0 ? indent + subindent : 0),
3769 y + get_baseline(item), item->text);
3770 item->set_in_view(1);
3772 if( first_in_view < 0 ) first_in_view = i;
3777 if( column == 0 && item->get_sublist() && item->get_columns() ) {
3778 // Create new expander
3779 if( *current_toggle >= expanders.total ) {
3780 BC_ListBoxToggle *toggle =
3781 new BC_ListBoxToggle(this, item,
3782 x + LISTBOX_BORDER + LISTBOX_MARGIN + indent, y);
3784 expanders.append(toggle);
3786 // Reposition existing expander
3788 BC_ListBoxToggle *toggle = expanders.values[*current_toggle];
3789 //printf("BC_ListBox::draw_text_recursive 1 %d\n", *current_toggle);
3790 toggle->update(item,
3791 x + LISTBOX_BORDER + LISTBOX_MARGIN + indent, y, 0);
3793 (*current_toggle)++;
3800 item->set_in_view(0);
3802 // Descend into sublist
3803 if( first_item->get_expand() ) {
3804 draw_text_recursive(first_item->get_sublist(),
3806 indent + LISTBOX_INDENT,
3812 int BC_ListBox::draw_border(int flash)
3814 BC_Resources *resources = top_level->get_resources();
3815 gui->draw_3d_border(0, 0,
3816 view_w + LISTBOX_BORDER * 2, view_h + title_h + LISTBOX_BORDER * 2,
3817 resources->listbox_border1,
3819 resources->listbox_border2_hi : resources->listbox_border2,
3821 resources->listbox_border3_hi : resources->listbox_border3,
3822 resources->listbox_border4);
3831 void BC_ListBox::draw_title(int number)
3833 // Column title background
3834 int image_number = 0;
3835 if( number == highlighted_title ) {
3837 if( current_operation == COLUMN_DN )
3841 gui->draw_3segmenth(get_column_offset(number) - xposition + LISTBOX_BORDER,
3843 get_column_width(number, 1) + get_resources()->listbox_title_overlap,
3844 column_bg[image_number]);
3846 int title_x = -xposition + get_column_offset(number) +
3847 LISTBOX_MARGIN + LISTBOX_BORDER;
3848 title_x += get_resources()->listbox_title_margin;
3850 gui->set_color(get_resources()->listbox_title_color);
3851 gui->draw_text(title_x,
3852 LISTBOX_MARGIN + LISTBOX_BORDER + get_text_ascent(MEDIUMFONT),
3853 column_titles[number]);
3855 // Column sort order
3856 if( number == sort_column ) {
3857 BC_Pixmap *src = sort_order == SORT_ASCENDING ?
3858 column_sort_dn : column_sort_up;
3860 // int column_offset = get_column_offset(number) - xposition + LISTBOX_BORDER;
3861 // int column_width = get_column_width(number, 1);
3862 // int toggle_x = column_offset + column_width - LISTBOX_BORDER;
3863 // if( toggle_x > items_w ) toggle_x = items_w;
3864 // toggle_x -= 5 + src->get_w();
3867 get_text_width(MEDIUMFONT, column_titles[number]) +
3870 gui->draw_pixmap(src,
3872 title_h / 2 - src->get_h() / 2 + LISTBOX_BORDER);
3876 int BC_ListBox::draw_titles(int flash)
3878 if( column_titles &&
3879 (display_format == LISTBOX_TEXT ||
3880 display_format == LISTBOX_ICON_LIST) ) {
3881 //printf("BC_ListBox::draw_titles 1 %d\n", highlighted_title);
3882 for( int i=0; i<columns; ++i ) {
3883 if( i != highlighted_title )
3887 if( highlighted_title >= 0 ) draw_title(highlighted_title);
3897 void BC_ListBox::draw_toggles(int flash)
3899 for( int i=0; i<expanders.total; ++i )
3900 expanders.values[i]->draw(0);
3902 //printf("BC_ListBox::draw_toggles 1 %d\n", flash);
3903 if( flash && expanders.total ) {
3908 int BC_ListBox::draw_rectangle(int flash)
3910 int x1 = MIN(rect_x1, rect_x2);
3911 int x2 = MAX(rect_x1, rect_x2);
3912 int y1 = MIN(rect_y1, rect_y2);
3913 int y2 = MAX(rect_y1, rect_y2);
3915 if( x1 == x2 || y1 == y2 ) return 0;
3918 gui->set_color(WHITE);
3919 gui->draw_rectangle(x1, y1, x2 - x1, y2 - y1);
3929 void BC_ListBox::dump(ArrayList<BC_ListBoxItem*> *data, int columns,
3930 int indent, int master_column)
3933 printf("BC_ListBox::dump 1\n");
3936 for( int i=0; i<data[master_column].total; ++i ) {
3937 for( int k=0; k<indent; ++k )
3939 for( int j=0; j<columns; ++j ) {
3940 BC_ListBoxItem *item = data[j].values[i];
3941 printf("%d,%d,%d=%s ",
3942 item->get_text_x(), item->get_text_y(),
3943 item->autoplace_text, item->get_text());
3947 if( data[master_column].values[i]->get_sublist() ) {
3948 dump(data[master_column].values[i]->get_sublist(),
3949 data[master_column].values[i]->get_columns(),