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