1 #include "Docking.h"
2 
3 namespace Upp {
4 
5 #define HIGHLIGHT_DURATION 1000
6 
DockConfigDlg(DockWindow & dockwindow)7 DockConfigDlg::DockConfigDlg(DockWindow& dockwindow)
8 : dock(dockwindow),
9   dockers(dockwindow.GetDockableCtrls()),
10   menu(&dockwindow),
11   highlight(NULL)
12 {
13 	CtrlLayoutOKCancel(*this, t_("Dockable Window Manager"));
14 	Sizeable().Zoomable();
15 
16 	// Make backup of layout
17 	StringStream s;
18 	dock.SerializeLayout(s, true);
19 	backup = s;
20 
21 	// Setup groups
22 	RefreshTree(true);
23 
24 	// Setup layout list
25 	const ArrayMap<String, String>& l = dock.GetLayouts();
26 	for (int i = 0; i < l.GetCount(); i++)
27 		list.Add(l.GetKey(i));
28 
29 	tree.MultiSelect(true);
30 	tree.WhenCursor 	= THISBACK(OnTreeCursor);
31 	tree.WhenBar 		= THISBACK(OnTreeContext);
32 	tree.WhenDropInsert = THISBACK(OnTreeDrop);
33 	tree.WhenDrag 		= THISBACK(OnTreeDrag);
34 
35 	list.MultiSelect(false);
36 	list.WhenSel	= THISBACK(OnListCursor);
37 	list.WhenSel	= THISBACK(OnListCursor);
38 
39 	savelayout	<<= THISBACK(OnSaveLayout);
40 	loadlayout	<<= THISBACK(OnLoadLayout);
41 	deletelayout <<= THISBACK(OnDeleteLayout);
42 	newgroup 	<<= THISBACK(OnNewGroup);
43 	deletegroup <<= THISBACK(OnDeleteGroup);
44 	ok 			<<= THISBACK(OnOK);
45 	cancel		<<= THISBACK(OnCancel);
46 	WhenClose 	=   THISBACK(OnCancel);
47 	locked		<<= THISBACK(OnLock);
48 
49 	animatehighlight	<<= dock.IsAnimatedHighlight();
50 	animateframes 		<<= dock.IsAnimatedFrames();
51 	animatewindows 		<<= dock.IsAnimatedWindows();
52 	locked		<<= dock.IsLocked();
53 	tabbing 	<<= dock.IsTabbing();
54 	tabnesting 	<<= dock.IsNestedTabs();
55 	autohide 	<<= dock.IsAutoHide();
56 	grouping	<<= dock.IsGrouping();
57 
58 	closebtn	<<= dock.HasCloseButtons();
59 	autohidebtn	<<= dock.HasHideButtons();
60 	menubtn		<<= dock.HasMenuButtons();
61 
62 	OnTreeCursor();
63 	OnListCursor();
64 }
65 
RefreshTree(bool dogroups)66 void DockConfigDlg::RefreshTree(bool dogroups)
67 {
68 	TreeCtrl::Node n;
69 
70 	if (dogroups) {
71 		tree.NoRoot(true).Clear();
72 		groups.Clear();
73 		n.Set(-1, t_("All")).CanSelect(false).CanOpen(true);
74 		all = tree.Add(0, n);
75 		for (int i = 0; i < dockers.GetCount(); i++) {
76 			String s = dockers[i]->GetGroup();
77 			int group = s.IsEmpty() ? -1 : groups.Find(s);
78 			if (!s.IsEmpty() && group < 0) {
79 				n.Set(groups.GetCount(), s);
80 				group = tree.Add(0, n);
81 				tree.Open(group);
82 				groups.Add(s, group);
83 			}
84 		}
85 		if (!groups.GetCount()) tree.Open(all);
86 	}
87 	else {
88 		for (int i = 0; i < tree.GetChildCount(0); i++)
89 			tree.RemoveChildren(tree.GetChild(0, i));
90 	}
91 	n.CanSelect(true).CanOpen(false);
92 	for (int i = 0; i < dockers.GetCount(); i++) {
93 		String s = dockers[i]->GetGroup();
94 		int group = s.IsEmpty() ? -1 : groups.Find(s);
95 		s = DockerString(dockers[i]);
96 		n.SetImage(dockers[i]->GetIcon()).Set(i, s);
97 		if (group >= 0)
98 			tree.Add(groups[group], n);
99 		tree.Add(all, n);
100 	}
101 }
102 
OnTreeContext(Bar & bar)103 void DockConfigDlg::OnTreeContext(Bar& bar)
104 {
105 	int id = tree.GetCursor();
106 	if (id >= 0) {
107 		int p = tree.GetParent(id);
108 		if (p != 0) {
109 			menu.WindowMenu(bar, dockers[(int)tree.Get(id)]);
110 			bar.Separator();
111 		}
112 		menu.GroupMenu(bar, (String)tree.GetValue((p==0) ? id : p));
113 		if (p == 0 && id != all) {
114 			bar.Separator();
115 			bar.Add(t_("Delete Group"), THISBACK1(DeleteGroup, id));
116 		}
117 	}
118 }
119 
OnSaveLayout()120 void DockConfigDlg::OnSaveLayout()
121 {
122 	int ix = ListIndex();
123 	String s = (ix >= 0) ? (String)list.Get(ix) : Null;
124 	if (EditText(s, t_("New Layout"), t_("Layout name:"), 25)) {
125 		if (!s.IsEmpty()) {
126 			ix = dock.GetLayouts().Find(s);
127 			if (ix < 0 || PromptOKCancel(Format(t_("Overwrite layout '%s'?"), s))) {
128 				dock.SaveLayout(s);
129 				if (ix < 0) {
130 					list.Add(s);
131 					list.SetCursor(list.GetCount()-1);
132 					OnListCursor();
133 				}
134 			}
135 		}
136 	}
137 }
138 
OnLoadLayout()139 void DockConfigDlg::OnLoadLayout()
140 {
141 	Ctrl *focus = GetFocusCtrl();
142 	int ix = ListIndex();
143 	ASSERT(ix >= 0);
144 	dock.LoadLayout((String)list.Get(ix));
145 	dock.DisableFloating();
146 	if (focus) focus->SetFocus();
147 	RefreshTree(true);
148 }
149 
OnDeleteLayout()150 void DockConfigDlg::OnDeleteLayout()
151 {
152 	int ix = ListIndex();
153 	if (!PromptOKCancel(Format(t_("Delete layout '%s'?"), (String)list.Get(ix)))) return;
154 	dock.DeleteLayout((String)list.Get(ix));
155 	list.Remove(ix);
156 }
157 
OnTreeCursor()158 void DockConfigDlg::OnTreeCursor()
159 {
160 	int id = tree.GetCursor();
161 	if (id <= 0) { deletegroup.Disable(); return; }
162 	int p = tree.GetParent(id);
163 	if (p == 0)
164 		deletegroup.Enable();
165 	else
166 		Highlight(dockers[(int)tree.Get(id)]);
167 }
168 
169 
OnListCursor()170 void DockConfigDlg::OnListCursor()
171 {
172 	loadlayout.Enable(list.GetCursor() >= 0);
173 	deletelayout.Enable(list.GetCursor() >= 0);
174 }
175 
OnNewGroup()176 void DockConfigDlg::OnNewGroup()
177 {
178 	String s;
179 	if (EditText(s, t_("New Group"), t_("Group name:"), 25)) {
180 		if (!s.IsEmpty()) {
181 			if (groups.Find(s) < 0) {
182 				int id = tree.Add(0, Image(), Value(-1), Value(s));
183 				groups.Add(s, id);
184 				tree.SetCursor(list.GetCount()-1);
185 				OnTreeCursor();
186 			}
187 			else {
188 				PromptOK(t_("Group '%s' already exists."));
189 				OnNewGroup();
190 			}
191 		}
192 	}
193 }
194 
OnDeleteGroup()195 void DockConfigDlg::OnDeleteGroup()
196 {
197 	int id = tree.GetCursor();
198 	if (id < 0) return;
199 	int p = tree.GetParent(id);
200 	if (p != 0) id = p;
201 	if (id == all) return;
202 	DeleteGroup(id);
203 }
204 
DeleteGroup(int id)205 void DockConfigDlg::DeleteGroup(int id)
206 {
207 	String s = (String)tree.GetValue(id);
208 	if (!PromptOKCancel(Format(t_("Delete group '%s'?"), s))) return;
209 	int ix = groups.Find(s);
210 	if (ix >= 0) {
211 		String g = Null;
212 		String name = groups.GetKey(ix);
213 		for (int i = 0; i < dockers.GetCount(); i++)
214 			if (dockers[i]->GetGroup() == name)
215 				dockers[i]->SetGroup(g);
216 		tree.RemoveChildren(id);
217 		tree.Remove(id);
218 	}
219 }
220 
OnOK()221 void DockConfigDlg::OnOK()
222 {
223 	dock.Animate(~animatehighlight, ~animateframes, ~animatewindows);
224 	dock.Tabbing(~tabbing);
225 	dock.NestedTabs(~tabnesting);
226 	dock.AutoHide(~autohide);
227 	dock.Grouping(~grouping);
228 	dock.WindowButtons(~menubtn, ~autohidebtn, ~closebtn);
229 	Close();
230 	dock.EnableFloating();
231 }
232 
OnCancel()233 void DockConfigDlg::OnCancel()
234 {
235 	// Restore layout
236 	StringStream s(backup);
237 	dock.SerializeLayout(s, true);
238 	Close();
239 }
240 
OnLock()241 void DockConfigDlg::OnLock()
242 {
243 	dock.LockLayout(locked);
244 }
245 
OnTreeDrag()246 void DockConfigDlg::OnTreeDrag()
247 {
248 	if (tree.GetCursor() >= 0 && tree.GetParent(tree.GetCursor()) == 0)
249 		return;
250 	tree.DoDragAndDrop(InternalClip(tree, "dockwindowdrag"), tree.GetDragSample(), DND_MOVE);
251 }
252 
OnTreeDrop(int parent,int ii,PasteClip & d)253 void DockConfigDlg::OnTreeDrop(int parent, int ii, PasteClip& d)
254 {
255 	if (parent == 0)
256 		return d.Reject();
257 	int p = tree.GetParent(parent);
258 	if (p != 0)
259 		parent = p;
260 
261 	if(AcceptInternal<TreeCtrl>(d, "dockwindowdrag")) {
262 		Vector<int> sel = tree.GetSel();
263 		for (int i = 0; i < sel.GetCount(); i++) {
264 			int ix = tree.Get(sel[i]);
265 			ASSERT(ix >= 0);
266 			dockers[ix]->SetGroup((parent == all) ? Null : (String)tree.GetValue(parent));
267 		}
268 		if (tree.GetCursor()) {
269 			int ix = tree.Get(tree.GetCursor());
270 			ASSERT(ix >= 0);
271 			dockers[ix]->SetGroup((parent == all) ? Null : (String)tree.GetValue(parent));
272 		}
273 		tree.SetFocus();
274 		RefreshTree();
275 		return;
276 	}
277 }
278 
Highlight(DockableCtrl * dc)279 void DockConfigDlg::Highlight(DockableCtrl *dc)
280 {
281 	if (dc != highlight) {
282 		if (DockCont *cont = dynamic_cast<DockCont *>(dc->GetParent())) {
283 			if (!highlight || cont != highlight->GetParent()) {
284 				StopHighlight();
285 				cont->Highlight();
286 			}
287 		}
288 		else {
289 			StopHighlight();
290 			dc->Highlight();
291 		}
292 		highlight = dc;
293 	}
294 	KillSetTimeCallback(HIGHLIGHT_DURATION, THISBACK(StopHighlight), 0);
295 }
296 
StopHighlight()297 void DockConfigDlg::StopHighlight()
298 {
299 	if (highlight) {
300 		if (DockCont *dc = dynamic_cast<DockCont *>(highlight->GetParent()))
301 			dc->Refresh();
302 		else
303 			highlight->Refresh();
304 	}
305 	highlight = NULL;
306 }
307 
ListIndex() const308 int DockConfigDlg::ListIndex() const
309 {
310 	if (!list.IsSelection()) {
311 		if (list.IsCursor())
312 			return list.GetCursor();
313 		else
314 			return -1;
315 	}
316 	for (int i = 0; i < list.GetCount(); i++)
317 		if (list.IsSelected(i))
318 			return i;
319 	return -1;
320 }
321 
322 
DockerString(DockableCtrl * dc) const323 String DockConfigDlg::DockerString(DockableCtrl *dc) const
324 {
325 	return Format("%20<s %s", dc->GetTitle(), PositionString(dc));
326 }
327 
PositionString(DockableCtrl * dc) const328 String DockConfigDlg::PositionString(DockableCtrl *dc) const
329 {
330 	if (dc->IsFloating())
331 		return t_("Floating");
332 	else if (dc->IsTabbed())
333 		return t_("Tabbed");
334 	else if (dc->IsDocked()) {
335 		int align = dc->GetDockAlign();
336 		switch (align) {
337 		case DockWindow::DOCK_LEFT:
338 			return Format(t_("Docked(%s)"), t_("Left"));
339 		case DockWindow::DOCK_TOP:
340 			return Format(t_("Docked(%s)"), t_("Top"));
341 		case DockWindow::DOCK_RIGHT:
342 			return Format(t_("Docked(%s)"), t_("Right"));
343 		case DockWindow::DOCK_BOTTOM:
344 			return Format(t_("Docked(%s)"), t_("Bottom"));
345 		default:
346 			return t_("Docked");
347 		}
348 	}
349 	else if (dc->IsAutoHide())
350 		return t_("Auto-Hide");
351 	else
352 		return t_("Hidden");
353 }
354 
355 }
356