1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/rearrangectrl.cpp
3 // Purpose: implementation of classes in wx/rearrangectrl.h
4 // Author: Vadim Zeitlin
6 // Copyright: (c) 2008 Vadim Zeitlin <vadim@wxwidgets.org>
7 // Licence: wxWindows licence
8 ///////////////////////////////////////////////////////////////////////////////
10 // ============================================================================
12 // ============================================================================
14 // ----------------------------------------------------------------------------
16 // ----------------------------------------------------------------------------
18 // for compilers that support precompilation, includes "wx.h".
19 #include "wx/wxprec.h"
25 #if wxUSE_REARRANGECTRL
28 #include "wx/button.h"
29 #include "wx/stattext.h"
33 #include "wx/rearrangectrl.h"
35 // ============================================================================
36 // wxRearrangeList implementation
37 // ============================================================================
40 WXDLLIMPEXP_DATA_CORE(const char) wxRearrangeListNameStr
[] = "wxRearrangeList";
42 BEGIN_EVENT_TABLE(wxRearrangeList
, wxCheckListBox
)
43 EVT_CHECKLISTBOX(wxID_ANY
, wxRearrangeList::OnCheck
)
46 bool wxRearrangeList::Create(wxWindow
*parent
,
50 const wxArrayInt
& order
,
51 const wxArrayString
& items
,
53 const wxValidator
& validator
,
56 // construct the array of items in the order in which they should appear in
58 const size_t count
= items
.size();
59 wxCHECK_MSG( order
.size() == count
, false, "arrays not in sync" );
61 wxArrayString itemsInOrder
;
62 itemsInOrder
.reserve(count
);
64 for ( n
= 0; n
< count
; n
++ )
69 itemsInOrder
.push_back(items
[idx
]);
72 // do create the real control
73 if ( !wxCheckListBox::Create(parent
, id
, pos
, size
, itemsInOrder
,
74 style
, validator
, name
) )
77 // and now check all the items which should be initially checked
78 for ( n
= 0; n
< count
; n
++ )
89 bool wxRearrangeList::CanMoveCurrentUp() const
91 const int sel
= GetSelection();
92 return sel
!= wxNOT_FOUND
&& sel
!= 0;
95 bool wxRearrangeList::CanMoveCurrentDown() const
97 const int sel
= GetSelection();
98 return sel
!= wxNOT_FOUND
&& static_cast<unsigned>(sel
) != GetCount() - 1;
101 bool wxRearrangeList::MoveCurrentUp()
103 const int sel
= GetSelection();
104 if ( sel
== wxNOT_FOUND
|| sel
== 0 )
108 SetSelection(sel
- 1);
113 bool wxRearrangeList::MoveCurrentDown()
115 const int sel
= GetSelection();
116 if ( sel
== wxNOT_FOUND
|| static_cast<unsigned>(sel
) == GetCount() - 1 )
120 SetSelection(sel
+ 1);
125 void wxRearrangeList::Swap(int pos1
, int pos2
)
127 // update the internally stored order
128 wxSwap(m_order
[pos1
], m_order
[pos2
]);
131 // and now also swap all the attributes of the items
134 const wxString stringTmp
= GetString(pos1
);
135 SetString(pos1
, GetString(pos2
));
136 SetString(pos2
, stringTmp
);
138 // then the checked state
139 const bool checkedTmp
= IsChecked(pos1
);
140 Check(pos1
, IsChecked(pos2
));
141 Check(pos2
, checkedTmp
);
143 // and finally the client data, if necessary
144 switch ( GetClientDataType() )
146 case wxClientData_None
:
150 case wxClientData_Object
:
152 wxClientData
* const dataTmp
= DetachClientObject(pos1
);
153 SetClientObject(pos1
, DetachClientObject(pos2
));
154 SetClientObject(pos2
, dataTmp
);
158 case wxClientData_Void
:
160 void * const dataTmp
= GetClientData(pos1
);
161 SetClientData(pos1
, GetClientData(pos2
));
162 SetClientData(pos2
, dataTmp
);
168 void wxRearrangeList::OnCheck(wxCommandEvent
& event
)
170 // update the internal state to match the new item state
171 const int n
= event
.GetInt();
173 m_order
[n
] = ~m_order
[n
];
175 wxASSERT_MSG( (m_order
[n
] >= 0) == IsChecked(n
),
176 "discrepancy between internal state and GUI" );
179 // ============================================================================
180 // wxRearrangeCtrl implementation
181 // ============================================================================
183 BEGIN_EVENT_TABLE(wxRearrangeCtrl
, wxPanel
)
184 EVT_UPDATE_UI(wxID_UP
, wxRearrangeCtrl::OnUpdateButtonUI
)
185 EVT_UPDATE_UI(wxID_DOWN
, wxRearrangeCtrl::OnUpdateButtonUI
)
187 EVT_BUTTON(wxID_UP
, wxRearrangeCtrl::OnButton
)
188 EVT_BUTTON(wxID_DOWN
, wxRearrangeCtrl::OnButton
)
191 void wxRearrangeCtrl::Init()
197 wxRearrangeCtrl::Create(wxWindow
*parent
,
201 const wxArrayInt
& order
,
202 const wxArrayString
& items
,
204 const wxValidator
& validator
,
205 const wxString
& name
)
207 // create all the windows
208 if ( !wxPanel::Create(parent
, id
, pos
, size
, wxTAB_TRAVERSAL
, name
) )
211 m_list
= new wxRearrangeList(this, wxID_ANY
,
212 wxDefaultPosition
, wxDefaultSize
,
215 wxButton
* const btnUp
= new wxButton(this, wxID_UP
);
216 wxButton
* const btnDown
= new wxButton(this, wxID_DOWN
);
218 // arrange them in a sizer
219 wxSizer
* const sizerBtns
= new wxBoxSizer(wxVERTICAL
);
220 sizerBtns
->Add(btnUp
, wxSizerFlags().Centre().Border(wxBOTTOM
));
221 sizerBtns
->Add(btnDown
, wxSizerFlags().Centre().Border(wxTOP
));
223 wxSizer
* const sizerTop
= new wxBoxSizer(wxHORIZONTAL
);
224 sizerTop
->Add(m_list
, wxSizerFlags(1).Expand().Border(wxRIGHT
));
225 sizerTop
->Add(sizerBtns
, wxSizerFlags(0).Centre().Border(wxLEFT
));
233 void wxRearrangeCtrl::OnUpdateButtonUI(wxUpdateUIEvent
& event
)
235 event
.Enable( event
.GetId() == wxID_UP
? m_list
->CanMoveCurrentUp()
236 : m_list
->CanMoveCurrentDown() );
239 void wxRearrangeCtrl::OnButton(wxCommandEvent
& event
)
241 if ( event
.GetId() == wxID_UP
)
242 m_list
->MoveCurrentUp();
244 m_list
->MoveCurrentDown();
247 // ============================================================================
248 // wxRearrangeDialog implementation
249 // ============================================================================
252 WXDLLIMPEXP_DATA_CORE(const char) wxRearrangeDialogNameStr
[] = "wxRearrangeDlg";
257 enum wxRearrangeDialogSizerPositions
265 } // anonymous namespace
267 bool wxRearrangeDialog::Create(wxWindow
*parent
,
268 const wxString
& message
,
269 const wxString
& title
,
270 const wxArrayInt
& order
,
271 const wxArrayString
& items
,
273 const wxString
& name
)
275 if ( !wxDialog::Create(parent
, wxID_ANY
, title
,
277 wxDEFAULT_DIALOG_STYLE
| wxRESIZE_BORDER
,
281 m_ctrl
= new wxRearrangeCtrl(this, wxID_ANY
, wxDefaultPosition
, wxDefaultSize
,
284 // notice that the items in this sizer should be inserted accordingly to
285 // wxRearrangeDialogSizerPositions order
286 wxSizer
* const sizerTop
= new wxBoxSizer(wxVERTICAL
);
288 if ( !message
.empty() )
290 sizerTop
->Add(new wxStaticText(this, wxID_ANY
, message
),
291 wxSizerFlags().Border());
295 // for convenience of other wxRearrangeDialog code that depends on
296 // positions of sizer items, insert a dummy zero-sized item
297 sizerTop
->AddSpacer(0);
300 sizerTop
->Add(m_ctrl
,
301 wxSizerFlags(1).Expand().Border());
302 sizerTop
->Add(CreateSeparatedButtonSizer(wxOK
| wxCANCEL
),
303 wxSizerFlags().Expand().Border());
304 SetSizerAndFit(sizerTop
);
309 void wxRearrangeDialog::AddExtraControls(wxWindow
*win
)
311 wxSizer
* const sizer
= GetSizer();
312 wxCHECK_RET( sizer
, "the dialog must be created first" );
314 wxASSERT_MSG( sizer
->GetChildren().GetCount() == Pos_Max
,
315 "calling AddExtraControls() twice?" );
317 sizer
->Insert(Pos_Buttons
, win
, wxSizerFlags().Expand().Border());
319 win
->MoveAfterInTabOrder(m_ctrl
);
321 // we need to update the initial/minimal window size
322 sizer
->SetSizeHints(this);
325 wxRearrangeList
*wxRearrangeDialog::GetList() const
327 wxCHECK_MSG( m_ctrl
, NULL
, "the dialog must be created first" );
329 return m_ctrl
->GetList();
332 wxArrayInt
wxRearrangeDialog::GetOrder() const
334 wxCHECK_MSG( m_ctrl
, wxArrayInt(), "the dialog must be created first" );
336 return m_ctrl
->GetList()->GetCurrentOrder();
339 #endif // wxUSE_REARRANGECTRL