1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        PropDlg.cpp
3 // Purpose:     Properties dialog (base class for all properties dialogs)
4 // Author:      Alex Thuering
5 // Created:     18.11.2003
6 // RCS-ID:      $Id: PropDlg.cpp,v 1.53 2016/08/12 16:17:20 ntalex Exp $
7 // Copyright:   (c) Alex Thuering
8 // Licence:     wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10 
11 #include "PropDlg.h"
12 #include "utils.h"
13 #include <wx/fontdlg.h>
14 #include <wx/colordlg.h>
15 #include <wx/filedlg.h>
16 #include <wx/dirdlg.h>
17 #include <wx/grid.h>
18 #include <wx/spinctrl.h>
19 #include <wx/statline.h>
20 #include <wx/bmpcbox.h>
21 #include <wx/tglbtn.h>
22 #include <wx/tooltip.h>
23 #include <wx/richtooltip.h>
24 #include <wx/wx.h>
25 #if !wxCHECK_VERSION(2,9,0)
26 #define wxBitmapToggleButton wxToggleBitmapButton
27 #endif
28 #ifdef __WXMSW__
29 #include <setupapi.h>
30 #include "wx/msw/private.h"
31 #endif
32 
33 #include "rc/delete.png.h"
34 
35 #include <wx/arrimpl.cpp>
36 WX_DEFINE_OBJARRAY(BitmapArray);
37 
38 //////////////////////////////////////////////////////////////////////////////
39 //////////////////////////// ColourPanel ////////////////////////////////////
40 //////////////////////////////////////////////////////////////////////////////
41 
ColourPanel(wxWindow * parent,wxWindowID id,const wxPoint & pos,const wxSize & size,long style,const wxString & name)42 ColourPanel::ColourPanel(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size,
43 		long style, const wxString& name): wxPanel(parent, id, pos, size, style, name) {
44 	m_bgColour = GetBackgroundColour();
45 }
46 
SetColour(wxColour colour)47 void ColourPanel::SetColour(wxColour colour) {
48 	m_colour = colour;
49 	if (colour.Ok())
50 		SetBackgroundColour(colour);
51 	else
52 		SetBackgroundColour(m_bgColour);
53 	Refresh();
54 }
55 
GetColour()56 wxColour ColourPanel::GetColour() {
57 	return m_colour;
58 }
59 
OnPaint(wxPaintEvent & event)60 void ColourPanel::OnPaint(wxPaintEvent &event) {
61 	wxPaintDC dc(this);
62 	PrepareDC(dc);
63 	if (!m_colour.Ok()) {
64 		dc.SetPen(*wxBLACK_PEN);
65 		dc.SetBrush(*wxTRANSPARENT_BRUSH);
66 		int w = GetClientSize().GetWidth();
67 		int h = GetClientSize().GetHeight();
68 		dc.DrawLine(0, 0, w, h);
69 		dc.DrawLine(w, 0, 0, h);
70 	}
71 }
72 
OnClick(wxMouseEvent & event)73 void ColourPanel::OnClick(wxMouseEvent &event) {
74 	if (m_colour.Ok()) {
75 		m_oldColour = GetColour();
76 		SetColour(wxColour());
77 	} else
78 		SetColour(m_oldColour);
79 	Refresh();
80 }
81 
82 BEGIN_EVENT_TABLE(ColourPanel, wxPanel)
83 	EVT_PAINT(ColourPanel::OnPaint)
84 	EVT_LEFT_DOWN(ColourPanel::OnClick)
85 END_EVENT_TABLE()
86 
87 //////////////////////////////////////////////////////////////////////////////
88 ///////////////////////////// wxPropDlg //////////////////////////////////////
89 //////////////////////////////////////////////////////////////////////////////
90 
91 enum {
92 	CUSTOM_CHOICE_ID = 7830,
93 	SELECT_FONT_BT_ID,
94 	SELECT_COLOR_BT_ID,
95 	SELECT_FILE_BT_ID,
96 	CLEAR_TEXT_BT_ID,
97 	SELECT_DIR_BT_ID,
98 	GROUP_CHECK_ID,
99 	ROW_DELETE_ID
100 };
101 
102 #ifndef EVT_GRID_CELL_CHANGED
103 #define EVT_GRID_CELL_CHANGED EVT_GRID_CELL_CHANGE
104 #endif
105 
106 BEGIN_EVENT_TABLE(wxPropDlg, wxDialog)
107 	EVT_BUTTON(wxID_CANCEL, wxPropDlg::OnCancel)
108 	EVT_BUTTON(wxID_OK, wxPropDlg::OnOk)
109 	EVT_BUTTON(wxID_APPLY, wxPropDlg::OnReset)
110 	EVT_BUTTON(SELECT_FONT_BT_ID, wxPropDlg::OnSelectFont)
111 	EVT_BUTTON(SELECT_COLOR_BT_ID, wxPropDlg::OnSelectColour)
112 	EVT_BUTTON(SELECT_FILE_BT_ID, wxPropDlg::OnSelectFile)
113 	EVT_BUTTON(CLEAR_TEXT_BT_ID, wxPropDlg::OnClearText)
114 	EVT_BUTTON(SELECT_DIR_BT_ID, wxPropDlg::OnSelectDir)
115 	EVT_CHECKBOX(GROUP_CHECK_ID, wxPropDlg::OnGroupCheck)
116 	EVT_GRID_CELL_LEFT_CLICK(wxPropDlg::OnCellLeftClick)
117 	EVT_GRID_CELL_RIGHT_CLICK(wxPropDlg::OnCellRightClick)
118 	EVT_GRID_CELL_CHANGED(wxPropDlg::OnCellChange)
119 	EVT_MENU(ROW_DELETE_ID, wxPropDlg::OnRowDelete)
120 	EVT_CHOICE(CUSTOM_CHOICE_ID, wxPropDlg::OnSelectCustomChoice)
121 END_EVENT_TABLE()
122 
123 enum PropertyType {
124 	propTEXT = 0,
125 	propSTAT_TEXT,
126 	propSPIN,
127 	propSPIN_DOUBLE,
128 	propCOMBO,
129 	propBITMAP_COMBO,
130 	propCHOICE,
131 	propCHECK,
132 	propRADIO,
133 	propRADIO_GROUP,
134 	propGRID,
135 	propCOLOUR,
136 	propFONT,
137 	propTOGGLE_BUTTON
138 };
139 
140 wxColourData wxPropDlg::m_colourData;
141 
wxPropDlg(wxWindow * parent,wxString title)142 wxPropDlg::wxPropDlg(wxWindow* parent, wxString title) : wxDialog(parent, -1, title, wxDefaultPosition, wxDefaultSize,
143 		wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER), m_currGroupChecker(NULL), propWindow(NULL) {
144 	m_currGroupId = 0;
145 	m_updateIndex = -1;
146 	m_currObject = NULL;
147 	m_currObjectItem = 0;
148 	SetIcon(((wxTopLevelWindow*) wxGetTopLevelParent(parent))->GetIcon());
149 }
150 
Create(bool resetButton,bool dontShowCheckbox)151 void wxPropDlg::Create(bool resetButton, bool dontShowCheckbox) {
152 	propWindow = this;
153 	wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
154 	wxBoxSizer* propSizer = new wxBoxSizer(wxVERTICAL);
155 	CreatePropPanel(propSizer);
156 	sizer->Add(propSizer, 1, wxEXPAND | wxALL, 10);
157 	CreateButtonPane(sizer, resetButton, dontShowCheckbox);
158 	SetAutoLayout(true);
159 	SetSizer(sizer);
160 	sizer->Fit(this);
161 	sizer->SetSizeHints(this);
162 	Layout();
163 	Centre();
164 	for (int i = 0; i < (int) m_controls.GetCount(); i++) {
165 		if (m_types[i] < propCOLOUR && m_types[i] != propRADIO_GROUP && ((wxControl*) m_controls[i])->IsEnabled()
166 				&& (m_types[i] != propRADIO || ((wxRadioButton*) m_controls[i])->GetValue())) {
167 			((wxControl*) m_controls[i])->SetFocus();
168 			break;
169 		}
170 	}
171 }
172 
~wxPropDlg()173 wxPropDlg::~wxPropDlg() {
174 	for (int i = 0; i < (int) m_types.GetCount(); i++)
175 		switch (m_types[i]) {
176 		case propFONT:
177 			delete (wxFontData*) m_controls[i];
178 			break;
179 		case propRADIO_GROUP:
180 			delete (wxArrayPtrVoid*) m_controls[i];
181 			break;
182 		}
183 }
184 
OnCancel(wxCommandEvent & WXUNUSED (event))185 void wxPropDlg::OnCancel(wxCommandEvent &WXUNUSED(event)) {
186 	EndModal(wxID_CANCEL);
187 }
188 
OnOk(wxCommandEvent & WXUNUSED (event))189 void wxPropDlg::OnOk(wxCommandEvent &WXUNUSED(event)) {
190 	if (SetValues())
191 		EndModal(wxID_OK);
192 }
193 
OnReset(wxCommandEvent & event)194 void wxPropDlg::OnReset(wxCommandEvent& event) {
195 	Reset();
196 }
197 
CreateButtonPane(wxSizer * sizer,bool resetButton,bool dontShowCheckbox)198 void wxPropDlg::CreateButtonPane(wxSizer* sizer, bool resetButton, bool dontShowCheckbox) {
199 	wxStdDialogButtonSizer* buttonPane = new wxStdDialogButtonSizer();
200 	if (dontShowCheckbox)
201 		AddCheckProp(buttonPane, _("&Don't show this dialog again"), false);
202 	buttonPane->Add(10, 10, dontShowCheckbox ? 0 : 1, wxEXPAND);
203 
204 	buttonPane->AddButton(new wxButton(this, wxID_OK, wxEmptyString));
205 	buttonPane->AddButton(new wxButton(this, wxID_CANCEL, wxEmptyString));
206 	if (resetButton) {
207 		buttonPane->AddButton(new wxButton(this, wxID_APPLY, _("Reset")));
208 	}
209 	buttonPane->Add(10, 10, dontShowCheckbox ? 0 : 1, wxEXPAND);
210 	buttonPane->Realize();
211 	buttonPane->GetAffirmativeButton()->SetDefault();
212 	sizer->Add(buttonPane, 0, wxEXPAND|wxLEFT|wxRIGHT|wxBOTTOM, 10);
213 }
214 
Reset()215 void wxPropDlg::Reset() {
216 	m_updateIndex = 0;
217 	CreatePropPanel(NULL);
218 }
219 
AddText(wxSizer * sizer,wxString text,int flag)220 void wxPropDlg::AddText(wxSizer* sizer, wxString text, int flag) {
221 	if (!sizer)
222 		return;
223 	// add static text
224 	if (text.length())
225 		sizer->Add(new wxStaticText(propWindow, -1, text), 0, flag);
226 	else
227 		sizer->Add(10, 10);
228 }
229 
AddTextProp(wxSizer * sizer,const wxString & label,const wxString & value,bool readonly,int width,bool addSpacer,long style)230 wxSizer* wxPropDlg::AddTextProp(wxSizer* sizer, const wxString& label, const wxString& value, bool readonly,
231 		int width, bool addSpacer, long style) {
232 	if (!sizer) { // only update value
233 		wxTextCtrl* ctrl = (wxTextCtrl*) m_controls[m_updateIndex];
234 		ctrl->SetValue(value);
235 		ctrl->SetEditable(!readonly);
236 		m_updateIndex++;
237 		return NULL;
238 	}
239 	// add label
240 	if (label.length())
241 		sizer->Add(new wxStaticText(propWindow, -1, label), 0, wxALIGN_CENTER_VERTICAL);
242 	// add text control
243 	wxSize size = width > 0 ? wxSize(width, -1) : wxDefaultSize;
244 	wxTextCtrl* ctrl = new wxTextCtrl(propWindow, -1, value, wxDefaultPosition, size, style);
245 	ctrl->SetEditable(!readonly);
246 	wxBoxSizer* pane = NULL;
247 	if (width > 0) {
248 		pane = new wxBoxSizer(wxHORIZONTAL);
249 		pane->Add(ctrl);
250 		if (addSpacer)
251 			pane->Add(0, 0, 1, wxEXPAND);
252 		sizer->Add(pane, 1, wxEXPAND, 0);
253 	} else
254 		sizer->Add(ctrl, 1, wxEXPAND, 0);
255 	m_types.Add(propTEXT);
256 	m_controls.Add(ctrl);
257 	m_groupIds.Add(m_currGroupId);
258 	return pane;
259 }
260 
AddStaticTextProp(wxSizer * sizer,const wxString & label,const wxString & value)261 void wxPropDlg::AddStaticTextProp(wxSizer* sizer, const wxString& label, const wxString& value) {
262 	if (!sizer) { // only update value
263 		((wxStaticText*) m_controls[m_updateIndex])->SetLabel(value);
264 		m_updateIndex++;
265 		return;
266 	}
267 	// add static text
268 	if (label.length())
269 		sizer->Add(new wxStaticText(propWindow, -1, label), 0, wxALIGN_CENTER_VERTICAL);
270 	wxStaticText* ctrl = new wxStaticText(propWindow, -1, value);
271 	sizer->Add(ctrl, 1, wxEXPAND, 0);
272 	m_types.Add(propSTAT_TEXT);
273 	m_controls.Add(ctrl);
274 	m_groupIds.Add(m_currGroupId);
275 }
276 
277 
AddStaticLine(wxSizer * sizer,wxString caption)278 void wxPropDlg::AddStaticLine(wxSizer* sizer, wxString caption) {
279 	wxBoxSizer* sizer2 = new wxBoxSizer(wxHORIZONTAL);
280 	wxStaticText* staticText = new wxStaticText(propWindow, -1, caption);
281 	int fontSize = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT).GetPointSize() + 2;
282 	staticText->SetFont(wxFont(fontSize, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD));
283 	sizer2->Add(staticText, 0, wxRIGHT | wxTOP | wxBOTTOM, 5);
284 	sizer2->Add(new wxStaticLine(propWindow, -1), 1, wxALIGN_CENTER_VERTICAL, 5);
285 	sizer->Add(sizer2, 0, wxEXPAND, 0);
286 }
287 
AddSpinProp(wxSizer * sizer,const wxString & label,int value,int min,int max,int width,const wxString & label2,bool addSpacer)288 wxSizer* wxPropDlg::AddSpinProp(wxSizer* sizer, const wxString& label, int value,
289 		int min, int max, int width, const wxString& label2, bool addSpacer) {
290 	if (!sizer) { // only update value
291 		wxSpinCtrl* ctrl = (wxSpinCtrl*) m_controls[m_updateIndex];
292 		ctrl->SetValue(value);
293 		m_updateIndex++;
294 		return NULL;
295 	}
296 	// add text control
297 	if (label.length())
298 		sizer->Add(new wxStaticText(propWindow, -1, label), 0, wxALIGN_CENTER_VERTICAL);
299 	wxSize size = width > 0 ? wxSize(width, -1) : wxDefaultSize;
300 	wxSpinCtrl* ctrl = new wxSpinCtrl(propWindow, -1, wxEmptyString, wxDefaultPosition, size,
301 			wxSP_ARROW_KEYS, min, max);
302 	ctrl->SetValue(value);
303 	wxBoxSizer* pane = NULL;
304 	if (width > 0) {
305 		pane = new wxBoxSizer(wxHORIZONTAL);
306 		pane->Add(ctrl, 0, wxALIGN_CENTER_VERTICAL, 0);
307 		if (label2.length() > 0) {
308 			pane->AddSpacer(2);
309 			AddText(pane, label2);
310 		}
311 		if (addSpacer)
312 			pane->Add(0, 0, 1, wxEXPAND);
313 		sizer->Add(pane, 1, wxEXPAND, 0);
314 	} else
315 		sizer->Add(ctrl, 1, wxEXPAND, 0);
316 	m_types.Add(propSPIN);
317 	m_controls.Add(ctrl);
318 	m_groupIds.Add(m_currGroupId);
319 	return pane;
320 }
321 
AddSpinDoubleProp(wxSizer * sizer,const wxString & label,double value,double min,double max,int width,const wxString & label2,bool addSpacer)322 wxSizer* wxPropDlg::AddSpinDoubleProp(wxSizer* sizer, const wxString& label, double value,
323 		double min, double max, int width, const wxString& label2, bool addSpacer) {
324 	if (!sizer) { // only update value
325 #if wxCHECK_VERSION(2,9,3)
326 		wxSpinCtrlDouble* ctrl = (wxSpinCtrlDouble*) m_controls[m_updateIndex];
327 		ctrl->SetValue(value);
328 #else
329 		wxTextCtrl* ctrl = (wxTextCtrl*) m_controls[m_updateIndex];
330 		ctrl->SetValue(wxString::Format(wxT("%g"), value));
331 #endif
332 		m_updateIndex++;
333 		return NULL;
334 	}
335 	// add text control
336 	if (label.length())
337 		sizer->Add(new wxStaticText(propWindow, -1, label), 0, wxALIGN_CENTER_VERTICAL);
338 	wxSize size = width > 0 ? wxSize(width, -1) : wxDefaultSize;
339 #if wxCHECK_VERSION(2,9,3)
340 	wxSpinCtrlDouble* ctrl = new wxSpinCtrlDouble(propWindow, -1, wxEmptyString, wxDefaultPosition, size,
341 			wxSP_ARROW_KEYS, min, max);
342 	ctrl->SetValue(value);
343 #else
344 	wxTextCtrl* ctrl = new wxTextCtrl(propWindow, -1, wxString::Format(wxT("%g"), value), wxDefaultPosition, size);
345 #endif
346 	wxBoxSizer* pane = NULL;
347 	if (width > 0) {
348 		pane = new wxBoxSizer(wxHORIZONTAL);
349 		pane->Add(ctrl, 0, wxALIGN_CENTER_VERTICAL, 0);
350 		if (label2.length() > 0) {
351 			pane->AddSpacer(4);
352 			AddText(pane, label2);
353 		}
354 		if (addSpacer)
355 			pane->Add(0, 0, 1, wxEXPAND);
356 		sizer->Add(pane, 1, wxEXPAND, 0);
357 	} else
358 		sizer->Add(ctrl, 1, wxEXPAND, 0);
359 	m_types.Add(propSPIN_DOUBLE);
360 	m_controls.Add(ctrl);
361 	m_groupIds.Add(m_currGroupId);
362 	return pane;
363 }
364 
AddCheckProp(wxSizer * sizer,const wxString & label,bool value,bool readonly,int id)365 void wxPropDlg::AddCheckProp(wxSizer* sizer, const wxString& label, bool value, bool readonly, int id) {
366 	if (!sizer) { // only update value
367 		wxCheckBox* ctrl = (wxCheckBox*) m_controls[m_updateIndex];
368 		ctrl->SetValue(value);
369 		ctrl->Enable(!readonly);
370 		m_updateIndex++;
371 		return;
372 	}
373 	// add checkbox control
374 	wxCheckBox* ctrl = new wxCheckBox(propWindow, id, label);
375 	ctrl->SetValue(value);
376 	ctrl->Enable(!readonly);
377 	ctrl->SetName(wxString::Format(_T("%d"), (int) m_controls.GetCount()));
378 	sizer->Add(ctrl, 0, wxEXPAND, 0);
379 	m_types.Add(propCHECK);
380 	m_controls.Add(ctrl);
381 	m_groupIds.Add(m_currGroupId);
382 }
383 
AddRadioProp(wxSizer * sizer,const wxString & label,bool value,long style,bool readonly,int id)384 void wxPropDlg::AddRadioProp(wxSizer* sizer, const wxString& label, bool value, long style, bool readonly, int id) {
385 	if (!sizer) { // only update value
386 		wxRadioButton* ctrl = (wxRadioButton*) m_controls[m_updateIndex];
387 		ctrl->SetValue(value);
388 		ctrl->Enable(!readonly);
389 		m_updateIndex++;
390 		return;
391 	}
392 	// add radio button
393 	wxRadioButton* ctrl = new wxRadioButton(propWindow, id, label, wxDefaultPosition, wxDefaultSize, style);
394 	ctrl->SetValue(value);
395 	ctrl->Enable(!readonly);
396 	ctrl->SetName(wxString::Format(_T("%d"), (int) m_controls.GetCount()));
397 	sizer->Add(ctrl, 1, wxEXPAND, 0);
398 	m_types.Add(propRADIO);
399 	m_controls.Add(ctrl);
400 	m_groupIds.Add(m_currGroupId);
401 }
402 
AddRadioGroupProp(wxSizer * sizer,const wxArrayString & text,int value,bool readonly)403 void wxPropDlg::AddRadioGroupProp(wxSizer* sizer, const wxArrayString& text, int value, bool readonly) {
404 	if (!sizer) { // only update value
405 		wxArrayPtrVoid* radioControls = (wxArrayPtrVoid*) m_controls[m_updateIndex];
406 		for (int i = 0; i < (int) radioControls->GetCount(); i++) {
407 			wxRadioButton* ctrl = (wxRadioButton*) (*radioControls)[i];
408 			ctrl->SetValue(i == value);
409 			ctrl->Enable(!readonly);
410 		}
411 		m_updateIndex++;
412 		return;
413 	}
414 	wxArrayPtrVoid* radioControls = new wxArrayPtrVoid();
415 	for (int i = 0; i < (int) text.GetCount(); i++) {
416 		// add checkbox control
417 		wxRadioButton* ctrl = new wxRadioButton(propWindow, -1, text[i], wxDefaultPosition, wxDefaultSize,
418 				i == 0 ? wxRB_GROUP : 0);
419 		ctrl->SetValue(i == value);
420 		ctrl->Enable(!readonly);
421 		ctrl->SetName(wxString::Format(_T("%d_%d"), (int) m_controls.GetCount(), i));
422 		sizer->Add(ctrl, 0, wxEXPAND, 0);
423 		radioControls->Add(ctrl);
424 	}
425 	m_types.Add(propRADIO_GROUP);
426 	m_controls.Add(radioControls);
427 	m_groupIds.Add(m_currGroupId);
428 }
429 
AddComboProp(wxSizer * sizer,const wxString & label,const wxString & value,const wxArrayString & choices,long style,int width,bool addSpacer,int id)430 wxSizer* wxPropDlg::AddComboProp(wxSizer* sizer, const wxString& label, const wxString& value,
431 		const wxArrayString& choices, long style, int width, bool addSpacer, int id) {
432 	if (!sizer) { // only update value
433 		wxComboBox* ctrl = (wxComboBox*)m_controls[m_updateIndex];
434 		ctrl->SetStringSelection(value);
435 		m_updateIndex++;
436 		return NULL;
437 	}
438 	if (label.length())
439 		sizer->Add(new wxStaticText(propWindow, -1, label), 0, wxALIGN_CENTER_VERTICAL);
440 	// add combobox control
441 	wxComboBox* ctrl = new wxComboBox(propWindow, id, value, wxDefaultPosition, wxDefaultSize, choices, style);
442 	ctrl->SetStringSelection(value);
443 	wxBoxSizer* pane = NULL;
444 	if (width > 0) {
445 		pane = new wxBoxSizer(wxHORIZONTAL);
446 		pane->Add(ctrl);
447 		if (addSpacer)
448 			pane->Add(10, 10, 1, wxEXPAND);
449 		sizer->Add(pane, 1, wxEXPAND, 0);
450 	} else
451 		sizer->Add(ctrl, 1, wxEXPAND, 0);
452 	m_types.Add(propCOMBO);
453 	m_controls.Add(ctrl);
454 	m_groupIds.Add(m_currGroupId);
455 	return pane;
456 }
457 
AddBitmapComboProp(wxSizer * sizer,const wxString & label,const wxString & value,const wxArrayString & choices,const BitmapArray & bitmaps,long style,int width,bool addSpacer,int id)458 wxSizer* wxPropDlg::AddBitmapComboProp(wxSizer* sizer, const wxString& label, const wxString& value,
459 		const wxArrayString& choices, const BitmapArray& bitmaps, long style, int width, bool addSpacer, int id) {
460 	if (!sizer) { // only update value
461 		wxBitmapComboBox* ctrl = (wxBitmapComboBox*)m_controls[m_updateIndex];
462 		ctrl->SetStringSelection(value);
463 		m_updateIndex++;
464 		return NULL;
465 	}
466 	if (label.length())
467 		sizer->Add(new wxStaticText(propWindow, -1, label), 0, wxALIGN_CENTER_VERTICAL);
468 	// add bitmap combobox control
469 	wxBitmapComboBox* ctrl =
470 		new wxBitmapComboBox(propWindow, id, value, wxDefaultPosition, wxDefaultSize, choices, style);
471 #if wxCHECK_VERSION(2,9,3)
472 	wxAssertHandler_t oldAssertHandler = wxSetAssertHandler(NULL);
473 #endif
474 	for (unsigned int i = 0; i < bitmaps.size(); i++)
475 		ctrl->SetItemBitmap(i, bitmaps[i]);
476 #if wxCHECK_VERSION(2,9,3)
477 	wxSetAssertHandler(oldAssertHandler);
478 #endif
479 	ctrl->SetStringSelection(value);
480 	wxBoxSizer* pane = NULL;
481 	if (width > 0) {
482 		pane = new wxBoxSizer(wxHORIZONTAL);
483 		pane->Add(ctrl);
484 		if (addSpacer)
485 			pane->Add(10, 10, 1, wxEXPAND);
486 		sizer->Add(pane, 1, wxEXPAND, 0);
487 	} else
488 		sizer->Add(ctrl, 1, wxEXPAND, 0);
489 	m_types.Add(propBITMAP_COMBO);
490 	m_controls.Add(ctrl);
491 	m_groupIds.Add(m_currGroupId);
492 	return pane;
493 }
494 
AddChoiceProp(wxSizer * sizer,const wxString & label,const wxString & value,const wxArrayString & choices,int width,bool addSpacer,int id)495 wxSizer* wxPropDlg::AddChoiceProp(wxSizer* sizer, const wxString& label, const wxString& value,
496 		const wxArrayString& choices, int width, bool addSpacer, int id) {
497 	if (!sizer) { // only update value
498 		wxChoice* ctrl = (wxChoice*)m_controls[m_updateIndex];
499 		ctrl->SetStringSelection(value);
500 		m_updateIndex++;
501 		return NULL;
502 	}
503 	if (label.length())
504 		sizer->Add(new wxStaticText(propWindow, -1, label), 0, wxALIGN_CENTER_VERTICAL);
505 	// add choice control
506 	wxChoice* ctrl = AddChoiceProp(value, choices, id);
507 	wxBoxSizer* pane = NULL;
508 	if (width >= 0) {
509 		pane = new wxBoxSizer(wxHORIZONTAL);
510 		pane->Add(ctrl);
511 		if (addSpacer)
512 			pane->Add(10, 10, 1, wxEXPAND);
513 		sizer->Add(pane, 1, wxEXPAND, 0);
514 		if (width > 0)
515 			ctrl->SetMinSize(wxSize(width, -1));
516 	} else
517 		sizer->Add(ctrl, width == -2 ? 0 : 1, wxEXPAND, 0);
518 	return pane;
519 }
520 
521 /**
522  * Creates choice control.
523  * @returns Choice control
524  */
AddChoiceProp(const wxString & value,const wxArrayString & choices,int id)525 wxChoice* wxPropDlg::AddChoiceProp(const wxString& value, const wxArrayString& choices, int id) {
526 	wxChoice* ctrl = new wxChoice(propWindow, id, wxDefaultPosition, wxDefaultSize, choices);
527 	ctrl->SetStringSelection(value);
528 	m_types.Add(propCHOICE);
529 	m_controls.Add(ctrl);
530 	m_groupIds.Add(m_currGroupId);
531 	return ctrl;
532 }
533 
534 
535 /**
536  * Creates label and choice control with item 'Custom'.
537  * @returns subSizer if width > 0, null otherwise
538  */
AddChoiceCustomProp(wxSizer * sizer,const wxString & label,const wxString & value,const wxArrayString & choices,int customItemIdx,int width,bool addSpacer)539 wxSizer* wxPropDlg::AddChoiceCustomProp(wxSizer* sizer, const wxString& label, const wxString& value,
540 		const wxArrayString& choices, int customItemIdx, int width, bool addSpacer) {
541 	wxSizer* s = AddChoiceProp(sizer, label, value, choices, width, addSpacer, CUSTOM_CHOICE_ID);
542 	GetLastControl()->SetName(wxString::Format(wxT("%d-%d"), GetLastControlIndex(), customItemIdx));
543 	return s;
544 }
545 
546 /** Sets the last control as control to enter the custom value. */
SetLastControlCustom(int choiceCtrlIdx,bool enable)547 void wxPropDlg::SetLastControlCustom(int choiceCtrlIdx, bool enable) {
548 	GetLastControl()->SetName(wxString::Format(wxT("customCtrlFor%d"), choiceCtrlIdx));
549 	GetLastControl()->Enable(enable);
550 }
551 
OnSelectCustomChoice(wxCommandEvent & evt)552 void wxPropDlg::OnSelectCustomChoice(wxCommandEvent& evt) {
553 	wxString name = ((wxWindow*)evt.GetEventObject())->GetName();
554 	long idx = 0;
555 	long itemIdx = 0;
556 	if (name.BeforeLast(wxT('-')).ToLong(&idx) && name.AfterFirst(wxT('-')).ToLong(&itemIdx)) {
557 		wxWindow* ctrl = this->FindWindowByName(wxString::Format(wxT("customCtrlFor%d"), (int) idx));
558 		ctrl->Enable(evt.GetSelection() == itemIdx && ((wxWindow*)evt.GetEventObject())->IsEnabled());
559 		if (!ctrl->IsEnabled() && ctrl->GetClassInfo()->IsKindOf(wxCLASSINFO(wxChoice))) {
560 			((wxChoice*) ctrl)->SetSelection(0);
561 			((wxChoice*) ctrl)->SendSelectionChangedEvent(wxEVT_CHOICE);
562 		}
563 	}
564 }
565 
566 //--- Grid property ---//
AddGridProp(wxSizer * sizer,const wxArrayPtrVoid & data,const wxString & rowTitle,bool editable)567 void wxPropDlg::AddGridProp(wxSizer* sizer, const wxArrayPtrVoid& data, const wxString& rowTitle, bool editable) {
568 	if (!sizer) { // only update value
569 		wxGrid* grid = (wxGrid*) m_controls[m_updateIndex];
570 		grid->ClearGrid();
571 		SetGridData(grid, data, rowTitle, editable);
572 		m_updateIndex++;
573 		return;
574 	}
575 	wxGrid* grid = new wxGrid(propWindow, -1, wxPoint(0, 0), wxSize(100, 100));
576 	grid->CreateGrid(0, 0);
577 	SetGridData(grid, data, rowTitle, editable);
578 
579 	// todo: autosize RowLableSize
580 	int width = 50;
581 	grid->SetRowLabelSize(50);
582 	//grid->SetRowSize(0, 60 );
583 	//grid->SetColSize(0, 120);
584 	//grid->AutoSize();
585 	grid->Fit();
586 	wxArrayString* cols = (wxArrayString*) data.Item(0);
587 	for (int c = 0; c < (int) cols->GetCount(); c++)
588 		width += grid->GetColSize(c);
589 	grid->SetSize(width + 20, 100);
590 
591 	sizer->Add(grid, 1, wxEXPAND);
592 	m_types.Add(propGRID);
593 	m_controls.Add(grid);
594 	m_groupIds.Add(m_currGroupId);
595 }
596 
SetGridData(wxGrid * grid,const wxArrayPtrVoid & data,const wxString & rowTitle,bool editable)597 void wxPropDlg::SetGridData(wxGrid* grid, const wxArrayPtrVoid& data, const wxString& rowTitle, bool editable) {
598 	grid->EnableEditing(editable);
599 
600 	wxArrayString* cols = (wxArrayString*) data.Item(0);
601 	int cnt = cols->GetCount() - grid->GetNumberCols();
602 	if (cnt > 0)
603 		grid->AppendCols(cnt);
604 	else if (cnt < 0)
605 		grid->DeleteCols(0, -cnt);
606 	grid->SetColLabelSize(grid->GetDefaultRowSize());
607 	for (int c = 0; c < (int) cols->GetCount(); c++)
608 		grid->SetColLabelValue(c, cols->Item(c));
609 
610 	cnt = data.GetCount() - (editable ? 0 : 1) - grid->GetNumberRows();
611 	if (cnt > 0)
612 		grid->AppendRows(cnt);
613 	else if (cnt < 0)
614 		grid->DeleteRows(0, -cnt);
615 	for (int r = 1; r <= (int) grid->GetNumberRows(); r++) {
616 		grid->SetRowLabelValue(r - 1, rowTitle + wxString::Format(_T("%d"), r));
617 		if (r < (int) data.GetCount()) {
618 			wxArrayString* row = (wxArrayString*) data.Item(r);
619 			for (int c = 0; c < (int) cols->GetCount(); c++)
620 				grid->SetCellValue(r - 1, c, row->Item(c));
621 		}
622 	}
623 }
624 
OnCellLeftClick(wxGridEvent & event)625 void wxPropDlg::OnCellLeftClick(wxGridEvent& event) {
626 	wxGrid* grid = (wxGrid*) event.GetEventObject();
627 	grid->ClearSelection();
628 	grid->SetGridCursor(event.GetRow(), event.GetCol());
629 	grid->EnableCellEditControl();
630 }
631 
OnCellChange(wxGridEvent & event)632 void wxPropDlg::OnCellChange(wxGridEvent& event) {
633 	wxGrid* grid = (wxGrid*) event.GetEventObject();
634 	if (event.GetRow() == grid->GetNumberRows() - 1)
635 		grid->AppendRows();
636 	wxString rowTitle = grid->GetRowLabelValue(0);
637 	rowTitle = rowTitle.Mid(0, rowTitle.length() - 1);
638 	grid->SetRowLabelValue(grid->GetNumberRows() - 1,
639 			rowTitle + wxString::Format(_T("%d"), grid->GetNumberRows()));
640 }
641 
OnCellRightClick(wxGridEvent & event)642 void wxPropDlg::OnCellRightClick(wxGridEvent& event) {
643 	wxGrid* grid = (wxGrid*) event.GetEventObject();
644 	if (grid->IsEditable()) {
645 		m_currObject = grid;
646 		m_currObjectItem = event.GetRow();
647 		wxMenu* menu = new wxMenu;
648 		menu->Append(ROW_DELETE_ID, _("&Delete"));
649 		menu->GetMenuItems()[0]->Enable(
650 				event.GetRow() < grid->GetNumberRows() - 1);
651 		grid->PopupMenu(menu, event.GetPosition());
652 	}
653 }
654 
OnRowDelete(wxCommandEvent & event)655 void wxPropDlg::OnRowDelete(wxCommandEvent& event) {
656 	wxGrid* grid = (wxGrid*) m_currObject;
657 	grid->DeleteRows(m_currObjectItem);
658 }
659 
660 //--- Font property ---//
AddFontProp(wxSizer * sizer,const wxString & label,wxFont font,wxString caption)661 void wxPropDlg::AddFontProp(wxSizer* sizer, const wxString& label, wxFont font, wxString caption) {
662 	wxFontData data;
663 	data.SetInitialFont(font);
664 	AddFontProp(sizer, label, data, caption);
665 }
666 
AddFontProp(wxSizer * sizer,const wxString & label,wxFontData font,wxString caption)667 void wxPropDlg::AddFontProp(wxSizer* sizer, const wxString& label,
668 		wxFontData font, wxString caption) {
669 	if (!sizer) { // only update value
670 		delete (wxFontData*) m_controls[m_updateIndex];
671 		m_controls[m_updateIndex] = new wxFontData(font);
672 		m_updateIndex++;
673 		return;
674 	}
675 	if (label.length())
676 		sizer->Add(new wxStaticText(propWindow, -1, label), 0, wxALIGN_CENTER_VERTICAL);
677 	wxButton* button = new wxButton(propWindow, SELECT_FONT_BT_ID, caption);
678 	if (caption == _T("..."))
679 		button->SetSizeHints(24, 24, 24, 24);
680 	button->SetName(wxString::Format(_T("%d"), (int) m_controls.GetCount()));
681 	sizer->Add(button);
682 	m_types.Add(propFONT);
683 	m_controls.Add(new wxFontData(font));
684 	m_groupIds.Add(m_currGroupId);
685 }
686 
OnSelectFont(wxCommandEvent & event)687 void wxPropDlg::OnSelectFont(wxCommandEvent& event) {
688 	long index = -1;
689 	((wxButton*) event.GetEventObject())->GetName().ToLong(&index);
690 	wxFontData* data = (wxFontData*) m_controls[index];
691 #if wxCHECK_VERSION(2,8,0)
692 	wxFontDialog dialog(propWindow, *data);
693 #else
694 	wxFontDialog dialog(propWindow, data);
695 #endif
696 	if (dialog.ShowModal() == wxID_OK)
697 		*data = dialog.GetFontData();
698 }
699 
AddColourProp(wxSizer * sizer,const wxString & label,wxColour colour,int opacity,wxString caption)700 void wxPropDlg::AddColourProp(wxSizer* sizer, const wxString& label, wxColour colour, int opacity, wxString caption) {
701 	if (!sizer) { // only update value
702 		((ColourPanel*) m_controls[m_updateIndex])->SetColour(colour);
703 		m_updateIndex++;
704 		return;
705 	}
706 	if (label.length())
707 		sizer->Add(new wxStaticText(propWindow, -1, label), 0, wxALIGN_CENTER_VERTICAL);
708 	wxBoxSizer* sizer2 = new wxBoxSizer(wxHORIZONTAL);
709 	ColourPanel* panel = new ColourPanel(propWindow, -1);
710 	panel->SetSize(wxSize(20, 20));
711 	panel->SetMinSize(wxSize(20, 20));
712 	panel->SetColour(colour);
713 	sizer2->Add(panel, 1, wxALL, 2);
714 	wxButton* button = new wxButton(propWindow, SELECT_COLOR_BT_ID, caption);
715 	if (caption == _T("..."))
716 		button->SetSizeHints(24, 24, 24, 24);
717 	button->SetName(wxString::Format(wxT("PropColourBt%d"), (int) m_controls.GetCount()));
718 	sizer2->Add(button);
719 	m_types.Add(propCOLOUR);
720 	m_controls.Add(panel);
721 	m_groupIds.Add(m_currGroupId);
722 	if (opacity >= 0) {
723 		// add spinctrl
724 		wxSpinCtrl* ctrl = new wxSpinCtrl(propWindow, -1, wxEmptyString, wxDefaultPosition, wxSize(54, -1),
725 				wxSP_ARROW_KEYS, 0, 100);
726 		ctrl->SetValue(opacity);
727 		sizer2->Add(ctrl, 0, wxALL, 2);
728 		AddText(sizer2, wxT("%"));
729 		m_types.Add(propSPIN);
730 		m_controls.Add(ctrl);
731 		m_groupIds.Add(m_currGroupId);
732 	}
733 	sizer->Add(sizer2);
734 }
735 
OnSelectColour(wxCommandEvent & event)736 void wxPropDlg::OnSelectColour(wxCommandEvent& event) {
737 	long index = -1;
738 	((wxButton*) event.GetEventObject())->GetName().Mid(12).ToLong(&index);
739 	ColourPanel* panel = ((ColourPanel*) m_controls[index]);
740 	m_colourData.SetColour(panel->GetColour());
741 	wxColourDialog dialog(propWindow, &m_colourData);
742 	if (dialog.ShowModal() == wxID_OK) {
743 		panel->SetColour(dialog.GetColourData().GetColour());
744 		m_colourData = dialog.GetColourData();
745 	}
746 }
747 
AddFileProp(wxSizer * sizer,const wxString & label,const wxString & value,int dlgStyle,wxString buttonLabel,wxString wildcard,int id)748 wxSizer* wxPropDlg::AddFileProp(wxSizer* sizer, const wxString& label, const wxString& value, int dlgStyle,
749 		wxString buttonLabel, wxString wildcard, int id) {
750 	if (!sizer) // only update value
751 	{
752 		wxTextCtrl* ctrl = (wxTextCtrl*) m_controls[m_updateIndex];
753 		ctrl->SetValue(value);
754 		m_updateIndex++;
755 		return NULL;
756 	}
757 	// add text control
758 	if (label.length())
759 		sizer->Add(new wxStaticText(propWindow, -1, label), 0, wxALIGN_CENTER_VERTICAL);
760 	wxBoxSizer* sizer2 = new wxBoxSizer(wxHORIZONTAL);
761 	wxTextCtrl* ctrl = new wxTextCtrl(propWindow, id, value);
762 	sizer2->Add(ctrl, 1, wxEXPAND);
763 	wxButton* button = new wxButton(propWindow, SELECT_FILE_BT_ID, buttonLabel);
764 	int h = ctrl->GetSize().GetHeight() > 24 ? ctrl->GetSize().GetHeight() : 24;
765 	if (buttonLabel == _T("..."))
766 		button->SetSizeHints(h, h, h, h);
767 	button->SetName(wxString::Format(_T("SelectFileButton_%d"), (int) m_controls.GetCount()));
768 	button->SetClientData(new wxStringClientData(wxString::Format(_T("%d:%s"), dlgStyle, wildcard.c_str())));
769 	sizer2->Add(button);
770 	wxBitmapButton* delBt = new wxBitmapButton(propWindow, CLEAR_TEXT_BT_ID, wxBITMAP_FROM_MEMORY(delete));
771 	delBt->SetName(wxString::Format(_T("ClearTextButton_%d"), (int) m_controls.GetCount()));
772 	sizer2->Add(delBt);
773 	sizer->Add(sizer2, 1, wxEXPAND);
774 	m_types.Add(propTEXT);
775 	m_controls.Add(ctrl);
776 	m_groupIds.Add(m_currGroupId);
777 	return sizer2;
778 }
779 
OnSelectFile(wxCommandEvent & event)780 void wxPropDlg::OnSelectFile(wxCommandEvent& event) {
781 	long index = -1;
782 	((wxButton*) event.GetEventObject())->GetName().Mid(17).ToLong(&index);
783 	wxString clientData = ((wxStringClientData*) ((wxButton*) event.GetEventObject())->GetClientData())->GetData();
784 	long dlgStyle = wxFD_DEFAULT_STYLE;
785 	clientData.BeforeFirst(wxT(':')).ToLong(&dlgStyle);
786 	wxString wildcard = clientData.AfterFirst(wxT(':'));
787 	wxTextCtrl* ctrl = ((wxTextCtrl*) m_controls[index]);
788 	wxFileDialog dialog(propWindow, _("Choose a file"), ctrl->GetValue(), wxT(""), wildcard, dlgStyle);
789 	dialog.SetPath(ctrl->GetValue());
790 	if (dialog.ShowModal() == wxID_OK)
791 		ctrl->SetValue(dialog.GetPath());
792 }
793 
OnClearText(wxCommandEvent & event)794 void wxPropDlg::OnClearText(wxCommandEvent& event) {
795 	long index = -1;
796 	((wxBitmapButton*) event.GetEventObject())->GetName().Mid(16).ToLong(&index);
797 	((wxTextCtrl*) m_controls[index])->SetValue(wxT(""));
798 }
799 
AddDirectoryProp(wxSizer * sizer,const wxString & label,const wxString & value,wxString buttonLabel)800 wxSizer* wxPropDlg::AddDirectoryProp(wxSizer* sizer, const wxString& label, const wxString& value, wxString buttonLabel) {
801 	if (!sizer) { // only update value
802 		wxTextCtrl* ctrl = (wxTextCtrl*) m_controls[m_updateIndex];
803 		ctrl->SetValue(value);
804 		m_updateIndex++;
805 		return NULL;
806 	}
807 	// add text control
808 	if (label.length())
809 		sizer->Add(new wxStaticText(propWindow, -1, label), 0, wxALIGN_CENTER_VERTICAL);
810 	wxBoxSizer* sizer2 = new wxBoxSizer(wxHORIZONTAL);
811 	wxTextCtrl* ctrl = new wxTextCtrl(propWindow, -1, value);
812 	sizer2->Add(ctrl, 1, wxEXPAND, 0);
813 	wxButton* button = new wxButton(propWindow, SELECT_DIR_BT_ID, buttonLabel);
814 	int h = ctrl->GetSize().GetHeight() > 24 ? ctrl->GetSize().GetHeight() : 24;
815 	if (buttonLabel == _T("..."))
816 		button->SetSizeHints(h, h, h, h);
817 	button->SetName(wxString::Format(wxT("SelectDirButton_%d"), (int) m_controls.GetCount()));
818 	sizer2->Add(button);
819 	sizer->Add(sizer2, 1, wxEXPAND);
820 	m_types.Add(propTEXT);
821 	m_controls.Add(ctrl);
822 	m_groupIds.Add(m_currGroupId);
823 	return sizer2;
824 }
825 
OnSelectDir(wxCommandEvent & event)826 void wxPropDlg::OnSelectDir(wxCommandEvent& event) {
827 	long index = -1;
828 	((wxButton*) event.GetEventObject())->GetName().AfterLast(wxT('_')).ToLong(&index);
829 	wxTextCtrl* ctrl = ((wxTextCtrl*) m_controls[index]);
830 	wxDirDialog dialog(propWindow, _("Choose a directory"), ctrl->GetValue(), wxDD_DEFAULT_STYLE | wxDD_NEW_DIR_BUTTON);
831 	dialog.SetPath(ctrl->GetValue());
832 	if (dialog.ShowModal() == wxID_OK)
833 		ctrl->SetValue(dialog.GetPath());
834 }
835 
AddButton(wxSizer * sizer,const wxString & label,const long id,const wxString & buttonLabel)836 void wxPropDlg::AddButton(wxSizer* sizer, const wxString& label, const long id, const wxString& buttonLabel) {
837 	if (!sizer) // skip
838 		return;
839 	// add text control
840 	if (label.length())
841 		sizer->Add(new wxStaticText(propWindow, -1, label), 0, wxALIGN_CENTER_VERTICAL);
842 	wxButton* bt = new wxButton(propWindow, id, buttonLabel);
843 	if (buttonLabel == wxT("...")) {
844 		int h = bt->GetSize().GetHeight() > 24 ? bt->GetSize().GetHeight() : 24;
845 		bt->SetSizeHints(h, h, h, h);
846 	}
847 	sizer->Add(bt);
848 }
849 
AddBitmapToggleButton(wxSizer * sizer,bool value,const long id,const wxBitmap & bitmap,const wxSize & size)850 void wxPropDlg::AddBitmapToggleButton(wxSizer* sizer, bool value, const long id, const wxBitmap& bitmap,
851 		const wxSize& size) {
852 	if (!sizer) { // only update value
853 		wxBitmapToggleButton* ctrl = (wxBitmapToggleButton*) m_controls[m_updateIndex];
854 		ctrl->SetValue(value);
855 		m_updateIndex++;
856 		return;
857 	}
858 	wxBitmapToggleButton* ctrl = new wxBitmapToggleButton(propWindow, id, bitmap, wxDefaultPosition, size);
859 	ctrl->SetValue(value);
860 	sizer->Add(ctrl);
861 	m_types.Add(propTOGGLE_BUTTON);
862 	m_controls.Add(ctrl);
863 	m_groupIds.Add(m_currGroupId);
864 }
865 
AddIcon(wxSizer * sizer,const wxString & title,const wxString & tooltip,wxArtID artId)866 int wxPropDlg::AddIcon(wxSizer* sizer, const wxString& title, const wxString& tooltip, wxArtID artId) {
867 	if (!sizer)
868 		return -1;
869 	m_tooltipTitle.Add(title);
870 	m_tooltipText.Add(tooltip);
871 	m_tooltipIcon.Add(artId == wxART_WARNING ? wxICON_WARNING : wxICON_INFORMATION);
872 	wxStaticBitmap* icon = new wxStaticBitmap(propWindow, wxID_ANY, wxArtProvider::GetBitmap(artId, wxART_BUTTON));
873 	icon->SetName(wxString::Format(_T("%d"), m_tooltipTitle.GetCount() - 1));
874 	sizer->Add(icon, 0, wxALIGN_CENTER_VERTICAL);
875 	m_icons.push_back(icon);
876 	icon->Connect(wxEVT_ENTER_WINDOW, wxMouseEventHandler(wxPropDlg::OnShowTooltip), NULL, this);
877 	return m_tooltipTitle.GetCount() - 1;
878 }
879 
UpdateIcon(int index,const wxString & title,const wxString & tooltip,wxArtID artId)880 void wxPropDlg::UpdateIcon(int index, const wxString& title, const wxString& tooltip, wxArtID artId) {
881 	if (title.length())
882 		m_tooltipTitle[index] = title;
883 	if (tooltip.length())
884 		m_tooltipText[index] = tooltip;
885 	m_tooltipIcon[index] = artId == wxART_WARNING ? wxICON_WARNING : wxICON_INFORMATION;
886 	m_icons[index]->SetBitmap(wxArtProvider::GetBitmap(artId, wxART_BUTTON));
887 }
888 
OnShowTooltip(wxMouseEvent & event)889 void wxPropDlg::OnShowTooltip(wxMouseEvent& event) {
890 	long idx;
891 	if (!((wxWindow*)event.GetEventObject())->GetName().ToLong(&idx))
892 		return;
893 #ifdef __WXMSW__2
894 	HWND hwndToolTips = CreateWindowExW(WS_EX_TOPMOST,
895 			TOOLTIPS_CLASSW,0,WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP | TTS_BALLOON,
896 			CW_USEDEFAULT, CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT, 0,0,wxGetInstance(),0);
897 	if (hwndToolTips) {
898 		TOOLINFOW ti = {};
899 		ti.cbSize = sizeof(TOOLINFOW);
900 		ti.uFlags = TTF_ABSOLUTE | TTF_IDISHWND;
901 		ti.hwnd   = hwndToolTips;
902 		ti.hinst  = NULL;
903 		ti.uId    = (UINT)hwndToolTips;
904 		ti.lpszText = (LPWSTR) m_tooltipText[idx].wc_str();
905 		SendMessageW(hwndToolTips, TTM_ADDTOOLW, 0, (LPARAM)&ti);
906 		SendMessageW(hwndToolTips, TTM_TRACKACTIVATE, (WPARAM)TRUE, (LPARAM)&ti);
907 		SendMessageW(hwndToolTips, TTM_TRACKPOSITION, 0, (LPARAM)MAKELONG(event.GetX(), event.GetY()));
908 	}
909 #else
910 	wxRichToolTip tip(m_tooltipTitle[idx], m_tooltipText[idx]);
911 	tip.SetIcon(m_tooltipIcon[idx]);
912 	tip.SetTipKind(wxTipKind_Bottom);
913 	tip.SetTimeout(3000, 0);
914 	tip.ShowFor((wxWindow*) event.GetEventObject());
915 #endif
916 }
917 
918 ////////////////////////////// Group /////////////////////////////////////////
919 
BeginGroup(wxSizer * sizer,wxString title,wxString checkTitle,bool value,bool readonly,bool vertical,int proportion)920 wxSizer* wxPropDlg::BeginGroup(wxSizer* sizer, wxString title, wxString checkTitle, bool value, bool readonly,
921 		bool vertical, int proportion) {
922 	if (!sizer) { // only update value
923 		if (checkTitle.length())
924 			AddCheckProp(NULL, wxEmptyString, value, readonly, GROUP_CHECK_ID);
925 		return NULL;
926 	}
927 	m_currGroupId++;
928 	if (title.size() > 0) {
929 		wxStaticBox* sb = new wxStaticBox(propWindow, -1, title);
930 		wxStaticBoxSizer* sbsizer = new wxStaticBoxSizer(sb, vertical ? wxVERTICAL : wxHORIZONTAL);
931 		sizer->Add(sbsizer, proportion, wxEXPAND);
932 		if (checkTitle.length()) {
933 			wxFlexGridSizer* groupSizer = new wxFlexGridSizer(2, 2, 8, 4);
934 			groupSizer->AddGrowableCol(1);
935 			sbsizer->Add(groupSizer, 0, wxEXPAND | wxALL, 4);
936 			AddCheckProp(groupSizer, wxEmptyString, value, readonly, GROUP_CHECK_ID);
937 			m_currGroupChecker = m_controls[m_controls.GetCount() - 1];
938 			AddText(groupSizer, checkTitle);
939 			AddText(groupSizer, wxEmptyString);
940 			return groupSizer;
941 		}
942 		m_currGroupChecker = NULL;
943 		return sbsizer;
944 	} else {
945 		wxBoxSizer* pane = new wxBoxSizer(wxHORIZONTAL);
946 		sizer->Add(pane, 1, wxEXPAND, 0);
947 		return pane;
948 	}
949 }
950 
BeginCheckGroup(wxSizer * sizer,wxString label,bool value,bool readonly)951 void wxPropDlg::BeginCheckGroup(wxSizer* sizer, wxString label, bool value, bool readonly) {
952 	if (!sizer) { // only update value
953 		AddCheckProp(NULL, label, value, readonly, GROUP_CHECK_ID);
954 		return;
955 	}
956 	m_currGroupId++;
957 	AddCheckProp(sizer, label, value, readonly, GROUP_CHECK_ID);
958 	m_currGroupChecker = m_controls[m_controls.GetCount() - 1];
959 }
960 
EndGroup()961 void wxPropDlg::EndGroup() {
962 	if (m_currGroupChecker) {
963 		wxCommandEvent evt;
964 		evt.SetEventObject((wxObject*) m_currGroupChecker);
965 		OnGroupCheck(evt);
966 	}
967 	m_currGroupChecker = NULL;
968 	m_currGroupId++;
969 }
970 
OnGroupCheck(wxCommandEvent & event)971 void wxPropDlg::OnGroupCheck(wxCommandEvent& event) {
972 	long index = -1;
973 	wxCheckBox* ctrl = (wxCheckBox*) event.GetEventObject();
974 	ctrl->GetName().ToLong(&index);
975 	int groupId = m_groupIds[index];
976 	for (int i = 0; i < (int) m_groupIds.GetCount(); i++)
977 		if (i != index && m_groupIds[i] == groupId && m_types[i] != propFONT) {
978 			((wxWindow*) m_controls[i])->Enable(ctrl->GetValue());
979 			if (m_types[i] == propCOLOUR) {
980 				wxWindow* button = FindWindowByName(wxString::Format(wxT("PropColourBt%d"), i));
981 				if (button != NULL)
982 					button->Enable(ctrl->GetValue());
983 			}
984 		}
985 }
986 
GetControl(int index)987 wxControl* wxPropDlg::GetControl(int index) {
988 	return (wxControl*) m_controls[index];
989 }
990 
GetLastControl()991 wxControl* wxPropDlg::GetLastControl() {
992 	return (wxControl*) m_controls[GetLastControlIndex()];
993 }
994 
GetLastControlIndex()995 int wxPropDlg::GetLastControlIndex() {
996 	return m_updateIndex > 0 ? m_updateIndex - 1 : m_controls.GetCount() -1;
997 }
998 
999 ///////////////////////// Get Values /////////////////////////////////////////
1000 
GetString(int index)1001 wxString wxPropDlg::GetString(int index) {
1002 	switch (m_types[index]) {
1003 	case propTEXT:
1004 		return ((wxTextCtrl*) m_controls[index])->GetValue();
1005 	case propSTAT_TEXT:
1006 		return ((wxStaticText*) m_controls[index])->GetLabel();
1007 	case propCOMBO:
1008 		return ((wxComboBox*) m_controls[index])->GetValue();
1009 	case propCHOICE:
1010 		return ((wxChoice*) m_controls[index])->GetStringSelection();
1011 	}
1012 	return wxEmptyString;
1013 }
1014 
GetInt(int index)1015 int wxPropDlg::GetInt(int index) {
1016 	switch (m_types[index]) {
1017 	case propSPIN:
1018 		return ((wxSpinCtrl*) m_controls[index])->GetValue();
1019 	case propCOMBO:
1020 		return ((wxComboBox*) m_controls[index])->GetSelection();
1021 	case propBITMAP_COMBO:
1022 		return ((wxBitmapComboBox*) m_controls[index])->GetSelection();
1023 	case propCHOICE:
1024 		return ((wxChoice*) m_controls[index])->GetSelection();
1025 	case propRADIO_GROUP: {
1026 		wxArrayPtrVoid* radioControls = (wxArrayPtrVoid*) m_controls[index];
1027 		for (int i = 0; i < (int) radioControls->GetCount(); i++) {
1028 			wxRadioButton* ctrl = (wxRadioButton*) (*radioControls)[i];
1029 			if (ctrl->GetValue())
1030 				return i;
1031 		}
1032 		return -1;
1033 	}
1034 	}
1035 	return -1;
1036 }
1037 
GetBool(int index)1038 bool wxPropDlg::GetBool(int index) {
1039 	switch (m_types[index]) {
1040 	case propCHECK:
1041 		return ((wxCheckBox*) m_controls[index])->GetValue();
1042 	case propRADIO:
1043 		return ((wxRadioButton*) m_controls[index])->GetValue();
1044 	case propTOGGLE_BUTTON:
1045 		return ((wxBitmapToggleButton*) m_controls[index])->GetValue();
1046 	}
1047 	return true;
1048 }
1049 
GetDouble(int index)1050 double wxPropDlg::GetDouble(int index) {
1051 	switch (m_types[index]) {
1052 	case propSPIN_DOUBLE:
1053 #if wxCHECK_VERSION(2,9,3)
1054 		return ((wxSpinCtrlDouble*) m_controls[index])->GetValue();
1055 #else
1056 		{
1057 			double val;
1058 			return ((wxTextCtrl*) m_controls[index])->GetValue().ToDouble(&val) ? val : -1;
1059 		}
1060 #endif
1061 	}
1062 	return -1;
1063 }
1064 
GetClientData(int index)1065 void* wxPropDlg::GetClientData(int index) {
1066 	switch (m_types[index]) {
1067 	case propCOMBO: {
1068 		wxComboBox* ctrl = (wxComboBox*) m_controls[index];
1069 		if (ctrl->GetSelection() >= 0)
1070 			return ctrl->GetClientData(ctrl->GetSelection());
1071 		break;
1072 	}
1073 	case propCHOICE: {
1074 		wxChoice* ctrl = (wxChoice*) m_controls[index];
1075 		if (ctrl->GetSelection() >= 0)
1076 			return ctrl->GetClientData(ctrl->GetSelection());
1077 		break;
1078 	}
1079 	default:
1080 		break;
1081 	}
1082 	return NULL;
1083 }
1084 
GetGrid(int index)1085 wxArrayPtrVoid wxPropDlg::GetGrid(int index) {
1086 	wxArrayPtrVoid data;
1087 	if (m_types[index] != propGRID)
1088 		return data;
1089 	wxGrid* grid = (wxGrid*) m_controls[index];
1090 	grid->SaveEditControlValue();
1091 	int count = grid->GetNumberRows() - (grid->IsEditable() ? 1 : 0);
1092 	for (int r = 0; r < count; r++) {
1093 		wxArrayString* row = new wxArrayString;
1094 		for (int c = 0; c < (int) grid->GetNumberCols(); c++)
1095 			row->Add(grid->GetCellValue(r, c));
1096 		data.Add(row);
1097 	}
1098 	return data;
1099 }
1100 
GetFont(int index)1101 wxFontData wxPropDlg::GetFont(int index) {
1102 	if (m_types[index] != propFONT)
1103 		return wxFontData();
1104 	wxFontData* data = (wxFontData*) m_controls[index];
1105 	if (!data->GetChosenFont().Ok())
1106 		data->SetChosenFont(data->GetInitialFont());
1107 	return *data;
1108 }
1109 
GetColour(int index)1110 wxColour wxPropDlg::GetColour(int index) {
1111 	if (m_types[index] != propCOLOUR)
1112 		return wxColour();
1113 	return ((ColourPanel*) m_controls[index])->GetColour();
1114 }
1115 
1116