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