• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files

hvirtual/guicast/bclistbox.C

Go to the documentation of this file.
00001 #include "bcdragwindow.h"
00002 #include "bclistbox.h"
00003 #include "bclistboxitem.h"
00004 #include "bcpixmap.h"
00005 #include "bcresources.h"
00006 #include "bcsignals.h"
00007 #include "clip.h"
00008 #include "cursors.h"
00009 #include "fonts.h"
00010 #include "keys.h"
00011 #include "language.h"
00012 #include "bctimer.h"
00013 #include "vframe.h"
00014 
00015 #include <string.h>
00016 #include <unistd.h>
00017 
00018 // ====================================================== scrollbars
00019 
00020 
00021 BC_ListBoxYScroll::BC_ListBoxYScroll(BC_ListBox *listbox, 
00022                           int total_height, 
00023                                           int view_height, 
00024                           int position)
00025  : BC_ScrollBar(listbox->get_yscroll_x(), 
00026         listbox->get_yscroll_y(), 
00027         SCROLL_VERT, 
00028         listbox->get_yscroll_height(), 
00029         total_height, 
00030         position, 
00031         view_height)
00032 {
00033         this->listbox = listbox;
00034 }
00035 
00036 BC_ListBoxYScroll::~BC_ListBoxYScroll()
00037 {
00038 }
00039 
00040 int BC_ListBoxYScroll::handle_event()
00041 {
00042         listbox->set_yposition(get_value());
00043         return 1;
00044 }
00045 
00046 
00047 
00048 
00049 
00050 
00051 
00052 BC_ListBoxXScroll::BC_ListBoxXScroll(BC_ListBox *listbox, 
00053                           int total_width, 
00054                                           int view_width,
00055                           int position)
00056  : BC_ScrollBar(listbox->get_xscroll_x(), 
00057         listbox->get_xscroll_y(), 
00058         SCROLL_HORIZ, 
00059         listbox->get_xscroll_width(), 
00060         total_width, 
00061         position, 
00062         view_width)
00063 {
00064         this->listbox = listbox;
00065 }
00066 
00067 BC_ListBoxXScroll::~BC_ListBoxXScroll()
00068 {
00069 }
00070 
00071 int BC_ListBoxXScroll::handle_event()
00072 {
00073         listbox->set_xposition(get_value());
00074         return 1;
00075 }
00076 
00077 
00078 
00079 
00080 
00081 
00082 
00083 
00084 BC_ListBoxToggle::BC_ListBoxToggle(BC_ListBox *listbox, 
00085         BC_ListBoxItem *item, 
00086         int x, 
00087         int y)
00088 {
00089         this->listbox = listbox;
00090         this->item = item;
00091         this->x = x;
00092         this->y = y;
00093         this->value = item->get_expand();
00094         if(this->value) 
00095                 state = BC_Toggle::TOGGLE_CHECKED;
00096         else
00097                 state = BC_Toggle::TOGGLE_UP;
00098 }
00099 
00100 void BC_ListBoxToggle::update(BC_ListBoxItem *item, 
00101         int x, 
00102         int y,
00103         int flash)
00104 {
00105         this->value = item->get_expand();
00106         this->item = item;
00107         this->x = x;
00108         this->y = y;
00109 
00110 // update state
00111         switch(state)
00112         {
00113                 case TOGGLE_UP:
00114                         if(value)
00115                                 state = TOGGLE_CHECKED;
00116                         break;
00117 
00118                 case TOGGLE_UPHI:
00119                         if(value)
00120                                 state = TOGGLE_CHECKEDHI;
00121                         break;
00122 
00123                 case TOGGLE_CHECKED:
00124                         if(!value)
00125                                 state = TOGGLE_UP;
00126                         break;
00127 
00128                 case TOGGLE_DOWN:
00129                         break;
00130 
00131                 case TOGGLE_CHECKEDHI:
00132                         if(!value)
00133                                 state = TOGGLE_UPHI;
00134                         break;
00135 
00136                 case TOGGLE_DOWN_EXIT:
00137                         break;
00138         }
00139 
00140 
00141         draw(flash);
00142 }
00143 
00144 int BC_ListBoxToggle::cursor_motion_event(int *redraw_toggles)
00145 {
00146         int w = listbox->toggle_images[0]->get_w();
00147         int h = listbox->toggle_images[0]->get_h();
00148         int cursor_inside = listbox->get_cursor_x() >= x && 
00149                 listbox->get_cursor_x() < x + w &&
00150                 listbox->get_cursor_y() >= y && 
00151                 listbox->get_cursor_y() < y + h;
00152         int result = 0;
00153 
00154         switch(state)
00155         {
00156                 case BC_ListBoxToggle::TOGGLE_UPHI:
00157                         if(!cursor_inside)
00158                         {
00159                                 state = BC_ListBoxToggle::TOGGLE_UP;
00160                                 *redraw_toggles = 1;
00161                         }
00162                         break;
00163 
00164                 case BC_ListBoxToggle::TOGGLE_CHECKEDHI:
00165                         if(!cursor_inside)
00166                         {
00167                                 state = BC_ListBoxToggle::TOGGLE_CHECKED;
00168                                 *redraw_toggles = 1;
00169                         }
00170                         break;
00171 
00172                 case BC_ListBoxToggle::TOGGLE_DOWN:
00173                         if(!cursor_inside)
00174                         {
00175                                 state = BC_ListBoxToggle::TOGGLE_DOWN_EXIT;
00176                                 *redraw_toggles = 1;
00177                         }
00178                         result = 1;
00179                         break;
00180 
00181                 case BC_ListBoxToggle::TOGGLE_DOWN_EXIT:
00182                         if(cursor_inside)
00183                         {
00184                                 state = BC_ListBoxToggle::TOGGLE_DOWN;
00185                                 *redraw_toggles = 1;
00186                         }
00187                         result = 1;
00188                         break;
00189 
00190                 default:
00191                         if(cursor_inside)
00192                         {
00193                                 if(value)
00194                                         state = BC_ListBoxToggle::TOGGLE_CHECKEDHI;
00195                                 else
00196                                         state = BC_ListBoxToggle::TOGGLE_UPHI;
00197                                 *redraw_toggles = 1;
00198                         }
00199                         break;
00200         }
00201         return result;
00202 }
00203 
00204 int BC_ListBoxToggle::cursor_leave_event(int *redraw_toggles)
00205 {
00206         if(value)
00207                 state = BC_ListBoxToggle::TOGGLE_CHECKED;
00208         else
00209                 state = BC_ListBoxToggle::TOGGLE_UP;
00210 }
00211 
00212 int BC_ListBoxToggle::button_press_event()
00213 {
00214         int w = listbox->toggle_images[0]->get_w();
00215         int h = listbox->toggle_images[0]->get_h();
00216 
00217         if(listbox->gui->get_cursor_x() >= x && 
00218                 listbox->gui->get_cursor_x() < x + w &&
00219                 listbox->gui->get_cursor_y() >= y && 
00220                 listbox->gui->get_cursor_y() < y + h)
00221         {
00222                 state = BC_ListBoxToggle::TOGGLE_DOWN;
00223                 return 1;
00224         }
00225         return 0;
00226 }
00227 
00228 int BC_ListBoxToggle::button_release_event(int *redraw_toggles)
00229 {
00230         int result = 0;
00231         switch(state)
00232         {
00233                 case BC_ListBoxToggle::TOGGLE_DOWN:
00234                         value = !value;
00235                         if(value)
00236                                 state = BC_ListBoxToggle::TOGGLE_CHECKEDHI;
00237                         else
00238                                 state = BC_ListBoxToggle::TOGGLE_UPHI;
00239                         listbox->expand_item(item, value);
00240                         result = 1;
00241                         break;
00242 
00243                 case BC_ListBoxToggle::TOGGLE_DOWN_EXIT:
00244                         if(value)
00245                                 state = BC_ListBoxToggle::TOGGLE_CHECKED;
00246                         else
00247                                 state = BC_ListBoxToggle::TOGGLE_UP;
00248                         *redraw_toggles = 1;
00249                         result = 1;
00250                         break;
00251         }
00252         return result;
00253 }
00254 
00255 void BC_ListBoxToggle::draw(int flash)
00256 {
00257         if(listbox->gui)
00258         {
00259                 int image_number = 0;
00260                 int w = listbox->toggle_images[0]->get_w();
00261                 int h = listbox->toggle_images[0]->get_h();
00262 
00263                 switch(state)
00264                 {
00265                         case BC_ListBoxToggle::TOGGLE_UP: image_number = 0; break;
00266                         case BC_ListBoxToggle::TOGGLE_UPHI: image_number = 1; break;
00267                         case BC_ListBoxToggle::TOGGLE_CHECKED: image_number = 2; break;
00268                         case BC_ListBoxToggle::TOGGLE_DOWN: image_number = 3; break;
00269                         case BC_ListBoxToggle::TOGGLE_CHECKEDHI: image_number = 4; break;
00270                         case BC_ListBoxToggle::TOGGLE_DOWN_EXIT:
00271                                 if(value)
00272                                         image_number = 2;
00273                                 else
00274                                         image_number = 0;
00275                                 break;
00276                 }
00277 
00278 //printf("BC_ListBoxToggle::draw 1 %d\n", state);
00279                 listbox->gui->draw_pixmap(listbox->toggle_images[image_number],
00280                         x,
00281                         y);
00282 
00283 
00284                 if(flash)
00285                 {
00286                         listbox->gui->flash(x, y, w, h);
00287                         listbox->gui->flush();
00288                 }
00289         }
00290 }
00291 
00292 
00293 
00294 
00295 
00296 
00297 
00298 
00299 
00300 
00301 
00302 
00303 
00304 
00305 // ====================================================== box
00306 
00307 BC_ListBox::BC_ListBox(int x, 
00308         int y, 
00309         int w, 
00310         int h,
00311         int display_format,
00312         ArrayList<BC_ListBoxItem*> *data,
00313         char **column_titles,
00314         int *column_width,
00315         int columns,
00316         int yposition,
00317         int is_popup,
00318         int selection_mode,
00319         int icon_position,
00320         int allow_drag)
00321  : BC_SubWindow(x, y, w, h, -1)
00322 {
00323         justify = LISTBOX_RIGHT;
00324         xposition = 0;
00325         highlighted_item = -1;
00326         highlighted_title = -1;
00327         highlighted_division = -1;
00328         highlighted_ptr = 0;
00329         xscrollbar = 0;
00330         yscrollbar = 0;
00331         current_cursor = ARROW_CURSOR;
00332         gui = 0;
00333         view_h = 0;
00334         view_w = 0;
00335         title_h = 0;
00336         active = 0;
00337         new_value = 0;
00338         need_xscroll = 0;
00339         need_yscroll = 0;
00340         bg_tile = 0;
00341         drag_popup = 0;
00342         selection_number1 = -1;
00343         selection_number2 = -1;
00344         bg_surface = 0;
00345         bg_pixmap = 0;
00346 
00347         current_operation = NO_OPERATION;
00348         button_highlighted = 0;
00349 
00350         disabled = 0;
00351 
00352         list_highlighted = 0;
00353 
00354         allow_drag_scroll = 1;
00355         process_drag = 1;
00356 
00357         sort_column = -1;
00358         sort_order = 0;
00359 
00360         allow_drag_column = 0;
00361         master_column = 0;
00362         search_column = 0;
00363 
00364         popup_w = w;
00365         popup_h = h;
00366 
00367         for(int i = 0; i < 3; i++)
00368                 column_bg[i] = 0;
00369 
00370         for(int i = 0; i < 4; i++)
00371                 button_images[i] = 0;
00372 
00373         for(int i = 0; i < 5; i++)
00374                 toggle_images[i] = 0;
00375 
00376         column_sort_up = 0;
00377         column_sort_dn = 0;
00378 
00379 //printf("BC_ListBox::BC_ListBox 1\n");
00380         this->data = data;
00381         this->columns = columns;
00382         this->yposition = yposition;
00383         this->is_popup = is_popup;
00384         this->display_format = display_format;
00385         this->selection_mode = selection_mode;
00386         this->icon_position = icon_position;
00387         this->allow_drag = allow_drag;
00388         this->column_titles = 0;
00389         this->column_width = 0;
00390 //printf("BC_ListBox::BC_ListBox 1\n");
00391 
00392         if((!column_titles && column_width) ||
00393                 (column_titles && !column_width))
00394         {
00395                 printf("BC_ListBox::BC_ListBox either column_titles or column_widths == NULL but not both.\n");
00396         }
00397 //printf("BC_ListBox::BC_ListBox 2 %p %p\n", column_titles, column_width);
00398         set_columns(column_titles, 
00399                 column_width, 
00400                 columns);
00401 
00402 //printf("BC_ListBox::BC_ListBox 3\n");
00403 
00404         drag_icon_vframe = 0;
00405         drag_column_icon_vframe = 0;
00406 
00407 
00408 
00409 // reset the search engine
00410 //printf("BC_ListBox::BC_ListBox 4\n");
00411         reset_query();
00412 //printf("BC_ListBox::BC_ListBox 5\n");
00413 }
00414 
00415 BC_ListBox::~BC_ListBox()
00416 {
00417         expanders.remove_all_objects();
00418         if(bg_surface) delete bg_surface;
00419         if(bg_pixmap) delete bg_pixmap;
00420         if(xscrollbar) delete xscrollbar;
00421         if(yscrollbar) delete yscrollbar;
00422         for(int i = 0; i < 3; i++)
00423                 if(column_bg[i]) delete column_bg[i];
00424         for(int i = 0; i < 4; i++)
00425                 if(button_images[i]) delete button_images[i];
00426         for(int i = 0; i < 5; i++)
00427                 if(toggle_images[i]) delete toggle_images[i];
00428         if(column_sort_up) delete column_sort_up;
00429         if(column_sort_dn) delete column_sort_dn;
00430 
00431         delete_columns();
00432         if(drag_popup) delete drag_popup;
00433 }
00434 
00435 int BC_ListBox::enable()
00436 {
00437   disabled = 0;
00438   draw_button();
00439   return 1;
00440 }
00441 
00442 int BC_ListBox::disable()
00443 {
00444   disabled = 1;
00445   draw_button();
00446   return 1;
00447 }
00448 
00449 void BC_ListBox::reset_query()
00450 {
00451         query[0] = 0;  // reset query
00452 }
00453 
00454 int BC_ListBox::evaluate_query(int list_item, char *string)
00455 {
00456         return(strcmp(string, data[search_column].values[list_item]->text) <= 0 && 
00457                 data[search_column].values[list_item]->searchable);
00458 }
00459 
00460 int BC_ListBox::query_list()
00461 {
00462         if(query[0] == 0) return 0;
00463 
00464         int done = 0;
00465         int result;
00466         int selection_changed = 0;
00467         int prev_selection = -1;
00468         for(int i = 0; !done && i < data[0].total; i++)
00469         {
00470                 if(evaluate_query(i, query))
00471                 {
00472                         result = i;
00473                         done = 1;
00474                 }
00475         }
00476 
00477         if(done)
00478         {
00479 // Deselect all
00480                 for(int i = 0; i < data[0].total; i++)
00481                 {
00482                         for(int j = 0; j < columns; j++)
00483                         {
00484                                 if(data[j].values[i]->selected) prev_selection = i;
00485                                 data[j].values[i]->selected = 0;
00486                         }
00487                 }
00488 
00489 // Select one
00490                 if(prev_selection != result)
00491                         selection_changed = 1;
00492                 for(int j = 0; j < columns; j++)
00493                 {
00494                         data[j].values[result]->selected = 1;
00495                 }
00496                 center_selection(result);
00497         }
00498 
00499         return selection_changed;
00500 }
00501 
00502 void BC_ListBox::init_column_width()
00503 {
00504         if(!column_width && data)
00505         {
00506                 int widest = 5, w;
00507                 for(int i = 0; i < data[0].total; i++)
00508                 {
00509                 w = get_text_width(MEDIUMFONT, data[0].values[i]->get_text()) + 2 * LISTBOX_MARGIN;
00510                         if(w > widest) widest = w;
00511                 }
00512                 default_column_width[0] = widest;
00513         }
00514 }
00515 
00516 int BC_ListBox::initialize()
00517 {
00518         if(is_popup)
00519         {
00520                 for(int i = 0; i < 4; i++)
00521                 {
00522                         button_images[i] = new BC_Pixmap(parent_window, 
00523                                 BC_WindowBase::get_resources()->listbox_button[i], 
00524                                 PIXMAP_ALPHA);
00525                 }
00526                 w = button_images[0]->get_w();
00527                 h = button_images[0]->get_h();
00528                 
00529                 gui = 0;
00530                 current_operation = NO_OPERATION;
00531         }
00532         else
00533         {
00534                 gui = this;
00535                 current_operation = NO_OPERATION;
00536         }
00537 
00538         for(int i = 0; i < 3; i++)
00539         {
00540                 column_bg[i] = new BC_Pixmap(parent_window,
00541                         get_resources()->listbox_column[i],
00542                         PIXMAP_ALPHA);
00543         }
00544         for(int i = 0; i < 5; i++)
00545         {
00546                 toggle_images[i] = new BC_Pixmap(parent_window,
00547                         get_resources()->listbox_expand[i],
00548                         PIXMAP_ALPHA);
00549         }
00550 
00551         column_sort_up = new BC_Pixmap(parent_window, 
00552                 BC_WindowBase::get_resources()->listbox_up, 
00553                 PIXMAP_ALPHA);
00554         column_sort_dn = new BC_Pixmap(parent_window, 
00555                 BC_WindowBase::get_resources()->listbox_dn, 
00556                 PIXMAP_ALPHA);
00557 
00558 //printf("BC_ListBox::initialize 10\n");
00559         drag_icon_vframe = get_resources()->type_to_icon[ICON_UNKNOWN];
00560         drag_column_icon_vframe = get_resources()->type_to_icon[ICON_COLUMN];
00561 // = new BC_Pixmap(parent_window, 
00562 //              get_resources()->type_to_icon[ICON_UNKNOWN], 
00563 //              PIXMAP_ALPHA);
00564 //      drag_column_icon = new BC_Pixmap(parent_window,
00565 //              get_resources()->type_to_icon[ICON_COLUMN],
00566 //              PIXMAP_ALPHA);
00567         BC_SubWindow::initialize();
00568 
00569         init_column_width();
00570 
00571         if(top_level->get_resources()->listbox_bg)
00572                 bg_pixmap = new BC_Pixmap(this, 
00573                         get_resources()->listbox_bg, 
00574                         PIXMAP_OPAQUE);
00575 
00576         draw_button();
00577         draw_items(1);
00578         return 0;
00579 }
00580 
00581 void BC_ListBox::deactivate_selection()
00582 {
00583         current_operation = NO_OPERATION;
00584 }
00585 
00586 int BC_ListBox::draw_button()
00587 {
00588 // Draw the button for a popup listbox
00589         if(is_popup)
00590         {
00591                 int image_number = 0;
00592 
00593                 draw_top_background(parent_window, 0, 0, w, h);
00594 
00595                 if(button_highlighted)
00596                         image_number = 1;
00597                 if(current_operation == BUTTON_DN)
00598                         image_number = 2;
00599                 if(disabled)
00600                         image_number = 3;
00601 
00602 
00603                 pixmap->draw_pixmap(button_images[image_number], 
00604                         0, 
00605                         0,
00606                         w,
00607                         h,
00608                         0,
00609                         0);
00610                 flash();
00611         }
00612         return 0;
00613 }
00614 
00615 int BC_ListBox::calculate_item_coords()
00616 {
00617         if(!data) return 0;
00618 
00619         int icon_x = 0;
00620         int next_icon_x = 0;
00621         int next_icon_y = 0;
00622         int next_text_y = 0;
00623 // Change the display_format to get the right item dimensions for both
00624 // text and icons.
00625         int display_format_temp = display_format;
00626 
00627 
00628 // Scan the first column for lowest y coord of all text
00629 // and lowest right x and y coord for all icons which aren't auto placable
00630         calculate_last_coords_recursive(data,
00631                 &icon_x,
00632                 &next_icon_x, 
00633                 &next_icon_y,
00634                 &next_text_y,
00635                 1);
00636 
00637 // Reset last column width.  It's recalculated based on text width.
00638 
00639         calculate_item_coords_recursive(data,
00640                 &icon_x,
00641                 &next_icon_x, 
00642                 &next_icon_y,
00643                 &next_text_y,
00644                 1);
00645 
00646 
00647 
00648         display_format = display_format_temp;
00649 
00650         return 0;
00651 }
00652 
00653 void BC_ListBox::calculate_last_coords_recursive(
00654         ArrayList<BC_ListBoxItem*> *data,
00655         int *icon_x,
00656         int *next_icon_x,
00657         int *next_icon_y,
00658         int *next_text_y,
00659         int top_level)
00660 {
00661         for(int i = 0; i < data[0].total; i++)
00662         {
00663                 int current_text_y = 0;
00664                 int current_icon_x = 0;
00665                 int current_icon_y = 0;
00666                 BC_ListBoxItem *item = data[0].values[i];
00667 
00668 // Get next_text_y
00669                 if(!item->autoplace_text)
00670                 {
00671 // Lowest text coordinate
00672                         display_format = LISTBOX_TEXT;
00673                         current_text_y = item->text_y + 
00674                                 get_text_height(MEDIUMFONT);
00675                         if(current_text_y > *next_text_y)
00676                                 *next_text_y = current_text_y;
00677 
00678 // Add sublist depth if it is expanded
00679                         if(item->get_sublist() && 
00680                                 item->get_columns() &&
00681                                 item->get_expand())
00682                         {
00683                                 calculate_last_coords_recursive(item->get_sublist(),
00684                                         icon_x,
00685                                         next_icon_x, 
00686                                         next_icon_y,
00687                                         next_text_y,
00688                                         0);
00689                         }
00690                 }
00691 
00692 // Get next_icon coordinate
00693                 if(top_level)
00694                 {
00695                         BC_ListBoxItem *item = data[master_column].values[i];
00696                         if(!item->autoplace_icon)
00697                         {
00698                                 display_format = LISTBOX_ICONS;
00699 // Lowest right icon coordinate.
00700                                 current_icon_x = item->icon_x;
00701                                 if(current_icon_x > *icon_x) *icon_x = current_icon_x;
00702                                 if(current_icon_x + get_item_w(item) > *next_icon_x)
00703                                         *next_icon_x = current_icon_x + get_item_w(item);
00704 
00705                                 current_icon_y = item->icon_y + get_item_h(item);
00706                                 if(current_icon_y > *next_icon_y) 
00707                                         *next_icon_y = current_icon_y;
00708                         }
00709                 }
00710         }
00711 }
00712 
00713 
00714 void BC_ListBox::calculate_item_coords_recursive(
00715         ArrayList<BC_ListBoxItem*> *data,
00716         int *icon_x,
00717         int *next_icon_x,
00718         int *next_icon_y,
00719         int *next_text_y,
00720         int top_level)
00721 {
00722 
00723 
00724 
00725 // Set up items which need autoplacement.
00726 // Should fill icons down and then across
00727         for(int i = 0; i < data[0].total; i++)
00728         {
00729 // Don't increase y unless the row requires autoplacing.
00730                 int total_autoplaced_columns = 0;
00731 
00732 // Set up icons in first column
00733                 if(top_level)
00734                 {
00735                         BC_ListBoxItem *item = data[master_column].values[i];
00736                         if(item->autoplace_icon)
00737                         {
00738 // 1 column only if icons are used
00739                                 display_format = LISTBOX_ICONS;
00740 // Test row height
00741 // Start new row.
00742                                 if(*next_icon_y + get_item_h(item) >= get_h() && 
00743                                         *next_icon_y > 0)
00744                                 {
00745                                         *icon_x = *next_icon_x;
00746                                         *next_icon_y = 0;
00747                                 }
00748 
00749                                 if(*icon_x + get_item_w(item) > *next_icon_x)
00750                                         *next_icon_x = *icon_x + get_item_w(item);
00751 
00752 
00753                                 item->set_icon_x(*icon_x);
00754                                 item->set_icon_y(*next_icon_y);
00755 
00756                                 *next_icon_y += get_item_h(item);
00757                         }
00758                 }
00759 
00760 
00761 
00762 // Set up a text row
00763                 int next_text_x = 0;
00764                 for(int j = 0; j < columns; j++)
00765                 {
00766                         BC_ListBoxItem *item = data[j].values[i];
00767                         if(item->autoplace_text)
00768                         {
00769                                 display_format = LISTBOX_TEXT;
00770                                 item->set_text_x(next_text_x);
00771                                 item->set_text_y(*next_text_y);
00772 
00773 // printf("BC_ListBox::calculate_item_coords_recursive %p %d %d %d %d %s \n", 
00774 // item->get_sublist(), 
00775 // item->get_columns(), 
00776 // item->get_expand(), 
00777 // next_text_x, 
00778 // *next_text_y,
00779 // item->get_text());
00780 // Increment position of next column
00781                                 if(j < columns - 1)
00782                                         next_text_x += (column_width ? 
00783                                                 column_width[j] : 
00784                                                 default_column_width[j]);
00785                                 else
00786 // Set last column width based on text width
00787                                 {
00788                                         int new_w = get_item_w(item);
00789 
00790                                         int *previous_w = (column_width ? 
00791                                                 &column_width[j] : 
00792                                                 &default_column_width[j]);
00793                                         if(new_w > *previous_w)
00794                                                 *previous_w = new_w;
00795 //printf("BC_ListBox::calculate_item_coords_recursive 1 %d\n", new_w);
00796                                 }
00797                                 total_autoplaced_columns++;
00798                         }
00799                 }
00800 
00801 // Increase the text vertical position
00802                 if(total_autoplaced_columns)
00803                 {
00804                         display_format = LISTBOX_TEXT;
00805                         *next_text_y += get_text_height(MEDIUMFONT);
00806                 }
00807 
00808 // Set up a sublist
00809                 BC_ListBoxItem *item = data[master_column].values[i];
00810                 if(item->get_sublist() &&
00811                         item->get_columns() &&
00812                         item->get_expand())
00813                 {
00814                         calculate_item_coords_recursive(
00815                                 item->get_sublist(),
00816                                 icon_x,
00817                                 next_icon_x,
00818                                 next_icon_y,
00819                                 next_text_y,
00820                                 0);
00821                 }
00822         }
00823 }
00824 
00825 void BC_ListBox::set_justify(int value)
00826 {
00827         this->justify = value;
00828 }
00829 
00830 void BC_ListBox::set_allow_drag_column(int value)
00831 {
00832         this->allow_drag_column = value;
00833 }
00834 
00835 void BC_ListBox::set_process_drag(int value)
00836 {
00837         this->process_drag = value;
00838 }
00839 
00840 void BC_ListBox::set_master_column(int value, int redraw)
00841 {
00842         this->master_column = value;
00843         if(redraw)
00844         {
00845                 draw_items(1);
00846         }
00847 }
00848 
00849 void BC_ListBox::set_search_column(int value)
00850 {
00851         this->search_column = value;
00852 }
00853 
00854 int BC_ListBox::get_sort_column()
00855 {
00856         return sort_column;
00857 }
00858 
00859 void BC_ListBox::set_sort_column(int value, int redraw)
00860 {
00861         sort_column = value;
00862         if(redraw)
00863         {
00864                 draw_titles(1);
00865         }
00866 }
00867 
00868 int BC_ListBox::get_sort_order()
00869 {
00870         return sort_order;
00871 }
00872 
00873 void BC_ListBox::set_sort_order(int value, int redraw)
00874 {
00875         sort_order = value;
00876         if(redraw)
00877         {
00878                 draw_titles(1);
00879         }
00880 }
00881 
00882 
00883 
00884 
00885 
00886 int BC_ListBox::get_display_mode()
00887 {
00888         return display_format;
00889 }
00890 
00891 int BC_ListBox::get_yposition()
00892 {
00893         return yposition;
00894 }
00895 
00896 int BC_ListBox::get_xposition()
00897 {
00898         return xposition;
00899 }
00900 
00901 int BC_ListBox::get_highlighted_item()
00902 {
00903         return highlighted_item;
00904 }
00905 
00906 
00907 int BC_ListBox::get_item_x(BC_ListBoxItem *item)
00908 {
00909         if(display_format == LISTBOX_TEXT)
00910                 return item->text_x - xposition + 2;
00911         else
00912                 return item->icon_x - xposition + 2;
00913 }
00914 
00915 int BC_ListBox::get_item_y(BC_ListBoxItem *item)
00916 {
00917         int result;
00918         if(display_format == LISTBOX_TEXT)
00919                 result = item->text_y - yposition + title_h + 2;
00920         else
00921                 result = item->icon_y - yposition + title_h + 2;
00922         return result;
00923 }
00924 
00925 int BC_ListBox::get_item_w(BC_ListBoxItem *item)
00926 {
00927         if(display_format == LISTBOX_ICONS)
00928         {
00929                 int x, y, w, h;
00930                 get_icon_mask(item, x, y, w, h);
00931                 int icon_w = w;
00932                 get_text_mask(item, x, y, w, h);
00933                 int text_w = w;
00934 
00935                 if(icon_position == ICON_LEFT)
00936                         return icon_w + text_w;
00937                 else
00938                         return (icon_w > text_w) ? icon_w : text_w;
00939         }
00940         else
00941         {
00942                 return get_text_width(MEDIUMFONT, item->text) + 2 * LISTBOX_MARGIN;
00943         }
00944 }
00945 
00946 int BC_ListBox::get_item_h(BC_ListBoxItem *item)
00947 {
00948         if(display_format == LISTBOX_ICONS)
00949         {
00950                 int x, y, w, h;
00951                 get_icon_mask(item, x, y, w, h);
00952                 int icon_h = h;
00953                 get_text_mask(item, x, y, w, h);
00954                 int text_h = h;
00955 
00956                 if(icon_position == ICON_LEFT)
00957                         return (icon_h > text_h) ? icon_h : text_h;
00958                 else
00959                         return icon_h + text_h;
00960         }
00961         else
00962         {
00963                 return get_text_height(MEDIUMFONT);
00964         }
00965         return 0;
00966 }
00967 
00968 
00969 int BC_ListBox::get_icon_w(BC_ListBoxItem *item)
00970 {
00971         BC_Pixmap *icon = item->icon;
00972         if(icon) return icon->get_w();
00973         return 0;
00974 }
00975 
00976 int BC_ListBox::get_icon_h(BC_ListBoxItem *item)
00977 {
00978         BC_Pixmap *icon = item->icon;
00979         if(icon) return icon->get_h();
00980         return 0;
00981 }
00982 
00983 int BC_ListBox::get_items_width()
00984 {
00985         int widest = 0;
00986 
00987         if(display_format == LISTBOX_ICONS)
00988         {
00989                 for(int i = 0; i < columns; i++)
00990                 {
00991                         for(int j = 0; j < data[i].total; j++)
00992                         {
00993                                 int x1, x, y, w, h;
00994                                 BC_ListBoxItem *item = data[i].values[j];
00995                                 x1 = item->icon_x;
00996 
00997                                 get_icon_mask(item, x, y, w, h);
00998                                 if(x1 + w > widest) widest = x1 + w;
00999 
01000                                 if(display_format == LISTBOX_ICONS && icon_position == ICON_LEFT)
01001                                         x1 += w;
01002 
01003                                 get_text_mask(item, x, y, w, h);
01004                                 if(x1 + w > widest) widest = x1 + w;
01005                         }
01006                 }
01007         }
01008         else
01009         if(display_format == LISTBOX_TEXT)
01010         {
01011                 return get_column_offset(columns);
01012         }
01013         return widest;
01014 }
01015 
01016 int BC_ListBox::get_items_height(ArrayList<BC_ListBoxItem*> *data, 
01017         int columns,
01018         int *result)
01019 {
01020         int temp = 0;
01021         int top_level = 0;
01022         int highest = 0;
01023         if(!result)
01024         {
01025                 result = &temp;
01026                 top_level = 1;
01027         }
01028 
01029 
01030 
01031 
01032 
01033         for(int j = 0; j < (data ? data[master_column].total : 0); j++)
01034         {
01035                 int y1, x, y, w, h;
01036                 BC_ListBoxItem *item = data[master_column].values[j];
01037 
01038                 if(display_format == LISTBOX_ICONS)
01039                 {
01040                         get_icon_mask(item, x, y, w, h);
01041                         if(y + h + yposition > highest) highest = y + h + yposition;
01042 
01043                         get_text_mask(item, x, y, w, h);
01044                         if(y + h + yposition > highest) highest = y + h + yposition;
01045                 }
01046                 else
01047                 {
01048                         get_text_mask(item, x, y, w, h);
01049                         *result += h;
01050 
01051 
01052 // Descend into sublist
01053                         if(item->get_sublist() &&
01054                                 item->get_expand())
01055                         {
01056                                 get_items_height(item->get_sublist(), 
01057                                         item->get_columns(), 
01058                                         result);
01059                         }
01060                 }
01061         }
01062         if(display_format == LISTBOX_TEXT && top_level) 
01063         {
01064                 highest = LISTBOX_MARGIN + *result;
01065         }
01066 
01067 
01068         return highest;
01069 }
01070 
01071 int BC_ListBox::set_yposition(int position, int draw_items)
01072 {
01073         this->yposition = position;
01074         if(draw_items)
01075         {
01076                 this->draw_items(1);
01077         }
01078         return 0;
01079 }
01080 
01081 int BC_ListBox::set_xposition(int position)
01082 {
01083         this->xposition = position;
01084         draw_items(1);
01085         return 0;
01086 }
01087 
01088 void BC_ListBox::expand_item(BC_ListBoxItem *item, int expand)
01089 {
01090         if(item)
01091         {
01092                 item->expand = expand;
01093 // Collapse sublists if this is collapsed to make it easier to calculate
01094 // coordinates
01095                 if(item->get_sublist())
01096                         collapse_recursive(item->get_sublist(), master_column);
01097 
01098 
01099 // Set everything for autoplacement
01100                 
01101                 set_autoplacement(data, 0, 1);
01102 
01103                 draw_items(1);
01104         }
01105 }
01106 
01107 void BC_ListBox::collapse_recursive(ArrayList<BC_ListBoxItem*> *data,
01108                 int master_column)
01109 {
01110         for(int i = 0; i < data[master_column].total; i++)
01111         {
01112                 BC_ListBoxItem *item = data[master_column].values[i];
01113                 if(item->get_sublist() && item->expand)
01114                 {
01115                         item->expand = 0;
01116                         collapse_recursive(item->get_sublist(), master_column);
01117                 }
01118         }
01119 }
01120 
01121 void BC_ListBox::set_autoplacement(ArrayList<BC_ListBoxItem*> *data,
01122         int do_icons, 
01123         int do_text)
01124 {
01125         for(int i = 0; i < data[0].total; i++)
01126         {
01127                 for(int j = 0; j < columns; j++)
01128                 {
01129                         if(do_icons) data[j].values[i]->autoplace_icon = 1;
01130                         if(do_text) data[j].values[i]->autoplace_text = 1;
01131                 }
01132 
01133                 BC_ListBoxItem *item = data[master_column].values[i];
01134                 if(item->get_sublist())
01135                 {
01136                         set_autoplacement(item->get_sublist(), do_icons, do_text);
01137                 }
01138         }
01139 }
01140 
01141 
01142 
01143 int BC_ListBox::get_w()
01144 {
01145         if(is_popup)
01146                 return BCPOPUPLISTBOX_W;
01147         else
01148                 return popup_w;
01149 }
01150 
01151 int BC_ListBox::get_h()
01152 {
01153         if(is_popup)
01154                 return BCPOPUPLISTBOX_H;
01155         else
01156                 return popup_h;
01157 }
01158 
01159 int BC_ListBox::get_yscroll_x()
01160 {
01161         if(is_popup)
01162                 return popup_w - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w();
01163         else
01164                 return get_x() + 
01165                         popup_w - 
01166                         get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w();
01167 }
01168 
01169 int BC_ListBox::get_yscroll_y()
01170 {
01171         if(is_popup)
01172                 return 0;
01173         else
01174                 return get_y();
01175 }
01176 
01177 int BC_ListBox::get_yscroll_height()
01178 {
01179         return popup_h - (need_xscroll ? 
01180                 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h() : 
01181                 0);
01182 }
01183 
01184 int BC_ListBox::get_xscroll_x()
01185 {
01186         if(is_popup)
01187                 return 0;
01188         else
01189                 return get_x();
01190 }
01191 
01192 int BC_ListBox::get_xscroll_y()
01193 {
01194         if(is_popup)
01195                 return popup_h - 
01196                         get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h();
01197         else
01198                 return get_y() + 
01199                         popup_h - 
01200                         get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h();
01201 }
01202 
01203 int BC_ListBox::get_xscroll_width()
01204 {
01205         return popup_w - (need_yscroll ? 
01206                 get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w() : 
01207                 0);
01208 }
01209 
01210 int BC_ListBox::get_column_offset(int column)
01211 {
01212         int x = 0;
01213         while(column > 0)
01214         {
01215                 x += column_width ? 
01216                         column_width[--column] : 
01217                         default_column_width[--column];
01218         }
01219         return x;
01220 }
01221 
01222 void BC_ListBox::column_width_boundaries()
01223 {
01224         if(column_width)
01225         {
01226                 for(int i = 0; i < columns; i++)
01227                 {
01228                         if(column_width[i] < MIN_COLUMN_WIDTH) column_width[i] = MIN_COLUMN_WIDTH;
01229                 }
01230         }
01231         else
01232         {
01233                 for(int i = 0; i < columns; i++)
01234                 {
01235                         if(default_column_width[i] < MIN_COLUMN_WIDTH) default_column_width[i] = MIN_COLUMN_WIDTH;
01236                 }
01237         }
01238 }
01239 
01240 int BC_ListBox::get_column_width(int column, int clamp_right)
01241 {
01242         if(column < columns - 1 || !clamp_right)
01243                 return column_width ? 
01244                         column_width[column] : 
01245                         default_column_width[column];
01246         else
01247                 return popup_w + 
01248                         xposition - 
01249                         get_column_offset(column);
01250 }
01251 
01252 int BC_ListBox::get_icon_mask(BC_ListBoxItem *item, 
01253         int &x, 
01254         int &y, 
01255         int &w, 
01256         int &h)
01257 {
01258         if(display_format == LISTBOX_ICONS)
01259         {
01260                 x = get_item_x(item);
01261                 y = get_item_y(item);
01262                 w = get_icon_w(item) + ICON_MARGIN * 2;
01263                 h = get_icon_h(item) + ICON_MARGIN * 2;
01264         }
01265         else
01266         if(display_format == LISTBOX_TEXT)
01267         {
01268                 x = y = w = h = 0;
01269         }
01270         return 0;
01271 }
01272 
01273 int BC_ListBox::get_text_mask(BC_ListBoxItem *item, 
01274         int &x, 
01275         int &y, 
01276         int &w, 
01277         int &h)
01278 {
01279         x = get_item_x(item);
01280         y = get_item_y(item);
01281 
01282         if(display_format == LISTBOX_ICONS)
01283         {
01284                 if(icon_position == ICON_LEFT)
01285                 {
01286                         x += get_icon_w(item) + ICON_MARGIN * 2;
01287                         y += get_icon_h(item) - get_text_height(MEDIUMFONT);
01288                 }
01289                 else
01290                 {
01291                         y += get_icon_h(item) + ICON_MARGIN;
01292                 }
01293 
01294                 w = get_text_width(MEDIUMFONT, item->text) + ICON_MARGIN * 2;
01295                 h = get_text_height(MEDIUMFONT) + ICON_MARGIN * 2;
01296         }
01297         else
01298         if(display_format == LISTBOX_TEXT)
01299         {
01300                 w = get_text_width(MEDIUMFONT, item->text) + LISTBOX_MARGIN * 2;
01301                 h = get_text_height(MEDIUMFONT);
01302         }
01303         return 0;
01304 }
01305 
01306 int BC_ListBox::get_item_highlight(ArrayList<BC_ListBoxItem*> *data, 
01307         int column, 
01308         int item)
01309 {
01310         BC_Resources *resources = get_resources();
01311         if(data[column].values[item]->selected)
01312                 return resources->listbox_selected;
01313         else
01314         if(highlighted_item >= 0 &&
01315                 highlighted_ptr == data[master_column].values[item])
01316                 return resources->listbox_highlighted;
01317         else
01318                 return resources->listbox_inactive;
01319 }
01320 
01321 int BC_ListBox::get_item_color(ArrayList<BC_ListBoxItem*> *data, 
01322         int column, 
01323         int item)
01324 {
01325         int color = data[column].values[item]->color;
01326         if(color == -1) color = get_resources()->listbox_text;
01327         if(get_item_highlight(data, column, item) == color)
01328                 return BLACK;
01329         else
01330                 return color;
01331 }
01332 
01333 int BC_ListBox::get_from_column()
01334 {
01335         return dragged_title;
01336 }
01337 
01338 int BC_ListBox::get_to_column()
01339 {
01340         return highlighted_title;
01341 }
01342 
01343 
01344 BC_ListBoxItem* BC_ListBox::get_selection(int column, 
01345         int selection_number)
01346 {
01347         return get_selection_recursive(data,
01348                 column,
01349                 selection_number);
01350 }
01351 
01352 BC_ListBoxItem* BC_ListBox::get_selection_recursive(
01353         ArrayList<BC_ListBoxItem*> *data,
01354         int column,
01355         int selection_number)
01356 {
01357         if(!data) return 0;
01358 
01359         for(int i = 0; i < data[master_column].total; i++)
01360         {
01361                 BC_ListBoxItem *item = data[master_column].values[i];
01362                 if(item->selected)
01363                 {
01364                         selection_number--;
01365                         if(selection_number < 0)
01366                         {
01367 
01368                                 return data[column].values[i];
01369                         }
01370                 }
01371 
01372                 if(item->get_sublist())
01373                 {
01374                         BC_ListBoxItem *result = get_selection_recursive(item->get_sublist(),
01375                                 column,
01376                                 selection_number);
01377                         if(result) return result;
01378                 }
01379         }
01380         return 0;
01381 }
01382 
01383 
01384 int BC_ListBox::get_selection_number(int column, 
01385         int selection_number)
01386 {
01387         return get_selection_number_recursive(data,
01388                 column,
01389                 selection_number);
01390 }
01391 
01392 int BC_ListBox::get_selection_number_recursive(
01393         ArrayList<BC_ListBoxItem*> *data,
01394         int column,
01395         int selection_number,
01396         int *counter)
01397 {
01398         int temp = -1;
01399         if(!data) return 0;
01400         if(!counter) counter = &temp;
01401 
01402         for(int i = 0; i < data[master_column].total; i++)
01403         {
01404                 (*counter)++;
01405                 BC_ListBoxItem *item = data[master_column].values[i];
01406                 if(item->selected)
01407                 {
01408                         selection_number--;
01409                         if(selection_number < 0)
01410                         {
01411                                 return (*counter);
01412                         }
01413                 }
01414                 if(item->get_sublist())
01415                 {
01416                         int result = get_selection_number_recursive(
01417                                 item->get_sublist(),
01418                                 column,
01419                                 selection_number,
01420                                 counter);
01421                         if(result >= 0) return result;
01422                 }
01423         }
01424         return -1;
01425 }
01426 
01427 
01428 int BC_ListBox::set_selection_mode(int mode)
01429 {
01430         this->selection_mode = mode;
01431         return 0;
01432 }
01433 
01434 void BC_ListBox::delete_columns()
01435 {
01436         if(column_titles)
01437         {
01438                 for(int i = 0; i < columns; i++)
01439                 {
01440                         delete [] column_titles[i];
01441                 }
01442                 delete [] column_titles;
01443         }
01444 
01445         if(column_width) delete [] column_width;
01446         
01447         column_titles = 0;
01448         column_width = 0;
01449 }
01450 
01451 // Need to copy titles so EDL can change
01452 void BC_ListBox::set_columns(char **column_titles, 
01453         int *column_width, 
01454         int columns)
01455 {
01456         if((!column_titles && column_width) ||
01457                 (column_titles && !column_width))
01458         {
01459                 printf("BC_ListBox::set_columns either column_titles or column_width == NULL but not both.\n");
01460                 return;
01461         }
01462 
01463 
01464         delete_columns();
01465 
01466         if(column_titles)
01467         {
01468                 this->column_titles = new char*[columns];
01469                 for(int i = 0; i < columns; i++)
01470                 {
01471                         this->column_titles[i] = new char[strlen(column_titles[i]) + 1];
01472                         strcpy(this->column_titles[i], column_titles[i]);
01473                 }
01474         }
01475         
01476         if(column_width)
01477         {
01478                 this->column_width = new int[columns];
01479                 for(int i = 0; i < columns; i++)
01480                 {
01481                         this->column_width[i] = column_width[i];
01482                 }
01483         }
01484         
01485         this->columns = columns;
01486 
01487 }
01488 
01489 
01490 int BC_ListBox::update(ArrayList<BC_ListBoxItem*> *data,
01491         char **column_titles,
01492         int *column_widths,
01493         int columns,
01494         int xposition,
01495         int yposition, 
01496         int highlighted_number,
01497         int recalc_positions,
01498         int draw)
01499 {
01500         set_columns(column_titles, 
01501                 column_widths, 
01502                 columns);
01503 
01504         this->data = data;
01505 
01506         this->yposition = yposition;
01507         this->xposition = xposition;
01508         this->highlighted_item = highlighted_number;
01509         this->highlighted_ptr = index_to_item(data, highlighted_number, 0);
01510 
01511         if(recalc_positions)
01512                 set_autoplacement(data, 1, 1);
01513 
01514         init_column_width();
01515 
01516         if(gui && draw)
01517         {
01518                 draw_background();
01519                 draw_items(1);
01520                 update_scrollbars();
01521         }
01522 
01523         return 0;
01524 }
01525 
01526 void BC_ListBox::center_selection()
01527 {
01528         int selection = get_selection_number(0, 0);
01529 
01530         calculate_item_coords();
01531         center_selection(selection);
01532 
01533 
01534         if(gui)
01535         {
01536                 draw_background();
01537                 draw_items(1);
01538                 update_scrollbars();
01539         }
01540 }
01541 
01542 void BC_ListBox::move_vertical(int pixels)
01543 {
01544 }
01545 
01546 void BC_ListBox::move_horizontal(int pixels)
01547 {
01548 }
01549 
01550 int BC_ListBox::select_previous(int skip, 
01551         BC_ListBoxItem *selected_item,
01552         int *counter,
01553         ArrayList<BC_ListBoxItem*> *data,
01554         int *got_first,
01555         int *got_second)
01556 {
01557         int top_level = 0;
01558         if(!selected_item)
01559                 selected_item = get_selection(0, 0);
01560         int temp = -1;
01561         if(!counter)
01562                 counter = &temp;
01563         int temp2 = 0;
01564         if(!got_first)
01565         {
01566                 got_first = &temp2;
01567                 top_level = 1;
01568         }
01569         int temp3 = 0;
01570         if(!got_second)
01571                 got_second = &temp3;
01572         if(!data)
01573                 data = this->data;
01574         int done = 0;
01575 
01576 // Scan backwards to item pointer.  Then count visible items to get 
01577 // destination.  Repeat to get wraparound.
01578         do
01579         {
01580                 for(int i = data[master_column].total - 1; i >= 0; i--)
01581                 {
01582                         BC_ListBoxItem *current_item = data[master_column].values[i];
01583                         if(current_item->get_sublist() &&
01584                                 current_item->get_expand())
01585                         {
01586                                 int result = select_previous(skip, 
01587                                         selected_item,
01588                                         counter,
01589                                         current_item->get_sublist(),
01590                                         got_first,
01591                                         got_second);
01592                                 if(*got_second)
01593                                 {
01594                                         return result;
01595                                 }
01596                         }
01597 
01598                         if(*got_first)
01599                         {
01600                                 (*counter)++;
01601                                 if((*counter) >= skip)
01602                                 {
01603                                         for(int j = 0; j < columns; j++)
01604                                                 data[j].values[i]->selected = 1;
01605                                         (*got_second) = 1;
01606                                         return item_to_index(this->data, current_item);
01607                                 }
01608                         }
01609                         else
01610                         {
01611                                 if(current_item->selected)
01612                                 {
01613                                         for(int j = 0; j < columns; j++)
01614                                                 data[j].values[i]->selected = 0;
01615                                         (*got_first) = 1;
01616                                         (*counter)++;
01617                                 }
01618                         }
01619                 }
01620 
01621 // Hit bottom of top level without finding a selected item.
01622                 if(top_level && !(*got_first)) (*got_first) = 1;
01623         }while(top_level && data[master_column].total);
01624         return -1;
01625 }
01626 
01627 int BC_ListBox::select_next(int skip, 
01628         BC_ListBoxItem *selected_item,
01629         int *counter,
01630         ArrayList<BC_ListBoxItem*> *data,
01631         int *got_first,
01632         int *got_second)
01633 {
01634         int top_level = 0;
01635         if(!selected_item)
01636                 selected_item = get_selection(0, 0);
01637         int temp = -1;
01638         if(!counter)
01639                 counter = &temp;
01640         int temp2 = 0;
01641         if(!got_first)
01642         {
01643                 got_first = &temp2;
01644                 top_level = 1;
01645         }
01646         int temp3 = 0;
01647         if(!got_second)
01648                 got_second = &temp3;
01649         if(!data)
01650                 data = this->data;
01651         int done = 0;
01652 
01653 // Scan backwards to item pointer.  Then count visible items to get 
01654 // destination.  Repeat to get wraparound.
01655         do
01656         {
01657                 for(int i = 0; i < data[master_column].total; i++)
01658                 {
01659                         BC_ListBoxItem *current_item = data[master_column].values[i];
01660                         if(*got_first)
01661                         {
01662                                 (*counter)++;
01663                                 if((*counter) >= skip)
01664                                 {
01665                                         for(int j = 0; j < columns; j++)
01666                                                 data[j].values[i]->selected = 1;
01667                                         (*got_second) = 1;
01668                                         return item_to_index(this->data, current_item);
01669                                 }
01670                         }
01671                         else
01672                         {
01673                                 if(current_item->selected)
01674                                 {
01675                                         for(int j = 0; j < columns; j++)
01676                                                 data[j].values[i]->selected = 0;
01677                                         (*got_first) = 1;
01678                                         (*counter)++;
01679                                 }
01680                         }
01681 
01682                         if(current_item->get_sublist() &&
01683                                 current_item->get_expand())
01684                         {
01685                                 int result = select_next(skip, 
01686                                         selected_item,
01687                                         counter,
01688                                         current_item->get_sublist(),
01689                                         got_first,
01690                                         got_second);
01691                                 if(*got_second)
01692                                 {
01693                                         return result;
01694                                 }
01695                         }
01696                 }
01697 
01698 // Hit bottom of top level without finding a selected item.
01699                 if(top_level && !(*got_first)) (*got_first) = 1;
01700         }while(top_level && data[master_column].total);
01701         return -1;
01702 }
01703 
01704 
01705 void BC_ListBox::clamp_positions()
01706 {
01707         items_w = get_items_width();
01708         items_h = get_items_height(data, columns);
01709 
01710         if(yposition < 0) yposition = 0;
01711         else
01712         if(yposition > items_h - view_h)
01713                 yposition = items_h - view_h;
01714 
01715         if(yposition < 0) yposition = 0;
01716 
01717         if(xposition < 0) xposition = 0;
01718         else
01719         if(xposition >= items_w - view_w)
01720                 xposition = items_w - view_w;
01721 
01722         if(xposition < 0) xposition = 0;
01723 }
01724 
01725 int BC_ListBox::center_selection(int selection,
01726         ArrayList<BC_ListBoxItem*> *data,
01727         int *counter)
01728 {
01729         int temp = -1;
01730         if(!data) data = this->data;
01731         if(!counter) counter = &temp;
01732 
01733         for(int i = 0; i < data[master_column].total; i++)
01734         {
01735                 (*counter)++;
01736 
01737 // Got it
01738                 BC_ListBoxItem *item = data[master_column].values[i];
01739                 if((*counter) == selection)
01740                 {
01741                         BC_ListBoxItem *top_item = this->data[master_column].values[0];
01742 
01743 
01744                         if(display_format == LISTBOX_ICONS)
01745                         {
01746 // Icon is out of window
01747                                 if(item->icon_y - yposition  > 
01748                                         view_h - get_text_height(MEDIUMFONT) ||
01749                                         item->icon_y - yposition < 0)
01750                                 {
01751                                         yposition = item->icon_y - view_h / 2;
01752                                 }
01753 
01754                                 if(data[master_column].values[selection]->icon_x - xposition > view_w ||
01755                                         data[master_column].values[selection]->icon_x - xposition < 0)
01756                                 {
01757                                         xposition = item->icon_x - view_w / 2;
01758                                 }
01759                         }
01760                         else
01761                         if(display_format == LISTBOX_TEXT)
01762                         {
01763 // Text coordinate is out of window
01764                                 if(item->text_y - yposition  > 
01765                                         view_h - get_text_height(MEDIUMFONT) ||
01766                                         item->text_y - yposition < 0)
01767                                 {
01768                                         yposition = item->text_y - 
01769                                                 top_item->text_y -
01770                                                 view_h / 2;
01771                                 }
01772                         }
01773                         return 1;
01774                 }
01775 
01776 // Descend
01777                 if(item->get_sublist())
01778                 {
01779                         int result = center_selection(selection,
01780                                 item->get_sublist(),
01781                                 counter);
01782                         if(result) return result;
01783                 }
01784         }
01785         return 0;
01786 }
01787 
01788 void BC_ListBox::update_scrollbars()
01789 {
01790         int h_needed = items_h = get_items_height(data, columns);
01791         int w_needed = items_w = get_items_width();
01792 
01793 // if(columns > 0 && column_width)
01794 // printf("BC_ListBox::update_scrollbars 1 %d %d\n", column_width[columns - 1], w_needed);
01795 
01796         if(xscrollbar)
01797         {
01798                 if(xposition != xscrollbar->get_value())
01799                         xscrollbar->update_value(xposition);
01800 
01801                 if(w_needed != xscrollbar->get_length() || 
01802                         view_w != xscrollbar->get_handlelength())
01803                         xscrollbar->update_length(w_needed, xposition, view_w);
01804         }
01805 
01806         if(yscrollbar)
01807         {
01808                 if(yposition != yscrollbar->get_value())
01809                         yscrollbar->update_value(yposition);
01810 
01811                 if(h_needed != yscrollbar->get_length() || view_h != yscrollbar->get_handlelength())
01812                         yscrollbar->update_length(h_needed, yposition, view_h);
01813         }
01814 }
01815 
01816 int BC_ListBox::get_scrollbars()
01817 {
01818         int h_needed = items_h = get_items_height(data, columns);
01819         int w_needed = items_w = get_items_width();
01820 
01821 
01822 
01823         title_h = get_title_h();
01824 
01825         view_h = popup_h - title_h - 4;
01826         view_w = popup_w - 4;
01827 
01828 // Create scrollbars as needed
01829         for(int i = 0; i < 2; i++)
01830         {
01831                 if(w_needed > view_w)
01832                 {
01833                         need_xscroll = 1;
01834                         view_h = popup_h - 
01835                                 title_h - 
01836                                 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h() - 
01837                                 4;
01838                 }
01839                 else
01840                 {
01841                         need_xscroll = 0;
01842                 }
01843 
01844                 if(h_needed > view_h)
01845                 {
01846                         need_yscroll = 1;
01847                         view_w = popup_w - 
01848                                 get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w() - 
01849                                 4;
01850                 }
01851                 else
01852                 {
01853                         need_yscroll = 0;
01854                 }
01855         }
01856 
01857 // Update subwindow size
01858         int new_w = popup_w;
01859         int new_h = popup_h;
01860         if(need_xscroll) new_h -= get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h();
01861         if(need_yscroll) new_w -= get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w();
01862 
01863         if(!is_popup)
01864                 if(new_w != BC_WindowBase::get_w() || new_h != BC_WindowBase::get_h())
01865                         gui->resize_window(new_w, new_h);
01866 
01867         BC_WindowBase *destination = (is_popup ? gui : parent_window);
01868         if(need_xscroll)
01869         {
01870                 if(!xscrollbar)
01871                 {
01872                         destination->add_subwindow(xscrollbar = 
01873                                 new BC_ListBoxXScroll(this, 
01874                                         w_needed, 
01875                                         view_w, 
01876                                         xposition));
01877                         xscrollbar->bound_to = this;
01878                 }
01879                 else
01880                 {
01881                     xscrollbar->update_length(w_needed, xposition, view_w);
01882                         xscrollbar->reposition_window(get_xscroll_x(),
01883                                 get_xscroll_y(),
01884                                 get_xscroll_width());
01885                 }
01886         }
01887         else
01888         {
01889                 if(xscrollbar) delete xscrollbar;
01890                 xscrollbar = 0;
01891                 xposition = 0;
01892         }
01893 
01894         if(need_yscroll)
01895         {
01896                 if(!yscrollbar)
01897                 {
01898                         destination->add_subwindow(yscrollbar = 
01899                                 new BC_ListBoxYScroll(this, 
01900                                         h_needed, 
01901                                         view_h, 
01902                                         yposition));
01903                         yscrollbar->bound_to = this;
01904                 }
01905                 else
01906                 {
01907                         yscrollbar->update_length(h_needed, yposition, view_h);
01908                         yscrollbar->reposition_window(get_yscroll_x(),
01909                                 get_yscroll_y(),
01910                                 get_yscroll_height());
01911                 }
01912         }
01913         else
01914         {
01915                 if(yscrollbar) delete yscrollbar;
01916                 yscrollbar = 0;
01917                 yposition = 0;
01918         }
01919         
01920         if(!bg_surface ||
01921                 view_w + 4 != bg_surface->get_w() ||
01922                 view_h + 4 != bg_surface->get_h())
01923         {
01924                 if(bg_surface) delete bg_surface;
01925                 bg_surface = new BC_Pixmap(gui, view_w + 4, view_h + 4);
01926                 draw_background();
01927         }
01928 
01929         return 0;
01930 }
01931 
01932 
01933 
01934 void BC_ListBox::set_drag_scroll(int value)
01935 {
01936         allow_drag_scroll = value;
01937 }
01938 
01939 
01940 // Test for scrolling by dragging
01941 
01942 int BC_ListBox::test_drag_scroll(int cursor_x, int cursor_y)
01943 {
01944         int result = 0;
01945         if(allow_drag_scroll || 
01946                 current_operation == SELECT_RECT)
01947         {
01948 
01949                 int top_boundary = get_title_h();
01950 
01951                 if(cursor_y < top_boundary ||
01952                         cursor_y >= view_h + title_h + LISTBOX_BORDER * 2 ||
01953                         cursor_x < LISTBOX_BORDER ||
01954                         cursor_x >= view_w + LISTBOX_BORDER)
01955                 {
01956                         result = 1;
01957                 }
01958         }
01959         return result;
01960 }
01961 
01962 int BC_ListBox::drag_scroll_event()
01963 {
01964         int top_boundary = get_title_h();
01965         int result = 0;
01966 
01967         if(get_cursor_y() < top_boundary)
01968         {
01969                 yposition -= top_boundary - get_cursor_y();
01970                 result = 1;
01971         }
01972         else
01973         if(get_cursor_y() >= view_h + title_h + 4)
01974         {
01975                 yposition += get_cursor_y() - (view_h + title_h + 4);
01976                 result = 1;
01977         }
01978 
01979         if(get_cursor_x() < 2)
01980         {
01981                 xposition -= 2 - get_cursor_x();
01982                 result = 1;
01983         }
01984         else
01985         if(get_cursor_x() >= view_w + 2)
01986         {
01987                 xposition += get_cursor_x() - (view_w + 2);
01988                 result = 1;
01989         }
01990         if(result) clamp_positions();
01991         return result;
01992 }
01993 
01994 int BC_ListBox::rectangle_scroll_event()
01995 {
01996         int old_xposition = xposition;
01997         int old_yposition = yposition;
01998         int result = drag_scroll_event();
01999 
02000         if(result)
02001         {
02002                 rect_x1 += old_xposition - xposition;
02003                 rect_y1 += old_yposition - yposition;
02004                 rect_x2 = get_cursor_x();
02005                 rect_y2 = get_cursor_y();
02006 
02007                 int x1 = MIN(rect_x1, rect_x2);
02008                 int x2 = MAX(rect_x1, rect_x2);
02009                 int y1 = MIN(rect_y1, rect_y2);
02010                 int y2 = MAX(rect_y1, rect_y2);
02011 
02012                 if(select_rectangle(data,
02013                         x1, 
02014                         y1,
02015                         x2, 
02016                         y2))
02017                 {
02018                         selection_changed();
02019                 }
02020 
02021                 clamp_positions();
02022                 draw_items(1);
02023                 update_scrollbars();
02024         }
02025         return result;
02026 }
02027 
02028 int BC_ListBox::select_scroll_event()
02029 {
02030         int result = drag_scroll_event();
02031 
02032         if(result)
02033         {
02034                 highlighted_item = selection_number = get_cursor_item(data, 
02035                         get_cursor_x(), 
02036                         get_cursor_y(),
02037                         &highlighted_ptr);
02038                 clamp_positions();
02039                 draw_items(1);
02040                 update_scrollbars();
02041                 selection_changed();
02042         }
02043         return result;
02044 }
02045 
02046 int BC_ListBox::select_rectangle(ArrayList<BC_ListBoxItem*> *data,
02047                 int x1, 
02048                 int y1,
02049                 int x2, 
02050                 int y2)
02051 {
02052         int result = 0;
02053         for(int i = 0; i < data[master_column].total; i++)
02054         {
02055                 for(int j = 0; j < columns; j++)
02056                 {
02057                         BC_ListBoxItem *item = data[j].values[i];
02058                         if(display_format == LISTBOX_ICONS)
02059                         {
02060                                 int icon_x, icon_y, icon_w, icon_h;
02061                                 int text_x, text_y, text_w, text_h;
02062                                 get_icon_mask(item, icon_x, icon_y, icon_w, icon_h);
02063                                 get_text_mask(item, text_x, text_y, text_w, text_h);
02064 
02065                                 if((x2 >= icon_x && x1 < icon_x + icon_w &&
02066                                         y2 >= icon_y && y1 < icon_y + icon_h) ||
02067                                         (x2 >= text_x && x1 < text_x + text_w &&
02068                                         y2 >= text_y && y1 < text_y + text_h))
02069                                 {
02070                                         if(!item->selected)
02071                                         {
02072                                                 item->selected = 1;
02073                                                 result = 1;
02074                                         }
02075                                 }
02076                                 else
02077                                 {
02078                                         if(item->selected)
02079                                         {
02080                                                 item->selected = 0;
02081                                                 result = 1;
02082                                         }
02083                                 }
02084                         }
02085                         else
02086                         {
02087                                 if(x2 >= 0 && 
02088                                         x1 < (yscrollbar ? 
02089                                                 gui->get_w() - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w() : 
02090                                                 gui->get_w()) &&
02091                                         y2 > 0 && 
02092                                         y1 < gui->get_h() &&
02093                                         y2 >= get_item_y(item) &&
02094                                         y1 < get_item_y(item) + get_item_h(item))
02095                                 {
02096                                         if(!item->selected)
02097                                         {
02098                                                 item->selected = 1;
02099                                                 result = 1;
02100                                         }
02101                                 }
02102                                 else
02103                                 {
02104                                         if(item->selected)
02105                                         {
02106                                                 item->selected = 0;
02107                                                 result = 1;
02108                                         }
02109                                 }
02110                         }
02111                 }
02112 
02113                 BC_ListBoxItem *item = data[master_column].values[i];
02114                 if(item->get_sublist() &&
02115                         item->get_expand())
02116                         result |= select_rectangle(item->get_sublist(),
02117                                 x1, 
02118                                 y1,
02119                                 x2, 
02120                                 y2);
02121         }
02122         return result;
02123 }
02124 
02125 int BC_ListBox::reposition_item(ArrayList<BC_ListBoxItem*> *data,
02126                 int selection_number,
02127                 int x,
02128                 int y,
02129                 int *counter)
02130 {
02131         int temp = -1;
02132         if(!counter) counter = &temp;
02133 
02134 
02135         for(int i = 0; i < data[master_column].total; i++)
02136         {
02137                 BC_ListBoxItem *item = data[master_column].values[i];
02138                 (*counter)++;
02139                 if((*counter) == selection_number)
02140                 {
02141                         item->icon_x = x;
02142                         item->icon_y = y;
02143                         return 1;
02144                 }
02145 // Not recursive because it's only used for icons
02146         }
02147         return 0;
02148 }
02149 
02150 void BC_ListBox::move_selection(ArrayList<BC_ListBoxItem*> *dst,
02151         ArrayList<BC_ListBoxItem*> *src)
02152 {
02153         for(int i = 0; i < src[master_column].total; i++)
02154         {
02155                 BC_ListBoxItem *item = src[master_column].values[i];
02156 
02157 // Move item to dst
02158                 if(item->selected)
02159                 {
02160                         for(int j = 0; j < columns; j++)
02161                         {
02162                                 dst[j].append(src[j].values[i]);
02163                                 src[j].remove_number(i);
02164                         }
02165                 }
02166                 else
02167 // Descend into sublist
02168                 if(item->get_sublist())
02169                 {
02170                         move_selection(dst, 
02171                                 item->get_sublist());
02172                 }
02173         }
02174 }
02175 
02176 int BC_ListBox::put_selection(ArrayList<BC_ListBoxItem*> *data,
02177         ArrayList<BC_ListBoxItem*> *src,
02178         int destination,
02179         int *counter)
02180 {
02181         int temp = -1;
02182         if(!counter) counter = &temp;
02183 
02184         if(destination < 0)
02185         {
02186                 for(int j = 0; j < columns; j++)
02187                 {
02188                         for(int i = 0; i < src[j].total; i++)
02189                         {
02190                                 data[j].append(src[j].values[i]);
02191                         }
02192                 }
02193                 return 1;
02194         }
02195         else
02196         for(int i = 0; i < data[master_column].total; i++)
02197         {
02198                 (*counter)++;
02199                 if((*counter) == destination)
02200                 {
02201                         for(int j = 0; j < columns; j++)
02202                         {
02203                                 for(int k = 0; k < src[j].total; k++)
02204                                 {
02205                                         data[j].insert(src[j].values[k], destination + k);
02206                                 }
02207                         }
02208                         return 1;
02209                 }
02210 
02211                 BC_ListBoxItem *item = data[master_column].values[i];
02212                 if(item->get_sublist())
02213                 {
02214                         if(put_selection(item->get_sublist(),
02215                                 src,
02216                                 destination,
02217                                 counter))
02218                                 return 1;
02219                 }
02220         }
02221         return 0;
02222 }
02223 
02224 
02225 
02226 int BC_ListBox::item_to_index(ArrayList<BC_ListBoxItem*> *data,
02227                 BC_ListBoxItem *item,
02228                 int *counter)
02229 {
02230         int temp = -1;
02231         if(!counter) counter = &temp;
02232 
02233         for(int i = 0; i < data[master_column].total; i++)
02234         {
02235                 (*counter)++;
02236                 for(int j = 0; j < columns; j++)
02237                 {
02238                         BC_ListBoxItem *new_item = data[j].values[i];
02239 //printf("BC_ListBox::item_to_index 1 %d %d %p\n", j, i, new_item);
02240                         if(new_item == item)
02241                         {
02242                                 return (*counter);
02243                         }
02244                 }
02245 
02246                 BC_ListBoxItem *new_item = data[master_column].values[i];
02247                 if(new_item->get_sublist())
02248                 {
02249                         if(item_to_index(new_item->get_sublist(),
02250                                 item,
02251                                 counter) >= 0)
02252                                 return (*counter);
02253                 }
02254         }
02255 
02256         return -1;
02257 }
02258 
02259 BC_ListBoxItem* BC_ListBox::index_to_item(ArrayList<BC_ListBoxItem*> *data,
02260                 int number,
02261                 int column,
02262                 int *counter)
02263 {
02264         int temp = -1;
02265         if(!counter) counter = &temp;
02266         for(int i = 0; i < data[master_column].total; i++)
02267         {
02268                 (*counter)++;
02269                 if((*counter) == number)
02270                 {
02271                         return data[column].values[i];
02272                 }
02273                 BC_ListBoxItem *item = data[master_column].values[i];
02274                 if(item->get_sublist())
02275                 {
02276                         BC_ListBoxItem *result = index_to_item(item->get_sublist(),
02277                                 number,
02278                                 column,
02279                                 counter);
02280                         if(result) return result;
02281                 }
02282         }
02283         return 0;
02284 }
02285 
02286 int BC_ListBox::get_cursor_item(ArrayList<BC_ListBoxItem*> *data,
02287         int cursor_x, 
02288         int cursor_y, 
02289         BC_ListBoxItem **item_return,
02290         int *counter,
02291         int expanded)
02292 {
02293         int temp = -1;
02294         if(!data) return -1;
02295         if(!counter) counter = &temp;
02296 
02297 // Icons are not treed
02298         if(display_format == LISTBOX_ICONS)
02299         {
02300                 for(int j = data[master_column].total - 1; j >= 0; j--)
02301                 {
02302                         int icon_x, icon_y, icon_w, icon_h;
02303                         int text_x, text_y, text_w, text_h;
02304                         BC_ListBoxItem *item = data[master_column].values[j];
02305                         get_icon_mask(item, icon_x, icon_y, icon_w, icon_h);
02306                         get_text_mask(item, text_x, text_y, text_w, text_h);
02307 
02308                         if((cursor_x >= icon_x && cursor_x < icon_x + icon_w &&
02309                                 cursor_y >= icon_y && cursor_y < icon_y + icon_h) ||
02310                                 (cursor_x >= text_x && cursor_x < text_x + text_w &&
02311                                 cursor_y >= text_y && cursor_y < text_y + text_h))
02312                         {
02313                                 if(item_return) (*item_return) = item;
02314                                 return j;
02315                         }
02316                 }
02317         }
02318         else
02319 // Text is treed
02320         if(display_format == LISTBOX_TEXT)
02321         {
02322 // Cursor is inside items rectangle
02323                 if(cursor_x >= 0 && 
02324                         cursor_x < (yscrollbar ? 
02325                                 gui->get_w() - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w() : 
02326                                 gui->get_w()) &&
02327 // Only clamp y if we're not in a SELECT operation.
02328                         (current_operation == BC_ListBox::SELECT ||
02329                                 (cursor_y > get_title_h() + LISTBOX_BORDER && 
02330                                 cursor_y < gui->get_h())))
02331                 {
02332 // Search table for cursor obstruction
02333                         for(int i = 0; i < data[master_column].total; i++)
02334                         {
02335                                 BC_ListBoxItem *item = data[master_column].values[i];
02336                                 (*counter)++;
02337 
02338 // Cursor is inside item on current level
02339                                 if(expanded &&
02340                                         item->selectable &&
02341                                         cursor_y >= get_item_y(item) &&
02342                                         cursor_y < get_item_y(item) + get_item_h(item))
02343                                 {
02344 //printf("BC_ListBox::get_cursor_item %d %d %p\n", master_column, i, item);
02345                                         if(item_return) (*item_return) = item;
02346                                         return (*counter);
02347                                 }
02348 
02349 // Descend into sublist
02350                                 if(item->get_sublist())
02351                                 {
02352                                         if(get_cursor_item(item->get_sublist(),
02353                                                 cursor_x, 
02354                                                 cursor_y, 
02355                                                 item_return,
02356                                                 counter,
02357                                                 item->get_expand()) >= 0)
02358                                                 return (*counter);
02359                                 }
02360                         }
02361                 }
02362         }
02363         return -1;
02364 }
02365 
02366 int BC_ListBox::repeat_event(int64_t duration)
02367 {
02368         switch(current_operation)
02369         {
02370 // Repeat out of bounds selection
02371                 case SELECT_RECT:
02372                         if(duration == get_resources()->scroll_repeat)
02373                                 return rectangle_scroll_event();
02374                         break;
02375 
02376                 case SELECT:
02377                         if(duration == get_resources()->scroll_repeat)
02378                                 return select_scroll_event();
02379                         break;
02380 
02381                 case NO_OPERATION:
02382 // Show tooltip
02383                         if(button_highlighted &&
02384                                 duration == get_resources()->tooltip_delay &&
02385                                 tooltip_text[0] != 0 &&
02386                                 is_popup &&
02387                                 !tooltip_done)
02388                         {
02389                                 show_tooltip();
02390                                 tooltip_done = 1;
02391                                 return 1;
02392                         }
02393                         break;
02394         }
02395         return 0;
02396 }
02397 
02398 
02399 int BC_ListBox::cursor_enter_event()
02400 {
02401         int result = 0;
02402 
02403         switch(current_operation)
02404         {
02405 // Cursor moved over button, pressed, and exited.
02406                 case BUTTON_DOWN_SELECT:
02407                         if(top_level->event_win == win)
02408                         {
02409                                 current_operation = BUTTON_DN;
02410                                 result = 1;
02411                                 button_highlighted = 1;
02412                                 draw_button();
02413                         }
02414                         break;
02415 
02416                 case NO_OPERATION:
02417 // Cursor entered button
02418                         if(is_popup && top_level->event_win == win)
02419                         {
02420                                 button_highlighted = 1;
02421                                 result = 1;
02422                                 draw_button();
02423                         }
02424                         else
02425 // TODO: Need to get the highlighted column title or item
02426                         if(gui && top_level->event_win == gui->win)
02427                         {
02428                                 list_highlighted = 1;
02429                                 draw_border(1);
02430                                 result = 1;
02431                         }
02432                         break;
02433         }
02434 
02435         return result;
02436 }
02437 
02438 int BC_ListBox::cursor_leave_event()
02439 {
02440         int redraw_button = 0;
02441         int redraw_border = 0;
02442         int redraw_titles = 0;
02443         int redraw_items = 0;
02444 
02445         if(current_operation == COLUMN_DRAG) return 0;
02446 
02447 // Left button area
02448         if(button_highlighted)
02449         {
02450                 button_highlighted = 0;
02451                 hide_tooltip();
02452                 draw_button();
02453         }
02454 
02455         if(list_highlighted)
02456         {
02457                 list_highlighted = 0;
02458                 highlighted_item = -1;
02459                 highlighted_ptr = 0;
02460                 highlighted_title = -1;
02461                 int redraw_toggles = 0;
02462                 for(int i = 0; i < expanders.total; i++)
02463                         expanders.values[i]->cursor_leave_event(&redraw_toggles);
02464 
02465                 draw_items(1);
02466         }
02467 
02468         return 0;
02469 }
02470 
02471 int BC_ListBox::get_first_selection(ArrayList<BC_ListBoxItem*> *data, int *result)
02472 {
02473         int temp = -1;
02474         if(!result) result = &temp;
02475 
02476         for(int i = 0; i < data[master_column].total; i++)
02477         {
02478                 BC_ListBoxItem *item = data[master_column].values[i];
02479                 (*result)++;
02480                 if(item->selected) return (*result);
02481                 if(item->get_sublist())
02482                 {
02483                         if(get_first_selection(item->get_sublist(), result) >= 0)
02484                                 return (*result);
02485                 }
02486         }
02487         return -1;
02488 }
02489 
02490 int BC_ListBox::get_total_items(ArrayList<BC_ListBoxItem*> *data, 
02491         int *result,
02492         int master_column)
02493 {
02494         int temp = 0;
02495         if(!result) result = &temp;
02496 
02497         for(int i = 0; i < data[master_column].total; i++)
02498         {
02499                 (*result)++;
02500                 if(data[master_column].values[i]->get_sublist())
02501                         get_total_items(data[master_column].values[i]->get_sublist(), 
02502                                 result,
02503                                 master_column);
02504         }
02505 
02506         return (*result);
02507 }
02508 
02509 
02510 int BC_ListBox::get_last_selection(ArrayList<BC_ListBoxItem*> *data, 
02511         int *result)
02512 {
02513         int temp = -1;
02514         int top_level = 0;
02515         if(!result)
02516         {
02517                 result = &temp;
02518                 top_level = 1;
02519         }
02520 
02521         for(int i = data[master_column].total - 1; i >= 0; i--)
02522         {
02523                 BC_ListBoxItem *item = data[master_column].values[i];
02524                 (*result)++;
02525                 if(item->selected)
02526                 {
02527                         if(top_level)
02528                                 return get_total_items(data, 0, master_column) - (*result) /* - 1 */;
02529                         else
02530                                 return (*result);
02531                 }
02532 
02533                 if(item->get_sublist())
02534                 {
02535                         if(get_last_selection(item->get_sublist(), result) >= 0)
02536                         {
02537                                 if(top_level)
02538                                         return get_total_items(data, 0, master_column) - (*result) /* - 1 */;
02539                                 else
02540                                         return (*result);
02541                         }
02542                 }
02543         }
02544         return -1;
02545 }
02546 
02547 void BC_ListBox::select_range(ArrayList<BC_ListBoxItem*> *data,
02548                 int start,
02549                 int end,
02550                 int *current)
02551 {
02552         int temp = -1;
02553         if(!current) current = &temp;
02554 
02555         for(int i = 0; i < data[master_column].total; i++)
02556         {
02557                 (*current)++;
02558                 if((*current) >= start && (*current) < end)
02559                 {
02560                         for(int j = 0; j < columns; j++)
02561                                 data[j].values[i]->selected = 1;
02562                 }
02563                 BC_ListBoxItem *item = data[master_column].values[i];
02564                 if(item->get_sublist())
02565                         select_range(item->get_sublist(),
02566                                 start,
02567                                 end,
02568                                 current);
02569         }
02570 }
02571 
02572 
02573 // Fill items between current selection and new selection
02574 int BC_ListBox::expand_selection(int button_press, int selection_number)
02575 {
02576         int old_selection_start = selection_start;
02577         int old_selection_end = selection_end;
02578 
02579 // printf("BC_ListBox::expand_selection %d %d\n", 
02580 // selection_center, 
02581 // selection_number);
02582 
02583 // Calculate the range to select based on selection_center and selection_number
02584         if(selection_number < selection_center)
02585         {
02586                 selection_start = selection_number;
02587         }
02588         else
02589         {
02590                 selection_end = selection_number + 1;
02591         }
02592 
02593 //printf("BC_ListBox::expand_selection %d %d %d %d\n", old_selection_start, old_selection_end, selection_start, selection_end);
02594 // Recurse through all the items and select the desired range
02595         select_range(data, selection_start, selection_end);
02596 
02597 // Trigger redraw
02598         return (old_selection_start != selection_start ||
02599                 old_selection_end != selection_end);
02600 }
02601 
02602 int BC_ListBox::toggle_item_selection(ArrayList<BC_ListBoxItem*> *data,
02603         int selection_number,
02604         int *counter)
02605 {
02606         int temp = -1;
02607         if(!counter) counter = &temp;
02608 
02609         for(int i = 0; i < data[master_column].total; i++)
02610         {
02611                 BC_ListBoxItem *item = data[master_column].values[i];
02612                 (*counter)++;
02613                 if((*counter) == selection_number)
02614                 {
02615 // Get new value for selection
02616                         int selected = !item->selected;
02617 // Set row
02618                         for(int j = 0; j < columns; j++)
02619                                 data[j].values[i]->selected = selected;
02620                         return 1;
02621                 }
02622 
02623 // Descend into sublist
02624                 if(item->get_sublist())
02625                 {
02626                         if(toggle_item_selection(item->get_sublist(),
02627                                 selection_number,
02628                                 counter))
02629                                 return 1;
02630                 }
02631         }
02632 
02633         return 0;
02634 }
02635 
02636 
02637 void BC_ListBox::set_all_selected(ArrayList<BC_ListBoxItem*> *data, int value)
02638 {
02639         for(int i = 0; i < data[master_column].total; i++)
02640         {
02641                 for(int j = 0; j < columns; j++)
02642                 {
02643                         BC_ListBoxItem *item = data[j].values[i];
02644                         item->selected = value;
02645                 }
02646                 BC_ListBoxItem *item = data[master_column].values[i];
02647                 if(item->get_sublist())
02648                 {
02649                         set_all_selected(item->get_sublist(), value);
02650                 }
02651         }
02652 }
02653 
02654 void BC_ListBox::set_selected(ArrayList<BC_ListBoxItem*> *data, 
02655                 int item_number, 
02656                 int value,
02657                 int *counter)
02658 {
02659         int temp = -1;
02660         if(!counter) counter = &temp;
02661         for(int i = 0; i < data[master_column].total && (*counter) != item_number; i++)
02662         {
02663                 (*counter)++;
02664                 if((*counter) == item_number)
02665                 {
02666                         for(int j = 0; j < columns; j++)
02667                         {
02668                                 BC_ListBoxItem *item = data[j].values[i];
02669                                 item->selected = value;
02670                         }
02671                         return;
02672                 }
02673 
02674                 BC_ListBoxItem *item = data[master_column].values[i];
02675                 if(item->get_sublist())
02676                 {
02677                         set_selected(item->get_sublist(), 
02678                                 item_number, 
02679                                 value,
02680                                 counter);
02681                 }
02682         }
02683 }
02684 
02685 int BC_ListBox::update_selection(ArrayList<BC_ListBoxItem*> *data, 
02686         int selection_number,
02687         int *counter)
02688 {
02689         int temp = -1;
02690         int result = 0;
02691         if(!counter) counter = &temp;
02692 
02693         for(int i = 0; i < data[master_column].total; i++)
02694         {
02695                 BC_ListBoxItem *item = data[master_column].values[i];
02696                 (*counter)++;
02697                 if((*counter) == selection_number && !item->selected)
02698                 {
02699                         result = 1;
02700                         for(int j = 0; j < columns; j++)
02701                                 data[j].values[i]->selected = 1;
02702                 }
02703                 else
02704                 if((*counter) != selection_number && item->selected)
02705                 {
02706                         result = 1;
02707                         for(int j = 0; j < columns; j++)
02708                                 data[j].values[i]->selected = 0;
02709                 }
02710                 if(item->get_sublist())
02711                         result |= update_selection(item->get_sublist(), 
02712                                 selection_number,
02713                                 counter);
02714         }
02715         return result;
02716 }
02717 
02718 void BC_ListBox::promote_selections(ArrayList<BC_ListBoxItem*> *data,
02719         int old_value,
02720         int new_value)
02721 {
02722         for(int i = 0; i < data[master_column].total; i++)
02723         {
02724                 for(int j = 0; j < columns; j++)
02725                 {
02726                         BC_ListBoxItem *item = data[j].values[i];
02727                         if(item->selected == old_value) item->selected = new_value;
02728                 }
02729                 BC_ListBoxItem *item = data[master_column].values[i];
02730                 if(item->get_sublist())
02731                         promote_selections(item->get_sublist(), old_value, new_value);
02732         }
02733 }
02734 
02735 int BC_ListBox::focus_out_event()
02736 {
02737         deactivate();
02738         return 0;
02739 }
02740 
02741 int BC_ListBox::button_press_event()
02742 {
02743         int result = 0;
02744         BC_ListBoxItem *current_item = 0;
02745         int new_cursor;
02746         int do_selection_change = 0;
02747 
02748         hide_tooltip();
02749 
02750 
02751 // Pressed in button
02752         if(is_popup && top_level->event_win == win)
02753         {
02754                 current_operation = BUTTON_DN;
02755                 draw_button();
02756 
02757 // Deploy listbox
02758                 if(!active && !disabled)
02759                 {
02760                         top_level->deactivate();
02761                         activate();
02762                 }
02763 
02764                 result = 1;
02765         }
02766         else
02767 // Pressed in scrollbar
02768         if((xscrollbar && top_level->event_win == xscrollbar->win) ||
02769                 (yscrollbar && top_level->event_win == yscrollbar->win))
02770         {
02771                 result = 0;
02772         }
02773         else
02774 // Pressed in items
02775         if(gui && top_level->event_win == gui->win)
02776         {
02777 // Activate list items
02778                 if(!active)
02779                 {
02780                         top_level->deactivate();
02781                         activate();
02782                 }
02783 
02784 // Wheel mouse pressed
02785                 if(get_buttonpress() == 4)
02786                 {
02787                         if(current_operation == NO_OPERATION)
02788                         {
02789                                 current_operation = WHEEL;
02790                                 if(yscrollbar)
02791                                 {
02792                                         set_yposition(yposition - gui->get_h() / 10, 0);
02793                                         clamp_positions();
02794                                         update_scrollbars();
02795                                         highlighted_ptr = 0;
02796                                         highlighted_item = get_cursor_item(data,
02797                                                 top_level->cursor_x, 
02798                                                 top_level->cursor_y, 
02799                                                 &highlighted_ptr);
02800                                         draw_items(1);
02801                                         result = 1;
02802                                 }
02803                         }
02804                 }
02805                 else
02806                 if(get_buttonpress() == 5)
02807                 {
02808                         if(current_operation == NO_OPERATION)
02809                         {
02810                                 current_operation = WHEEL;
02811                                 if(yscrollbar)
02812                                 {
02813                                         set_yposition(yposition + gui->get_h() / 10, 0);
02814                                         clamp_positions();
02815                                         update_scrollbars();
02816                                         highlighted_ptr = 0;
02817                                         highlighted_item = get_cursor_item(data,
02818                                                 top_level->cursor_x, 
02819                                                 top_level->cursor_y,
02820                                                 &highlighted_ptr);
02821                                         draw_items(1);
02822                                         result = 1;
02823                                 }
02824                         }
02825                 }
02826                 else
02827 // Pressed over column title division
02828                 if(test_column_divisions(gui->get_cursor_x(), 
02829                         gui->get_cursor_y(), 
02830                         new_cursor))
02831                 {
02832                         current_operation = DRAG_DIVISION;
02833                         reset_query();
02834                 }
02835                 else
02836 // Pressed in column title
02837                 if(test_column_titles(gui->get_cursor_x(), gui->get_cursor_y()))
02838                 {
02839                         current_operation = COLUMN_DN;
02840                         button_highlighted = 0;
02841                         list_highlighted = 1;
02842                         draw_items(1);
02843                         result = 1;
02844                 }
02845                 else
02846 // Pressed in expander
02847                 if(test_expanders())
02848                 {
02849                         current_operation = EXPAND_DN;
02850 // Need to redraw items because of alpha
02851                         draw_items(1);
02852                         result = 1;
02853                 }
02854                 else
02855 // Pressed over item
02856                 if((selection_number = get_cursor_item(data, 
02857                                         gui->get_cursor_x(), 
02858                                         gui->get_cursor_y(),
02859                                         &current_item)) >= 0)
02860                 {
02861 // Get item button was pressed over
02862                         selection_number2 = selection_number1;
02863                         selection_number1 = selection_number;
02864 
02865                         selection_start = -1;
02866                         selection_end = -1;
02867 
02868 
02869 // Multiple item selection is possible
02870                         if(selection_mode == LISTBOX_MULTIPLE && 
02871                                 (ctrl_down() || shift_down()))
02872                         {
02873 // Expand text selection.
02874 // Fill items between selected region and current item.
02875                                 if(shift_down() && display_format == LISTBOX_TEXT)
02876                                 {
02877 // Get first item selected
02878                                         selection_start = get_first_selection(data);
02879 // Get last item selected
02880                                         selection_end = get_last_selection(data);
02881 // Get center of selected region
02882                                         if(selection_end > selection_start)
02883                                         {
02884                                                 selection_center = (selection_end + selection_start) >> 1;
02885                                         }
02886                                         else
02887                                         {
02888                                                 selection_center = selection_number;
02889                                         }
02890 
02891 
02892 // Deselect everything.
02893                                         set_all_selected(data, 0);
02894 // Select just the items
02895                                         expand_selection(1, selection_number);
02896                                         new_value = 1;
02897                                 }
02898                                 else
02899 // Toggle a single item on or off
02900                                 {
02901                                         toggle_item_selection(data, selection_number);
02902                                         new_value = current_item->selected;
02903                                 }
02904                         }
02905                         else
02906 // Select single item
02907                         {
02908                                 if(!current_item->selected)
02909                                 {
02910                                         set_all_selected(data, 0);
02911                                         set_selected(data,
02912                                                 selection_number,
02913                                                 1);
02914                                 }
02915                                 new_value = 1;
02916                         }
02917 
02918 
02919                         current_operation = SELECT;
02920                         highlighted_item = selection_number;
02921                         highlighted_ptr = current_item;
02922                         button_highlighted = 0;
02923                         list_highlighted = 1;
02924                         reset_query();
02925                         draw_items(1);
02926                         do_selection_change = 1;
02927                         result = 1;
02928                 }
02929                 else
02930                 if(data)
02931 // Pressed over nothing.  Start rectangle selection.
02932                 {
02933                         if(get_buttonpress() == 1 && 
02934                                 selection_mode == LISTBOX_MULTIPLE)
02935                         {
02936                                 if(!shift_down())
02937                                 {
02938 // Deselect all and redraw if anything was selected
02939                                         if(get_selection_number(0, 0) >= 0)
02940                                         {
02941                                                 set_all_selected(data, 0);
02942                                                 draw_items(1);
02943                                                 do_selection_change = 1;
02944                                                 result = 1;
02945                                         }
02946                                 }
02947                                 else
02948                                 {
02949 // Promote selections to protect from a rectangle selection
02950                                         promote_selections(data, 1, 2);
02951                                 }
02952 
02953 // Start rectangle selection
02954                                 current_operation = SELECT_RECT;
02955                                 rect_x1 = rect_x2 = get_cursor_x();
02956                                 rect_y1 = rect_y2 = get_cursor_y();
02957                         }
02958                 }
02959 
02960 
02961                 reset_query();
02962         }
02963         else
02964         if(is_popup && active)
02965         {
02966                 deactivate();
02967                 result = 1;
02968         }
02969 
02970 
02971         if(do_selection_change) selection_changed();
02972 
02973         return result;
02974 }
02975 
02976 int BC_ListBox::button_release_event()
02977 {
02978         int result = 0;
02979         int cursor_x, cursor_y;
02980         int do_event = 0;
02981         new_value = 0;
02982 
02983 //printf("BC_ListBox::button_release_event 1 %d\n", current_operation);
02984         switch(current_operation)
02985         {
02986                 case DRAG_DIVISION:
02987                         current_operation = NO_OPERATION;
02988                         result = 1;
02989                         break;
02990 
02991                 case WHEEL:
02992                         current_operation = NO_OPERATION;
02993                         result = 1;
02994                         break;
02995 
02996 // Release item selection
02997                 case BUTTON_DOWN_SELECT:
02998                 case SELECT:
02999 //printf("BC_ListBox::button_release_event 10\n");
03000                         unset_repeat(get_resources()->scroll_repeat);
03001                         current_operation = NO_OPERATION;
03002                         translate_coordinates(top_level->event_win,
03003                                 gui->win,
03004                                 gui->get_cursor_x(),
03005                                 gui->get_cursor_y(),
03006                                 &cursor_x,
03007                                 &cursor_y);
03008 
03009                         selection_number1 = 
03010                                 selection_number = 
03011                                 get_cursor_item(data, cursor_x, cursor_y);
03012 //printf("BC_ListBox::button_release_event %d %d\n", selection_number2, selection_number1);
03013 
03014                         if(is_popup)
03015                         {
03016                                 button_releases++;
03017                                 if(selection_number >= 0)
03018                                 {
03019                                         deactivate();
03020                                         do_event = 1;
03021                                 }
03022                                 else
03023 // Second button release outside button
03024                                 if(button_releases > 1)
03025                                 {
03026                                         deactivate();
03027                                 }
03028                         }
03029                         else
03030                         {
03031                                 if(top_level->get_double_click() &&
03032                                         selection_number2 == selection_number1 &&
03033                                         selection_number2 >= 0 &&
03034                                         selection_number1 >= 0)
03035                                 {
03036                                         do_event = 1;
03037                                 }
03038                                 result = 1;
03039                         }
03040                         break;
03041 
03042 
03043                 case SELECT_RECT:
03044                         unset_repeat(get_resources()->scroll_repeat);
03045                         if(data)
03046                         {
03047 // Demote selections from rectangle selection
03048                                 promote_selections(data, 2, 1);
03049                         }
03050 
03051 // Hide rectangle overlay
03052                         draw_rectangle(1);
03053                         current_operation = NO_OPERATION;
03054                         result = 1;
03055                         break;
03056 
03057 // Release popup button
03058                 case BUTTON_DN:
03059                         hide_tooltip();
03060                         current_operation = NO_OPERATION;
03061                         button_releases++;
03062                         draw_button();
03063 
03064 // Second button release inside button
03065                         if(button_releases > 1)
03066                         {
03067                                 deactivate();
03068                         }
03069                         result = 1;
03070                         break;
03071 
03072                 case COLUMN_DN:
03073                         current_operation = NO_OPERATION;
03074 // Update the sort column and the sort order for the user only if the existing
03075 // sort column is valid.
03076                         if(sort_column >= 0)
03077                         {
03078 // Invert order only if column is the same
03079                                 if(highlighted_title == sort_column)
03080                                         sort_order = 
03081                                                 (sort_order == SORT_ASCENDING) ? 
03082                                                 SORT_DESCENDING : 
03083                                                 SORT_ASCENDING;
03084 // Set the new sort column
03085                                 sort_column = highlighted_title;
03086                                 if(!sort_order_event())
03087                                 {
03088                                         draw_titles(1);
03089                                 }
03090                         }
03091                         else
03092 // Sorting not enabled.  Redraw the title state.
03093                         {
03094                                 draw_titles(1);
03095                         }
03096                         result = 1;
03097                         break;
03098 
03099                 case EXPAND_DN:
03100                 {
03101                         int redraw_toggles = 0;
03102                         for(int i = 0; i < expanders.total && !result; i++)
03103                         {
03104                                 if(expanders.values[i]->button_release_event(&redraw_toggles))
03105                                 {
03106                                         result = 1;
03107                                 }
03108                         }
03109 // Need to redraw items because of alpha
03110                         if(redraw_toggles) draw_items(1);
03111                         current_operation = NO_OPERATION;
03112                         break;
03113                 }
03114 
03115                 default:
03116 // Can't default to NO_OPERATION because it may be used in a drag event.
03117                         break;
03118         }
03119 
03120 
03121         if(do_event) handle_event();
03122 
03123         return result;
03124 }
03125 
03126 int BC_ListBox::get_title_h()
03127 {
03128         if(display_format == LISTBOX_TEXT)
03129                 return column_titles ? column_bg[0]->get_h() : 0;
03130         else
03131                 return 0;
03132 }
03133 
03134 void BC_ListBox::reset_cursor(int new_cursor)
03135 {
03136         if(is_popup)
03137         {
03138                 if(gui->get_cursor() != new_cursor)
03139                 {
03140                         gui->set_cursor(new_cursor);
03141                 }
03142         }
03143         else
03144         if(get_cursor() != new_cursor)
03145         {
03146                 set_cursor(new_cursor);
03147         }
03148 }
03149 
03150 int BC_ListBox::test_column_divisions(int cursor_x, int cursor_y, int &new_cursor)
03151 {
03152         if(gui &&
03153                 column_titles && 
03154                 cursor_y >= 0 && 
03155                 cursor_y < get_title_h() &&
03156                 cursor_x >= 0 &&
03157                 cursor_x < gui->get_w())
03158         {
03159                 for(int i = 1; i < columns; i++)
03160                 {
03161                         if(cursor_x >= -xposition + get_column_offset(i) - 5 &&
03162                                 cursor_x <  -xposition + get_column_offset(i) + 
03163                                         get_resources()->listbox_title_hotspot)
03164                         {
03165                                 highlighted_item = -1;
03166                                 highlighted_ptr = 0;
03167                                 highlighted_division = i;
03168                                 highlighted_title = -1;
03169                                 list_highlighted = 1;
03170                                 new_cursor = HSEPARATE_CURSOR;
03171                                 return 1;
03172                         }
03173                 }
03174         }
03175         highlighted_division = -1;
03176         return 0;
03177 }
03178 
03179 int BC_ListBox::test_column_titles(int cursor_x, int cursor_y)
03180 {
03181         if(gui &&
03182                 column_titles && 
03183                 cursor_y >= 0 && 
03184                 cursor_y < get_title_h() &&
03185                 cursor_x >= 0 && 
03186                 cursor_x < gui->get_w())
03187         {
03188                 for(int i = 0; i < columns; i++)
03189                 {
03190                         if(cursor_x >= -xposition + get_column_offset(i) &&
03191                                 (cursor_x < -xposition + get_column_offset(i + 1) ||
03192                                         i == columns - 1))
03193                         {
03194                                 highlighted_item = -1;
03195                                 highlighted_ptr = 0;
03196                                 highlighted_division = -1;
03197                                 highlighted_title = i;
03198                                 list_highlighted = 1;
03199                                 return 1;
03200                         }
03201                 }
03202         }
03203         highlighted_title = -1;
03204         return 0;
03205 }
03206 
03207 int BC_ListBox::test_expanders()
03208 {
03209         for(int i = 0; i < expanders.total; i++)
03210         {
03211                 if(expanders.values[i]->button_press_event())
03212                 {
03213                         current_operation = EXPAND_DN;
03214                         draw_toggles(1);
03215                         return 1;
03216                 }
03217         }
03218         return 0 ;
03219 }
03220 
03221 int BC_ListBox::cursor_motion_event()
03222 {
03223         int redraw = 0, result = 0;
03224         int new_cursor = ARROW_CURSOR;
03225 
03226         selection_number = -1;
03227 
03228 
03229         switch(current_operation)
03230         {
03231                 case BUTTON_DN:
03232 // Button pressed and slid off button
03233                         if(!cursor_inside())
03234                         {
03235                                 current_operation = BUTTON_DOWN_SELECT;
03236                                 draw_button();
03237                                 result = 1;
03238                         }
03239                         break;
03240 
03241                 case DRAG_DIVISION:
03242                 {
03243                         int new_w = get_cursor_x() + 
03244                                 xposition - 
03245                                 get_column_offset(highlighted_division - 1);
03246                         new_cursor = HSEPARATE_CURSOR;
03247 
03248                         if(column_width)
03249                         {
03250                                 column_width[highlighted_division - 1] = new_w;
03251                         }
03252                         else
03253                         {
03254                                 default_column_width[highlighted_division - 1] = new_w;
03255                         }
03256 
03257                         column_width_boundaries();
03258 
03259 // Force update of coords
03260                         set_autoplacement(data, 0, 1);
03261                         column_resize_event();
03262 
03263                         clamp_positions();
03264                         draw_items(1);
03265                         update_scrollbars();
03266                         result = 1;
03267                         break;
03268                 }
03269 
03270                 case SELECT_RECT:
03271                 {
03272                         if(test_drag_scroll(get_cursor_x(), get_cursor_y()))
03273                         {
03274                                 set_repeat(get_resources()->scroll_repeat);
03275                         }
03276 
03277                         int old_x1 = MIN(rect_x1, rect_x2);
03278                         int old_x2 = MAX(rect_x1, rect_x2);
03279                         int old_y1 = MIN(rect_y1, rect_y2);
03280                         int old_y2 = MAX(rect_y1, rect_y2);
03281 
03282                         int new_rect_x2 = get_cursor_x();
03283                         int new_rect_y2 = get_cursor_y();
03284 
03285                         int x1 = MIN(rect_x1, new_rect_x2);
03286                         int x2 = MAX(rect_x1, new_rect_x2);
03287                         int y1 = MIN(rect_y1, new_rect_y2);
03288                         int y2 = MAX(rect_y1, new_rect_y2);
03289 
03290 // Adjust rectangle coverage
03291                         if(old_x1 != x1 ||
03292                                 old_x2 != x2 ||
03293                                 old_y1 != y1 ||
03294                                 old_y2 != y2)
03295                         {
03296                                 if(data)
03297                                 {
03298                                         redraw = select_rectangle(data,
03299                                                 x1, 
03300                                                 y1,
03301                                                 x2, 
03302                                                 y2);
03303                                 }
03304 
03305 // hide rectangle
03306                                 if(!redraw)
03307                                         draw_rectangle(0);
03308                         }
03309 
03310                         rect_x2 = get_cursor_x();
03311                         rect_y2 = get_cursor_y();
03312                         if(redraw)
03313                         {
03314                                 clamp_positions();
03315                                 draw_items(1);
03316                                 update_scrollbars();
03317                                 selection_changed();
03318                         }
03319                         else
03320                         {
03321                                 draw_rectangle(1);
03322                         }
03323                         result = 1;
03324                         break;
03325                 }
03326 
03327                 case SELECT:
03328                 {
03329                         int old_highlighted_item = highlighted_item;
03330                         int old_highlighted_title = highlighted_title;
03331                         BC_ListBoxItem *old_highlighted_ptr = highlighted_ptr;
03332 
03333                         if(test_drag_scroll(get_cursor_x(), 
03334                                 get_cursor_y()))
03335                         {
03336                                 set_repeat(get_resources()->scroll_repeat);
03337                         }
03338 
03339 
03340                         highlighted_item = selection_number = get_cursor_item(data, 
03341                                 get_cursor_x(), 
03342                                 get_cursor_y(),
03343                                 &highlighted_ptr);
03344                         result = 1;
03345 
03346 // Deselect all items and select just the one we're over
03347                         if(selection_number >= 0 && 
03348                                 !allow_drag &&
03349                                 ((!shift_down() &&
03350                                         !ctrl_down()) ||
03351                                         selection_mode == LISTBOX_SINGLE))
03352                         {
03353                                 redraw = update_selection(data, selection_number);
03354                         }
03355                         else
03356                         if(selection_mode == LISTBOX_MULTIPLE &&
03357                                 (shift_down() || ctrl_down()))
03358 // Expand multiple selection
03359                         {
03360 // Expand selected region in text mode centered around initial range
03361                                 if(display_format == LISTBOX_TEXT && shift_down())
03362                                 {
03363 // Deselect everything.
03364                                         set_all_selected(data, 0);
03365 
03366 // Select just the items
03367                                         redraw = expand_selection(0, selection_number);
03368                                 }
03369                                 else
03370 // Set the one item we're over to the selection value determined in
03371 // button_press_event.
03372                                 {
03373                                         set_selected(data, 
03374                                                 selection_number, 
03375                                                 new_value);
03376                                 }
03377                         }
03378 
03379                         if(highlighted_item != old_highlighted_item)
03380                         {
03381                                 clamp_positions();
03382                                 draw_items(1);
03383                                 update_scrollbars();
03384 //printf("BC_ListBox::cursor_motion_event %d %d\n", highlighted_item, old_highlighted_item);
03385                                 selection_changed();
03386                         }
03387                         break;
03388                 }
03389 
03390                 case BUTTON_DOWN_SELECT:
03391 // Went back into button area
03392                         if(cursor_inside())
03393                         {
03394                                 current_operation = BUTTON_DN;
03395                                 draw_button();
03396                                 result = 1;
03397                         }
03398                         else
03399 // Went into item area
03400                         if(gui)
03401                         {
03402                                 int cursor_x = 0, cursor_y = 0;
03403                                 translate_coordinates(top_level->event_win, 
03404                                         gui->win,
03405                                         top_level->cursor_x,
03406                                         top_level->cursor_y,
03407                                         &cursor_x,
03408                                         &cursor_y);
03409                                 int old_highlighted_item = highlighted_item;
03410                                 highlighted_item = selection_number = get_cursor_item(data, 
03411                                                 cursor_x, 
03412                                                 cursor_y,
03413                                                 &highlighted_ptr);
03414 
03415                                 if(highlighted_item != old_highlighted_item)
03416                                 {
03417                                         update_selection(data, selection_number);
03418                                         draw_items(1);
03419                                         selection_changed();
03420                                 }
03421                         }
03422                         break;
03423 
03424                 case EXPAND_DN:
03425                 {
03426                         int redraw_toggles = 0;
03427                         for(int i = 0; i < expanders.total && !result; i++)
03428                         {
03429                                 result = expanders.values[i]->cursor_motion_event(
03430                                         &redraw_toggles);
03431                         }
03432                         if(redraw_toggles)
03433                         {
03434 // Need to redraw items because of the alpha
03435                                 draw_items(1);
03436                         }
03437                         break;
03438                 }
03439 
03440                 case NO_OPERATION:
03441                 {
03442                         int cursor_x = get_cursor_x(), cursor_y = get_cursor_y();
03443                         if(gui && top_level->event_win == gui->win)
03444                         {
03445                                 int old_highlighted_title = highlighted_title;
03446                                 int old_list_highlighted = list_highlighted;
03447                                 int old_highlighted_division = highlighted_division;
03448                                 int old_highlighted_item = highlighted_item;
03449                                 int redraw_titles = 0;
03450                                 int redraw_border = 0;
03451                                 int redraw_items = 0;
03452                                 int redraw_toggles = 0;
03453                                 result = 1;
03454 
03455 
03456 // Test if cursor moved over a title division
03457                                 test_column_divisions(cursor_x, cursor_y, new_cursor);
03458 
03459 // Test if cursor moved over a title
03460                                 if(highlighted_division < 0)
03461                                 {
03462                                         test_column_titles(cursor_x, cursor_y);
03463                                 }
03464 
03465 // Test if cursor moved over expander
03466                                 if(highlighted_division < 0 && 
03467                                         highlighted_title < 0 &&
03468                                         display_format == LISTBOX_TEXT)
03469                                 {
03470                                         for(int i = 0; i < expanders.total; i++)
03471                                         {
03472                                                 expanders.values[i]->cursor_motion_event(
03473                                                         &redraw_toggles);
03474                                         }
03475 //printf("BC_ListBox::cursor_motion_event %d\n", redraw_toggles);
03476                                 }
03477 
03478 // Test if cursor moved over an item
03479                                 if(highlighted_division < 0 && 
03480                                         highlighted_title < 0)
03481                                 {
03482                                         highlighted_item = get_cursor_item(data, 
03483                                                 cursor_x, 
03484                                                 cursor_y,
03485                                                 &highlighted_ptr);
03486                                 }
03487 
03488 
03489 // Clear title highlighting if moved over division
03490                                 if(old_highlighted_title != highlighted_title)
03491                                 {
03492                                         redraw_titles = 1;
03493                                 }
03494 
03495 // Highlight list border
03496                                 if(old_list_highlighted != list_highlighted)
03497                                 {
03498                                         redraw_border = 1;
03499                                 }
03500 
03501 // Moved out of item area
03502                                 if(old_highlighted_item != highlighted_item)
03503                                 {
03504                                         redraw_items = 1;
03505                                 }
03506 
03507 //printf("BC_ListBox::cursor_motion_event 1 %d\n", highlighted_item);
03508 
03509 // Change cursor to title division adjustment
03510                                 reset_cursor(new_cursor);
03511 
03512                                 if(redraw_items)
03513                                 {
03514                                         draw_items(0);
03515                                 }
03516                                 else
03517                                 {
03518                                         if(redraw_titles)
03519                                                 draw_titles(0);
03520                                         if(redraw_border)
03521                                                 draw_border(0);
03522                                         if(redraw_toggles)
03523                                                 draw_toggles(0);
03524                                 }
03525 
03526                                 if(redraw_items || 
03527                                         redraw_titles || 
03528                                         redraw_border || 
03529                                         redraw_toggles)
03530                                 {
03531                                         gui->flash();
03532                                         gui->flush();
03533                                 }
03534                         }
03535 
03536 
03537                         if(!result && list_highlighted)
03538                         {
03539                                 list_highlighted = 0;
03540                                 highlighted_item = -1;
03541                                 highlighted_ptr = 0;
03542                                 highlighted_title = -1;
03543                                 highlighted_division = -1;
03544                                 draw_items(1);
03545                                 result = 0;
03546                         }
03547                         break;
03548                 }
03549         }
03550 
03551 
03552         return result;
03553 }
03554 
03555 int BC_ListBox::drag_start_event()
03556 {
03557         switch(current_operation)
03558         {
03559                 case SELECT:
03560                         if(gui && 
03561                                 gui->is_event_win() && 
03562                                 allow_drag)
03563                         {
03564                                 BC_ListBoxItem *item_return = 0;
03565                                 selection_number = get_cursor_item(data, 
03566                                         top_level->cursor_x, 
03567                                         top_level->cursor_y,
03568                                         &item_return);
03569 
03570                                 if(selection_number >= 0)
03571                                 {
03572                                         
03573                                         if (item_return->icon_vframe)
03574                                         {
03575                                                 drag_popup = new BC_DragWindow(this, 
03576                                                         item_return->icon_vframe, 
03577                                                         get_abs_cursor_x(0) - item_return->icon_vframe->get_w() / 2,
03578                                                         get_abs_cursor_y(0) - item_return->icon_vframe->get_h() / 2);
03579                                         }
03580                                         else    
03581 // this probably works not!
03582                                         if (item_return->icon)  
03583                                                 drag_popup = new BC_DragWindow(this, 
03584                                                         item_return->icon, 
03585                                                         get_abs_cursor_x(0) - item_return->icon->get_w() / 2,
03586                                                         get_abs_cursor_y(0) - item_return->icon->get_h() / 2);
03587                                         else
03588                                                 drag_popup = new BC_DragWindow(this, 
03589                                                         drag_icon_vframe, 
03590                                                         get_abs_cursor_x(0) - drag_icon_vframe->get_w() / 2,
03591                                                         get_abs_cursor_y(0) - drag_icon_vframe->get_h() / 2);
03592                                         current_operation = DRAG_ITEM;
03593                                         return 1;
03594                                 }
03595                         }
03596                         break;
03597 
03598                 case COLUMN_DN:
03599                         if(gui && gui->is_event_win() && allow_drag_column)
03600                         {
03601                                 drag_popup = new BC_DragWindow(this, 
03602                                         drag_column_icon_vframe, 
03603                                         get_abs_cursor_x(0) - drag_column_icon_vframe->get_w() / 2,
03604                                         get_abs_cursor_y(0) - drag_column_icon_vframe->get_h() / 2);
03605                                 dragged_title = highlighted_title;
03606                                 current_operation = COLUMN_DRAG;
03607                                 draw_titles(1);
03608                                 return 1;
03609                         }
03610                         break;
03611         }
03612 
03613         return 0;
03614 }
03615 
03616 int BC_ListBox::drag_motion_event()
03617 {
03618 //printf("BC_ListBox::drag_motion_event 1 %d\n", current_operation);
03619         switch(current_operation)
03620         {
03621                 case DRAG_ITEM:
03622                 {
03623                         int redraw = 0;
03624 
03625                         int new_highlighted_item = -1;
03626                         BC_ListBoxItem *new_highlighted_ptr = 0;
03627                         int new_highlight = new_highlighted_item = get_cursor_item(data,
03628                                 top_level->cursor_x, 
03629                                 top_level->cursor_y,
03630                                 &new_highlighted_ptr);
03631 
03632                         if(new_highlighted_item != highlighted_item)
03633                         {
03634                                 redraw = 1;
03635                         }
03636 
03637 // Always update highlighted value for drag_stop
03638                         highlighted_item = new_highlighted_item;
03639                         highlighted_ptr = new_highlighted_ptr;
03640 //printf("BC_ListBox::drag_motion_event 1 %p\n", highlighted_ptr);
03641                         if(redraw)
03642                         {
03643                                 clamp_positions();
03644                                 draw_items(1);
03645                                 update_scrollbars();
03646                         }
03647 
03648                         return drag_popup->cursor_motion_event();
03649                         break;
03650                 }
03651 
03652                 case COLUMN_DRAG:
03653                 {
03654                         int old_highlighted_title = highlighted_title;
03655                         test_column_titles(get_cursor_x(), get_cursor_y());
03656                         if(old_highlighted_title != highlighted_title)
03657                         {
03658                                 draw_titles(1);
03659                         }
03660                         return drag_popup->cursor_motion_event();
03661                         break;
03662                 }
03663         }
03664         return 0;
03665 }
03666 
03667 int BC_ListBox::drag_stop_event()
03668 {
03669         switch(current_operation)
03670         {
03671                 case DRAG_ITEM:
03672 // Inside window boundary
03673                         if(top_level->cursor_x > 0 && 
03674                                 top_level->cursor_x < gui->get_w() - drag_popup->get_w() / 2 && 
03675                                 top_level->cursor_y > 0 &&
03676                                 top_level->cursor_y < gui->get_h() - drag_popup->get_h() / 2)
03677                         {
03678 // Move icon
03679 
03680 
03681                                 if(display_format == LISTBOX_ICONS)
03682                                 {
03683                                         reposition_item(data, 
03684                                                 selection_number, 
03685                                                 top_level->cursor_x + 
03686                                                         drag_popup->get_offset_x() - 
03687                                                         LISTBOX_MARGIN - 
03688                                                         2 + 
03689                                                         xposition,
03690                                                 top_level->cursor_y + 
03691                                                         drag_popup->get_offset_y() - 
03692                                                         LISTBOX_MARGIN - 
03693                                                         2 + 
03694                                                         yposition);
03695                                 }
03696                                 else
03697 // Move rows
03698                                 if(process_drag)
03699                                 {
03700 // Get destination
03701                                         int destination = highlighted_item = item_to_index(data,
03702                                                 highlighted_ptr);
03703 //printf("BC_ListBox::drag_stop_event 1 %p %d\n", highlighted_ptr, destination);
03704 
03705 // Move selected items from data to temporary
03706                                         ArrayList<BC_ListBoxItem*> *src_items = 
03707                                                 new ArrayList<BC_ListBoxItem*>[columns];
03708 
03709                                         move_selection(src_items, data);
03710 
03711 // Insert items from temporary to data
03712                                         put_selection(data,
03713                                                 src_items,
03714                                                 destination);
03715 
03716 
03717                                         delete [] src_items;                            
03718                                         set_autoplacement(data, 0, 1);
03719                                 }
03720 
03721                         
03722                                 draw_items(1);
03723                         }
03724                         else
03725                                 drag_popup->drag_failure_event();
03726 
03727                         delete drag_popup;
03728                         drag_popup = 0;
03729                         current_operation = NO_OPERATION;
03730                         new_value = 0;
03731                         return 1;
03732                         break;
03733 
03734                 case COLUMN_DRAG:
03735                         if(dragged_title != highlighted_title)
03736                         {
03737                                 if(highlighted_title >= 0)
03738                                 {
03739                                         if(!move_column_event()) draw_titles(1);
03740                                 }
03741                                 else
03742                                         drag_popup->drag_failure_event();
03743                         }
03744                         current_operation = NO_OPERATION;
03745                         delete drag_popup;
03746                         drag_popup = 0;
03747                         return 1;
03748                         break;
03749         }
03750         return 0;
03751 }
03752 
03753 BC_DragWindow* BC_ListBox::get_drag_popup()
03754 {
03755         return drag_popup;
03756 }
03757 
03758 int BC_ListBox::translation_event()
03759 {
03760         if(is_popup && gui)
03761         {
03762                 int new_x = gui->get_x() + 
03763                         (top_level->last_translate_x - 
03764                                 top_level->prev_x - 
03765                                 top_level->get_resources()->get_left_border());
03766                 int new_y = gui->get_y() + 
03767                         (top_level->last_translate_y - 
03768                                 top_level->prev_y -
03769                                 top_level->get_resources()->get_top_border());
03770 
03771                 gui->reposition_window(new_x, new_y);
03772                 
03773         }
03774         return 0;
03775 }
03776 
03777 int BC_ListBox::reposition_window(int x, int y, int w, int h)
03778 {
03779         if(w != -1)
03780         {
03781                 if(w != -1) popup_w = w;
03782                 if(h != -1) popup_h = h;
03783 //printf("BC_ListBox::reposition_window %d %d\n", popup_w, popup_h);
03784 
03785                 if(!is_popup)
03786                 {
03787                         if(w != -1) popup_w = w;
03788                         if(h != -1) popup_h = h;
03789                         if(xscrollbar)
03790                                 xscrollbar->reposition_window(get_xscroll_x(), 
03791                                         get_xscroll_y(), 
03792                                         get_xscroll_width());
03793                         if(yscrollbar)
03794                                 yscrollbar->reposition_window(get_yscroll_x(), 
03795                                         get_yscroll_y(), 
03796                                         get_yscroll_height());
03797                 }
03798         }
03799 
03800 
03801         BC_WindowBase::reposition_window(x, y, w, h);
03802         draw_button();
03803         draw_items(1);
03804         return 0;
03805 }
03806 
03807 int BC_ListBox::deactivate()
03808 {
03809         if(active)
03810         {
03811                 active = 0;
03812                 if(is_popup)
03813                 {
03814                         if(gui) delete gui;
03815                         xscrollbar = 0;
03816                         yscrollbar = 0;
03817                         gui = 0;
03818                         highlighted_item = -1;
03819                         highlighted_ptr = 0;
03820                 }
03821                 top_level->active_subwindow = 0;
03822         }
03823         return 0;
03824 }
03825 
03826 int BC_ListBox::activate()
03827 {
03828         if(!active)
03829         {
03830                 top_level->active_subwindow = this;
03831                 active = 1;
03832                 button_releases = 0;
03833 
03834                 if(is_popup)
03835                 {
03836                         Window tempwin;
03837                         int x, y;
03838                         int new_x, new_y;
03839                         y = get_y() + get_h();
03840                         if(justify == LISTBOX_RIGHT)
03841                         {
03842                                 x = get_x() - popup_w + get_w();
03843                         }
03844                         else
03845                         {
03846                                 x = get_x();
03847                         }
03848 
03849                         
03850                         XTranslateCoordinates(top_level->display, 
03851                                 parent_window->win, 
03852                                 top_level->rootwin, 
03853                                 x, 
03854                                 y, 
03855                                 &new_x, 
03856                                 &new_y, 
03857                                 &tempwin);
03858 
03859                         if(new_x < 0) new_x = 0;
03860                         if(new_y + popup_h > top_level->get_root_h(0)) 
03861                                 new_y -= get_h() + popup_h;
03862 
03863 //printf("BC_ListBox::activate %d %d\n", popup_w, popup_h);
03864                         add_subwindow(gui = new BC_Popup(this, 
03865                                 new_x, 
03866                                 new_y, 
03867                                 popup_w, 
03868                                 popup_h, 
03869                                 -1,
03870                                 0,
03871                                 0));
03872                         draw_items(1);
03873                 }
03874         }
03875         return 0;
03876 }
03877 
03878 int BC_ListBox::keypress_event()
03879 {
03880         if(!active) return 0;
03881         
03882         int result = 0, redraw = 0, done, view_items = view_h / get_text_height(MEDIUMFONT);
03883         int new_item = -1, new_selection = 0;
03884 
03885         switch(top_level->get_keypress())
03886         {
03887                 case ESC:
03888                 case RETURN:
03889                         top_level->deactivate();
03890                         result = 0;
03891                         break;
03892 
03893                 case UP:
03894                         new_selection = new_item = select_previous(0);
03895 
03896 //printf("BC_ListBox::keypress_event 1 %d\n", new_item);
03897                         if(new_item >= 0)
03898                         {
03899                                 center_selection(new_item);
03900                                 redraw = 1;
03901                         }
03902                         result = 1;
03903                         break;
03904 
03905                 case DOWN:
03906                         new_selection = new_item = select_next(0);
03907 
03908                         if(new_item >= 0)
03909                         {
03910                                 center_selection(new_item);
03911                                 redraw = 1;
03912                         }
03913                         result = 1;
03914                         break;
03915 
03916                 case PGUP:
03917                         new_selection = new_item = select_previous(view_items - 1);
03918 
03919                         if(new_item >= 0)
03920                         {
03921                                 center_selection(new_item);
03922                                 redraw = 1;
03923                         }
03924                         result = 1;
03925                         break;
03926 
03927                 case PGDN:
03928                         new_selection = new_item = select_next(view_items - 1);
03929 
03930                         if(new_item >= 0)
03931                         {
03932                                 center_selection(new_item);
03933                                 redraw = 1;
03934                         }
03935                         result = 1;
03936                         break;
03937 
03938                 case LEFT:
03939                         xposition -= 10;
03940                         redraw = 1;
03941                         result = 1;
03942                         break;
03943 
03944                 case RIGHT:
03945                         xposition += 10;
03946                         redraw = 1;
03947                         result = 1;
03948                         break;
03949 
03950                 default:
03951                         if(!ctrl_down())
03952                         {
03953                                 if(top_level->get_keypress() > 30 && 
03954                                         top_level->get_keypress() < 127)
03955                                 {
03956                                         int query_len = strlen(query);
03957                                         query[query_len++] = top_level->get_keypress();
03958                                         query[query_len] = 0;
03959                                         new_selection = query_list();
03960                                 }
03961                                 else
03962                                 if(top_level->get_keypress() == BACKSPACE)
03963                                 {
03964                                         int query_len = strlen(query);
03965                                         if(query_len > 0) query[--query_len] = 0;
03966                                         new_selection = query_list();
03967                                 }
03968 
03969                                 redraw = 1;
03970                                 result = 1;
03971                         }
03972                         break;
03973         }
03974 
03975         if(redraw)
03976         {
03977                 clamp_positions();
03978                 draw_items(1);
03979                 update_scrollbars();
03980         }
03981         
03982         if(new_selection >= 0)
03983         {
03984                 selection_changed();
03985         }
03986 
03987         return result;
03988 }
03989 
03990 
03991 BC_Pixmap* BC_ListBox::get_bg_surface()
03992 {
03993         return bg_surface;
03994 }
03995 
03996 
03997 void BC_ListBox::draw_background()
03998 {
03999 // White background pixmap
04000         set_color(top_level->get_resources()->listbox_inactive);
04001         draw_box(0, 0, bg_surface->get_w(), bg_surface->get_h(), bg_surface);
04002 
04003 // Optional heroine pixmap
04004         if(bg_pixmap)
04005                 bg_surface->draw_pixmap(bg_pixmap,
04006                         bg_surface->get_w() - top_level->get_resources()->listbox_bg->get_w(),
04007                         0);
04008 }
04009 
04010 void BC_ListBox::clear_listbox(int x, int y, int w, int h)
04011 {
04012         gui->draw_pixmap(bg_surface, 
04013                 x, 
04014                 y, 
04015                 w, 
04016                 h,
04017                 x,
04018                 y - title_h);
04019 }
04020 
04021 void BC_ListBox::update_format(int display_format, int redraw)
04022 {
04023         this->display_format = display_format;
04024         if(redraw)
04025         {
04026                 if(gui) draw_items(1);
04027         }
04028 }
04029 
04030 int BC_ListBox::get_format()
04031 {
04032         return display_format;
04033 }
04034 
04035 
04036 
04037 int BC_ListBox::draw_items(int flash)
04038 {
04039         if(gui)
04040         {
04041                 BC_Resources *resources = get_resources();
04042 
04043 //dump(data, columns);
04044 
04045 // Calculate items width 
04046                 calculate_item_coords();
04047 
04048 
04049 // Create and destroy scrollbars as needed
04050                 get_scrollbars();
04051 
04052 
04053 
04054 //              draw_background();
04055 
04056 // Icon display
04057                 if(display_format == LISTBOX_ICONS)
04058                 {
04059                         clear_listbox(2, 2 + title_h, view_w, view_h);
04060 
04061                         set_font(MEDIUMFONT);
04062                         for(int i = 0; i < data[master_column].total; i++)
04063                         {
04064                                 BC_ListBoxItem *item = data[master_column].values[i];
04065                                 if(get_item_x(item) >= -get_item_w(item) && 
04066                                         get_item_x(item) < view_w &&
04067                                         get_item_y(item) >= -get_item_h(item) + title_h &&
04068                                         get_item_y(item) < view_h + title_h)
04069                                 {
04070                                         int item_color = get_item_highlight(data, 0, i);
04071                                         int icon_x, icon_y, icon_w, icon_h;
04072                                         int text_x, text_y, text_w, text_h;
04073 
04074 // Draw highlights
04075                                         get_icon_mask(item, icon_x, icon_y, icon_w, icon_h);
04076                                         get_text_mask(item, text_x, text_y, text_w, text_h);
04077 
04078 
04079                                         if(item_color != resources->listbox_inactive)
04080                                         {
04081                                                 gui->set_color(BLACK);
04082                                                 gui->draw_rectangle(icon_x, icon_y, icon_w, icon_h);
04083                                                 gui->set_color(item_color);
04084                                                 gui->draw_box(icon_x + 1, icon_y + 1, icon_w - 2, icon_h - 2);
04085                                                 gui->set_color(BLACK);
04086                                                 gui->draw_rectangle(text_x, text_y, text_w, text_h);
04087                                                 gui->set_color(item_color);
04088                                                 gui->draw_box(text_x + 1, text_y + 1, text_w - 2, text_h - 2);
04089 
04090                                                 if(icon_position == ICON_LEFT)
04091                                                         gui->draw_box(text_x - 1, text_y + 1, 2, text_h - 2);
04092                                                 else
04093                                                 if(icon_position == ICON_TOP)
04094                                                         gui->draw_line(text_x + 1, text_y, text_x + icon_w - 2, text_y);
04095                                                 if(text_x + text_w < icon_x + icon_w)
04096                                                 {
04097                                                         gui->set_color(BLACK);
04098                                                         gui->draw_line(text_x + text_w, 
04099                                                                 icon_y + icon_h,
04100                                                                 icon_x + icon_w,
04101                                                                 icon_y + icon_h);
04102                                                 }
04103                                         }
04104 
04105 // Draw icons
04106                                         gui->set_color(get_item_color(data, 0, i));
04107                                         if(item->icon)
04108                                                 gui->pixmap->draw_pixmap(item->icon, 
04109                                                         icon_x + ICON_MARGIN, 
04110                                                         icon_y + ICON_MARGIN);
04111                                         gui->draw_text(text_x + ICON_MARGIN, 
04112                                                 text_y + ICON_MARGIN + get_text_ascent(MEDIUMFONT), 
04113                                                 item->text);
04114                                 }
04115                         }
04116                 }
04117                 else
04118 // Text display
04119                 if(display_format == LISTBOX_TEXT)
04120                 {
04121 // Draw one column at a time so text overruns don't go into the next column
04122 // clear column backgrounds
04123                         int current_toggle = 0;
04124                         for(int j = 0; j < columns; j++)
04125                         {
04126                                 clear_listbox(LISTBOX_BORDER + get_column_offset(j) - xposition, 
04127                                         LISTBOX_BORDER + title_h, 
04128                                         get_column_width(j, 1), 
04129                                         view_h);
04130 
04131 // Draw rows in the column recursively
04132