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 TEXTXADJUST 0 // how much is read-only text's x adjusted
50 #define DEFAULT_DROPBUTTON_WIDTH 19
52 #elif defined(__WXMSW__)
54 // position adjustment for wxTextCtrl, to achieve zero left margin
55 // meaningless if LEFT_MARGIN_CAN_BE_SET set to 1 in combocmn.cpp
56 #define TEXTCTRLXADJUST 2
58 #define TEXTXADJUST 0 // how much is read-only text's x adjusted
59 #define DEFAULT_DROPBUTTON_WIDTH 17
61 #elif defined(__WXGTK__)
63 // position adjustment for wxTextCtrl, to achieve zero left margin
64 // meaningless if LEFT_MARGIN_CAN_BE_SET set to 1 in combocmn.cpp
65 #define TEXTCTRLXADJUST -1
67 #define TEXTXADJUST 1 // how much is read-only text's x adjusted
68 #define DEFAULT_DROPBUTTON_WIDTH 23
70 #elif defined(__WXMAC__)
72 // position adjustment for wxTextCtrl, to achieve zero left margin
73 // meaningless if LEFT_MARGIN_CAN_BE_SET set to 1 in combocmn.cpp
74 #define TEXTCTRLXADJUST 0
76 #define TEXTXADJUST 0 // how much is read-only text's x adjusted
77 #define DEFAULT_DROPBUTTON_WIDTH 22
81 // position adjustment for wxTextCtrl, to achieve zero left margin
82 // meaningless if LEFT_MARGIN_CAN_BE_SET set to 1 in combocmn.cpp
83 #define TEXTCTRLXADJUST 0
85 #define TEXTXADJUST 0 // how much is read-only text's x adjusted
86 #define DEFAULT_DROPBUTTON_WIDTH 19
91 // ============================================================================
93 // ============================================================================
95 // Only implement if no native or it wasn't fully featured
96 #ifndef wxCOMBOCONTROL_FULLY_FEATURED
99 // ----------------------------------------------------------------------------
100 // wxGenericComboCtrl
101 // ----------------------------------------------------------------------------
103 BEGIN_EVENT_TABLE(wxGenericComboCtrl
, wxComboCtrlBase
)
104 EVT_PAINT(wxGenericComboCtrl::OnPaintEvent
)
105 EVT_MOUSE_EVENTS(wxGenericComboCtrl::OnMouseEvent
)
109 IMPLEMENT_DYNAMIC_CLASS(wxGenericComboCtrl
, wxComboCtrlBase
)
111 void wxGenericComboCtrl::Init()
115 bool wxGenericComboCtrl::Create(wxWindow
*parent
,
117 const wxString
& value
,
121 const wxValidator
& validator
,
122 const wxString
& name
)
125 // Note that technically we only support 'default' border and wxNO_BORDER.
126 long border
= style
& wxBORDER_MASK
;
127 int tcBorder
= wxNO_BORDER
;
129 #if defined(__WXUNIVERSAL__)
131 border
= wxBORDER_SIMPLE
;
132 #elif defined(__WXMSW__)
134 // For XP, have 1-width custom border, for older version use sunken
135 /*if ( wxUxThemeEngine::GetIfActive() )
137 border = wxBORDER_NONE;
138 m_widthCustomBorder = 1;
141 border
= wxBORDER_SUNKEN
;
145 // Generic version is optimized for wxGTK
148 #define UNRELIABLE_TEXTCTRL_BORDER
152 if ( style
& wxCB_READONLY
)
154 m_widthCustomBorder
= 1;
158 m_widthCustomBorder
= 0;
164 // Have textctrl instead use the border given.
168 // Because we are going to have button outside the border,
169 // let's use wxBORDER_NONE for the whole control.
170 border
= wxBORDER_NONE
;
172 Customize( wxCC_BUTTON_OUTSIDE_BORDER
|
173 wxCC_NO_TEXT_AUTO_SELECT
|
174 wxCC_BUTTON_STAYS_DOWN
);
178 style
= (style
& ~(wxBORDER_MASK
)) | border
;
179 if ( style
& wxCC_STD_BUTTON
)
180 m_iFlags
|= wxCC_POPUP_ON_MOUSE_UP
;
182 // create main window
183 if ( !wxComboCtrlBase::Create(parent
,
188 style
| wxFULL_REPAINT_ON_RESIZE
,
193 // Create textctrl, if necessary
194 CreateTextCtrl( tcBorder
);
196 // Add keyboard input handlers for main control and textctrl
197 InstallInputHandlers();
199 // Set background style for double-buffering, when needed
200 // (cannot use when system draws background automatically)
201 if ( !HasTransparentBackground() )
202 SetBackgroundStyle( wxBG_STYLE_PAINT
);
204 // SetInitialSize should be called last
205 SetInitialSize(size
);
210 wxGenericComboCtrl::~wxGenericComboCtrl()
214 void wxGenericComboCtrl::OnResize()
217 // Recalculates button and textctrl areas
218 CalculateAreas(DEFAULT_DROPBUTTON_WIDTH
);
221 // Move separate button control, if any, to correct position
224 wxSize sz
= GetClientSize();
225 m_btn
->SetSize( m_btnArea
.x
+ m_btnSpacingX
,
226 (sz
.y
-m_btnSize
.y
)/2,
232 // Move textctrl, if any, accordingly
233 PositionTextCtrl( TEXTCTRLXADJUST
);
236 void wxGenericComboCtrl::OnPaintEvent( wxPaintEvent
& WXUNUSED(event
) )
238 // Determine wxDC to use based on need to double-buffer or
239 // use system-generated transparent background portions
241 if ( HasTransparentBackground() )
242 dcPtr
= new wxPaintDC(this);
244 dcPtr
= new wxAutoBufferedPaintDC(this);
247 wxSize sz
= GetClientSize();
248 const wxRect
& butRect
= m_btnArea
;
249 wxRect tcRect
= m_tcArea
;
250 wxRect
fullRect(0, 0, sz
.x
, sz
.y
);
252 // artificial simple border
253 if ( m_widthCustomBorder
)
255 int customBorder
= m_widthCustomBorder
;
259 wxPen
pen1( wxColour(133,133,133),
263 wxPen
pen1( wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT
),
269 // area around both controls
270 wxRect
rect2(fullRect
);
271 if ( m_iFlags
& wxCC_IFLAG_BUTTON_OUTSIDE
)
274 if ( customBorder
== 1 )
284 rect2
.x
-= customBorder
;
285 rect2
.y
-= customBorder
;
287 rect2
.width
+= 1 + customBorder
;
288 rect2
.height
+= 1 + customBorder
;
292 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
293 dc
.DrawRectangle(rect2
);
296 // Clear the main background if the system doesn't do it by itself
297 if ( !HasTransparentBackground() &&
298 (tcRect
.x
> 0 || tcRect
.y
> 0) )
300 wxColour winCol
= GetParent()->GetBackgroundColour();
304 dc
.DrawRectangle(fullRect
);
309 // Standard button rendering
310 DrawButton(dc
, butRect
);
313 // paint required portion on the control
314 if ( !m_text
|| m_widthCustomPaint
)
316 wxASSERT( m_widthCustomPaint
>= 0 );
318 // Clear the text-control area background
319 wxColour tcCol
= GetBackgroundColour();
322 dc
.DrawRectangle(tcRect
);
324 // this is intentionally here to allow drawed rectangle's
325 // right edge to be hidden
327 tcRect
.width
= m_widthCustomPaint
;
329 dc
.SetFont( GetFont() );
331 dc
.SetClippingRegion(tcRect
);
332 if ( m_popupInterface
)
333 m_popupInterface
->PaintComboControl(dc
, tcRect
);
335 wxComboPopup::DefaultPaintComboControl(this, dc
, tcRect
);
341 void wxGenericComboCtrl::OnMouseEvent( wxMouseEvent
& event
)
344 bool isOnButtonArea
= m_btnArea
.Contains(mx
,event
.m_y
);
345 int handlerFlags
= isOnButtonArea
? wxCC_MF_ON_BUTTON
: 0;
347 if ( PreprocessMouseEvent(event
,handlerFlags
) )
350 const bool ctrlIsButton
= wxPlatformIs(wxOS_WINDOWS
);
353 (m_windowStyle
& (wxCC_SPECIAL_DCLICK
|wxCB_READONLY
)) == wxCB_READONLY
)
355 // if no textctrl and no special double-click, then the entire control acts
357 handlerFlags
|= wxCC_MF_ON_BUTTON
;
358 if ( HandleButtonMouseEvent(event
,handlerFlags
) )
363 if ( isOnButtonArea
|| HasCapture() ||
364 (m_widthCustomPaint
&& mx
< (m_tcArea
.x
+m_widthCustomPaint
)) )
366 handlerFlags
|= wxCC_MF_ON_CLICK_AREA
;
368 if ( HandleButtonMouseEvent(event
,handlerFlags
) )
371 else if ( m_btnState
)
373 // otherwise need to clear the hover status
375 RefreshRect(m_btnArea
);
380 // This will handle left_down and left_dclick events outside button in a Windows/GTK-like manner.
381 // See header file for further information on this method.
382 HandleNormalMouseEvent(event
);
386 void wxGenericComboCtrl::SetCustomPaintWidth( int width
)
388 #ifdef UNRELIABLE_TEXTCTRL_BORDER
390 // If starting/stopping to show an image in front
391 // of a writable text-field, then re-create textctrl
392 // with different kind of border (because we can't
393 // assume that textctrl fully supports wxNO_BORDER).
395 wxTextCtrl
* tc
= GetTextCtrl();
397 if ( tc
&& (m_iFlags
& wxCC_BUTTON_OUTSIDE_BORDER
) )
399 int borderType
= tc
->GetWindowStyle() & wxBORDER_MASK
;
400 int tcCreateStyle
= -1;
404 // Re-create textctrl with no border
405 if ( borderType
!= wxNO_BORDER
)
407 m_widthCustomBorder
= 1;
408 tcCreateStyle
= wxNO_BORDER
;
411 else if ( width
== 0 )
413 // Re-create textctrl with normal border
414 if ( borderType
== wxNO_BORDER
)
416 m_widthCustomBorder
= 0;
421 // Common textctrl re-creation code
422 if ( tcCreateStyle
!= -1 )
424 tc
->RemoveEventHandler(m_textEvtHandler
);
425 delete m_textEvtHandler
;
427 CreateTextCtrl( tcCreateStyle
);
429 InstallInputHandlers();
432 #endif // UNRELIABLE_TEXTCTRL_BORDER
434 wxComboCtrlBase::SetCustomPaintWidth( width
);
437 bool wxGenericComboCtrl::IsKeyPopupToggle(const wxKeyEvent
& event
) const
439 int keycode
= event
.GetKeyCode();
440 bool isPopupShown
= IsPopupShown();
442 // This code is AFAIK appropriate for wxGTK.
446 if ( keycode
== WXK_ESCAPE
||
447 ( keycode
== WXK_UP
&& event
.AltDown() ) )
452 if ( (keycode
== WXK_DOWN
&& event
.AltDown()) ||
453 (keycode
== WXK_F4
) )
460 #ifdef __WXUNIVERSAL__
462 bool wxGenericComboCtrl::PerformAction(const wxControlAction
& action
,
464 const wxString
& strArg
)
466 bool processed
= false;
467 if ( action
== wxACTION_COMBOBOX_POPUP
)
469 if ( !IsPopupShown() )
476 else if ( action
== wxACTION_COMBOBOX_DISMISS
)
478 if ( IsPopupShown() )
489 return wxControl::PerformAction(action
, numArg
, strArg
);
495 #endif // __WXUNIVERSAL__
497 // If native wxComboCtrl was not defined, then prepare a simple
498 // front-end so that wxRTTI works as expected.
499 #ifndef _WX_COMBOCONTROL_H_
500 IMPLEMENT_DYNAMIC_CLASS(wxComboCtrl
, wxGenericComboCtrl
)
503 #endif // !wxCOMBOCONTROL_FULLY_FEATURED
505 #endif // wxUSE_COMBOCTRL