1/////////////////////////////////////////////////////////////////////////////
2// Program:     wxWidgets Widgets Sample
3// Name:        bmpcombobox.cpp
4// Purpose:     Part of the widgets sample showing wxBitmapComboBox
5// Author:      Jaakko Salli
6// Created:     Sep-01-2006
7// Id:          $Id: bmpcombobox.cpp 58156 2009-01-16 19:12:20Z VZ $
8// Copyright:   (c) 2006 Jaakko Salli
9// License:     wxWindows license
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#if wxUSE_BITMAPCOMBOBOX
28
29// for all others, include the necessary headers
30#ifndef WX_PRECOMP
31    #include "wx/log.h"
32
33    #include "wx/bitmap.h"
34    #include "wx/button.h"
35    #include "wx/checkbox.h"
36    #include "wx/combobox.h"
37    #include "wx/radiobox.h"
38    #include "wx/statbox.h"
39    #include "wx/textctrl.h"
40    #include "wx/filedlg.h"
41#endif
42
43#include "wx/stattext.h"
44#include "wx/dc.h"
45#include "wx/dcmemory.h"
46#include "wx/sizer.h"
47#include "wx/icon.h"
48#include "wx/dir.h"
49#include "wx/msgdlg.h"
50#include "wx/filename.h"
51#include "wx/image.h"
52#include "wx/imaglist.h"
53#include "wx/bmpcbox.h"
54
55#include "widgets.h"
56
57#include "icons/bmpcombobox.xpm"
58
59// Images loaded from file are reduced this width and height, if larger
60#define IMG_SIZE_TRUNC  256
61
62
63// ----------------------------------------------------------------------------
64// constants
65// ----------------------------------------------------------------------------
66
67// control ids
68enum
69{
70    BitmapComboBoxPage_Reset = wxID_HIGHEST,
71    BitmapComboBoxPage_Insert,
72    BitmapComboBoxPage_InsertText,
73    BitmapComboBoxPage_ChangeHeight,
74    BitmapComboBoxPage_LoadFromFile,
75    BitmapComboBoxPage_SetFromFile,
76    BitmapComboBoxPage_AddWidgetIcons,
77    BitmapComboBoxPage_AddSeveralWithImages,
78    BitmapComboBoxPage_AddSeveral,
79    BitmapComboBoxPage_AddMany,
80    BitmapComboBoxPage_Clear,
81    BitmapComboBoxPage_Change,
82    BitmapComboBoxPage_Delete,
83    BitmapComboBoxPage_DeleteText,
84    BitmapComboBoxPage_DeleteSel,
85    BitmapComboBoxPage_Combo
86};
87
88
89// ----------------------------------------------------------------------------
90// BitmapComboBoxWidgetsPage
91// ----------------------------------------------------------------------------
92
93class BitmapComboBoxWidgetsPage : public WidgetsPage
94{
95public:
96    BitmapComboBoxWidgetsPage(WidgetsBookCtrl *book, wxImageList *imaglist);
97
98    virtual wxControl *GetWidget() const { return m_combobox; }
99    virtual void RecreateWidget() { CreateCombo(); }
100
101    // lazy creation of the content
102    virtual void CreateContent();
103
104protected:
105    // event handlers
106    void OnButtonReset(wxCommandEvent& event);
107    void OnButtonChange(wxCommandEvent& event);
108    void OnButtonDelete(wxCommandEvent& event);
109    void OnButtonDeleteSel(wxCommandEvent& event);
110    void OnButtonClear(wxCommandEvent& event);
111    void OnButtonInsert(wxCommandEvent &event);
112    void OnTextChangeHeight(wxCommandEvent& event);
113    void OnButtonLoadFromFile(wxCommandEvent& event);
114    void OnButtonSetFromFile(wxCommandEvent& event);
115    void OnButtonAddSeveral(wxCommandEvent& event);
116    void OnButtonAddSeveralWithImages(wxCommandEvent& event);
117    void OnButtonAddWidgetIcons(wxCommandEvent& event);
118    void OnButtonAddMany(wxCommandEvent& event);
119
120    void OnComboBox(wxCommandEvent& event);
121    void OnComboText(wxCommandEvent& event);
122
123    void OnCheckOrRadioBox(wxCommandEvent& event);
124
125    void OnTextPopupWidth(wxCommandEvent& event);
126    void OnTextPopupHeight(wxCommandEvent& event);
127    void OnTextButtonAll(wxCommandEvent& event);
128
129    void OnUpdateUIInsert(wxUpdateUIEvent& event);
130    void OnUpdateUIAddSeveral(wxUpdateUIEvent& event);
131    void OnUpdateUIAddSeveralWithImages(wxUpdateUIEvent& event);
132    void OnUpdateUIClearButton(wxUpdateUIEvent& event);
133    void OnUpdateUIDeleteButton(wxUpdateUIEvent& event);
134    void OnUpdateUIItemManipulator(wxUpdateUIEvent& event);
135    void OnUpdateUIResetButton(wxUpdateUIEvent& event);
136
137    // reset the bmpcombobox parameters
138    void Reset();
139
140    // (re)create the bmpcombobox
141    void CreateCombo();
142
143    // helpers for creating bitmaps
144    wxBitmap CreateBitmap(const wxColour& colour);
145    wxBitmap CreateRandomBitmap(wxString* pStr);
146    wxBitmap LoadBitmap(const wxString& filepath);
147    wxBitmap QueryBitmap(wxString* pStr);
148
149    void LoadWidgetImages( wxArrayString* strings, wxImageList* images );
150
151    wxSizer *CreateSizerWithSmallTextAndLabel(const wxString& label,
152                                              wxWindowID id,
153                                              wxTextCtrl **ppText);
154
155#if wxUSE_IMAGE
156    void RescaleImage(wxImage& image, int w, int h);
157#endif
158
159    // the controls
160    // ------------
161
162    // the checkboxes for styles
163    wxCheckBox *m_chkSort,
164               *m_chkReadonly;
165
166    // the combobox itself and the sizer it is in
167    wxBitmapComboBox *m_combobox;
168    wxSizer *m_sizerCombo;
169
170    // the text entries for "Add/change string" and "Delete" buttons
171    wxTextCtrl *m_textInsert,
172               *m_textChangeHeight,
173               *m_textChange,
174               *m_textDelete;
175
176private:
177    DECLARE_EVENT_TABLE()
178    DECLARE_WIDGETS_PAGE(BitmapComboBoxWidgetsPage)
179};
180
181// ----------------------------------------------------------------------------
182// event tables
183// ----------------------------------------------------------------------------
184
185BEGIN_EVENT_TABLE(BitmapComboBoxWidgetsPage, WidgetsPage)
186    EVT_BUTTON(BitmapComboBoxPage_Reset, BitmapComboBoxWidgetsPage::OnButtonReset)
187    EVT_BUTTON(BitmapComboBoxPage_Change, BitmapComboBoxWidgetsPage::OnButtonChange)
188    EVT_BUTTON(BitmapComboBoxPage_Delete, BitmapComboBoxWidgetsPage::OnButtonDelete)
189    EVT_BUTTON(BitmapComboBoxPage_DeleteSel, BitmapComboBoxWidgetsPage::OnButtonDeleteSel)
190    EVT_BUTTON(BitmapComboBoxPage_Clear, BitmapComboBoxWidgetsPage::OnButtonClear)
191    EVT_BUTTON(BitmapComboBoxPage_Insert, BitmapComboBoxWidgetsPage::OnButtonInsert)
192    EVT_BUTTON(BitmapComboBoxPage_AddSeveral, BitmapComboBoxWidgetsPage::OnButtonAddSeveral)
193    EVT_BUTTON(BitmapComboBoxPage_AddSeveralWithImages, BitmapComboBoxWidgetsPage::OnButtonAddSeveralWithImages)
194    EVT_BUTTON(BitmapComboBoxPage_AddWidgetIcons, BitmapComboBoxWidgetsPage::OnButtonAddWidgetIcons)
195    EVT_BUTTON(BitmapComboBoxPage_AddMany, BitmapComboBoxWidgetsPage::OnButtonAddMany)
196    EVT_BUTTON(BitmapComboBoxPage_LoadFromFile, BitmapComboBoxWidgetsPage::OnButtonLoadFromFile)
197    EVT_BUTTON(BitmapComboBoxPage_SetFromFile, BitmapComboBoxWidgetsPage::OnButtonSetFromFile)
198
199    EVT_TEXT_ENTER(BitmapComboBoxPage_InsertText, BitmapComboBoxWidgetsPage::OnButtonInsert)
200    EVT_TEXT(BitmapComboBoxPage_ChangeHeight, BitmapComboBoxWidgetsPage::OnTextChangeHeight)
201    EVT_TEXT_ENTER(BitmapComboBoxPage_DeleteText, BitmapComboBoxWidgetsPage::OnButtonDelete)
202
203    EVT_UPDATE_UI(BitmapComboBoxPage_Reset, BitmapComboBoxWidgetsPage::OnUpdateUIResetButton)
204    EVT_UPDATE_UI(BitmapComboBoxPage_Insert, BitmapComboBoxWidgetsPage::OnUpdateUIInsert)
205    EVT_UPDATE_UI(BitmapComboBoxPage_LoadFromFile, BitmapComboBoxWidgetsPage::OnUpdateUIInsert)
206    EVT_UPDATE_UI(BitmapComboBoxPage_AddSeveral, BitmapComboBoxWidgetsPage::OnUpdateUIAddSeveral)
207    EVT_UPDATE_UI(BitmapComboBoxPage_AddSeveralWithImages, BitmapComboBoxWidgetsPage::OnUpdateUIAddSeveralWithImages)
208    EVT_UPDATE_UI(BitmapComboBoxPage_Clear, BitmapComboBoxWidgetsPage::OnUpdateUIClearButton)
209    EVT_UPDATE_UI(BitmapComboBoxPage_DeleteText, BitmapComboBoxWidgetsPage::OnUpdateUIClearButton)
210    EVT_UPDATE_UI(BitmapComboBoxPage_Delete, BitmapComboBoxWidgetsPage::OnUpdateUIDeleteButton)
211    EVT_UPDATE_UI(BitmapComboBoxPage_Change, BitmapComboBoxWidgetsPage::OnUpdateUIItemManipulator)
212    EVT_UPDATE_UI(BitmapComboBoxPage_SetFromFile, BitmapComboBoxWidgetsPage::OnUpdateUIItemManipulator)
213    EVT_UPDATE_UI(BitmapComboBoxPage_DeleteSel, BitmapComboBoxWidgetsPage::OnUpdateUIItemManipulator)
214
215    EVT_COMBOBOX(BitmapComboBoxPage_Combo, BitmapComboBoxWidgetsPage::OnComboBox)
216    EVT_TEXT(BitmapComboBoxPage_Combo, BitmapComboBoxWidgetsPage::OnComboText)
217    EVT_TEXT_ENTER(BitmapComboBoxPage_Combo, BitmapComboBoxWidgetsPage::OnComboText)
218
219    EVT_CHECKBOX(wxID_ANY, BitmapComboBoxWidgetsPage::OnCheckOrRadioBox)
220    EVT_RADIOBOX(wxID_ANY, BitmapComboBoxWidgetsPage::OnCheckOrRadioBox)
221END_EVENT_TABLE()
222
223// ============================================================================
224// implementation
225// ============================================================================
226
227
228
229IMPLEMENT_WIDGETS_PAGE(BitmapComboBoxWidgetsPage, _T("BitmapCombobox"),
230                       GENERIC_CTRLS | WITH_ITEMS_CTRLS | COMBO_CTRLS
231                       );
232
233
234BitmapComboBoxWidgetsPage::BitmapComboBoxWidgetsPage(WidgetsBookCtrl *book,
235                                             wxImageList *imaglist)
236                  : WidgetsPage(book, imaglist, bmpcombobox_xpm)
237{
238    // init everything
239    m_chkSort =
240    m_chkReadonly = (wxCheckBox *)NULL;
241
242    m_combobox = (wxBitmapComboBox *)NULL;
243    m_sizerCombo = (wxSizer *)NULL;
244}
245
246// create a sizer containing a label and a small text ctrl
247wxSizer *BitmapComboBoxWidgetsPage::CreateSizerWithSmallTextAndLabel(const wxString& label,
248                                                                    wxWindowID id,
249                                                                    wxTextCtrl **ppText)
250{
251    wxControl* control = new wxStaticText(this, wxID_ANY, label);
252    wxSizer *sizerRow = new wxBoxSizer(wxHORIZONTAL);
253    wxTextCtrl *text = new wxTextCtrl(this, id, wxEmptyString,
254        wxDefaultPosition, wxSize(50,wxDefaultCoord), wxTE_PROCESS_ENTER);
255
256    sizerRow->Add(control, 0, wxRIGHT | wxALIGN_CENTRE_VERTICAL, 5);
257    sizerRow->Add(text, 1, wxFIXED_MINSIZE | wxLEFT | wxALIGN_CENTRE_VERTICAL, 5);
258
259    if ( ppText )
260        *ppText = text;
261
262    return sizerRow;
263}
264
265void BitmapComboBoxWidgetsPage::CreateContent()
266{
267    /*
268       What we create here is a frame having 3 panes: style pane is the
269       leftmost one, in the middle the pane with buttons allowing to perform
270       miscellaneous combobox operations and the pane containing the combobox
271       itself to the right
272    */
273    //wxTextCtrl *text;
274    wxSizer *sizerRow;
275
276    wxSizer *sizerTop = new wxBoxSizer(wxHORIZONTAL);
277
278    wxSizer *sizerLeft = new wxBoxSizer(wxVERTICAL);
279
280    // left pane - style box
281    wxStaticBox *box = new wxStaticBox(this, wxID_ANY, _T("&Set style"));
282
283    wxSizer *sizerStyle = new wxStaticBoxSizer(box, wxVERTICAL);
284
285    m_chkSort = CreateCheckBoxAndAddToSizer(sizerStyle, _T("&Sort items"));
286    m_chkReadonly = CreateCheckBoxAndAddToSizer(sizerStyle, _T("&Read only"));
287
288    wxButton *btn = new wxButton(this, BitmapComboBoxPage_Reset, _T("&Reset"));
289    sizerStyle->Add(btn, 0, wxALIGN_CENTRE_HORIZONTAL | wxALL, 3);
290
291    sizerLeft->Add(sizerStyle, 0, wxGROW | wxALIGN_CENTRE_HORIZONTAL);
292
293    // left pane - other options box
294    box = new wxStaticBox(this, wxID_ANY, _T("Demo options"));
295
296    wxSizer *sizerOptions = new wxStaticBoxSizer(box, wxVERTICAL);
297
298    sizerRow = CreateSizerWithSmallTextAndLabel(_T("Control &height:"),
299                                                BitmapComboBoxPage_ChangeHeight,
300                                                &m_textChangeHeight);
301    m_textChangeHeight->SetSize(20, wxDefaultCoord);
302    sizerOptions->Add(sizerRow, 0, wxALL | wxFIXED_MINSIZE /*| wxGROW*/, 5);
303
304    sizerLeft->Add(sizerOptions, 0, wxGROW | wxALIGN_CENTRE_HORIZONTAL | wxTOP, 2);
305
306    // middle pane
307    wxStaticBox *box2 = new wxStaticBox(this, wxID_ANY,
308        _T("&Change wxBitmapComboBox contents"));
309    wxSizer *sizerMiddle = new wxStaticBoxSizer(box2, wxVERTICAL);
310
311#if wxUSE_IMAGE
312    btn = new wxButton(this, BitmapComboBoxPage_AddWidgetIcons, _T("Add &widget icons"));
313    sizerMiddle->Add(btn, 0, wxALL | wxGROW, 5);
314
315    btn = new wxButton(this, BitmapComboBoxPage_LoadFromFile, _T("Insert image from &file"));
316    sizerMiddle->Add(btn, 0, wxALL | wxGROW, 5);
317
318    btn = new wxButton(this, BitmapComboBoxPage_SetFromFile, _T("&Set image from file"));
319    sizerMiddle->Add(btn, 0, wxALL | wxGROW, 5);
320#endif
321
322    btn = new wxButton(this, BitmapComboBoxPage_AddSeveralWithImages, _T("A&ppend a few strings with images"));
323    sizerMiddle->Add(btn, 0, wxALL | wxGROW, 5);
324
325    btn = new wxButton(this, BitmapComboBoxPage_AddSeveral, _T("Append a &few strings"));
326    sizerMiddle->Add(btn, 0, wxALL | wxGROW, 5);
327
328    btn = new wxButton(this, BitmapComboBoxPage_AddMany, _T("Append &many strings"));
329    sizerMiddle->Add(btn, 0, wxALL | wxGROW, 5);
330
331    sizerRow = CreateSizerWithTextAndButton(BitmapComboBoxPage_Delete,
332                                            _T("&Delete this item"),
333                                            BitmapComboBoxPage_DeleteText,
334                                            &m_textDelete);
335    sizerMiddle->Add(sizerRow, 0, wxALL | wxGROW, 5);
336
337    btn = new wxButton(this, BitmapComboBoxPage_DeleteSel, _T("Delete &selection"));
338    sizerMiddle->Add(btn, 0, wxALL | wxGROW, 5);
339
340    btn = new wxButton(this, BitmapComboBoxPage_Clear, _T("&Clear"));
341    sizerMiddle->Add(btn, 0, wxALL | wxGROW, 5);
342
343#if wxUSE_IMAGE
344    wxInitAllImageHandlers();
345#endif
346
347    // right pane
348    wxSizer *sizerRight = new wxBoxSizer(wxVERTICAL);
349    m_combobox = new wxBitmapComboBox();
350    m_combobox->Create(this, BitmapComboBoxPage_Combo, wxEmptyString,
351                       wxDefaultPosition, wxDefaultSize,
352                       0, NULL,
353                       wxCB_READONLY);
354
355#if defined(wxGENERIC_BITMAPCOMBOBOX)
356    // This will sure make the list look nicer when larger images are used.
357    m_combobox->SetPopupMaxHeight(600);
358#endif
359
360    sizerRight->Add(m_combobox, 0, wxGROW | wxALL, 5);
361    sizerRight->SetMinSize(150, 0);
362    m_sizerCombo = sizerRight; // save it to modify it later
363
364    // the 3 panes panes compose the window
365    sizerTop->Add(sizerLeft, 0, wxGROW | (wxALL & ~wxLEFT), 10);
366    sizerTop->Add(sizerMiddle, 5, wxGROW | wxALL, 10);
367    sizerTop->Add(sizerRight, 4, wxGROW | (wxALL & ~wxRIGHT), 10);
368
369    // final initializations
370    Reset();
371
372    SetSizer(sizerTop);
373}
374
375// ----------------------------------------------------------------------------
376// operations
377// ----------------------------------------------------------------------------
378
379void BitmapComboBoxWidgetsPage::Reset()
380{
381    m_chkSort->SetValue(false);
382    m_chkReadonly->SetValue(true);
383}
384
385void BitmapComboBoxWidgetsPage::CreateCombo()
386{
387    int flags = ms_defaultFlags;
388
389    if ( m_chkSort->GetValue() )
390        flags |= wxCB_SORT;
391    if ( m_chkReadonly->GetValue() )
392        flags |= wxCB_READONLY;
393
394    wxArrayString items;
395    wxArrayPtrVoid bitmaps;
396    if ( m_combobox )
397    {
398        unsigned int count = m_combobox->GetCount();
399        for ( unsigned int n = 0; n < count; n++ )
400        {
401            items.Add(m_combobox->GetString(n));
402            wxBitmap bmp = m_combobox->GetItemBitmap(n);
403            bitmaps.Add(new wxBitmap(bmp));
404        }
405
406        m_sizerCombo->Detach( m_combobox );
407        delete m_combobox;
408    }
409
410    m_combobox = new wxBitmapComboBox();
411    m_combobox->Create(this, BitmapComboBoxPage_Combo, wxEmptyString,
412                       wxDefaultPosition, wxDefaultSize,
413                       0, NULL,
414                       flags);
415
416#if defined(wxGENERIC_BITMAPCOMBOBOX)
417    // This will sure make the list look nicer when larger images are used.
418    m_combobox->SetPopupMaxHeight(600);
419#endif
420
421    unsigned int count = items.GetCount();
422    for ( unsigned int n = 0; n < count; n++ )
423    {
424        wxBitmap* bmp = (wxBitmap*) bitmaps[n];
425        m_combobox->Append(items[n], *bmp);
426        delete bmp;
427    }
428
429    m_sizerCombo->Add(m_combobox, 0, wxGROW | wxALL, 5);
430    m_sizerCombo->Layout();
431
432    // Allow changing height inorder to demonstrate flexible
433    // size of image "thumbnail" painted in the control itself.
434    long h = 0;
435    m_textChangeHeight->GetValue().ToLong(&h);
436    if ( h >= 5 )
437        m_combobox->SetSize(wxDefaultCoord, h);
438}
439
440// ----------------------------------------------------------------------------
441// event handlers
442// ----------------------------------------------------------------------------
443
444void BitmapComboBoxWidgetsPage::OnButtonReset(wxCommandEvent& WXUNUSED(event))
445{
446    Reset();
447
448    CreateCombo();
449}
450
451void BitmapComboBoxWidgetsPage::OnButtonChange(wxCommandEvent& WXUNUSED(event))
452{
453    int sel = m_combobox->GetSelection();
454    if ( sel != wxNOT_FOUND )
455    {
456#ifndef __WXGTK__
457        m_combobox->SetString(sel, m_textChange->GetValue());
458#else
459        wxLogMessage(_T("Not implemented in wxGTK"));
460#endif
461    }
462}
463
464void BitmapComboBoxWidgetsPage::OnButtonDelete(wxCommandEvent& WXUNUSED(event))
465{
466    unsigned long n;
467    if ( !m_textDelete->GetValue().ToULong(&n) ||
468            (n >= m_combobox->GetCount()) )
469    {
470        return;
471    }
472
473    m_combobox->Delete(n);
474}
475
476void BitmapComboBoxWidgetsPage::OnButtonDeleteSel(wxCommandEvent& WXUNUSED(event))
477{
478    int sel = m_combobox->GetSelection();
479    if ( sel != wxNOT_FOUND )
480    {
481        m_combobox->Delete(sel);
482    }
483}
484
485void BitmapComboBoxWidgetsPage::OnButtonClear(wxCommandEvent& WXUNUSED(event))
486{
487    m_combobox->Clear();
488}
489
490void BitmapComboBoxWidgetsPage::OnButtonInsert(wxCommandEvent& WXUNUSED(event))
491{
492    static unsigned int s_item = 0;
493
494    wxString s = m_textInsert->GetValue();
495    if ( !m_textInsert->IsModified() )
496    {
497        // update the default string
498        m_textInsert->SetValue(wxString::Format(_T("test item %u"), ++s_item));
499    }
500
501    int sel = m_combobox->GetSelection();
502    if ( sel == wxNOT_FOUND )
503        sel = m_combobox->GetCount();
504
505    m_combobox->Insert(s, wxNullBitmap, m_combobox->GetSelection());
506}
507
508void BitmapComboBoxWidgetsPage::OnTextChangeHeight(wxCommandEvent& WXUNUSED(event))
509{
510    long h = 0;
511    m_textChangeHeight->GetValue().ToLong(&h);
512    if ( h < 5 )
513        return;
514    m_combobox->SetSize(wxDefaultCoord, h);
515}
516
517void BitmapComboBoxWidgetsPage::OnButtonLoadFromFile(wxCommandEvent& WXUNUSED(event))
518{
519    wxString s;
520    int sel = m_combobox->GetSelection();
521    if ( sel == wxNOT_FOUND )
522        sel = m_combobox->GetCount();
523
524    m_combobox->Insert(s, QueryBitmap(&s), sel);
525}
526
527void BitmapComboBoxWidgetsPage::OnButtonSetFromFile(wxCommandEvent& WXUNUSED(event))
528{
529    m_combobox->SetItemBitmap(m_combobox->GetSelection(), QueryBitmap(NULL));
530}
531
532void BitmapComboBoxWidgetsPage::OnButtonAddMany(wxCommandEvent& WXUNUSED(event))
533{
534    // "many" means 1000 here
535    for ( unsigned int n = 0; n < 1000; n++ )
536    {
537        m_combobox->Append(wxString::Format(_T("item #%u"), n));
538    }
539}
540
541void BitmapComboBoxWidgetsPage::OnButtonAddSeveral(wxCommandEvent& WXUNUSED(event))
542{
543    m_combobox->Append(_T("First"));
544    m_combobox->Append(_T("another one"));
545    m_combobox->Append(_T("and the last (very very very very very very very very very very long) one"));
546}
547
548void BitmapComboBoxWidgetsPage::OnButtonAddSeveralWithImages(wxCommandEvent& WXUNUSED(event))
549{
550    int i;
551
552    for ( i=0; i<4; i++ )
553    {
554        wxString s;
555        wxBitmap bmp = CreateRandomBitmap(&s);
556        m_combobox->Append(s, bmp);
557    }
558}
559
560#if wxUSE_IMAGE
561void BitmapComboBoxWidgetsPage::RescaleImage(wxImage& image, int w, int h)
562{
563    if ( image.GetWidth() == w && image.GetHeight() == h )
564        return;
565
566    if ( w <= 0 || h <= 0 )
567        return;
568
569    static bool isFirstScale = true;
570
571    if ( isFirstScale && m_combobox->GetCount() > 0 )
572    {
573        wxMessageBox( wxT("wxBitmapComboBox normally only supports images of one size. ")
574                      wxT("However, for demonstration purposes, loaded bitmaps are scaled to fit ")
575                      wxT("using wxImage::Rescale."),
576                      wxT("Notice"),
577                      wxOK,
578                      this );
579
580        isFirstScale = false;
581    }
582
583    image.Rescale(w, h);
584}
585#endif
586
587void BitmapComboBoxWidgetsPage::LoadWidgetImages( wxArrayString* strings, wxImageList* images )
588{
589    wxFileName fn;
590    fn.AssignCwd();
591    fn.AppendDir(wxT("icons"));
592
593    wxSetCursor(*wxHOURGLASS_CURSOR);
594
595    if ( !wxDir::Exists(fn.GetFullPath()) ||
596         !wxDir::GetAllFiles(fn.GetFullPath(),strings,wxT("*.xpm")) )
597    {
598        fn.RemoveLastDir();
599        fn.RemoveLastDir();
600        fn.AppendDir(wxT("icons"));
601        if ( !wxDir::Exists(fn.GetFullPath()) ||
602             !wxDir::GetAllFiles(fn.GetFullPath(),strings,wxT("*.xpm")) )
603        {
604            // Try ../../../samples/widgets/icons
605            fn.AssignCwd();
606            fn.RemoveLastDir();
607            fn.RemoveLastDir();
608            fn.RemoveLastDir();
609            fn.AppendDir(wxT("samples"));
610            fn.AppendDir(wxT("widgets"));
611            fn.AppendDir(wxT("icons"));
612            if ( !wxDir::Exists(fn.GetFullPath()) ||
613                 !wxDir::GetAllFiles(fn.GetFullPath(),strings,wxT("*.xpm")) )
614            {
615                wxLogWarning(wxT("Could not load widget icons."));
616                wxSetCursor(*wxSTANDARD_CURSOR);
617                return;
618            }
619        }
620    }
621
622    unsigned int i;
623
624    // Get size of existing images in list
625    wxSize foundSize = m_combobox->GetBitmapSize();
626
627    for ( i=0; i<strings->size(); i++ )
628    {
629        fn.SetFullName((*strings)[i]);
630        wxString name =fn.GetName();
631
632        // Handle few exceptions
633        if ( name == wxT("bmpbtn") )
634        {
635            strings->RemoveAt(i);
636            i--;
637        }
638        else
639        {
640#if wxUSE_IMAGE
641            wxASSERT(fn.FileExists());
642            wxImage image(fn.GetFullPath());
643            wxASSERT(image.Ok());
644            RescaleImage(image, foundSize.x, foundSize.y);
645            wxBitmap bmp(image);
646            wxASSERT( bmp.Ok() );
647#else
648            wxBitmap bmp(wxNullBitmap);
649#endif
650            images->Add(bmp);
651            (*strings)[i] = name;
652        }
653    }
654
655    wxSetCursor(*wxSTANDARD_CURSOR);
656}
657
658void BitmapComboBoxWidgetsPage::OnButtonAddWidgetIcons(wxCommandEvent& WXUNUSED(event))
659{
660    wxArrayString strings;
661
662    wxSize sz = m_combobox->GetBitmapSize();
663    if ( sz.x <= 0 )
664    {
665        sz.x = 32;
666        sz.y = 32;
667    }
668
669    wxImageList images(sz.x, sz.y);
670
671    LoadWidgetImages(&strings, &images);
672
673    unsigned int i;
674
675    for ( i=0; i<strings.size(); i++ )
676    {
677        m_combobox->Append(strings[i], images.GetBitmap(i));
678    }
679}
680
681void BitmapComboBoxWidgetsPage::OnUpdateUIResetButton(wxUpdateUIEvent& event)
682{
683    if (m_combobox)
684        event.Enable( m_chkSort->GetValue() || m_chkReadonly->GetValue() );
685}
686
687void BitmapComboBoxWidgetsPage::OnUpdateUIInsert(wxUpdateUIEvent& event)
688{
689    if (m_combobox)
690    {
691        bool enable = !(m_combobox->GetWindowStyle() & wxCB_SORT);
692
693        event.Enable(enable);
694    }
695}
696
697void BitmapComboBoxWidgetsPage::OnUpdateUIDeleteButton(wxUpdateUIEvent& event)
698{
699    if (m_combobox)
700    {
701      unsigned long n;
702      event.Enable(m_textDelete->GetValue().ToULong(&n) &&
703        (n < (unsigned)m_combobox->GetCount()));
704    }
705}
706
707void BitmapComboBoxWidgetsPage::OnUpdateUIItemManipulator(wxUpdateUIEvent& event)
708{
709    if (m_combobox)
710        event.Enable(m_combobox->GetSelection() != wxNOT_FOUND);
711}
712
713void BitmapComboBoxWidgetsPage::OnUpdateUIClearButton(wxUpdateUIEvent& event)
714{
715    if (m_combobox)
716        event.Enable(m_combobox->GetCount() != 0);
717}
718
719void BitmapComboBoxWidgetsPage::OnUpdateUIAddSeveral(wxUpdateUIEvent& event)
720{
721    if (m_combobox)
722        event.Enable(!(m_combobox->GetWindowStyle() & wxCB_SORT));
723}
724
725void BitmapComboBoxWidgetsPage::OnUpdateUIAddSeveralWithImages(wxUpdateUIEvent& event)
726{
727    if (m_combobox)
728        event.Enable(!(m_combobox->GetWindowStyle() & wxCB_SORT));
729}
730
731void BitmapComboBoxWidgetsPage::OnComboText(wxCommandEvent& event)
732{
733    if (!m_combobox)
734        return;
735
736    wxString s = event.GetString();
737
738    wxASSERT_MSG( s == m_combobox->GetValue(),
739                  _T("event and combobox values should be the same") );
740
741    if (event.GetEventType() == wxEVT_COMMAND_TEXT_ENTER)
742        wxLogMessage(_T("BitmapCombobox enter pressed (now '%s')"), s.c_str());
743    else
744        wxLogMessage(_T("BitmapCombobox text changed (now '%s')"), s.c_str());
745}
746
747void BitmapComboBoxWidgetsPage::OnComboBox(wxCommandEvent& event)
748{
749    long sel = event.GetInt();
750    m_textDelete->SetValue(wxString::Format(_T("%ld"), sel));
751
752    wxLogMessage(_T("BitmapCombobox item %ld selected"), sel);
753
754    wxLogMessage(_T("BitmapCombobox GetValue(): %s"), m_combobox->GetValue().c_str() );
755}
756
757void BitmapComboBoxWidgetsPage::OnCheckOrRadioBox(wxCommandEvent& WXUNUSED(event))
758{
759    CreateCombo();
760}
761
762#if wxUSE_IMAGE
763wxBitmap BitmapComboBoxWidgetsPage::LoadBitmap(const wxString& filepath)
764{
765    // Get size of existing images in list
766    wxSize foundSize = m_combobox->GetBitmapSize();
767
768    // Have some reasonable maximum size
769    if ( foundSize.x <= 0 )
770    {
771        foundSize.x = IMG_SIZE_TRUNC;
772        foundSize.y = IMG_SIZE_TRUNC;
773    }
774
775    wxImage image(filepath);
776    if ( image.Ok() )
777    {
778        // Rescale very large images
779        int ow = image.GetWidth();
780        int oh = image.GetHeight();
781
782        if ( foundSize.x > 0 &&
783             (ow != foundSize.x || oh != foundSize.y) )
784        {
785            int w = ow;
786            if ( w > foundSize.x )
787                w = foundSize.x;
788            int h = oh;
789            if ( h > foundSize.y )
790                h = foundSize.y;
791
792            RescaleImage(image, w, h);
793        }
794
795        return wxBitmap(image);
796    }
797
798    return wxNullBitmap;
799}
800#else
801wxBitmap BitmapComboBoxWidgetsPage::LoadBitmap(const wxString& WXUNUSED(filepath))
802{
803    return wxNullBitmap;
804}
805#endif
806
807wxBitmap BitmapComboBoxWidgetsPage::QueryBitmap(wxString* pStr)
808{
809    wxString filepath = wxFileSelector(wxT("Choose image file"),
810                                       wxEmptyString,
811                                       wxEmptyString,
812                                       wxEmptyString,
813                                       wxT("*.*"),
814                                       wxFD_OPEN | wxFD_FILE_MUST_EXIST,
815                                       this);
816
817    wxBitmap bitmap;
818
819    ::wxSetCursor( *wxHOURGLASS_CURSOR );
820
821    if ( filepath.length() )
822    {
823        if ( pStr )
824        {
825            *pStr = wxFileName(filepath).GetName();
826        }
827
828        bitmap = LoadBitmap(filepath);
829    }
830
831    wxLogDebug(wxT("%i, %i"),bitmap.GetWidth(), bitmap.GetHeight());
832
833    ::wxSetCursor( *wxSTANDARD_CURSOR );
834
835    return bitmap;
836}
837
838wxBitmap BitmapComboBoxWidgetsPage::CreateBitmap(const wxColour& colour)
839{
840    const int w = 10,
841              h = 10;
842
843    wxMemoryDC dc;
844    wxBitmap bmp(w, h);
845    dc.SelectObject(bmp);
846
847    // Draw transparent background
848    wxColour magic(255, 0, 255);
849    wxBrush magicBrush(magic);
850    dc.SetBrush(magicBrush);
851    dc.SetPen(*wxTRANSPARENT_PEN);
852    dc.DrawRectangle(0, 0, w, h);
853
854    // Draw image content
855    dc.SetBrush(wxBrush(colour));
856    dc.DrawCircle(h/2, h/2+1, h/2);
857
858    dc.SelectObject(wxNullBitmap);
859
860    // Finalize transparency with a mask
861    wxMask *mask = new wxMask(bmp, magic);
862    bmp.SetMask(mask);
863
864    return bmp;
865}
866
867wxBitmap BitmapComboBoxWidgetsPage::CreateRandomBitmap( wxString* pStr )
868{
869    int i = rand() % 6;
870    const wxChar* str = wxT("");
871    wxBitmap bmp;
872
873    if ( i == 0 )
874    {
875        str = wxT("Red Circle");
876        bmp = CreateBitmap( *wxRED );
877    }
878    else if ( i == 1 )
879    {
880        str = wxT("Green Circle");
881        bmp = CreateBitmap( *wxGREEN );
882    }
883    else if ( i == 2 )
884    {
885        str = wxT("Blue Circle");
886        bmp = CreateBitmap( *wxBLUE );
887    }
888    else if ( i == 3 )
889    {
890        str = wxT("Black Circle");
891        bmp = CreateBitmap( *wxBLACK );
892    }
893    else if ( i == 4 )
894    {
895        str = wxT("Cyan Circle");
896        bmp = CreateBitmap( *wxCYAN );
897    }
898    else if ( i == 5 )
899    {
900        str = wxT("Light Grey Circle");
901        bmp = CreateBitmap( *wxLIGHT_GREY );
902    }
903
904    if ( pStr )
905        *pStr = str;
906
907    return bmp;
908}
909
910#endif //wxUSE_BITMAPCOMBOBOX
911