Back to index

plt-scheme  4.2.1
ListBox.cc
Go to the documentation of this file.
00001 /*                                                      -*- C++ -*-
00002  *
00003  * Purpose: list box panel item
00004  *
00005  * Authors: Markus Holzem and Julian Smart
00006  *
00007  * Copyright: (C) 2004-2009 PLT Scheme Inc.
00008  * Copyright: (C) 1995, AIAI, University of Edinburgh (Julian)
00009  * Copyright: (C) 1995, GNU (Markus)
00010  *
00011  * This program is free software; you can redistribute it and/or modify
00012  * it under the terms of the GNU General Public License as published by
00013  * the Free Software Foundation; either version 2 of the License, or
00014  * (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software
00023  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00024  * 02110-1301 USA.
00025  */
00026 
00027 #ifdef __GNUG__
00028 #pragma implementation "ListBox.h"
00029 #endif
00030 
00031 #define  Uses_XtIntrinsic
00032 #define  Uses_wxListBox
00033 #define  Uses_wxStringList
00034 #include "wx.h"
00035 #define  Uses_TraversingEnforcerWidget
00036 #define  Uses_MultiListWidget
00037 #define  Uses_ScrollWinWidget
00038 #include "widgets.h"
00039 
00040 #include <ctype.h>
00041 
00042 // don't allocate or free for every append or del
00043 #define LIST_CHUNK_SIZE     20
00044 #define MULTILIST    ((XfwfMultiListWidget)(X->handle))
00045 
00046 #define wxLIST_BOX_WIDTH    70
00047 #define wxLIST_BOX_HEIGHT   50
00048 
00049 char *wxchoice_unprotect_amp(char *s);
00050 
00051 //-----------------------------------------------------------------------------
00052 // create and destroy wxListBox
00053 //-----------------------------------------------------------------------------
00054 
00055 wxListBox::wxListBox(wxPanel *panel, wxFunction func, char *title,
00056                    Bool multiple, int x, int y, int width, int height,
00057                    int n, char **_choices, long style, 
00058                    wxFont *_font, wxFont *_label_font, 
00059                    char *name) : wxItem(_font)
00060 {
00061     __type = wxTYPE_LIST_BOX;
00062 
00063     AllowDoubleClick(TRUE);
00064 
00065     choices = client_data = NULL;
00066     num_choices = 0;
00067     num_free = 0;
00068     typepos = 0;
00069     typetime = 0;
00070 
00071     label_font = (_label_font ? _label_font : wxSYSTEM_FONT);
00072 
00073     Create(panel, func, title, multiple, x, y, width, height,
00074           n, _choices, style, name);
00075 }
00076 
00077 Bool wxListBox::Create(wxPanel *panel, wxFunction func, char *title,
00078                      Bool multiple, int x, int y, int width, int height,
00079                      int n, char **choices, long style, char *name)
00080 {
00081     wxWindow_Xintern *ph;
00082     Widget wgt;
00083     Bool vert;
00084     long labelw = 0, labelh = 0;
00085 
00086     ChainToPanel(panel, style | ((long)multiple), name);
00087     
00088     if (style & wxVERTICAL_LABEL)
00089       vert = 1;
00090     else if (style & wxHORIZONTAL_LABEL)
00091       vert = 0;
00092     else
00093       vert = (panel->GetLabelPosition() == wxVERTICAL);
00094 
00095     title = wxGetCtlLabel(title);
00096 
00097     ph = parent->GetHandle();
00098 
00099     // create frame
00100     wgt = XtVaCreateWidget
00101        (name, xfwfTraversingEnforcerWidgetClass, ph->handle,
00102         XtNlabel,       title,
00103         XtNalignment,   vert ? XfwfTop : XfwfTopLeft,
00104         XtNbackground,  wxGREY_PIXEL,
00105         XtNforeground,  wxBLACK_PIXEL,
00106         XtNhighlightColor, wxCTL_HIGHLIGHT_PIXEL,
00107         XtNhighlightThickness, 2,
00108         XtNfont,        label_font->GetInternalFont(),
00109 #ifdef WX_USE_XFT
00110         XtNxfont,       label_font->GetInternalAAFont(),
00111 #endif
00112         NULL);
00113     if (!(style & wxINVISIBLE))
00114       XtManageChild(wgt);
00115     else
00116       XtRealizeWidget(wgt);
00117     X->frame = wgt;
00118     // create viewport
00119     wgt = XtVaCreateManagedWidget
00120        ("viewport", xfwfScrolledWindowWidgetClass, X->frame,
00121         XtNhideHScrollbar, TRUE,
00122         XtNbackground, wxGREY_PIXEL,
00123         XtNdoScroll, FALSE,
00124         XtNhighlightThickness, 0,
00125         XtNhighlightColor, wxCTL_HIGHLIGHT_PIXEL,
00126         XtNtraversalOn, FALSE,
00127         NULL);
00128     X->scroll = wgt;
00129     // create multi list
00130     wgt = XtVaCreateManagedWidget
00131        ("list", xfwfMultiListWidgetClass, X->scroll,
00132         XtNbackground,     wxWHITE_PIXEL,
00133         XtNforeground,     wxBLACK_PIXEL,
00134         XtNhighlightBackground,  wxCTL_HIGHLIGHT_PIXEL,
00135         XtNhighlightForeground,  wxGREY_PIXEL,
00136         XtNfont,           font->GetInternalFont(),
00137 #ifdef WX_USE_XFT
00138         XtNmlXftFont,          font->GetInternalAAFont(),
00139 #endif
00140         XtNborderWidth,    0,
00141         XtNshadeSurplus,   FALSE,
00142         XtNdefaultColumns, 1,
00143         XtNforceColumns,   TRUE,
00144         XtNcursor,         NULL,
00145         XtNmaxSelectable,  (multiple & (wxMULTIPLE | wxEXTENDED)) ? 10000 : 1,
00146         XtNclickExtends,   (Boolean)(multiple & wxEXTENDED),
00147         NULL);
00148     X->handle = wgt;
00149 
00150     XtVaSetValues(X->scroll, XtNautoAdjustScrollbars, 0, NULL);
00151     misc_flags |= 8; /* Indicates no auto-scroll. */
00152 
00153     Set(n, choices);
00154     // propagate key events from frame to scrollwin widget
00155     XtVaSetValues(X->frame, XtNpropagateTarget, X->handle, NULL);
00156     // callback
00157     callback = func;
00158     XtAddCallback(X->handle, XtNcallback,
00159                 wxListBox::EventCallback,  (XtPointer)saferef);
00160 
00161     if (title) {
00162       double w, h;
00163       char *label_stripped;
00164       label_stripped = wxchoice_unprotect_amp(title);
00165       GetTextExtent(label_stripped, &w, &h, NULL, NULL, label_font);
00166       if (vert)
00167        labelh = (long)h;
00168       else
00169        labelw = (long)w;
00170     }
00171 
00172     panel->PositionItem(this, x, y,
00173                      (width  > -1 ? width  : (wxLIST_BOX_WIDTH + labelw)),
00174                      (height > -1 ? height : (wxLIST_BOX_HEIGHT + labelh)));
00175     AddEventHandlers();
00176 
00177     if (style & wxINVISIBLE)
00178       Show(FALSE);
00179 
00180     return TRUE;
00181 }
00182 
00183 wxListBox::~wxListBox(void)
00184 {
00185     Clear();
00186 }
00187 
00188 //-----------------------------------------------------------------------------
00189 // override parent methods
00190 //-----------------------------------------------------------------------------
00191 
00192 void wxListBox::SetSize(int x, int y, int width, int height, int flags)
00193 {
00194     wxItem::SetSize(x, y, width, height, flags);
00195     OnListSize(width, height);
00196 }
00197 
00198 //-----------------------------------------------------------------------------
00199 // change contents of wxListBox
00200 //-----------------------------------------------------------------------------
00201 
00202 void wxListBox::Append(char *item)
00203 {
00204   int i, count, *selections;
00205 
00206   count = GetSelections(&selections);
00207 
00208   if (num_free == 0) {
00209     char **new_choices, **new_client_data;
00210 
00211     num_free = LIST_CHUNK_SIZE;
00212     new_choices     = new WXGC_PTRS char *[num_choices+LIST_CHUNK_SIZE];
00213     new_client_data = new WXGC_PTRS char *[num_choices+LIST_CHUNK_SIZE];
00214     // copy current choices
00215     for (i=0; i<num_choices; ++i) {
00216       new_choices[i] = choices[i];
00217       new_client_data[i] = client_data[i];
00218     }
00219     choices = new_choices;
00220     client_data = new_client_data;
00221   }
00222   // set new item
00223   {
00224     char *s;
00225     s = copystring(item);
00226     choices[num_choices]     = s;
00227   }
00228   client_data[num_choices] = NULL;
00229   // one choice more, one free space less
00230   ++num_choices; --num_free;
00231   SetInternalData();
00232 
00233   while (count--) {
00234     SetSelection(selections[count], TRUE);
00235   }
00236 }
00237 
00238 void wxListBox::Append(char *item, char *_client_data)
00239 {
00240     Append(item);
00241     client_data[num_choices-1] = _client_data;
00242 }
00243 
00244 void wxListBox::Clear(void)
00245 {
00246     if (choices)
00247       choices = NULL;
00248     if (client_data)
00249       client_data = NULL;
00250     num_choices = num_free = 0;
00251     SetInternalData();
00252 }
00253 
00254 void wxListBox::Delete(int n)
00255 {
00256     if (0 <= n && n < num_choices) {
00257       int i, count, *selections;
00258       
00259       count = GetSelections(&selections);
00260 
00261 
00262       for (i=n+1; i<num_choices; ++i) { // shrink arrays
00263        choices[i-1] = choices[i];
00264        client_data[i-1] = client_data[i];
00265       }
00266       --num_choices; ++num_free;
00267       SetInternalData();
00268 
00269       while (count--) {
00270        if (selections[count] < n)
00271          SetSelection(selections[count], TRUE);
00272        else if (selections[count] > n)
00273          SetSelection(selections[count] - 1, TRUE);
00274       }
00275     }
00276 }
00277 
00278 void wxListBox::InsertItems(int n_items, char **items, int pos)
00279 {
00280     int     i, j;
00281     char **new_choices, **new_client_data;
00282 
00283     pos = pos < num_choices ? pos : num_choices;
00284 
00285     new_choices     = new WXGC_PTRS char *[num_choices+n_items];
00286     new_client_data = new WXGC_PTRS char *[num_choices+n_items];
00287 
00288     for (i = 0; i < pos; ++i) {                  // copy choices previous to pos
00289        new_choices[i] = choices[i];
00290        new_client_data[i] = client_data[i];
00291     }
00292     for (j = 0; j < n_items; ++i, ++j) {             // copy new choices
00293        new_choices[i] = items[j];
00294        new_client_data[i] = NULL;
00295     }
00296     for (j = pos; j < num_choices; ++i, ++j) {          // copy left old choices
00297        new_choices[i] = choices[j];
00298        new_client_data[i] = client_data[j];
00299     }
00300     num_choices+=n_items;
00301     choices = new_choices;
00302     client_data = new_client_data;
00303 
00304     SetInternalData();
00305 }
00306 
00307 void wxListBox::Set(int n, char *_choices[])
00308 {
00309   int i;
00310   char **sa;
00311 
00312   // clear ListBox
00313   Clear();
00314 
00315   // copy choices and initialize client_data
00316   num_choices = n;
00317   num_free = LIST_CHUNK_SIZE;
00318   sa = new WXGC_PTRS char*[n+num_free];
00319   choices = sa;
00320   sa = new WXGC_PTRS char*[n+num_free];
00321   client_data = sa;
00322   for (i = 0; i < n; i++) {
00323     char *s;
00324     s = copystring(_choices[i]);
00325     choices[i] = s;
00326     client_data[i] = NULL;
00327   }
00328   SetInternalData();
00329 }
00330 
00331 void wxListBox::SetInternalData(void)
00332 {
00333     int ww, hh, p;
00334 
00335     GetSize(&ww, &hh);
00336     XfwfMultiListSetNewData(
00337        MULTILIST, num_choices ? choices : (String*)NULL, num_choices,
00338        ww, TRUE, (Boolean*)NULL);
00339 
00340     OnListSize(0, 0);
00341 
00342     p = GetScrollPos(wxVERTICAL);
00343     XtVaSetValues(X->handle, XtNoffset, p, NULL);
00344 }
00345 
00346 void wxListBox::OnScroll(wxScrollEvent* event)
00347 {
00348   int p;
00349 
00350   wxItem::OnScroll(event);
00351 
00352   p = GetScrollPos(wxVERTICAL);
00353   XtVaSetValues(X->handle, XtNoffset, p, NULL);
00354 }
00355 
00356 void wxListBox::OnSize(int width, int height)
00357 {
00358   OnListSize(width, height);
00359   wxItem::OnSize(width, height);
00360 }
00361 
00362 void wxListBox::OnListSize(int, int)
00363 {
00364   int v, s, n;
00365   v = NumberOfVisibleItems();
00366   s = num_choices - v;
00367   if (s < 0)
00368     s = 0;
00369   SetScrollRange(wxVERTICAL, s);
00370   if (!v)
00371     v = 1;
00372   SetScrollPage(wxVERTICAL, v);
00373 
00374   n = GetScrollPos(wxVERTICAL);
00375   XtVaSetValues(X->handle, XtNoffset, n, NULL);
00376 }
00377 
00378 void wxListBox::SetFirstItem(int n)
00379 {
00380   SetScrollPos(wxVERTICAL, n);
00381     
00382   n = GetScrollPos(wxVERTICAL);
00383   XtVaSetValues(X->handle, XtNoffset, n, NULL);
00384 }
00385 
00386 int wxListBox::GetFirstItem()
00387 {
00388   return GetScrollPos(wxVERTICAL);
00389 }
00390 
00391 void wxListBox::SetFirstItem(char *s)
00392 {
00393   int n;
00394   if ((n = FindString(s)) > -1) {
00395     SetFirstItem(n);
00396   }
00397 }
00398 
00399 int wxListBox::NumberOfVisibleItems()
00400 {
00401   Dimension row_height;
00402   int cw, ch;
00403 
00404   XtVaGetValues(X->handle, XtNrowHeight, &row_height, NULL);
00405 
00406   GetClientSize(&cw, &ch);
00407   
00408   ch = ch / row_height;
00409 
00410   return max(1, ch);
00411 }
00412 
00413 //-----------------------------------------------------------------------------
00414 // change state of wxListBox
00415 //-----------------------------------------------------------------------------
00416 
00417 void wxListBox::Deselect(int n)
00418 {
00419     XfwfMultiListUnhighlightItem(MULTILIST, n);
00420 }
00421 
00422 int wxListBox::FindString(char *s)
00423 {
00424   for (int i=0; i<num_choices; ++i) {
00425     if (!strcmp(s, choices[i]))
00426       return i;
00427   }
00428   return -1;
00429 }
00430 
00431 char *wxListBox::GetClientData(int n)
00432 {
00433     if (0 <= n && n < num_choices)
00434        return client_data[n];
00435     return NULL;
00436 }
00437 
00438 int wxListBox::GetSelection(void)
00439 {
00440   XfwfMultiListReturnStruct *rs;
00441   rs = XfwfMultiListGetHighlighted(MULTILIST);
00442   if (rs->num_selected >= 1)
00443     return rs->selected_items[0];
00444   return -1;
00445 }
00446 
00447 static int int_le(const void *a, const void *b)
00448 {
00449   return (*(int *)a - *(int *)b);
00450 }
00451 
00452 int wxListBox::GetSelections(int **list_selections)
00453 {
00454     XfwfMultiListReturnStruct *rs;
00455     int *selections, i;
00456 
00457     rs = XfwfMultiListGetHighlighted(MULTILIST);
00458 
00459     selections = new WXGC_ATOMIC int[rs->num_selected];
00460     for (i = 0; i < rs->num_selected; i++) {
00461       selections[i] = rs->selected_items[i];
00462     }
00463     
00464     qsort(selections, rs->num_selected, sizeof(int), int_le);
00465 
00466     *list_selections = selections;
00467 
00468     return (rs->num_selected);
00469 }
00470 
00471 char *wxListBox::GetString(int n)
00472 {
00473     if (0 <= n && n < num_choices)
00474        return choices[n];
00475     return NULL;
00476 }
00477 
00478 char *wxListBox::GetStringSelection(void)
00479 {
00480     int n;
00481     if ((n = GetSelection()) > -1)
00482        return choices[n];
00483     return NULL;
00484 }
00485 
00486 int wxListBox::Number(void)
00487 {
00488     return num_choices;
00489 }
00490 
00491 Bool wxListBox::Selected(int n)
00492 {
00493     if (0 <= n && n < num_choices)
00494        return XfwfMultiListIsHighlighted(MULTILIST, n);
00495     return FALSE;
00496 }
00497 
00498 void wxListBox::SetClientData(int n, char *_client_data)
00499 {
00500     if (0 <= n && n < num_choices)
00501        client_data[n] = _client_data;
00502 }
00503 
00504 void wxListBox::SetSelection(int n, Bool select)
00505 {
00506   if (0 <= n && n < num_choices)
00507     if (select)
00508       XfwfMultiListHighlightItem(MULTILIST, n);
00509     else
00510       XfwfMultiListUnhighlightItem(MULTILIST, n);
00511 }
00512 
00513 void wxListBox::SetOneSelection(int n)
00514 {
00515   if (0 <= n && n < num_choices) {
00516     if (style & (wxMULTIPLE | wxEXTENDED))
00517       XfwfMultiListUnhighlightAll(MULTILIST);
00518     XfwfMultiListHighlightItem(MULTILIST, n);
00519   }
00520 }
00521 
00522 Bool wxListBox::SetStringSelection(char *s)
00523 {
00524     int n;
00525     if ((n = FindString(s)) > -1) {
00526        SetOneSelection(n);
00527        return TRUE;
00528     }
00529     return FALSE;
00530 }
00531 
00532 void wxListBox::SetString(int n, char *s)
00533 {
00534   if (0 <= n && n < num_choices) {
00535     s = copystring(s);
00536     choices[n] = s;
00537     SetInternalData();    
00538   }
00539 }
00540 
00541 void wxListBox::Command(wxCommandEvent *event)
00542 {
00543   ProcessCommand (event);
00544 }
00545 
00546 //-----------------------------------------------------------------------------
00547 // callback for xfwfMultiListWidgetClass
00548 //-----------------------------------------------------------------------------
00549 
00550 void wxListBox::EventCallback(Widget WXUNUSED(w),
00551                           XtPointer dclient, XtPointer dcall)
00552 {
00553     wxListBox                 *lbox   = (wxListBox *)GET_SAFEREF(dclient);
00554     XfwfMultiListReturnStruct *rs     = (XfwfMultiListReturnStruct*)dcall;
00555     wxCommandEvent            *event;
00556 
00557     event = new wxCommandEvent(wxEVENT_TYPE_LISTBOX_COMMAND);
00558 
00559     if (rs->action == XfwfMultiListActionDClick 
00560        && lbox->allow_dclicks)
00561       event->eventType = wxEVENT_TYPE_LISTBOX_DCLICK_COMMAND;
00562 
00563     lbox->ProcessCommand(event);
00564 
00565 #ifdef MZ_PRECISE_GC
00566     XFORM_RESET_VAR_STACK;
00567 #endif
00568 }
00569 
00570 extern void wxBell(void);
00571 
00572 void wxListBox::OnChar(wxKeyEvent *e)
00573 {
00574   int delta = 0;
00575 
00576   switch (e->keyCode) {
00577   case WXK_UP:
00578     delta = -1;
00579     break;
00580   case WXK_PRIOR:
00581     delta = - NumberOfVisibleItems();
00582     break;
00583   case WXK_HOME:
00584     delta = - num_choices;
00585     break;
00586   case WXK_DOWN:
00587     delta = 1;
00588     break;
00589   case WXK_NEXT:
00590     delta = NumberOfVisibleItems();
00591     break;
00592   case WXK_END:
00593     delta = num_choices;
00594     break;
00595   default:
00596     if ((e->keyCode < 0)
00597        || (e->keyCode > 255)
00598        || !isprint(e->keyCode))
00599       return;
00600 
00601     if (e->timeStamp && typetime 
00602        && (e->timeStamp - typetime < 500))
00603       typepos++;
00604     else
00605       typepos = 0;
00606     if (typepos == 16) {
00607       wxBell();
00608       typepos = 15;
00609       return;
00610     }
00611     typetime = e->timeStamp;
00612     typing[typepos] = e->keyCode;
00613     /* Try to find it */
00614     {
00615       int *sels;
00616       int n;
00617       n = GetSelections(&sels);
00618       if (n <= 1) {
00619        int i, start;
00620        if (n)
00621          start = sels[0];
00622        else
00623          start = 0;
00624        for (i = 0; i < num_choices; i++) {
00625          char *s;
00626          int j;
00627          s = GetString((start + i) % num_choices);
00628          for (j = 0; j <= typepos; j++) {
00629            if (toupper(typing[j]) != toupper(s[j]))
00630              break;
00631          }
00632          if (j > typepos) {
00633            if (n)
00634              delta = ((start + i) % num_choices) - start;
00635            else
00636              delta = i + 1;
00637            break;
00638          }
00639        }
00640        
00641        if (i == num_choices) {
00642          wxBell();
00643          return;
00644        }
00645       }
00646     }
00647     break;
00648   }
00649 
00650   if (delta && num_choices) {
00651     int *sels;
00652     int n;
00653     n = GetSelections(&sels);
00654     if (n <= 1) {
00655       int s, s2;
00656       if (n == 1)
00657        s = sels[0];
00658       else if (delta < 0)
00659        s = 2;
00660       else
00661        s = -1;
00662 
00663       s2 = s + delta;
00664       if (s2 < 0)
00665        s2 = 0;
00666       else if (s2 >= num_choices)
00667        s2 = num_choices - 1;
00668       SetSelection(s2);
00669 
00670       if (s != GetSelection()) {
00671        wxCommandEvent *event;
00672        int first, count;
00673 
00674        // Is is visible?
00675        first = GetFirstItem();
00676        count = NumberOfVisibleItems() - 1;
00677        s = GetSelection();
00678        if (s < first)
00679          SetFirstItem(s);
00680        else if (s > first + count) {
00681          SetFirstItem(s - count);
00682        }
00683 
00684        event = new wxCommandEvent(wxEVENT_TYPE_LISTBOX_COMMAND);
00685        ProcessCommand(event);
00686       }
00687     }
00688   }
00689 }