Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members

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 "clip.h"
00007 #include "cursors.h"
00008 #include "fonts.h"
00009 #include "keys.h"
00010 #include "language.h"
00011 #include "bctimer.h"
00012 #include "vframe.h"
00013 
00014 #include <string.h>
00015 #include <unistd.h>
00016 
00017 // ====================================================== scrollbars
00018 
00019 
00020 BC_ListBoxYScroll::BC_ListBoxYScroll(BC_ListBox *listbox, 
00021                           int total_height, 
00022                                           int view_height, 
00023                           int position)
00024  : BC_ScrollBar(listbox->get_yscroll_x(), 
00025         listbox->get_yscroll_y(), 
00026         SCROLL_VERT, 
00027         listbox->get_yscroll_height(), 
00028         total_height, 
00029         position, 
00030         view_height)
00031 {
00032         this->listbox = listbox;
00033 }
00034 
00035 BC_ListBoxYScroll::~BC_ListBoxYScroll()
00036 {
00037 }
00038 
00039 int BC_ListBoxYScroll::handle_event()
00040 {
00041         listbox->set_yposition(get_value());
00042         return 1;
00043 }
00044 
00045 
00046 
00047 
00048 
00049 
00050 
00051 BC_ListBoxXScroll::BC_ListBoxXScroll(BC_ListBox *listbox, 
00052                           int total_width, 
00053                                           int view_width,
00054                           int position)
00055  : BC_ScrollBar(listbox->get_xscroll_x(), 
00056         listbox->get_xscroll_y(), 
00057         SCROLL_HORIZ, 
00058         listbox->get_xscroll_width(), 
00059         total_width, 
00060         position, 
00061         view_width)
00062 {
00063         this->listbox = listbox;
00064 }
00065 
00066 BC_ListBoxXScroll::~BC_ListBoxXScroll()
00067 {
00068 }
00069 
00070 int BC_ListBoxXScroll::handle_event()
00071 {
00072         listbox->set_xposition(get_value());
00073         return 1;
00074 }
00075 
00076 
00077 
00078 
00079 
00080 
00081 
00082 
00083 BC_ListBoxToggle::BC_ListBoxToggle(BC_ListBox *listbox, 
00084         BC_ListBoxItem *item, 
00085         int x, 
00086         int y)
00087 {
00088         this->listbox = listbox;
00089         this->item = item;
00090         this->x = x;
00091         this->y = y;
00092         this->value = item->get_expand();
00093         if(this->value) 
00094                 state = BC_Toggle::TOGGLE_CHECKED;
00095         else
00096                 state = BC_Toggle::TOGGLE_UP;
00097 }
00098 
00099 void BC_ListBoxToggle::update(BC_ListBoxItem *item, 
00100         int x, 
00101         int y,
00102         int flash)
00103 {
00104         this->value = item->get_expand();
00105         this->item = item;
00106         this->x = x;
00107         this->y = y;
00108 
00109 // update state
00110         switch(state)
00111         {
00112                 case TOGGLE_UP:
00113                         if(value)
00114                                 state = TOGGLE_CHECKED;
00115                         break;
00116 
00117                 case TOGGLE_UPHI:
00118                         if(value)
00119                                 state = TOGGLE_CHECKEDHI;
00120                         break;
00121 
00122                 case TOGGLE_CHECKED:
00123                         if(!value)
00124                                 state = TOGGLE_UP;
00125                         break;
00126 
00127                 case TOGGLE_DOWN:
00128                         break;
00129 
00130                 case TOGGLE_CHECKEDHI:
00131                         if(!value)
00132                                 state = TOGGLE_UPHI;
00133                         break;
00134 
00135                 case TOGGLE_DOWN_EXIT:
00136                         break;
00137         }
00138 
00139 
00140         draw(flash);
00141 }
00142 
00143 int BC_ListBoxToggle::cursor_motion_event(int *redraw_toggles)
00144 {
00145         int w = listbox->toggle_images[0]->get_w();
00146         int h = listbox->toggle_images[0]->get_h();
00147         int cursor_inside = listbox->get_cursor_x() >= x && 
00148                 listbox->get_cursor_x() < x + w &&
00149                 listbox->get_cursor_y() >= y && 
00150                 listbox->get_cursor_y() < y + h;
00151         int result = 0;
00152 
00153         switch(state)
00154         {
00155                 case BC_ListBoxToggle::TOGGLE_UPHI:
00156                         if(!cursor_inside)
00157                         {
00158                                 state = BC_ListBoxToggle::TOGGLE_UP;
00159                                 *redraw_toggles = 1;
00160                         }
00161                         break;
00162 
00163                 case BC_ListBoxToggle::TOGGLE_CHECKEDHI:
00164                         if(!cursor_inside)
00165                         {
00166                                 state = BC_ListBoxToggle::TOGGLE_CHECKED;
00167                                 *redraw_toggles = 1;
00168                         }
00169                         break;
00170 
00171                 case BC_ListBoxToggle::TOGGLE_DOWN:
00172                         if(!cursor_inside)
00173                         {
00174                                 state = BC_ListBoxToggle::TOGGLE_DOWN_EXIT;
00175                                 *redraw_toggles = 1;
00176                         }
00177                         result = 1;
00178                         break;
00179 
00180                 case BC_ListBoxToggle::TOGGLE_DOWN_EXIT:
00181                         if(cursor_inside)
00182                         {
00183                                 state = BC_ListBoxToggle::TOGGLE_DOWN;
00184                                 *redraw_toggles = 1;
00185                         }
00186                         result = 1;
00187                         break;
00188 
00189                 default:
00190                         if(cursor_inside)
00191                         {
00192                                 if(value)
00193                                         state = BC_ListBoxToggle::TOGGLE_CHECKEDHI;
00194                                 else
00195                                         state = BC_ListBoxToggle::TOGGLE_UPHI;
00196                                 *redraw_toggles = 1;
00197                         }
00198                         break;
00199         }
00200         return result;
00201 }
00202 
00203 int BC_ListBoxToggle::cursor_leave_event(int *redraw_toggles)
00204 {
00205         if(value)
00206                 state = BC_ListBoxToggle::TOGGLE_CHECKED;
00207         else
00208                 state = BC_ListBoxToggle::TOGGLE_UP;
00209 }
00210 
00211 int BC_ListBoxToggle::button_press_event()
00212 {
00213         int w = listbox->toggle_images[0]->get_w();
00214         int h = listbox->toggle_images[0]->get_h();
00215 
00216         if(listbox->gui->get_cursor_x() >= x && 
00217                 listbox->gui->get_cursor_x() < x + w &&
00218                 listbox->gui->get_cursor_y() >= y && 
00219                 listbox->gui->get_cursor_y() < y + h)
00220         {
00221                 state = BC_ListBoxToggle::TOGGLE_DOWN;
00222                 return 1;
00223         }
00224         return 0;
00225 }
00226 
00227 int BC_ListBoxToggle::button_release_event(int *redraw_toggles)
00228 {
00229         int result = 0;
00230         switch(state)
00231         {
00232                 case BC_ListBoxToggle::TOGGLE_DOWN:
00233                         value = !value;
00234                         if(value)
00235                                 state = BC_ListBoxToggle::TOGGLE_CHECKEDHI;
00236                         else
00237                                 state = BC_ListBoxToggle::TOGGLE_UPHI;
00238                         listbox->expand_item(item, value);
00239                         result = 1;
00240                         break;
00241 
00242                 case BC_ListBoxToggle::TOGGLE_DOWN_EXIT:
00243                         if(value)
00244                                 state = BC_ListBoxToggle::TOGGLE_CHECKED;
00245                         else
00246                                 state = BC_ListBoxToggle::TOGGLE_UP;
00247                         *redraw_toggles = 1;
00248                         result = 1;
00249                         break;
00250         }
00251         return result;
00252 }
00253 
00254 void BC_ListBoxToggle::draw(int flash)
00255 {
00256         if(listbox->gui)
00257         {
00258                 int image_number = 0;
00259                 int w = listbox->toggle_images[0]->get_w();
00260                 int h = listbox->toggle_images[0]->get_h();
00261 
00262                 switch(state)
00263                 {
00264                         case BC_ListBoxToggle::TOGGLE_UP: image_number = 0; break;
00265                         case BC_ListBoxToggle::TOGGLE_UPHI: image_number = 1; break;
00266                         case BC_ListBoxToggle::TOGGLE_CHECKED: image_number = 2; break;
00267                         case BC_ListBoxToggle::TOGGLE_DOWN: image_number = 3; break;
00268                         case BC_ListBoxToggle::TOGGLE_CHECKEDHI: image_number = 4; break;
00269                         case BC_ListBoxToggle::TOGGLE_DOWN_EXIT:
00270                                 if(value)
00271                                         image_number = 2;
00272                                 else
00273                                         image_number = 0;
00274                                 break;
00275                 }
00276 
00277 //printf("BC_ListBoxToggle::draw 1 %d\n", state);
00278                 listbox->gui->draw_pixmap(listbox->toggle_images[image_number],
00279                         x,
00280                         y);
00281 
00282 
00283                 if(flash)
00284                 {
00285                         listbox->gui->flash(x, y, w, h);
00286                         listbox->gui->flush();
00287                 }
00288         }
00289 }
00290 
00291 
00292 
00293 
00294 
00295 
00296 
00297 
00298 
00299 
00300 
00301 
00302 
00303 
00304 // ====================================================== box
00305 
00306 BC_ListBox::BC_ListBox(int x, 
00307         int y, 
00308         int w, 
00309         int h,
00310         int display_format,
00311         ArrayList<BC_ListBoxItem*> *data,
00312         char **column_titles,
00313         int *column_width,
00314         int columns,
00315         int yposition,
00316         int is_popup,
00317         int selection_mode,
00318         int icon_position,
00319         int allow_drag)
00320  : BC_SubWindow(x, y, w, h, -1)
00321 {
00322         justify = LISTBOX_RIGHT;
00323         xposition = 0;
00324         highlighted_item = -1;
00325         highlighted_title = -1;
00326         highlighted_division = -1;
00327         highlighted_ptr = 0;
00328         xscrollbar = 0;
00329         yscrollbar = 0;
00330         current_cursor = ARROW_CURSOR;
00331         gui = 0;
00332         view_h = 0;
00333         view_w = 0;
00334         title_h = 0;
00335         active = 0;
00336         new_value = 0;
00337         need_xscroll = 0;
00338         need_yscroll = 0;
00339         bg_tile = 0;
00340         drag_popup = 0;
00341         selection_number1 = -1;
00342         selection_number2 = -1;
00343         bg_surface = 0;
00344         bg_pixmap = 0;
00345 
00346         current_operation = NO_OPERATION;
00347         button_highlighted = 0;
00348 
00349         disabled = 0;
00350 
00351         list_highlighted = 0;
00352 
00353         allow_drag_scroll = 1;
00354         process_drag = 1;
00355 
00356         sort_column = -1;
00357         sort_order = 0;
00358 
00359         allow_drag_column = 0;
00360         master_column = 0;
00361         search_column = 0;
00362 
00363         popup_w = w;
00364         popup_h = h;
00365 
00366         for(int i = 0; i < 3; i++)
00367                 column_bg[i] = 0;
00368 
00369         for(int i = 0; i < 4; i++)
00370                 button_images[i] = 0;
00371 
00372         for(int i = 0; i < 5; i++)
00373                 toggle_images[i] = 0;
00374 
00375         column_sort_up = 0;
00376         column_sort_dn = 0;
00377 
00378 //printf("BC_ListBox::BC_ListBox 1\n");
00379         this->data = data;
00380         this->columns = columns;
00381         this->yposition = yposition;
00382         this->is_popup = is_popup;
00383         this->display_format = display_format;
00384         this->selection_mode = selection_mode;
00385         this->icon_position = icon_position;
00386         this->allow_drag = allow_drag;
00387         this->column_titles = 0;
00388         this->column_width = 0;
00389 //printf("BC_ListBox::BC_ListBox 1\n");
00390 
00391         if((!column_titles && column_width) ||
00392                 (column_titles && !column_width))
00393         {
00394                 printf("BC_ListBox::BC_ListBox either column_titles or column_widths == NULL but not both.\n");
00395         }
00396 //printf("BC_ListBox::BC_ListBox 2 %p %p\n", column_titles, column_width);
00397         set_columns(column_titles, 
00398                 column_width, 
00399                 columns);
00400 
00401 //printf("BC_ListBox::BC_ListBox 3\n");
00402 
00403         drag_icon_vframe = 0;
00404         drag_column_icon_vframe = 0;
00405 
00406 
00407 
00408 // reset the search engine
00409 //printf("BC_ListBox::BC_ListBox 4\n");
00410         reset_query();
00411 //printf("BC_ListBox::BC_ListBox 5\n");
00412 }
00413 
00414 BC_ListBox::~BC_ListBox()
00415 {
00416         expanders.remove_all_objects();
00417         if(bg_surface) delete bg_surface;
00418         if(bg_pixmap) delete bg_pixmap;
00419         if(xscrollbar) delete xscrollbar;
00420         if(yscrollbar) delete yscrollbar;
00421         for(int i = 0; i < 3; i++)
00422                 if(column_bg[i]) delete column_bg[i];
00423         for(int i = 0; i < 4; i++)
00424                 if(button_images[i]) delete button_images[i];
00425         for(int i = 0; i < 5; i++)
00426                 if(toggle_images[i]) delete toggle_images[i];
00427         if(column_sort_up) delete column_sort_up;
00428         if(column_sort_dn) delete column_sort_dn;
00429 
00430         delete_columns();
00431         if(drag_popup) delete drag_popup;
00432 }
00433 
00434 int BC_ListBox::enable()
00435 {
00436   disabled = 0;
00437   draw_button();
00438   return 1;
00439 }
00440 
00441 int BC_ListBox::disable()
00442 {
00443   disabled = 1;
00444   draw_button();
00445   return 1;
00446 }
00447 
00448 void BC_ListBox::reset_query()
00449 {
00450         query[0] = 0;  // reset query
00451 }
00452 
00453 int BC_ListBox::evaluate_query(int list_item, char *string)
00454 {
00455         return(strcmp(string, data[search_column].values[list_item]->text) <= 0 && 
00456                 data[search_column].values[list_item]->searchable);
00457 }
00458 
00459 int BC_ListBox::query_list()
00460 {
00461         if(query[0] == 0) return 0;
00462 
00463         int done = 0;
00464         int result;
00465         int selection_changed = 0;
00466         int prev_selection = -1;
00467         for(int i = 0; !done && i < data[0].total; i++)
00468         {
00469                 if(evaluate_query(i, query))
00470                 {
00471                         result = i;
00472                         done = 1;
00473                 }
00474         }
00475 
00476         if(done)
00477         {
00478 // Deselect all
00479                 for(int i = 0; i < data[0].total; i++)
00480                 {
00481                         for(int j = 0; j < columns; j++)
00482                         {
00483                                 if(data[j].values[i]->selected) prev_selection = i;
00484                                 data[j].values[i]->selected = 0;
00485                         }
00486                 }
00487 
00488 // Select one
00489                 if(prev_selection != result)
00490                         selection_changed = 1;
00491                 for(int j = 0; j < columns; j++)
00492                 {
00493                         data[j].values[result]->selected = 1;
00494                 }
00495                 center_selection(result);
00496         }
00497 
00498         return selection_changed;
00499 }
00500 
00501 void BC_ListBox::init_column_width()
00502 {
00503         if(!column_width && data)
00504         {
00505                 int widest = 5, w;
00506                 for(int i = 0; i < data[0].total; i++)
00507                 {
00508                         w = get_text_width(MEDIUMFONT, data[0].values[i]->get_text()) + 2 * LISTBOX_MARGIN;
00509                         if(w > widest) widest = w;
00510                 }
00511                 default_column_width[0] = widest;
00512         }
00513 }
00514 
00515 int BC_ListBox::initialize()
00516 {
00517         if(is_popup)
00518         {
00519                 for(int i = 0; i < 4; i++)
00520                 {
00521                         button_images[i] = new BC_Pixmap(parent_window, 
00522                                 BC_WindowBase::get_resources()->listbox_button[i], 
00523                                 PIXMAP_ALPHA);
00524                 }
00525                 w = button_images[0]->get_w();
00526                 h = button_images[0]->get_h();
00527                 
00528                 gui = 0;
00529                 current_operation = NO_OPERATION;
00530         }
00531         else
00532         {
00533                 gui = this;
00534                 current_operation = NO_OPERATION;
00535         }
00536 
00537         for(int i = 0; i < 3; i++)
00538         {
00539                 column_bg[i] = new BC_Pixmap(parent_window,
00540                         get_resources()->listbox_column[i],
00541                         PIXMAP_ALPHA);
00542         }
00543         for(int i = 0; i < 5; i++)
00544         {
00545                 toggle_images[i] = new BC_Pixmap(parent_window,
00546                         get_resources()->listbox_expand[i],
00547                         PIXMAP_ALPHA);
00548         }
00549 
00550         column_sort_up = new BC_Pixmap(parent_window, 
00551                 BC_WindowBase::get_resources()->listbox_up, 
00552                 PIXMAP_ALPHA);
00553         column_sort_dn = new BC_Pixmap(parent_window, 
00554                 BC_WindowBase::get_resources()->listbox_dn, 
00555                 PIXMAP_ALPHA);
00556 
00557 //printf("BC_ListBox::initialize 10\n");
00558         drag_icon_vframe = get_resources()->type_to_icon[ICON_UNKNOWN];
00559         drag_column_icon_vframe = get_resources()->type_to_icon[ICON_COLUMN];
00560 // = new BC_Pixmap(parent_window, 
00561 //              get_resources()->type_to_icon[ICON_UNKNOWN], 
00562 //              PIXMAP_ALPHA);
00563 //      drag_column_icon = new BC_Pixmap(parent_window,
00564 //              get_resources()->type_to_icon[ICON_COLUMN],
00565 //              PIXMAP_ALPHA);
00566         BC_SubWindow::initialize();
00567 
00568         init_column_width();
00569 
00570         if(top_level->get_resources()->listbox_bg)
00571                 bg_pixmap = new BC_Pixmap(this, 
00572                         get_resources()->listbox_bg, 
00573                         PIXMAP_OPAQUE);
00574 
00575         draw_button();
00576         draw_items(1);
00577         return 0;
00578 }
00579 
00580 void BC_ListBox::deactivate_selection()
00581 {
00582         current_operation = NO_OPERATION;
00583 }
00584 
00585 int BC_ListBox::draw_button()
00586 {
00587 // Draw the button for a popup listbox
00588         if(is_popup)
00589         {
00590                 int image_number = 0;
00591 
00592                 draw_top_background(parent_window, 0, 0, w, h);
00593 
00594                 if(button_highlighted)
00595                         image_number = 1;
00596                 if(current_operation == BUTTON_DN)
00597                         image_number = 2;
00598                 if(disabled)
00599                         image_number = 3;
00600 
00601 
00602                 button_images[image_number]->write_drawable(pixmap, 
00603                         0, 
00604                         0,
00605                         w,
00606                         h,
00607                         0,
00608                         0);
00609                 flash();
00610         }
00611         return 0;
00612 }
00613 
00614 int BC_ListBox::calculate_item_coords()
00615 {
00616         if(!data) return 0;
00617 
00618         int icon_x = 0;
00619         int next_icon_x = 0;
00620         int next_icon_y = 0;
00621         int next_text_y = 0;
00622 // Change the display_format to get the right item dimensions for both
00623 // text and icons.
00624         int display_format_temp = display_format;
00625 
00626 
00627 // Scan the first column for lowest y coord of all text
00628 // and lowest right x and y coord for all icons which aren't auto placable
00629         calculate_last_coords_recursive(data,
00630                 &icon_x,
00631                 &next_icon_x, 
00632                 &next_icon_y,
00633                 &next_text_y,
00634                 1);
00635 
00636 // Reset last column width.  It's recalculated based on text width.
00637 
00638         calculate_item_coords_recursive(data,
00639                 &icon_x,
00640                 &next_icon_x, 
00641                 &next_icon_y,
00642                 &next_text_y,
00643                 1);
00644 
00645 
00646 
00647         display_format = display_format_temp;
00648 
00649         return 0;
00650 }
00651 
00652 void BC_ListBox::calculate_last_coords_recursive(
00653         ArrayList<BC_ListBoxItem*> *data,
00654         int *icon_x,
00655         int *next_icon_x,
00656         int *next_icon_y,
00657         int *next_text_y,
00658         int top_level)
00659 {
00660         for(int i = 0; i < data[0].total; i++)
00661         {
00662                 int current_text_y = 0;
00663                 int current_icon_x = 0;
00664                 int current_icon_y = 0;
00665                 BC_ListBoxItem *item = data[0].values[i];
00666 
00667 // Get next_text_y
00668                 if(!item->autoplace_text)
00669                 {
00670 // Lowest text coordinate
00671                         display_format = LISTBOX_TEXT;
00672                         current_text_y = item->text_y + 
00673                                 get_text_height(MEDIUMFONT);
00674                         if(current_text_y > *next_text_y)
00675                                 *next_text_y = current_text_y;
00676 
00677 // Add sublist depth if it is expanded
00678                         if(item->get_sublist() && 
00679                                 item->get_columns() &&
00680                                 item->get_expand())
00681                         {
00682                                 calculate_last_coords_recursive(item->get_sublist(),
00683                                         icon_x,
00684                                         next_icon_x, 
00685                                         next_icon_y,
00686                                         next_text_y,
00687                                         0);
00688                         }
00689                 }
00690 
00691 // Get next_icon coordinate
00692                 if(top_level)
00693                 {
00694                         BC_ListBoxItem *item = data[master_column].values[i];
00695                         if(!item->autoplace_icon)
00696                         {
00697                                 display_format = LISTBOX_ICONS;
00698 // Lowest right icon coordinate.
00699                                 current_icon_x = item->icon_x;
00700                                 if(current_icon_x > *icon_x) *icon_x = current_icon_x;
00701                                 if(current_icon_x + get_item_w(item) > *next_icon_x)
00702                                         *next_icon_x = current_icon_x + get_item_w(item);
00703 
00704                                 current_icon_y = item->icon_y + get_item_h(item);
00705                                 if(current_icon_y > *next_icon_y) 
00706                                         *next_icon_y = current_icon_y;
00707                         }
00708                 }
00709         }
00710 }
00711 
00712 
00713 void BC_ListBox::calculate_item_coords_recursive(
00714         ArrayList<BC_ListBoxItem*> *data,
00715         int *icon_x,
00716         int *next_icon_x,
00717         int *next_icon_y,
00718         int *next_text_y,
00719         int top_level)
00720 {
00721 
00722 
00723 
00724 // Set up items which need autoplacement.
00725 // Should fill icons down and then across
00726         for(int i = 0; i < data[0].total; i++)
00727         {
00728 // Don't increase y unless the row requires autoplacing.
00729                 int total_autoplaced_columns = 0;
00730 
00731 // Set up icons in first column
00732                 if(top_level)
00733                 {
00734                         BC_ListBoxItem *item = data[master_column].values[i];
00735                         if(item->autoplace_icon)
00736                         {
00737 // 1 column only if icons are used
00738                                 display_format = LISTBOX_ICONS;
00739 // Test row height
00740 // Start new row.
00741                                 if(*next_icon_y + get_item_h(item) >= get_h() && 
00742                                         *next_icon_y > 0)
00743                                 {
00744                                         *icon_x = *next_icon_x;
00745                                         *next_icon_y = 0;
00746                                 }
00747 
00748                                 if(*icon_x + get_item_w(item) > *next_icon_x)
00749                                         *next_icon_x = *icon_x + get_item_w(item);
00750 
00751 
00752                                 item->set_icon_x(*icon_x);
00753                                 item->set_icon_y(*next_icon_y);
00754 
00755                                 *next_icon_y += get_item_h(item);
00756                         }
00757                 }
00758 
00759 
00760 
00761 // Set up a text row
00762                 int next_text_x = 0;
00763                 for(int j = 0; j < columns; j++)
00764                 {
00765                         BC_ListBoxItem *item = data[j].values[i];
00766                         if(item->autoplace_text)
00767                         {
00768                                 display_format = LISTBOX_TEXT;
00769                                 item->set_text_x(next_text_x);
00770                                 item->set_text_y(*next_text_y);
00771 
00772 // printf("BC_ListBox::calculate_item_coords_recursive %p %d %d %d %d %s \n", 
00773 // item->get_sublist(), 
00774 // item->get_columns(), 
00775 // item->get_expand(), 
00776 // next_text_x, 
00777 // *next_text_y,
00778 // item->get_text());
00779 // Increment position of next column
00780                                 if(j < columns - 1)
00781                                         next_text_x += (column_width ? 
00782                                                 column_width[j] : 
00783                                                 default_column_width[j]);
00784                                 else
00785 // Set last column width based on text width
00786                                 {
00787                                         int new_w = get_item_w(item);
00788 
00789                                         int *previous_w = (column_width ? 
00790                                                 &column_width[j] : 
00791                                                 &default_column_width[j]);
00792                                         if(new_w > *previous_w)
00793                                                 *previous_w = new_w;
00794 //printf("BC_ListBox::calculate_item_coords_recursive 1 %d\n", new_w);
00795                                 }
00796                                 total_autoplaced_columns++;
00797                         }
00798                 }
00799 
00800 // Increase the text vertical position
00801                 if(total_autoplaced_columns)
00802                 {
00803                         display_format = LISTBOX_TEXT;
00804                         *next_text_y += get_text_height(MEDIUMFONT);
00805                 }
00806 
00807 // Set up a sublist
00808                 BC_ListBoxItem *item = data[master_column].values[i];
00809                 if(item->get_sublist() &&
00810                         item->get_columns() &&
00811                         item->get_expand())
00812                 {
00813                         calculate_item_coords_recursive(
00814                                 item->get_sublist(),
00815                                 icon_x,
00816                                 next_icon_x,
00817                                 next_icon_y,
00818                                 next_text_y,
00819                                 0);
00820                 }
00821         }
00822 }
00823 
00824 void BC_ListBox::set_justify(int value)
00825 {
00826         this->justify = value;
00827 }
00828 
00829 void BC_ListBox::set_allow_drag_column(int value)
00830 {
00831         this->allow_drag_column = value;
00832 }
00833 
00834 void BC_ListBox::set_process_drag(int value)
00835 {
00836         this->process_drag = value;
00837 }
00838 
00839 void BC_ListBox::set_master_column(int value, int redraw)
00840 {
00841         this->master_column = value;
00842         if(redraw)
00843         {
00844                 draw_items(1);
00845         }
00846 }
00847 
00848 void BC_ListBox::set_search_column(int value)
00849 {
00850         this->search_column = value;
00851 }
00852 
00853 int BC_ListBox::get_sort_column()
00854 {
00855         return sort_column;
00856 }
00857 
00858 void BC_ListBox::set_sort_column(int value, int redraw)
00859 {
00860         sort_column = value;
00861         if(redraw)
00862         {
00863                 draw_titles(1);
00864         }
00865 }
00866 
00867 int BC_ListBox::get_sort_order()
00868 {
00869         return sort_order;
00870 }
00871 
00872 void BC_ListBox::set_sort_order(int value, int redraw)
00873 {
00874         sort_order = value;
00875         if(redraw)
00876         {
00877                 draw_titles(1);
00878         }
00879 }
00880 
00881 
00882 
00883 
00884 
00885 int BC_ListBox::get_display_mode()
00886 {
00887         return display_format;
00888 }
00889 
00890 int BC_ListBox::get_yposition()
00891 {
00892         return yposition;
00893 }
00894 
00895 int BC_ListBox::get_xposition()
00896 {
00897         return xposition;
00898 }
00899 
00900 int BC_ListBox::get_highlighted_item()
00901 {
00902         return highlighted_item;
00903 }
00904 
00905 
00906 int BC_ListBox::get_item_x(BC_ListBoxItem *item)
00907 {
00908         if(display_format == LISTBOX_TEXT)
00909                 return item->text_x - xposition + 2;
00910         else
00911                 return item->icon_x - xposition + 2;
00912 }
00913 
00914 int BC_ListBox::get_item_y(BC_ListBoxItem *item)
00915 {
00916         int result;
00917         if(display_format == LISTBOX_TEXT)
00918                 result = item->text_y - yposition + title_h + 2;
00919         else
00920                 result = item->icon_y - yposition + title_h + 2;
00921         return result;
00922 }
00923 
00924 int BC_ListBox::get_item_w(BC_ListBoxItem *item)
00925 {
00926         if(display_format == LISTBOX_ICONS)
00927         {
00928                 int x, y, w, h;
00929                 get_icon_mask(item, x, y, w, h);
00930                 int icon_w = w;
00931                 get_text_mask(item, x, y, w, h);
00932                 int text_w = w;
00933 
00934                 if(icon_position == ICON_LEFT)
00935                         return icon_w + text_w;
00936                 else
00937                         return (icon_w > text_w) ? icon_w : text_w;
00938         }
00939         else
00940         {
00941                 return get_text_width(MEDIUMFONT, item->text) + 2 * LISTBOX_MARGIN;
00942         }
00943 }
00944 
00945 int BC_ListBox::get_item_h(BC_ListBoxItem *item)
00946 {
00947         if(display_format == LISTBOX_ICONS)
00948         {
00949                 int x, y, w, h;
00950                 get_icon_mask(item, x, y, w, h);
00951                 int icon_h = h;
00952                 get_text_mask(item, x, y, w, h);
00953                 int text_h = h;
00954 
00955                 if(icon_position == ICON_LEFT)
00956                         return (icon_h > text_h) ? icon_h : text_h;
00957                 else
00958                         return icon_h + text_h;
00959         }
00960         else
00961         {
00962                 return get_text_height(MEDIUMFONT);
00963         }
00964         return 0;
00965 }
00966 
00967 
00968 int BC_ListBox::get_icon_w(BC_ListBoxItem *item)
00969 {
00970         BC_Pixmap *icon = item->icon;
00971         if(icon) return icon->get_w();
00972         return 0;
00973 }
00974 
00975 int BC_ListBox::get_icon_h(BC_ListBoxItem *item)
00976 {
00977         BC_Pixmap *icon = item->icon;
00978         if(icon) return icon->get_h();
00979         return 0;
00980 }
00981 
00982 int BC_ListBox::get_items_width()
00983 {
00984         int widest = 0;
00985 
00986         if(display_format == LISTBOX_ICONS)
00987         {
00988                 for(int i = 0; i < columns; i++)
00989                 {
00990                         for(int j = 0; j < data[i].total; j++)
00991                         {
00992                                 int x1, x, y, w, h;
00993                                 BC_ListBoxItem *item = data[i].values[j];
00994                                 x1 = item->icon_x;
00995 
00996                                 get_icon_mask(item, x, y, w, h);
00997                                 if(x1 + w > widest) widest = x1 + w;
00998 
00999                                 if(display_format == LISTBOX_ICONS && icon_position == ICON_LEFT)
01000                                         x1 += w;
01001 
01002                                 get_text_mask(item, x, y, w, h);
01003                                 if(x1 + w > widest) widest = x1 + w;
01004                         }
01005                 }
01006         }
01007         else
01008         if(display_format == LISTBOX_TEXT)
01009         {
01010                 return get_column_offset(columns);
01011         }
01012         return widest;
01013 }
01014 
01015 int BC_ListBox::get_items_height(ArrayList<BC_ListBoxItem*> *data, 
01016         int columns,
01017         int *result)
01018 {
01019         int temp = 0;
01020         int top_level = 0;
01021         int highest = 0;
01022         if(!result)
01023         {
01024                 result = &temp;
01025                 top_level = 1;
01026         }
01027 
01028 
01029 
01030 
01031 
01032         for(int j = 0; j < (data ? data[master_column].total : 0); j++)
01033         {
01034                 int y1, x, y, w, h;
01035                 BC_ListBoxItem *item = data[master_column].values[j];
01036 
01037                 if(display_format == LISTBOX_ICONS)
01038                 {
01039                         get_icon_mask(item, x, y, w, h);
01040                         if(y + h + yposition > highest) highest = y + h + yposition;
01041 
01042                         get_text_mask(item, x, y, w, h);
01043                         if(y + h + yposition > highest) highest = y + h + yposition;
01044                 }
01045                 else
01046                 {
01047                         get_text_mask(item, x, y, w, h);
01048                         *result += h;
01049 
01050 
01051 // Descend into sublist
01052                         if(item->get_sublist() &&
01053                                 item->get_expand())
01054                         {
01055                                 get_items_height(item->get_sublist(), 
01056                                         item->get_columns(), 
01057                                         result);
01058                         }
01059                 }
01060         }
01061         if(display_format == LISTBOX_TEXT && top_level) 
01062         {
01063                 highest = LISTBOX_MARGIN + *result;
01064         }
01065 
01066 
01067         return highest;
01068 }
01069 
01070 int BC_ListBox::set_yposition(int position, int draw_items)
01071 {
01072         this->yposition = position;
01073         if(draw_items)
01074         {
01075                 this->draw_items(1);
01076         }
01077         return 0;
01078 }
01079 
01080 int BC_ListBox::set_xposition(int position)
01081 {
01082         this->xposition = position;
01083         draw_items(1);
01084         return 0;
01085 }
01086 
01087 void BC_ListBox::expand_item(BC_ListBoxItem *item, int expand)
01088 {
01089         if(item)
01090         {
01091                 item->expand = expand;
01092 // Collapse sublists if this is collapsed to make it easier to calculate
01093 // coordinates
01094                 if(item->get_sublist())
01095                         collapse_recursive(item->get_sublist(), master_column);
01096 
01097 
01098 // Set everything for autoplacement
01099                 
01100                 set_autoplacement(data, 0, 1);
01101 
01102                 draw_items(1);
01103         }
01104 }
01105 
01106 void BC_ListBox::collapse_recursive(ArrayList<BC_ListBoxItem*> *data,
01107                 int master_column)
01108 {
01109         for(int i = 0; i < data[master_column].total; i++)
01110         {
01111                 BC_ListBoxItem *item = data[master_column].values[i];
01112                 if(item->get_sublist() && item->expand)
01113                 {
01114                         item->expand = 0;
01115                         collapse_recursive(item->get_sublist(), master_column);
01116                 }
01117         }
01118 }
01119 
01120 void BC_ListBox::set_autoplacement(ArrayList<BC_ListBoxItem*> *data,
01121         int do_icons, 
01122         int do_text)
01123 {
01124         for(int i = 0; i < data[0].total; i++)
01125         {
01126                 for(int j = 0; j < columns; j++)
01127                 {
01128                         if(do_icons) data[j].values[i]->autoplace_icon = 1;
01129                         if(do_text) data[j].values[i]->autoplace_text = 1;
01130                 }
01131 
01132                 BC_ListBoxItem *item = data[master_column].values[i];
01133                 if(item->get_sublist())
01134                 {
01135                         set_autoplacement(item->get_sublist(), do_icons, do_text);
01136                 }
01137         }
01138 }
01139 
01140 
01141 
01142 int BC_ListBox::get_w()
01143 {
01144         if(is_popup)
01145                 return BCPOPUPLISTBOX_W;
01146         else
01147                 return popup_w;
01148 }
01149 
01150 int BC_ListBox::get_h()
01151 {
01152         if(is_popup)
01153                 return BCPOPUPLISTBOX_H;
01154         else
01155                 return popup_h;
01156 }
01157 
01158 int BC_ListBox::get_yscroll_x()
01159 {
01160         if(is_popup)
01161                 return popup_w - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w();
01162         else
01163                 return get_x() + 
01164                         popup_w - 
01165                         get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w();
01166 }
01167 
01168 int BC_ListBox::get_yscroll_y()
01169 {
01170         if(is_popup)
01171                 return 0;
01172         else
01173                 return get_y();
01174 }
01175 
01176 int BC_ListBox::get_yscroll_height()
01177 {
01178         return popup_h - (need_xscroll ? 
01179                 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h() : 
01180                 0);
01181 }
01182 
01183 int BC_ListBox::get_xscroll_x()
01184 {
01185         if(is_popup)
01186                 return 0;
01187         else
01188                 return get_x();
01189 }
01190 
01191 int BC_ListBox::get_xscroll_y()
01192 {
01193         if(is_popup)
01194                 return popup_h - 
01195                         get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h();
01196         else
01197                 return get_y() + 
01198                         popup_h - 
01199                         get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h();
01200 }
01201 
01202 int BC_ListBox::get_xscroll_width()
01203 {
01204         return popup_w - (need_yscroll ? 
01205                 get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w() : 
01206                 0);
01207 }
01208 
01209 int BC_ListBox::get_column_offset(int column)
01210 {
01211         int x = 0;
01212         while(column > 0)
01213         {
01214                 x += column_width ? 
01215                         column_width[--column] : 
01216                         default_column_width[--column];
01217         }
01218         return x;
01219 }
01220 
01221 void BC_ListBox::column_width_boundaries()
01222 {
01223         if(column_width)
01224         {
01225                 for(int i = 0; i < columns; i++)
01226                 {
01227                         if(column_width[i] < MIN_COLUMN_WIDTH) column_width[i] = MIN_COLUMN_WIDTH;
01228                 }
01229         }
01230         else
01231         {
01232                 for(int i = 0; i < columns; i++)
01233                 {
01234                         if(default_column_width[i] < MIN_COLUMN_WIDTH) default_column_width[i] = MIN_COLUMN_WIDTH;
01235                 }
01236         }
01237 }
01238 
01239 int BC_ListBox::get_column_width(int column, int clamp_right)
01240 {
01241         if(column < columns - 1 || !clamp_right)
01242                 return column_width ? 
01243                         column_width[column] : 
01244                         default_column_width[column];
01245         else
01246                 return popup_w + 
01247                         xposition - 
01248                         get_column_offset(column);
01249 }
01250 
01251 int BC_ListBox::get_icon_mask(BC_ListBoxItem *item, 
01252         int &x, 
01253         int &y, 
01254         int &w, 
01255         int &h)
01256 {
01257         if(display_format == LISTBOX_ICONS)
01258         {
01259                 x = get_item_x(item);
01260                 y = get_item_y(item);
01261                 w = get_icon_w(item) + ICON_MARGIN * 2;
01262                 h = get_icon_h(item) + ICON_MARGIN * 2;
01263         }
01264         else
01265         if(display_format == LISTBOX_TEXT)
01266         {
01267                 x = y = w = h = 0;
01268         }
01269         return 0;
01270 }
01271 
01272 int BC_ListBox::get_text_mask(BC_ListBoxItem *item, 
01273         int &x, 
01274         int &y, 
01275         int &w, 
01276         int &h)
01277 {
01278         x = get_item_x(item);
01279         y = get_item_y(item);
01280 
01281         if(display_format == LISTBOX_ICONS)
01282         {
01283                 if(icon_position == ICON_LEFT)
01284                 {
01285                         x += get_icon_w(item) + ICON_MARGIN * 2;
01286                         y += get_icon_h(item) - get_text_height(MEDIUMFONT);
01287                 }
01288                 else
01289                 {
01290                         y += get_icon_h(item) + ICON_MARGIN;
01291                 }
01292 
01293                 w = get_text_width(MEDIUMFONT, item->text) + ICON_MARGIN * 2;
01294                 h = get_text_height(MEDIUMFONT) + ICON_MARGIN * 2;
01295         }
01296         else
01297         if(display_format == LISTBOX_TEXT)
01298         {
01299                 w = get_text_width(MEDIUMFONT, item->text) + LISTBOX_MARGIN * 2;
01300                 h = get_text_height(MEDIUMFONT);
01301         }
01302         return 0;
01303 }
01304 
01305 int BC_ListBox::get_item_highlight(ArrayList<BC_ListBoxItem*> *data, 
01306         int column, 
01307         int item)
01308 {
01309         BC_Resources *resources = get_resources();
01310         if(data[column].values[item]->selected)
01311                 return resources->listbox_selected;
01312         else
01313         if(highlighted_item >= 0 &&
01314                 highlighted_ptr == data[master_column].values[item])
01315                 return resources->listbox_highlighted;
01316         else
01317                 return resources->listbox_inactive;
01318 }
01319 
01320 int BC_ListBox::get_item_color(ArrayList<BC_ListBoxItem*> *data, 
01321         int column, 
01322         int item)
01323 {
01324         int color = data[column].values[item]->color;
01325         if(color == -1) color = get_resources()->listbox_text;
01326         if(get_item_highlight(data, column, item) == color)
01327                 return BLACK;
01328         else
01329                 return color;
01330 }
01331 
01332 int BC_ListBox::get_from_column()
01333 {
01334         return dragged_title;
01335 }
01336 
01337 int BC_ListBox::get_to_column()
01338 {
01339         return highlighted_title;
01340 }
01341 
01342 
01343 BC_ListBoxItem* BC_ListBox::get_selection(int column, 
01344         int selection_number)
01345 {
01346         return get_selection_recursive(data,
01347                 column,
01348                 selection_number);
01349 }
01350 
01351 BC_ListBoxItem* BC_ListBox::get_selection_recursive(
01352         ArrayList<BC_ListBoxItem*> *data,
01353         int column,
01354         int selection_number)
01355 {
01356         if(!data) return 0;
01357 
01358         for(int i = 0; i < data[master_column].total; i++)
01359         {
01360                 BC_ListBoxItem *item = data[master_column].values[i];
01361                 if(item->selected)
01362                 {
01363                         selection_number--;
01364                         if(selection_number < 0)
01365                         {
01366 
01367                                 return data[column].values[i];
01368                         }
01369                 }
01370 
01371                 if(item->get_sublist())
01372                 {
01373                         BC_ListBoxItem *result = get_selection_recursive(item->get_sublist(),
01374                                 column,
01375                                 selection_number);
01376                         if(result) return result;
01377                 }
01378         }
01379         return 0;
01380 }
01381 
01382 
01383 int BC_ListBox::get_selection_number(int column, 
01384         int selection_number)
01385 {
01386         return get_selection_number_recursive(data,
01387                 column,
01388                 selection_number);
01389 }
01390 
01391 int BC_ListBox::get_selection_number_recursive(
01392         ArrayList<BC_ListBoxItem*> *data,
01393         int column,
01394         int selection_number,
01395         int *counter)
01396 {
01397         int temp = -1;
01398         if(!data) return 0;
01399         if(!counter) counter = &temp;
01400 
01401         for(int i = 0; i < data[master_column].total; i++)
01402         {
01403                 (*counter)++;
01404                 BC_ListBoxItem *item = data[master_column].values[i];
01405                 if(item->selected)
01406                 {
01407                         selection_number--;
01408                         if(selection_number < 0)
01409                         {
01410                                 return (*counter);
01411                         }
01412                 }
01413                 if(item->get_sublist())
01414                 {
01415                         int result = get_selection_number_recursive(
01416                                 item->get_sublist(),
01417                                 column,
01418                                 selection_number,
01419                                 counter);
01420                         if(result >= 0) return result;
01421                 }
01422         }
01423         return -1;
01424 }
01425 
01426 
01427 int BC_ListBox::set_selection_mode(int mode)
01428 {
01429         this->selection_mode = mode;
01430         return 0;
01431 }
01432 
01433 void BC_ListBox::delete_columns()
01434 {
01435         if(column_titles)
01436         {
01437                 for(int i = 0; i < columns; i++)
01438                 {
01439                         delete [] column_titles[i];
01440                 }
01441                 delete [] column_titles;
01442         }
01443 
01444         if(column_width) delete [] column_width;
01445         
01446         column_titles = 0;
01447         column_width = 0;
01448 }
01449 
01450 // Need to copy titles so EDL can change
01451 void BC_ListBox::set_columns(char **column_titles, 
01452         int *column_width, 
01453         int columns)
01454 {
01455         if((!column_titles && column_width) ||
01456                 (column_titles && !column_width))
01457         {
01458                 printf("BC_ListBox::set_columns either column_titles or column_width == NULL but not both.\n");
01459                 return;
01460         }
01461 
01462 
01463         delete_columns();
01464 
01465         if(column_titles)
01466         {
01467                 this->column_titles = new char*[columns];
01468                 for(int i = 0; i < columns; i++)
01469                 {
01470                         this->column_titles[i] = new char[strlen(column_titles[i]) + 1];
01471                         strcpy(this->column_titles[i], column_titles[i]);
01472                 }
01473         }
01474         
01475         if(column_width)
01476         {
01477                 this->column_width = new int[columns];
01478                 for(int i = 0; i < columns; i++)
01479                 {
01480                         this->column_width[i] = column_width[i];
01481                 }
01482         }
01483         
01484         this->columns = columns;
01485 
01486 }
01487 
01488 
01489 int BC_ListBox::update(ArrayList<BC_ListBoxItem*> *data,
01490         char **column_titles,
01491         int *column_widths,
01492         int columns,
01493         int xposition,
01494         int yposition, 
01495         int highlighted_number,
01496         int recalc_positions,
01497         int draw)
01498 {
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 
02752 // Pressed in button
02753         if(is_popup && top_level->event_win == win)
02754         {
02755                 current_operation = BUTTON_DN;
02756                 draw_button();
02757 
02758 // Deploy listbox
02759                 if(!active && !disabled)
02760                 {
02761                         top_level->deactivate();
02762                         activate();
02763                 }
02764 
02765                 result = 1;
02766         }
02767         else
02768 // Pressed in scrollbar
02769         if((xscrollbar && top_level->event_win == xscrollbar->win) ||
02770                 (yscrollbar && top_level->event_win == yscrollbar->win))
02771         {
02772                 result = 0;
02773         }
02774         else
02775 // Pressed in items
02776         if(gui && top_level->event_win == gui->win)
02777         {
02778 // Activate list items
02779                 if(!active)
02780                 {
02781                         top_level->deactivate();
02782                         activate();
02783                 }
02784 
02785 // Wheel mouse pressed
02786                 if(get_buttonpress() == 4 && current_operation == NO_OPERATION)
02787                 {
02788                         current_operation = WHEEL;
02789                         if(yscrollbar)
02790                         {
02791                                 set_yposition(yposition - gui->get_h() / 10, 0);
02792                                 clamp_positions();
02793                                 update_scrollbars();
02794                                 highlighted_ptr = 0;
02795                                 highlighted_item = get_cursor_item(data,
02796                                         top_level->cursor_x, 
02797                                         top_level->cursor_y, 
02798                                         &highlighted_ptr);
02799                                 draw_items(1);
02800                                 result = 1;
02801                         }
02802                 }
02803                 else
02804                 if(get_buttonpress() == 5 && current_operation == NO_OPERATION)
02805                 {
02806                         current_operation = WHEEL;
02807                         if(yscrollbar)
02808                         {
02809                                 set_yposition(yposition + gui->get_h() / 10, 0);
02810                                 clamp_positions();
02811                                 update_scrollbars();
02812                                 highlighted_ptr = 0;
02813                                 highlighted_item = get_cursor_item(data,
02814                                         top_level->cursor_x, 
02815                                         top_level->cursor_y,
02816                                         &highlighted_ptr);
02817                                 draw_items(1);
02818                                 result = 1;
02819                         }
02820                 }
02821                 else
02822 // Pressed over column title division
02823                 if(test_column_divisions(gui->get_cursor_x(), 
02824                         gui->get_cursor_y(), 
02825                         new_cursor))
02826                 {
02827                         current_operation = DRAG_DIVISION;
02828                         reset_query();
02829                 }
02830                 else
02831 // Pressed in column title
02832                 if(test_column_titles(gui->get_cursor_x(), gui->get_cursor_y()))
02833                 {
02834                         current_operation = COLUMN_DN;
02835                         button_highlighted = 0;
02836                         list_highlighted = 1;
02837                         draw_items(1);
02838                         result = 1;
02839                 }
02840                 else
02841 // Pressed in expander
02842                 if(test_expanders())
02843                 {
02844                         current_operation = EXPAND_DN;
02845 // Need to redraw items because of alpha
02846                         draw_items(1);
02847                         result = 1;
02848                 }
02849                 else
02850 // Pressed over item
02851                 if((selection_number = get_cursor_item(data, 
02852                                         gui->get_cursor_x(), 
02853                                         gui->get_cursor_y(),
02854                                         &current_item)) >= 0)
02855                 {
02856 // Get item button was pressed over
02857                         selection_number2 = selection_number1;
02858                         selection_number1 = selection_number;
02859 
02860                         selection_start = -1;
02861                         selection_end = -1;
02862 
02863 
02864 // Multiple item selection is possible
02865                         if(selection_mode == LISTBOX_MULTIPLE && 
02866                                 (ctrl_down() || shift_down()))
02867                         {
02868 // Expand text selection.
02869 // Fill items between selected region and current item.
02870                                 if(shift_down() && display_format == LISTBOX_TEXT)
02871                                 {
02872 // Get first item selected
02873                                         selection_start = get_first_selection(data);
02874 // Get last item selected
02875                                         selection_end = get_last_selection(data);
02876 // Get center of selected region
02877                                         if(selection_end > selection_start)
02878                                         {
02879                                                 selection_center = (selection_end + selection_start) >> 1;
02880                                         }
02881                                         else
02882                                         {
02883                                                 selection_center = selection_number;
02884                                         }
02885 
02886 
02887 // Deselect everything.
02888                                         set_all_selected(data, 0);
02889 // Select just the items
02890                                         expand_selection(1, selection_number);
02891                                         new_value = 1;
02892                                 }
02893                                 else
02894 // Toggle a single item on or off
02895                                 {
02896                                         toggle_item_selection(data, selection_number);
02897                                         new_value = current_item->selected;
02898                                 }
02899                         }
02900                         else
02901 // Select single item
02902                         {
02903                                 if(!current_item->selected)
02904                                 {
02905                                         set_all_selected(data, 0);
02906                                         set_selected(data,
02907                                                 selection_number,
02908                                                 1);
02909                                 }
02910                                 new_value = 1;
02911                         }
02912 
02913 
02914                         current_operation = SELECT;
02915                         highlighted_item = selection_number;
02916                         highlighted_ptr = current_item;
02917                         button_highlighted = 0;
02918                         list_highlighted = 1;
02919                         reset_query();
02920                         draw_items(1);
02921                         do_selection_change = 1;
02922                         result = 1;
02923                 }
02924                 else
02925                 if(data)
02926 // Pressed over nothing.  Start rectangle selection.
02927                 {
02928                         if(get_buttonpress() == 1 && 
02929                                 selection_mode == LISTBOX_MULTIPLE)
02930                         {
02931                                 if(!shift_down())
02932                                 {
02933 // Deselect all and redraw if anything was selected
02934                                         if(get_selection_number(0, 0) >= 0)
02935                                         {
02936                                                 set_all_selected(data, 0);
02937                                                 draw_items(1);
02938                                                 do_selection_change = 1;
02939                                                 result = 1;
02940                                         }
02941                                 }
02942                                 else
02943                                 {
02944 // Promote selections to protect from a rectangle selection
02945                                         promote_selections(data, 1, 2);
02946                                 }
02947 
02948 // Start rectangle selection
02949                                 current_operation = SELECT_RECT;
02950                                 rect_x1 = rect_x2 = get_cursor_x();
02951                                 rect_y1 = rect_y2 = get_cursor_y();
02952                         }
02953                 }
02954 
02955 
02956                 reset_query();
02957         }
02958         else
02959         if(is_popup && active)
02960         {
02961                 deactivate();
02962                 result = 1;
02963         }
02964 
02965 
02966         if(do_selection_change) selection_changed();
02967 
02968         return result;
02969 }
02970 
02971 int BC_ListBox::button_release_event()
02972 {
02973         int result = 0;
02974         int cursor_x, cursor_y;
02975         int do_event = 0;
02976         new_value = 0;
02977 
02978 //printf("BC_ListBox::button_release_event 1 %d\n", current_operation);
02979         switch(current_operation)
02980         {
02981                 case DRAG_DIVISION:
02982                         current_operation = NO_OPERATION;
02983                         result = 1;
02984                         break;
02985 
02986                 case WHEEL:
02987                         current_operation = NO_OPERATION;
02988                         result = 1;
02989                         break;
02990 
02991 // Release item selection
02992                 case BUTTON_DOWN_SELECT:
02993                 case SELECT:
02994 //printf("BC_ListBox::button_release_event 10\n");
02995                         unset_repeat(get_resources()->scroll_repeat);
02996                         current_operation = NO_OPERATION;
02997                         translate_coordinates(top_level->event_win,
02998                                 gui->win,
02999                                 gui->get_cursor_x(),
03000                                 gui->get_cursor_y(),
03001                                 &cursor_x,
03002                                 &cursor_y);
03003 
03004                         selection_number1 = 
03005                                 selection_number = 
03006                                 get_cursor_item(data, cursor_x, cursor_y);
03007 //printf("BC_ListBox::button_release_event %d %d\n", selection_number2, selection_number1);
03008 
03009                         if(is_popup)
03010                         {
03011                                 button_releases++;
03012                                 if(selection_number >= 0)
03013                                 {
03014                                         deactivate();
03015                                         do_event = 1;
03016                                 }
03017                                 else
03018 // Second button release outside button
03019                                 if(button_releases > 1)
03020                                 {
03021                                         deactivate();
03022                                 }
03023                         }
03024                         else
03025                         {
03026                                 if(top_level->get_double_click() &&
03027                                         selection_number2 == selection_number1 &&
03028                                         selection_number2 >= 0 &&
03029                                         selection_number1 >= 0)
03030                                 {
03031                                         do_event = 1;
03032                                 }
03033                                 result = 1;
03034                         }
03035                         break;
03036 
03037 
03038                 case SELECT_RECT:
03039                         unset_repeat(get_resources()->scroll_repeat);
03040                         if(data)
03041                         {
03042 // Demote selections from rectangle selection
03043                                 promote_selections(data, 2, 1);
03044                         }
03045 
03046 // Hide rectangle overlay
03047                         draw_rectangle(1);
03048                         current_operation = NO_OPERATION;
03049                         result = 1;
03050                         break;
03051 
03052 // Release popup button
03053                 case BUTTON_DN:
03054                         hide_tooltip();
03055                         current_operation = NO_OPERATION;
03056                         button_releases++;
03057                         draw_button();
03058 
03059 // Second button release inside button
03060                         if(button_releases > 1)
03061                         {
03062                                 deactivate();
03063                         }
03064                         result = 1;
03065                         break;
03066 
03067                 case COLUMN_DN:
03068                         current_operation = NO_OPERATION;
03069 // Update the sort column and the sort order for the user only if the existing
03070 // sort column is valid.
03071                         if(sort_column >= 0)
03072                         {
03073 // Invert order only if column is the same
03074                                 if(highlighted_title == sort_column)
03075                                         sort_order = 
03076                                                 (sort_order == SORT_ASCENDING) ? 
03077                                                 SORT_DESCENDING : 
03078                                                 SORT_ASCENDING;
03079 // Set the new sort column
03080                                 sort_column = highlighted_title;
03081                                 if(!sort_order_event())
03082                                 {
03083                                         draw_titles(1);
03084                                 }
03085                         }
03086                         else
03087 // Sorting not enabled.  Redraw the title state.
03088                         {
03089                                 draw_titles(1);
03090                         }
03091                         result = 1;
03092                         break;
03093 
03094                 case EXPAND_DN:
03095                 {
03096                         int redraw_toggles = 0;
03097                         for(int i = 0; i < expanders.total && !result; i++)
03098                         {
03099                                 if(expanders.values[i]->button_release_event(&redraw_toggles))
03100                                 {
03101                                         result = 1;
03102                                 }
03103                         }
03104 // Need to redraw items because of alpha
03105                         if(redraw_toggles) draw_items(1);
03106                         current_operation = NO_OPERATION;
03107                         break;
03108                 }
03109 
03110                 default:
03111 // Can't default to NO_OPERATION because it may be used in a drag event.
03112                         break;
03113         }
03114 
03115 
03116         if(do_event) handle_event();
03117 
03118         return result;
03119 }
03120 
03121 int BC_ListBox::get_title_h()
03122 {
03123         if(display_format == LISTBOX_TEXT)
03124                 return column_titles ? column_bg[0]->get_h() : 0;
03125         else
03126                 return 0;
03127 }
03128 
03129 void BC_ListBox::reset_cursor(int new_cursor)
03130 {
03131         if(is_popup)
03132         {
03133                 if(gui->get_cursor() != new_cursor)
03134                 {
03135                         gui->set_cursor(new_cursor);
03136                 }
03137         }
03138         else
03139         if(get_cursor() != new_cursor)
03140         {
03141                 set_cursor(new_cursor);
03142         }
03143 }
03144 
03145 int BC_ListBox::test_column_divisions(int cursor_x, int cursor_y, int &new_cursor)
03146 {
03147         if(gui &&
03148                 column_titles && 
03149                 cursor_y >= 0 && 
03150                 cursor_y < get_title_h() &&
03151                 cursor_x >= 0 &&
03152                 cursor_x < gui->get_w())
03153         {
03154                 for(int i = 1; i < columns; i++)
03155                 {
03156                         if(cursor_x >= -xposition + get_column_offset(i) - 5 &&
03157                                 cursor_x <  -xposition + get_column_offset(i) + 
03158                                         get_resources()->listbox_title_hotspot)
03159                         {
03160                                 highlighted_item = -1;
03161                                 highlighted_ptr = 0;
03162                                 highlighted_division = i;
03163                                 highlighted_title = -1;
03164                                 list_highlighted = 1;
03165                                 new_cursor = HSEPARATE_CURSOR;
03166                                 return 1;
03167                         }
03168                 }
03169         }
03170         highlighted_division = -1;
03171         return 0;
03172 }
03173 
03174 int BC_ListBox::test_column_titles(int cursor_x, int cursor_y)
03175 {
03176         if(gui &&
03177                 column_titles && 
03178                 cursor_y >= 0 && 
03179                 cursor_y < get_title_h() &&
03180                 cursor_x >= 0 && 
03181                 cursor_x < gui->get_w())
03182         {
03183                 for(int i = 0; i < columns; i++)
03184                 {
03185                         if(cursor_x >= -xposition + get_column_offset(i) &&
03186                                 (cursor_x < -xposition + get_column_offset(i + 1) ||
03187                                         i == columns - 1))
03188                         {
03189                                 highlighted_item = -1;
03190                                 highlighted_ptr = 0;
03191                                 highlighted_division = -1;
03192                                 highlighted_title = i;
03193                                 list_highlighted = 1;
03194                                 return 1;
03195                         }
03196                 }
03197         }
03198         highlighted_title = -1;
03199         return 0;
03200 }
03201 
03202 int BC_ListBox::test_expanders()
03203 {
03204         for(int i = 0; i < expanders.total; i++)
03205         {
03206                 if(expanders.values[i]->button_press_event())
03207                 {
03208                         current_operation = EXPAND_DN;
03209                         draw_toggles(1);
03210                         return 1;
03211                 }
03212         }
03213         return 0 ;
03214 }
03215 
03216 int BC_ListBox::cursor_motion_event()
03217 {
03218         int redraw = 0, result = 0;
03219         int new_cursor = ARROW_CURSOR;
03220 
03221         selection_number = -1;
03222 
03223 
03224         switch(current_operation)
03225         {
03226                 case BUTTON_DN:
03227 // Button pressed and slid off button
03228                         if(!cursor_inside())
03229                         {
03230                                 current_operation = BUTTON_DOWN_SELECT;
03231                                 draw_button();
03232                                 result = 1;
03233                         }
03234                         break;
03235 
03236                 case DRAG_DIVISION:
03237                 {
03238                         int new_w = get_cursor_x() + 
03239                                 xposition - 
03240                                 get_column_offset(highlighted_division - 1);
03241                         new_cursor = HSEPARATE_CURSOR;
03242 
03243                         if(column_width)
03244                         {
03245                                 column_width[highlighted_division - 1] = new_w;
03246                         }
03247                         else
03248                         {
03249                                 default_column_width[highlighted_division - 1] = new_w;
03250                         }
03251 
03252                         column_width_boundaries();
03253 
03254 // Force update of coords
03255                         set_autoplacement(data, 0, 1);
03256                         column_resize_event();
03257 
03258                         clamp_positions();
03259                         draw_items(1);
03260                         update_scrollbars();
03261                         result = 1;
03262                         break;
03263                 }
03264 
03265                 case SELECT_RECT:
03266                 {
03267                         if(test_drag_scroll(get_cursor_x(), get_cursor_y()))
03268                         {
03269                                 set_repeat(get_resources()->scroll_repeat);
03270                         }
03271 
03272                         int old_x1 = MIN(rect_x1, rect_x2);
03273                         int old_x2 = MAX(rect_x1, rect_x2);
03274                         int old_y1 = MIN(rect_y1, rect_y2);
03275                         int old_y2 = MAX(rect_y1, rect_y2);
03276 
03277                         int new_rect_x2 = get_cursor_x();
03278                         int new_rect_y2 = get_cursor_y();
03279 
03280                         int x1 = MIN(rect_x1, new_rect_x2);
03281                         int x2 = MAX(rect_x1, new_rect_x2);
03282                         int y1 = MIN(rect_y1, new_rect_y2);
03283                         int y2 = MAX(rect_y1, new_rect_y2);
03284 
03285 // Adjust rectangle coverage
03286                         if(old_x1 != x1 ||
03287                                 old_x2 != x2 ||
03288                                 old_y1 != y1 ||
03289                                 old_y2 != y2)
03290                         {
03291                                 if(data)
03292                                 {
03293                                         redraw = select_rectangle(data,
03294                                                 x1, 
03295                                                 y1,
03296                                                 x2, 
03297                                                 y2);
03298                                 }
03299 
03300 // hide rectangle
03301                                 if(!redraw)
03302                                         draw_rectangle(0);
03303                         }
03304 
03305                         rect_x2 = get_cursor_x();
03306                         rect_y2 = get_cursor_y();
03307                         if(redraw)
03308                         {
03309                                 clamp_positions();
03310                                 draw_items(1);
03311                                 update_scrollbars();
03312                                 selection_changed();
03313                         }
03314                         else
03315                         {
03316                                 draw_rectangle(1);
03317                         }
03318                         result = 1;
03319                         break;
03320                 }
03321 
03322                 case SELECT:
03323                 {
03324                         int old_highlighted_item = highlighted_item;
03325                         int old_highlighted_title = highlighted_title;
03326                         BC_ListBoxItem *old_highlighted_ptr = highlighted_ptr;
03327 
03328                         if(test_drag_scroll(get_cursor_x(), 
03329                                 get_cursor_y()))
03330                         {
03331                                 set_repeat(get_resources()->scroll_repeat);
03332                         }
03333 
03334 
03335                         highlighted_item = selection_number = get_cursor_item(data, 
03336                                 get_cursor_x(), 
03337                                 get_cursor_y(),
03338                                 &highlighted_ptr);
03339                         result = 1;
03340 
03341 // Deselect all items and select just the one we're over
03342                         if(selection_number >= 0 && 
03343                                 !allow_drag &&
03344                                 ((!shift_down() &&
03345                                         !ctrl_down()) ||
03346                                         selection_mode == LISTBOX_SINGLE))
03347                         {
03348                                 redraw = update_selection(data, selection_number);
03349                         }
03350                         else
03351                         if(selection_mode == LISTBOX_MULTIPLE &&
03352                                 (shift_down() || ctrl_down()))
03353 // Expand multiple selection
03354                         {
03355 // Expand selected region in text mode centered around initial range
03356                                 if(display_format == LISTBOX_TEXT && shift_down())
03357                                 {
03358 // Deselect everything.
03359                                         set_all_selected(data, 0);
03360 
03361 // Select just the items
03362                                         redraw = expand_selection(0, selection_number);
03363                                 }
03364                                 else
03365 // Set the one item we're over to the selection value determined in
03366 // button_press_event.
03367                                 {
03368                                         set_selected(data, 
03369                                                 selection_number, 
03370                                                 new_value);
03371                                 }
03372                         }
03373 
03374                         if(highlighted_item != old_highlighted_item)
03375                         {
03376                                 clamp_positions();
03377                                 draw_items(1);
03378                                 update_scrollbars();
03379 //printf("BC_ListBox::cursor_motion_event %d %d\n", highlighted_item, old_highlighted_item);
03380                                 selection_changed();
03381                         }
03382                         break;
03383                 }
03384 
03385                 case BUTTON_DOWN_SELECT:
03386 // Went back into button area
03387                         if(cursor_inside())
03388                         {
03389                                 current_operation = BUTTON_DN;
03390                                 draw_button();
03391                                 result = 1;
03392                         }
03393                         else
03394 // Went into item area
03395                         if(gui)
03396                         {
03397                                 int cursor_x = 0, cursor_y = 0;
03398                                 translate_coordinates(top_level->event_win, 
03399                                         gui->win,
03400                                         top_level->cursor_x,
03401                                         top_level->cursor_y,
03402                                         &cursor_x,
03403                                         &cursor_y);
03404                                 int old_highlighted_item = highlighted_item;
03405                                 highlighted_item = selection_number = get_cursor_item(data, 
03406                                                 cursor_x, 
03407                                                 cursor_y,
03408                                                 &highlighted_ptr);
03409 
03410                                 if(highlighted_item != old_highlighted_item)
03411                                 {
03412                                         update_selection(data, selection_number);
03413                                         draw_items(1);
03414                                         selection_changed();
03415                                 }
03416                         }
03417                         break;
03418 
03419                 case EXPAND_DN:
03420                 {
03421                         int redraw_toggles = 0;
03422                         for(int i = 0; i < expanders.total && !result; i++)
03423                         {
03424                                 result = expanders.values[i]->cursor_motion_event(
03425                                         &redraw_toggles);
03426                         }
03427                         if(redraw_toggles)
03428                         {
03429 // Need to redraw items because of the alpha
03430                                 draw_items(1);
03431                         }
03432                         break;
03433                 }
03434 
03435                 case NO_OPERATION:
03436                 {
03437                         int cursor_x = get_cursor_x(), cursor_y = get_cursor_y();
03438                         if(gui && top_level->event_win == gui->win)
03439                         {
03440                                 int old_highlighted_title = highlighted_title;
03441                                 int old_list_highlighted = list_highlighted;
03442                                 int old_highlighted_division = highlighted_division;
03443                                 int old_highlighted_item = highlighted_item;
03444                                 int redraw_titles = 0;
03445                                 int redraw_border = 0;
03446                                 int redraw_items = 0;
03447                                 int redraw_toggles = 0;
03448                                 result = 1;
03449 
03450 
03451 // Test if cursor moved over a title division
03452                                 test_column_divisions(cursor_x, cursor_y, new_cursor);
03453 
03454 // Test if cursor moved over a title
03455                                 if(highlighted_division < 0)
03456                                 {
03457                                         test_column_titles(cursor_x, cursor_y);
03458                                 }
03459 
03460 // Test if cursor moved over expander
03461                                 if(highlighted_division < 0 && 
03462                                         highlighted_title < 0 &&
03463                                         display_format == LISTBOX_TEXT)
03464                                 {
03465                                         for(int i = 0; i < expanders.total; i++)
03466                                         {
03467                                                 expanders.values[i]->cursor_motion_event(
03468                                                         &redraw_toggles);
03469                                         }
03470 //printf("BC_ListBox::cursor_motion_event %d\n", redraw_toggles);
03471                                 }
03472 
03473 // Test if cursor moved over an item
03474                                 if(highlighted_division < 0 && 
03475                                         highlighted_title < 0)
03476                                 {
03477                                         highlighted_item = get_cursor_item(data, 
03478                                                 cursor_x, 
03479                                                 cursor_y,
03480                                                 &highlighted_ptr);
03481                                 }
03482 
03483 
03484 // Clear title highlighting if moved over division
03485                                 if(old_highlighted_title != highlighted_title)
03486                                 {
03487                                         redraw_titles = 1;
03488                                 }
03489 
03490 // Highlight list border
03491                                 if(old_list_highlighted != list_highlighted)
03492                                 {
03493                                         redraw_border = 1;
03494                                 }
03495 
03496 // Moved out of item area
03497                                 if(old_highlighted_item != highlighted_item)
03498                                 {
03499                                         redraw_items = 1;
03500                                 }
03501 
03502 //printf("BC_ListBox::cursor_motion_event 1 %d\n", highlighted_item);
03503 
03504 // Change cursor to title division adjustment
03505                                 reset_cursor(new_cursor);
03506 
03507                                 if(redraw_items)
03508                                 {
03509                                         draw_items(0);
03510                                 }
03511                                 else
03512                                 {
03513                                         if(redraw_titles)
03514                                                 draw_titles(0);
03515                                         if(redraw_border)
03516                                                 draw_border(0);
03517                                         if(redraw_toggles)
03518                                                 draw_toggles(0);
03519                                 }
03520 
03521                                 if(redraw_items || 
03522                                         redraw_titles || 
03523                                         redraw_border || 
03524                                         redraw_toggles)
03525                                 {
03526                                         gui->flash();
03527                                         gui->flush();
03528                                 }
03529                         }
03530 
03531 
03532                         if(!result && list_highlighted)
03533                         {
03534                                 list_highlighted = 0;
03535                                 highlighted_item = -1;
03536                                 highlighted_ptr = 0;
03537                                 highlighted_title = -1;
03538                                 highlighted_division = -1;
03539                                 draw_items(1);
03540                                 result = 0;
03541                         }
03542                         break;
03543                 }
03544         }
03545 
03546 
03547         return result;
03548 }
03549 
03550 int BC_ListBox::drag_start_event()
03551 {
03552         switch(current_operation)
03553         {
03554                 case SELECT:
03555                         if(gui && 
03556                                 gui->is_event_win() && 
03557                                 allow_drag)
03558                         {
03559                                 BC_ListBoxItem *item_return = 0;
03560                                 selection_number = get_cursor_item(data, 
03561                                         top_level->cursor_x, 
03562                                         top_level->cursor_y,
03563                                         &item_return);
03564 
03565                                 if(selection_number >= 0)
03566                                 {
03567                                         
03568                                         if (item_return->icon_vframe)
03569                                         {
03570                                                 drag_popup = new BC_DragWindow(this, 
03571                                                         item_return->icon_vframe, 
03572                                                         get_abs_cursor_x(0) - item_return->icon_vframe->get_w() / 2,
03573                                                         get_abs_cursor_y(0) - item_return->icon_vframe->get_h() / 2);
03574                                         }
03575                                         else    
03576 // this probably works not!
03577                                         if (item_return->icon)  
03578                                                 drag_popup = new BC_DragWindow(this, 
03579                                                         item_return->icon, 
03580                                                         get_abs_cursor_x(0) - item_return->icon->get_w() / 2,
03581                                                         get_abs_cursor_y(0) - item_return->icon->get_h() / 2);
03582                                         else
03583                                                 drag_popup = new BC_DragWindow(this, 
03584                                                         drag_icon_vframe, 
03585                                                         get_abs_cursor_x(0) - drag_icon_vframe->get_w() / 2,
03586                                                         get_abs_cursor_y(0) - drag_icon_vframe->get_h() / 2);
03587                                         current_operation = DRAG_ITEM;
03588                                         return 1;
03589                                 }
03590                         }
03591                         break;
03592 
03593                 case COLUMN_DN:
03594                         if(gui && gui->is_event_win() && allow_drag_column)
03595                         {
03596                                 drag_popup = new BC_DragWindow(this, 
03597                                         drag_column_icon_vframe, 
03598                                         get_abs_cursor_x(0) - drag_column_icon_vframe->get_w() / 2,
03599                                         get_abs_cursor_y(0) - drag_column_icon_vframe->get_h() / 2);
03600                                 dragged_title = highlighted_title;
03601                                 current_operation = COLUMN_DRAG;
03602                                 draw_titles(1);
03603                                 return 1;
03604                         }
03605                         break;
03606         }
03607 
03608         return 0;
03609 }
03610 
03611 int BC_ListBox::drag_motion_event()
03612 {
03613 //printf("BC_ListBox::drag_motion_event 1 %d\n", current_operation);
03614         switch(current_operation)
03615         {
03616                 case DRAG_ITEM:
03617                 {
03618                         int redraw = 0;
03619 
03620                         int new_highlighted_item = -1;
03621                         BC_ListBoxItem *new_highlighted_ptr = 0;
03622                         int new_highlight = new_highlighted_item = get_cursor_item(data,
03623                                 top_level->cursor_x, 
03624                                 top_level->cursor_y,
03625                                 &new_highlighted_ptr);
03626 
03627                         if(new_highlighted_item != highlighted_item)
03628                         {
03629                                 redraw = 1;
03630                         }
03631 
03632 // Always update highlighted value for drag_stop
03633                         highlighted_item = new_highlighted_item;
03634                         highlighted_ptr = new_highlighted_ptr;
03635 //printf("BC_ListBox::drag_motion_event 1 %p\n", highlighted_ptr);
03636                         if(redraw)
03637                         {
03638                                 clamp_positions();
03639                                 draw_items(1);
03640                                 update_scrollbars();
03641                         }
03642 
03643                         return drag_popup->cursor_motion_event();
03644                         break;
03645                 }
03646 
03647                 case COLUMN_DRAG:
03648                 {
03649                         int old_highlighted_title = highlighted_title;
03650                         test_column_titles(get_cursor_x(), get_cursor_y());
03651                         if(old_highlighted_title != highlighted_title)
03652                         {
03653                                 draw_titles(1);
03654                         }
03655                         return drag_popup->cursor_motion_event();
03656                         break;
03657                 }
03658         }
03659         return 0;
03660 }
03661 
03662 int BC_ListBox::drag_stop_event()
03663 {
03664         switch(current_operation)
03665         {
03666                 case DRAG_ITEM:
03667 // Inside window boundary
03668                         if(top_level->cursor_x > 0 && 
03669                                 top_level->cursor_x < gui->get_w() - drag_popup->get_w() / 2 && 
03670                                 top_level->cursor_y > 0 &&
03671                                 top_level->cursor_y < gui->get_h() - drag_popup->get_h() / 2)
03672                         {
03673 // Move icon
03674 
03675 
03676                                 if(display_format == LISTBOX_ICONS)
03677                                 {
03678                                         reposition_item(data, 
03679                                                 selection_number, 
03680                                                 top_level->cursor_x + 
03681                                                         drag_popup->get_offset_x() - 
03682                                                         LISTBOX_MARGIN - 
03683                                                         2 + 
03684                                                         xposition,
03685                                                 top_level->cursor_y + 
03686                                                         drag_popup->get_offset_y() - 
03687                                                         LISTBOX_MARGIN - 
03688                                                         2 + 
03689                                                         yposition);
03690                                 }
03691                                 else
03692 // Move rows
03693                                 if(process_drag)
03694                                 {
03695 // Get destination
03696                                         int destination = highlighted_item = item_to_index(data,
03697                                                 highlighted_ptr);
03698 //printf("BC_ListBox::drag_stop_event 1 %p %d\n", highlighted_ptr, destination);
03699 
03700 // Move selected items from data to temporary
03701                                         ArrayList<BC_ListBoxItem*> *src_items = 
03702                                                 new ArrayList<BC_ListBoxItem*>[columns];
03703 
03704                                         move_selection(src_items, data);
03705 
03706 // Insert items from temporary to data
03707                                         put_selection(data,
03708                                                 src_items,
03709                                                 destination);
03710 
03711 
03712                                         delete [] src_items;                            
03713                                         set_autoplacement(data, 0, 1);
03714                                 }
03715 
03716                         
03717                                 draw_items(1);
03718                         }
03719                         else
03720                                 drag_popup->drag_failure_event();
03721 
03722                         delete drag_popup;
03723                         drag_popup = 0;
03724                         current_operation = NO_OPERATION;
03725                         new_value = 0;
03726                         return 1;
03727                         break;
03728 
03729                 case COLUMN_DRAG:
03730                         if(dragged_title != highlighted_title)
03731                         {
03732                                 if(highlighted_title >= 0)
03733                                 {
03734                                         if(!move_column_event()) draw_titles(1);
03735                                 }
03736                                 else
03737                                         drag_popup->drag_failure_event();
03738                         }
03739                         current_operation = NO_OPERATION;
03740                         delete drag_popup;
03741                         drag_popup = 0;
03742                         return 1;
03743                         break;
03744         }
03745         return 0;
03746 }
03747 
03748 BC_DragWindow* BC_ListBox::get_drag_popup()
03749 {
03750         return drag_popup;
03751 }
03752 
03753 int BC_ListBox::translation_event()
03754 {
03755         if(is_popup && gui)
03756         {
03757                 int new_x = gui->get_x() + 
03758                         (top_level->last_translate_x - 
03759                                 top_level->prev_x - 
03760                                 top_level->get_resources()->get_left_border());
03761                 int new_y = gui->get_y() + 
03762                         (top_level->last_translate_y - 
03763                                 top_level->prev_y -
03764                                 top_level->get_resources()->get_top_border());
03765 
03766                 gui->reposition_window(new_x, new_y);
03767                 
03768         }
03769         return 0;
03770 }
03771 
03772 int BC_ListBox::reposition_window(int x, int y, int w, int h)
03773 {
03774         if(w != -1)
03775         {
03776                 if(w != -1) popup_w = w;
03777                 if(h != -1) popup_h = h;
03778 //printf("BC_ListBox::reposition_window %d %d\n", popup_w, popup_h);
03779 
03780                 if(!is_popup)
03781                 {
03782                         if(w != -1) popup_w = w;
03783                         if(h != -1) popup_h = h;
03784                         if(xscrollbar)
03785                                 xscrollbar->reposition_window(get_xscroll_x(), 
03786                                         get_xscroll_y(), 
03787                                         get_xscroll_width());
03788                         if(yscrollbar)
03789                                 yscrollbar->reposition_window(get_yscroll_x(), 
03790                                         get_yscroll_y(), 
03791                                         get_yscroll_height());
03792                 }
03793         }
03794 
03795 
03796         BC_WindowBase::reposition_window(x, y, w, h);
03797         draw_button();
03798         draw_items(1);
03799         return 0;
03800 }
03801 
03802 int BC_ListBox::deactivate()
03803 {
03804         if(active)
03805         {
03806                 active = 0;
03807                 if(is_popup)
03808                 {
03809                         if(gui) delete gui;
03810                         xscrollbar = 0;
03811                         yscrollbar = 0;
03812                         gui = 0;
03813                         highlighted_item = -1;
03814                         highlighted_ptr = 0;
03815                 }
03816                 top_level->active_subwindow = 0;
03817         }
03818         return 0;
03819 }
03820 
03821 int BC_ListBox::activate()
03822 {
03823         if(!active)
03824         {
03825                 top_level->active_subwindow = this;
03826                 active = 1;
03827                 button_releases = 0;
03828 
03829                 if(is_popup)
03830                 {
03831                         Window tempwin;
03832                         int x, y;
03833                         int new_x, new_y;
03834                         y = get_y() + get_h();
03835                         if(justify == LISTBOX_RIGHT)
03836                         {
03837                                 x = get_x() - popup_w + get_w();
03838                         }
03839                         else
03840                         {
03841                                 x = get_x();
03842                         }
03843 
03844                         
03845                         XTranslateCoordinates(top_level->display, 
03846                                 parent_window->win, 
03847                                 top_level->rootwin, 
03848                                 x, 
03849                                 y, 
03850                                 &new_x, 
03851                                 &new_y, 
03852                                 &tempwin);
03853 
03854                         if(new_x < 0) new_x = 0;
03855                         if(new_y + popup_h > top_level->get_root_h(0)) 
03856                                 new_y -= get_h() + popup_h;
03857 
03858 //printf("BC_ListBox::activate %d %d\n", popup_w, popup_h);
03859                         add_subwindow(gui = new BC_Popup(this, 
03860                                 new_x, 
03861                                 new_y, 
03862                                 popup_w, 
03863                                 popup_h, 
03864                                 -1,
03865                                 0,
03866                                 0));
03867                         draw_items(1);
03868                 }
03869         }
03870         return 0;
03871 }
03872 
03873 int BC_ListBox::keypress_event()
03874 {
03875         if(!active) return 0;
03876         
03877         int result = 0, redraw = 0, done, view_items = view_h / get_text_height(MEDIUMFONT);
03878         int new_item = -1, new_selection = 0;
03879 
03880         switch(top_level->get_keypress())
03881         {
03882                 case ESC:
03883                 case RETURN:
03884                         top_level->deactivate();
03885                         result = 0;
03886                         break;
03887 
03888                 case UP:
03889                         new_selection = new_item = select_previous(0);
03890 
03891 //printf("BC_ListBox::keypress_event 1 %d\n", new_item);
03892                         if(new_item >= 0)
03893                         {
03894                                 center_selection(new_item);
03895                                 redraw = 1;
03896                         }
03897                         result = 1;
03898                         break;
03899 
03900                 case DOWN:
03901                         new_selection = new_item = select_next(0);
03902 
03903                         if(new_item >= 0)
03904                         {
03905                                 center_selection(new_item);
03906                                 redraw = 1;
03907                         }
03908                         result = 1;
03909                         break;
03910 
03911                 case PGUP:
03912                         new_selection = new_item = select_previous(view_items - 1);
03913 
03914                         if(new_item >= 0)
03915                         {
03916                                 center_selection(new_item);
03917                                 redraw = 1;
03918                         }
03919                         result = 1;
03920                         break;
03921 
03922                 case PGDN:
03923                         new_selection = new_item = select_next(view_items - 1);
03924 
03925                         if(new_item >= 0)
03926                         {
03927                                 center_selection(new_item);
03928                                 redraw = 1;
03929                         }
03930                         result = 1;
03931                         break;
03932 
03933                 case LEFT:
03934                         xposition -= 10;
03935                         redraw = 1;
03936                         result = 1;
03937                         break;
03938 
03939                 case RIGHT:
03940                         xposition += 10;
03941                         redraw = 1;
03942                         result = 1;
03943                         break;
03944 
03945                 default:
03946                         if(!ctrl_down())
03947                         {
03948                                 if(top_level->get_keypress() > 30 && 
03949                                         top_level->get_keypress() < 127)
03950                                 {
03951                                         int query_len = strlen(query);
03952                                         query[query_len++] = top_level->get_keypress();
03953                                         query[query_len] = 0;
03954                                         new_selection = query_list();
03955                                 }
03956                                 else
03957                                 if(top_level->get_keypress() == BACKSPACE)
03958                                 {
03959                                         int query_len = strlen(query);
03960                                         if(query_len > 0) query[--query_len] = 0;
03961                                         new_selection = query_list();
03962                                 }
03963 
03964                                 redraw = 1;
03965                                 result = 1;
03966                         }
03967                         break;
03968         }
03969 
03970         if(redraw)
03971         {
03972                 clamp_positions();
03973                 draw_items(1);
03974                 update_scrollbars();
03975         }
03976         
03977         if(new_selection >= 0)
03978         {
03979                 selection_changed();
03980         }
03981 
03982         return result;
03983 }
03984 
03985 
03986 BC_Pixmap* BC_ListBox::get_bg_surface()
03987 {
03988         return bg_surface;
03989 }
03990 
03991 
03992 void BC_ListBox::draw_background()
03993 {
03994 // White background pixmap
03995         set_color(top_level->get_resources()->listbox_inactive);
03996         draw_box(0, 0, bg_surface->get_w(), bg_surface->get_h(), bg_surface);
03997 
03998 // Optional heroine pixmap
03999         if(bg_pixmap)
04000                 bg_surface->draw_pixmap(bg_pixmap,
04001                         bg_surface->get_w() - top_level->get_resources()->listbox_bg->get_w(),
04002                         0);
04003 }
04004 
04005 void BC_ListBox::clear_listbox(int x, int y, int w, int h)
04006 {
04007         gui->draw_pixmap(bg_surface, 
04008                 x, 
04009                 y, 
04010                 w, 
04011                 h,
04012                 x,
04013                 y - title_h);
04014 }
04015 
04016 void BC_ListBox::update_format(int display_format, int redraw)
04017 {
04018         this->display_format = display_format;
04019         if(redraw)
04020         {
04021                 if(gui) draw_items(1);
04022         }
04023 }
04024 
04025 int BC_ListBox::get_format()
04026 {
04027         return display_format;
04028 }
04029 
04030 
04031 
04032 int BC_ListBox::draw_items(int flash)
04033 {
04034         if(gui)
04035         {
04036                 BC_Resources *resources = get_resources();
04037 
04038 //dump(data, columns);
04039 
04040 // Calculate items width 
04041                 calculate_item_coords();
04042 
04043 
04044 // Create and destroy scrollbars as needed
04045                 get_scrollbars();
04046 
04047 
04048 
04049 //              draw_background();
04050 
04051 // Icon display
04052                 if(display_format == LISTBOX_ICONS)
04053                 {
04054                         clear_listbox(2, 2 + title_h, view_w, view_h);
04055 
04056                         set_font(MEDIUMFONT);
04057                         for(int i = 0; i < data[master_column].total; i++)
04058                         {
04059                                 BC_ListBoxItem *item = data[master_column].values[i];
04060                                 if(get_item_x(item) >= -get_item_w(item) && 
04061                                         get_item_x(item) < view_w &&
04062                                         get_item_y(item) >= -get_item_h(item) + title_h &&
04063                                         get_item_y(item) < view_h + title_h)
04064                                 {
04065                                         int item_color = get_item_highlight(data, 0, i);
04066                                         int icon_x, icon_y, icon_w, icon_h;
04067                                         int text_x, text_y, text_w, text_h;
04068 
04069 // Draw highlights
04070                                         get_icon_mask(item, icon_x, icon_y, icon_w, icon_h);
04071                                         get_text_mask(item, text_x, text_y, text_w, text_h);
04072 
04073 
04074                                         if(item_color != resources->listbox_inactive)
04075                                         {
04076                                                 gui->set_color(BLACK);
04077                                                 gui->draw_rectangle(icon_x, icon_y, icon_w, icon_h);
04078                                                 gui->set_color(item_color);
04079                                                 gui->draw_box(icon_x + 1, icon_y + 1, icon_w - 2, icon_h - 2);
04080                                                 gui->set_color(BLACK);
04081                                                 gui->draw_rectangle(text_x, text_y, text_w, text_h);
04082                                                 gui->set_color(item_color);
04083                                                 gui->draw_box(text_x + 1, text_y + 1, text_w - 2, text_h - 2);
04084 
04085                                                 if(icon_position == ICON_LEFT)
04086                                                         gui->draw_box(text_x - 1, text_y + 1, 2, text_h - 2);
04087                                                 else
04088                                                 if(icon_position == ICON_TOP)
04089                                                         gui->draw_line(text_x + 1, text_y, text_x + icon_w - 2, text_y);
04090                                                 if(text_x + text_w < icon_x + icon_w)
04091                                                 {
04092                                                         gui->set_color(BLACK);
04093                                                         gui->draw_line(text_x + text_w, 
04094                                                                 icon_y + icon_h,
04095                                                                 icon_x + icon_w,
04096                                                                 icon_y + icon_h);
04097                                                 }
04098                                         }
04099 
04100 // Draw icons
04101                                         gui->set_color(get_item_color(data, 0, i));
04102                                         if(item->icon)
04103                                                 item->icon->write_drawable(gui->pixmap, 
04104                                                         icon_x + ICON_MARGIN, 
04105                                                         icon_y + ICON_MARGIN);
04106                                         gui->draw_text(text_x + ICON_MARGIN, 
04107                                                 text_y + ICON_MARGIN + get_text_ascent(MEDIUMFONT), 
04108                                                 item->text);
04109                                 }
04110                         }
04111                 }
04112                 else
04113 // Text display
04114                 if(display_format == LISTBOX_TEXT)
04115                 {
04116 // Draw one column at a time so text overruns don't go into the next column
04117 // clear column backgrounds
04118                         int current_toggle = 0;
04119                         for(int j = 0; j < columns; j++)
04120                         {
04121                                 clear_listbox(LISTBOX_BORDER + get_column_offset(j) - xposition, 
04122                                         LISTBOX_BORDER + title_h, 
04123                                         get_column_width(j, 1), 
04124                                         view_h);
04125 
04126 // Draw rows in the column recursively
04127                                 draw_text_recursive(data, j, 0, &current_toggle);
04128                         }
04129 
04130 // Delete excess expanders
04131                         while(expanders.total > current_toggle)
04132                         {
04133                                 expanders.remove_object();
04134                         }
04135                 }
04136 
04137 // Draw titles on top of rows for superposition effect
04138                 draw_titles(0);
04139 
04140 // Clear garbage from bottom right corner
04141                 if(xscrollbar && yscrollbar && is_popup)
04142                 {
04143                         gui->draw_top_background(parent_window, 
04144                                 popup_w - get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w(), 
04145                                 popup_h - get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h(), 
04146                                 get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w(),
04147                                 get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h());
04148                 }
04149 
04150 // Draw borders
04151                 draw_border(0);
04152 
04153 
04154                 if(current_operation == SELECT_RECT)
04155                         draw_rectangle(0);
04156 
04157                 if(flash)
04158                 {
04159                         gui->flash();
04160                         gui->flush();
04161                 }
04162         }
04163 
04164         return 0;
04165 }
04166 
04167 
04168 void BC_ListBox::draw_text_recursive(ArrayList<BC_ListBoxItem*> *data, 
04169         int column,
04170         int indent,
04171         int *current_toggle)
04172 {
04173         if(!data) return;
04174 
04175 
04176         BC_Resources *resources = get_resources();
04177 
04178         set_font(MEDIUMFONT);
04179         int subindent = 0;
04180 
04181 // Search for a branch and make room for toggle if there is one
04182         if(column == 0)
04183         {
04184                 for(int i = 0; i < data[column].total; i++)
04185                 {
04186                         if(data[column].values[i]->get_sublist())
04187                         {
04188                                 subindent = BC_WindowBase::get_resources()->listbox_expand[0]->get_w();
04189                                 break;
04190                         }
04191                 }
04192         }
04193 
04194         for(int i = 0; i < data[column].total; i++)
04195         {
04196 // Draw a row
04197                 BC_ListBoxItem *item = data[column].values[i];
04198                 BC_ListBoxItem *first_item = data[master_column].values[i];
04199 
04200                 if(get_item_y(item) >= -get_item_h(item) + title_h &&
04201                         get_item_y(item) < view_h + title_h)
04202                 {
04203                         int row_color = get_item_highlight(data, 0, i);
04204                         int x, y, w, h, column_width;
04205 
04206                         get_text_mask(item, x, y, w, h);
04207                         column_width = get_column_width(column, 1);
04208                         if(x + column_width > view_w + LISTBOX_BORDER * 2)
04209                                 column_width = view_w + LISTBOX_BORDER * 2 - x;
04210 
04211                         if(row_color != resources->listbox_inactive)
04212                         {
04213                                 gui->set_color(row_color);
04214                                 gui->draw_box(x, 
04215                                         y, 
04216                                         column_width, 
04217                                         h);
04218                                 gui->set_color(BLACK);
04219                                 gui->draw_line(x, 
04220                                         y, 
04221                                         x + column_width - 1, 
04222                                         y);
04223                                 gui->draw_line(x, 
04224                                         y + get_text_height(MEDIUMFONT), 
04225                                         x + column_width - 1, 
04226                                         y + get_text_height(MEDIUMFONT));
04227                         }
04228 
04229                         gui->set_color(get_item_color(data, column, i));
04230 
04231 
04232 // Indent only applies to first column
04233                         gui->draw_text(
04234                                 x + 
04235                                         LISTBOX_BORDER + 
04236                                         LISTBOX_MARGIN + 
04237                                         (column == 0 ? indent + subindent : 0), 
04238                                 y + get_text_ascent(MEDIUMFONT), 
04239                                 item->text);
04240 
04241 
04242 // Update expander
04243                         if(column == 0 &&
04244                                 item->get_sublist() && 
04245                                 item->get_columns())
04246                         {
04247 // Create new expander
04248                                 if(*current_toggle >= expanders.total)
04249                                 {
04250                                         BC_ListBoxToggle *toggle = 
04251                                                 new BC_ListBoxToggle(this, 
04252                                                         item, 
04253                                                         x + LISTBOX_BORDER + LISTBOX_MARGIN + indent,
04254                                                         y);
04255                                         toggle->draw(0);
04256                                         expanders.append(toggle);
04257                                 }
04258                                 else
04259 // Reposition existing expander
04260                                 {
04261                                         BC_ListBoxToggle *toggle = expanders.values[*current_toggle];
04262 //printf("BC_ListBox::draw_text_recursive 1 %d\n", *current_toggle);
04263                                         toggle->update(item, 
04264                                                 x + LISTBOX_BORDER + LISTBOX_MARGIN + indent,
04265                                                 y,
04266                                                 0);
04267                                 }
04268                                 (*current_toggle)++;
04269                         }
04270 
04271 
04272 
04273                 }
04274 
04275 // Descend into sublist
04276                 if(first_item->get_expand())
04277                 {
04278                         draw_text_recursive(first_item->get_sublist(), 
04279                                 column, 
04280                                 indent + LISTBOX_INDENT, 
04281                                 current_toggle);
04282                 }
04283         }
04284 }
04285 
04286 
04287 
04288 
04289 
04290 int BC_ListBox::draw_border(int flash)
04291 {
04292         BC_Resources *resources = top_level->get_resources();
04293         gui->draw_3d_border(0, 
04294                 0, 
04295                 view_w + LISTBOX_BORDER * 2, 
04296                 view_h + title_h + LISTBOX_BORDER * 2, 
04297                 resources->listbox_border1, 
04298                 list_highlighted ? 
04299                         resources->listbox_border2_hi : 
04300                         resources->listbox_border2, 
04301                 list_highlighted ? 
04302                         resources->listbox_border3_hi : 
04303                         resources->listbox_border3, 
04304                 resources->listbox_border4);
04305 
04306         if(flash)
04307         {
04308                 gui->flash();
04309                 gui->flush();
04310         }
04311         return 0;
04312 }
04313 
04314 int BC_ListBox::draw_titles(int flash)
04315 {
04316         if(column_titles && display_format == LISTBOX_TEXT)
04317         {
04318 //printf("BC_ListBox::draw_titles 1 %d\n", highlighted_title);
04319                 for(int i = 0; i < columns; i++)
04320                 {
04321 
04322 
04323 // Column title background
04324                         int image_number = 0;
04325                         if(i == highlighted_title)
04326                         {
04327                                 image_number = 1;
04328                                 if(current_operation == COLUMN_DN)
04329                                         image_number = 2;
04330                         }
04331 
04332                         int column_offset = get_column_offset(i) - xposition + LISTBOX_BORDER;
04333                         int column_width = get_column_width(i, 1);
04334                         gui->draw_3segmenth(get_column_offset(i) - xposition + LISTBOX_BORDER,
04335                                 LISTBOX_BORDER,
04336                                 get_column_width(i, 1),
04337                                 column_bg[image_number]);
04338 
04339 // Column title sort order
04340                         if(i == sort_column)
04341                         {
04342                                 BC_Pixmap *src;
04343                                 if(sort_order == SORT_ASCENDING) 
04344                                         src = column_sort_dn;
04345                                 else
04346                                         src = column_sort_up;
04347 
04348                                 int x = column_offset + 
04349                                         column_width - 
04350                                         LISTBOX_BORDER;
04351                                 if(x > items_w) x = items_w;
04352                                 x -= 5 + src->get_w();
04353                                 gui->draw_pixmap(src,
04354                                         x,
04355                                         title_h / 2 - src->get_h() / 2 + LISTBOX_BORDER);
04356                         }
04357 
04358 
04359                         int x = -xposition + 
04360                                 get_column_offset(i) + 
04361                                 LISTBOX_MARGIN + 
04362                                 LISTBOX_BORDER;
04363                         x += get_resources()->listbox_title_margin;
04364 
04365                         gui->set_color(get_resources()->listbox_title_color);
04366                         gui->draw_text(x, 
04367                                 LISTBOX_MARGIN + LISTBOX_BORDER + get_text_ascent(MEDIUMFONT), 
04368                                 _(column_titles[i]));
04369                 }
04370                 draw_border(0);
04371         }
04372 
04373         if(flash)
04374         {
04375                 gui->flash();
04376                 gui->flush();
04377         }
04378 }
04379 
04380 void BC_ListBox::draw_toggles(int flash)
04381 {
04382         for(int i = 0; i < expanders.total; i++)
04383                 expanders.values[i]->draw(0);
04384 
04385 //printf("BC_ListBox::draw_toggles 1 %d\n", flash);
04386         if(flash && expanders.total)
04387         {
04388                 gui->flash();
04389                 gui->flush();
04390         }
04391 }
04392 
04393 int BC_ListBox::draw_rectangle(int flash)
04394 {
04395         int x1 = MIN(rect_x1, rect_x2);
04396         int x2 = MAX(rect_x1, rect_x2);
04397         int y1 = MIN(rect_y1, rect_y2);
04398         int y2 = MAX(rect_y1, rect_y2);
04399 
04400         if(x1 == x2 || y1 == y2) return 0;
04401 
04402         gui->set_inverse();
04403         gui->set_color(WHITE);
04404         gui->draw_rectangle(x1, y1, x2 - x1, y2 - y1);
04405         gui->set_opaque();
04406 
04407 
04408         if(flash)
04409         {
04410                 gui->flash();
04411                 gui->flush();
04412         }
04413         return 0;
04414 }
04415 
04416 void BC_ListBox::dump(ArrayList<BC_ListBoxItem*> *data, 
04417         int columns, 
04418         int indent,
04419         int master_column)
04420 {
04421         if(!indent)
04422         {
04423                 printf("BC_ListBox::dump 1\n");
04424         }
04425 
04426         for(int i = 0; i < data[master_column].total; i++)
04427         {
04428                 for(int k = 0; k < indent; k++)
04429                         printf(" ");
04430                 for(int j = 0; j < columns; j++)
04431                 {
04432                         BC_ListBoxItem *item = data[j].values[i];
04433                         printf("%d,%d,%d=%s ", 
04434                                 item->get_text_x(), 
04435                                 item->get_text_y(),
04436                                 item->autoplace_text, 
04437                                 item->get_text());
04438                 }
04439                 printf("\n");
04440 
04441                 if(data[master_column].values[i]->get_sublist())
04442                 {
04443                         dump(data[master_column].values[i]->get_sublist(),
04444                                 data[master_column].values[i]->get_columns(),
04445                                 indent + 4,
04446                                 master_column);
04447                 }
04448         }
04449 
04450         
04451 }
04452 
04453 
04454 
04455 

Generated on Sun Jan 8 13:26:32 2006 for Guicast-svn by  doxygen 1.4.4