Don't force ColWidth to always grow for wxGridCellAutoWrapStringRenderer (#1798)
[wxWidgets.git] / src / generic / gridctrl.cpp
1 ///////////////////////////////////////////////////////////////////////////
2 // Name: generic/gridctrl.cpp
3 // Purpose: wxGrid controls
4 // Author: Paul Gammans, Roger Gammans
5 // Modified by:
6 // Created: 11/04/2001
7 // RCS-ID: $Id$
8 // Copyright: (c) The Computer Surgery (paul@compsurg.co.uk)
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #include "wx/wxprec.h"
13
14 #ifdef __BORLANDC__
15 #pragma hdrstop
16 #endif
17
18 #if wxUSE_GRID
19
20 #include "wx/generic/gridctrl.h"
21
22 #ifndef WX_PRECOMP
23 #include "wx/textctrl.h"
24 #include "wx/dc.h"
25 #include "wx/combobox.h"
26 #endif // WX_PRECOMP
27
28 #include "wx/tokenzr.h"
29
30 // ----------------------------------------------------------------------------
31 // wxGridCellDateTimeRenderer
32 // ----------------------------------------------------------------------------
33
34 #if wxUSE_DATETIME
35
36 // Enables a grid cell to display a formatted date and or time
37
38 wxGridCellDateTimeRenderer::wxGridCellDateTimeRenderer(const wxString& outformat, const wxString& informat)
39 {
40 m_iformat = informat;
41 m_oformat = outformat;
42 m_tz = wxDateTime::Local;
43 m_dateDef = wxDefaultDateTime;
44 }
45
46 wxGridCellRenderer *wxGridCellDateTimeRenderer::Clone() const
47 {
48 wxGridCellDateTimeRenderer *renderer = new wxGridCellDateTimeRenderer;
49 renderer->m_iformat = m_iformat;
50 renderer->m_oformat = m_oformat;
51 renderer->m_dateDef = m_dateDef;
52 renderer->m_tz = m_tz;
53
54 return renderer;
55 }
56
57 wxString wxGridCellDateTimeRenderer::GetString(const wxGrid& grid, int row, int col)
58 {
59 wxGridTableBase *table = grid.GetTable();
60
61 bool hasDatetime = false;
62 wxDateTime val;
63 wxString text;
64 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_DATETIME) )
65 {
66 void * tempval = table->GetValueAsCustom(row, col,wxGRID_VALUE_DATETIME);
67
68 if (tempval)
69 {
70 val = *((wxDateTime *)tempval);
71 hasDatetime = true;
72 delete (wxDateTime *)tempval;
73 }
74
75 }
76
77 if (!hasDatetime )
78 {
79 text = table->GetValue(row, col);
80 const char * const end = val.ParseFormat(text, m_iformat, m_dateDef);
81 hasDatetime = end && !*end;
82 }
83
84 if ( hasDatetime )
85 text = val.Format(m_oformat, m_tz );
86
87 // If we failed to parse string just show what we where given?
88 return text;
89 }
90
91 void wxGridCellDateTimeRenderer::Draw(wxGrid& grid,
92 wxGridCellAttr& attr,
93 wxDC& dc,
94 const wxRect& rectCell,
95 int row, int col,
96 bool isSelected)
97 {
98 wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
99
100 SetTextColoursAndFont(grid, attr, dc, isSelected);
101
102 // draw the text right aligned by default
103 int hAlign, vAlign;
104 attr.GetAlignment(&hAlign, &vAlign);
105 hAlign = wxRIGHT;
106
107 wxRect rect = rectCell;
108 rect.Inflate(-1);
109
110 grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, hAlign, vAlign);
111 }
112
113 wxSize wxGridCellDateTimeRenderer::GetBestSize(wxGrid& grid,
114 wxGridCellAttr& attr,
115 wxDC& dc,
116 int row, int col)
117 {
118 return DoGetBestSize(attr, dc, GetString(grid, row, col));
119 }
120
121 void wxGridCellDateTimeRenderer::SetParameters(const wxString& params)
122 {
123 if (!params.empty())
124 m_oformat=params;
125 }
126
127 #endif // wxUSE_DATETIME
128
129 // ----------------------------------------------------------------------------
130 // wxGridCellChoiceNumberRenderer
131 // ----------------------------------------------------------------------------
132 // Renders a number as a textual equivalent.
133 // eg data in cell is 0,1,2 ... n the cell could be rendered as "John","Fred"..."Bob"
134
135
136 wxGridCellEnumRenderer::wxGridCellEnumRenderer(const wxString& choices)
137 {
138 if (!choices.empty())
139 SetParameters(choices);
140 }
141
142 wxGridCellRenderer *wxGridCellEnumRenderer::Clone() const
143 {
144 wxGridCellEnumRenderer *renderer = new wxGridCellEnumRenderer;
145 renderer->m_choices = m_choices;
146 return renderer;
147 }
148
149 wxString wxGridCellEnumRenderer::GetString(const wxGrid& grid, int row, int col)
150 {
151 wxGridTableBase *table = grid.GetTable();
152 wxString text;
153 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) )
154 {
155 int choiceno = table->GetValueAsLong(row, col);
156 text.Printf(_T("%s"), m_choices[ choiceno ].c_str() );
157 }
158 else
159 {
160 text = table->GetValue(row, col);
161 }
162
163
164 //If we faild to parse string just show what we where given?
165 return text;
166 }
167
168 void wxGridCellEnumRenderer::Draw(wxGrid& grid,
169 wxGridCellAttr& attr,
170 wxDC& dc,
171 const wxRect& rectCell,
172 int row, int col,
173 bool isSelected)
174 {
175 wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
176
177 SetTextColoursAndFont(grid, attr, dc, isSelected);
178
179 // draw the text right aligned by default
180 int hAlign, vAlign;
181 attr.GetAlignment(&hAlign, &vAlign);
182 hAlign = wxRIGHT;
183
184 wxRect rect = rectCell;
185 rect.Inflate(-1);
186
187 grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, hAlign, vAlign);
188 }
189
190 wxSize wxGridCellEnumRenderer::GetBestSize(wxGrid& grid,
191 wxGridCellAttr& attr,
192 wxDC& dc,
193 int row, int col)
194 {
195 return DoGetBestSize(attr, dc, GetString(grid, row, col));
196 }
197
198 void wxGridCellEnumRenderer::SetParameters(const wxString& params)
199 {
200 if ( !params )
201 {
202 // what can we do?
203 return;
204 }
205
206 m_choices.Empty();
207
208 wxStringTokenizer tk(params, _T(','));
209 while ( tk.HasMoreTokens() )
210 {
211 m_choices.Add(tk.GetNextToken());
212 }
213 }
214
215 #if wxUSE_COMBOBOX
216
217 // ----------------------------------------------------------------------------
218 // wxGridCellEnumEditor
219 // ----------------------------------------------------------------------------
220
221 // A cell editor which displays an enum number as a textual equivalent. eg
222 // data in cell is 0,1,2 ... n the cell could be displayed as
223 // "John","Fred"..."Bob" in the combo choice box
224
225 wxGridCellEnumEditor::wxGridCellEnumEditor(const wxString& choices)
226 :wxGridCellChoiceEditor()
227 {
228 m_startint = -1;
229
230 if (!choices.empty())
231 SetParameters(choices);
232 }
233
234 wxGridCellEditor *wxGridCellEnumEditor::Clone() const
235 {
236 wxGridCellEnumEditor *editor = new wxGridCellEnumEditor();
237 editor->m_startint = m_startint;
238 return editor;
239 }
240
241 void wxGridCellEnumEditor::BeginEdit(int row, int col, wxGrid* grid)
242 {
243 wxASSERT_MSG(m_control,
244 wxT("The wxGridCellEnumEditor must be Created first!"));
245
246 wxGridTableBase *table = grid->GetTable();
247
248 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) )
249 {
250 m_startint = table->GetValueAsLong(row, col);
251 }
252 else
253 {
254 wxString startValue = table->GetValue(row, col);
255 if (startValue.IsNumber() && !startValue.empty())
256 {
257 startValue.ToLong(&m_startint);
258 }
259 else
260 {
261 m_startint=-1;
262 }
263 }
264
265 Combo()->SetSelection(m_startint);
266 Combo()->SetInsertionPointEnd();
267 Combo()->SetFocus();
268
269 }
270
271 bool wxGridCellEnumEditor::EndEdit(int row, int col, wxGrid* grid)
272 {
273 int pos = Combo()->GetSelection();
274 bool changed = (pos != m_startint);
275 if (changed)
276 {
277 if (grid->GetTable()->CanSetValueAs(row, col, wxGRID_VALUE_NUMBER))
278 grid->GetTable()->SetValueAsLong(row, col, pos);
279 else
280 grid->GetTable()->SetValue(row, col,wxString::Format(wxT("%i"),pos));
281 }
282
283 return changed;
284 }
285
286 #endif // wxUSE_COMBOBOX
287
288 // ----------------------------------------------------------------------------
289 // wxGridCellAutoWrapStringEditor
290 // ----------------------------------------------------------------------------
291
292 void
293 wxGridCellAutoWrapStringEditor::Create(wxWindow* parent,
294 wxWindowID id,
295 wxEvtHandler* evtHandler)
296 {
297 wxGridCellTextEditor::DoCreate(parent, id, evtHandler,
298 wxTE_MULTILINE | wxTE_RICH);
299 }
300
301 void
302 wxGridCellAutoWrapStringRenderer::Draw(wxGrid& grid,
303 wxGridCellAttr& attr,
304 wxDC& dc,
305 const wxRect& rectCell,
306 int row, int col,
307 bool isSelected) {
308
309
310 wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
311
312 // now we only have to draw the text
313 SetTextColoursAndFont(grid, attr, dc, isSelected);
314
315 int horizAlign, vertAlign;
316 attr.GetAlignment(&horizAlign, &vertAlign);
317
318 wxRect rect = rectCell;
319 rect.Inflate(-1);
320
321 grid.DrawTextRectangle(dc, GetTextLines(grid,dc,attr,rect,row,col),
322 rect, horizAlign, vertAlign);
323 }
324
325
326 wxArrayString
327 wxGridCellAutoWrapStringRenderer::GetTextLines(wxGrid& grid,
328 wxDC& dc,
329 const wxGridCellAttr& attr,
330 const wxRect& rect,
331 int row, int col)
332 {
333 wxString data = grid.GetCellValue(row, col);
334
335 wxArrayString lines;
336 dc.SetFont(attr.GetFont());
337
338 //Taken from wxGrid again!
339 wxCoord x = 0, y = 0, curr_x = 0;
340 wxCoord max_x = rect.GetWidth();
341
342 dc.SetFont(attr.GetFont());
343 wxStringTokenizer tk(data , _T(" \n\t\r"));
344 wxString thisline = wxEmptyString;
345
346 while ( tk.HasMoreTokens() )
347 {
348 wxString tok = tk.GetNextToken();
349 //FIXME: this causes us to print an extra unnecesary
350 // space at the end of the line. But it
351 // is invisible , simplifies the size calculation
352 // and ensures tokens are separated in the display
353 tok += _T(" ");
354
355 dc.GetTextExtent(tok, &x, &y);
356 if ( curr_x + x > max_x)
357 {
358 lines.Add( wxString(thisline) );
359 thisline = tok;
360 curr_x=x;
361 }
362 else
363 {
364 thisline+= tok;
365 curr_x += x;
366 }
367 }
368 //Add last line
369 lines.Add( wxString(thisline) );
370
371 return lines;
372 }
373
374
375 wxSize
376 wxGridCellAutoWrapStringRenderer::GetBestSize(wxGrid& grid,
377 wxGridCellAttr& attr,
378 wxDC& dc,
379 int row, int col)
380 {
381 wxCoord x,y, height , width = grid.GetColSize(col) -20;
382 // for width, subtract 20 because ColSize includes a magin of 10 pixels
383 // that we do not want here and because we always start with an increment
384 // by 10 in the loop below.
385 int count = 250; //Limit iterations..
386
387 wxRect rect(0,0,width,10);
388
389 // M is a nice large character 'y' gives descender!.
390 dc.GetTextExtent(wxT("My"), &x, &y);
391
392 do
393 {
394 width+=10;
395 rect.SetWidth(width);
396 height = y * (wx_truncate_cast(wxCoord, GetTextLines(grid,dc,attr,rect,row,col).GetCount()));
397 count--;
398 // Search for a shape no taller than the golden ratio.
399 } while (count && (width < (height*1.68)) );
400
401
402 return wxSize(width,height);
403 }
404
405 #endif // wxUSE_GRID
406