1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/generic/combog.cpp
3 // Purpose: Generic wxComboCtrl
4 // Author: Jaakko Salli
6 // Created: Apr-30-2006
8 // Copyright: (c) 2005 Jaakko Salli
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 #include "wx/wxprec.h"
32 #include "wx/combobox.h"
33 #include "wx/dcclient.h"
34 #include "wx/settings.h"
35 #include "wx/textctrl.h"
38 #include "wx/dcbuffer.h"
40 // ----------------------------------------------------------------------------
41 // Some constant adjustments to make the generic more bearable
43 #if defined(__WXUNIVERSAL__)
45 // position adjustment for wxTextCtrl, to achieve zero left margin
46 // meaningless if LEFT_MARGIN_CAN_BE_SET set to 1 in combocmn.cpp
47 #define TEXTCTRLXADJUST 0
49 #define TEXTCTRLYADJUST 0
50 #define TEXTXADJUST 0 // how much is read-only text's x adjusted
51 #define DEFAULT_DROPBUTTON_WIDTH 19
53 #elif defined(__WXMSW__)
55 // position adjustment for wxTextCtrl, to achieve zero left margin
56 // meaningless if LEFT_MARGIN_CAN_BE_SET set to 1 in combocmn.cpp
57 #define TEXTCTRLXADJUST 2
59 #define TEXTCTRLYADJUST 3
60 #define TEXTXADJUST 0 // how much is read-only text's x adjusted
61 #define DEFAULT_DROPBUTTON_WIDTH 17
63 #elif defined(__WXGTK__)
65 // position adjustment for wxTextCtrl, to achieve zero left margin
66 // meaningless if LEFT_MARGIN_CAN_BE_SET set to 1 in combocmn.cpp
67 #define TEXTCTRLXADJUST -1
69 #define TEXTCTRLYADJUST 0
70 #define TEXTXADJUST 1 // how much is read-only text's x adjusted
71 #define DEFAULT_DROPBUTTON_WIDTH 23
73 #elif defined(__WXMAC__)
75 // position adjustment for wxTextCtrl, to achieve zero left margin
76 // meaningless if LEFT_MARGIN_CAN_BE_SET set to 1 in combocmn.cpp
77 #define TEXTCTRLXADJUST 0
79 #define TEXTCTRLYADJUST 0
80 #define TEXTXADJUST 0 // how much is read-only text's x adjusted
81 #define DEFAULT_DROPBUTTON_WIDTH 22
85 // position adjustment for wxTextCtrl, to achieve zero left margin
86 // meaningless if LEFT_MARGIN_CAN_BE_SET set to 1 in combocmn.cpp
87 #define TEXTCTRLXADJUST 0
89 #define TEXTCTRLYADJUST 0
90 #define TEXTXADJUST 0 // how much is read-only text's x adjusted
91 #define DEFAULT_DROPBUTTON_WIDTH 19
96 // ============================================================================
98 // ============================================================================
100 // Only implement if no native or it wasn't fully featured
101 #ifndef wxCOMBOCONTROL_FULLY_FEATURED
104 // ----------------------------------------------------------------------------
105 // wxGenericComboCtrl
106 // ----------------------------------------------------------------------------
108 BEGIN_EVENT_TABLE(wxGenericComboCtrl
, wxComboCtrlBase
)
109 EVT_PAINT(wxGenericComboCtrl::OnPaintEvent
)
110 EVT_MOUSE_EVENTS(wxGenericComboCtrl::OnMouseEvent
)
114 IMPLEMENT_DYNAMIC_CLASS(wxGenericComboCtrl
, wxComboCtrlBase
)
116 void wxGenericComboCtrl::Init()
120 bool wxGenericComboCtrl::Create(wxWindow
*parent
,
122 const wxString
& value
,
126 const wxValidator
& validator
,
127 const wxString
& name
)
130 // Note that technically we only support 'default' border and wxNO_BORDER.
131 long border
= style
& wxBORDER_MASK
;
132 int tcBorder
= wxNO_BORDER
;
134 #if defined(__WXUNIVERSAL__)
136 border
= wxBORDER_SIMPLE
;
137 #elif defined(__WXMSW__)
139 // For XP, have 1-width custom border, for older version use sunken
140 /*if ( wxUxThemeEngine::GetIfActive() )
142 border = wxBORDER_NONE;
143 m_widthCustomBorder = 1;
146 border
= wxBORDER_SUNKEN
;
150 // Generic version is optimized for wxGTK
153 #define UNRELIABLE_TEXTCTRL_BORDER
157 if ( style
& wxCB_READONLY
)
159 m_widthCustomBorder
= 1;
163 m_widthCustomBorder
= 0;
169 // Have textctrl instead use the border given.
173 // Because we are going to have button outside the border,
174 // let's use wxBORDER_NONE for the whole control.
175 border
= wxBORDER_NONE
;
177 Customize( wxCC_BUTTON_OUTSIDE_BORDER
|
178 wxCC_NO_TEXT_AUTO_SELECT
|
179 wxCC_BUTTON_STAYS_DOWN
);
183 style
= (style
& ~(wxBORDER_MASK
)) | border
;
184 if ( style
& wxCC_STD_BUTTON
)
185 m_iFlags
|= wxCC_POPUP_ON_MOUSE_UP
;
187 // create main window
188 if ( !wxComboCtrlBase::Create(parent
,
193 style
| wxFULL_REPAINT_ON_RESIZE
,
198 // Create textctrl, if necessary
199 CreateTextCtrl( tcBorder
, validator
);
201 // Add keyboard input handlers for main control and textctrl
202 InstallInputHandlers();
205 SetBackgroundStyle( wxBG_STYLE_CUSTOM
); // for double-buffering
207 // SetInitialSize should be called last
208 SetInitialSize(size
);
213 wxGenericComboCtrl::~wxGenericComboCtrl()
217 void wxGenericComboCtrl::OnResize()
220 // Recalculates button and textctrl areas
221 CalculateAreas(DEFAULT_DROPBUTTON_WIDTH
);
224 // Move separate button control, if any, to correct position
227 wxSize sz
= GetClientSize();
228 m_btn
->SetSize( m_btnArea
.x
+ m_btnSpacingX
,
229 (sz
.y
-m_btnSize
.y
)/2,
235 // Move textctrl, if any, accordingly
236 PositionTextCtrl( TEXTCTRLXADJUST
, TEXTCTRLYADJUST
);
239 void wxGenericComboCtrl::OnPaintEvent( wxPaintEvent
& WXUNUSED(event
) )
241 wxSize sz
= GetClientSize();
242 wxAutoBufferedPaintDC
dc(this);
244 const wxRect
& rectb
= m_btnArea
;
245 wxRect rect
= m_tcArea
;
247 // artificial simple border
248 if ( m_widthCustomBorder
)
250 int customBorder
= m_widthCustomBorder
;
253 wxPen
pen1( wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT
),
258 // area around both controls
259 wxRect
rect2(0,0,sz
.x
,sz
.y
);
260 if ( m_iFlags
& wxCC_IFLAG_BUTTON_OUTSIDE
)
263 if ( customBorder
== 1 )
273 rect2
.x
-= customBorder
;
274 rect2
.y
-= customBorder
;
276 rect2
.width
+= 1 + customBorder
;
277 rect2
.height
+= 1 + customBorder
;
281 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
282 dc
.DrawRectangle(rect2
);
285 #ifndef __WXMAC__ // see note in OnThemeChange
286 wxColour winCol
= GetBackgroundColour();
288 wxColour winCol
= wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW
);
293 //wxLogDebug(wxT("hei: %i tcy: %i tchei: %i"),GetClientSize().y,m_tcArea.y,m_tcArea.height);
294 //wxLogDebug(wxT("btnx: %i tcx: %i tcwid: %i"),m_btnArea.x,m_tcArea.x,m_tcArea.width);
296 // clear main background
297 dc
.DrawRectangle(rect
);
301 // Standard button rendering
302 DrawButton(dc
,rectb
);
305 // paint required portion on the control
306 if ( (!m_text
|| m_widthCustomPaint
) )
308 wxASSERT( m_widthCustomPaint
>= 0 );
310 // this is intentionally here to allow drawed rectangle's
311 // right edge to be hidden
313 rect
.width
= m_widthCustomPaint
;
315 dc
.SetFont( GetFont() );
317 dc
.SetClippingRegion(rect
);
318 if ( m_popupInterface
)
319 m_popupInterface
->PaintComboControl(dc
,rect
);
321 wxComboPopup::DefaultPaintComboControl(this,dc
,rect
);
325 void wxGenericComboCtrl::OnMouseEvent( wxMouseEvent
& event
)
328 bool isOnButtonArea
= m_btnArea
.Contains(mx
,event
.m_y
);
329 int handlerFlags
= isOnButtonArea
? wxCC_MF_ON_BUTTON
: 0;
331 if ( PreprocessMouseEvent(event
,handlerFlags
) )
334 const bool ctrlIsButton
= wxPlatformIs(wxOS_WINDOWS
);
337 (m_windowStyle
& (wxCC_SPECIAL_DCLICK
|wxCB_READONLY
)) == wxCB_READONLY
)
339 // if no textctrl and no special double-click, then the entire control acts
341 handlerFlags
|= wxCC_MF_ON_BUTTON
;
342 if ( HandleButtonMouseEvent(event
,handlerFlags
) )
347 if ( isOnButtonArea
|| HasCapture() ||
348 (m_widthCustomPaint
&& mx
< (m_tcArea
.x
+m_widthCustomPaint
)) )
350 handlerFlags
|= wxCC_MF_ON_CLICK_AREA
;
352 if ( HandleButtonMouseEvent(event
,handlerFlags
) )
355 else if ( m_btnState
)
357 // otherwise need to clear the hover status
359 RefreshRect(m_btnArea
);
364 // This will handle left_down and left_dclick events outside button in a Windows/GTK-like manner.
365 // See header file for further information on this method.
366 HandleNormalMouseEvent(event
);
370 void wxGenericComboCtrl::SetCustomPaintWidth( int width
)
372 #ifdef UNRELIABLE_TEXTCTRL_BORDER
374 // If starting/stopping to show an image in front
375 // of a writable text-field, then re-create textctrl
376 // with different kind of border (because we can't
377 // assume that textctrl fully supports wxNO_BORDER).
379 wxTextCtrl
* tc
= GetTextCtrl();
381 if ( tc
&& (m_iFlags
& wxCC_BUTTON_OUTSIDE_BORDER
) )
383 int borderType
= tc
->GetWindowStyle() & wxBORDER_MASK
;
384 int tcCreateStyle
= -1;
388 // Re-create textctrl with no border
389 if ( borderType
!= wxNO_BORDER
)
391 m_widthCustomBorder
= 1;
392 tcCreateStyle
= wxNO_BORDER
;
395 else if ( width
== 0 )
397 // Re-create textctrl with normal border
398 if ( borderType
== wxNO_BORDER
)
400 m_widthCustomBorder
= 0;
405 // Common textctrl re-creation code
406 if ( tcCreateStyle
!= -1 )
408 tc
->RemoveEventHandler(m_textEvtHandler
);
409 delete m_textEvtHandler
;
412 wxValidator
* pValidator
= tc
->GetValidator();
415 pValidator
= (wxValidator
*) pValidator
->Clone();
416 CreateTextCtrl( tcCreateStyle
, *pValidator
);
422 CreateTextCtrl( tcCreateStyle
, wxDefaultValidator
);
425 InstallInputHandlers();
428 #endif // UNRELIABLE_TEXTCTRL_BORDER
430 wxComboCtrlBase::SetCustomPaintWidth( width
);
433 bool wxGenericComboCtrl::IsKeyPopupToggle(const wxKeyEvent
& event
) const
435 int keycode
= event
.GetKeyCode();
436 bool isPopupShown
= IsPopupShown();
438 // This code is AFAIK appropriate for wxGTK.
442 if ( keycode
== WXK_ESCAPE
||
443 ( keycode
== WXK_UP
&& event
.AltDown() ) )
448 if ( (keycode
== WXK_DOWN
&& event
.AltDown()) ||
449 (keycode
== WXK_F4
) )
456 #ifdef __WXUNIVERSAL__
458 bool wxGenericComboCtrl::PerformAction(const wxControlAction
& action
,
460 const wxString
& strArg
)
462 bool processed
= false;
463 if ( action
== wxACTION_COMBOBOX_POPUP
)
465 if ( !IsPopupShown() )
472 else if ( action
== wxACTION_COMBOBOX_DISMISS
)
474 if ( IsPopupShown() )
485 return wxControl::PerformAction(action
, numArg
, strArg
);
491 #endif // __WXUNIVERSAL__
493 // If native wxComboCtrl was not defined, then prepare a simple
494 // front-end so that wxRTTI works as expected.
495 #ifndef _WX_COMBOCONTROL_H_
496 IMPLEMENT_DYNAMIC_CLASS(wxComboCtrl
, wxGenericComboCtrl
)
499 #endif // !wxCOMBOCONTROL_FULLY_FEATURED
501 #endif // wxUSE_COMBOCTRL