1 #include "CtrlCore.h"
2 
3 namespace Upp {
4 
5 #define LLOG(x)   // DLOG(x)
6 
7 #define IMAGECLASS CtrlCoreImg
8 #define IMAGEFILE <CtrlCore/CtrlCore.iml>
9 #include <Draw/iml_source.h>
10 
StdDisplayErrorFn(const Value & e)11 static bool StdDisplayErrorFn(const Value& e)
12 {
13 	GuiLock __;
14 	if(!e.IsError())
15 		return false;
16 	String s = GetErrorText(e);
17 #ifdef PLATFORM_WIN32
18 	MessageBox(NULL, s, GetExeTitle(), MB_OK | MB_ICONQUESTION);
19 #else
20 	fputs(String().Cat() << GetExeTitle() << ": " << s << '\n', stderr);
21 #endif
22 	return true;
23 }
24 
DisplayErrorFn()25 bool (*&DisplayErrorFn())(const Value& v)
26 {
27 	static bool (*errfn)(const Value& v) = &StdDisplayErrorFn;
28 	return errfn;
29 }
30 
31 int64 Ctrl::eventid;
32 
33 Ctrl *Ctrl::LoopCtrl;
34 int   Ctrl::LoopLevel;
35 int64 Ctrl::EventLoopNo;
36 int64 Ctrl::EndSessionLoopNo;
37 
38 bool Ctrl::MemoryCheck;
39 
40 bool Ctrl::painting = false;
41 
SetData(const Value &)42 void   Ctrl::SetData(const Value&) {}
GetData() const43 Value  Ctrl::GetData() const       { return Value(); }
44 
Paint(Draw & draw)45 void Ctrl::Paint(Draw& draw)                        {}
OverPaint() const46 int  Ctrl::OverPaint() const                        { return 0; }
47 
Activate()48 void Ctrl::Activate()                               {}
Deactivate()49 void Ctrl::Deactivate()                             {}
DeactivateBy(Ctrl *)50 void Ctrl::DeactivateBy(Ctrl *)                     {}
51 
CancelMode()52 void Ctrl::CancelMode()                             {}
MouseEnter(Point p,dword keyflags)53 void Ctrl::MouseEnter(Point p, dword keyflags)      {}
LeftDown(Point p,dword keyflags)54 void Ctrl::LeftDown(Point p, dword keyflags)        {}
RightDown(Point p,dword keyflags)55 void Ctrl::RightDown(Point p, dword keyflags)       {}
LeftRepeat(Point p,dword keyflags)56 void Ctrl::LeftRepeat(Point p, dword keyflags)      {}
RightRepeat(Point p,dword keyflags)57 void Ctrl::RightRepeat(Point p, dword keyflags)     {}
MouseMove(Point p,dword keyflags)58 void Ctrl::MouseMove(Point p, dword keyflags)       {}
LeftUp(Point,dword keyflags)59 void Ctrl::LeftUp(Point, dword keyflags)            {}
RightUp(Point p,dword keyflags)60 void Ctrl::RightUp(Point p, dword keyflags)         {}
MouseLeave()61 void Ctrl::MouseLeave()                             {}
LeftDrag(Point p,dword keyflags)62 void Ctrl::LeftDrag(Point p, dword keyflags)        {}
LeftHold(Point p,dword keyflags)63 void Ctrl::LeftHold(Point p, dword keyflags)        {}
RightDrag(Point p,dword keyflags)64 void Ctrl::RightDrag(Point p, dword keyflags)       {}
RightHold(Point p,dword keyflags)65 void Ctrl::RightHold(Point p, dword keyflags)       {}
MiddleDown(Point p,dword keyflags)66 void Ctrl::MiddleDown(Point p, dword keyflags)      {}
MiddleDouble(Point p,dword keyflags)67 void Ctrl::MiddleDouble(Point p, dword keyflags)    {}
MiddleTriple(Point p,dword keyflags)68 void Ctrl::MiddleTriple(Point p, dword keyflags)    {}
MiddleRepeat(Point p,dword keyflags)69 void Ctrl::MiddleRepeat(Point p, dword keyflags)    {}
MiddleDrag(Point p,dword keyflags)70 void Ctrl::MiddleDrag(Point p, dword keyflags)      {}
MiddleHold(Point p,dword keyflags)71 void Ctrl::MiddleHold(Point p, dword keyflags)      {}
MiddleUp(Point p,dword keyflags)72 void Ctrl::MiddleUp(Point p, dword keyflags)        {}
73 
Layout()74 void Ctrl::Layout()                                 {}
75 
PostInput()76 void Ctrl::PostInput()
77 {
78 	GuiLock __;
79 	if(parent) parent->PostInput();
80 }
81 
LeftDouble(Point p,dword keyflags)82 void Ctrl::LeftDouble(Point p, dword keyflags)
83 {
84 	LeftDown(p, keyflags);
85 }
86 
LeftTriple(Point p,dword keyflags)87 void Ctrl::LeftTriple(Point p, dword keyflags)
88 {
89 	LeftDown(p, keyflags);
90 }
91 
RightDouble(Point p,dword keyflags)92 void Ctrl::RightDouble(Point p, dword keyflags)
93 {
94 	RightDown(p, keyflags);
95 }
96 
RightTriple(Point p,dword keyflags)97 void Ctrl::RightTriple(Point p, dword keyflags)
98 {
99 	RightDown(p, keyflags);
100 }
101 
ChildGotFocus()102 void Ctrl::ChildGotFocus()
103 {
104 	GuiLock __;
105 	if(parent) parent->ChildGotFocus();
106 }
107 
ChildLostFocus()108 void Ctrl::ChildLostFocus()
109 {
110 	GuiLock __;
111 	if(parent) parent->ChildLostFocus();
112 }
113 
ChildAdded(Ctrl * q)114 void Ctrl::ChildAdded(Ctrl *q)
115 {
116 	GuiLock __;
117 	if(parent) parent->ChildAdded(q);
118 }
119 
ChildRemoved(Ctrl * q)120 void Ctrl::ChildRemoved(Ctrl *q)
121 {
122 	GuiLock __;
123 	if(parent) parent->ChildRemoved(q);
124 }
125 
ParentChange()126 void Ctrl::ParentChange() {}
127 
Key(dword key,int count)128 bool Ctrl::Key(dword key, int count)
129 {
130 	return false;
131 }
132 
GotFocus()133 void Ctrl::GotFocus()                               {}
LostFocus()134 void Ctrl::LostFocus()                              {}
135 
AccessKeyBit(int accesskey)136 dword  Ctrl::AccessKeyBit(int accesskey)
137 {
138 	accesskey &= 255;
139 	if(accesskey >= 'A' && accesskey <= 'Z')
140 		return (uint64)2 << (accesskey - 'A');
141 	return !!accesskey;
142 }
143 
GetAccessKeysDeep() const144 dword Ctrl::GetAccessKeysDeep() const
145 {
146 	GuiLock __;
147 	dword used = GetAccessKeys();
148 	for(Ctrl *ctrl = GetFirstChild(); ctrl; ctrl = ctrl->GetNext())
149 		used |= ctrl->GetAccessKeysDeep();
150 	return used;
151 }
152 
AssignAccessKeys(dword used)153 void Ctrl::AssignAccessKeys(dword used)
154 {
155 	GuiLock __;
156 	for(Ctrl *ctrl = GetFirstChild(); ctrl; ctrl = ctrl->GetNext()) {
157 		ctrl->AssignAccessKeys(used);
158 		used |= ctrl->GetAccessKeys();
159 	}
160 }
161 
GetAccessKeys() const162 dword Ctrl::GetAccessKeys() const
163 {
164 	return 0;
165 }
166 
DistributeAccessKeys()167 void Ctrl::DistributeAccessKeys()
168 {
169 	AssignAccessKeys(GetAccessKeysDeep());
170 }
171 
VisibleAccessKeys()172 bool Ctrl::VisibleAccessKeys()
173 {
174 	GuiLock __;
175 	if(GUI_AltAccessKeys())
176 		return GetAlt() && GetTopCtrl() == GetActiveCtrl();
177 	return true;
178 }
179 
State(int)180 void Ctrl::State(int) {}
181 
StateDeep(int reason)182 void Ctrl::StateDeep(int reason)
183 {
184 	GuiLock __;
185 	if(destroying)
186 		return;
187 	for(Ctrl *q = GetFirstChild(); q; q = q->GetNext())
188 		q->StateDeep(reason);
189 	State(reason);
190 }
191 
StateH(int reason)192 void Ctrl::StateH(int reason)
193 {
194 	GuiLock __;
195 	for(int i = 0; i < statehook().GetCount(); i++)
196 		if((*statehook()[i])(this, reason))
197 			return;
198 	StateDeep(reason);
199 }
200 
Accept()201 bool   Ctrl::Accept()
202 {
203 	GuiLock __;
204 	if(!IsEnabled() || !IsShown())
205 		return true;
206 	if(DisplayError(GetData())) {
207 		SetWantFocus();
208 		return false;
209 	}
210 	for(Ctrl *q = GetFirstChild(); q; q = q->GetNext())
211 		if(!q->Accept()) return false;
212 	return true;
213 }
214 
Reject()215 void   Ctrl::Reject()
216 {
217 	GuiLock __;
218 	for(Ctrl *q = GetFirstChild(); q; q = q->GetNext())
219 		q->Reject();
220 }
221 
Serialize(Stream & s)222 void   Ctrl::Serialize(Stream& s)
223 {
224 	GuiLock __;
225 	Value x;
226 	if(s.IsStoring())
227 		x = GetData();
228 	s % x;
229 	if(s.IsLoading())
230 		SetData(x);
231 	for(Ctrl *q = GetFirstChild(); q; q = q->GetNext())
232 		q->Serialize(s);
233 }
234 
Jsonize(JsonIO & jio)235 void Ctrl::Jsonize(JsonIO& jio)
236 {
237 	GuiLock __;
238 	Value x;
239 	if(jio.IsStoring())
240 		x = GetData();
241 	x.Jsonize(jio);
242 	if(jio.IsLoading())
243 		SetData(x);
244 }
245 
Xmlize(XmlIO & xio)246 void Ctrl::Xmlize(XmlIO& xio)
247 {
248 	GuiLock __;
249 	Value x;
250 	if(xio.IsStoring())
251 		x = GetData();
252 	x.Xmlize(xio);
253 	if(xio.IsLoading())
254 		SetData(x);
255 }
256 
Updated()257 void Ctrl::Updated() {}
258 
IsForeground() const259 bool Ctrl::IsForeground() const
260 {
261 	GuiLock __;
262 	return GetTopCtrl()->IsWndForeground();
263 }
264 
SetForeground()265 void Ctrl::SetForeground()
266 {
267 	GuiLock __;
268 	GetTopCtrl()->SetWndForeground();
269 }
270 
IsOpen() const271 bool Ctrl::IsOpen() const
272 {
273 	GuiLock __;
274 	const Ctrl *q = GetTopCtrl();
275 	return q->isopen && q->IsWndOpen();
276 }
277 
Show(bool ashow)278 void Ctrl::Show(bool ashow) {
279 	GuiLock __;
280 	if(visible != ashow) {
281 		visible = true;
282 		fullrefresh = false;
283 		RefreshFrame();
284 		visible = ashow;
285 		fullrefresh = false;
286 		RefreshFrame();
287 		if(parent)
288 			StateH(SHOW);
289 		if(top)
290 			WndShow(visible);
291 		if(InFrame() && parent)
292 			RefreshParentLayout();
293 	}
294 }
295 
IsVisible() const296 bool Ctrl::IsVisible() const {
297 	GuiLock __;
298 	const Ctrl *q = this;
299 	for(;;) {
300 		if(!q->visible) return false;
301 		if(!q->parent) break;
302 		q = q->parent;
303 	}
304 	return q->visible;
305 }
306 
Enable(bool aenable)307 void Ctrl::Enable(bool aenable) {
308 	GuiLock __;
309 	if(enabled != aenable) {
310 		enabled = aenable;
311 		if(top) WndEnable(enabled);
312 		if(!enabled && parent && HasFocusDeep())
313 			IterateFocusForward(this, GetTopCtrl());
314 		RefreshFrame();
315 		StateH(ENABLE);
316 		SyncCaret();
317 	}
318 }
319 
IsShowEnabled() const320 bool Ctrl::IsShowEnabled() const {
321 	GuiLock __;
322 	return IsEnabled() && (!parent || parent->IsShowEnabled());
323 }
324 
SetEditable(bool aeditable)325 Ctrl& Ctrl::SetEditable(bool aeditable) {
326 	GuiLock __;
327 	if(editable != aeditable) {
328 		editable = aeditable;
329 		RefreshFrame();
330 		StateH(EDITABLE);
331 	}
332 	return *this;
333 }
334 
SetModify()335 void Ctrl::SetModify()
336 {
337 	GuiLock __;
338 	modify = true;
339 }
340 
ClearModify()341 void Ctrl::ClearModify()
342 {
343 	GuiLock __;
344 	modify = false;
345 }
346 
ClearModifyDeep()347 void Ctrl::ClearModifyDeep()
348 {
349 	GuiLock __;
350 	ClearModify();
351 	for(Ctrl *q = firstchild; q; q = q->next)
352 		q->ClearModify();
353 }
354 
355 
IsModified() const356 bool Ctrl::IsModified() const
357 {
358 	GuiLock __;
359 	return modify;
360 }
361 
IsModifiedDeep() const362 bool Ctrl::IsModifiedDeep() const
363 {
364 	GuiLock __;
365 	if(IsModified()) return true;
366 	for(Ctrl *q = firstchild; q; q = q->next)
367 		if(q->IsModified()) return true;
368 	return false;
369 }
370 
SetCaret(const Rect & r)371 void Ctrl::SetCaret(const Rect& r)
372 {
373 	SetCaret(r.left, r.top, r.GetWidth(), r.GetHeight());
374 }
375 
GetCaret() const376 Rect Ctrl::GetCaret() const
377 {
378 	return RectC(caretx, carety, caretcx, caretcy);
379 }
380 
KillCaret()381 void Ctrl::KillCaret()
382 {
383 	SetCaret(0, 0, 0, 0);
384 }
385 
SetInfoPart(int i,const char * txt)386 void Ctrl::SetInfoPart(int i, const char *txt)
387 {
388 	Vector<String> f = Split(info, '\x7f', false);
389 	f.At(i) = txt;
390 	info = Join(f, "\x7f");
391 }
392 
Tip(const char * txt)393 Ctrl& Ctrl::Tip(const char *txt)
394 {
395 	SetInfoPart(0, txt);
396 	return *this;
397 }
398 
HelpLine(const char * txt)399 Ctrl& Ctrl::HelpLine(const char *txt)
400 {
401 	SetInfoPart(1, txt);
402 	return *this;
403 }
404 
Description(const char * txt)405 Ctrl& Ctrl::Description(const char *txt)
406 {
407 	SetInfoPart(2, txt);
408 	return *this;
409 }
410 
HelpTopic(const char * txt)411 Ctrl& Ctrl::HelpTopic(const char *txt)
412 {
413 	SetInfoPart(3, txt);
414 	return *this;
415 }
416 
LayoutId(const char * txt)417 Ctrl& Ctrl::LayoutId(const char *txt)
418 {
419 	SetInfoPart(4, txt);
420 	return *this;
421 }
422 
GetInfoPart(int i) const423 String Ctrl::GetInfoPart(int i) const
424 {
425 	Vector<String> f = Split(info, '\x7f', false);
426 	return i < f.GetCount() ? f[i] : String();
427 }
428 
GetTip() const429 String Ctrl::GetTip() const
430 {
431 	return GetInfoPart(0);
432 }
433 
GetHelpLine() const434 String Ctrl::GetHelpLine() const
435 {
436 	return GetInfoPart(1);
437 }
438 
GetDescription() const439 String Ctrl::GetDescription() const
440 {
441 	return GetInfoPart(2);
442 }
443 
GetHelpTopic() const444 String Ctrl::GetHelpTopic() const
445 {
446 	return GetInfoPart(3);
447 }
448 
GetLayoutId() const449 String Ctrl::GetLayoutId() const
450 {
451 	return GetInfoPart(4);
452 }
453 
SetWantFocus()454 bool  Ctrl::SetWantFocus() {
455 	GuiLock __;
456 	if(IsWantFocus() && IsEnabled() && IsVisible() && IsOpen())
457 		return SetFocus();
458 	return false;
459 }
460 
UpdateRefresh()461 void Ctrl::UpdateRefresh() {
462 	Update();
463 	Refresh();
464 }
465 
Update()466 void Ctrl::Update() {
467 	SetModify();
468 	Updated();
469 }
470 
Action()471 void Ctrl::Action()
472 {
473 	Event<> h = WhenAction; // we make copy of action just in case widget is destroyed during the call
474 	h();
475 }
476 
UpdateAction()477 void Ctrl::UpdateAction() {
478 	Update();
479 	Action();
480 }
481 
UpdateActionRefresh()482 void Ctrl::UpdateActionRefresh() {
483 	Update();
484 	Action();
485 	Refresh();
486 };
487 
CancelModeDeep()488 void  Ctrl::CancelModeDeep() {
489 	GuiLock __;
490 	CancelMode();
491 	for(Ctrl *q = firstchild; q; q = q->next)
492 		q->CancelModeDeep();
493 }
494 
GetDesc() const495 String Ctrl::GetDesc() const
496 {
497 	return "";
498 }
499 
500 
Name(const Ctrl * ctrl)501 String Name(const Ctrl *ctrl)
502 {
503 	return ctrl ? ctrl->Name() : "NULL";
504 }
505 
Desc(const Ctrl * ctrl)506 String Desc(const Ctrl *ctrl)
507 {
508 	if(!ctrl)
509 		return "NULL";
510 	String s;
511 	s << typeid(*ctrl).name();
512 	String q = ctrl->GetDesc();
513 	if(IsNull(q)) {
514 		if(ctrl->GetPrev()) {
515 			q = ctrl->GetPrev()->GetDesc();
516 			if(!IsNull(q))
517 			  s << " <<\"" << q << "\">>";
518 		}
519 	}
520 	else
521 	  s << " \"" << q << '\"';
522 	const Ctrl *top = ctrl->GetTopWindow();
523 	if(top && top != ctrl) {
524  		String q = top->GetDesc();
525  		if(IsNull(q))
526  			s << " (" << typeid(*top).name() << ")";
527  		else
528 	 		s << " (\"" << q << "\")";
529  	}
530 	return s;
531 }
532 
533 #ifdef _DEBUG
534 
535 #define sFLAG(x)  (x ? #x" " : "")
536 #define LG(x)     s << x << '\n'
537 
Dump(Stream & s) const538 void Ctrl::Dump(Stream& s) const {
539 	GuiLock __;
540 	LG(Name());
541 	LG(sFLAG(backpaint) << sFLAG(inframe) << sFLAG(visible) << sFLAG(enabled) <<
542 	   sFLAG(wantfocus) << sFLAG(editable) << sFLAG(IsModified()) << sFLAG(transparent));
543 	LG("Rect:   " << GetRect());
544 	LG("View:   " << GetView());
545 	for(int i = 0; i < frame.GetCount(); i++)
546 		LG("Frame " << i << ": " << typeid(decltype(*frame[i].frame)).name() << " - " << frame[i].view);
547 	LG("Data: " << GetData().ToString());
548 	if(firstchild) {
549 		LG("Children");
550 		s << LOG_BEGIN;
551 		for(Ctrl *q = GetFirstChild(); q; q = q->GetNext()) {
552 			q->Dump(s);
553 			LG("------");
554 		}
555 		s << LOG_END;
556 	}
557 	else
558 		LG("No child");
559 }
560 
Dump() const561 void Ctrl::Dump() const {
562 	Dump(VppLog());
563 }
564 
Dump(const Ctrl * ctrl)565 void   Dump(const Ctrl *ctrl)
566 {
567 	if(ctrl)
568 		ctrl->Dump();
569 	else
570 		LOG("NULL");
571 }
572 
573 #endif
574 
IsOcxChild()575 bool Ctrl::IsOcxChild()
576 {
577 	return false;
578 }
579 
Ctrl()580 Ctrl::Ctrl() {
581 	ONCELOCK {
582 		InstallPanicBox();
583 	}
584 	ASSERT_(IsMainRunning(), "GUI widgets cannot be global variables");
585 	ASSERT_(ThreadHasGuiLock(), "GUI widgets cannot be initialized in non-main thread without GuiLock");
586 	GuiLock __; // Beware: Even if we have ThreadHasGuiLock ASSERT, we still can be the main thread!
587 	LLOG("Ctrl::Ctrl");
588 	GuiPlatformConstruct();
589 	destroying = false;
590 	parent = prev = next = firstchild = lastchild = NULL;
591 	top = NULL;
592 	exitcode = 0;
593 	frame.Add().frame = &NullFrame();
594 	enabled = visible = wantfocus = initfocus = true;
595 	editable = true;
596 	backpaint = IsCompositedGui() ? FULLBACKPAINT : TRANSPARENTBACKPAINT;
597 	inframe = false;
598 	ignoremouse = transparent = false;
599 	caretcx = caretcy = caretx = carety = 0;
600 	pos.x = PosLeft(0, 0);
601 	pos.y = PosTop(0, 0);
602 	rect = Rect(0, 0, 0, 0);
603 	inloop = popup = isopen = false;
604 	modify = false;
605 	unicode = false;
606 	popupgrab = false;
607 	fullrefresh = false;
608 	akv = false;
609 }
610 
611 void KillTimeCallbacks(void *id, void *idlim);
612 
DoRemove()613 void Ctrl::DoRemove() {
614 	GuiLock __;
615 	if(!IsOpen()) return;
616 	ReleaseCapture();
617 	if(HasChildDeep(captureCtrl))
618 		captureCtrl->ReleaseCapture();
619 	CancelModeDeep();
620 	if(HasChildDeep(mouseCtrl) || mouseCtrl == this)
621 		mouseCtrl = NULL;
622 	LLOG("DoRemove " << Name() << " focusCtrl: " << UPP::Name(focusCtrl));
623 	GuiPlatformRemove();
624 	if(HasFocusDeep()) {
625 		LLOG("DoRemove - HasFocusDeep");
626 		if(destroying) {
627 			if(parent) {
628 				LLOG("parent - deferred SetFocus / ChildLostFocus; parent = " << UPP::Name(parent));
629 				defferedSetFocus = parent;
630 				defferedChildLostFocus.Add(parent);
631 			}
632 			else
633 				if(IsPopUp()) {
634 					LLOG("Remove Popup");
635 					Ctrl *owner = GetOwner();
636 					if(owner && owner->IsEnabled())
637 						owner->ActivateWnd();
638 				}
639 			NoWantFocus();
640 		}
641 		else {
642 			Ptr<Ctrl> fc = focusCtrl;
643 			focusCtrl = NULL;
644 			DoKillFocus(fc, NULL);
645 			if(parent) {
646 				LLOG("DoRemove -> SetFocus(" << UPP::Name(parent) << "), focusCtrl = " << UPP::Name(focusCtrl) << ", fc = " << UPP::Name(fc));
647 				bool b = IsWantFocus();
648 				NoWantFocus();
649 				parent->SetFocus0(false);
650 				WantFocus(b);
651 			}
652 			else
653 				if(IsPopUp()) {
654 					LLOG("Remove Popup");
655 					Ctrl *owner = GetOwner();
656 					if(owner && owner->IsEnabled()) {
657 						LLOG("Remove popup -> owner->ActivateWnd");
658 						owner->ActivateWnd();
659 					}
660 				}
661 		}
662 		SyncCaret();
663 	}
664 	LLOG("//DoRemove " << Name() << " focusCtrl: " << UPP::Name(focusCtrl));
665 }
666 
Close()667 void Ctrl::Close()
668 {
669 	GuiLock __;
670 	Ctrl *q = GetTopCtrl();
671 	if(!q->top) return;
672 	DoRemove();
673 	if(parent) return;
674 	StateH(CLOSE);
675 	USRLOG("   CLOSE " + Desc(this));
676 	WndDestroy();
677 	visible = true;
678 	popup = false;
679 }
680 
~Ctrl()681 Ctrl::~Ctrl() {
682 	GuiLock __;
683 	LLOG("Ctrl::~Ctrl");
684 	destroying = true;
685 	while(GetFirstChild())
686 		RemoveChild(GetFirstChild());
687 	if(parent)
688 		parent->RemoveChild(this);
689 	Close();
690 	KillTimeCallbacks(this, (byte *) this + sizeof(Ctrl));
691 }
692 
mousehook()693 Vector<Ctrl::MouseHook>& Ctrl::mousehook() { static Vector<Ctrl::MouseHook> h; return h; }
keyhook()694 Vector<Ctrl::KeyHook>&   Ctrl::keyhook() { static Vector<Ctrl::KeyHook> h; return h; }
statehook()695 Vector<Ctrl::StateHook>& Ctrl::statehook() { static Vector<Ctrl::StateHook> h; return h; }
696 
InstallMouseHook(MouseHook hook)697 void Ctrl::InstallMouseHook(MouseHook hook)
698 {
699 	GuiLock __;
700 	mousehook().Add(hook);
701 }
702 
DeinstallMouseHook(MouseHook hook)703 void Ctrl::DeinstallMouseHook(MouseHook hook)
704 {
705 	GuiLock __;
706 	int q = FindIndex(mousehook(), hook);
707 	if(q >= 0) mousehook().Remove(q);
708 }
709 
InstallKeyHook(KeyHook hook)710 void Ctrl::InstallKeyHook(KeyHook hook)
711 {
712 	GuiLock __;
713 	keyhook().Add(hook);
714 }
715 
DeinstallKeyHook(KeyHook hook)716 void Ctrl::DeinstallKeyHook(KeyHook hook)
717 {
718 	GuiLock __;
719 	int q = FindIndex(keyhook(), hook);
720 	if(q >= 0) keyhook().Remove(q);
721 }
722 
InstallStateHook(StateHook hook)723 void Ctrl::InstallStateHook(StateHook hook)
724 {
725 	GuiLock __;
726 	statehook().Add(hook);
727 }
728 
DeinstallStateHook(StateHook hook)729 void Ctrl::DeinstallStateHook(StateHook hook)
730 {
731 	GuiLock __;
732 	int q = FindIndex(statehook(), hook);
733 	if(q >= 0) statehook().Remove(q);
734 }
735 
736 static char sZoomText[] = "OK Cancel Exit Retry";
737 
GetZoomText()738 const char *Ctrl::GetZoomText()
739 {
740 	GuiLock __;
741 	return sZoomText;
742 }
743 
744 Size Ctrl::Bsize;
745 Size Ctrl::Dsize;
746 Size Ctrl::Csize;
747 bool Ctrl::IsNoLayoutZoom;
748 
749 /*
750 void InitRichTextZoom()
751 {
752 	SetRichTextStdScreenZoom(96 * GetTextSize(sZoomText, StdFont()).cy / 13, 600);
753 	Ctrl::ReSkin();
754 }
755 */
InitRichTextZoom()756 void InitRichTextZoom()
757 {
758 	Size h = 96 * Ctrl::Bsize / Ctrl::Dsize;
759 	SetRichTextStdScreenZoom(min(h.cx, h.cy), 600);
760 	Ctrl::ReSkin();
761 }
762 
763 
Csizeinit()764 void Ctrl::Csizeinit()
765 {
766 	GuiLock __;
767 	if(Csize.cx == 0 || Dsize.cx == 0) {
768 		bool bigger = GetStdFontCy() > 20;
769 		if(Csize.cx == 0) {
770 			Csize = GetTextSize(sZoomText, StdFont());
771 			Csize.cy += 4 * bigger; // this is intended to compensate for editfield / droplist edges - in any case looks better on UHD
772 		}
773 		Bsize = Csize;
774 		if(Dsize.cx == 0)
775 			Dsize = Size(99, 13 + 4 * bigger);
776 		Csize.cx = max(Csize.cx, Dsize.cx);
777 		Csize.cy = max(Csize.cy, Dsize.cy);
778 		InitRichTextZoom();
779 	}
780 }
781 
SetZoomSize(Size sz,Size bsz)782 void Ctrl::SetZoomSize(Size sz, Size bsz)
783 {
784 	GuiLock __;
785 	Csize = sz;
786 	Dsize = bsz;
787 	IsNoLayoutZoom = false;
788 	ReSkin();
789 }
790 
NoLayoutZoom()791 void Ctrl::NoLayoutZoom()
792 {
793 	GuiLock __;
794 	IsNoLayoutZoom = true;
795 	Csize = Dsize = Size(1, 1);
796 	ReSkin();
797 }
798 
GetZoomRatio(Size & m,Size & d)799 void Ctrl::GetZoomRatio(Size& m, Size& d)
800 {
801 	GuiLock __;
802 	m = Csize;
803 	d = Dsize;
804 }
805 
HorzLayoutZoom(int cx)806 int  Ctrl::HorzLayoutZoom(int cx)
807 {
808 	Csizeinit();
809 	return cx > -16000 ? Csize.cx * cx / Dsize.cx : cx;
810 }
811 
HorzLayoutZoomf(double cx)812 double  Ctrl::HorzLayoutZoomf(double cx)
813 {
814 	Csizeinit();
815 	return cx > -16000 ? Csize.cx * cx / Dsize.cx : cx;
816 }
817 
VertLayoutZoom(int cy)818 int  Ctrl::VertLayoutZoom(int cy)
819 {
820 	Csizeinit();
821 	return cy > -16000 ? Csize.cy * cy / Dsize.cy : cy;
822 }
823 
LayoutZoom(int cx,int cy)824 Size Ctrl::LayoutZoom(int cx, int cy)
825 {
826 	return Size(HorzLayoutZoom(cx), VertLayoutZoom(cy));
827 }
828 
LayoutZoom(Size sz)829 Size Ctrl::LayoutZoom(Size sz)
830 {
831 	return LayoutZoom(sz.cx, sz.cy);
832 }
833 
FontZ(int face,int height)834 Font FontZ(int face, int height)
835 {
836 	return Font(face, Ctrl::VertLayoutZoom(height));
837 }
838 
839 bool ApplicationUHDEnabled = true;
840 
SetUHDEnabled(bool set)841 void Ctrl::SetUHDEnabled(bool set)
842 {
843 	ApplicationUHDEnabled = set;
844 	ReSkin();
845 }
846 
IsUHDEnabled()847 bool Ctrl::IsUHDEnabled()
848 {
849 	if(GetEnv("UPP_DISABLE_UHD__") == "1")
850 		return false;
851 	return ApplicationUHDEnabled;
852 }
853 
854 bool ApplicationDarkThemeEnabled = true;
855 
SetDarkThemeEnabled(bool set)856 void Ctrl::SetDarkThemeEnabled(bool set)
857 {
858 	ApplicationDarkThemeEnabled = set;
859 	ReSkin();
860 }
861 
IsDarkThemeEnabled()862 bool Ctrl::IsDarkThemeEnabled()
863 {
864 	return ApplicationDarkThemeEnabled;
865 }
866 
StdFontZ(int height)867 Font StdFontZ(int height)   { return FontZ(Font::STDFONT, height); }
SansSerifZ(int height)868 Font SansSerifZ(int height) { return FontZ(Font::SANSSERIF, height); }
SerifZ(int height)869 Font SerifZ(int height)     { return FontZ(Font::SERIF, height); }
MonospaceZ(int height)870 Font MonospaceZ(int height) { return FontZ(Font::MONOSPACE, height); }
871 
ScreenSansZ(int height)872 Font ScreenSansZ(int height) { return FontZ(Font::SCREEN_SANS, height); }
ScreenSerifZ(int height)873 Font ScreenSerifZ(int height) { return FontZ(Font::SCREEN_SERIF, height); }
ScreenFixedZ(int height)874 Font ScreenFixedZ(int height) { return FontZ(Font::SCREEN_FIXED, height); }
RomanZ(int height)875 Font RomanZ(int height) { return FontZ(Font::ROMAN, height); }
ArialZ(int height)876 Font ArialZ(int height) { return FontZ(Font::ARIAL, height); }
CourierZ(int height)877 Font CourierZ(int height) { return FontZ(Font::COURIER, height); }
878 
879 String Ctrl::appname;
880 
SetAppName(const String & nm)881 void Ctrl::SetAppName(const String& nm)
882 {
883 	GuiLock __;
884 	appname = nm;
885 }
886 
GetAppName()887 String Ctrl::GetAppName()
888 {
889 	GuiLock __;
890 	if(appname.IsEmpty())
891 		appname = GetExeTitle();
892 	return appname;
893 }
894 
895 static bool _ClickFocus;
ClickFocus()896 bool Ctrl::ClickFocus() { return _ClickFocus; }
ClickFocus(bool cf)897 void Ctrl::ClickFocus(bool cf) { _ClickFocus = cf; }
898 
899 
GetTopWindows()900 Vector<Ctrl *> Ctrl::GetTopWindows()
901 {
902 	GuiLock __;
903 	Vector<Ctrl *> c = GetTopCtrls();
904 	Vector<Ctrl *> r;
905 	for(int i = 0; i < c.GetCount(); i++)
906 		if(!c[i]->IsPopUp())
907 			r.Add(c[i]);
908 	return r;
909 }
910 
CloseTopCtrls()911 void Ctrl::CloseTopCtrls()
912 {
913 	GuiLock __;
914 	Vector<Ctrl *> tc = Ctrl::GetTopCtrls();
915 	for(int i = 0; i < tc.GetCount(); i++)
916 		tc[i]->Close();
917 }
918 
919 bool xpstyle;
920 
IsOrOwnedBy(Ctrl * q,Ctrl * window)921 bool IsOrOwnedBy(Ctrl *q, Ctrl *window)
922 {
923 	while(q) {
924 		if(q == window)
925 			return true;
926 		q = q->GetOwner();
927 	}
928 	return false;
929 }
930 
DisableCtrls(const Vector<Ctrl * > & ctrl,Ctrl * exclude)931 Vector< Ptr<Ctrl> > DisableCtrls(const Vector<Ctrl *>& ctrl, Ctrl *exclude)
932 {
933 	Vector< Ptr<Ctrl> > disabled;
934 	for(int i = 0; i < ctrl.GetCount(); i++) {
935 		Ctrl *q = ctrl[i];
936 		if(q && q->IsEnabled() && !IsOrOwnedBy(q, exclude)) {
937 			q->Disable();
938 			disabled.Add(q);
939 		}
940 	}
941 	return disabled;
942 }
943 
EnableCtrls(const Vector<Ptr<Ctrl>> & ctrl)944 void EnableCtrls(const Vector< Ptr<Ctrl> >& ctrl)
945 {
946 	for(int i = ctrl.GetCount(); --i >= 0;) {
947 		Ctrl *q = ctrl[i];
948 		if(q) q->Enable();
949 	}
950 }
951 
Begin(Ctrl * modal,bool fo)952 void Modality::Begin(Ctrl *modal, bool fo)
953 {
954 	active = Ctrl::GetFocusCtrl();
955 	fore_only = fo;
956 	LLOG("Active " << Name(active));
957 	enable = DisableCtrls(Ctrl::GetTopWindows(), modal);
958 }
959 
End()960 void Modality::End()
961 {
962 	EnableCtrls(enable);
963 	if(active && (!fore_only || active->IsForeground()))
964 		active->SetFocus();
965 	enable.Clear();
966 	active = NULL;
967 }
968 
969 extern void (*whenSetStdFont)();
970 
971 INITBLOCK {
972 	whenSetStdFont = &Ctrl::ReSkin;
973 }
974 
975 void (*Ctrl::skin)();
976 
CtrlSetDefaultSkin(void (* _skin)())977 void CtrlSetDefaultSkin(void (*_skin)())
978 {
979 	Ctrl::skin = _skin;
980 }
981 
SetSkin(void (* _skin)())982 void Ctrl::SetSkin(void (*_skin)())
983 {
984 	GuiLock __;
985 	skin = _skin;
986 	ReSkin();
987 }
988 
ReSkin()989 void Ctrl::ReSkin()
990 {
991 	GuiLock __;
992 	static int lock;
993 	if(lock)
994 		return;
995 	lock++;
996 	ChReset();
997 	Iml::ResetAll();
998 	Csize.cx = Dsize.cx = IsNoLayoutZoom;
999 	if(skin)
1000 		(*skin)();
1001 	Csize.cx = Dsize.cx = IsNoLayoutZoom;
1002 	Csizeinit();
1003 	ChFinish();
1004 	Vector<Ctrl *> ctrl = GetTopCtrls();
1005 	for(int i = 0; i < ctrl.GetCount(); i++) {
1006 		ctrl[i]->RefreshLayoutDeep();
1007 		ctrl[i]->RefreshFrame();
1008 	}
1009 	lock--;
1010 }
1011 
1012 CH_INT(GUI_GlobalStyle, GUISTYLE_CLASSIC);
1013 CH_INT(GUI_DragFullWindow, 1);
1014 CH_INT(GUI_PopUpEffect, GUIEFFECT_SLIDE);
1015 CH_INT(GUI_ToolTips, 1);
1016 CH_INT(GUI_ToolTipDelay, 1000);
1017 CH_INT(GUI_DropShadows, 1);
1018 CH_INT(GUI_AltAccessKeys, 1);
1019 CH_INT(GUI_AKD_Conservative, 0);
1020 CH_INT(GUI_DragDistance, 4);
1021 CH_INT(GUI_DblClickTime, 500);
1022 CH_INT(GUI_WheelScrollLines, 3);
1023 
Name0() const1024 String Ctrl::Name0() const {
1025 	GuiLock __;
1026 	String s = CppDemangle(typeid(*this).name());
1027 	const Ctrl *q = this;
1028 	String path;
1029 	while(q) {
1030 		String id = q->GetLayoutId();
1031 		if(id.GetCount())
1032 			path = '.' + q->GetLayoutId() + path;
1033 		q = q->parent;
1034 	}
1035 	s << ' ' << path;
1036 #ifdef CPU_64
1037 	s << " : 0x" + FormatIntHex(this);
1038 #else
1039 	s << " : " + Format("0x%x", (int) this);
1040 #endif
1041 	if(IsChild())
1042 		s << " (parent " << CppDemangle(typeid(*parent).name()) << ")";
1043 	return s;
1044 }
1045 
Name(Ctrl * ctrl)1046 String Ctrl::Name(Ctrl *ctrl)
1047 {
1048 	return Upp::Name(ctrl);
1049 }
1050 
EndLoop()1051 void   Ctrl::EndLoop()
1052 {
1053 	GuiLock __;
1054 	inloop = false;
1055 	SysEndLoop();
1056 }
1057 
EndLoop(int code)1058 void   Ctrl::EndLoop(int code)
1059 {
1060 	GuiLock __;
1061 	ASSERT(!parent);
1062 	exitcode = code;
1063 	EndLoop();
1064 }
1065 
InLoop() const1066 bool   Ctrl::InLoop() const
1067 {
1068 	GuiLock __;
1069 	return inloop;
1070 }
1071 
InCurrentLoop() const1072 bool   Ctrl::InCurrentLoop() const
1073 {
1074 	GuiLock __;
1075 	return GetLoopCtrl() == this;
1076 }
1077 
GetExitCode() const1078 int    Ctrl::GetExitCode() const
1079 {
1080 	GuiLock __;
1081 	return exitcode;
1082 }
1083 
1084 #ifdef HAS_TopFrameDraw
1085 
ViewDraw(Ctrl * ctrl,const Rect & r)1086 ViewDraw::ViewDraw(Ctrl *ctrl, const Rect& r)
1087 :	TopFrameDraw(ctrl, (ctrl->GetScreenView() & (r + ctrl->GetScreenView().TopLeft()))
1088                        - ctrl->GetTopCtrl()->GetScreenRect().TopLeft())
1089 {
1090 	Point p = r.TopLeft();
1091 	Offset(min(p.x, 0), min(p.y, 0));
1092 }
1093 
1094 #endif
1095 
1096 }
1097