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