implement click events in wxHeaderCtrl
[wxWidgets.git] / src / generic / headerctrlg.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/generic/headerctrlg.cpp
3 // Purpose: generic wxHeaderCtrl implementation
4 // Author: Vadim Zeitlin
5 // Created: 2008-12-03
6 // RCS-ID: $Id$
7 // Copyright: (c) 2008 Vadim Zeitlin <vadim@wxwidgets.org>
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
10
11 // ============================================================================
12 // declarations
13 // ============================================================================
14
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18
19 // for compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21
22 #ifdef __BORLANDC__
23 #pragma hdrstop
24 #endif
25
26 #ifndef WX_PRECOMP
27 #endif // WX_PRECOMP
28
29 #include "wx/headerctrl.h"
30
31 #ifdef wxHAS_GENERIC_HEADERCTRL
32
33 #include "wx/dcbuffer.h"
34 #include "wx/renderer.h"
35
36 // ----------------------------------------------------------------------------
37 // constants
38 // ----------------------------------------------------------------------------
39
40 namespace
41 {
42
43 const unsigned NO_SORT = (unsigned)-1;
44
45 const unsigned COL_NONE = (unsigned)-1;
46
47 } // anonymous namespace
48
49 // ============================================================================
50 // wxHeaderCtrl implementation
51 // ============================================================================
52
53 // ----------------------------------------------------------------------------
54 // wxHeaderCtrl creation
55 // ----------------------------------------------------------------------------
56
57 void wxHeaderCtrl::Init()
58 {
59 m_numColumns = 0;
60 m_hover = COL_NONE;
61 m_scrollOffset = 0;
62 }
63
64 bool wxHeaderCtrl::Create(wxWindow *parent,
65 wxWindowID id,
66 const wxPoint& pos,
67 const wxSize& size,
68 long style,
69 const wxString& name)
70 {
71 if ( !wxHeaderCtrlBase::Create(parent, id, pos, size,
72 style, wxDefaultValidator, name) )
73 return false;
74
75 // tell the system to not paint the background at all to avoid flicker as
76 // we paint the entire window area in our OnPaint()
77 SetBackgroundStyle(wxBG_STYLE_CUSTOM);
78
79 return true;
80 }
81
82 wxHeaderCtrl::~wxHeaderCtrl()
83 {
84 }
85
86 // ----------------------------------------------------------------------------
87 // wxHeaderCtrl columns manipulation
88 // ----------------------------------------------------------------------------
89
90 void wxHeaderCtrl::DoSetCount(unsigned int count)
91 {
92 m_numColumns = count;
93
94 Refresh();
95 }
96
97 unsigned int wxHeaderCtrl::DoGetCount() const
98 {
99 return m_numColumns;
100 }
101
102 void wxHeaderCtrl::DoUpdate(unsigned int idx)
103 {
104 // we need to refresh not only this column but also the ones after it in
105 // case it was shown or hidden or its width changed -- it would be nice to
106 // avoid doing this unnecessary by storing the old column width (TODO)
107 RefreshColsAfter(idx);
108 }
109
110 // ----------------------------------------------------------------------------
111 // wxHeaderCtrl scrolling
112 // ----------------------------------------------------------------------------
113
114 void wxHeaderCtrl::DoScrollHorz(int dx)
115 {
116 m_scrollOffset += dx;
117
118 // don't call our own version which calls this function!
119 wxControl::ScrollWindow(dx, 0);
120 }
121
122 // ----------------------------------------------------------------------------
123 // wxHeaderCtrl geometry
124 // ----------------------------------------------------------------------------
125
126 wxSize wxHeaderCtrl::DoGetBestSize() const
127 {
128 // the vertical size is rather arbitrary but it looks better if we leave
129 // some space around the text
130 return wxSize(GetColStart(GetColumnCount()), (7*GetCharHeight())/4);
131 }
132
133 int wxHeaderCtrl::GetColStart(unsigned int idx) const
134 {
135 wxHeaderCtrl * const self = const_cast<wxHeaderCtrl *>(this);
136
137 int pos = 0;
138 for ( unsigned n = 0; n < idx; n++ )
139 {
140 const wxHeaderColumnBase& col = self->GetColumn(n);
141 if ( col.IsShown() )
142 pos += col.GetWidth();
143 }
144
145 return pos;
146 }
147
148 int wxHeaderCtrl::FindColumnAtPos(int x, bool& onSeparator) const
149 {
150 wxHeaderCtrl * const self = const_cast<wxHeaderCtrl *>(this);
151
152 int pos = 0;
153 const unsigned count = GetColumnCount();
154 for ( unsigned n = 0; n < count; n++ )
155 {
156 const wxHeaderColumnBase& col = self->GetColumn(n);
157 if ( col.IsHidden() )
158 continue;
159
160 pos += col.GetWidth();
161
162 // if the column is resizeable, check if we're approximatively over the
163 // line separating it from the next column
164 //
165 // TODO: don't hardcode sensitivity
166 if ( col.IsResizeable() && abs(x - pos) < 8 )
167 {
168 onSeparator = true;
169 return n;
170 }
171
172 // inside this column?
173 if ( x < pos )
174 {
175 onSeparator = false;
176 return n;
177 }
178 }
179
180 return COL_NONE;
181 }
182
183 // ----------------------------------------------------------------------------
184 // wxHeaderCtrl repainting
185 // ----------------------------------------------------------------------------
186
187 void wxHeaderCtrl::RefreshCol(unsigned int idx)
188 {
189 wxRect rect = GetClientRect();
190 rect.x += GetColStart(idx);
191 rect.width = GetColumn(idx).GetWidth();
192
193 RefreshRect(rect);
194 }
195
196 void wxHeaderCtrl::RefreshColsAfter(unsigned int idx)
197 {
198 wxRect rect = GetClientRect();
199 const int ofs = GetColStart(idx);
200 rect.x += ofs;
201 rect.width -= ofs;
202
203 RefreshRect(rect);
204 }
205
206 // ----------------------------------------------------------------------------
207 // wxHeaderCtrl event handlers
208 // ----------------------------------------------------------------------------
209
210 BEGIN_EVENT_TABLE(wxHeaderCtrl, wxControl)
211 EVT_PAINT(wxHeaderCtrl::OnPaint)
212
213 EVT_MOUSE_EVENTS(wxHeaderCtrl::OnMouse)
214 END_EVENT_TABLE()
215
216 void wxHeaderCtrl::OnPaint(wxPaintEvent& WXUNUSED(event))
217 {
218 int w, h;
219 GetClientSize(&w, &h);
220
221 wxAutoBufferedPaintDC dc(this);
222
223 dc.SetBackground(GetBackgroundColour());
224 dc.Clear();
225
226 // account for the horizontal scrollbar offset in the parent window
227 dc.SetDeviceOrigin(m_scrollOffset, 0);
228
229 const unsigned int count = m_numColumns;
230 int xpos = 0;
231 for ( unsigned int i = 0; i < count; i++ )
232 {
233 const wxHeaderColumnBase& col = GetColumn(i);
234 if ( col.IsHidden() )
235 continue;
236
237 const int colWidth = col.GetWidth();
238
239 wxHeaderSortIconType sortArrow;
240 if ( col.IsSortKey() )
241 {
242 sortArrow = col.IsSortOrderAscending() ? wxHDR_SORT_ICON_UP
243 : wxHDR_SORT_ICON_DOWN;
244 }
245 else // not sorting by this column
246 {
247 sortArrow = wxHDR_SORT_ICON_NONE;
248 }
249
250 int state = 0;
251 if ( IsEnabled() )
252 {
253 if ( i == m_hover )
254 state = wxCONTROL_CURRENT;
255 }
256 else // disabled
257 {
258 state = wxCONTROL_DISABLED;
259 }
260
261 wxHeaderButtonParams params;
262 params.m_labelText = col.GetTitle();
263 params.m_labelBitmap = col.GetBitmap();
264 params.m_labelAlignment = col.GetAlignment();
265
266 wxRendererNative::Get().DrawHeaderButton
267 (
268 this,
269 dc,
270 wxRect(xpos, 0, colWidth, h),
271 state,
272 sortArrow,
273 &params
274 );
275
276 xpos += colWidth;
277 }
278 }
279
280 void wxHeaderCtrl::OnMouse(wxMouseEvent& mevent)
281 {
282 mevent.Skip();
283
284 // find if the event is over a column at all
285 bool onSeparator;
286 const unsigned col = FindColumnAtPos(mevent.GetX(), onSeparator);
287 if ( col == COL_NONE )
288 return;
289
290 // update mouse cursor as it moves around
291 if ( mevent.Moving() )
292 {
293 SetCursor(onSeparator ? wxCursor(wxCURSOR_SIZEWE) : wxNullCursor);
294 return;
295 }
296
297 if ( mevent.LeftDown() )
298 {
299 // TODO
300 if ( onSeparator )
301 // resize column
302 ;
303 else
304 // drag column
305 ;
306
307 return;
308 }
309
310 // determine the type of header event corresponding to this mouse event
311 wxEventType evtType;
312 const bool click = mevent.ButtonUp();
313 if ( click || mevent.ButtonDClick() )
314 {
315 switch ( mevent.GetButton() )
316 {
317 case wxMOUSE_BTN_LEFT:
318 evtType = click ? wxEVT_COMMAND_HEADER_CLICK
319 : wxEVT_COMMAND_HEADER_DCLICK;
320 break;
321
322 case wxMOUSE_BTN_RIGHT:
323 evtType = click ? wxEVT_COMMAND_HEADER_RIGHT_CLICK
324 : wxEVT_COMMAND_HEADER_RIGHT_DCLICK;
325 break;
326
327 case wxMOUSE_BTN_MIDDLE:
328 evtType = click ? wxEVT_COMMAND_HEADER_MIDDLE_CLICK
329 : wxEVT_COMMAND_HEADER_MIDDLE_DCLICK;
330 break;
331
332 default:
333 // ignore clicks from other mouse buttons
334 return;
335 }
336
337 wxHeaderCtrlEvent event(evtType, GetId());
338 event.SetEventObject(this);
339 event.SetColumn(col);
340
341 if ( GetEventHandler()->ProcessEvent(event) )
342 mevent.Skip(false);
343 }
344 }
345
346 #endif // wxHAS_GENERIC_HEADERCTRL