home *** CD-ROM | disk | FTP | other *** search
/ Geek 6 / Geek-006.iso / linux / video / xmovie-1.5.3.tar.gz / xmovie-1.5.3.tar / xmovie-1.5.3 / guicast / bclistbox.C < prev    next >
C/C++ Source or Header  |  2000-11-29  |  35KB  |  1,811 lines

  1. #include "bcdragwindow.h"
  2. #include "bclistbox.h"
  3. #include "bcpixmap.h"
  4. #include "bcresources.h"
  5. #include "fonts.h"
  6. #include "keys.h"
  7. #include <string.h>
  8.  
  9. // ====================================================== item
  10.  
  11. BC_ListBoxItem::BC_ListBoxItem()
  12. {
  13.     initialize();
  14. }
  15.  
  16. BC_ListBoxItem::BC_ListBoxItem(int x, 
  17.     int y, 
  18.     char *text, 
  19.     BC_Pixmap *icon, 
  20.     int color = BLACK)
  21. {
  22.     initialize();
  23.     this->x = x;
  24.     this->y = y;
  25.     this->text = new char[strlen(text) + 1];
  26.     this->icon = icon;
  27.  
  28.     strcpy(this->text, text);
  29.     this->color = color;
  30. }
  31.  
  32. BC_ListBoxItem::BC_ListBoxItem(char *text, int color)
  33. {
  34.     initialize();
  35.     this->text = new char[strlen(text) + 1];
  36.     strcpy(this->text, text);
  37.     this->color = color;
  38. }
  39.  
  40. BC_ListBoxItem::~BC_ListBoxItem()
  41. {
  42.     if(text) delete text;
  43. }
  44.  
  45. int BC_ListBoxItem::initialize()
  46. {
  47.     text = 0;
  48.     color = BLACK;
  49.     selected = 0;
  50.     icon = 0;
  51.     y = 0;
  52.     x = 0;
  53.     return 0;
  54. }
  55.  
  56. int BC_ListBoxItem::get_x()
  57. {
  58.     return x;
  59. }
  60.  
  61. int BC_ListBoxItem::get_y()
  62. {
  63.     return y;
  64. }
  65.  
  66. int BC_ListBoxItem::get_icon_w()
  67. {
  68.     return icon->get_w();
  69. }
  70.  
  71. int BC_ListBoxItem::get_icon_h()
  72. {
  73.     return icon->get_h();
  74. }
  75.  
  76. void BC_ListBoxItem::set_text(char *new_text)
  77. {
  78.     if(this->text) delete this->text;
  79.     this->text = 0;
  80.  
  81.     if(new_text)
  82.     {
  83.         this->text = new char[strlen(new_text) + 1];
  84.         strcpy(this->text, new_text);
  85.     }
  86. }
  87.  
  88. char* BC_ListBoxItem::get_text()
  89. {
  90.     return text;
  91. }
  92.  
  93. BC_ListBoxItem& BC_ListBoxItem::operator=(BC_ListBoxItem& item)
  94. {
  95.     if(item.text) set_text(item.text);
  96.     color = item.color;
  97.     y = item.y;
  98.     return *this;
  99. }
  100.  
  101.  
  102. // ====================================================== scrollbars
  103.  
  104.  
  105. BC_ListBoxYScroll::BC_ListBoxYScroll(BC_ListBox *listbox, 
  106.                       int total_height, 
  107.                       int view_height, 
  108.                       int position)
  109.  : BC_ScrollBar(listbox->get_yscroll_x(), listbox->get_yscroll_y(), SCROLL_VERT, 
  110.      listbox->get_yscroll_height(), total_height, position, view_height)
  111. {
  112.     this->listbox = listbox;
  113. }
  114.  
  115. int BC_ListBoxYScroll::handle_event()
  116. {
  117.     listbox->set_yposition(get_value());
  118.     return 1;
  119. }
  120.  
  121. BC_ListBoxXScroll::BC_ListBoxXScroll(BC_ListBox *listbox, 
  122.                       int total_width, 
  123.                       int view_width,
  124.                       int position)
  125.  : BC_ScrollBar(listbox->get_xscroll_x(), listbox->get_xscroll_y(), SCROLL_HORIZ, 
  126.      listbox->get_xscroll_width(), total_width, position, view_width)
  127. {
  128.     this->listbox = listbox;
  129. }
  130.  
  131. int BC_ListBoxXScroll::handle_event()
  132. {
  133.     listbox->set_xposition(get_value());
  134.     return 1;
  135. }
  136.  
  137.  
  138. // ====================================================== box
  139.  
  140. BC_ListBox::BC_ListBox(int x, int y, int w, int h,
  141.         int display_format,
  142.         ArrayList<BC_ListBoxItem*> *data,
  143.         char **column_titles,
  144.         int *column_width,
  145.         int columns,
  146.         int yposition,
  147.         int popup,
  148.         int selection_mode,
  149.         int icon_position,
  150.         int assign_icon_coords,
  151.         int allow_drag)
  152.  : BC_SubWindow(x, y, w, h, -1)
  153. {
  154.     this->data = data;
  155.     this->column_titles = column_titles;
  156.     this->columns = columns;
  157.     this->yposition = yposition;
  158.     this->column_width = column_width;
  159.     this->popup = popup;
  160.     this->display_format = display_format;
  161.     this->selection_mode = selection_mode;
  162.     this->icon_position = icon_position;
  163.     this->assign_icon_coords = assign_icon_coords;
  164.     this->allow_drag = allow_drag;
  165.     popup_w = w;
  166.     popup_h = h;
  167.  
  168.     xposition = 0;
  169.     highlighted_item = -1;
  170.     highlighted = 0;
  171.     xscrollbar = 0;
  172.     yscrollbar = 0;
  173.     gui = 0;
  174.     view_h = 0;
  175.     view_w = 0;
  176.     title_h = 0;
  177.     selection_active = 0;
  178.     active = 0;
  179.     new_value = 0;
  180.     need_xscroll = 0;
  181.     need_yscroll = 0;
  182.     bg_tile = 0;
  183.     drag_popup = 0;
  184.     last_selection1 = last_selection2 = 0;
  185. // reset the search engine
  186.     reset_query();
  187. }
  188.  
  189. BC_ListBox::~BC_ListBox()
  190. {
  191.     if(xscrollbar) delete xscrollbar;
  192.     if(yscrollbar) delete yscrollbar;
  193.     if(popup)
  194.     {
  195.         delete images[0];
  196.         delete images[1];
  197.         delete images[2];
  198.     }
  199. }
  200.  
  201. void BC_ListBox::reset_query()
  202. {
  203.     query[0] = 0;  // reset query
  204. }
  205.  
  206. void BC_ListBox::query_list()
  207. {
  208.     if(query[0] == 0) return;
  209.  
  210.     int done = 0, result;
  211.     for(int i = 0; !done && i < data[0].total; i++)
  212.     {
  213.         if(strcmp(query, data[0].values[i]->text) <= 0)
  214.         {
  215.             result = i;
  216.             done = 1;
  217.         }
  218.     }
  219.  
  220.     if(done)
  221.     {
  222.         for(int i = 0; i < data[0].total; i++)
  223.         {
  224.             for(int j = 0; j < columns; j++)
  225.             {
  226.                 data[j].values[i]->selected = 0;
  227.             }
  228.         }
  229.  
  230.         for(int j = 0; j < columns; j++)
  231.         {
  232.             data[j].values[result]->selected = 1;
  233.         }
  234.         center_selection(result);
  235.     }
  236. }
  237.  
  238. void BC_ListBox::init_column_width()
  239. {
  240.     if(!column_width && data)
  241.     {
  242.         int widest = 5, w;
  243.         for(int i = 0; i < data[0].total; i++)
  244.         {
  245.             w = get_text_width(MEDIUMFONT, data[0].values[i]->get_text()) + 2 * LISTBOX_MARGIN;
  246.             if(w > widest) widest = w;
  247.         }
  248. //        if(widest < popup_w - 4) widest = popup_w - 4;
  249.         default_column_width[0] = widest;
  250.         column_width = default_column_width;
  251.     }
  252. }
  253.  
  254. int BC_ListBox::initialize()
  255. {
  256.     if(popup)
  257.     {
  258.         images[0] = new BC_Pixmap(parent_window, BC_WindowBase::get_resources()->listbox_button[0], PIXMAP_ALPHA);
  259.         images[1] = new BC_Pixmap(parent_window, BC_WindowBase::get_resources()->listbox_button[1], PIXMAP_ALPHA);
  260.         images[2] = new BC_Pixmap(parent_window, BC_WindowBase::get_resources()->listbox_button[2], PIXMAP_ALPHA);
  261.         w = images[0]->get_w();
  262.         h = images[0]->get_h();
  263.         gui = 0;
  264.         status = LISTBOX_UP;
  265.     }
  266.     else
  267.     {
  268.         gui = this;
  269.     }
  270.  
  271.     BC_SubWindow::initialize();
  272.  
  273.     init_column_width();
  274.  
  275.     if(assign_icon_coords) set_item_coords();
  276.  
  277.     if(top_level->get_resources()->listbox_bg)
  278.         bg_pixmap = new BC_Pixmap(this, 
  279.             get_resources()->listbox_bg, 
  280.             PIXMAP_OPAQUE);
  281.  
  282.     draw_face();
  283.     draw_items();
  284.     if(!popup) gui->flash();
  285.     return 0;
  286. }
  287.  
  288. int BC_ListBox::draw_face()
  289. {
  290. // Draw the button for a popup listbox
  291.     if(popup)
  292.     {
  293.         draw_top_background(parent_window, 0, 0, w, h);
  294.         images[status]->write_drawable(pixmap, 
  295.             0, 
  296.             0,
  297.             w,
  298.             h,
  299.             0,
  300.             0);
  301.         flash();
  302.     }
  303.     return 0;
  304. }
  305.  
  306. int BC_ListBox::set_item_coords()
  307. {
  308.     if(!data) return 0;
  309.  
  310.     if(display_format == LISTBOX_TEXT)
  311.     {
  312.         for(int i = 0, y = 0; 
  313.             i < data[0].total; 
  314.             i++, y += get_text_height(MEDIUMFONT))
  315.         {
  316.             for(int j = 0, x = 0; j < columns; j++)
  317.             {
  318.                 data[j].values[i]->y = y;
  319.                 data[j].values[i]->x = x;
  320.                 if(j < columns - 1) x += column_width[j];
  321.             }
  322.         }
  323.     }
  324.     else
  325.     if(display_format == LISTBOX_ICONS)
  326.     {
  327.         int x = 0, y = 0;
  328.         int row_h = 0, column_w = 0;
  329.  
  330. // Get row height
  331.         for(int i = 0; i < data[0].total; i++)
  332.         {
  333.             int item_h = get_item_h(0, i);
  334.             if(item_h > row_h) row_h = item_h;
  335.         }
  336.  
  337. // Place items
  338.         for(int i = 0; i < data[0].total; i++)
  339.         {
  340.             int item_w = get_item_w(0, i);
  341.             int item_h = get_item_h(0, i);
  342.             
  343. // Insert values into all columns to satisfy get_items_height
  344.             for(int j = 0; j < columns; j++)
  345.             {
  346.                 data[j].values[i]->x = x;
  347.                 data[j].values[i]->y = y;
  348.             }
  349.             
  350.             if(item_w > column_w) column_w = item_w;
  351.             y += row_h;
  352.             if(y >= get_h() - row_h)
  353.             {
  354.                 x += column_w;
  355.                 y = 0;
  356.                 column_w = 0;
  357.             }
  358.         }
  359.     }
  360.     return 0;
  361. }
  362.  
  363. int BC_ListBox::get_display_mode()
  364. {
  365.     return display_format;
  366. }
  367.  
  368. int BC_ListBox::get_yposition()
  369. {
  370.     return yposition;
  371. }
  372.  
  373. int BC_ListBox::get_xposition()
  374. {
  375.     return xposition;
  376. }
  377.  
  378. int BC_ListBox::get_item_x(int column, int item)
  379. {
  380.     return data[column].values[item]->x - xposition + 2;
  381. }
  382.  
  383. int BC_ListBox::get_item_y(int column, int item)
  384. {
  385.     int result;
  386.     result = data[column].values[item]->y - yposition + title_h + 2;
  387.  
  388.     return result;
  389. }
  390.  
  391. int BC_ListBox::get_item_w(int column, int item)
  392. {
  393.     if(display_format == LISTBOX_ICONS)
  394.     {
  395.         int x, y, w, h;
  396.         get_icon_mask(column, item, x, y, w, h);
  397.         int icon_w = w;
  398.         get_text_mask(column, item, x, y, w, h);
  399.         int text_w = w;
  400.  
  401.         if(icon_position == ICON_LEFT)
  402.             return icon_w + text_w;
  403.         else
  404.             return (icon_w > text_w) ? icon_w : text_w;
  405.     }
  406.     else
  407.     {
  408.         return get_text_width(MEDIUMFONT, data[column].values[item]->text) + 2 * LISTBOX_MARGIN;
  409.     }
  410. }
  411.  
  412. int BC_ListBox::get_item_h(int column, int item)
  413. {
  414.     if(display_format == LISTBOX_ICONS)
  415.     {
  416.         int x, y, w, h;
  417.         get_icon_mask(column, item, x, y, w, h);
  418.         int icon_h = h;
  419.         get_text_mask(column, item, x, y, w, h);
  420.         int text_h = h;
  421.  
  422.         if(icon_position == ICON_LEFT)
  423.             return (icon_h > text_h) ? icon_h : text_h;
  424.         else
  425.             return icon_h + text_h;
  426.     }
  427.     else
  428.     {
  429.         return get_text_height(MEDIUMFONT);
  430.     }
  431.     return 0;
  432. }
  433.  
  434.  
  435. int BC_ListBox::get_icon_w(int column, int item)
  436. {
  437.     BC_Pixmap *icon = data[column].values[item]->icon;
  438.     if(icon) return icon->get_w();
  439.     return 0;
  440. }
  441.  
  442. int BC_ListBox::get_icon_h(int column, int item)
  443. {
  444.     BC_Pixmap *icon = data[column].values[item]->icon;
  445.     if(icon) return icon->get_h();
  446.     return 0;
  447. }
  448.  
  449. int BC_ListBox::get_items_width()
  450. {
  451.     int widest = 0;
  452.  
  453.     if(display_format == LISTBOX_ICONS)
  454.     {
  455.         for(int i = 0; i < columns; i++)
  456.         {
  457.             for(int j = 0; j < data[i].total; j++)
  458.             {
  459.                 int x1, x, y, w, h;
  460.                 x1 = data[i].values[j]->x;
  461.  
  462.                 get_icon_mask(i, j, x, y, w, h);
  463.                 if(x1 + w > widest) widest = x1 + w;
  464.  
  465.                 if(display_format == LISTBOX_ICONS && icon_position == ICON_LEFT)
  466.                     x1 += w;
  467.  
  468.                 get_text_mask(i, j, x, y, w, h);
  469.                 if(x1 + w > widest) widest = x1 + w;
  470.             }
  471.         }
  472.     }
  473.     else
  474.     if(display_format == LISTBOX_TEXT)
  475.     {
  476.         return get_column_offset(columns);
  477.     }
  478.     return widest;
  479. }
  480.  
  481. int BC_ListBox::get_items_height()
  482. {
  483.     int highest = 0;
  484.  
  485.     for(int i = 0; i < columns; i++)
  486.     {
  487.         for(int j = 0; j < data[i].total; j++)
  488.         {
  489.             int y1, x, y, w, h;
  490.             y1 = data[i].values[j]->y;
  491.  
  492.             get_icon_mask(i, j, x, y, w, h);
  493.             if(y1 + h > highest) highest = y1 + h;
  494.             get_text_mask(i, j, x, y, w, h);
  495.             if(y1 + h > highest) highest = y1 + h;
  496.         }
  497.     }
  498.     if(display_format == LISTBOX_TEXT) highest += LISTBOX_MARGIN;
  499.  
  500.     return highest;
  501. }
  502.  
  503. int BC_ListBox::set_yposition(int position)
  504. {
  505.     this->yposition = position;
  506.     draw_items();
  507.     gui->flash();
  508.     return 0;
  509. }
  510.  
  511. int BC_ListBox::set_xposition(int position)
  512. {
  513.     this->xposition = position;
  514.     draw_items();
  515.     gui->flash();
  516.     return 0;
  517. }
  518.  
  519. int BC_ListBox::get_w()
  520. {
  521.     if(popup)
  522.         return BCPOPUPLISTBOX_W;
  523.     else
  524.         return popup_w;
  525. }
  526.  
  527. int BC_ListBox::get_h()
  528. {
  529.     if(popup)
  530.         return BCPOPUPLISTBOX_H;
  531.     else
  532.         return popup_h;
  533. }
  534.  
  535. int BC_ListBox::get_yscroll_x()
  536. {
  537.     if(popup)
  538.         return popup_w - SCROLL_SPAN;
  539.     else
  540.         return get_x() + popup_w - SCROLL_SPAN;
  541. }
  542.  
  543. int BC_ListBox::get_yscroll_y()
  544. {
  545.     if(popup)
  546.         return 0;
  547.     else
  548.         return get_y();
  549. }
  550.  
  551. int BC_ListBox::get_yscroll_height()
  552. {
  553.     return popup_h - (need_xscroll ? SCROLL_SPAN : 0);
  554. }
  555.  
  556. int BC_ListBox::get_xscroll_x()
  557. {
  558.     if(popup)
  559.         return 0;
  560.     else
  561.         return get_x();
  562. }
  563.  
  564. int BC_ListBox::get_xscroll_y()
  565. {
  566.     if(popup)
  567.         return popup_h - SCROLL_SPAN;
  568.     else
  569.         return get_y() + popup_h - SCROLL_SPAN;
  570. }
  571.  
  572. int BC_ListBox::get_xscroll_width()
  573. {
  574.     return popup_w - (need_yscroll ? SCROLL_SPAN : 0);
  575. }
  576.  
  577. int BC_ListBox::get_column_offset(int column)
  578. {
  579.     int x = 0;
  580.     while(column > 0)
  581.     {
  582.         x += column_width[--column];
  583.     }
  584.     return x;
  585. }
  586.  
  587. int BC_ListBox::get_column_width(int column)
  588. {
  589.     if(column < columns - 1)
  590.         return column_width[column];
  591.     else
  592.         return popup_w - get_column_offset(column);
  593. }
  594.  
  595. BC_Pixmap* BC_ListBox::get_item_pixmap(int item)
  596. {
  597.     return data[0].values[item]->icon;
  598. }
  599.  
  600. int BC_ListBox::get_icon_mask(int column, int item, int &x, int &y, int &w, int &h)
  601. {
  602.     if(display_format == LISTBOX_ICONS)
  603.     {
  604.         x = get_item_x(0, item);
  605.         y = get_item_y(0, item);
  606.         w = get_icon_w(0, item) + ICON_MARGIN * 2;
  607.         h = get_icon_h(0, item) + ICON_MARGIN * 2;
  608.     }
  609.     else
  610.     if(display_format == LISTBOX_TEXT)
  611.     {
  612.         x = y = w = h = 0;
  613.     }
  614.     return 0;
  615. }
  616.  
  617. int BC_ListBox::get_text_mask(int column, int item, int &x, int &y, int &w, int &h)
  618. {
  619.     x = get_item_x(column, item);
  620.     y = get_item_y(column, item);
  621.  
  622.     if(display_format == LISTBOX_ICONS)
  623.     {
  624.         if(icon_position == ICON_LEFT)
  625.         {
  626.             x += get_icon_w(column, item) + ICON_MARGIN * 2;
  627.             y += get_icon_h(column, item) - get_text_height(MEDIUMFONT); - ICON_MARGIN * 2;
  628.         }
  629.         else
  630.         {
  631.             y += get_icon_h(column, item) + ICON_MARGIN;
  632.         }
  633.  
  634.         w = get_text_width(MEDIUMFONT, data[column].values[item]->text) + ICON_MARGIN * 2;
  635.         h = get_text_height(MEDIUMFONT) + ICON_MARGIN * 2;
  636.     }
  637.     else
  638.     if(display_format == LISTBOX_TEXT)
  639.     {
  640.         w = get_text_width(MEDIUMFONT, data[column].values[item]->text) + LISTBOX_MARGIN * 2;
  641.         h = get_text_height(MEDIUMFONT);
  642.     }
  643.     return 0;
  644. }
  645.  
  646. int BC_ListBox::get_item_highlight(int column, int item)
  647. {
  648.     if(data[column].values[item]->selected)
  649.         return BLUE;
  650.     else
  651.     if(highlighted_item == item)
  652.         return LTGREY;
  653.     else
  654.         return WHITE;
  655. }
  656.  
  657. int BC_ListBox::get_item_color(int column, int item)
  658. {
  659.     int color = data[column].values[item]->color;
  660.     if(get_item_highlight(column, item) == color)
  661.         return BLACK;
  662.     else
  663.         return color;
  664. }
  665.  
  666.  
  667. BC_ListBoxItem* BC_ListBox::get_selection(int column, int selection_number)
  668. {
  669.     for(int i = 0; i < data[0].total; i++)
  670.     {
  671.         if(data[0].values[i]->selected)
  672.         {
  673.             if(!selection_number)
  674.             {
  675.                 return data[column].values[i];
  676.             }
  677.             selection_number--;
  678.         }
  679.     }
  680.     return 0;
  681. }
  682.  
  683. int BC_ListBox::get_selection_number(int column, int selection_number)
  684. {
  685.     for(int i = 0; i < data[0].total; i++)
  686.     {
  687.         if(data[0].values[i]->selected)
  688.         {
  689.             if(!selection_number)
  690.             {
  691.                 return i;
  692.             }
  693.             selection_number--;
  694.         }
  695.     }
  696.     return -1;
  697. }
  698.  
  699. int BC_ListBox::set_selection_mode(int mode)
  700. {
  701.     this->selection_mode = mode;
  702.     return 0;
  703. }
  704.  
  705. int BC_ListBox::update(ArrayList<BC_ListBoxItem*> *data,
  706.                         char **column_titles,
  707.                         int columns,
  708.                         int yposition,
  709.                         int xposition, 
  710.                         int currentitem,
  711.                         int set_coords)
  712. {
  713.     this->data = data;
  714.     this->column_titles = column_titles;
  715.     this->columns = columns;
  716.  
  717.     this->yposition = yposition;
  718.     this->xposition = xposition;
  719.     highlighted_item = -1;
  720.  
  721.     for(int i = 0; i < data[0].total; i++)
  722.     {
  723.         for(int j = 0; j < columns; j++)
  724.         {
  725.             if(i == currentitem)
  726.                 data[j].values[i]->selected = 1;
  727.             else
  728.                 data[j].values[i]->selected = 0;
  729.         }
  730.     }
  731.  
  732.     init_column_width();
  733.  
  734.     if(set_coords)
  735.         set_item_coords();
  736.  
  737.     if(gui)
  738.     {
  739.         draw_items();
  740.         update_scrollbars();
  741.         gui->flash();
  742.     }
  743.     return 0;
  744. }
  745.  
  746. void BC_ListBox::move_vertical(int pixels)
  747. {
  748. }
  749.  
  750. void BC_ListBox::move_horizontal(int pixels)
  751. {
  752. }
  753.  
  754. void BC_ListBox::fix_positions()
  755. {
  756.     if(yposition < 0) yposition = 0;
  757.     else
  758.     if(yposition > get_items_height() - view_h)
  759.         yposition = get_items_height() - view_h;
  760.  
  761.     if(yposition < 0) yposition = 0;
  762.  
  763.     if(xposition < 0) xposition = 0;
  764.     else
  765.     if(xposition >= get_items_width() - view_w)
  766.         xposition = get_items_width() - view_w;
  767.  
  768.     if(xposition < 0) xposition = 0;
  769. }
  770.  
  771. void BC_ListBox::center_selection(int selection)
  772. {
  773.     if(data[0].values[selection]->y - yposition  > view_h - get_text_height(MEDIUMFONT) ||
  774.         data[0].values[selection]->y - yposition < 0)
  775.     {
  776.         yposition = selection * get_text_height(MEDIUMFONT) - view_h / 2;
  777.     }
  778.     
  779.     if(display_format == LISTBOX_ICONS)
  780.     {
  781.         if(data[0].values[selection]->x - xposition > view_w ||
  782.             data[0].values[selection]->x - xposition < 0)
  783.         {
  784.             xposition = data[0].values[selection]->x - view_w / 2;
  785.         }
  786.     }
  787. }
  788.  
  789. void BC_ListBox::update_scrollbars()
  790. {
  791.     int h_needed = get_items_height();
  792.     int w_needed = get_items_width();
  793.  
  794.     if(xscrollbar)
  795.     {
  796.         if(xposition != xscrollbar->get_value())
  797.             xscrollbar->update_value(xposition);
  798.  
  799.         if(w_needed != xscrollbar->get_length() || view_w != xscrollbar->get_handlelength())
  800.             xscrollbar->update_length(w_needed, xposition, view_w);
  801.     }
  802.  
  803.     if(yscrollbar)
  804.     {
  805.         if(yposition != yscrollbar->get_value())
  806.             yscrollbar->update_value(yposition);
  807.  
  808.         if(h_needed != yscrollbar->get_length() || view_h != yscrollbar->get_handlelength())
  809.             yscrollbar->update_length(h_needed, yposition, view_h);
  810.     }
  811. }
  812.  
  813. void BC_ListBox::test_drag_scroll(int &redraw, int cursor_x, int cursor_y)
  814. {
  815.     if(cursor_y < title_h + 2)
  816.     {
  817.         yposition -= (title_h + 2) - cursor_y;
  818.         redraw = 1;
  819.     }
  820.     else
  821.     if(cursor_y >= view_h + title_h + 4)
  822.     {
  823.         yposition += cursor_y - (view_h + title_h + 4);
  824.         redraw = 1;
  825.     }
  826.  
  827.     if(cursor_x < 2)
  828.     {
  829.         xposition -= 2 - cursor_x;
  830.         redraw = 1;
  831.     }
  832.     else
  833.     if(cursor_x >= view_w + 2)
  834.     {
  835.         xposition += cursor_x - (view_w + 2);
  836.         redraw = 1;
  837.     }
  838. }
  839.  
  840. int BC_ListBox::cursor_item(int cursor_x, int cursor_y)
  841. {
  842.     if(display_format == LISTBOX_ICONS)
  843.     {
  844.         for(int i = 0; i < columns; i++)
  845.         {
  846.             for(int j = data[i].total - 1; j >= 0; j--)
  847.             {
  848.                 int icon_x, icon_y, icon_w, icon_h;
  849.                 int text_x, text_y, text_w, text_h;
  850.                 get_icon_mask(i, j, icon_x, icon_y, icon_w, icon_h);
  851.                 get_text_mask(i, j, text_x, text_y, text_w, text_h);
  852.  
  853.                 if((cursor_x >= icon_x && cursor_x < icon_x + icon_w &&
  854.                     cursor_y >= icon_y && cursor_y < icon_y + icon_h) ||
  855.                     (cursor_x >= text_x && cursor_x < text_x + text_w &&
  856.                     cursor_y >= text_y && cursor_y < text_y + text_h))
  857.                 {
  858.                     return j;
  859.                 }
  860.             }
  861.         }
  862.     }
  863.     else
  864.     if(display_format == LISTBOX_TEXT)
  865.         if(cursor_x >= 0 && cursor_x < (xscrollbar ? gui->get_w() - SCROLL_SPAN : gui->get_w()))
  866.         {
  867.             for(int i = 0; i < data[0].total; i++)
  868.             {
  869.                 if(cursor_y >= get_item_y(0, i) &&
  870.                     cursor_y < get_item_y(0, i) + get_item_h(0, i))
  871.                 {
  872.                     return i;
  873.                 }
  874.             }
  875.         }
  876.     return -1;
  877. }
  878.  
  879. int BC_ListBox::repeat_event(long duration)
  880. {
  881.     if(duration == top_level->get_resources()->tooltip_delay &&
  882.         tooltip_text[0] != 0 &&
  883.         popup &&
  884.         status == LISTBOX_HIGH &&
  885.         !tooltip_done)
  886.     {
  887.         show_tooltip();
  888.         tooltip_done = 1;
  889.         return 1;
  890.     }
  891.     return 0;
  892. }
  893.  
  894.  
  895. int BC_ListBox::cursor_enter_event()
  896. {
  897.     int result = 0;
  898.     
  899. //    if(active) result = 1;
  900.  
  901.     if(popup)
  902.     {
  903.         if(top_level->event_win == win)
  904.         {
  905.             tooltip_done = 0;
  906.             if(top_level->button_down)
  907.             {
  908.                 status = LISTBOX_DN;
  909.             }
  910.             else
  911.             if(status == LISTBOX_UP)
  912.             {
  913.                 status = LISTBOX_HIGH;
  914.             }
  915.             draw_face();
  916.             result = 1;
  917.         }
  918.     }
  919.  
  920.     if(gui && top_level->event_win == gui->win)
  921.     {
  922.         if(!highlighted)
  923.         {
  924.             highlighted = 1;
  925.             draw_border();
  926.             flash();
  927.         }
  928.         result = 1;
  929.     }
  930.     return result;
  931. }
  932.  
  933. int BC_ListBox::cursor_leave_event()
  934. {
  935.     if(popup)
  936.     {
  937.         hide_tooltip();
  938.         if(status == LISTBOX_HIGH)
  939.         {
  940.             status = LISTBOX_UP;
  941.             draw_face();
  942.         }
  943.     }
  944.  
  945.     if(gui && highlighted)
  946.     {
  947.         highlighted = 0;
  948.         if(highlighted_item >= 0) 
  949.         {
  950.             highlighted_item = -1;
  951.             draw_items();
  952.         }
  953.         else
  954.             draw_border();
  955.         gui->flash();
  956.     }
  957.     return 0;
  958. }
  959.  
  960. int BC_ListBox::button_press_event()
  961. {
  962. // Selected item
  963.     int selection = -1;
  964.     int redraw = 0;
  965.     int result = 0;
  966.  
  967.     hide_tooltip();
  968.     if(popup)
  969.     {
  970.         if(top_level->event_win == win)
  971.         {
  972.             status = LISTBOX_DN;
  973.             draw_face();
  974. // Deploy listbox
  975.             if(!active)
  976.             {
  977.                 top_level->deactivate();
  978.                 activate();
  979.             }
  980.  
  981.             result = 1;
  982.         }
  983.         else
  984.         if((xscrollbar && top_level->event_win == xscrollbar->win) ||
  985.             (yscrollbar && top_level->event_win == yscrollbar->win) ||
  986.             (gui && top_level->event_win == gui->win))
  987.         {
  988.             result = 0;
  989.         }
  990.         else
  991.         if(active)
  992.         {
  993.             deactivate();
  994.             result = 1;
  995.         }
  996.     }
  997.  
  998.     if(gui && top_level->event_win == gui->win)
  999.     {
  1000.         if(!active)
  1001.         {
  1002.             top_level->deactivate();
  1003.             activate();
  1004.             selection_active = 1;
  1005.         }
  1006.  
  1007.         last_selection2 = last_selection1;
  1008.         selection = cursor_item(top_level->cursor_x, top_level->cursor_y);
  1009.         last_selection1 = selection;
  1010.  
  1011.         if(selection >= 0)
  1012.         {
  1013.             for(int j = 0; j < columns; j++)
  1014.             {
  1015.                 if(selection_mode == LISTBOX_SINGLE)
  1016.                 {
  1017.                     for(int k = 0; k < data[0].total; k++)
  1018.                         data[j].values[k]->selected = 0;
  1019.  
  1020.                     data[j].values[selection]->selected = 1;
  1021.                 }
  1022.                  else
  1023.                 {
  1024.                     data[j].values[selection]->selected = !data[j].values[selection]->selected;
  1025.                     new_value = data[j].values[selection]->selected;
  1026.                 }
  1027.             }
  1028.  
  1029.             highlighted_item = -1;
  1030.             selection_active = 1;
  1031.             reset_query();
  1032.             redraw = 1;
  1033.             result = 1;
  1034.         }
  1035.         else
  1036.         {    for(int j = 0; j < columns; j++)
  1037.             {
  1038.                 for(int k = 0; k < data[0].total; k++)
  1039.                 {
  1040.                     if(data[j].values[k]->selected)
  1041.                     {    
  1042.                         redraw = 1;
  1043.                         result = 1;
  1044.                         reset_query();
  1045.                     }
  1046.                     data[j].values[k]->selected = 0;
  1047.                 }
  1048.             }
  1049.         }
  1050.     }
  1051.  
  1052.     if(redraw)
  1053.     {
  1054.         draw_items();
  1055.         gui->flash();
  1056.         selection_changed();
  1057.     }
  1058.  
  1059.     return result;
  1060. }
  1061.  
  1062. int BC_ListBox::button_release_event()
  1063. {
  1064.     int result = 0;
  1065.     selection_active = 0;
  1066.     new_value = 0;
  1067.     int cursor_x, cursor_y;
  1068.     Window tempwin;
  1069.  
  1070.  
  1071. // Popup window
  1072.     if(popup)
  1073.     {
  1074.         hide_tooltip();
  1075.         button_releases++;
  1076.         if(status == LISTBOX_DN)
  1077.         {
  1078.             status = LISTBOX_HIGH;
  1079.             draw_face();
  1080.             result = 1;
  1081.         }
  1082.  
  1083. // Second button release inside button
  1084.         if(top_level->event_win == win && 
  1085.             cursor_inside() && 
  1086.             button_releases > 1)
  1087.         {
  1088.             deactivate();
  1089.             result = 1;
  1090.         }
  1091. // First button release inside button
  1092.         else
  1093.         if(top_level->event_win == win && cursor_inside())
  1094.         {
  1095.             result = 1;
  1096.         }
  1097. // Button release in popup window
  1098.         else
  1099.         if(gui && 
  1100.             (top_level->event_win == win || top_level->event_win == gui->win))
  1101.         {
  1102.             XTranslateCoordinates(top_level->display, 
  1103.                 top_level->event_win, 
  1104.                 gui->win, 
  1105.                 top_level->cursor_x, 
  1106.                 top_level->cursor_y, 
  1107.                 &cursor_x, 
  1108.                 &cursor_y, 
  1109.                 &tempwin);
  1110.  
  1111.             selection = cursor_item(cursor_x, cursor_y);
  1112.  
  1113.             if(selection >= 0)
  1114.             {
  1115.                 handle_event();
  1116.             }
  1117.             deactivate();
  1118.             result = 1;
  1119.         }
  1120. // Button release outside all ranges
  1121.         else
  1122.         if(active)
  1123.         {
  1124.             deactivate();
  1125.             result = 1;
  1126.         }
  1127.     }
  1128.     else
  1129. // No popup window
  1130.     if(gui &&
  1131.         top_level->event_win == gui->win &&
  1132.         top_level->get_double_click() &&
  1133.         last_selection2 == last_selection1)
  1134.     {
  1135.         handle_event();
  1136.         result = 1;
  1137.     }
  1138.     return result;
  1139. }
  1140.  
  1141. int BC_ListBox::cursor_motion_event()
  1142. {
  1143.     int selection = -1, redraw = 0, result = 0;
  1144.     int cursor_x, cursor_y;
  1145.     Window tempwin;
  1146.  
  1147.     if(popup && 
  1148.         top_level->event_win == win && 
  1149.         status == LISTBOX_DN && 
  1150.         !cursor_inside())
  1151.     {
  1152.         status = LISTBOX_UP;
  1153.         draw_face();
  1154.     }
  1155.  
  1156.     if(gui && 
  1157.         (top_level->event_win == gui->win || 
  1158.         (popup && top_level->event_win == win)))
  1159.     {
  1160.         XTranslateCoordinates(top_level->display, 
  1161.             top_level->event_win, 
  1162.             gui->win, 
  1163.             top_level->cursor_x, 
  1164.             top_level->cursor_y, 
  1165.             &cursor_x, 
  1166.             &cursor_y, 
  1167.             &tempwin);
  1168.  
  1169.         result = 1;
  1170.         selection = cursor_item(cursor_x, cursor_y);
  1171.  
  1172. // Cursor just moved in after pressing popup button
  1173.         if(top_level->get_button_down() && selection >= 0 && !selection_active) selection_active = 1;
  1174.  
  1175. // Cursor is inside and selecting an item
  1176.         if(selection >= 0 && selection_active)
  1177.         {
  1178.             for(int j = 0; j < columns; j++)
  1179.             {
  1180.                 if(selection_mode == LISTBOX_SINGLE)
  1181.                 {
  1182.                     for(int k = 0; k < data[0].total; k++)
  1183.                     {
  1184.                         if(k != selection && data[j].values[k]->selected)
  1185.                         {
  1186.                             redraw = 1;
  1187.                             data[j].values[k]->selected = 0;
  1188.                         }
  1189.                         else
  1190.                         if(k == selection && !data[j].values[k]->selected)
  1191.                         {
  1192.                             redraw = 1;
  1193.                             data[j].values[selection]->selected = 1;
  1194.                         }
  1195.                     }
  1196.                 }
  1197.                 else
  1198.                 {
  1199.                     if(data[j].values[selection]->selected != new_value)
  1200.                     {
  1201.                         data[j].values[selection]->selected = new_value;
  1202.                         redraw = 1;
  1203.                     }
  1204.                 }
  1205.             }
  1206.         }
  1207.  
  1208.         if(top_level->get_button_down() && selection_active)
  1209.         {
  1210.             test_drag_scroll(redraw, cursor_x, cursor_y);
  1211.         }
  1212.         else
  1213.         if(highlighted_item != selection)
  1214.         {
  1215.             highlighted_item = selection;
  1216.             redraw = 1;
  1217.         }
  1218.     }
  1219.  
  1220.     if(redraw)
  1221.     {
  1222.         fix_positions();
  1223.         draw_items();
  1224.         update_scrollbars();
  1225.         gui->flash();
  1226.         if(selection_active) selection_changed();
  1227.         return 1;
  1228.     }
  1229.     else
  1230.     if(!result && highlighted_item >= 0)
  1231.     {
  1232.         highlighted_item = -1;
  1233.         draw_items();
  1234.         gui->flash();
  1235.         return 0;
  1236.     }
  1237.     return result;
  1238. }
  1239.  
  1240. int BC_ListBox::drag_start_event()
  1241. {
  1242.     if(gui && 
  1243.         top_level->event_win == gui->win && 
  1244.         allow_drag)
  1245.     {
  1246.         selection = cursor_item(top_level->cursor_x, top_level->cursor_y);
  1247.         if(selection >= 0 && get_item_pixmap(selection))
  1248.         {
  1249.             drag_popup = new BC_DragWindow(this, 
  1250.                 get_item_pixmap(selection), 
  1251.                 get_item_x(0, selection),
  1252.                 get_item_y(0, selection));
  1253.             return 1;
  1254.         }
  1255.     }
  1256.     return 0;
  1257. }
  1258.  
  1259. int BC_ListBox::drag_motion_event()
  1260. {
  1261.     if(drag_popup)
  1262.     {
  1263.         int redraw = 0;
  1264.         test_drag_scroll(redraw, top_level->cursor_x, top_level->cursor_y);
  1265.         if(redraw)
  1266.         {
  1267.             fix_positions();
  1268.             draw_items();
  1269.             update_scrollbars();
  1270.             gui->flash();
  1271.         }
  1272.  
  1273.         return drag_popup->cursor_motion_event();
  1274.         return 1;
  1275.     }
  1276.     return 0;
  1277. }
  1278.  
  1279. int BC_ListBox::drag_stop_event()
  1280. {
  1281.     if(drag_popup)
  1282.     {
  1283. // Inside window boundary
  1284.         if(top_level->cursor_x > 0 && 
  1285.             top_level->cursor_x < gui->get_w() - drag_popup->get_w() / 2 && 
  1286.             top_level->cursor_y > 0 &&
  1287.             top_level->cursor_y < gui->get_h() - drag_popup->get_h() / 2)
  1288.         {
  1289.             data[0].values[selection]->x = top_level->cursor_x + drag_popup->get_offset_x() - LISTBOX_MARGIN - 2 + xposition;
  1290.             data[0].values[selection]->y = top_level->cursor_y + drag_popup->get_offset_y() - LISTBOX_MARGIN - 2 + yposition;
  1291.             draw_items();
  1292.             gui->flash();
  1293.         }
  1294.         else
  1295.             drag_popup->drag_failure_event();
  1296.  
  1297.         delete drag_popup;
  1298.         drag_popup = 0;
  1299.         selection_active = 0;
  1300.         new_value = 0;
  1301.         return 1;
  1302.     }
  1303.     return 0;
  1304. }
  1305.  
  1306. int BC_ListBox::translation_event()
  1307. {
  1308.     if(popup && gui)
  1309.     {
  1310.         int new_x = gui->get_x() + (top_level->last_translate_x - top_level->x);
  1311.         int new_y = gui->get_y() + (top_level->last_translate_y - top_level->y);
  1312.  
  1313.         gui->reposition_window(new_x, new_y);
  1314.         
  1315.     }
  1316.     return 0;
  1317. }
  1318.  
  1319. int BC_ListBox::reposition_window(int x, int y, int w, int h)
  1320. {
  1321.     if(w != -1)
  1322.     {
  1323.         if(!popup)
  1324.         {
  1325.             popup_w = w;
  1326.             popup_h = h;
  1327.             if(xscrollbar)
  1328.                 xscrollbar->reposition_window(get_xscroll_x(), 
  1329.                     get_xscroll_y(), 
  1330.                     get_xscroll_width(),
  1331.                     SCROLL_SPAN);
  1332.             if(yscrollbar)
  1333.                 yscrollbar->reposition_window(get_yscroll_x(), 
  1334.                     get_yscroll_y(), 
  1335.                     SCROLL_SPAN,
  1336.                     get_yscroll_height());
  1337.         }
  1338.     }
  1339.  
  1340.     BC_WindowBase::reposition_window(x, y, w, h);
  1341.     draw_face();
  1342.     draw_items();
  1343.     flash();
  1344.     return 0;
  1345. }
  1346.  
  1347. int BC_ListBox::deactivate()
  1348. {
  1349.     if(active)
  1350.     {
  1351.         active = 0;
  1352.         if(popup)
  1353.         {
  1354.             if(gui) delete gui;
  1355.             xscrollbar = 0;
  1356.             yscrollbar = 0;
  1357.             gui = 0;
  1358.         }
  1359.         top_level->active_subwindow = 0;
  1360.     }
  1361.     return 0;
  1362. }
  1363.  
  1364. int BC_ListBox::activate()
  1365. {
  1366.     if(!active)
  1367.     {
  1368.         top_level->active_subwindow = this;
  1369.         active = 1;
  1370.         button_releases = 0;
  1371.  
  1372.         if(popup)
  1373.         {
  1374.             Window tempwin;
  1375.             int new_x, new_y;
  1376.             XTranslateCoordinates(top_level->display, 
  1377.                 parent_window->win, 
  1378.                 top_level->rootwin, 
  1379.                 get_x() - popup_w + get_w(), 
  1380.                 get_y() + get_h(), 
  1381.                 &new_x, 
  1382.                 &new_y, 
  1383.                 &tempwin);
  1384.  
  1385.             if(new_x < 0) new_x = 0;
  1386.             if(new_y + popup_h > top_level->get_root_h()) new_y -= get_h() + popup_h;
  1387.  
  1388.             add_subwindow(gui = new BC_Popup(this, 
  1389.                 new_x, 
  1390.                 new_y, 
  1391.                 popup_w, 
  1392.                 popup_h, 
  1393.                 -1,
  1394.                 0,
  1395.                 bg_pixmap));
  1396.             draw_items();
  1397.             gui->flash();
  1398.         }
  1399.     }
  1400.     return 0;
  1401. }
  1402.  
  1403. int BC_ListBox::keypress_event()
  1404. {
  1405.     if(!active) return 0;
  1406.     
  1407.     int result = 0, redraw = 0, done, view_items = view_h / get_text_height(MEDIUMFONT);
  1408.     int new_item = -1, new_selection = 0;
  1409.     switch(top_level->get_keypress())
  1410.     {
  1411.         case ESC:
  1412.         case RETURN:
  1413.             top_level->deactivate();
  1414.             result = 0;
  1415.             break;
  1416.  
  1417.         case UP:
  1418.             if(selection_mode == LISTBOX_SINGLE)
  1419.             {
  1420.                 done = 0;
  1421.                 for(int i = data[0].total - 1; !done && i > 0; i--)
  1422.                 {
  1423.                     if(data[0].values[i]->selected)
  1424.                     {
  1425.                         new_item = i - 1;
  1426.                         for(int j = 0; j < columns; j++)
  1427.                         {
  1428.                             data[j].values[i]->selected = 0;
  1429.                             data[j].values[new_item]->selected = 1;
  1430.                             redraw = 1;
  1431.                             result = 1;
  1432.                             new_selection = 1;
  1433.                             center_selection(new_item);
  1434.                         }
  1435.                         done = 1;
  1436.                     }
  1437.                 }
  1438.             }
  1439.             break;
  1440.  
  1441.         case DOWN:
  1442.             if(selection_mode == LISTBOX_SINGLE)
  1443.             {
  1444.                 done = 0;
  1445.                 for(int i = 0; !done && i < data[0].total - 1; i++)
  1446.                 {
  1447.                     if(data[0].values[i]->selected)
  1448.                     {
  1449.                         new_item = i + 1;
  1450.                         for(int j = 0; j < columns; j++)
  1451.                         {
  1452.                             data[j].values[i]->selected = 0;
  1453.                             data[j].values[new_item]->selected = 1;
  1454.                             redraw = 1;
  1455.                             result = 1;
  1456.                             new_selection = 1;
  1457.                             center_selection(new_item);
  1458.                         }
  1459.                         done = 1;
  1460.                     }
  1461.                 }
  1462.             }
  1463.             
  1464.             break;
  1465.  
  1466.         case PGUP:
  1467.             if(selection_mode == LISTBOX_SINGLE)
  1468.             {
  1469.                 done = 0;
  1470.                 for(int i = data[0].total - 1; !done && i > 0; i--)
  1471.                 {
  1472.                     if(data[0].values[i]->selected)
  1473.                     {
  1474.                         new_item = i - view_items;
  1475.                         if(new_item < 0) new_item = 0;
  1476.  
  1477.                         for(int j = 0; j < columns; j++)
  1478.                         {
  1479.                             data[j].values[i]->selected = 0;
  1480.                             data[j].values[new_item]->selected = 1;
  1481.                             redraw = 1;
  1482.                             result = 1;
  1483.                             new_selection = 1;
  1484.                             center_selection(new_item);
  1485.                         }
  1486.                         done = 1;
  1487.                     }
  1488.                 }
  1489.             }
  1490.             break;
  1491.  
  1492.         case PGDN:
  1493.             if(selection_mode == LISTBOX_SINGLE)
  1494.             {
  1495.                 done = 0;
  1496.                 for(int i = 0; !done && i < data[0].total - 1; i++)
  1497.                 {
  1498.                     if(data[0].values[i]->selected)
  1499.                     {
  1500.                         new_item = i + view_items;
  1501.                         if(new_item >= data[0].total) new_item = data[0].total - 1;
  1502.  
  1503.                         for(int j = 0; j < columns; j++)
  1504.                         {
  1505.                             data[j].values[i]->selected = 0;
  1506.                             data[j].values[new_item]->selected = 1;
  1507.                             redraw = 1;
  1508.                             result = 1;
  1509.                             new_selection = 1;
  1510.                             center_selection(new_item);
  1511.                         }
  1512.                         done = 1;
  1513.                     }
  1514.                 }
  1515.             }
  1516.             break;
  1517.  
  1518.         case LEFT:
  1519.             xposition -= 10;
  1520.             redraw = 1;
  1521.             result = 1;
  1522.             break;
  1523.  
  1524.         case RIGHT:
  1525.             xposition += 10;
  1526.             redraw = 1;
  1527.             result = 1;
  1528.             break;
  1529.  
  1530.         default:
  1531.             if(top_level->get_keypress() > 30 && top_level->get_keypress() < 127)
  1532.             {
  1533.                 int query_len = strlen(query);
  1534.                 query[query_len++] = top_level->get_keypress();
  1535.                 query[query_len] = 0;
  1536.                 query_list();
  1537.             }
  1538.             else
  1539.             if(top_level->get_keypress() == BACKSPACE)
  1540.             {
  1541.                 int query_len = strlen(query);
  1542.                 if(query_len > 0) query[--query_len] = 0;
  1543.                 query_list();
  1544.             }
  1545.  
  1546.             redraw = 1;
  1547.             result = 1;
  1548.             break;
  1549.     }
  1550.  
  1551.     if(redraw)
  1552.     {
  1553.         fix_positions();
  1554.         draw_items();
  1555.         update_scrollbars();
  1556.         gui->flash();
  1557.     }
  1558.     
  1559.     if(new_selection)
  1560.     {
  1561.         selection_changed();
  1562.     }
  1563.  
  1564.     return result;
  1565. }
  1566.  
  1567. int BC_ListBox::get_scrollbars()
  1568. {
  1569.     int h_needed = get_items_height();
  1570.     int w_needed = get_items_width();
  1571.  
  1572.     if(display_format != LISTBOX_ICONS)
  1573.         title_h = column_titles ? (get_text_height(MEDIUMFONT) + 4) : 0;
  1574.     else
  1575.         title_h = 0;
  1576.  
  1577.     view_h = popup_h - title_h - 4;
  1578.     view_w = popup_w - 4;
  1579.  
  1580. // Create scrollbars as needed
  1581.     for(int i = 0; i < 2; i++)
  1582.     {
  1583.         if(w_needed > view_w)
  1584.         {
  1585.             need_xscroll = 1;
  1586.             view_h = popup_h - title_h - SCROLL_SPAN - 4;
  1587.         }
  1588.         else
  1589.         {
  1590.             need_xscroll = 0;
  1591.         }
  1592.  
  1593.         if(h_needed > view_h)
  1594.         {
  1595.             need_yscroll = 1;
  1596.             view_w = popup_w - SCROLL_SPAN - 4;
  1597.         }
  1598.         else
  1599.         {
  1600.             need_yscroll = 0;
  1601.         }
  1602.     }
  1603.  
  1604. // Update subwindow size
  1605.     int new_w = popup_w, new_h = popup_h;
  1606.     if(need_xscroll) new_h -= SCROLL_SPAN;
  1607.     if(need_yscroll) new_w -= SCROLL_SPAN;
  1608.  
  1609.     if(!popup)
  1610.         if(new_w != BC_WindowBase::get_w() || new_h != BC_WindowBase::get_h())
  1611.             gui->resize_window(new_w, new_h);
  1612.  
  1613.     BC_WindowBase *destination = (popup ? gui : parent_window);
  1614.     if(need_xscroll)
  1615.     {
  1616.         if(!xscrollbar)
  1617.         {
  1618.             destination->add_subwindow(xscrollbar = 
  1619.                 new BC_ListBoxXScroll(this, 
  1620.                     w_needed, 
  1621.                     view_w, 
  1622.                     xposition));
  1623.             xscrollbar->bound_to = this;
  1624.         }
  1625.     }
  1626.     else
  1627.     {
  1628.         if(xscrollbar) delete xscrollbar;
  1629.         xscrollbar = 0;
  1630.     }
  1631.  
  1632.     if(need_yscroll)
  1633.     {
  1634.         if(!yscrollbar)
  1635.         {
  1636.             destination->add_subwindow(yscrollbar = 
  1637.                 new BC_ListBoxYScroll(this, 
  1638.                     h_needed, 
  1639.                     view_h, 
  1640.                     yposition));
  1641.             yscrollbar->bound_to = this;
  1642.         }
  1643.     }
  1644.     else
  1645.     {
  1646.         if(yscrollbar) delete yscrollbar;
  1647.         yscrollbar = 0;
  1648.     }
  1649.  
  1650.     return 0;
  1651. }
  1652.  
  1653. void BC_ListBox::clear_listbox(int x, int y, int w, int h)
  1654. {
  1655.     if(bg_pixmap)
  1656.     {
  1657.         gui->draw_tiles(bg_pixmap, 0, 0, x, y, w, h);
  1658.     }
  1659.     else
  1660.     {
  1661.         gui->set_color(WHITE);
  1662.         gui->draw_box(x, y, w, h);
  1663.     }
  1664. }
  1665.  
  1666. int BC_ListBox::draw_items()
  1667. {
  1668.     if(gui)
  1669.     {
  1670.         get_scrollbars();
  1671.  
  1672. // Icon display
  1673.         if(display_format == LISTBOX_ICONS)
  1674.         {
  1675.             clear_listbox(2, 2 + title_h, view_w, view_h);
  1676.  
  1677.             set_font(MEDIUMFONT);
  1678.             for(int i = 0; i < data[0].total; i++)
  1679.             {
  1680.                 if(get_item_x(0, i) >= -get_item_w(0, i) && 
  1681.                     get_item_x(0, i) < view_w &&
  1682.                     get_item_y(0, i) >= -get_item_h(0, i) + title_h &&
  1683.                     get_item_y(0, i) < view_h + title_h)
  1684.                 {
  1685.                     int item_color = get_item_highlight(0, i);
  1686.                     int icon_x, icon_y, icon_w, icon_h;
  1687.                     int text_x, text_y, text_w, text_h;
  1688.  
  1689. // Draw highlights                    
  1690.                     get_icon_mask(0, i, icon_x, icon_y, icon_w, icon_h);
  1691.                     get_text_mask(0, i, text_x, text_y, text_w, text_h);
  1692.                     if(item_color != WHITE)
  1693.                     {
  1694.                         gui->set_color(BLACK);
  1695.                         gui->draw_rectangle(icon_x, icon_y, icon_w, icon_h);
  1696.                         gui->set_color(item_color);
  1697.                         gui->draw_box(icon_x + 1, icon_y + 1, icon_w - 2, icon_h - 2);
  1698.                         gui->set_color(BLACK);
  1699.                         gui->draw_rectangle(text_x, text_y, text_w, text_h);
  1700.                         gui->set_color(item_color);
  1701.                         gui->draw_box(text_x + 1, text_y + 1, text_w - 2, text_h - 2);
  1702.                     
  1703.                         if(icon_position == ICON_LEFT)
  1704.                             gui->draw_box(text_x - 1, text_y + 1, 2, text_h - 2);
  1705.                         else
  1706.                         if(icon_position == ICON_TOP)
  1707.                             gui->draw_line(text_x + 1, text_y, text_x + icon_w - 2, text_y);                    }
  1708.  
  1709. // Draw icons
  1710.                     gui->set_color(get_item_color(0, i));
  1711.                     if(get_item_pixmap(i))
  1712.                         get_item_pixmap(i)->write_drawable(gui->pixmap, icon_x + ICON_MARGIN, icon_y + ICON_MARGIN);
  1713.                     gui->draw_text(text_x + ICON_MARGIN, 
  1714.                         text_y + ICON_MARGIN + get_text_ascent(MEDIUMFONT), 
  1715.                         data[0].values[i]->text);
  1716.                 }
  1717.             }
  1718.         }
  1719.         else
  1720. // Text display
  1721.         if(display_format == LISTBOX_TEXT)
  1722.         {
  1723.             for(int j = 0; j < columns; j++)
  1724.             {
  1725.                 clear_listbox(2 + get_column_offset(j) - xposition, 
  1726.                     2 + title_h, 
  1727.                     get_column_width(j), 
  1728.                     view_h);
  1729.  
  1730.                 set_font(MEDIUMFONT);
  1731.                 for(int i = 0; i < data[j].total; i++)
  1732.                 {
  1733.                     if(get_item_y(0, i) >= -get_item_h(0, i) + title_h &&
  1734.                         get_item_y(0, i) < view_h + title_h)
  1735.                     {
  1736.                         int row_color = get_item_highlight(0, i);
  1737.                         int x, y, w, h;
  1738.                         
  1739.                         get_text_mask(j, i, x, y, w, h);
  1740.  
  1741.                         if(row_color != WHITE) 
  1742.                         {
  1743.                             gui->set_color(row_color);
  1744.                             gui->draw_box(x, 
  1745.                                 y, 
  1746.                                 get_column_width(j), 
  1747.                                 h);
  1748.                             gui->set_color(BLACK);
  1749.                             gui->draw_line(x, y, x + get_column_width(j) - 1, y);
  1750.                             gui->draw_line(x, y + get_text_height(MEDIUMFONT), x + get_column_width(j) - 1, y + get_text_height(MEDIUMFONT));
  1751.                         }
  1752.  
  1753.                         gui->set_color(get_item_color(j, i));
  1754.  
  1755.                         gui->draw_text(x + 2 + LISTBOX_MARGIN, 
  1756.                             y + get_text_ascent(MEDIUMFONT), 
  1757.                             data[j].values[i]->text);
  1758.                     }
  1759.                 }
  1760.             }
  1761.         }
  1762.  
  1763. // Draw titles
  1764.         if(column_titles && display_format != LISTBOX_ICONS)
  1765.         {
  1766.             for(int i = 0; i < columns; i++)
  1767.             {
  1768.                 gui->draw_3d_box(get_column_offset(i) - xposition + 2, 
  1769.                     2, 
  1770.                     get_column_width(i), 
  1771.                     title_h, 
  1772.                     top_level->get_resources()->button_light, 
  1773.                     top_level->get_resources()->button_up, 
  1774.                     top_level->get_resources()->button_up, 
  1775.                     top_level->get_resources()->button_shadow,
  1776.                     BLACK);
  1777.  
  1778.                 gui->set_color(BLACK);
  1779.                 gui->draw_text(-xposition + get_column_offset(i) + LISTBOX_MARGIN + 2, 
  1780.                     2 + get_text_ascent(MEDIUMFONT), column_titles[i]);
  1781.             }
  1782.         }
  1783.  
  1784. // Clear garbage
  1785.         if(xscrollbar && yscrollbar && popup)
  1786.         {
  1787.             gui->draw_top_background(parent_window, 
  1788.                 popup_w - SCROLL_SPAN, 
  1789.                 popup_h - SCROLL_SPAN, 
  1790.                 SCROLL_SPAN, 
  1791.                 SCROLL_SPAN);
  1792.         }
  1793.         draw_border();
  1794.     }
  1795.  
  1796.     return 0;
  1797. }
  1798.  
  1799. int BC_ListBox::draw_border()
  1800. {
  1801.     gui->draw_3d_border(0, 
  1802.         0, 
  1803.         view_w + 4, 
  1804.         view_h + title_h + 4, 
  1805.         top_level->get_resources()->button_shadow, 
  1806.         highlighted ? RED : BLACK, 
  1807.         highlighted ? RED : top_level->get_resources()->button_up, 
  1808.         top_level->get_resources()->button_light);
  1809.     return 0;
  1810. }
  1811.