]> git.saurik.com Git - wxWidgets.git/blob - src/generic/combog.cpp
Corrected GetFontAttributes
[wxWidgets.git] / src / generic / combog.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/generic/combog.cpp
3 // Purpose:     Generic wxComboCtrl
4 // Author:      Jaakko Salli
5 // Modified by:
6 // Created:     Apr-30-2006
7 // RCS-ID:      $Id$
8 // Copyright:   (c) 2005 Jaakko Salli
9 // Licence:     wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #include "wx/wxprec.h"
21
22 #ifdef __BORLANDC__
23     #pragma hdrstop
24 #endif
25
26 #if wxUSE_COMBOCTRL
27
28 #include "wx/combo.h"
29
30 #ifndef WX_PRECOMP
31     #include "wx/log.h"
32     #include "wx/combobox.h"
33     #include "wx/dcclient.h"
34     #include "wx/settings.h"
35     #include "wx/textctrl.h"
36 #endif
37
38 #include "wx/dcbuffer.h"
39
40 // ----------------------------------------------------------------------------
41 // Some constant adjustments to make the generic more bearable
42
43 #if defined(__WXUNIVERSAL__)
44
45 #define TEXTCTRLXADJUST                 0 // position adjustment for wxTextCtrl, with zero indent
46 #define TEXTCTRLYADJUST                 0
47 #define TEXTXADJUST                     0 // how much is read-only text's x adjusted
48 #define DEFAULT_DROPBUTTON_WIDTH        19
49
50 #elif defined(__WXMSW__)
51
52 #define TEXTCTRLXADJUST                 2 // position adjustment for wxTextCtrl, with zero indent
53 #define TEXTCTRLYADJUST                 3
54 #define TEXTXADJUST                     0 // how much is read-only text's x adjusted
55 #define DEFAULT_DROPBUTTON_WIDTH        17
56
57 #elif defined(__WXGTK__)
58
59 #define TEXTCTRLXADJUST                 -1 // position adjustment for wxTextCtrl, with zero indent
60 #define TEXTCTRLYADJUST                 0
61 #define TEXTXADJUST                     1 // how much is read-only text's x adjusted
62 #define DEFAULT_DROPBUTTON_WIDTH        23
63
64 #elif defined(__WXMAC__)
65
66 #define TEXTCTRLXADJUST                 0 // position adjustment for wxTextCtrl, with zero indent
67 #define TEXTCTRLYADJUST                 0
68 #define TEXTXADJUST                     0 // how much is read-only text's x adjusted
69 #define DEFAULT_DROPBUTTON_WIDTH        22
70
71 #else
72
73 #define TEXTCTRLXADJUST                 0 // position adjustment for wxTextCtrl, with zero indent
74 #define TEXTCTRLYADJUST                 0
75 #define TEXTXADJUST                     0 // how much is read-only text's x adjusted
76 #define DEFAULT_DROPBUTTON_WIDTH        19
77
78 #endif
79
80
81 // ============================================================================
82 // implementation
83 // ============================================================================
84
85 // Only implement if no native or it wasn't fully featured
86 #ifndef wxCOMBOCONTROL_FULLY_FEATURED
87
88
89 // ----------------------------------------------------------------------------
90 // wxGenericComboCtrl
91 // ----------------------------------------------------------------------------
92
93 BEGIN_EVENT_TABLE(wxGenericComboCtrl, wxComboCtrlBase)
94     EVT_PAINT(wxGenericComboCtrl::OnPaintEvent)
95     EVT_MOUSE_EVENTS(wxGenericComboCtrl::OnMouseEvent)
96 END_EVENT_TABLE()
97
98
99 IMPLEMENT_DYNAMIC_CLASS(wxGenericComboCtrl, wxComboCtrlBase)
100
101 void wxGenericComboCtrl::Init()
102 {
103 }
104
105 bool wxGenericComboCtrl::Create(wxWindow *parent,
106                                 wxWindowID id,
107                                 const wxString& value,
108                                 const wxPoint& pos,
109                                 const wxSize& size,
110                                 long style,
111                                 const wxValidator& validator,
112                                 const wxString& name)
113 {
114     //
115     // Note that technically we only support 'default' border and wxNO_BORDER.
116     long border = style & wxBORDER_MASK;
117     int tcBorder = wxNO_BORDER;
118
119 #if defined(__WXUNIVERSAL__)
120     if ( !border )
121         border = wxBORDER_SIMPLE;
122 #elif defined(__WXMSW__)
123     if ( !border )
124         // For XP, have 1-width custom border, for older version use sunken
125         /*if ( wxUxThemeEngine::GetIfActive() )
126         {
127             border = wxBORDER_NONE;
128             m_widthCustomBorder = 1;
129         }
130         else*/
131             border = wxBORDER_SUNKEN;
132 #else
133
134     //
135     // Generic version is optimized for wxGTK
136     //
137
138     #define UNRELIABLE_TEXTCTRL_BORDER
139
140     if ( !border )
141     {
142         if ( style & wxCB_READONLY )
143         {
144             m_widthCustomBorder = 1;
145         }
146         else
147         {
148             m_widthCustomBorder = 0;
149             tcBorder = 0;
150         }
151     }
152     else
153     {
154         // Have textctrl instead use the border given.
155         tcBorder = border;
156     }
157
158     // Because we are going to have button outside the border,
159     // let's use wxBORDER_NONE for the whole control.
160     border = wxBORDER_NONE;
161
162     Customize( wxCC_BUTTON_OUTSIDE_BORDER |
163                wxCC_NO_TEXT_AUTO_SELECT |
164                wxCC_BUTTON_STAYS_DOWN );
165
166 #endif
167
168     style = (style & ~(wxBORDER_MASK)) | border;
169     if ( style & wxCC_STD_BUTTON )
170         m_iFlags |= wxCC_POPUP_ON_MOUSE_UP;
171
172     // create main window
173     if ( !wxComboCtrlBase::Create(parent,
174                                   id,
175                                   value,
176                                   pos,
177                                   size,
178                                   style | wxFULL_REPAINT_ON_RESIZE,
179                                   wxDefaultValidator,
180                                   name) )
181         return false;
182
183     // Create textctrl, if necessary
184     CreateTextCtrl( tcBorder, validator );
185
186     // Add keyboard input handlers for main control and textctrl
187     InstallInputHandlers();
188
189     // Set background
190     SetBackgroundStyle( wxBG_STYLE_CUSTOM ); // for double-buffering
191
192     // SetInitialSize should be called last
193     SetInitialSize(size);
194
195     return true;
196 }
197
198 wxGenericComboCtrl::~wxGenericComboCtrl()
199 {
200 }
201
202 void wxGenericComboCtrl::OnResize()
203 {
204
205     // Recalculates button and textctrl areas
206     CalculateAreas(DEFAULT_DROPBUTTON_WIDTH);
207
208 #if 0
209     // Move separate button control, if any, to correct position
210     if ( m_btn )
211     {
212         wxSize sz = GetClientSize();
213         m_btn->SetSize( m_btnArea.x + m_btnSpacingX,
214                         (sz.y-m_btnSize.y)/2,
215                         m_btnSize.x,
216                         m_btnSize.y );
217     }
218 #endif
219
220     // Move textctrl, if any, accordingly
221     PositionTextCtrl( TEXTCTRLXADJUST, TEXTCTRLYADJUST );
222 }
223
224 void wxGenericComboCtrl::OnPaintEvent( wxPaintEvent& WXUNUSED(event) )
225 {
226     wxSize sz = GetClientSize();
227     wxAutoBufferedPaintDC dc(this);
228
229     const wxRect& rectb = m_btnArea;
230     wxRect rect = m_tcArea;
231
232     // artificial simple border
233     if ( m_widthCustomBorder )
234     {
235         int customBorder = m_widthCustomBorder;
236
237         // Set border colour
238         wxPen pen1( wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT),
239                     customBorder,
240                     wxSOLID );
241         dc.SetPen( pen1 );
242
243         // area around both controls
244         wxRect rect2(0,0,sz.x,sz.y);
245         if ( m_iFlags & wxCC_IFLAG_BUTTON_OUTSIDE )
246         {
247             rect2 = m_tcArea;
248             if ( customBorder == 1 )
249             {
250                 rect2.Inflate(1);
251             }
252             else
253             {
254             #ifdef __WXGTK__
255                 rect2.x -= 1;
256                 rect2.y -= 1;
257             #else
258                 rect2.x -= customBorder;
259                 rect2.y -= customBorder;
260             #endif
261                 rect2.width += 1 + customBorder;
262                 rect2.height += 1 + customBorder;
263             }
264         }
265
266         dc.SetBrush( *wxTRANSPARENT_BRUSH );
267         dc.DrawRectangle(rect2);
268     }
269
270 #ifndef __WXMAC__  // see note in OnThemeChange
271     wxColour winCol = GetBackgroundColour();
272 #else
273     wxColour winCol = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
274 #endif
275     dc.SetBrush(winCol);
276     dc.SetPen(winCol);
277
278     //wxLogDebug(wxT("hei: %i tcy: %i tchei: %i"),GetClientSize().y,m_tcArea.y,m_tcArea.height);
279     //wxLogDebug(wxT("btnx: %i tcx: %i tcwid: %i"),m_btnArea.x,m_tcArea.x,m_tcArea.width);
280
281     // clear main background
282     dc.DrawRectangle(rect);
283     
284     if ( !m_btn )
285     {
286         // Standard button rendering
287         DrawButton(dc,rectb);
288     }
289
290     // paint required portion on the control
291     if ( (!m_text || m_widthCustomPaint) )
292     {
293         wxASSERT( m_widthCustomPaint >= 0 );
294
295         // this is intentionally here to allow drawed rectangle's
296         // right edge to be hidden
297         if ( m_text )
298             rect.width = m_widthCustomPaint;
299
300         dc.SetFont( GetFont() );
301
302         dc.SetClippingRegion(rect);
303         if ( m_popupInterface )
304             m_popupInterface->PaintComboControl(dc,rect);
305         else
306             wxComboPopup::DefaultPaintComboControl(this,dc,rect);
307     }
308 }
309
310 void wxGenericComboCtrl::OnMouseEvent( wxMouseEvent& event )
311 {
312     int mx = event.m_x;
313     bool isOnButtonArea = m_btnArea.Contains(mx,event.m_y);
314     int handlerFlags = isOnButtonArea ? wxCC_MF_ON_BUTTON : 0;
315
316     if ( PreprocessMouseEvent(event,handlerFlags) )
317         return;
318
319     const bool ctrlIsButton = wxPlatformIs(wxOS_WINDOWS);
320
321     if ( ctrlIsButton &&
322          (m_windowStyle & (wxCC_SPECIAL_DCLICK|wxCB_READONLY)) == wxCB_READONLY )
323     {
324         // if no textctrl and no special double-click, then the entire control acts
325         // as a button
326         handlerFlags |= wxCC_MF_ON_BUTTON;
327         if ( HandleButtonMouseEvent(event,handlerFlags) )
328             return;
329     }
330     else
331     {
332         if ( isOnButtonArea || HasCapture() ||
333              (m_widthCustomPaint && mx < (m_tcArea.x+m_widthCustomPaint)) )
334         {
335             handlerFlags |= wxCC_MF_ON_CLICK_AREA;
336
337             if ( HandleButtonMouseEvent(event,handlerFlags) )
338                 return;
339         }
340         else if ( m_btnState )
341         {
342             // otherwise need to clear the hover status
343             m_btnState = 0;
344             RefreshRect(m_btnArea);
345         }
346     }
347
348     //
349     // This will handle left_down and left_dclick events outside button in a Windows/GTK-like manner.
350     // See header file for further information on this method.
351     HandleNormalMouseEvent(event);
352
353 }
354
355 void wxGenericComboCtrl::SetCustomPaintWidth( int width )
356 {
357 #ifdef UNRELIABLE_TEXTCTRL_BORDER
358     //
359     // If starting/stopping to show an image in front
360     // of a writable text-field, then re-create textctrl
361     // with different kind of border (because we can't
362     // assume that textctrl fully supports wxNO_BORDER).
363     //
364     wxTextCtrl* tc = GetTextCtrl();
365
366     if ( tc && (m_iFlags & wxCC_BUTTON_OUTSIDE_BORDER) )
367     {
368         int borderType = tc->GetWindowStyle() & wxBORDER_MASK;
369         int tcCreateStyle = -1;
370
371         if ( width > 0 )
372         {
373             // Re-create textctrl with no border
374             if ( borderType != wxNO_BORDER )
375             {
376                 m_widthCustomBorder = 1;
377                 tcCreateStyle = wxNO_BORDER;
378             }
379         }
380         else if ( width == 0 )
381         {
382             // Re-create textctrl with normal border
383             if ( borderType == wxNO_BORDER )
384             {
385                 m_widthCustomBorder = 0;
386                 tcCreateStyle = 0;
387             }
388         }
389
390         // Common textctrl re-creation code
391         if ( tcCreateStyle != -1 )
392         {
393             tc->RemoveEventHandler(m_textEvtHandler);
394             delete m_textEvtHandler;
395
396 #if wxUSE_VALIDATORS
397             wxValidator* pValidator = tc->GetValidator();
398             if ( pValidator )
399             {
400                 pValidator = (wxValidator*) pValidator->Clone();
401                 CreateTextCtrl( tcCreateStyle, *pValidator );
402                 delete pValidator;
403             }
404             else
405 #endif
406             {
407                 CreateTextCtrl( tcCreateStyle, wxDefaultValidator );
408             }
409
410             InstallInputHandlers();
411         }
412     }
413 #endif // UNRELIABLE_TEXTCTRL_BORDER
414
415     wxComboCtrlBase::SetCustomPaintWidth( width );
416 }
417
418 bool wxGenericComboCtrl::IsKeyPopupToggle(const wxKeyEvent& event) const
419 {
420     int keycode = event.GetKeyCode();
421     bool isPopupShown = IsPopupShown();
422
423     // This code is AFAIK appropriate for wxGTK.
424
425     if ( isPopupShown )
426     {
427         if ( keycode == WXK_ESCAPE ||
428              ( keycode == WXK_UP && event.AltDown() ) )
429             return true;
430     }
431     else
432     {
433         if ( keycode == WXK_DOWN && event.AltDown() )
434             return true;
435     }
436
437     return false;
438 }
439
440 #ifdef __WXUNIVERSAL__
441
442 bool wxGenericComboCtrl::PerformAction(const wxControlAction& action,
443                                        long numArg,
444                                        const wxString& strArg)
445 {
446     bool processed = false;
447     if ( action == wxACTION_COMBOBOX_POPUP )
448     {
449         if ( !IsPopupShown() )
450         {
451             ShowPopup();
452
453             processed = true;
454         }
455     }
456     else if ( action == wxACTION_COMBOBOX_DISMISS )
457     {
458         if ( IsPopupShown() )
459         {
460             HidePopup();
461
462             processed = true;
463         }
464     }
465
466     if ( !processed )
467     {
468         // pass along
469         return wxControl::PerformAction(action, numArg, strArg);
470     }
471
472     return true;
473 }
474
475 #endif // __WXUNIVERSAL__
476
477 // If native wxComboCtrl was not defined, then prepare a simple
478 // front-end so that wxRTTI works as expected.
479 #ifndef _WX_COMBOCONTROL_H_
480 IMPLEMENT_DYNAMIC_CLASS(wxComboCtrl, wxGenericComboCtrl)
481 #endif
482
483 #endif // !wxCOMBOCONTROL_FULLY_FEATURED
484
485 #endif // wxUSE_COMBOCTRL