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