1. wxSingleChoiceDialog looks Ok under Windows
[wxWidgets.git] / src / generic / choicdgg.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: choicdgg.cpp
3 // Purpose: Choice dialogs
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "choicdgg.h"
14 #endif
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22
23 #ifndef WX_PRECOMP
24 #include <stdio.h>
25 #include "wx/utils.h"
26 #include "wx/dialog.h"
27 #include "wx/button.h"
28 #include "wx/listbox.h"
29 #include "wx/stattext.h"
30 #include "wx/intl.h"
31 #endif
32
33 #if wxUSE_STATLINE
34 #include "wx/statline.h"
35 #endif
36
37 #include "wx/generic/choicdgg.h"
38
39 #define wxID_LISTBOX 3000
40
41 wxString wxGetSingleChoice( const wxString& message, const wxString& caption, int n,
42 const wxString *choices, wxWindow *parent,
43 int WXUNUSED(x), int WXUNUSED(y), bool WXUNUSED(centre),
44 int WXUNUSED(width), int WXUNUSED(height) )
45 {
46 wxSingleChoiceDialog dialog(parent, message, caption, n, choices);
47 if ( dialog.ShowModal() == wxID_OK )
48 return dialog.GetStringSelection();
49 else
50 return _T("");
51 }
52
53 // Overloaded for backward compatibility
54 wxString wxGetSingleChoice( const wxString& message, const wxString& caption, int n,
55 char *choices[], wxWindow *parent,
56 int x, int y, bool centre,
57 int width, int height )
58 {
59 wxString *strings = new wxString[n];
60 int i;
61 for ( i = 0; i < n; i++)
62 {
63 strings[i] = choices[i];
64 }
65 wxString ans(wxGetSingleChoice(message, caption, n, (const wxString *)strings, parent,
66 x, y, centre, width, height));
67 delete[] strings;
68 return ans;
69 }
70
71 int wxGetSingleChoiceIndex( const wxString& message, const wxString& caption, int n,
72 const wxString *choices, wxWindow *parent,
73 int WXUNUSED(x), int WXUNUSED(y), bool WXUNUSED(centre),
74 int WXUNUSED(width), int WXUNUSED(height) )
75 {
76 wxSingleChoiceDialog dialog(parent, message, caption, n, choices);
77 if ( dialog.ShowModal() == wxID_OK )
78 return dialog.GetSelection();
79 else
80 return -1;
81 }
82
83 // Overloaded for backward compatibility
84 int wxGetSingleChoiceIndex( const wxString& message, const wxString& caption, int n,
85 wxChar *choices[], wxWindow *parent,
86 int x, int y, bool centre,
87 int width, int height )
88 {
89 wxString *strings = new wxString[n];
90 for ( int i = 0; i < n; i++)
91 strings[i] = choices[i];
92 int ans = wxGetSingleChoiceIndex(message, caption, n, (const wxString *)strings, parent,
93 x, y, centre, width, height);
94 delete[] strings;
95 return ans;
96 }
97
98 wxChar *wxGetSingleChoiceData( const wxString& message, const wxString& caption, int n,
99 const wxString *choices, wxChar **client_data, wxWindow *parent,
100 int WXUNUSED(x), int WXUNUSED(y), bool WXUNUSED(centre),
101 int WXUNUSED(width), int WXUNUSED(height) )
102 {
103 wxSingleChoiceDialog dialog(parent, message, caption, n, choices, client_data);
104 if ( dialog.ShowModal() == wxID_OK )
105 return dialog.GetSelectionClientData();
106 else
107 return NULL;
108 }
109
110 // Overloaded for backward compatibility
111 wxChar *wxGetSingleChoiceData( const wxString& message, const wxString& caption, int n,
112 wxChar *choices[], wxChar **client_data, wxWindow *parent,
113 int x, int y, bool centre,
114 int width, int height )
115 {
116 wxString *strings = new wxString[n];
117 int i;
118 for ( i = 0; i < n; i++)
119 {
120 strings[i] = choices[i];
121 }
122 wxChar *data = wxGetSingleChoiceData(message, caption, n, (const wxString *)strings, client_data, parent,
123 x, y, centre, width, height);
124 delete[] strings;
125 return data;
126 }
127
128
129 /* Multiple choice dialog contributed by Robert Cowell
130 *
131
132 The new data passed are in the "int nsel" and "int * selection"
133
134 The idea is to make a multiple selection from list of strings.
135 The returned value is the total number selected. initialily there
136 are nsel selected, with indices stored in
137 selection[0],...,selection[nsel-1] which appear highlighted to
138 begin with. On exit with value i
139 selection[0..i-1] contains the indices of the selected items.
140 (Some prior selectecions might be deselected.)
141 Thus selection must be as big as choices, in case all items are
142 selected.
143
144 */
145 /*
146 int wxGetMultipleChoice(const wxString& message, const wxString& caption,
147 int n, const wxString *choices,
148 int nsel, int * selection,
149 wxWindow *parent , int x , int y, bool centre,
150 int width, int height)
151 {
152 return -1;
153 }
154 */
155
156 // wxSingleChoiceDialog
157
158 #if !USE_SHARED_LIBRARY
159 BEGIN_EVENT_TABLE(wxSingleChoiceDialog, wxDialog)
160 EVT_BUTTON(wxID_OK, wxSingleChoiceDialog::OnOK)
161 EVT_LISTBOX_DCLICK(wxID_LISTBOX, wxSingleChoiceDialog::OnListBoxDClick)
162 END_EVENT_TABLE()
163
164 IMPLEMENT_CLASS(wxSingleChoiceDialog, wxDialog)
165 #endif
166
167 #define wxCHOICEDLG_DIALOG_STYLE (wxDEFAULT_DIALOG_STYLE | \
168 wxDIALOG_MODAL | \
169 wxTAB_TRAVERSAL)
170
171 wxSingleChoiceDialog::wxSingleChoiceDialog(wxWindow *parent,
172 const wxString& message,
173 const wxString& caption,
174 int n,
175 const wxString *choices,
176 char **clientData,
177 long style,
178 const wxPoint& pos)
179 : wxDialog(parent, -1, caption, pos, wxDefaultSize,
180 wxCHOICEDLG_DIALOG_STYLE)
181 {
182 Create(parent, message, caption, n, choices, clientData, style);
183 }
184
185 wxSingleChoiceDialog::wxSingleChoiceDialog(wxWindow *parent,
186 const wxString& message,
187 const wxString& caption,
188 const wxStringList& choices,
189 wxChar **clientData,
190 long style,
191 const wxPoint& pos)
192 : wxDialog(parent, -1, caption, pos, wxDefaultSize,
193 wxCHOICEDLG_DIALOG_STYLE)
194 {
195 Create(parent, message, caption, choices, clientData, style);
196 }
197
198 bool wxSingleChoiceDialog::Create(wxWindow *parent,
199 const wxString& message,
200 const wxString& caption,
201 const wxStringList& choices,
202 char **clientData,
203 long style,
204 const wxPoint& pos)
205 {
206 wxString *strings = new wxString[choices.Number()];
207 int i;
208 for ( i = 0; i < choices.Number(); i++)
209 {
210 strings[i] = (char *)choices.Nth(i)->Data();
211 }
212 bool ans = Create(parent, message, caption, choices.Number(), strings, clientData, style, pos);
213 delete[] strings;
214 return ans;
215 }
216
217 bool wxSingleChoiceDialog::Create( wxWindow *WXUNUSED(parent),
218 const wxString& message,
219 const wxString& WXUNUSED(caption),
220 int n,
221 const wxString *choices,
222 char **clientData,
223 long style,
224 const wxPoint& WXUNUSED(pos) )
225 {
226 m_dialogStyle = style;
227 m_selection = 0;
228 m_clientData = NULL;
229
230 // dialog layout constants
231 static const int LAYOUT_X_MARGIN = 5;
232 static const int LAYOUT_Y_MARGIN = 5;
233 static const int MARGIN_BETWEEN_BUTTONS = 3*LAYOUT_X_MARGIN;
234
235 // calc the message size
236 // ---------------------
237
238 // TODO this should be factored out to a common function (also used in
239 // msgdlgg.cpp)
240 wxClientDC dc(this);
241 dc.SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT));
242
243 wxArrayString lines;
244 wxString curLine;
245 long height, width, heightTextMax = 0, widthTextMax = 0;
246 for ( const char *pc = message; ; pc++ ) {
247 if ( *pc == '\n' || *pc == '\0' ) {
248 dc.GetTextExtent(curLine, &width, &height);
249 if ( width > widthTextMax )
250 widthTextMax = width;
251 if ( height > heightTextMax )
252 heightTextMax = height;
253
254 lines.Add(curLine);
255
256 if ( *pc == '\n' ) {
257 curLine.Empty();
258 }
259 else {
260 // the end of string
261 break;
262 }
263 }
264 else {
265 curLine += *pc;
266 }
267 }
268
269 size_t nLineCount = lines.Count();
270 long hTotalMsg = heightTextMax*nLineCount;
271
272 // calc the button size
273 // --------------------
274
275 bool hasCancel = FALSE;
276
277 // always create the OK button - the code below supposes we do have buttons
278 // and besides the user should have some way to close this dialog
279 wxASSERT_MSG( style & wxOK, _T("this dialog should have OK button") );
280
281 wxString labelOk(_("OK"));
282 long wButton = 0;
283 dc.GetTextExtent(labelOk, &width, NULL);
284 if ( width > wButton )
285 wButton = width;
286
287 wxString labelCancel;
288 if ( style & wxCANCEL )
289 {
290 labelCancel = _("Cancel");
291 dc.GetTextExtent(labelCancel, &width, NULL);
292 if ( width > wButton )
293 wButton = width;
294
295 hasCancel = TRUE;
296 }
297
298 if ( wButton < 75 )
299 wButton = 75;
300 else
301 wButton += 10;
302
303 long hButton = wButton*23/75;
304 long wTotalButtons = wButton;
305 if ( hasCancel )
306 {
307 wTotalButtons *= 2; // second button
308 wTotalButtons += MARGIN_BETWEEN_BUTTONS; // margin between the 2
309 }
310
311 // listbox and stat line
312 // ---------------------
313
314 // make the listbox at least as tall as the message - otherwise it looks
315 // ugly (the lower limit of 300 for the width is arbitrary OTOH)
316 //
317 // NB: we write "n + 2" because the horiz. scrollbar also takes some place
318 long hListbox = wxMax((n + 2) * heightTextMax, hTotalMsg),
319 wListbox = wxMax(300, wxMax(wTotalButtons, widthTextMax));
320
321 #if wxUSE_STATLINE
322 // arbitrary...
323 long hStatLine = 5;
324 #endif
325
326 // now the complete dialog size
327 // ----------------------------
328
329 long hDialog = 2*LAYOUT_Y_MARGIN + // top margin
330 hTotalMsg + // message
331 2*LAYOUT_Y_MARGIN + // margin between text and listbox
332 hListbox + // listbox
333 #if wxUSE_STATLINE
334 LAYOUT_Y_MARGIN + // margin
335 hStatLine + // separator line
336 #endif
337 2*LAYOUT_Y_MARGIN + // margin between listbox and buttons
338 hButton + // button(s)
339 LAYOUT_Y_MARGIN; // bottom margin
340
341 long wDialog = wxMax(wTotalButtons, widthTextMax) +
342 4*LAYOUT_X_MARGIN; // 2 from each side
343
344 // create the controls
345 // -------------------
346
347 // message
348 wxStaticText *text;
349 int y = 2*LAYOUT_Y_MARGIN;
350 for ( size_t nLine = 0; nLine < nLineCount; nLine++ )
351 {
352 text = new wxStaticText(this, -1, lines[nLine],
353 wxPoint(2*LAYOUT_X_MARGIN, y),
354 wxSize(widthTextMax, heightTextMax));
355 y += heightTextMax;
356 }
357
358 y += 2*LAYOUT_X_MARGIN;
359
360 // listbox
361 m_listbox = new wxListBox( this, wxID_LISTBOX,
362 wxPoint(2*LAYOUT_X_MARGIN, y),
363 wxSize(wListbox, hListbox),
364 n, choices,
365 wxLB_HSCROLL);
366 y += hListbox;
367
368 if ( clientData )
369 {
370 for (int i = 0; i < n; i++)
371 m_listbox->SetClientData(i, clientData[i]);
372 }
373
374 // separator line
375 #if wxUSE_STATLINE
376 (void) new wxStaticLine( this, -1,
377 wxPoint(0, y + LAYOUT_Y_MARGIN),
378 wxSize(wDialog, hStatLine) );
379
380 y += LAYOUT_Y_MARGIN + hStatLine;
381 #endif
382
383 // buttons
384
385 y += 2*LAYOUT_X_MARGIN;
386
387 // NB: create [Ok] first to get the right tab order
388
389 wxButton *ok = (wxButton *) NULL;
390 wxButton *cancel = (wxButton *) NULL;
391
392 long x = wDialog / 2;
393 if ( hasCancel )
394 x -= MARGIN_BETWEEN_BUTTONS / 2 + wButton;
395 else
396 x -= wButton / 2;
397
398 ok = new wxButton( this, wxID_OK, labelOk,
399 wxPoint(x, y),
400 wxSize(wButton, hButton) );
401
402 if ( hasCancel )
403 {
404 x += MARGIN_BETWEEN_BUTTONS + wButton;
405 cancel = new wxButton( this, wxID_CANCEL, labelCancel,
406 wxPoint(x, y),
407 wxSize(wButton, hButton) );
408 }
409
410 ok->SetDefault();
411 ok->SetFocus();
412
413 SetClientSize( wDialog, hDialog );
414
415 Centre( wxBOTH );
416
417 return TRUE;
418 }
419
420 // Set the selection
421 void wxSingleChoiceDialog::SetSelection(int sel)
422 {
423 m_listbox->SetSelection(sel);
424 m_selection = sel;
425 }
426
427 void wxSingleChoiceDialog::OnOK(wxCommandEvent& WXUNUSED(event))
428 {
429 m_selection = m_listbox->GetSelection();
430 m_stringSelection = m_listbox->GetStringSelection();
431 m_clientData = m_listbox->GetClientData(m_selection);
432
433 EndModal(wxID_OK);
434 }
435
436 void wxSingleChoiceDialog::OnListBoxDClick(wxCommandEvent& WXUNUSED(event))
437 {
438 m_selection = m_listbox->GetSelection();
439 m_stringSelection = m_listbox->GetStringSelection();
440 m_clientData = m_listbox->GetClientData(m_selection);
441
442 EndModal(wxID_OK);
443 }
444