added wxRearrange{List,Ctrl,Dialog} and use it in wxHeaderCtrl and wxGrid to provide...
[wxWidgets.git] / src / common / rearrangectrl.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/rearrangectrl.cpp
3 // Purpose: implementation of classes in wx/rearrangectrl.h
4 // Author: Vadim Zeitlin
5 // Created: 2008-12-15
6 // RCS-ID: $Id$
7 // Copyright: (c) 2008 Vadim Zeitlin <vadim@wxwidgets.org>
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
10
11 // ============================================================================
12 // declarations
13 // ============================================================================
14
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18
19 // for compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21
22 #ifdef __BORLANDC__
23 #pragma hdrstop
24 #endif
25
26 #ifndef WX_PRECOMP
27 #endif // WX_PRECOMP
28
29 #include "wx/rearrangectrl.h"
30
31 // ============================================================================
32 // wxRearrangeList implementation
33 // ============================================================================
34
35 extern
36 WXDLLIMPEXP_DATA_CORE(const char) wxRearrangeListNameStr[] = "wxRearrangeList";
37
38 BEGIN_EVENT_TABLE(wxRearrangeList, wxCheckListBox)
39 EVT_CHECKLISTBOX(wxID_ANY, wxRearrangeList::OnCheck)
40 END_EVENT_TABLE()
41
42 bool wxRearrangeList::Create(wxWindow *parent,
43 wxWindowID id,
44 const wxPoint& pos,
45 const wxSize& size,
46 const wxArrayInt& order,
47 const wxArrayString& items,
48 long style,
49 const wxValidator& validator,
50 const wxString& name)
51 {
52 // construct the array of items in the order in which they should appear in
53 // the control
54 const size_t count = items.size();
55 wxCHECK_MSG( order.size() == count, false, "arrays not in sync" );
56
57 wxArrayString itemsInOrder;
58 itemsInOrder.reserve(count);
59 size_t n;
60 for ( n = 0; n < count; n++ )
61 {
62 int idx = order[n];
63 if ( idx < 0 )
64 idx = -idx - 1;
65 itemsInOrder.push_back(items[idx]);
66 }
67
68 // do create the real control
69 if ( !wxCheckListBox::Create(parent, id, pos, size, itemsInOrder,
70 style, validator, name) )
71 return false;
72
73 // and now check all the items which should be initially checked
74 for ( n = 0; n < count; n++ )
75 {
76 if ( order[n] >= 0 )
77 Check(n);
78 }
79
80 m_order = order;
81
82 return true;
83 }
84
85 bool wxRearrangeList::CanMoveCurrentUp() const
86 {
87 const int sel = GetSelection();
88 return sel != wxNOT_FOUND && sel != 0;
89 }
90
91 bool wxRearrangeList::CanMoveCurrentDown() const
92 {
93 const int sel = GetSelection();
94 return sel != wxNOT_FOUND && static_cast<unsigned>(sel) != GetCount() - 1;
95 }
96
97 bool wxRearrangeList::MoveCurrentUp()
98 {
99 const int sel = GetSelection();
100 if ( sel == wxNOT_FOUND || sel == 0 )
101 return false;
102
103 Swap(sel, sel - 1);
104 SetSelection(sel - 1);
105
106 return true;
107 }
108
109 bool wxRearrangeList::MoveCurrentDown()
110 {
111 const int sel = GetSelection();
112 if ( sel == wxNOT_FOUND || static_cast<unsigned>(sel) == GetCount() - 1 )
113 return false;
114
115 Swap(sel, sel + 1);
116 SetSelection(sel + 1);
117
118 return true;
119 }
120
121 void wxRearrangeList::Swap(int pos1, int pos2)
122 {
123 wxSwap(m_order[pos1], m_order[pos2]);
124
125 const wxString stringTmp = GetString(pos1);
126 const bool checkedTmp = IsChecked(pos1);
127
128 SetString(pos1, GetString(pos2));
129 Check(pos1, IsChecked(pos2));
130
131 SetString(pos2, stringTmp);
132 Check(pos2, checkedTmp);
133 }
134
135 void wxRearrangeList::OnCheck(wxCommandEvent& event)
136 {
137 // update the internal state to match the new item state
138 const int n = event.GetInt();
139
140 const bool checked = IsChecked(n);
141 wxASSERT_MSG( (m_order[n] >= 0) == !checked,
142 "discrepancy between internal state and GUI" );
143
144 m_order[n] = ~m_order[n];
145 }
146
147 // ============================================================================
148 // wxRearrangeCtrl implementation
149 // ============================================================================
150
151 BEGIN_EVENT_TABLE(wxRearrangeCtrl, wxPanel)
152 EVT_UPDATE_UI(wxID_UP, wxRearrangeCtrl::OnUpdateButtonUI)
153 EVT_UPDATE_UI(wxID_DOWN, wxRearrangeCtrl::OnUpdateButtonUI)
154
155 EVT_BUTTON(wxID_UP, wxRearrangeCtrl::OnButton)
156 EVT_BUTTON(wxID_DOWN, wxRearrangeCtrl::OnButton)
157 END_EVENT_TABLE()
158
159 void wxRearrangeCtrl::Init()
160 {
161 m_list = NULL;
162 }
163
164 bool
165 wxRearrangeCtrl::Create(wxWindow *parent,
166 wxWindowID id,
167 const wxPoint& pos,
168 const wxSize& size,
169 const wxArrayInt& order,
170 const wxArrayString& items,
171 long style,
172 const wxValidator& validator,
173 const wxString& name)
174 {
175 // create all the windows
176 if ( !wxPanel::Create(parent, id, pos, size, wxTAB_TRAVERSAL, name) )
177 return false;
178
179 m_list = new wxRearrangeList(this, wxID_ANY,
180 wxDefaultPosition, wxDefaultSize,
181 order, items,
182 style, validator);
183 wxButton * const btnUp = new wxButton(this, wxID_UP);
184 wxButton * const btnDown = new wxButton(this, wxID_DOWN);
185
186 // arrange them in a sizer
187 wxSizer * const sizerBtns = new wxBoxSizer(wxVERTICAL);
188 sizerBtns->Add(btnUp, wxSizerFlags().Centre().Border(wxBOTTOM));
189 sizerBtns->Add(btnDown, wxSizerFlags().Centre().Border(wxTOP));
190
191 wxSizer * const sizerTop = new wxBoxSizer(wxHORIZONTAL);
192 sizerTop->Add(m_list, wxSizerFlags(1).Expand().Border(wxRIGHT));
193 sizerTop->Add(sizerBtns, wxSizerFlags(0).Centre().Border(wxLEFT));
194 SetSizer(sizerTop);
195
196 m_list->SetFocus();
197
198 return true;
199 }
200
201 void wxRearrangeCtrl::OnUpdateButtonUI(wxUpdateUIEvent& event)
202 {
203 event.Enable( event.GetId() == wxID_UP ? m_list->CanMoveCurrentUp()
204 : m_list->CanMoveCurrentDown() );
205 }
206
207 void wxRearrangeCtrl::OnButton(wxCommandEvent& event)
208 {
209 if ( event.GetId() == wxID_UP )
210 m_list->MoveCurrentUp();
211 else
212 m_list->MoveCurrentDown();
213 }
214
215 // ============================================================================
216 // wxRearrangeDialog implementation
217 // ============================================================================
218
219 extern
220 WXDLLIMPEXP_DATA_CORE(const char) wxRearrangeDialogNameStr[] = "wxRearrangeDlg";
221
222 wxRearrangeDialog::wxRearrangeDialog(wxWindow *parent,
223 const wxString& message,
224 const wxString& title,
225 const wxArrayInt& order,
226 const wxArrayString& items,
227 const wxPoint& pos,
228 const wxString& name)
229 : wxDialog(parent, wxID_ANY, title,
230 pos, wxDefaultSize,
231 wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER,
232 name)
233 {
234 m_ctrl = new wxRearrangeCtrl(this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
235 order, items);
236
237 wxSizer * const sizerTop = new wxBoxSizer(wxVERTICAL);
238 sizerTop->Add(new wxStaticText(this, wxID_ANY, message),
239 wxSizerFlags().DoubleBorder());
240 sizerTop->Add(m_ctrl,
241 wxSizerFlags(1).Expand().Border());
242 sizerTop->Add(CreateSeparatedButtonSizer(wxOK | wxCANCEL),
243 wxSizerFlags().Expand().Border());
244 SetSizerAndFit(sizerTop);
245 }