1 #include "CtrlCore.h"
2
3 namespace Upp {
4
5 #define LLOG(x) // DLOG(x)
6 #define LTIMING(x) // RTIMING(x)
7
IsEmpty() const8 bool Ctrl::Logc::IsEmpty() const {
9 return GetAlign() == SIZE ? GetB() <= GetA() : GetB() <= 0;
10 }
11
PosVal(int v) const12 Size Ctrl::PosVal(int v) const {
13 switch(v) {
14 case MINSIZE: return GetMinSize();
15 case STDSIZE: return GetStdSize();
16 case MAXSIZE: return GetMaxSize();
17 }
18 return Size(v, v);
19 }
20
Lay1(int & pos,int & r,int align,int a,int b,int sz) const21 void Ctrl::Lay1(int& pos, int& r, int align, int a, int b, int sz) const
22 {
23 pos = a;
24 int size = b;
25 switch(align) {
26 case CENTER:
27 pos = (sz - b) / 2 + a;
28 break;
29 case RIGHT:
30 pos = sz - (a + b);
31 break;
32 case SIZE:
33 size = sz - (a + b);
34 break;
35 }
36 r = pos + max(size, 0);
37 }
38
CalcRect(LogPos pos,const Rect & prect,const Rect & pview) const39 Rect Ctrl::CalcRect(LogPos pos, const Rect& prect, const Rect& pview) const
40 {
41 Rect r;
42 Size sz = InFrame() ? prect.Size() : pview.Size();
43 Lay1(r.left, r.right, pos.x.GetAlign(),
44 PosVal(pos.x.GetA()).cx, PosVal(pos.x.GetB()).cx, sz.cx);
45 Lay1(r.top, r.bottom, pos.y.GetAlign(),
46 PosVal(pos.y.GetA()).cy, PosVal(pos.y.GetB()).cy, sz.cy);
47 return r;
48 }
49
CalcRect(const Rect & prect,const Rect & pview) const50 Rect Ctrl::CalcRect(const Rect& prect, const Rect& pview) const
51 {
52 return CalcRect(pos, prect, pview);
53 }
54
GetRect() const55 Rect Ctrl::GetRect() const
56 {
57 return rect;
58 }
59
GetView() const60 Rect Ctrl::GetView() const
61 {
62 GuiLock __;
63 return frame.GetCount() == 0 ? Rect(Size(rect.Size())) : Rect(frame[frame.GetCount() - 1].view);
64 }
65
GetSize() const66 Size Ctrl::GetSize() const
67 {
68 return GetView().GetSize();
69 }
70
GetScreenRect() const71 Rect Ctrl::GetScreenRect() const
72 {
73 GuiLock __;
74 Rect r = GetRect();
75 if(parent) {
76 Rect pr = inframe ? parent->GetScreenRect() : parent->GetScreenView();
77 r = r + pr.TopLeft();
78 }
79 else
80 GuiPlatformGetTopRect(r);
81 return r;
82 }
83
GetScreenView() const84 Rect Ctrl::GetScreenView() const
85 {
86 Rect r = GetScreenRect();
87 return GetView() + r.TopLeft();
88 }
89
GetVisibleScreenRect() const90 Rect Ctrl::GetVisibleScreenRect() const
91 {
92 GuiLock __;
93 Rect r = GetRect();
94 if(parent) {
95 Rect pr = inframe ? parent->GetVisibleScreenRect() : parent->GetVisibleScreenView();
96 Rect pr1 = inframe ? parent->GetScreenRect() : parent->GetScreenView();
97 r = (r + pr1.TopLeft()) & pr;
98 }
99 else
100 GuiPlatformGetTopRect(r);
101 return r & GetVirtualScreenArea();
102 }
103
GetVisibleScreenView() const104 Rect Ctrl::GetVisibleScreenView() const
105 {
106 Rect r = GetVisibleScreenRect();
107 return (GetView() + r.TopLeft()) & r;
108 }
109
AddFrameSize(int cx,int cy) const110 Size Ctrl::AddFrameSize(int cx, int cy) const
111 {
112 GuiLock __;
113 Size sz = Size(cx, cy);
114 for(int i = frame.GetCount() - 1; i >= 0; i--)
115 frame[i].frame->FrameAddSize(sz);
116 return sz;
117 }
118
119 int EditFieldIsThin();
120
GetMinSize() const121 Size Ctrl::GetMinSize() const
122 {
123 int fcy = Draw::GetStdFontCy();
124 return AddFrameSize(fcy / 2, fcy + 2 + 2 * EditFieldIsThin());
125 }
126
GetStdSize() const127 Size Ctrl::GetStdSize() const
128 {
129 Size sz = GetMinSize();
130 sz.cx *= 10;
131 return sz;
132 }
133
GetMaxSize() const134 Size Ctrl::GetMaxSize() const
135 {
136 return GetVirtualScreenArea().Size();
137 }
138
SyncLayout(int force)139 void Ctrl::SyncLayout(int force)
140 {
141 GuiLock __;
142 if(destroying)
143 return;
144 LLOG("SyncLayout " << Name() << " size: " << GetSize());
145 bool refresh = false;
146 Rect oview = GetView();
147 Rect view = GetRect().Size();
148 overpaint = OverPaint();
149 for(int i = 0; i < frame.GetCount(); i++) {
150 Frame& f = frame[i];
151 f.frame->FrameLayout(view);
152 if(view != f.view) {
153 f.view = view;
154 refresh = true;
155 }
156 int q = f.frame->OverPaint();
157 if(q > overpaint) overpaint = q;
158 }
159 if(oview.Size() != view.Size() || force > 1) {
160 for(Ctrl *q = GetFirstChild(); q; q = q->next) {
161 q->rect = q->CalcRect(rect, view);
162 LLOG("Layout set rect " << q->Name() << " " << q->rect);
163 q->SyncLayout(force > 1 ? force : 0);
164 }
165 Refresh();
166 }
167 if(oview != view || force) {
168 State(LAYOUTPOS);
169 Layout();
170 }
171 if(refresh)
172 RefreshFrame();
173 }
174
FindMoveCtrl(const VectorMap<Ctrl *,MoveCtrl> & m,Ctrl * x)175 int Ctrl::FindMoveCtrl(const VectorMap<Ctrl *, MoveCtrl>& m, Ctrl *x)
176 {
177 int q = m.Find(x);
178 return q >= 0 && m[q].ctrl ? q : -1;
179 }
180
FindMoveCtrlPtr(VectorMap<Ctrl *,MoveCtrl> & m,Ctrl * x)181 Ctrl::MoveCtrl *Ctrl::FindMoveCtrlPtr(VectorMap<Ctrl *, MoveCtrl>& m, Ctrl *x)
182 {
183 int q = FindMoveCtrl(m, x);
184 return q >= 0 ? &m[q] : NULL;
185 }
186
SetPos0(LogPos p,bool _inframe)187 void Ctrl::SetPos0(LogPos p, bool _inframe)
188 {
189 GuiLock __;
190 if(p == pos && inframe == _inframe) return;
191 if(parent && !IsDHCtrl()) {
192 if(!globalbackbuffer) {
193 Rect from = GetRect().Size();
194 Top *top = GetTopRect(from, true)->top;
195 if(top) {
196 LTIMING("SetPos0 MoveCtrl");
197 pos = p;
198 inframe = _inframe;
199 Rect to = GetRect().Size();
200 UpdateRect0();
201 GetTopRect(to, true);
202 MoveCtrl *s = FindMoveCtrlPtr(top->scroll_move, this);
203 if(s && s->from == from && s->to == to) {
204 s->ctrl = NULL;
205 LLOG("SetPos Matched " << from << " -> " << to);
206 }
207 else {
208 MoveCtrl& m = top->move.Add(this);
209 m.ctrl = this;
210 m.from = from;
211 m.to = to;
212 LLOG("SetPos Add " << UPP::Name(this) << from << " -> " << to);
213 }
214 StateH(POSITION);
215 return;
216 }
217 }
218 RefreshFrame();
219 }
220 pos = p;
221 inframe = _inframe;
222 UpdateRect();
223 StateH(POSITION);
224 }
225
UpdateRect0(bool sync)226 void Ctrl::UpdateRect0(bool sync)
227 {
228 GuiLock __;
229 LTIMING("UpdateRect0");
230 if(parent)
231 rect = CalcRect(parent->GetRect(), parent->GetView());
232 else {
233 static Rect pwa;
234 ONCELOCK {
235 pwa = GetPrimaryWorkArea();
236 }
237 rect = CalcRect(pwa, pwa);
238 }
239 LLOG("UpdateRect0 " << Name() << " to " << rect);
240 LTIMING("UpdateRect0 SyncLayout");
241 if(sync)
242 SyncLayout();
243 }
244
245
UpdateRect(bool sync)246 void Ctrl::UpdateRect(bool sync)
247 {
248 GuiLock __;
249 UpdateRect0(sync);
250 if(parent) RefreshFrame();
251 }
252
SetPos(LogPos p,bool _inframe)253 Ctrl& Ctrl::SetPos(LogPos p, bool _inframe)
254 {
255 GuiLock __;
256 if(p != pos || inframe != _inframe) {
257 if(parent || !IsOpen())
258 SetPos0(p, _inframe);
259 else {
260 Rect wa = GetWorkArea();
261 WndSetPos(CalcRect(p, wa, wa));
262 StateH(POSITION);
263 }
264 }
265 return *this;
266 }
267
SetPos(LogPos p)268 Ctrl& Ctrl::SetPos(LogPos p)
269 {
270 return SetPos(p, false);
271 }
272
SetPosX(Logc x)273 Ctrl& Ctrl::SetPosX(Logc x)
274 {
275 return SetPos(LogPos(x, pos.y));
276 }
277
SetPosY(Logc y)278 Ctrl& Ctrl::SetPosY(Logc y)
279 {
280 return SetPos(LogPos(pos.x, y));
281 }
282
SetFramePos(LogPos p)283 Ctrl& Ctrl::SetFramePos(LogPos p)
284 {
285 return SetPos(p, true);
286 }
287
SetFramePosX(Logc x)288 Ctrl& Ctrl::SetFramePosX(Logc x) {
289 return SetPos(LogPos(x, pos.y), true);
290 }
291
SetFramePosY(Logc y)292 Ctrl& Ctrl::SetFramePosY(Logc y) {
293 return SetPos(LogPos(pos.x, y), true);
294 }
295
SetRect(int x,int y,int cx,int cy)296 void Ctrl::SetRect(int x, int y, int cx, int cy)
297 {
298 LLOG("SetRect " << Name() << " rect: " << RectC(x, y, cx, cy));
299 auto clampc = [](int c) { return clamp(c, -10000, 10000); }; // Logc vals only have 15 bits
300 SetPos(PosLeft(clampc(x), clampc(cx)), PosTop(clampc(y), clampc(cy)));
301 }
302
SetWndRect(const Rect & r)303 void Ctrl::SetWndRect(const Rect& r)
304 {
305 LLOG("SetWndRect " << Name() << " rect: " << r << " (Ctrl::GetRect = " << GetRect() << ")");
306 SetPos0(LogPos(PosLeft(r.left, r.Width()), PosTop(r.top, r.Height())), false);
307 }
308
SetRect(const Rect & r)309 void Ctrl::SetRect(const Rect& r)
310 {
311 LLOG("SetRect " << Name() << " rect: " << r << " (Ctrl::GetRect = " << GetRect() << ")");
312 SetRect(r.left, r.top, r.Width(), r.Height());
313 }
314
SetRectX(int x,int cx)315 void Ctrl::SetRectX(int x, int cx) {
316 SetPosX(PosLeft(x, cx));
317 }
318
SetRectY(int y,int cy)319 void Ctrl::SetRectY(int y, int cy) {
320 SetPosY(PosTop(y, cy));
321 }
322
SetFrameRect(int x,int y,int cx,int cy)323 void Ctrl::SetFrameRect(int x, int y, int cx, int cy) {
324 SetFramePos(PosLeft(x, cx), PosTop(y, cy));
325 }
326
SetFrameRect(const Rect & r)327 void Ctrl::SetFrameRect(const Rect& r) {
328 SetFrameRect(r.left, r.top, r.Width(), r.Height());
329 }
330
SetFrameRectX(int x,int cx)331 void Ctrl::SetFrameRectX(int x, int cx) {
332 SetFramePosX(PosLeft(x, cx));
333 }
334
SetFrameRectY(int y,int cy)335 void Ctrl::SetFrameRectY(int y, int cy) {
336 SetFramePosY(PosTop(y, cy));
337 }
338
SetFrame(int i,CtrlFrame & fr)339 Ctrl& Ctrl::SetFrame(int i, CtrlFrame& fr) {
340 GuiLock __;
341 LLOG("SetFrame " << typeid(fr).name());
342 while(frame.GetCount() <= i)
343 frame.Add().frame = &NullFrame();
344 frame[i].frame->FrameRemove();
345 frame[i].frame = &fr;
346 fr.FrameAdd(*this);
347 SyncLayout();
348 RefreshFrame();
349 return *this;
350 }
351
AddFrame(CtrlFrame & fr)352 Ctrl& Ctrl::AddFrame(CtrlFrame& fr) {
353 GuiLock __;
354 LLOG("AddFrame " << typeid(fr).name());
355 frame.Add().frame = &fr;
356 fr.FrameAdd(*this);
357 SyncLayout();
358 RefreshFrame();
359 return *this;
360 }
361
ClearFrames()362 void Ctrl::ClearFrames() {
363 GuiLock __;
364 for(int i = 0; i < frame.GetCount(); i++)
365 frame[i].frame->FrameRemove();
366 frame.Clear();
367 frame.Add().frame = &NullFrame();
368 RefreshFrame();
369 SyncLayout();
370 }
371
RemoveFrame(int i)372 void Ctrl::RemoveFrame(int i) {
373 GuiLock __;
374 int n = frame.GetCount();
375 Mitor<Frame> m;
376 if(n > 1)
377 for(int q = 0; q < n; q++) {
378 if(q != i)
379 m.Add().frame = frame[q].frame;
380 else
381 frame[q].frame->FrameRemove();
382 }
383 frame = pick(m);
384 if(frame.GetCount() == 0)
385 frame.Add().frame = &NullFrame();
386 RefreshFrame();
387 SyncLayout();
388 }
389
FindFrame(CtrlFrame & frm)390 int Ctrl::FindFrame(CtrlFrame& frm)
391 {
392 GuiLock __;
393 for(int i = 0; i < frame.GetCount(); i++)
394 if(frame[i].frame == &frm)
395 return i;
396 return -1;
397 }
398
RemoveFrame(CtrlFrame & frm)399 void Ctrl::RemoveFrame(CtrlFrame& frm)
400 {
401 GuiLock __;
402 int i = FindFrame(frm);
403 if(i >= 0)
404 RemoveFrame(i);
405 }
406
InsertFrame(int i,CtrlFrame & fr)407 void Ctrl::InsertFrame(int i, CtrlFrame& fr)
408 {
409 GuiLock __;
410 ASSERT(i >= 0 && i <= frame.GetCount());
411 int n = frame.GetCount();
412 Mitor<Frame> m;
413 if(n >= 1)
414 for(int q = 0; q < n; q++) {
415 if(q == i) m.Add().frame = &fr;
416 m.Add().frame = frame[q].frame;
417 }
418 if(i == n)
419 m.Add().frame = &fr;
420 frame = pick(m);
421 fr.FrameAdd(*this);
422 SyncLayout();
423 RefreshFrame();
424 }
425
LeftPos(int a,int size)426 Ctrl& Ctrl::LeftPos(int a, int size) {
427 return SetPosX(PosLeft(a, size));
428 }
429
RightPos(int a,int size)430 Ctrl& Ctrl::RightPos(int a, int size) {
431 return SetPosX(PosRight(a, size));
432 }
433
TopPos(int a,int size)434 Ctrl& Ctrl::TopPos(int a, int size) {
435 return SetPosY(PosTop(a, size));
436 }
437
BottomPos(int a,int size)438 Ctrl& Ctrl::BottomPos(int a, int size) {
439 return SetPosY(PosBottom(a, size));
440 }
441
HSizePos(int a,int b)442 Ctrl& Ctrl::HSizePos(int a, int b) {
443 return SetPosX(PosSize(a, b));
444 }
445
VSizePos(int a,int b)446 Ctrl& Ctrl::VSizePos(int a, int b) {
447 return SetPosY(PosSize(a, b));
448 }
449
SizePos()450 Ctrl& Ctrl::SizePos() {
451 return HSizePos().VSizePos();
452 }
453
HCenterPos(int size,int delta)454 Ctrl& Ctrl::HCenterPos(int size, int delta) {
455 return SetPosX(PosCenter(size, delta));
456 }
457
VCenterPos(int size,int delta)458 Ctrl& Ctrl::VCenterPos(int size, int delta) {
459 return SetPosY(PosCenter(size, delta));
460 }
461
LeftPosZ(int a,int size)462 Ctrl& Ctrl::LeftPosZ(int a, int size) {
463 return LeftPos(HorzLayoutZoom(a), HorzLayoutZoom(size));
464 }
465
RightPosZ(int a,int size)466 Ctrl& Ctrl::RightPosZ(int a, int size) {
467 return RightPos(HorzLayoutZoom(a), HorzLayoutZoom(size));
468 }
469
TopPosZ(int a,int size)470 Ctrl& Ctrl::TopPosZ(int a, int size) {
471 return TopPos(VertLayoutZoom(a), VertLayoutZoom(size));
472 }
473
BottomPosZ(int a,int size)474 Ctrl& Ctrl::BottomPosZ(int a, int size) {
475 return BottomPos(VertLayoutZoom(a), VertLayoutZoom(size));
476 }
477
HSizePosZ(int a,int b)478 Ctrl& Ctrl::HSizePosZ(int a, int b) {
479 return HSizePos(HorzLayoutZoom(a), HorzLayoutZoom(b));
480 }
481
VSizePosZ(int a,int b)482 Ctrl& Ctrl::VSizePosZ(int a, int b) {
483 return VSizePos(VertLayoutZoom(a), VertLayoutZoom(b));
484 }
485
HCenterPosZ(int size,int delta)486 Ctrl& Ctrl::HCenterPosZ(int size, int delta) {
487 return HCenterPos(HorzLayoutZoom(size), HorzLayoutZoom(delta));
488 }
489
VCenterPosZ(int size,int delta)490 Ctrl& Ctrl::VCenterPosZ(int size, int delta) {
491 return VCenterPos(VertLayoutZoom(size), VertLayoutZoom(delta));
492 }
493
GetWorkArea(Point pt)494 Rect Ctrl::GetWorkArea(Point pt)
495 {
496 GuiLock __;
497 static Array<Rect> rc;
498 if (rc.IsEmpty())
499 GetWorkArea(rc);
500 for(int i = 0; i < rc.GetCount(); i++)
501 if(rc[i].Contains(pt))
502 return rc[i];
503 return GetPrimaryWorkArea();
504 }
505
506 }
507