odcombo.cpp

Go to the documentation of this file.
00001 // $Id: odcombo.cpp 1496 2006-07-22 13:09:45Z alex $
00002 /* @@tag:xara-cn-tp@@ THIRD PARTY COPYRIGHT */
00003 // The following line makes normalize.pl skip type fixing
00004 /* SKIPFIXTYPES: START */
00005 
00007 // Name:        odcombo.cpp
00008 // Purpose:     wxOwnerDrawnComboBox, wxVListBoxComboPopup
00009 // Author:      Jaakko Salli
00010 // Modified by:
00011 // Created:     Apr-30-2006
00012 // RCS-ID:
00013 // Copyright:   (c) 2005 Jaakko Salli
00014 // Licence:     wxWindows licence
00016 
00017 // ============================================================================
00018 // declarations
00019 // ============================================================================
00020 
00021 // ----------------------------------------------------------------------------
00022 // headers
00023 // ----------------------------------------------------------------------------
00024 
00025 #include <wx/wx.h>
00026 
00027 #include "odcombo.h"
00028 // Only compile stuff if this is not already in WX
00029 #if wxXTRA_ODCOMBOBOX
00030 
00031 #include <wx/renderer.h>
00032 
00033 // ============================================================================
00034 // implementation
00035 // ============================================================================
00036 
00037 // time in milliseconds before partial completion buffer drops
00038 #define wxODCB_PARTIAL_COMPLETION_TIME 1000
00039 
00040 // ----------------------------------------------------------------------------
00041 // wxVListBoxComboPopup is a wxVListBox customized to act as a popup control
00042 //
00043 // ----------------------------------------------------------------------------
00044 
00045 
00046 BEGIN_EVENT_TABLE(wxVListBoxComboPopup, wxVListBox)
00047     EVT_MOTION(wxVListBoxComboPopup::OnMouseMove)
00048     EVT_KEY_DOWN(wxVListBoxComboPopup::OnKey)
00049     EVT_LEFT_UP(wxVListBoxComboPopup::OnLeftClick)
00050 END_EVENT_TABLE()
00051 
00052 
00053 void wxVListBoxComboPopup::Init()
00054 {
00055     m_widestWidth = 0;
00056     m_widestItem = -1;
00057     m_widthsDirty = false;
00058     m_findWidest = false;
00059     m_itemHeight = 0;
00060     m_value = -1;
00061     m_itemHover = -1;
00062     m_clientDataItemsType = wxClientData_None;
00063     m_partialCompletionString = wxEmptyString;
00064 }
00065 
00066 bool wxVListBoxComboPopup::Create(wxWindow* parent)
00067 {
00068     if ( !wxVListBox::Create(parent,
00069                              wxID_ANY,
00070                              wxDefaultPosition,
00071                              wxDefaultSize,
00072                              wxBORDER_SIMPLE | wxLB_INT_HEIGHT | wxWANTS_CHARS) )
00073         return false;
00074 
00075     m_useFont = m_combo->GetFont();
00076 
00077     wxVListBox::SetItemCount(m_strings.GetCount());
00078 
00079     // TODO: Move this to SetFont
00080     m_itemHeight = GetCharHeight() + 0;
00081 
00082     return true;
00083 }
00084 
00085 wxVListBoxComboPopup::~wxVListBoxComboPopup()
00086 {
00087     Clear();
00088 }
00089 
00090 bool wxVListBoxComboPopup::LazyCreate()
00091 {
00092     // NB: There is a bug with wxVListBox that can be avoided by creating
00093     //     it later (bug causes empty space to be shown if initial selection
00094     //     is at the end of a list longer than the control can show at once).
00095     return true;
00096 }
00097 
00098 // paint the control itself
00099 void wxVListBoxComboPopup::PaintComboControl( wxDC& dc, const wxRect& rect )
00100 {
00101     if ( !(m_combo->GetWindowStyle() & wxODCB_STD_CONTROL_PAINT) )
00102     {
00103         OnDrawBg(dc,rect,m_value,wxODCB_PAINTING_CONTROL);
00104         if ( m_value >= 0 )
00105         {
00106             OnDrawItem(dc,rect,m_value,wxODCB_PAINTING_CONTROL);
00107             return;
00108         }
00109     }
00110 
00111     wxComboPopup::PaintComboControl(dc,rect);
00112 }
00113 
00114 void wxVListBoxComboPopup::OnDrawItem(wxDC& dc, const wxRect& rect, size_t n) const
00115 {
00116     // TODO: Maybe this code could be moved to wxVListBox::OnPaint?
00117     dc.SetFont(m_useFont);
00118 
00119     // Set correct text colour for selected items
00120     if ( wxVListBox::GetSelection() == (int) n )
00121         dc.SetTextForeground( wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT) );
00122     else
00123         dc.SetTextForeground( wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT) );
00124 
00125     OnDrawItem(dc,rect,(int)n,0);
00126 }
00127 
00128 wxCoord wxVListBoxComboPopup::OnMeasureItem(size_t n) const
00129 {
00130     wxOwnerDrawnComboBox* combo = (wxOwnerDrawnComboBox*) m_combo;
00131 
00132     wxASSERT_MSG( combo->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox)),
00133                   wxT("you must subclass wxVListBoxComboPopup for drawing and measuring methods") );
00134 
00135     wxCoord h = combo->OnMeasureItem(n);
00136     if ( h < 0 )
00137         h = m_itemHeight;
00138     return h;
00139 }
00140 
00141 wxCoord wxVListBoxComboPopup::OnMeasureItemWidth(size_t n) const
00142 {
00143     wxOwnerDrawnComboBox* combo = (wxOwnerDrawnComboBox*) m_combo;
00144 
00145     wxASSERT_MSG( combo->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox)),
00146                   wxT("you must subclass wxVListBoxComboPopup for drawing and measuring methods") );
00147 
00148     return combo->OnMeasureItemWidth(n);
00149 }
00150 
00151 void wxVListBoxComboPopup::OnDrawBg( wxDC& dc,
00152                                      const wxRect& rect,
00153                                      int item,
00154                                      int flags ) const
00155 {
00156     wxOwnerDrawnComboBox* combo = (wxOwnerDrawnComboBox*) m_combo;
00157 
00158     wxASSERT_MSG( combo->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox)),
00159                   wxT("you must subclass wxVListBoxComboPopup for drawing and measuring methods") );
00160 
00161     combo->OnDrawBackground(dc,rect,item,flags);
00162 }
00163 
00164 void wxVListBoxComboPopup::OnDrawBackground(wxDC& dc, const wxRect& rect, size_t n) const
00165 {
00166     OnDrawBg(dc,rect,(int)n,0);
00167 }
00168 
00169 // This is called from wxVListBoxComboPopup::OnDrawItem, with text colour and font prepared
00170 void wxVListBoxComboPopup::OnDrawItem( wxDC& dc, const wxRect& rect, int item, int flags ) const
00171 {
00172     wxOwnerDrawnComboBox* combo = (wxOwnerDrawnComboBox*) m_combo;
00173 
00174     wxASSERT_MSG( combo->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox)),
00175                   wxT("you must subclass wxVListBoxComboPopup for drawing and measuring methods") );
00176 
00177     combo->OnDrawItem(dc,rect,item,flags);
00178 }
00179 
00180 void wxVListBoxComboPopup::DismissWithEvent()
00181 {
00182     StopPartialCompletion();
00183 
00184     int selection = wxVListBox::GetSelection();
00185 
00186     Dismiss();
00187 
00188     wxString valStr;
00189     if ( selection != wxNOT_FOUND )
00190         valStr = m_strings[selection];
00191     else
00192         valStr = wxEmptyString;
00193 
00194     m_value = selection;
00195 
00196     if ( valStr != m_combo->GetValue() )
00197         m_combo->SetValue(valStr);
00198 
00199     SendComboBoxEvent(selection);
00200 }
00201 
00202 void wxVListBoxComboPopup::SendComboBoxEvent( int selection )
00203 {
00204     wxCommandEvent evt(wxEVT_COMMAND_COMBOBOX_SELECTED,m_combo->GetId());
00205 
00206     evt.SetEventObject(m_combo);
00207 
00208     evt.SetInt(selection);
00209 
00210     // Set client data, if any
00211     if ( selection >= 0 && (int)m_clientDatas.GetCount() > selection )
00212     {
00213         void* clientData = m_clientDatas[selection];
00214         if ( m_clientDataItemsType == wxClientData_Object )
00215             evt.SetClientObject((wxClientData*)clientData);
00216         else
00217             evt.SetClientData(clientData);
00218     }
00219 
00220     m_combo->GetEventHandler()->AddPendingEvent(evt);
00221 }
00222 
00223 // returns true if key was consumed
00224 bool wxVListBoxComboPopup::HandleKey( int keycode, bool saturate, wxChar unicode )
00225 {
00226     int value = m_value;
00227     int itemCount = GetCount();
00228     int comboStyle = m_combo->GetWindowStyle();
00229 
00230     // this is the character equivalent of the code
00231     wxChar keychar=0;
00232     if ((keycode >= WXK_SPACE) && (keycode <=255) && (keycode != WXK_DELETE) && wxIsprint(keycode))
00233     {
00234         keychar = (wxChar)keycode;
00235     }
00236     else if (unicode>0)
00237     {
00238         keychar = unicode; 
00239     }
00240 
00241     if ( keycode == WXK_DOWN || keycode == WXK_RIGHT )
00242     {
00243         value++;
00244         StopPartialCompletion();
00245     }
00246     else if ( keycode == WXK_UP || keycode == WXK_LEFT )
00247     {
00248         value--;
00249         StopPartialCompletion();
00250     }
00251     else if ( keycode == WXK_PAGEDOWN )
00252     {
00253         value+=10;
00254         StopPartialCompletion();
00255     }
00256     else if ( keycode == WXK_PAGEUP )
00257     {
00258         value-=10;
00259         StopPartialCompletion();
00260     }
00261     else if ( comboStyle & wxCB_READONLY )
00262     {
00263         // Try partial completion
00264 
00265         // find the new partial completion string
00266 #if wxUSE_TIMER
00267         if (m_partialCompletionTimer.IsRunning())
00268             m_partialCompletionString+=wxString(keychar);
00269         else
00270 #endif // wxUSE_TIMER
00271             m_partialCompletionString=wxString(keychar);
00272 
00273         // now search through the values to see if this is found
00274         int found = -1;
00275         unsigned int length=m_partialCompletionString.Length();
00276         int i;
00277         for (i=0; i<itemCount; i++)
00278         {
00279             wxString item=GetString(i);
00280             if (( item.Length() >=length) && (!  m_partialCompletionString.CmpNoCase(item.Left(length))))
00281             {
00282                 found=i;
00283                 break;
00284             }
00285         }
00286 
00287         if (found<0)
00288         {
00289             StopPartialCompletion();
00290             ::wxBell();
00291             return true; // to stop the first value being set
00292         }
00293         else
00294         {
00295             value=i;
00296 #if wxUSE_TIMER
00297             m_partialCompletionTimer.Start(wxODCB_PARTIAL_COMPLETION_TIME, true);
00298 #endif // wxUSE_TIMER
00299         }
00300     }
00301     else
00302         return false;
00303 
00304     if ( saturate )
00305     {
00306         if ( value >= itemCount )
00307             value = itemCount - 1;
00308         else if ( value < 0 )
00309             value = 0;
00310     }
00311     else
00312     {
00313         if ( value >= itemCount )
00314             value -= itemCount;
00315         else if ( value < 0 )
00316             value += itemCount;
00317     }
00318 
00319     if ( value == m_value )
00320         // Even if value was same, don't skip the event
00321         // (good for consistency)
00322         return true;
00323 
00324     m_value = value;
00325 
00326     if ( value >= 0 )
00327         m_combo->SetValue(m_strings[value]);
00328 
00329     SendComboBoxEvent(m_value);
00330 
00331     return true;
00332 }
00333 
00334 // stop partial completion
00335 void wxVListBoxComboPopup::StopPartialCompletion()
00336 {
00337     m_partialCompletionString = wxEmptyString;
00338 #if wxUSE_TIMER
00339     m_partialCompletionTimer.Stop();
00340 #endif // wxUSE_TIMER
00341 }
00342 
00343 void wxVListBoxComboPopup::OnComboDoubleClick()
00344 {
00345     // Cycle on dclick (disable saturation to allow true cycling).
00346     if ( !::wxGetKeyState(WXK_SHIFT) )
00347         HandleKey(WXK_DOWN,false);
00348     else
00349         HandleKey(WXK_UP,false);
00350 }
00351 
00352 void wxVListBoxComboPopup::OnComboKeyEvent( wxKeyEvent& event )
00353 {
00354     // Saturated key movement on
00355     if ( !HandleKey(event.GetKeyCode(),true,
00356 #if wxUSE_UNICODE
00357         event.GetUnicodeKey()
00358 #else
00359         0
00360 #endif
00361         ) )
00362         event.Skip();
00363 }
00364 
00365 void wxVListBoxComboPopup::OnPopup()
00366 {
00367     // *must* set value after size is set (this is because of a vlbox bug)
00368     wxVListBox::SetSelection(m_value);
00369 }
00370 
00371 void wxVListBoxComboPopup::OnMouseMove(wxMouseEvent& event)
00372 {
00373     event.Skip();
00374 
00375     // Move selection to cursor if it is inside the popup
00376 
00377     int y = event.GetPosition().y;
00378     int fromBottom = GetClientSize().y - y;
00379 
00380     // Since in any case we need to find out if the last item is only
00381     // partially visible, we might just as well replicate the HitTest
00382     // loop here.
00383     const size_t lineMax = GetVisibleEnd();
00384     for ( size_t line = GetVisibleBegin(); line < lineMax; line++ )
00385     {
00386         y -= OnGetLineHeight(line);
00387         if ( y < 0 )
00388         {
00389             // Only change selection if item is fully visible
00390             if ( (y + fromBottom) >= 0 )
00391             {
00392                 wxVListBox::SetSelection((int)line);
00393                 return;
00394             }
00395         }
00396     }
00397 }
00398 
00399 void wxVListBoxComboPopup::OnLeftClick(wxMouseEvent& WXUNUSED(event))
00400 {
00401     DismissWithEvent();
00402 }
00403 
00404 void wxVListBoxComboPopup::OnKey(wxKeyEvent& event)
00405 {
00406     // Select item if ENTER is pressed
00407     if ( event.GetKeyCode() == WXK_RETURN || event.GetKeyCode() == WXK_NUMPAD_ENTER )
00408     {
00409         DismissWithEvent();
00410     }
00411     // Hide popup if ESC is pressed
00412     else if ( event.GetKeyCode() == WXK_ESCAPE )
00413     {
00414         StopPartialCompletion();
00415         Dismiss();
00416     }
00417     else
00418     {
00419         int comboStyle = m_combo->GetWindowStyle();
00420         int keycode = event.GetKeyCode();
00421         // Process partial completion key codes here, but not the arrow keys as the base class will do that for us
00422         if ((comboStyle & wxCB_READONLY) &&
00423             (keycode >= WXK_SPACE) && (keycode <=255) && (keycode != WXK_DELETE) && wxIsprint(keycode))
00424         {
00425             OnComboKeyEvent(event);
00426             SetSelection(m_value); // ensure the highlight bar moves
00427         }
00428         else
00429             event.Skip();
00430     }
00431 }
00432 
00433 void wxVListBoxComboPopup::Insert( const wxString& item, int pos )
00434 {
00435     // Need to change selection?
00436     wxString strValue;
00437     if ( !(m_combo->GetWindowStyle() & wxCB_READONLY) &&
00438          m_combo->GetValue() == item )
00439     {
00440         m_value = pos;
00441     }
00442 
00443     m_strings.Insert(item,pos);
00444     m_widths.Insert(-1,pos);
00445     m_widthsDirty = true;
00446 
00447     if ( IsCreated() )
00448         wxVListBox::SetItemCount( wxVListBox::GetItemCount()+1 );
00449 }
00450 
00451 int wxVListBoxComboPopup::Append(const wxString& item)
00452 {
00453     int pos = (int)m_strings.GetCount();
00454 
00455     if ( m_combo->GetWindowStyle() & wxCB_SORT )
00456     {
00457         // Find position
00458         // TODO: Could be optimized with binary search
00459         wxArrayString strings = m_strings;
00460         unsigned int i;
00461 
00462         for ( i=0; i<strings.GetCount(); i++ )
00463         {
00464             if ( item.Cmp(strings.Item(i)) < 0 )
00465             {
00466                 pos = (int)i;
00467                 break;
00468             }
00469         }
00470     }
00471 
00472     Insert(item,pos);
00473 
00474     return pos;
00475 }
00476 
00477 void wxVListBoxComboPopup::Clear()
00478 {
00479     wxASSERT(m_combo);
00480 
00481     m_strings.Empty();
00482     m_widths.Empty();
00483 
00484     m_widestWidth = 0;
00485     m_widestItem = -1;
00486 
00487     ClearClientDatas();
00488 
00489     m_value = wxNOT_FOUND;
00490 
00491     if ( IsCreated() )
00492         wxVListBox::SetItemCount(0);
00493 }
00494 
00495 void wxVListBoxComboPopup::ClearClientDatas()
00496 {
00497     if ( m_clientDataItemsType == wxClientData_Object )
00498     {
00499         size_t i;
00500         for ( i=0; i<m_clientDatas.GetCount(); i++ )
00501             delete (wxClientData*) m_clientDatas[i];
00502     }
00503 
00504     m_clientDatas.Empty();
00505 }
00506 
00507 void wxVListBoxComboPopup::SetItemClientData( unsigned int n,
00508                                               void* clientData,
00509                                               wxClientDataType clientDataItemsType )
00510 {
00511     // It should be sufficient to update this variable only here
00512     m_clientDataItemsType = clientDataItemsType;
00513 
00514     m_clientDatas.SetCount(n+1,NULL);
00515     m_clientDatas[n] = clientData;
00516 
00517     ItemWidthChanged(n);
00518 }
00519 
00520 void* wxVListBoxComboPopup::GetItemClientData(unsigned int n) const
00521 {
00522     if ( m_clientDatas.GetCount() > n )
00523         return m_clientDatas[n];
00524 
00525     return NULL;
00526 }
00527 
00528 void wxVListBoxComboPopup::Delete( unsigned int item )
00529 {
00530     // Remove client data, if set
00531     if ( m_clientDatas.GetCount() )
00532     {
00533         if ( m_clientDataItemsType == wxClientData_Object )
00534             delete (wxClientData*) m_clientDatas[item];
00535 
00536         m_clientDatas.RemoveAt(item);
00537     }
00538 
00539     m_strings.RemoveAt(item);
00540     m_widths.RemoveAt(item);
00541 
00542     if ( (int)item == m_widestItem )
00543         m_findWidest = true;
00544 
00545     if ( IsCreated() )
00546         wxVListBox::SetItemCount( wxVListBox::GetItemCount()-1 );
00547 }
00548 
00549 int wxVListBoxComboPopup::FindString(const wxString& s, bool bCase) const
00550 {
00551     return m_strings.Index(s, bCase);
00552 }
00553 
00554 unsigned int wxVListBoxComboPopup::GetCount() const
00555 {
00556     return m_strings.GetCount();
00557 }
00558 
00559 wxString wxVListBoxComboPopup::GetString( int item ) const
00560 {
00561     return m_strings[item];
00562 }
00563 
00564 void wxVListBoxComboPopup::SetString( int item, const wxString& str )
00565 {
00566     m_strings[item] = str;
00567     ItemWidthChanged(item);
00568 }
00569 
00570 wxString wxVListBoxComboPopup::GetStringValue() const
00571 {
00572     if ( m_value >= 0 )
00573         return m_strings[m_value];
00574     return wxEmptyString;
00575 }
00576 
00577 void wxVListBoxComboPopup::SetSelection( int item )
00578 {
00579     wxCHECK_RET( item == wxNOT_FOUND || ((unsigned int)item < GetCount()),
00580                  wxT("invalid index in wxVListBoxComboPopup::SetSelection") );
00581 
00582     m_value = item;
00583 
00584     if ( IsCreated() )
00585         wxVListBox::SetSelection(item);
00586 }
00587 
00588 int wxVListBoxComboPopup::GetSelection() const
00589 {
00590     return m_value;
00591 }
00592 
00593 void wxVListBoxComboPopup::SetStringValue( const wxString& value )
00594 {
00595     int index = m_strings.Index(value);
00596 
00597     m_value = index;
00598 
00599     if ( index >= -1 && index < (int)wxVListBox::GetItemCount() )
00600         wxVListBox::SetSelection(index);
00601 }
00602 
00603 void wxVListBoxComboPopup::CalcWidths()
00604 {
00605     bool doFindWidest = m_findWidest;
00606 
00607     // Measure items with dirty width.
00608     if ( m_widthsDirty )
00609     {
00610         unsigned int i;
00611         unsigned int n = m_widths.GetCount();
00612         int dirtyHandled = 0;
00613         wxArrayInt& widths = m_widths;
00614 
00615         // I think using wxDC::GetTextExtent is faster than
00616         // wxWindow::GetTextExtent (assuming same dc is used
00617         // for all calls, as we do here).
00618         wxClientDC dc(m_combo);
00619         dc.SetFont(m_useFont);
00620 
00621         for ( i=0; i<n; i++ )
00622         {
00623             if ( widths[i] < 0 )
00624             {
00625                 wxCoord x = OnMeasureItemWidth(i);
00626 
00627                 if ( x < 0 )
00628                 {
00629                     const wxString& text = m_strings[i];
00630 
00631                     // To make sure performance won't suck in extreme scenarios,
00632                     // we'll estimate length after some arbitrary number of items
00633                     // have been checked precily.
00634                     if ( dirtyHandled < 1024 )
00635                     {
00636                         wxCoord y;
00637                         dc.GetTextExtent(text, &x, &y, 0, 0);
00638                         x += 4;
00639                     }
00640                     else
00641                     {
00642                         x = text.length() * (dc.GetCharWidth()+1);
00643                     }
00644                 }
00645 
00646                 widths[i] = x;
00647 
00648                 if ( x >= m_widestWidth )
00649                 {
00650                     m_widestWidth = x;
00651                     m_widestItem = (int)i;
00652                 }
00653                 else if ( (int)i == m_widestItem )
00654                 {
00655                     // Width of previously widest item has been decreased, so
00656                     // we'll have to check all to find current widest item.
00657                     doFindWidest = true;
00658                 }
00659 
00660                 dirtyHandled++;
00661             }
00662         }
00663 
00664         m_widthsDirty = false;
00665     }
00666 
00667     if ( doFindWidest )
00668     {
00669         unsigned int i;
00670         unsigned int n = m_widths.GetCount();
00671 
00672         int bestWidth = -1;
00673         int bestIndex = -1;
00674 
00675         for ( i=0; i<n; i++ )
00676         {
00677             int w = m_widths[i];
00678             if ( w > bestWidth )
00679             {
00680                 bestIndex = (int)i;
00681                 bestWidth = w;
00682             }
00683         }
00684 
00685         m_widestWidth = bestWidth;
00686         m_widestItem = bestIndex;
00687 
00688         m_findWidest = false;
00689     }
00690 }
00691 
00692 wxSize wxVListBoxComboPopup::GetAdjustedSize( int minWidth, int prefHeight, int maxHeight )
00693 {
00694     int height = 250;
00695 
00696     if ( m_strings.GetCount() )
00697     {
00698         if ( prefHeight > 0 )
00699             height = prefHeight;
00700 
00701         if ( height > maxHeight )
00702             height = maxHeight;
00703 
00704         int totalHeight = GetTotalHeight(); // + 3;
00705         if ( height >= totalHeight )
00706         {
00707             height = totalHeight;
00708         }
00709         else
00710         {
00711             // Adjust height to a multiple of the height of the first item
00712             // NB: Calculations that take variable height into account
00713             //     are unnecessary.
00714             int fih = GetLineHeight(0);
00715             int shown = height/fih;
00716             height = shown * fih;
00717         }
00718     }
00719     else
00720         height = 50;
00721 
00722     CalcWidths();
00723 
00724     // Take scrollbar into account in width calculations
00725     int widestWidth = m_widestWidth + wxSystemSettings::GetMetric(wxSYS_VSCROLL_X);
00726     return wxSize(minWidth > widestWidth ? minWidth : widestWidth,
00727                   height+2);
00728 }
00729 
00730 //void wxVListBoxComboPopup::Populate( int n, const wxString choices[] )
00731 void wxVListBoxComboPopup::Populate( const wxArrayString& choices )
00732 {
00733     int i;
00734 
00735     int n = choices.GetCount();
00736 
00737     for ( i=0; i<n; i++ )
00738     {
00739         const wxString& item = choices.Item(i);
00740         m_strings.Add(item);
00741     }
00742 
00743     m_widths.SetCount(n,-1);
00744     m_widthsDirty = true;
00745 
00746     if ( IsCreated() )
00747         wxVListBox::SetItemCount(n);
00748 
00749     // Sort the initial choices
00750     if ( m_combo->GetWindowStyle() & wxCB_SORT )
00751         m_strings.Sort();
00752 
00753     // Find initial selection
00754     wxString strValue = m_combo->GetValue();
00755     if ( strValue.length() )
00756         m_value = m_strings.Index(strValue);
00757 }
00758 
00759 // ----------------------------------------------------------------------------
00760 // wxOwnerDrawnComboBox
00761 // ----------------------------------------------------------------------------
00762 
00763 
00764 BEGIN_EVENT_TABLE(wxOwnerDrawnComboBox, wxComboCtrl)
00765 END_EVENT_TABLE()
00766 
00767 
00768 IMPLEMENT_DYNAMIC_CLASS2(wxOwnerDrawnComboBox, wxComboCtrl, wxControlWithItems)
00769 
00770 void wxOwnerDrawnComboBox::Init()
00771 {
00772 }
00773 
00774 bool wxOwnerDrawnComboBox::Create(wxWindow *parent,
00775                                   wxWindowID id,
00776                                   const wxString& value,
00777                                   const wxPoint& pos,
00778                                   const wxSize& size,
00779                                   long style,
00780                                   const wxValidator& validator,
00781                                   const wxString& name)
00782 {
00783     return wxComboCtrl::Create(parent,id,value,pos,size,style,validator,name);
00784 }
00785 
00786 wxOwnerDrawnComboBox::wxOwnerDrawnComboBox(wxWindow *parent,
00787                                            wxWindowID id,
00788                                            const wxString& value,
00789                                            const wxPoint& pos,
00790                                            const wxSize& size,
00791                                            const wxArrayString& choices,
00792                                            long style,
00793                                            const wxValidator& validator,
00794                                            const wxString& name)
00795     : wxComboCtrl()
00796 {
00797     Init();
00798 
00799     Create(parent,id,value,pos,size,choices,style, validator, name);
00800 }
00801 
00802 bool wxOwnerDrawnComboBox::Create(wxWindow *parent,
00803                                   wxWindowID id,
00804                                   const wxString& value,
00805                                   const wxPoint& pos,
00806                                   const wxSize& size,
00807                                   const wxArrayString& choices,
00808                                   long style,
00809                                   const wxValidator& validator,
00810                                   const wxString& name)
00811 {
00812     m_initChs = choices;
00813     //wxCArrayString chs(choices);
00814 
00815     //return Create(parent, id, value, pos, size, chs.GetCount(),
00816     //              chs.GetStrings(), style, validator, name);
00817     return Create(parent, id, value, pos, size, 0,
00818                   NULL, style, validator, name);
00819 }
00820 
00821 bool wxOwnerDrawnComboBox::Create(wxWindow *parent,
00822                                   wxWindowID id,
00823                                   const wxString& value,
00824                                   const wxPoint& pos,
00825                                   const wxSize& size,
00826                                   int n,
00827                                   const wxString choices[],
00828                                   long style,
00829                                   const wxValidator& validator,
00830                                   const wxString& name)
00831 {
00832 
00833     if ( !Create(parent, id, value, pos, size, style,
00834                  validator, name) )
00835     {
00836         return false;
00837     }
00838 
00839     int i;
00840     for ( i=0; i<n; i++ )
00841         m_initChs.Add(choices[i]);
00842 
00843     return true;
00844 }
00845 
00846 wxOwnerDrawnComboBox::~wxOwnerDrawnComboBox()
00847 {
00848     if ( m_popupInterface )
00849         GetVListBoxComboPopup()->ClearClientDatas();
00850 }
00851 
00852 void wxOwnerDrawnComboBox::DoSetPopupControl(wxComboPopup* popup)
00853 {
00854     if ( !popup )
00855     {
00856         popup = new wxVListBoxComboPopup();
00857     }
00858 
00859     wxComboCtrl::DoSetPopupControl(popup);
00860 
00861     wxASSERT(popup);
00862 
00863     // Add initial choices to the wxVListBox
00864     if ( !GetVListBoxComboPopup()->GetCount() )
00865     {
00866         GetVListBoxComboPopup()->Populate(m_initChs);
00867         m_initChs.Clear();
00868     }
00869 }
00870 
00871 // ----------------------------------------------------------------------------
00872 // wxOwnerDrawnComboBox item manipulation methods
00873 // ----------------------------------------------------------------------------
00874 
00875 void wxOwnerDrawnComboBox::Clear()
00876 {
00877     EnsurePopupControl();
00878 
00879     GetVListBoxComboPopup()->Clear();
00880 
00881     SetValue(wxEmptyString);
00882 }
00883 
00884 void wxOwnerDrawnComboBox::Delete(wxIndex n)
00885 {
00886     wxCHECK_RET( IsValid(n), _T("invalid index in wxOwnerDrawnComboBox::Delete") );
00887 
00888     if ( GetSelection() == (int) n )
00889         SetValue(wxEmptyString);
00890 
00891     GetVListBoxComboPopup()->Delete(n);
00892 }
00893 
00894 wxIndex wxOwnerDrawnComboBox::GetCount() const
00895 {
00896     if ( !m_popupInterface )
00897         return m_initChs.GetCount();
00898 
00899     return GetVListBoxComboPopup()->GetCount();
00900 }
00901 
00902 wxString wxOwnerDrawnComboBox::GetString(wxIndex n) const
00903 {
00904     wxCHECK_MSG( IsValid(n), wxEmptyString, _T("invalid index in wxOwnerDrawnComboBox::GetString") );
00905 
00906     if ( !m_popupInterface )
00907         return m_initChs.Item(n);
00908 
00909     return GetVListBoxComboPopup()->GetString(n);
00910 }
00911 
00912 void wxOwnerDrawnComboBox::SetString(wxIndex n, const wxString& s)
00913 {
00914     EnsurePopupControl();
00915 
00916     wxCHECK_RET( IsValid(n), _T("invalid index in wxOwnerDrawnComboBox::SetString") );
00917 
00918     GetVListBoxComboPopup()->SetString(n,s);
00919 }
00920 
00921 int wxOwnerDrawnComboBox::FindString(const wxString& s, bool bCase) const
00922 {
00923     if ( !m_popupInterface )
00924         return m_initChs.Index(s, bCase);
00925 
00926     return GetVListBoxComboPopup()->FindString(s, bCase);
00927 }
00928 
00929 void wxOwnerDrawnComboBox::Select(int n)
00930 {
00931     EnsurePopupControl();
00932 
00933     wxCHECK_RET( (n == wxNOT_FOUND) || IsValid(n), _T("invalid index in wxOwnerDrawnComboBox::Select") );
00934 
00935     GetVListBoxComboPopup()->SetSelection(n);
00936 
00937     wxString str;
00938     if ( n >= 0 )
00939         str = GetVListBoxComboPopup()->GetString(n);
00940 
00941     // Refresh text portion in control
00942     if ( m_text )
00943         m_text->SetValue( str );
00944     else
00945         m_valueString = str;
00946 
00947     Refresh();
00948 }
00949 
00950 int wxOwnerDrawnComboBox::GetSelection() const
00951 {
00952     if ( !m_popupInterface )
00953         return m_initChs.Index(m_valueString);
00954 
00955     return GetVListBoxComboPopup()->GetSelection();
00956 }
00957 
00958 int wxOwnerDrawnComboBox::DoAppend(const wxString& item)
00959 {
00960     EnsurePopupControl();
00961     wxASSERT(m_popupInterface);
00962 
00963     return GetVListBoxComboPopup()->Append(item);
00964 }
00965 
00966 int wxOwnerDrawnComboBox::DoInsert(const wxString& item, wxIndex pos)
00967 {
00968     EnsurePopupControl();
00969 
00970     wxCHECK_MSG(!(GetWindowStyle() & wxCB_SORT), -1, wxT("can't insert into sorted list"));
00971 #if 0
00972     wxCHECK_MSG(IsValidInsert(pos), -1, wxT("invalid index"));
00973 #endif
00974 
00975     GetVListBoxComboPopup()->Insert(item,pos);
00976 
00977     return pos;
00978 }
00979 
00980 void wxOwnerDrawnComboBox::DoSetItemClientData(wxIndex n, void* clientData)
00981 {
00982     EnsurePopupControl();
00983 
00984     GetVListBoxComboPopup()->SetItemClientData(n,clientData,m_clientDataItemsType);
00985 }
00986 
00987 void* wxOwnerDrawnComboBox::DoGetItemClientData(wxIndex n) const
00988 {
00989     if ( !m_popupInterface )
00990         return NULL;
00991 
00992     return GetVListBoxComboPopup()->GetItemClientData(n);
00993 }
00994 
00995 void wxOwnerDrawnComboBox::DoSetItemClientObject(wxIndex n, wxClientData* clientData)
00996 {
00997     DoSetItemClientData(n, (void*) clientData);
00998 }
00999 
01000 wxClientData* wxOwnerDrawnComboBox::DoGetItemClientObject(wxIndex n) const
01001 {
01002     return (wxClientData*) DoGetItemClientData(n);
01003 }
01004 
01005 // ----------------------------------------------------------------------------
01006 // wxOwnerDrawnComboBox item drawing and measuring default implementations
01007 // ----------------------------------------------------------------------------
01008 
01009 void wxOwnerDrawnComboBox::OnDrawItem( wxDC& dc,
01010                                        const wxRect& rect,
01011                                        int item,
01012                                        int flags ) const
01013 {
01014     if ( flags & wxODCB_PAINTING_CONTROL )
01015     {
01016         dc.DrawText( GetValue(),
01017                      rect.x + GetTextIndent(),
01018                      (rect.height-dc.GetCharHeight())/2 + rect.y );
01019     }
01020     else
01021     {
01022         dc.DrawText( GetVListBoxComboPopup()->GetString(item), rect.x + 2, rect.y );
01023     }
01024 }
01025 
01026 wxCoord wxOwnerDrawnComboBox::OnMeasureItem( size_t WXUNUSED(item) ) const
01027 {
01028     return -1;
01029 }
01030 
01031 wxCoord wxOwnerDrawnComboBox::OnMeasureItemWidth( size_t WXUNUSED(item) ) const
01032 {
01033     return -1;
01034 }
01035 
01036 void wxOwnerDrawnComboBox::OnDrawBackground(wxDC& dc, const wxRect& rect, int item, int flags) const
01037 {
01038     // we need to render selected and current items differently
01039     if ( GetVListBoxComboPopup()->IsCurrent((size_t)item) ||
01040          (flags & wxODCB_PAINTING_CONTROL) )
01041     {
01042         DrawFocusBackground(dc,
01043                             rect,
01044                             (flags&wxODCB_PAINTING_CONTROL?0:wxCONTROL_ISSUBMENU) |
01045                             wxCONTROL_SELECTED);
01046     }
01047     //else: do nothing for the normal items
01048 }
01049 
01050 #endif // wxXTRA_OWNERDRAWNCOMBOBOX

Generated on Sat Nov 10 03:49:02 2007 for Camelot by  doxygen 1.4.4