1 ///////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     ListBox with editable items 
   4 // Author:      Vaclav Slavik 
   6 // Copyright:   (c) Vaclav Slavik 
   7 // Licence:     wxWindows licence 
   8 ///////////////////////////////////////////////////////////////////////////// 
  10 // For compilers that support precompilation, includes "wx/wx.h". 
  11 #include "wx/wxprec.h" 
  17 #if wxUSE_EDITABLELISTBOX 
  19 // for all others, include the necessary headers (this file is usually all you 
  20 // need because it includes almost all "standard" wxWidgets headers) 
  25 #include "wx/editlbox.h" 
  27 #include "wx/listctrl.h" 
  29 // ============================================================================ 
  31 // ============================================================================ 
  33 const char wxEditableListBoxNameStr
[] = "editableListBox"; 
  35 static const char * eledit_xpm
[] = { 
  57 static const char * elnew_xpm
[] = { 
  81 static const char * eldel_xpm
[] = { 
 103 static const char * eldown_xpm
[] = { 
 124 static const char * elup_xpm
[] = { 
 145 // list control with auto-resizable column: 
 146 class CleverListCtrl 
: public wxListCtrl
 
 149    CleverListCtrl(wxWindow 
*parent
, 
 150                   wxWindowID id 
= wxID_ANY
, 
 151                   const wxPoint 
&pos 
= wxDefaultPosition
, 
 152                   const wxSize 
&size 
= wxDefaultSize
, 
 153                   long style 
= wxLC_ICON
, 
 154                   const wxValidator
& validator 
= wxDefaultValidator
, 
 155                   const wxString 
&name 
= wxListCtrlNameStr
) 
 156          : wxListCtrl(parent
, id
, pos
, size
, style
, validator
, name
) 
 163         InsertColumn(0, _T("item")); 
 171          w 
-= wxSystemSettings::GetMetric(wxSYS_VSCROLL_X
) + 6; 
 173          w 
-= 2*wxSystemSettings::GetMetric(wxSYS_VSCROLL_X
); 
 175          SetColumnWidth(0, w
); 
 179     DECLARE_EVENT_TABLE() 
 180     void OnSize(wxSizeEvent
& event
) 
 187 BEGIN_EVENT_TABLE(CleverListCtrl
, wxListCtrl
) 
 188    EVT_SIZE(CleverListCtrl::OnSize
) 
 192 // ---------------------------------------------------------------------------- 
 194 // ---------------------------------------------------------------------------- 
 196 IMPLEMENT_CLASS(wxEditableListBox
, wxPanel
) 
 198 // NB: generate the IDs at runtime to avoid conflict with XRCID values, 
 199 //     they could cause XRCCTRL() failures in XRC-based dialogs 
 200 const wxWindowIDRef wxID_ELB_DELETE 
= wxWindow::NewControlId(); 
 201 const wxWindowIDRef wxID_ELB_EDIT 
= wxWindow::NewControlId(); 
 202 const wxWindowIDRef wxID_ELB_NEW 
= wxWindow::NewControlId(); 
 203 const wxWindowIDRef wxID_ELB_UP 
= wxWindow::NewControlId(); 
 204 const wxWindowIDRef wxID_ELB_DOWN 
= wxWindow::NewControlId(); 
 205 const wxWindowIDRef wxID_ELB_LISTCTRL 
= wxWindow::NewControlId(); 
 207 BEGIN_EVENT_TABLE(wxEditableListBox
, wxPanel
) 
 208     EVT_LIST_ITEM_SELECTED(wxID_ELB_LISTCTRL
, wxEditableListBox::OnItemSelected
) 
 209     EVT_LIST_END_LABEL_EDIT(wxID_ELB_LISTCTRL
, wxEditableListBox::OnEndLabelEdit
) 
 210     EVT_BUTTON(wxID_ELB_NEW
, wxEditableListBox::OnNewItem
) 
 211     EVT_BUTTON(wxID_ELB_UP
, wxEditableListBox::OnUpItem
) 
 212     EVT_BUTTON(wxID_ELB_DOWN
, wxEditableListBox::OnDownItem
) 
 213     EVT_BUTTON(wxID_ELB_EDIT
, wxEditableListBox::OnEditItem
) 
 214     EVT_BUTTON(wxID_ELB_DELETE
, wxEditableListBox::OnDelItem
) 
 217 bool wxEditableListBox::Create(wxWindow 
*parent
, wxWindowID id
, 
 218                           const wxString
& label
, 
 219                           const wxPoint
& pos
, const wxSize
& size
, 
 221                           const wxString
& name
) 
 223     if (!wxPanel::Create(parent
, id
, pos
, size
, wxTAB_TRAVERSAL
, name
)) 
 228     wxSizer 
*sizer 
= new wxBoxSizer(wxVERTICAL
); 
 230     wxPanel 
*subp 
= new wxPanel(this, wxID_ANY
, wxDefaultPosition
, wxDefaultSize
, 
 231                                 wxSUNKEN_BORDER 
| wxTAB_TRAVERSAL
); 
 232     wxSizer 
*subsizer 
= new wxBoxSizer(wxHORIZONTAL
); 
 233     subsizer
->Add(new wxStaticText(subp
, wxID_ANY
, label
), 1, wxALIGN_CENTRE_VERTICAL 
| wxLEFT
, 4); 
 237     // FIXME - why is this needed? There's some reason why sunken border is 
 238     //         ignored by sizers in wxMSW but not in wxGTK that I can't 
 244     if ( m_style 
& wxEL_ALLOW_EDIT 
) 
 246         m_bEdit 
= new wxBitmapButton(subp
, wxID_ELB_EDIT
, wxBitmap(eledit_xpm
)); 
 247         subsizer
->Add(m_bEdit
, 0, wxALIGN_CENTRE_VERTICAL 
| wxTOP 
| wxBOTTOM
, BTN_BORDER
); 
 250     if ( m_style 
& wxEL_ALLOW_NEW 
) 
 252         m_bNew 
= new wxBitmapButton(subp
, wxID_ELB_NEW
, wxBitmap(elnew_xpm
)); 
 253         subsizer
->Add(m_bNew
, 0, wxALIGN_CENTRE_VERTICAL 
| wxTOP 
| wxBOTTOM
, BTN_BORDER
); 
 256     if ( m_style 
& wxEL_ALLOW_DELETE 
) 
 258         m_bDel 
= new wxBitmapButton(subp
, wxID_ELB_DELETE
, wxBitmap(eldel_xpm
)); 
 259         subsizer
->Add(m_bDel
, 0, wxALIGN_CENTRE_VERTICAL 
| wxTOP 
| wxBOTTOM
, BTN_BORDER
); 
 262     if (!(m_style 
& wxEL_NO_REORDER
)) 
 264         m_bUp 
= new wxBitmapButton(subp
, wxID_ELB_UP
, wxBitmap(elup_xpm
)); 
 265         subsizer
->Add(m_bUp
, 0, wxALIGN_CENTRE_VERTICAL 
| wxTOP 
| wxBOTTOM
, BTN_BORDER
); 
 267         m_bDown 
= new wxBitmapButton(subp
, wxID_ELB_DOWN
, wxBitmap(eldown_xpm
)); 
 268         subsizer
->Add(m_bDown
, 0, wxALIGN_CENTRE_VERTICAL 
| wxTOP 
| wxBOTTOM
, BTN_BORDER
); 
 272     if ( m_bEdit 
) m_bEdit
->SetToolTip(_("Edit item")); 
 273     if ( m_bNew 
) m_bNew
->SetToolTip(_("New item")); 
 274     if ( m_bDel 
) m_bDel
->SetToolTip(_("Delete item")); 
 275     if ( m_bUp 
) m_bUp
->SetToolTip(_("Move up")); 
 276     if ( m_bDown 
) m_bDown
->SetToolTip(_("Move down")); 
 279     subp
->SetSizer(subsizer
); 
 282     sizer
->Add(subp
, 0, wxEXPAND
); 
 284     long st 
= wxLC_REPORT 
| wxLC_NO_HEADER 
| wxLC_SINGLE_SEL 
| wxSUNKEN_BORDER
; 
 285     if ( style 
& wxEL_ALLOW_EDIT 
) 
 286          st 
|= wxLC_EDIT_LABELS
; 
 287     m_listCtrl 
= new CleverListCtrl(this, wxID_ELB_LISTCTRL
, 
 288                                     wxDefaultPosition
, wxDefaultSize
, st
); 
 289     wxArrayString empty_ar
; 
 290     SetStrings(empty_ar
); 
 292     sizer
->Add(m_listCtrl
, 1, wxEXPAND
); 
 300 void wxEditableListBox::SetStrings(const wxArrayString
& strings
) 
 302     m_listCtrl
->DeleteAllItems(); 
 305     for (i 
= 0; i 
< strings
.GetCount(); i
++) 
 306         m_listCtrl
->InsertItem(i
, strings
[i
]); 
 308     m_listCtrl
->InsertItem(strings
.GetCount(), wxEmptyString
); 
 309     m_listCtrl
->SetItemState(0, wxLIST_STATE_SELECTED
, wxLIST_STATE_SELECTED
); 
 312 void wxEditableListBox::GetStrings(wxArrayString
& strings
) const 
 316     for (int i 
= 0; i 
< m_listCtrl
->GetItemCount()-1; i
++) 
 317         strings
.Add(m_listCtrl
->GetItemText(i
)); 
 320 void wxEditableListBox::OnItemSelected(wxListEvent
& event
) 
 322     m_selection 
= event
.GetIndex(); 
 323     if (!(m_style 
& wxEL_NO_REORDER
)) 
 325         m_bUp
->Enable(m_selection 
!= 0 && m_selection 
< m_listCtrl
->GetItemCount()-1); 
 326         m_bDown
->Enable(m_selection 
< m_listCtrl
->GetItemCount()-2); 
 329     if (m_style 
& wxEL_ALLOW_EDIT
) 
 330         m_bEdit
->Enable(m_selection 
< m_listCtrl
->GetItemCount()-1); 
 331     if (m_style 
& wxEL_ALLOW_DELETE
) 
 332         m_bDel
->Enable(m_selection 
< m_listCtrl
->GetItemCount()-1); 
 335 void wxEditableListBox::OnNewItem(wxCommandEvent
& WXUNUSED(event
)) 
 337     m_listCtrl
->SetItemState(m_listCtrl
->GetItemCount()-1, 
 338                              wxLIST_STATE_SELECTED
, wxLIST_STATE_SELECTED
); 
 339     m_listCtrl
->EditLabel(m_selection
); 
 342 void wxEditableListBox::OnEndLabelEdit(wxListEvent
& event
) 
 344     if ( event
.GetIndex() == m_listCtrl
->GetItemCount()-1 && 
 345          !event
.GetText().empty() ) 
 347         // The user edited last (empty) line, i.e. added new entry. We have to 
 348         // add new empty line here so that adding one more line is still 
 350         m_listCtrl
->InsertItem(m_listCtrl
->GetItemCount(), wxEmptyString
); 
 352         // Simulate a wxEVT_COMMAND_LIST_ITEM_SELECTED event for the new item, 
 353         // so that the buttons are enabled/disabled properly 
 354         wxListEvent 
selectionEvent(wxEVT_COMMAND_LIST_ITEM_SELECTED
, m_listCtrl
->GetId()); 
 355         selectionEvent
.m_itemIndex 
= event
.GetIndex(); 
 356         m_listCtrl
->GetEventHandler()->ProcessEvent(selectionEvent
); 
 360 void wxEditableListBox::OnDelItem(wxCommandEvent
& WXUNUSED(event
)) 
 362     m_listCtrl
->DeleteItem(m_selection
); 
 363     m_listCtrl
->SetItemState(m_selection
, 
 364                              wxLIST_STATE_SELECTED
, wxLIST_STATE_SELECTED
); 
 367 void wxEditableListBox::OnEditItem(wxCommandEvent
& WXUNUSED(event
)) 
 369     m_listCtrl
->EditLabel(m_selection
); 
 372 void wxEditableListBox::OnUpItem(wxCommandEvent
& WXUNUSED(event
)) 
 376     t1 
= m_listCtrl
->GetItemText(m_selection 
- 1); 
 377     t2 
= m_listCtrl
->GetItemText(m_selection
); 
 378     m_listCtrl
->SetItemText(m_selection 
- 1, t2
); 
 379     m_listCtrl
->SetItemText(m_selection
, t1
); 
 380     m_listCtrl
->SetItemState(m_selection 
- 1, 
 381                              wxLIST_STATE_SELECTED
, wxLIST_STATE_SELECTED
); 
 384 void wxEditableListBox::OnDownItem(wxCommandEvent
& WXUNUSED(event
)) 
 388     t1 
= m_listCtrl
->GetItemText(m_selection 
+ 1); 
 389     t2 
= m_listCtrl
->GetItemText(m_selection
); 
 390     m_listCtrl
->SetItemText(m_selection 
+ 1, t2
); 
 391     m_listCtrl
->SetItemText(m_selection
, t1
); 
 392     m_listCtrl
->SetItemState(m_selection 
+ 1, 
 393                              wxLIST_STATE_SELECTED
, wxLIST_STATE_SELECTED
); 
 396 #endif // wxUSE_EDITABLELISTBOX