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