]> git.saurik.com Git - wxWidgets.git/blame - src/generic/combog.cpp
Get DC size from GDK window if possible, client size can unfortunately be wrong
[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
c375936d
JS
258#ifdef __WXMAC__
259 wxPen pen1( wxColour(133,133,133),
260 customBorder,
261 wxSOLID );
e2ac737f 262#else
a340b80d
VZ
263 wxPen pen1( wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT),
264 customBorder,
04ee05f9 265 wxPENSTYLE_SOLID);
c375936d 266#endif
a340b80d
VZ
267 dc.SetPen( pen1 );
268
269 // area around both controls
10ba2677 270 wxRect rect2(fullRect);
a340b80d
VZ
271 if ( m_iFlags & wxCC_IFLAG_BUTTON_OUTSIDE )
272 {
10ba2677 273 rect2 = tcRect;
a340b80d
VZ
274 if ( customBorder == 1 )
275 {
276 rect2.Inflate(1);
277 }
278 else
279 {
280 #ifdef __WXGTK__
281 rect2.x -= 1;
282 rect2.y -= 1;
283 #else
284 rect2.x -= customBorder;
285 rect2.y -= customBorder;
286 #endif
287 rect2.width += 1 + customBorder;
288 rect2.height += 1 + customBorder;
289 }
290 }
291
292 dc.SetBrush( *wxTRANSPARENT_BRUSH );
293 dc.DrawRectangle(rect2);
294 }
295
10ba2677
JS
296 // Clear the main background if the system doesn't do it by itself
297 if ( !HasTransparentBackground() &&
298 (tcRect.x > 0 || tcRect.y > 0) )
299 {
300 wxColour winCol = GetParent()->GetBackgroundColour();
301 dc.SetBrush(winCol);
302 dc.SetPen(winCol);
a340b80d 303
10ba2677
JS
304 dc.DrawRectangle(fullRect);
305 }
03647350 306
a340b80d 307 if ( !m_btn )
373d466f 308 {
a340b80d 309 // Standard button rendering
10ba2677 310 DrawButton(dc, butRect);
373d466f 311 }
a340b80d
VZ
312
313 // paint required portion on the control
10ba2677 314 if ( !m_text || m_widthCustomPaint )
a340b80d
VZ
315 {
316 wxASSERT( m_widthCustomPaint >= 0 );
317
10ba2677
JS
318 // Clear the text-control area background
319 wxColour tcCol = GetBackgroundColour();
320 dc.SetBrush(tcCol);
321 dc.SetPen(tcCol);
322 dc.DrawRectangle(tcRect);
323
a340b80d
VZ
324 // this is intentionally here to allow drawed rectangle's
325 // right edge to be hidden
326 if ( m_text )
10ba2677 327 tcRect.width = m_widthCustomPaint;
a340b80d
VZ
328
329 dc.SetFont( GetFont() );
330
10ba2677 331 dc.SetClippingRegion(tcRect);
6d0ce565 332 if ( m_popupInterface )
10ba2677 333 m_popupInterface->PaintComboControl(dc, tcRect);
6d0ce565 334 else
10ba2677 335 wxComboPopup::DefaultPaintComboControl(this, dc, tcRect);
a340b80d 336 }
10ba2677
JS
337
338 delete dcPtr;
a340b80d
VZ
339}
340
129c8cf3 341void wxGenericComboCtrl::OnMouseEvent( wxMouseEvent& event )
a340b80d 342{
1efad474
RR
343 int mx = event.m_x;
344 bool isOnButtonArea = m_btnArea.Contains(mx,event.m_y);
a340b80d
VZ
345 int handlerFlags = isOnButtonArea ? wxCC_MF_ON_BUTTON : 0;
346
a340b80d
VZ
347 if ( PreprocessMouseEvent(event,handlerFlags) )
348 return;
349
406d283a 350 const bool ctrlIsButton = wxPlatformIs(wxOS_WINDOWS);
6d0ce565
VZ
351
352 if ( ctrlIsButton &&
353 (m_windowStyle & (wxCC_SPECIAL_DCLICK|wxCB_READONLY)) == wxCB_READONLY )
a340b80d
VZ
354 {
355 // if no textctrl and no special double-click, then the entire control acts
356 // as a button
357 handlerFlags |= wxCC_MF_ON_BUTTON;
358 if ( HandleButtonMouseEvent(event,handlerFlags) )
359 return;
360 }
361 else
362 {
1efad474
RR
363 if ( isOnButtonArea || HasCapture() ||
364 (m_widthCustomPaint && mx < (m_tcArea.x+m_widthCustomPaint)) )
a340b80d 365 {
1efad474
RR
366 handlerFlags |= wxCC_MF_ON_CLICK_AREA;
367
a340b80d
VZ
368 if ( HandleButtonMouseEvent(event,handlerFlags) )
369 return;
370 }
371 else if ( m_btnState )
372 {
373 // otherwise need to clear the hover status
374 m_btnState = 0;
375 RefreshRect(m_btnArea);
376 }
377 }
378
379 //
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);
383
384}
385
8e9ec723
RR
386void wxGenericComboCtrl::SetCustomPaintWidth( int width )
387{
388#ifdef UNRELIABLE_TEXTCTRL_BORDER
389 //
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).
394 //
395 wxTextCtrl* tc = GetTextCtrl();
396
397 if ( tc && (m_iFlags & wxCC_BUTTON_OUTSIDE_BORDER) )
398 {
399 int borderType = tc->GetWindowStyle() & wxBORDER_MASK;
400 int tcCreateStyle = -1;
401
402 if ( width > 0 )
403 {
404 // Re-create textctrl with no border
405 if ( borderType != wxNO_BORDER )
406 {
407 m_widthCustomBorder = 1;
408 tcCreateStyle = wxNO_BORDER;
409 }
410 }
411 else if ( width == 0 )
412 {
413 // Re-create textctrl with normal border
414 if ( borderType == wxNO_BORDER )
415 {
416 m_widthCustomBorder = 0;
417 tcCreateStyle = 0;
418 }
419 }
420
421 // Common textctrl re-creation code
422 if ( tcCreateStyle != -1 )
423 {
424 tc->RemoveEventHandler(m_textEvtHandler);
425 delete m_textEvtHandler;
426
fda62793 427 CreateTextCtrl( tcCreateStyle );
8e9ec723
RR
428
429 InstallInputHandlers();
430 }
431 }
432#endif // UNRELIABLE_TEXTCTRL_BORDER
433
434 wxComboCtrlBase::SetCustomPaintWidth( width );
435}
436
129c8cf3 437bool wxGenericComboCtrl::IsKeyPopupToggle(const wxKeyEvent& event) const
b445b6a7
VZ
438{
439 int keycode = event.GetKeyCode();
440 bool isPopupShown = IsPopupShown();
441
442 // This code is AFAIK appropriate for wxGTK.
443
444 if ( isPopupShown )
445 {
446 if ( keycode == WXK_ESCAPE ||
447 ( keycode == WXK_UP && event.AltDown() ) )
448 return true;
449 }
450 else
451 {
3b354b96
RR
452 if ( (keycode == WXK_DOWN && event.AltDown()) ||
453 (keycode == WXK_F4) )
b445b6a7
VZ
454 return true;
455 }
456
457 return false;
458}
459
a340b80d
VZ
460#ifdef __WXUNIVERSAL__
461
129c8cf3
RR
462bool wxGenericComboCtrl::PerformAction(const wxControlAction& action,
463 long numArg,
464 const wxString& strArg)
a340b80d
VZ
465{
466 bool processed = false;
467 if ( action == wxACTION_COMBOBOX_POPUP )
468 {
a305d600 469 if ( !IsPopupShown() )
a340b80d
VZ
470 {
471 ShowPopup();
472
473 processed = true;
474 }
475 }
476 else if ( action == wxACTION_COMBOBOX_DISMISS )
477 {
a305d600 478 if ( IsPopupShown() )
a340b80d
VZ
479 {
480 HidePopup();
481
482 processed = true;
483 }
484 }
485
486 if ( !processed )
487 {
488 // pass along
489 return wxControl::PerformAction(action, numArg, strArg);
490 }
491
492 return true;
493}
494
495#endif // __WXUNIVERSAL__
496
a57d600f 497// If native wxComboCtrl was not defined, then prepare a simple
a340b80d
VZ
498// front-end so that wxRTTI works as expected.
499#ifndef _WX_COMBOCONTROL_H_
129c8cf3 500IMPLEMENT_DYNAMIC_CLASS(wxComboCtrl, wxGenericComboCtrl)
a340b80d
VZ
501#endif
502
503#endif // !wxCOMBOCONTROL_FULLY_FEATURED
504
a57d600f 505#endif // wxUSE_COMBOCTRL