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