1 #include "LogPosCtrl.h"
2 
sLay1(int & pos,int & r,int align,int a,int b,int sz)3 static void sLay1(int& pos, int& r, int align, int a, int b, int sz)
4 {
5 	pos = a;
6 	int size = b;
7 	switch(align) {
8 	case Ctrl::CENTER:
9 		pos = (sz - b) / 2 + a;
10 		break;
11 	case Ctrl::RIGHT:
12 		pos = sz - (a + b);
13 		break;
14 	case Ctrl::SIZE:
15 		size = sz - (a + b);
16 		break;
17 	}
18 	r = pos + max(size, 0);
19 }
20 
21 //LogPos, parent Size -> Rect
22 
23 //generates a Rect from a LogPos info and its parent size
CtrlRect(Ctrl::LogPos pos,Size sz)24 Rect LogPosPopUp::CtrlRect(Ctrl::LogPos pos, Size sz)
25 {
26 	Rect r;
27 	sLay1(r.left, r.right, pos.x.GetAlign(), pos.x.GetA(), pos.x.GetB(), sz.cx);
28 	sLay1(r.top, r.bottom, pos.y.GetAlign(), pos.y.GetA(), pos.y.GetB(), sz.cy);
29 	return r;
30 }
31 
32 //same as above but zoom support
CtrlRectZ(Ctrl::LogPos pos,Size sz)33 Rect LogPosPopUp::CtrlRectZ(Ctrl::LogPos pos, Size sz)
34 {
35 	Rect r = CtrlRect(pos, sz);
36 	r.left = HorzLayoutZoom(r.left);
37 	r.right = HorzLayoutZoom(r.right);
38 	r.top = VertLayoutZoom(r.top);
39 	r.bottom = VertLayoutZoom(r.bottom);
40 	return r;
41 }
42 
MakeLogc(int align,int a,int b,int sz)43 Ctrl::Logc MakeLogc(int align, int a, int b, int sz)
44 {
45 	int isz = b - a;
46 	switch(align) {
47 	case Ctrl::LEFT:
48 		return Ctrl::PosLeft(a, isz);
49 	case Ctrl::RIGHT:
50 		return Ctrl::PosRight(sz - b, isz);
51 	case Ctrl::CENTER:
52 		return Ctrl::PosCenter(isz, a - (sz - isz) / 2);
53 	}
54 	return Ctrl::PosSize(a, sz - b);
55 }
56 
57 //alignment info, Rect, parent Size -> LogPos
58 
MakeLogPos(int ax,int ay,const Rect & r,Size sz)59 Ctrl::LogPos LogPosPopUp::MakeLogPos(int ax, int ay, const Rect& r, Size sz)
60 {
61 	return Ctrl::LogPos(MakeLogc(ax, r.left, r.right, sz.cx),
62 	                    MakeLogc(ay, r.top, r.bottom, sz.cy));
63 }
64 
65 //same as above, but takes align infos from a LogPos info
MakeLogPos(Ctrl::LogPos p,const Rect & r,Size sz)66 Ctrl::LogPos LogPosPopUp::MakeLogPos(Ctrl::LogPos p, const Rect& r, Size sz)
67 {
68 	return MakeLogPos(p.x.GetAlign(), p.y.GetAlign(), r, sz);
69 }
70 
71 //same as above, but generates source Rect from pos/sz
72 //then applying new alignment to it, taken from p
73 //this effectivly replaces the alignment info, keeping the rect visually in place
74 //which includes recalculation of a and b data
MakeLogPos(Ctrl::LogPos p,const Ctrl::LogPos & pos,Size sz)75 Ctrl::LogPos LogPosPopUp::MakeLogPos(Ctrl::LogPos p, const Ctrl::LogPos& pos, Size sz)
76 {
77 	Rect r = CtrlRect(pos, sz); //generate the source rect
78 	return MakeLogPos(p, r, sz);
79 }
80 
81 //same as above but it does it for a specific Ctrl already
MakeLogPos(Ctrl::LogPos p,const Ctrl & c)82 Ctrl::LogPos LogPosPopUp::MakeLogPos(Ctrl::LogPos p, const Ctrl& c)
83 {
84 	if(!c.GetParent()) return p;
85 	//reconvert to logpos using new align
86 	return MakeLogPos(p, c.GetPos(), c.GetParent()->GetSize());
87 }
88 
Set(const Ctrl::LogPos & p)89 void LogPosPopUp::Set(const Ctrl::LogPos& p)
90 {
91 	pos = p;
92 	xa <<= pos.x.GetA(); xb <<= pos.x.GetB();
93 
94 	switch(pos.x.GetAlign())
95 	{
96 		case Ctrl::LEFT:   l = true;  r = false; break;
97 		case Ctrl::RIGHT:  l = false; r = true; break;
98 		case Ctrl::SIZE:   l = true;  r = true; break;
99 		default:
100 		case Ctrl::CENTER: l = false; r = false; break;
101 	}
102 	ya <<= pos.y.GetA(); yb <<= pos.y.GetB();
103 	switch(pos.y.GetAlign())
104 	{
105 		case Ctrl::TOP: t    = true;  b = false; break;
106 		case Ctrl::BOTTOM: t = false; b = true;  break;
107 		case Ctrl::SIZE: t   = true;  b = true;  break;
108 		default:
109 		case Ctrl::CENTER: t = false; b = false; break;
110 	}
111 }
112 
Updated()113 void LogPosPopUp::Updated()
114 {
115 	switch(pos.x.GetAlign())
116 	{
117 		case Ctrl::LEFT:   sxa.SetText("Marg L"); sxb.SetText("Size"); sxn.SetText("Left"); break;
118 		case Ctrl::RIGHT:  sxa.SetText("Marg R"); sxb.SetText("Size"); sxn.SetText("Right"); break;
119 		case Ctrl::SIZE:   sxa.SetText("Marg L"); sxb.SetText("Marg R"); sxn.SetText("HFill"); break;
120 		default:
121 		case Ctrl::CENTER: sxa.SetText("Offs");   sxb.SetText("Size"); sxn.SetText("HCenter"); break;
122 	}
123 	switch(pos.y.GetAlign())
124 	{
125 		case Ctrl::TOP:    sya.SetText("Marg U"); syb.SetText("Size"); syn.SetText("Top"); break;
126 		case Ctrl::BOTTOM: sya.SetText("Marg D"); syb.SetText("Size"); syn.SetText("Bottom"); break;
127 		case Ctrl::SIZE:   sya.SetText("Marg U"); syb.SetText("Marg D"); syn.SetText("VFill"); break;
128 		default:
129 		case Ctrl::CENTER: sya.SetText("Offs");   syb.SetText("Size"); syn.SetText("VCenter"); break;
130 	}
131 }
132 
GetData() const133 Value LogPosPopUp::GetData() const
134 {
135 	return RichToValue(pos);
136 }
137 
SetData(const Value & v)138 void LogPosPopUp::SetData(const Value& v)
139 {
140 	if(!v.Is<Ctrl::LogPos>())
141 		return; Set(RichValue<Ctrl::LogPos>::Extract(v));
142 	Update();
143 }
144 
145 //obsolete
Generate() const146 Ctrl::LogPos LogPosPopUp::Generate() const
147 {
148 	Ctrl::LogPos pos;
149 	int q;
150 
151 	q = 0;
152 	q |= l ? 1 : 0;
153 	q |= r ? 2 : 0;
154 	switch(q)
155 	{
156 		case 1: pos.x.SetAlign(Ctrl::LEFT); break;
157 		case 2: pos.x.SetAlign(Ctrl::RIGHT); break;
158 		case 3: pos.x.SetAlign(Ctrl::SIZE); break;
159 		default:
160 		case 0: pos.x.SetAlign(Ctrl::CENTER); break;
161 	}
162 	pos.x.SetA(xa); pos.x.SetB(xb);
163 
164 	q = 0;
165 	q |= t ? 1 : 0;
166 	q |= b ? 2 : 0;
167 	switch(q)
168 	{
169 		case 1: pos.y.SetAlign(Ctrl::TOP); break;
170 		case 2: pos.y.SetAlign(Ctrl::BOTTOM); break;
171 		case 3: pos.y.SetAlign(Ctrl::SIZE); break;
172 		default:
173 		case 0: pos.y.SetAlign(Ctrl::CENTER); break;
174 	}
175 	pos.y.SetA(ya); pos.y.SetB(yb);
176 
177 	return pos;
178 }
179 
XaCB()180 void LogPosPopUp::XaCB()
181 {
182 	pos.x.SetA(xa);
183 	WhenSizeChange();
184 	UpdateAction();
185 }
XbCB()186 void LogPosPopUp::XbCB()
187 {
188 	pos.x.SetB(xb);
189 	WhenSizeChange();
190 	UpdateAction();
191 }
YaCB()192 void LogPosPopUp::YaCB()
193 {
194 	pos.y.SetA(ya);
195 	WhenSizeChange();
196 	UpdateAction();
197 }
YbCB()198 void LogPosPopUp::YbCB()
199 {
200 	pos.y.SetB(yb);
201 	WhenSizeChange();
202 	UpdateAction();
203 }
XAlign()204 void LogPosPopUp::XAlign()
205 {
206 	int q = 0;
207 	q |= l ? 1 : 0;
208 	q |= r ? 2 : 0;
209 	switch(q)
210 	{
211 		case 1: pos.x.SetAlign(Ctrl::LEFT); break;
212 		case 2: pos.x.SetAlign(Ctrl::RIGHT); break;
213 		case 3: pos.x.SetAlign(Ctrl::SIZE); break;
214 		default:
215 		case 0: pos.x.SetAlign(Ctrl::CENTER); break;
216 	}
217 }
YAlign()218 void LogPosPopUp::YAlign()
219 {
220 	int q = 0;
221 	q |= t ? 1 : 0;
222 	q |= b ? 2 : 0;
223 	switch(q)
224 	{
225 		case 1: pos.y.SetAlign(Ctrl::TOP); break;
226 		case 2: pos.y.SetAlign(Ctrl::BOTTOM); break;
227 		case 3: pos.y.SetAlign(Ctrl::SIZE); break;
228 		default:
229 		case 0: pos.y.SetAlign(Ctrl::CENTER); break;
230 	}
231 }
232 
LogPosPopUp()233 LogPosPopUp::LogPosPopUp()
234 {
235 	CtrlLayoutCancel(*this, "");
236 	cktype = CKOKCANCEL;
237 	SetFrame(BlackFrame());
238 
239 	l.SetLabel("<");
240 	r.SetLabel(">");
241 	t.SetLabel("/\\");
242 	b.SetLabel("\\/");
243 
244 	xa <<= THISBACK(XaCB);
245 	xb <<= THISBACK(XbCB);
246 	ya <<= THISBACK(YaCB);
247 	yb <<= THISBACK(YbCB);
248 
249 	l <<= THISBACK(LRCB);
250 	r <<= THISBACK(LRCB);
251 	t <<= THISBACK(TBCB);
252 	b <<= THISBACK(TBCB);
253 
254 	lt <<= THISBACK(LTCB);
255 	rt <<= THISBACK(RTCB);
256 	lb <<= THISBACK(LBCB);
257 	rb <<= THISBACK(RBCB);
258 
259 	hc <<= THISBACK(HCCB);
260 	vc <<= THISBACK(VCCB);
261 	cc <<= THISBACK(CCCB);
262 
263 	hs <<= THISBACK(HSCB);
264 	vs <<= THISBACK(VSCB);
265 	ss <<= THISBACK(SSCB);
266 }
267 
LogPosCtrl()268 LogPosCtrl::LogPosCtrl() : push(false)
269 {
270 	IgnoreMouse(false);
271 
272 	lc.WhenAccept = THISBACK(OnAccept);
273 	lc.WhenReject = THISBACK(OnReject);
274 	lc.WhenAction = THISBACK(OnAction);
275 
276 	lc.WhenSizeChange = THISBACK(OnSizeChange);
277 	lc.WhenAlignChange = THISBACK(OnAlignChange);
278 
279 	bsz.SetNull();
280 }
281 
LeftDown(Point p,dword keyflags)282 void LogPosCtrl::LeftDown(Point p, dword keyflags)
283 {
284 	if(IsReadOnly() || !IsEnabled()) return;
285 	if(!HasFocus()) SetFocus();
286 	Drop();
287 }
288 
GetData() const289 Value LogPosCtrl::GetData() const
290 {
291 	return RichToValue(pos);
292 }
293 
SetData(const Value & v)294 void LogPosCtrl::SetData(const Value& v)
295 {
296 	if(!v.Is<Ctrl::LogPos>())
297 		return;
298 	pos = RichValue<Ctrl::LogPos>::Extract(v);
299 	Update();
300 }
301 
Drop()302 void LogPosCtrl::Drop()
303 {
304 	if(push) return;
305 	push = true;
306 	lc.Set(pos);
307 	lc.Backup();
308 	lc.PopUp(this);
309 }
310 
OnReject()311 void LogPosCtrl::OnReject()
312 {
313 	push = false;
314 	Ctrl::LogPos _pos = lc.Get();
315 	if(pos != _pos) {
316 		pos = _pos;
317 		OnSizeChange(); //restore
318 		UpdateAction();
319 	}
320 }
321 
OnAccept()322 void LogPosCtrl::OnAccept()
323 {
324 	push = false;
325 //	OnAction();
326 	pos = lc.Get();
327 }
328 
OnAction()329 void LogPosCtrl::OnAction()
330 {
331 	pos = lc.Get();
332 	UpdateAction();
333 }
334 
Updated()335 void LogPosCtrl::Updated()
336 {
337 	SetText(AsString(pos));
338 }
339 
OnSizeChange()340 void LogPosCtrl::OnSizeChange()
341 {
342 }
343 
OnAlignChange()344 void LogPosCtrl::OnAlignChange()
345 {
346 	if(bsz.IsNullInstance()) return;
347 	lc.Set(LogPosPopUp::MakeLogPos(lc.Get(), pos, bsz));
348 	lc.Update(); //feedback to lc
349 }
350