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