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