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