readded wxEditableListBox as part of adv library
[wxWidgets.git] / src / generic / editlbox.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: editlbox.cpp
3 // Purpose: ListBox with editable items
4 // Author: Vaclav Slavik
5 // RCS-ID: $Id$
6 // Copyright: (c) Vaclav Slavik
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 // For compilers that support precompilation, includes "wx/wx.h".
11 #include "wx/wxprec.h"
12
13 #ifdef __BORLANDC__
14 #pragma hdrstop
15 #endif
16
17 // for all others, include the necessary headers (this file is usually all you
18 // need because it includes almost all "standard" wxWidgets headers)
19 #ifndef WX_PRECOMP
20 #include "wx/wx.h"
21 #endif
22
23 #include "wx/editlbox.h"
24 #include "wx/sizer.h"
25 #include "wx/listctrl.h"
26
27 static char * eledit_xpm[] = {
28 "16 16 3 1",
29 " c None",
30 ". c #000000",
31 "+ c #00007F",
32 " ",
33 " ",
34 " .. .. ",
35 " . ",
36 " . ",
37 " ++++ . ++++ ",
38 " ++ . ++ ++",
39 " +++++ . ++++++",
40 " ++ ++ . ++ ",
41 " ++ ++ . ++ ++",
42 " +++++ . ++++ ",
43 " . ",
44 " . ",
45 " .. .. ",
46 " ",
47 " "};
48
49 static char * elnew_xpm[] = {
50 "16 16 5 1",
51 " c None",
52 ". c #7F7F7F",
53 "+ c #FFFFFF",
54 "@ c #FFFF00",
55 "# c #000000",
56 " ",
57 " ",
58 " . .+ .@ ",
59 " . .@.@# # # ",
60 " @.@+.... # ",
61 " ... @@ ",
62 " @ . @. # ",
63 " .# .@ ",
64 " . # ",
65 " # ",
66 " # ",
67 " # ",
68 " # ",
69 " # # # # # # ",
70 " ",
71 " "};
72
73 static char * eldel_xpm[] = {
74 "16 16 3 1",
75 " c None",
76 ". c #7F0000",
77 "+ c #FFFFFF",
78 " ",
79 " ",
80 " ",
81 " ..+ ..+ ",
82 " ....+ ..+ ",
83 " ....+ ..+ ",
84 " ...+ .+ ",
85 " .....+ ",
86 " ...+ ",
87 " .....+ ",
88 " ...+ ..+ ",
89 " ...+ ..+ ",
90 " ...+ .+ ",
91 " ...+ .+ ",
92 " . . ",
93 " "};
94
95 static char * eldown_xpm[] = {
96 "16 16 2 1",
97 " c None",
98 ". c #000000",
99 " ",
100 " ",
101 " ... ",
102 " ... ",
103 " ... ",
104 " ... ",
105 " ... ",
106 " ... ",
107 " ........... ",
108 " ......... ",
109 " ....... ",
110 " ..... ",
111 " ... ",
112 " . ",
113 " ",
114 " "};
115
116 static char * elup_xpm[] = {
117 "16 16 2 1",
118 " c None",
119 ". c #000000",
120 " ",
121 " . ",
122 " ... ",
123 " ..... ",
124 " ....... ",
125 " ......... ",
126 " ........... ",
127 " ... ",
128 " ... ",
129 " ... ",
130 " ... ",
131 " ... ",
132 " ... ",
133 " ",
134 " ",
135 " "};
136
137 // list control with auto-resizable column:
138 class CleverListCtrl : public wxListCtrl
139 {
140 public:
141 CleverListCtrl(wxWindow *parent,
142 wxWindowID id = wxID_ANY,
143 const wxPoint &pos = wxDefaultPosition,
144 const wxSize &size = wxDefaultSize,
145 long style = wxLC_ICON,
146 const wxValidator& validator = wxDefaultValidator,
147 const wxString &name = wxListCtrlNameStr)
148 : wxListCtrl(parent, id, pos, size, style, validator, name)
149 {
150 CreateColumns();
151 }
152
153 void CreateColumns()
154 {
155 InsertColumn(0, _T("item"));
156 SizeColumns();
157 }
158
159 void SizeColumns()
160 {
161 int w = GetSize().x;
162 #ifdef __WXMSW__
163 w -= wxSystemSettings::GetMetric(wxSYS_VSCROLL_X) + 6;
164 #else
165 w -= 2*wxSystemSettings::GetMetric(wxSYS_VSCROLL_X);
166 #endif
167 SetColumnWidth(0, w);
168 }
169
170 private:
171 DECLARE_EVENT_TABLE()
172 void OnSize(wxSizeEvent& event)
173 {
174 SizeColumns();
175 event.Skip();
176 }
177 };
178
179 BEGIN_EVENT_TABLE(CleverListCtrl, wxListCtrl)
180 EVT_SIZE(CleverListCtrl::OnSize)
181 END_EVENT_TABLE()
182
183 IMPLEMENT_CLASS(wxEditableListBox, wxPanel)
184
185 // NB: generate the IDs at runtime to avoid conflict with XRCID values,
186 // they could cause XRCCTRL() failures in XRC-based dialogs
187 const int wxID_ELB_DELETE = wxNewId();
188 const int wxID_ELB_EDIT = wxNewId();
189 const int wxID_ELB_NEW = wxNewId();
190 const int wxID_ELB_UP = wxNewId();
191 const int wxID_ELB_DOWN = wxNewId();
192 const int wxID_ELB_LISTCTRL = wxNewId();
193
194 BEGIN_EVENT_TABLE(wxEditableListBox, wxPanel)
195 EVT_LIST_ITEM_SELECTED(wxID_ELB_LISTCTRL, wxEditableListBox::OnItemSelected)
196 EVT_LIST_END_LABEL_EDIT(wxID_ELB_LISTCTRL, wxEditableListBox::OnEndLabelEdit)
197 EVT_BUTTON(wxID_ELB_NEW, wxEditableListBox::OnNewItem)
198 EVT_BUTTON(wxID_ELB_UP, wxEditableListBox::OnUpItem)
199 EVT_BUTTON(wxID_ELB_DOWN, wxEditableListBox::OnDownItem)
200 EVT_BUTTON(wxID_ELB_EDIT, wxEditableListBox::OnEditItem)
201 EVT_BUTTON(wxID_ELB_DELETE, wxEditableListBox::OnDelItem)
202 END_EVENT_TABLE()
203
204 wxEditableListBox::wxEditableListBox(wxWindow *parent, wxWindowID id,
205 const wxString& label,
206 const wxPoint& pos, const wxSize& size,
207 long style,
208 const wxString& name)
209 : wxPanel(parent, id, pos, size, wxTAB_TRAVERSAL, name)
210 {
211 m_style = style;
212 m_bEdit = m_bNew = m_bDel = m_bUp = m_bDown = NULL;
213
214 wxSizer *sizer = new wxBoxSizer(wxVERTICAL);
215
216 wxPanel *subp = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
217 wxSUNKEN_BORDER | wxTAB_TRAVERSAL);
218 wxSizer *subsizer = new wxBoxSizer(wxHORIZONTAL);
219 subsizer->Add(new wxStaticText(subp, wxID_ANY, label), 1, wxALIGN_CENTRE_VERTICAL | wxLEFT, 4);
220
221 #ifdef __WXMSW__
222 #define BTN_BORDER 4
223 // FIXME - why is this needed? There's some reason why sunken border is
224 // ignored by sizers in wxMSW but not in wxGTK that I can't
225 // figure out...
226 #else
227 #define BTN_BORDER 0
228 #endif
229
230 if ( m_style & wxEL_ALLOW_EDIT )
231 {
232 m_bEdit = new wxBitmapButton(subp, wxID_ELB_EDIT, wxBitmap(eledit_xpm));
233 subsizer->Add(m_bEdit, 0, wxALIGN_CENTRE_VERTICAL | wxTOP | wxBOTTOM, BTN_BORDER);
234 }
235
236 if ( m_style & wxEL_ALLOW_NEW )
237 {
238 m_bNew = new wxBitmapButton(subp, wxID_ELB_NEW, wxBitmap(elnew_xpm));
239 subsizer->Add(m_bNew, 0, wxALIGN_CENTRE_VERTICAL | wxTOP | wxBOTTOM, BTN_BORDER);
240 }
241
242 if ( m_style & wxEL_ALLOW_DELETE )
243 {
244 m_bDel = new wxBitmapButton(subp, wxID_ELB_DELETE, wxBitmap(eldel_xpm));
245 subsizer->Add(m_bDel, 0, wxALIGN_CENTRE_VERTICAL | wxTOP | wxBOTTOM, BTN_BORDER);
246 }
247
248 if (!(m_style & wxEL_NO_REORDER))
249 {
250 m_bUp = new wxBitmapButton(subp, wxID_ELB_UP, wxBitmap(elup_xpm));
251 subsizer->Add(m_bUp, 0, wxALIGN_CENTRE_VERTICAL | wxTOP | wxBOTTOM, BTN_BORDER);
252
253 m_bDown = new wxBitmapButton(subp, wxID_ELB_DOWN, wxBitmap(eldown_xpm));
254 subsizer->Add(m_bDown, 0, wxALIGN_CENTRE_VERTICAL | wxTOP | wxBOTTOM, BTN_BORDER);
255 }
256
257 #if wxUSE_TOOLTIPS
258 if ( m_bEdit ) m_bEdit->SetToolTip(_("Edit item"));
259 if ( m_bNew ) m_bNew->SetToolTip(_("New item"));
260 if ( m_bDel ) m_bDel->SetToolTip(_("Delete item"));
261 if ( m_bUp ) m_bUp->SetToolTip(_("Move up"));
262 if ( m_bDown ) m_bDown->SetToolTip(_("Move down"));
263 #endif
264
265 subp->SetSizer(subsizer);
266 subsizer->Fit(subp);
267
268 sizer->Add(subp, 0, wxEXPAND);
269
270 long st = wxLC_REPORT | wxLC_NO_HEADER | wxLC_SINGLE_SEL | wxSUNKEN_BORDER;
271 if ( style & wxEL_ALLOW_EDIT )
272 st |= wxLC_EDIT_LABELS;
273 m_listCtrl = new CleverListCtrl(this, wxID_ELB_LISTCTRL,
274 wxDefaultPosition, wxDefaultSize, st);
275 wxArrayString empty_ar;
276 SetStrings(empty_ar);
277
278 sizer->Add(m_listCtrl, 1, wxEXPAND);
279
280 SetSizer(sizer);
281 Layout();
282 }
283
284 void wxEditableListBox::SetStrings(const wxArrayString& strings)
285 {
286 m_listCtrl->DeleteAllItems();
287 size_t i;
288
289 for (i = 0; i < strings.GetCount(); i++)
290 m_listCtrl->InsertItem(i, strings[i]);
291
292 m_listCtrl->InsertItem(strings.GetCount(), wxEmptyString);
293 m_listCtrl->SetItemState(0, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
294 }
295
296 void wxEditableListBox::GetStrings(wxArrayString& strings) const
297 {
298 strings.Clear();
299
300 for (int i = 0; i < m_listCtrl->GetItemCount()-1; i++)
301 strings.Add(m_listCtrl->GetItemText(i));
302 }
303
304 void wxEditableListBox::OnItemSelected(wxListEvent& event)
305 {
306 m_selection = event.GetIndex();
307 if (!(m_style & wxEL_NO_REORDER))
308 {
309 m_bUp->Enable(m_selection != 0 && m_selection < m_listCtrl->GetItemCount()-1);
310 m_bDown->Enable(m_selection < m_listCtrl->GetItemCount()-2);
311 }
312
313 if (m_style & wxEL_ALLOW_EDIT)
314 m_bEdit->Enable(m_selection < m_listCtrl->GetItemCount()-1);
315 if (m_style & wxEL_ALLOW_DELETE)
316 m_bDel->Enable(m_selection < m_listCtrl->GetItemCount()-1);
317 }
318
319 void wxEditableListBox::OnNewItem(wxCommandEvent& WXUNUSED(event))
320 {
321 m_listCtrl->SetItemState(m_listCtrl->GetItemCount()-1,
322 wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
323 m_listCtrl->EditLabel(m_selection);
324 }
325
326 void wxEditableListBox::OnEndLabelEdit(wxListEvent& event)
327 {
328 if ( event.GetIndex() == m_listCtrl->GetItemCount()-1 &&
329 !event.GetText().empty() )
330 {
331 // The user edited last (empty) line, i.e. added new entry. We have to
332 // add new empty line here so that adding one more line is still
333 // possible:
334 m_listCtrl->InsertItem(m_listCtrl->GetItemCount(), wxEmptyString);
335
336 // Simulate a wxEVT_COMMAND_LIST_ITEM_SELECTED event for the new item,
337 // so that the buttons are enabled/disabled properly
338 wxListEvent selectionEvent(wxEVT_COMMAND_LIST_ITEM_SELECTED, m_listCtrl->GetId());
339 selectionEvent.m_itemIndex = event.GetIndex();
340 m_listCtrl->GetEventHandler()->ProcessEvent(selectionEvent);
341 }
342 }
343
344 void wxEditableListBox::OnDelItem(wxCommandEvent& WXUNUSED(event))
345 {
346 m_listCtrl->DeleteItem(m_selection);
347 m_listCtrl->SetItemState(m_selection,
348 wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
349 }
350
351 void wxEditableListBox::OnEditItem(wxCommandEvent& WXUNUSED(event))
352 {
353 m_listCtrl->EditLabel(m_selection);
354 }
355
356 void wxEditableListBox::OnUpItem(wxCommandEvent& WXUNUSED(event))
357 {
358 wxString t1, t2;
359
360 t1 = m_listCtrl->GetItemText(m_selection - 1);
361 t2 = m_listCtrl->GetItemText(m_selection);
362 m_listCtrl->SetItemText(m_selection - 1, t2);
363 m_listCtrl->SetItemText(m_selection, t1);
364 m_listCtrl->SetItemState(m_selection - 1,
365 wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
366 }
367
368 void wxEditableListBox::OnDownItem(wxCommandEvent& WXUNUSED(event))
369 {
370 wxString t1, t2;
371
372 t1 = m_listCtrl->GetItemText(m_selection + 1);
373 t2 = m_listCtrl->GetItemText(m_selection);
374 m_listCtrl->SetItemText(m_selection + 1, t2);
375 m_listCtrl->SetItemText(m_selection, t1);
376 m_listCtrl->SetItemState(m_selection + 1,
377 wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
378 }