1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        combo.cpp
3 // Purpose:     wxComboCtrl sample
4 // Author:      Jaakko Salli
5 // Modified by:
6 // Created:     Apr-30-2006
7 // RCS-ID:      $Id: combo.cpp 64398 2010-05-26 15:12:03Z JMS $
8 // Copyright:   (c) Jaakko Salli
9 // Licence:     wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11 
12 // ============================================================================
13 // declarations
14 // ============================================================================
15 
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19 
20 // For compilers that support precompilation, includes "wx/wx.h".
21 #include "wx/wxprec.h"
22 
23 #ifdef __BORLANDC__
24     #pragma hdrstop
25 #endif
26 
27 // for all others, include the necessary headers (this file is usually all you
28 // need because it includes almost all "standard" wxWidgets headers)
29 #ifndef WX_PRECOMP
30     #include "wx/wx.h"
31 #endif
32 
33 #if !wxUSE_COMBOCTRL
34     #error "Please set wxUSE_COMBOCTRL to 1 and rebuild the library."
35 #endif
36 
37 #include "wx/image.h"
38 
39 #include "wx/combo.h"
40 #include "wx/odcombo.h"
41 
42 // ----------------------------------------------------------------------------
43 // resources
44 // ----------------------------------------------------------------------------
45 
46 // the application icon (under Windows and OS/2 it is in resources and even
47 // though we could still include the XPM here it would be unused)
48 #if !defined(__WXMSW__) && !defined(__WXPM__)
49     #include "../sample.xpm"
50 #endif
51 
52 // ----------------------------------------------------------------------------
53 // private classes
54 // ----------------------------------------------------------------------------
55 
56 // Define a new application type, each program should derive a class from wxApp
57 class MyApp : public wxApp
58 {
59 public:
60     // override base class virtuals
61     // ----------------------------
62 
63     // this one is called on application startup and is a good place for the app
64     // initialization (doing it here and not in the ctor allows to have an error
65     // return: if OnInit() returns false, the application terminates)
66     virtual bool OnInit();
67 };
68 
69 // Define a new frame type: this is going to be our main frame
70 class MyFrame : public wxFrame
71 {
72 public:
73     // ctor and dtor
74     MyFrame(const wxString& title);
75     ~MyFrame();
76 
77     // event handlers (these functions should _not_ be virtual)
78     void OnQuit(wxCommandEvent& event);
79     void OnAbout(wxCommandEvent& event);
80 
81     void OnShowComparison( wxCommandEvent& event );
82 
83     // log wxComboCtrl events
84     void OnComboBoxUpdate( wxCommandEvent& event );
85 
86     void OnIdle( wxIdleEvent& event );
87 
88 
89     wxCheckBox*     m_cbUseAnim;
90 
91 protected:
92     wxTextCtrl*     m_logWin;
93     wxLog*          m_logOld;
94 
95     // Common list of items for all dialogs.
96     wxArrayString   m_arrItems;
97 
98 private:
99     // any class wishing to process wxWidgets events must use this macro
100     DECLARE_EVENT_TABLE()
101 };
102 
103 // ----------------------------------------------------------------------------
104 // constants
105 // ----------------------------------------------------------------------------
106 
107 // IDs for the controls and the menu commands
108 enum
109 {
110     ComboCtrl_Compare = wxID_HIGHEST,
111 
112     // menu items
113     ComboCtrl_Quit = wxID_EXIT,
114 
115     // it is important for the id corresponding to the "About" command to have
116     // this standard value as otherwise it won't be handled properly under Mac
117     // (where it is special and put into the "Apple" menu)
118     ComboCtrl_About = wxID_ABOUT
119 };
120 
121 // ----------------------------------------------------------------------------
122 // event tables and other macros for wxWidgets
123 // ----------------------------------------------------------------------------
124 
125 // the event tables connect the wxWidgets events with the functions (event
126 // handlers) which process them. It can be also done at run-time, but for the
127 // simple menu events like this the static method is much simpler.
BEGIN_EVENT_TABLE(MyFrame,wxFrame)128 BEGIN_EVENT_TABLE(MyFrame, wxFrame)
129     EVT_TEXT(wxID_ANY,MyFrame::OnComboBoxUpdate)
130     EVT_COMBOBOX(wxID_ANY,MyFrame::OnComboBoxUpdate)
131 
132     EVT_MENU(ComboCtrl_Compare,  MyFrame::OnShowComparison)
133     EVT_MENU(ComboCtrl_Quit,     MyFrame::OnQuit)
134     EVT_MENU(ComboCtrl_About,    MyFrame::OnAbout)
135 
136     EVT_IDLE(MyFrame::OnIdle)
137 END_EVENT_TABLE()
138 
139 // Create a new application object: this macro will allow wxWidgets to create
140 // the application object during program execution (it's better than using a
141 // static object for many reasons) and also implements the accessor function
142 // wxGetApp() which will return the reference of the right type (i.e. MyApp and
143 // not wxApp)
144 IMPLEMENT_APP(MyApp)
145 
146 // ============================================================================
147 // implementation
148 // ============================================================================
149 
150 // ----------------------------------------------------------------------------
151 // the application class
152 // ----------------------------------------------------------------------------
153 
154 // 'Main program' equivalent: the program execution "starts" here
155 bool MyApp::OnInit()
156 {
157     // create the main application window
158     MyFrame *frame = new MyFrame(_T("wxComboCtrl and wxOwnerDrawnComboBox Sample"));
159 
160     // and show it (the frames, unlike simple controls, are not shown when
161     // created initially)
162     frame->Show(true);
163 
164     // success: wxApp::OnRun() will be called which will enter the main message
165     // loop and the application will run. If we returned false here, the
166     // application would exit immediately.
167     return true;
168 }
169 
170 
171 // ----------------------------------------------------------------------------
172 // wxOwnerDrawnComboBox with custom paint list items
173 // ----------------------------------------------------------------------------
174 
175 class wxPenStyleComboBox : public wxOwnerDrawnComboBox
176 {
177 public:
OnDrawItem(wxDC & dc,const wxRect & rect,int item,int flags) const178     virtual void OnDrawItem( wxDC& dc,
179                              const wxRect& rect,
180                              int item,
181                              int flags ) const
182     {
183         if ( item == wxNOT_FOUND )
184             return;
185 
186         wxRect r(rect);
187         r.Deflate(3);
188         r.height -= 2;
189 
190         int penStyle = wxSOLID;
191         if ( item == 1 )
192             penStyle = wxTRANSPARENT;
193         else if ( item == 2 )
194             penStyle = wxDOT;
195         else if ( item == 3 )
196             penStyle = wxLONG_DASH;
197         else if ( item == 4 )
198             penStyle = wxSHORT_DASH;
199         else if ( item == 5 )
200             penStyle = wxDOT_DASH;
201         else if ( item == 6 )
202             penStyle = wxBDIAGONAL_HATCH;
203         else if ( item == 7 )
204             penStyle = wxCROSSDIAG_HATCH;
205         else if ( item == 8 )
206             penStyle = wxFDIAGONAL_HATCH;
207         else if ( item == 9 )
208             penStyle = wxCROSS_HATCH;
209         else if ( item == 10 )
210             penStyle = wxHORIZONTAL_HATCH;
211         else if ( item == 11 )
212             penStyle = wxVERTICAL_HATCH;
213 
214         wxPen pen( dc.GetTextForeground(), 3, penStyle );
215 
216         // Get text colour as pen colour
217         dc.SetPen( pen );
218 
219         if ( !(flags & wxODCB_PAINTING_CONTROL) )
220         {
221             dc.DrawText(GetString( item ),
222                         r.x + 3,
223                         (r.y + 0) + ( (r.height/2) - dc.GetCharHeight() )/2
224                        );
225 
226             dc.DrawLine( r.x+5, r.y+((r.height/4)*3), r.x+r.width - 5, r.y+((r.height/4)*3) );
227         }
228         else
229         {
230             dc.DrawLine( r.x+5, r.y+r.height/2, r.x+r.width - 5, r.y+r.height/2 );
231         }
232     }
233 
OnDrawBackground(wxDC & dc,const wxRect & rect,int item,int flags) const234     virtual void OnDrawBackground( wxDC& dc, const wxRect& rect,
235                                    int item, int flags ) const
236     {
237 
238         // If item is selected or even, or we are painting the
239         // combo control itself, use the default rendering.
240         if ( (flags & (wxODCB_PAINTING_CONTROL|wxODCB_PAINTING_SELECTED)) ||
241              (item & 1) == 0 )
242         {
243             wxOwnerDrawnComboBox::OnDrawBackground(dc,rect,item,flags);
244             return;
245         }
246 
247         // Otherwise, draw every other background with different colour.
248         wxColour bgCol(240,240,250);
249         dc.SetBrush(wxBrush(bgCol));
250         dc.SetPen(wxPen(bgCol));
251         dc.DrawRectangle(rect);
252     }
253 
OnMeasureItem(size_t item) const254     virtual wxCoord OnMeasureItem( size_t item ) const
255     {
256         // Simply demonstrate the ability to have variable-height items
257         if ( item & 1 )
258             return 36;
259         else
260             return 24;
261     }
262 
OnMeasureItemWidth(size_t WXUNUSED (item)) const263     virtual wxCoord OnMeasureItemWidth( size_t WXUNUSED(item) ) const
264     {
265         return -1; // default - will be measured from text width
266     }
267 
268 };
269 
270 
271 // ----------------------------------------------------------------------------
272 // wxListView Custom popup interface
273 // ----------------------------------------------------------------------------
274 
275 #include <wx/listctrl.h>
276 
277 class ListViewComboPopup : public wxListView, public wxComboPopup
278 {
279 public:
280 
Init()281     virtual void Init()
282     {
283         m_value = -1;
284         m_itemHere = -1; // hot item in list
285     }
286 
Create(wxWindow * parent)287     virtual bool Create( wxWindow* parent )
288     {
289         return wxListView::Create(parent,1,
290                                   wxPoint(0,0),wxDefaultSize,
291                                   wxLC_LIST|wxLC_SINGLE_SEL|
292                                   wxLC_SORT_ASCENDING|wxSIMPLE_BORDER);
293     }
294 
GetControl()295     virtual wxWindow *GetControl() { return this; }
296 
SetStringValue(const wxString & s)297     virtual void SetStringValue( const wxString& s )
298     {
299         int n = wxListView::FindItem(-1,s);
300         if ( n >= 0 && n < GetItemCount() )
301             wxListView::Select(n);
302     }
303 
GetStringValue() const304     virtual wxString GetStringValue() const
305     {
306         if ( m_value >= 0 )
307             return wxListView::GetItemText(m_value);
308         return wxEmptyString;
309     }
310 
311     //
312     // Popup event handlers
313     //
314 
315     // Mouse hot-tracking
OnMouseMove(wxMouseEvent & event)316     void OnMouseMove(wxMouseEvent& event)
317     {
318         // Move selection to cursor if it is inside the popup
319 
320         int resFlags;
321         int itemHere = HitTest(event.GetPosition(),resFlags);
322         if ( itemHere >= 0 )
323         {
324             wxListView::Select(itemHere,true);
325             m_itemHere = itemHere;
326         }
327         event.Skip();
328     }
329 
330     // On mouse left, set the value and close the popup
OnMouseClick(wxMouseEvent & WXUNUSED (event))331     void OnMouseClick(wxMouseEvent& WXUNUSED(event))
332     {
333         m_value = m_itemHere;
334         // TODO: Send event
335         Dismiss();
336     }
337 
338     //
339     // Utilies for item manipulation
340     //
341 
AddSelection(const wxString & selstr)342     void AddSelection( const wxString& selstr )
343     {
344         wxListView::InsertItem(GetItemCount(),selstr);
345     }
346 
347 protected:
348 
349     int             m_value; // current item index
350     int             m_itemHere; // hot item in popup
351 
352 private:
353     DECLARE_EVENT_TABLE()
354 };
355 
356 BEGIN_EVENT_TABLE(ListViewComboPopup, wxListView)
357     EVT_MOTION(ListViewComboPopup::OnMouseMove)
358     // NOTE: Left down event is used instead of left up right now
359     //       since MSW wxListCtrl doesn't seem to emit left ups
360     //       consistently.
361     EVT_LEFT_DOWN(ListViewComboPopup::OnMouseClick)
362 END_EVENT_TABLE()
363 
364 
365 // ----------------------------------------------------------------------------
366 // wxTreeCtrl Custom popup interface
367 // ----------------------------------------------------------------------------
368 
369 #include <wx/treectrl.h>
370 
371 class TreeCtrlComboPopup : public wxTreeCtrl, public wxComboPopup
372 {
373 public:
374 
Init()375     virtual void Init()
376     {
377     }
378 
Create(wxWindow * parent)379     virtual bool Create( wxWindow* parent )
380     {
381         return wxTreeCtrl::Create(parent,1,
382                                   wxPoint(0,0),wxDefaultSize,
383                                   wxTR_HIDE_ROOT|wxTR_HAS_BUTTONS|
384                                   wxTR_SINGLE|wxTR_LINES_AT_ROOT|
385                                   wxSIMPLE_BORDER);
386     }
387 
OnShow()388     virtual void OnShow()
389     {
390         // make sure selected item is visible
391         if ( m_value.IsOk() )
392             EnsureVisible(m_value);
393     }
394 
GetAdjustedSize(int minWidth,int WXUNUSED (prefHeight),int maxHeight)395     virtual wxSize GetAdjustedSize( int minWidth,
396                                     int WXUNUSED(prefHeight),
397                                     int maxHeight )
398     {
399         return wxSize(wxMax(300,minWidth),wxMin(250,maxHeight));
400     }
401 
GetControl()402     virtual wxWindow *GetControl() { return this; }
403 
404     // Needed by SetStringValue
FindItemByText(wxTreeItemId parent,const wxString & text)405     wxTreeItemId FindItemByText( wxTreeItemId parent, const wxString& text )
406     {
407         wxTreeItemIdValue cookie;
408         wxTreeItemId child = GetFirstChild(parent,cookie);
409         while ( child.IsOk() )
410         {
411             if ( GetItemText(child) == text )
412             {
413                 return child;
414             }
415             if ( ItemHasChildren(child) )
416             {
417                 wxTreeItemId found = FindItemByText(child,text);
418                 if ( found.IsOk() )
419                     return found;
420             }
421             child = GetNextChild(parent,cookie);
422         }
423         return wxTreeItemId();
424     }
425 
SetStringValue(const wxString & s)426     virtual void SetStringValue( const wxString& s )
427     {
428         wxTreeItemId root = GetRootItem();
429         if ( !root.IsOk() )
430             return;
431 
432         wxTreeItemId found = FindItemByText(root,s);
433         if ( found.IsOk() )
434         {
435             m_value = m_itemHere = found;
436             wxTreeCtrl::SelectItem(found);
437         }
438     }
439 
GetStringValue() const440     virtual wxString GetStringValue() const
441     {
442         if ( m_value.IsOk() )
443             return wxTreeCtrl::GetItemText(m_value);
444         return wxEmptyString;
445     }
446 
447     //
448     // Popup event handlers
449     //
450 
451     // Mouse hot-tracking
OnMouseMove(wxMouseEvent & event)452     void OnMouseMove(wxMouseEvent& event)
453     {
454         int resFlags;
455         wxTreeItemId itemHere = HitTest(event.GetPosition(),resFlags);
456         if ( itemHere.IsOk() && (resFlags & wxTREE_HITTEST_ONITEMLABEL) )
457         {
458             wxTreeCtrl::SelectItem(itemHere,true);
459             m_itemHere = itemHere;
460         }
461         event.Skip();
462     }
463 
464     // On mouse left, set the value and close the popup
OnMouseClick(wxMouseEvent & event)465     void OnMouseClick(wxMouseEvent& event)
466     {
467         int resFlags;
468         wxTreeItemId itemHere = HitTest(event.GetPosition(),resFlags);
469         if ( itemHere.IsOk() && (resFlags & wxTREE_HITTEST_ONITEMLABEL) )
470         {
471             m_itemHere = itemHere;
472             m_value = itemHere;
473             Dismiss();
474             // TODO: Send event
475         }
476         event.Skip();
477     }
478 
479 protected:
480 
481     wxTreeItemId        m_value; // current item index
482     wxTreeItemId        m_itemHere; // hot item in popup
483 
484 private:
485     DECLARE_EVENT_TABLE()
486 };
487 
488 BEGIN_EVENT_TABLE(TreeCtrlComboPopup, wxTreeCtrl)
489     EVT_MOTION(TreeCtrlComboPopup::OnMouseMove)
490     // NOTE: Left down event is used instead of left up right now
491     //       since MSW wxTreeCtrl doesn't seem to emit left ups
492     //       consistently.
493     EVT_LEFT_DOWN(TreeCtrlComboPopup::OnMouseClick)
494 END_EVENT_TABLE()
495 
496 // ----------------------------------------------------------------------------
497 // wxComboCtrl with custom popup animation. We use EVT_TIMER, which is quite
498 // safe, but requires much more can than doing it in a single function (ie.
499 // AnimateShow) and using combination of wxSleep and wxSafeYield.
500 // ----------------------------------------------------------------------------
501 
502 #if wxUSE_TIMER
503 
504 #define CUSTOM_COMBOBOX_ANIMATION_DURATION  200  // In milliseconds
505 
506 #include "wx/timer.h"
507 
508 class wxComboCtrlWithCustomPopupAnim : public wxComboCtrl
509 {
510 public:
511 
AnimateShow(const wxRect & rect,int flags)512     virtual bool AnimateShow( const wxRect& rect, int flags )
513     {
514         MyFrame* myFrame = (MyFrame*) ::wxGetTopLevelParent(this);
515 
516         if ( !myFrame->m_cbUseAnim->GetValue() )
517             return true;
518 
519         m_animStart = ::wxGetLocalTimeMillis();
520         m_animRect = rect;
521         m_animFlags = flags;
522 
523         wxScreenDC dc;
524 
525         wxBitmap bitmap( rect.width, rect.height, -1 );
526         wxMemoryDC memdc( bitmap );
527         memdc.Blit( 0, 0, rect.width, rect.height, &dc, rect.x, rect.y );
528         memdc.SelectObject(wxNullBitmap);
529         m_animBackBitmap = bitmap;
530 
531         m_animTimer.SetOwner( this, wxID_ANY );
532         m_animTimer.Start( 10, wxTIMER_CONTINUOUS );
533 
534         OnTimerEvent(*((wxTimerEvent*)NULL));  // Event is never used, so we can give NULL
535         return false;
536     }
537 
OnTimerEvent(wxTimerEvent & WXUNUSED (event))538     void OnTimerEvent( wxTimerEvent& WXUNUSED(event) )
539     {
540         bool stopTimer = false;
541 
542         wxWindow* popup = GetPopupControl()->GetControl();
543         wxScreenDC dc;
544         const wxRect& rect = m_animRect;
545 
546         // Popup was hidden before it was fully shown?
547         if ( IsPopupWindowState(Hidden) )
548         {
549             stopTimer = true;
550         }
551         else
552         {
553             wxLongLong t = ::wxGetLocalTimeMillis();
554 
555             int pos = (int) (t-m_animStart).GetLo();
556             if ( pos < CUSTOM_COMBOBOX_ANIMATION_DURATION )
557             {
558                 //
559                 // Actual animation happens here
560                 //
561                 int width = rect.width;
562                 int height = rect.height;
563 
564                 int center_x = rect.x + (width/2);
565                 int center_y = rect.y + (height/2);
566 
567                 double d_height = (double) height;
568 
569                 dc.SetPen( *wxBLACK_PEN );
570                 dc.SetBrush( *wxTRANSPARENT_BRUSH );
571 
572                 int w = (((pos*256)/CUSTOM_COMBOBOX_ANIMATION_DURATION)*width)/256;
573 
574                 double ratio = ((double)w / (double)width);
575                 int h = (int)(d_height * ratio);
576                 dc.DrawBitmap( m_animBackBitmap, rect.x, rect.y );
577                 dc.DrawRectangle( center_x - w/2, center_y - h/2, w, h );
578             }
579             else
580             {
581                 stopTimer = true;
582             }
583         }
584 
585         if ( stopTimer )
586         {
587             dc.DrawBitmap( m_animBackBitmap, rect.x, rect.y );
588             popup->Move( 0, 0 );
589             m_animTimer.Stop();
590             DoShowPopup( m_animRect, m_animFlags );
591         }
592     }
593 
594 protected:
595 
596     // Popup animation related
597     wxLongLong  m_animStart;
598     wxTimer     m_animTimer;
599     wxRect      m_animRect;
600     wxBitmap    m_animBackBitmap;
601     int         m_animFlags;
602 
603 private:
604     DECLARE_EVENT_TABLE()
605 };
606 
607 BEGIN_EVENT_TABLE(wxComboCtrlWithCustomPopupAnim, wxComboCtrl)
608     EVT_TIMER(wxID_ANY, wxComboCtrlWithCustomPopupAnim::OnTimerEvent)
609 END_EVENT_TABLE()
610 
611 #else
612 
613 #define wxComboCtrlWithCustomPopupAnim wxComboCtrl
614 
615 #endif
616 
617 // ----------------------------------------------------------------------------
618 // wxComboCtrl with entirely custom button action (opens file dialog)
619 // ----------------------------------------------------------------------------
620 
621 class wxFileSelectorCombo : public wxComboCtrl
622 {
623 public:
wxFileSelectorCombo()624     wxFileSelectorCombo() : wxComboCtrl() { Init(); }
625 
wxFileSelectorCombo(wxWindow * parent,wxWindowID id=wxID_ANY,const wxString & value=wxEmptyString,const wxPoint & pos=wxDefaultPosition,const wxSize & size=wxDefaultSize,long style=0,const wxValidator & validator=wxDefaultValidator,const wxString & name=wxComboBoxNameStr)626     wxFileSelectorCombo(wxWindow *parent,
627                         wxWindowID id = wxID_ANY,
628                         const wxString& value = wxEmptyString,
629                         const wxPoint& pos = wxDefaultPosition,
630                         const wxSize& size = wxDefaultSize,
631                         long style = 0,
632                         const wxValidator& validator = wxDefaultValidator,
633                         const wxString& name = wxComboBoxNameStr)
634         : wxComboCtrl()
635     {
636         Init();
637         Create(parent,id,value,
638                pos,size,
639                // Style flag wxCC_STD_BUTTON makes the button
640                // behave more like a standard push button.
641                style | wxCC_STD_BUTTON,
642                validator,name);
643 
644         //
645         // Prepare custom button bitmap (just '...' text)
646         wxMemoryDC dc;
647         wxBitmap bmp(12,16);
648         dc.SelectObject(bmp);
649 
650         // Draw transparent background
651         wxColour magic(255,0,255);
652         wxBrush magicBrush(magic);
653         dc.SetBrush( magicBrush );
654         dc.SetPen( *wxTRANSPARENT_PEN );
655         dc.DrawRectangle(0,0,bmp.GetWidth(),bmp.GetHeight());
656 
657         // Draw text
658         wxString str = wxT("...");
659         int w,h;
660         dc.GetTextExtent(str, &w, &h, 0, 0);
661         dc.DrawText(str, (bmp.GetWidth()-w)/2, (bmp.GetHeight()-h)/2);
662 
663         dc.SelectObject( wxNullBitmap );
664 
665         // Finalize transparency with a mask
666         wxMask *mask = new wxMask( bmp, magic );
667         bmp.SetMask( mask );
668 
669         SetButtonBitmaps(bmp,true);
670     }
671 
OnButtonClick()672     virtual void OnButtonClick()
673     {
674         // Show standard wxFileDialog on button click
675 
676         wxFileDialog dlg(this,
677                          wxT("Choose File"),
678                          wxEmptyString,
679                          GetValue(),
680                          wxT("All files (*.*)|*.*"),
681                          wxFD_OPEN);
682 
683         if ( dlg.ShowModal() == wxID_OK )
684         {
685             SetValue(dlg.GetPath());
686         }
687     }
688 
689     // Implement empty DoSetPopupControl to prevent assertion failure.
DoSetPopupControl(wxComboPopup * WXUNUSED (popup))690     virtual void DoSetPopupControl(wxComboPopup* WXUNUSED(popup))
691     {
692     }
693 
694 private:
Init()695     void Init()
696     {
697         // Initialize member variables here
698     }
699 };
700 
701 // ----------------------------------------------------------------------------
702 // main frame
703 // ----------------------------------------------------------------------------
704 
705 // frame constructor
MyFrame(const wxString & title)706 MyFrame::MyFrame(const wxString& title)
707        : wxFrame(NULL, wxID_ANY, title)
708 {
709     wxBoxSizer* topSizer;
710     wxBoxSizer* topRowSizer;
711     wxBoxSizer* colSizer;
712     wxBoxSizer* rowSizer;
713 
714     // set the frame icon
715     SetIcon(wxICON(sample));
716 
717 #if wxUSE_MENUS
718     // create a menu bar
719     wxMenu *fileMenu = new wxMenu;
720 
721     // the "About" item should be in the help menu
722     wxMenu *helpMenu = new wxMenu;
723     helpMenu->Append(ComboCtrl_About, _T("&About...\tF1"), _T("Show about dialog"));
724 
725     fileMenu->Append(ComboCtrl_Compare, _T("&Compare against wxComboBox..."),
726         _T("Show some wxOwnerDrawnComboBoxes side-by-side with native wxComboBoxes."));
727     fileMenu->AppendSeparator();
728     fileMenu->Append(ComboCtrl_Quit, _T("E&xit\tAlt-X"), _T("Quit this program"));
729 
730     // now append the freshly created menu to the menu bar...
731     wxMenuBar *menuBar = new wxMenuBar();
732     menuBar->Append(fileMenu, _T("&File"));
733     menuBar->Append(helpMenu, _T("&Help"));
734 
735     // ... and attach this menu bar to the frame
736     SetMenuBar(menuBar);
737 #endif // wxUSE_MENUS
738 
739     wxPanel* panel = new wxPanel(this);
740 
741     // Prepare log window right away since it shows EVT_TEXTs
742     m_logWin = new wxTextCtrl( panel, 105, wxEmptyString, wxDefaultPosition,
743                                wxSize(-1,125), wxTE_MULTILINE|wxFULL_REPAINT_ON_RESIZE );
744     m_logWin->SetEditable(false);
745     wxLogTextCtrl* logger = new wxLogTextCtrl( m_logWin );
746     m_logOld = logger->SetActiveTarget( logger );
747     logger->SetTimestamp( NULL );
748 
749 
750     topSizer = new wxBoxSizer( wxVERTICAL );
751 
752     topRowSizer = new wxBoxSizer( wxHORIZONTAL );
753 
754     colSizer = new wxBoxSizer( wxVERTICAL );
755 
756 
757     wxComboCtrl* cc;
758     wxGenericComboCtrl* gcc;
759     wxOwnerDrawnComboBox* odc;
760 
761     // Create common strings array
762     m_arrItems.Add( wxT("Solid") );
763     m_arrItems.Add( wxT("Transparent") );
764     m_arrItems.Add( wxT("Dot") );
765     m_arrItems.Add( wxT("Long Dash") );
766     m_arrItems.Add( wxT("Short Dash") );
767     m_arrItems.Add( wxT("Dot Dash") );
768     m_arrItems.Add( wxT("Backward Diagonal Hatch") );
769     m_arrItems.Add( wxT("Cross-diagonal Hatch") );
770     m_arrItems.Add( wxT("Forward Diagonal Hatch") );
771     m_arrItems.Add( wxT("Cross Hatch") );
772     m_arrItems.Add( wxT("Horizontal Hatch") );
773     m_arrItems.Add( wxT("Vertical Hatch") );
774 
775 
776     //
777     // Create pen selector ODComboBox with owner-drawn items
778     //
779     rowSizer = new wxBoxSizer( wxHORIZONTAL );
780     rowSizer->Add( new wxStaticText(panel,wxID_ANY,
781                    wxT("OwnerDrawnComboBox with owner-drawn items:")), 1,
782                    wxALIGN_CENTER_VERTICAL|wxRIGHT, 4 );
783     colSizer->Add( rowSizer, 0, wxEXPAND|wxALL, 5 );
784 
785     rowSizer = new wxBoxSizer( wxHORIZONTAL );
786 
787 
788     // When defining derivative class for callbacks, we need
789     // to use two-stage creation (or redefine the common wx
790     // constructor).
791     odc = new wxPenStyleComboBox();
792     odc->Create(panel,wxID_ANY,wxEmptyString,
793                 wxDefaultPosition, wxDefaultSize,
794                 m_arrItems,
795                 wxCB_READONLY //wxNO_BORDER | wxCB_READONLY
796                );
797 
798 
799     odc->SetSelection(0);
800 
801     rowSizer->Add( odc, 1, wxALIGN_CENTER_VERTICAL|wxALL, 4 );
802     rowSizer->AddStretchSpacer(1);
803     colSizer->Add( rowSizer, 0, wxEXPAND|wxALL, 5 );
804 
805 
806 
807     //
808     // Same but with changed button position
809     //
810     rowSizer = new wxBoxSizer( wxHORIZONTAL );
811     rowSizer->Add( new wxStaticText(panel,wxID_ANY,
812                    wxT("OwnerDrawnComboBox with owner-drawn items and button on the left:")), 1,
813                    wxALIGN_CENTER_VERTICAL|wxRIGHT, 4 );
814     colSizer->Add( rowSizer, 0, wxEXPAND|wxALL, 5 );
815 
816     rowSizer = new wxBoxSizer( wxHORIZONTAL );
817 
818 
819     // When defining derivative class for callbacks, we need
820     // to use two-stage creation (or redefine the common wx
821     // constructor).
822     odc = new wxPenStyleComboBox();
823     odc->Create(panel,wxID_ANY,wxEmptyString,
824                 wxDefaultPosition, wxDefaultSize,
825                 m_arrItems,
826                 wxCB_READONLY //wxNO_BORDER | wxCB_READONLY
827                );
828 
829 
830     odc->SetSelection(0);
831 
832     // Use button size that is slightly smaller than the default.
833     wxSize butSize = odc->GetButtonSize();
834     odc->SetButtonPosition(butSize.x - 2, // button width
835                            butSize.y - 6, // button height
836                            wxLEFT, // side
837                            2 // horizontal spacing
838                           );
839 
840     rowSizer->Add( odc, 1, wxALIGN_CENTER_VERTICAL|wxALL, 4 );
841     rowSizer->AddStretchSpacer(1);
842     colSizer->Add( rowSizer, 0, wxEXPAND|wxALL, 5 );
843 
844 
845     //
846     // List View wxComboCtrl
847     //
848 
849     rowSizer = new wxBoxSizer( wxHORIZONTAL );
850     rowSizer->Add( new wxStaticText(panel,wxID_ANY,wxT("List View wxComboCtrl:")), 1,
851                    wxALIGN_CENTER_VERTICAL|wxRIGHT, 4 );
852     rowSizer->Add( new wxStaticText(panel,wxID_ANY,wxT("Tree Ctrl wxComboCtrl:")), 1,
853                    wxALIGN_CENTER_VERTICAL|wxRIGHT, 4 );
854     colSizer->Add( rowSizer, 0, wxEXPAND|wxALL, 5 );
855 
856     rowSizer = new wxBoxSizer( wxHORIZONTAL );
857     cc = new wxComboCtrlWithCustomPopupAnim();
858     cc->Create(panel, wxID_ANY, wxEmptyString);
859 
860     // Make sure we use popup that allows focusing the listview.
861     cc->UseAltPopupWindow();
862 
863     cc->SetPopupMinWidth(300);
864 
865     ListViewComboPopup* iface = new ListViewComboPopup();
866     cc->SetPopupControl(iface);
867 
868     int i;
869     for ( i=0; i<100; i++ )
870         iface->AddSelection( wxString::Format(wxT("Item %02i"),i));
871 
872     rowSizer->Add( cc, 1, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
873 
874 
875     //
876     // Tree Ctrl wxComboCtrl
877     //
878 
879     // Note that we test that wxGenericComboCtrl works
880     gcc = new wxGenericComboCtrl(panel,wxID_ANY,wxEmptyString,
881                                  wxDefaultPosition, wxDefaultSize);
882 
883     // Make sure we use popup that allows focusing the treectrl.
884     gcc->UseAltPopupWindow();
885 
886     // Set popup interface right away, otherwise some of the calls
887     // below may fail
888     TreeCtrlComboPopup* tcPopup = new TreeCtrlComboPopup();
889     gcc->SetPopupControl(tcPopup);
890 
891     // Add items using wxTreeCtrl methods directly
892     wxTreeItemId rootId = tcPopup->AddRoot(wxT("<hidden_root>"));
893 
894     wxTreeItemId groupId;
895 
896     for ( i=0; i<4; i++ )
897     {
898         groupId = tcPopup->AppendItem(rootId,
899             wxString::Format(wxT("Branch %02i"),i));
900 
901         int n;
902         for ( n=0; n<25; n++ )
903             tcPopup->AppendItem(groupId,
904                 wxString::Format(wxT("Subitem %02i"),(i*25)+n));
905     }
906 
907     gcc->SetValue(wxT("Subitem 05"));
908 
909     // Move button to left - it makes more sense for a tree ctrl
910     gcc->SetButtonPosition(-1, // button width
911                            -1, // button height
912                            wxLEFT, // side
913                            0 // horizontal spacing
914                           );
915 
916     rowSizer->Add( gcc, 1, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
917 
918     colSizer->Add( rowSizer, 0, wxEXPAND|wxALL, 5 );
919 
920 #if wxUSE_IMAGE
921     wxInitAllImageHandlers();
922 
923     //
924     // Custom Dropbutton Bitmaps
925     // (second one uses blank button background)
926     //
927     rowSizer = new wxBoxSizer( wxHORIZONTAL );
928     rowSizer->Add( new wxStaticText(panel,wxID_ANY,
929                    wxT("OwnerDrawnComboBox with simple dropbutton graphics:")), 1,
930                    wxALIGN_CENTER_VERTICAL|wxRIGHT, 4 );
931 
932     colSizer->Add( rowSizer, 0, wxEXPAND|wxALL, 5 );
933 
934     rowSizer = new wxBoxSizer( wxHORIZONTAL );
935 
936     odc = new wxOwnerDrawnComboBox(panel,wxID_ANY,wxEmptyString,
937                                    wxDefaultPosition, wxDefaultSize,
938                                    m_arrItems,
939                                    (long)0 // wxCB_SORT // wxNO_BORDER | wxCB_READONLY
940                                   );
941 
942     wxOwnerDrawnComboBox* odc2;
943     odc2 = new wxOwnerDrawnComboBox(panel,wxID_ANY,wxEmptyString,
944                                     wxDefaultPosition, wxDefaultSize,
945                                     m_arrItems,
946                                     (long)0 // wxCB_SORT // wxNO_BORDER | wxCB_READONLY
947                                    );
948 
949     // Load images from disk
950     wxImage imgNormal(wxT("dropbutn.png"));
951     wxImage imgPressed(wxT("dropbutp.png"));
952     wxImage imgHover(wxT("dropbuth.png"));
953 
954     if ( imgNormal.IsOk() && imgPressed.IsOk() && imgHover.IsOk() )
955     {
956         wxBitmap bmpNormal(imgNormal);
957         wxBitmap bmpPressed(imgPressed);
958         wxBitmap bmpHover(imgHover);
959         odc->SetButtonBitmaps(bmpNormal,false,bmpPressed,bmpHover);
960         odc2->SetButtonBitmaps(bmpNormal,true,bmpPressed,bmpHover);
961     }
962     else
963         wxLogError(wxT("Dropbutton images not found"));
964 
965     //odc2->SetButtonPosition(0, // width adjustment
966     //                        0, // height adjustment
967     //                        wxLEFT, // side
968     //                        0 // horizontal spacing
969     //                       );
970 
971     rowSizer->Add( odc, 1, wxALIGN_CENTER_VERTICAL|wxALL, 4 );
972     rowSizer->Add( odc2, 1, wxALIGN_CENTER_VERTICAL|wxALL, 4 );
973     colSizer->Add( rowSizer, 0, wxEXPAND|wxALL, 5 );
974 #endif
975 
976 
977     //
978     // wxComboCtrl with totally custom button action (open file dialog)
979     //
980     rowSizer = new wxBoxSizer( wxHORIZONTAL );
981     rowSizer->Add( new wxStaticText(panel,wxID_ANY,
982                         wxT("wxComboCtrl with custom button action:")), 1,
983                    wxALIGN_CENTER_VERTICAL|wxRIGHT, 4 );
984 
985 
986     colSizer->Add( rowSizer, 0, wxEXPAND|wxALL, 5 );
987 
988     rowSizer = new wxBoxSizer( wxHORIZONTAL );
989     wxFileSelectorCombo* fsc;
990 
991     fsc = new wxFileSelectorCombo(panel,wxID_ANY,wxEmptyString,
992                                   wxDefaultPosition, wxDefaultSize,
993                                   (long)0
994                                  );
995 
996     rowSizer->Add( fsc, 1, wxALIGN_CENTER_VERTICAL|wxALL, 4 );
997     colSizer->Add( rowSizer, 0, wxEXPAND|wxALL, 5 );
998 
999 
1000     // Make sure GetFeatures is implemented
1001     wxComboCtrl::GetFeatures();
1002 
1003 
1004     topRowSizer->Add( colSizer, 1, wxALL, 2 );
1005 
1006     colSizer = new wxBoxSizer( wxVERTICAL );
1007 
1008     wxStaticBoxSizer* sbSizer = new wxStaticBoxSizer( new wxStaticBox(panel,
1009                                                                       wxID_ANY,
1010                                                                       wxT("Options")),
1011                                                       wxVERTICAL );
1012 
1013     m_cbUseAnim = new wxCheckBox(panel, wxID_ANY, wxT("Custom popup animation for ListView wxComboCtrl"));
1014     m_cbUseAnim->SetValue(true);
1015     sbSizer->Add( m_cbUseAnim, 0, wxALL, 3 );
1016 
1017     colSizer->Add( sbSizer, 0, wxEXPAND|wxALL, 3 );
1018     colSizer->AddSpacer(8);
1019     colSizer->Add( new wxStaticText(panel, wxID_ANY, wxT("Log Messages:")), 0, wxTOP|wxLEFT, 3 );
1020     colSizer->Add( m_logWin, 1, wxEXPAND|wxALL, 3 );
1021 
1022     topRowSizer->Add( colSizer, 1, wxEXPAND|wxALL, 2 );
1023     topSizer->Add( topRowSizer, 1, wxEXPAND );
1024 
1025     panel->SetSizer( topSizer );
1026     topSizer->SetSizeHints( panel );
1027 
1028     SetSize(740,400);
1029     Centre();
1030 }
1031 
1032 // event handlers
1033 
OnComboBoxUpdate(wxCommandEvent & event)1034 void MyFrame::OnComboBoxUpdate( wxCommandEvent& event )
1035 {
1036     // Don't show messages for the log output window (it'll crash)
1037     if ( !event.GetEventObject()->IsKindOf(CLASSINFO(wxComboCtrl)) )
1038         return;
1039 
1040     if ( event.GetEventType() == wxEVT_COMMAND_COMBOBOX_SELECTED )
1041         wxLogDebug(wxT("EVT_COMBOBOX(id=%i,selection=%i)"),event.GetId(),event.GetSelection());
1042     else if ( event.GetEventType() == wxEVT_COMMAND_TEXT_UPDATED )
1043         wxLogDebug(wxT("EVT_TEXT(id=%i,string=\"%s\")"),event.GetId(),event.GetString().c_str());
1044 }
1045 
OnShowComparison(wxCommandEvent & WXUNUSED (event))1046 void MyFrame::OnShowComparison( wxCommandEvent& WXUNUSED(event) )
1047 {
1048     //
1049     // Show some wxOwnerDrawComboBoxes for comparison
1050     //
1051 
1052     wxBoxSizer* colSizer;
1053     wxBoxSizer* rowSizer;
1054     wxStaticBoxSizer* groupSizer;
1055 
1056     wxComboBox* cb;
1057     wxOwnerDrawnComboBox* odc;
1058 
1059     const int border = 4;
1060 
1061     wxDialog* dlg = new wxDialog(this,wxID_ANY,
1062                                  wxT("Compare against wxComboBox"),
1063                                  wxDefaultPosition,wxDefaultSize,
1064                                  wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER);
1065 
1066     colSizer = new wxBoxSizer( wxVERTICAL );
1067 
1068     rowSizer = new wxBoxSizer(wxHORIZONTAL);
1069 
1070     groupSizer = new wxStaticBoxSizer(new wxStaticBox(dlg,wxID_ANY,wxT(" wxOwnerDrawnComboBox ")),
1071                                       wxVERTICAL);
1072 
1073     groupSizer->Add( new wxStaticText(dlg,wxID_ANY,wxT("Writable, sorted:")), 0,
1074                      wxALIGN_CENTER_VERTICAL|wxRIGHT|wxEXPAND, border );
1075 
1076     odc = new wxOwnerDrawnComboBox(dlg,wxID_ANY,wxEmptyString,
1077                                    wxDefaultPosition, wxDefaultSize,
1078                                    m_arrItems,
1079                                    wxCB_SORT // wxNO_BORDER|wxCB_READONLY
1080                                   );
1081 
1082     odc->Append(wxT("H - Appended Item")); // test sorting in append
1083 
1084     odc->SetValue(wxT("Dot Dash"));
1085 
1086     groupSizer->Add( odc, 1, wxALIGN_CENTER_VERTICAL|wxEXPAND|wxALL, border );
1087 
1088     //
1089     // Readonly ODComboBox
1090     groupSizer->Add( new wxStaticText(dlg,wxID_ANY,wxT("Read-only:")), 0,
1091                      wxALIGN_CENTER_VERTICAL|wxRIGHT, border );
1092 
1093     odc = new wxOwnerDrawnComboBox(dlg,wxID_ANY,wxEmptyString,
1094                                    wxDefaultPosition, wxDefaultSize,
1095                                    m_arrItems,
1096                                    wxCB_SORT|wxCB_READONLY // wxNO_BORDER|wxCB_READONLY
1097                                   );
1098 
1099     odc->SetValue(wxT("Dot Dash"));
1100     odc->SetText(wxT("Dot Dash (Testing SetText)"));
1101 
1102     groupSizer->Add( odc, 1, wxALIGN_CENTER_VERTICAL|wxEXPAND|wxALL, border );
1103 
1104     //
1105     // Disabled ODComboBox
1106     groupSizer->Add( new wxStaticText(dlg,wxID_ANY,wxT("Disabled:")), 0,
1107                    wxALIGN_CENTER_VERTICAL|wxRIGHT, border );
1108 
1109     odc = new wxOwnerDrawnComboBox(dlg,wxID_ANY,wxEmptyString,
1110                                      wxDefaultPosition, wxDefaultSize,
1111                                      m_arrItems,
1112                                      wxCB_SORT|wxCB_READONLY // wxNO_BORDER|wxCB_READONLY
1113                                      );
1114 
1115     odc->SetValue(wxT("Dot Dash"));
1116     odc->Enable(false);
1117 
1118     groupSizer->Add( odc, 1, wxALIGN_CENTER_VERTICAL|wxEXPAND|wxALL, border );
1119 
1120     rowSizer->Add( groupSizer, 1, wxEXPAND|wxALL, border );
1121 
1122 
1123     groupSizer = new wxStaticBoxSizer(new wxStaticBox(dlg,wxID_ANY,wxT(" wxComboBox ")),
1124                                       wxVERTICAL);
1125 
1126     //
1127     // wxComboBox
1128     //
1129     groupSizer->Add( new wxStaticText(dlg,wxID_ANY,wxT("Writable, sorted:")), 0,
1130                      wxALIGN_CENTER_VERTICAL|wxRIGHT|wxEXPAND, border );
1131 
1132     cb = new wxComboBox(dlg,wxID_ANY,wxEmptyString,
1133                         wxDefaultPosition, wxDefaultSize,
1134                         m_arrItems,
1135                         wxCB_SORT // wxNO_BORDER|wxCB_READONLY
1136                        );
1137 
1138     cb->Append(wxT("H - Appended Item")); // test sorting in append
1139 
1140     cb->SetValue(wxT("Dot Dash"));
1141 
1142     groupSizer->Add( cb, 1, wxALIGN_CENTER_VERTICAL|wxEXPAND|wxALL, border );
1143 
1144     //
1145     // Readonly wxComboBox
1146     groupSizer->Add( new wxStaticText(dlg,wxID_ANY,wxT("Read-only:")), 0,
1147                      wxALIGN_CENTER_VERTICAL|wxRIGHT, border );
1148 
1149     cb = new wxComboBox(dlg,wxID_ANY,wxEmptyString,
1150                         wxDefaultPosition, wxDefaultSize,
1151                         m_arrItems,
1152                         wxCB_SORT|wxCB_READONLY // wxNO_BORDER|wxCB_READONLY
1153                        );
1154 
1155     cb->SetValue(wxT("Dot Dash"));
1156 
1157     groupSizer->Add( cb, 1, wxALIGN_CENTER_VERTICAL|wxEXPAND|wxALL, border );
1158 
1159     //
1160     // Disabled wxComboBox
1161     groupSizer->Add( new wxStaticText(dlg,wxID_ANY,wxT("Disabled:")), 0,
1162                    wxALIGN_CENTER_VERTICAL|wxRIGHT, border );
1163 
1164     cb = new wxComboBox(dlg,wxID_ANY,wxEmptyString,
1165                         wxDefaultPosition, wxDefaultSize,
1166                         m_arrItems,
1167                         wxCB_SORT|wxCB_READONLY // wxNO_BORDER|wxCB_READONLY
1168                        );
1169 
1170     cb->SetValue(wxT("Dot Dash"));
1171     cb->Enable(false);
1172 
1173     groupSizer->Add( cb, 1, wxALIGN_CENTER_VERTICAL|wxEXPAND|wxALL, border );
1174 
1175     rowSizer->Add( groupSizer, 1, wxEXPAND|wxALL, border );
1176 
1177     colSizer->Add( rowSizer, 0, wxEXPAND|wxALL, border );
1178 
1179     dlg->SetSizer( colSizer );
1180     colSizer->SetSizeHints( dlg );
1181 
1182     dlg->SetSize(60,240);
1183     dlg->Centre();
1184     dlg->ShowModal();
1185 }
1186 
~MyFrame()1187 MyFrame::~MyFrame()
1188 {
1189     delete wxLog::SetActiveTarget(m_logOld);
1190 }
1191 
OnQuit(wxCommandEvent & WXUNUSED (event))1192 void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
1193 {
1194     // true is to force the frame to close
1195     Close(true);
1196 }
1197 
OnAbout(wxCommandEvent & WXUNUSED (event))1198 void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
1199 {
1200     wxMessageBox(wxString::Format(
1201                     _T("Welcome to %s!\n")
1202                     _T("\n")
1203                     _T("This is the wxWidgets wxComboCtrl and wxOwnerDrawnComboBox sample\n")
1204                     _T("running under %s."),
1205                     wxVERSION_STRING,
1206                     wxGetOsDescription().c_str()
1207                  ),
1208                  _T("About wxComboCtrl sample"),
1209                  wxOK | wxICON_INFORMATION,
1210                  this);
1211 }
1212 
OnIdle(wxIdleEvent & event)1213 void MyFrame::OnIdle(wxIdleEvent& event)
1214 {
1215     // This code is useful for debugging focus problems
1216     // (which are plentiful when dealing with popup windows).
1217 #if 0
1218     static wxWindow* lastFocus = (wxWindow*) NULL;
1219 
1220     wxWindow* curFocus = ::wxWindow::FindFocus();
1221 
1222     if ( curFocus != lastFocus )
1223     {
1224         const wxChar* className = wxT("<none>");
1225         if ( curFocus )
1226             className = curFocus->GetClassInfo()->GetClassName();
1227         lastFocus = curFocus;
1228         wxLogDebug( wxT("FOCUSED: %s %X"),
1229             className,
1230             (unsigned int)curFocus);
1231     }
1232 #endif
1233 
1234     event.Skip();
1235 }
1236