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