fixes and missing files from the first wxComboControl patch (update of patch 1479938)
[wxWidgets.git] / src / generic / combog.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: combog.cpp
3 // Purpose: Generic wxComboControl
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
26 #if wxUSE_COMBOCONTROL
27
28 #ifndef WX_PRECOMP
29 #include "wx/log.h"
30 #include "wx/combobox.h"
31 #include "wx/dcclient.h"
32 #include "wx/settings.h"
33 #endif
34
35 #include "wx/dcbuffer.h"
36
37 #include "wx/combo.h"
38
39
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
69 #define DEFAULT_DROPBUTTON_WIDTH 19
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 // ----------------------------------------------------------------------------
90 // wxGenericComboControl
91 // ----------------------------------------------------------------------------
92
93 BEGIN_EVENT_TABLE(wxGenericComboControl, wxComboControlBase)
94 EVT_PAINT(wxGenericComboControl::OnPaintEvent)
95 EVT_MOUSE_EVENTS(wxGenericComboControl::OnMouseEvent)
96 END_EVENT_TABLE()
97
98
99 IMPLEMENT_DYNAMIC_CLASS(wxGenericComboControl, wxComboControlBase)
100
101 void wxGenericComboControl::Init()
102 {
103 }
104
105 bool wxGenericComboControl::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)
113 {
114
115 // Set border
116 long border = style & wxBORDER_MASK;
117
118 if ( !border )
119 {
120 #if defined(__WXUNIVERSAL__)
121 border = wxBORDER_SIMPLE;
122 #elif defined(__WXMSW__)
123 // For XP, have 1-width custom border, for older version use sunken
124 if ( wxUxThemeEngine::GetIfActive() )
125 {
126 border = wxBORDER_NONE;
127 m_widthCustomBorder = 1;
128 }
129 else
130 border = wxBORDER_SUNKEN;
131 #elif defined(__WXGTK__)
132 border = wxBORDER_NONE;
133 //m_widthCustomBorder = 2;
134 m_widthCustomBorder = 1;
135 #else
136 border = wxBORDER_SIMPLE;
137 #endif
138
139 style = (style & ~(wxBORDER_MASK)) | border;
140 }
141
142 #if defined(__WXGTK__)
143 Customize( wxCC_BUTTON_OUTSIDE_BORDER |
144 wxCC_NO_TEXT_AUTO_SELECT );
145 #endif
146
147 if ( style & wxCC_STD_BUTTON )
148 m_iFlags |= wxCC_POPUP_ON_MOUSE_UP;
149
150 // create main window
151 if ( !wxComboControlBase::Create(parent,
152 id,
153 value,
154 wxDefaultPosition,
155 wxDefaultSize,
156 style | wxFULL_REPAINT_ON_RESIZE,
157 wxDefaultValidator,
158 name) )
159 return false;
160
161 // Create textctrl, if necessary
162 CreateTextCtrl( wxNO_BORDER, validator );
163
164 // Add keyboard input handlers for main control and textctrl
165 InstallInputHandlers( true );
166
167 // Set background
168 SetBackgroundStyle( wxBG_STYLE_CUSTOM ); // for double-buffering
169
170 // SetSize should be called last
171 SetSize(pos.x,pos.y,size.x,size.y);
172
173 return true;
174 }
175
176 wxGenericComboControl::~wxGenericComboControl()
177 {
178 }
179
180 void wxGenericComboControl::OnResize()
181 {
182
183 // Recalculates button and textctrl areas
184 CalculateAreas(DEFAULT_DROPBUTTON_WIDTH);
185
186 #if 0
187 // Move separate button control, if any, to correct position
188 if ( m_btn )
189 {
190 wxSize sz = GetClientSize();
191 m_btn->SetSize( m_btnArea.x + m_btnSpacingX,
192 (sz.y-m_btnSize.y)/2,
193 m_btnSize.x,
194 m_btnSize.y );
195 }
196 #endif
197
198 // Move textctrl, if any, accordingly
199 PositionTextCtrl( TEXTCTRLXADJUST, TEXTCTRLYADJUST );
200 }
201
202 void wxGenericComboControl::OnPaintEvent( wxPaintEvent& WXUNUSED(event) )
203 {
204 wxSize sz = GetClientSize();
205 wxBufferedPaintDC dc(this,GetBufferBitmap(sz));
206
207 const wxRect& rectb = m_btnArea;
208 wxRect rect = m_tcArea;
209
210 // artificial simple border
211 if ( m_widthCustomBorder )
212 {
213 int customBorder = m_widthCustomBorder;
214
215 // Set border colour
216 wxPen pen1( wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT),
217 customBorder,
218 wxSOLID );
219 dc.SetPen( pen1 );
220
221 // area around both controls
222 wxRect rect2(0,0,sz.x,sz.y);
223 if ( m_iFlags & wxCC_IFLAG_BUTTON_OUTSIDE )
224 {
225 rect2 = m_tcArea;
226 if ( customBorder == 1 )
227 {
228 rect2.Inflate(1);
229 }
230 else
231 {
232 #ifdef __WXGTK__
233 rect2.x -= 1;
234 rect2.y -= 1;
235 #else
236 rect2.x -= customBorder;
237 rect2.y -= customBorder;
238 #endif
239 rect2.width += 1 + customBorder;
240 rect2.height += 1 + customBorder;
241 }
242 }
243
244 dc.SetBrush( *wxTRANSPARENT_BRUSH );
245 dc.DrawRectangle(rect2);
246 }
247
248 wxColour winCol = GetBackgroundColour();
249 dc.SetBrush(winCol);
250 dc.SetPen(winCol);
251
252 //wxLogDebug(wxT("hei: %i tcy: %i tchei: %i"),GetClientSize().y,m_tcArea.y,m_tcArea.height);
253 //wxLogDebug(wxT("btnx: %i tcx: %i tcwid: %i"),m_btnArea.x,m_tcArea.x,m_tcArea.width);
254
255 // clear main background
256 dc.DrawRectangle(rect);
257
258 if ( !m_btn )
259 // Standard button rendering
260 DrawButton(dc,rectb,true);
261
262 // paint required portion on the control
263 if ( (!m_text || m_widthCustomPaint) )
264 {
265 wxASSERT( m_widthCustomPaint >= 0 );
266
267 // this is intentionally here to allow drawed rectangle's
268 // right edge to be hidden
269 if ( m_text )
270 rect.width = m_widthCustomPaint;
271
272 dc.SetFont( GetFont() );
273
274 dc.SetClippingRegion(rect);
275 if ( m_popupInterface )
276 m_popupInterface->PaintComboControl(dc,rect);
277 else
278 wxComboPopup::DefaultPaintComboControl(this,dc,rect);
279 }
280 }
281
282 void wxGenericComboControl::OnMouseEvent( wxMouseEvent& event )
283 {
284 bool isOnButtonArea = m_btnArea.Inside(event.m_x,event.m_y);
285 int handlerFlags = isOnButtonArea ? wxCC_MF_ON_BUTTON : 0;
286
287 // Preprocessing fabricates double-clicks and prevents
288 // (it may also do other common things in future)
289 if ( PreprocessMouseEvent(event,handlerFlags) )
290 return;
291
292 #ifdef __WXMSW__
293 const bool ctrlIsButton = true;
294 #else
295 const bool ctrlIsButton = false;
296 #endif
297
298 if ( ctrlIsButton &&
299 (m_windowStyle & (wxCC_SPECIAL_DCLICK|wxCB_READONLY)) == wxCB_READONLY )
300 {
301 // if no textctrl and no special double-click, then the entire control acts
302 // as a button
303 handlerFlags |= wxCC_MF_ON_BUTTON;
304 if ( HandleButtonMouseEvent(event,handlerFlags) )
305 return;
306 }
307 else
308 {
309 if ( isOnButtonArea || HasCapture() )
310 {
311 if ( HandleButtonMouseEvent(event,handlerFlags) )
312 return;
313 }
314 else if ( m_btnState )
315 {
316 // otherwise need to clear the hover status
317 m_btnState = 0;
318 RefreshRect(m_btnArea);
319 }
320 }
321
322 //
323 // This will handle left_down and left_dclick events outside button in a Windows/GTK-like manner.
324 // See header file for further information on this method.
325 HandleNormalMouseEvent(event);
326
327 }
328
329 #ifdef __WXUNIVERSAL__
330
331 bool wxGenericComboControl::PerformAction(const wxControlAction& action,
332 long numArg,
333 const wxString& strArg)
334 {
335 bool processed = false;
336 if ( action == wxACTION_COMBOBOX_POPUP )
337 {
338 if ( !m_isPopupShown )
339 {
340 ShowPopup();
341
342 processed = true;
343 }
344 }
345 else if ( action == wxACTION_COMBOBOX_DISMISS )
346 {
347 if ( m_isPopupShown )
348 {
349 HidePopup();
350
351 processed = true;
352 }
353 }
354
355 if ( !processed )
356 {
357 // pass along
358 return wxControl::PerformAction(action, numArg, strArg);
359 }
360
361 return true;
362 }
363
364 #endif // __WXUNIVERSAL__
365
366 // If native wxComboControl was not defined, then prepare a simple
367 // front-end so that wxRTTI works as expected.
368 #ifndef _WX_COMBOCONTROL_H_
369 IMPLEMENT_DYNAMIC_CLASS(wxComboControl, wxGenericComboControl)
370 #endif
371
372 #endif // !wxCOMBOCONTROL_FULLY_FEATURED
373
374 #endif // wxUSE_COMBOCONTROL