mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-15 14:16:07 -06:00
1045 lines
20 KiB
C++
1045 lines
20 KiB
C++
#include "CtrlCore.h"
|
|
|
|
namespace Upp {
|
|
|
|
#define LLOG(x) // DLOG(x)
|
|
|
|
#define IMAGECLASS CtrlCoreImg
|
|
#define IMAGEFILE <CtrlCore/CtrlCore.iml>
|
|
#include <Draw/iml_source.h>
|
|
|
|
static bool StdDisplayErrorFn(const Value& e)
|
|
{
|
|
GuiLock __;
|
|
if(!e.IsError())
|
|
return false;
|
|
String s = GetErrorText(e);
|
|
#ifdef PLATFORM_WIN32
|
|
MessageBox(NULL, s, GetExeTitle(), MB_OK | MB_ICONQUESTION);
|
|
#else
|
|
fputs(String().Cat() << GetExeTitle() << ": " << s << '\n', stderr);
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
bool (*&DisplayErrorFn())(const Value& v)
|
|
{
|
|
static bool (*errfn)(const Value& v) = &StdDisplayErrorFn;
|
|
return errfn;
|
|
}
|
|
|
|
int64 Ctrl::eventid;
|
|
int Ctrl::EventLevel;
|
|
|
|
Ctrl *Ctrl::LoopCtrl;
|
|
int Ctrl::LoopLevel;
|
|
int64 Ctrl::EventLoopNo;
|
|
int64 Ctrl::EndSessionLoopNo;
|
|
|
|
bool Ctrl::MemoryCheck;
|
|
|
|
bool Ctrl::painting = false;
|
|
|
|
void Ctrl::SetData(const Value&) {}
|
|
Value Ctrl::GetData() const { return Value(); }
|
|
|
|
void Ctrl::Paint(Draw& draw) {}
|
|
int Ctrl::OverPaint() const { return 0; }
|
|
|
|
void Ctrl::Activate() {}
|
|
void Ctrl::Deactivate() {}
|
|
void Ctrl::DeactivateBy(Ctrl *) {}
|
|
|
|
void Ctrl::CancelMode() {}
|
|
void Ctrl::MouseEnter(Point p, dword keyflags) {}
|
|
void Ctrl::LeftDown(Point p, dword keyflags) {}
|
|
void Ctrl::RightDown(Point p, dword keyflags) {}
|
|
void Ctrl::LeftRepeat(Point p, dword keyflags) {}
|
|
void Ctrl::RightRepeat(Point p, dword keyflags) {}
|
|
void Ctrl::MouseMove(Point p, dword keyflags) {}
|
|
void Ctrl::LeftUp(Point, dword keyflags) {}
|
|
void Ctrl::RightUp(Point p, dword keyflags) {}
|
|
void Ctrl::MouseLeave() {}
|
|
void Ctrl::LeftDrag(Point p, dword keyflags) {}
|
|
void Ctrl::LeftHold(Point p, dword keyflags) {}
|
|
void Ctrl::RightDrag(Point p, dword keyflags) {}
|
|
void Ctrl::RightHold(Point p, dword keyflags) {}
|
|
void Ctrl::MiddleDown(Point p, dword keyflags) {}
|
|
void Ctrl::MiddleDouble(Point p, dword keyflags) {}
|
|
void Ctrl::MiddleTriple(Point p, dword keyflags) {}
|
|
void Ctrl::MiddleRepeat(Point p, dword keyflags) {}
|
|
void Ctrl::MiddleDrag(Point p, dword keyflags) {}
|
|
void Ctrl::MiddleHold(Point p, dword keyflags) {}
|
|
void Ctrl::MiddleUp(Point p, dword keyflags) {}
|
|
|
|
void Ctrl::Pen(Point p, const PenInfo& pen, dword keyflags) {}
|
|
|
|
void Ctrl::Layout() {}
|
|
|
|
void Ctrl::PostInput()
|
|
{
|
|
GuiLock __;
|
|
Ctrl *parent = GetParent();
|
|
if(parent)
|
|
parent->PostInput();
|
|
}
|
|
|
|
void Ctrl::LeftDouble(Point p, dword keyflags)
|
|
{
|
|
LeftDown(p, keyflags);
|
|
}
|
|
|
|
void Ctrl::LeftTriple(Point p, dword keyflags)
|
|
{
|
|
LeftDown(p, keyflags);
|
|
}
|
|
|
|
void Ctrl::RightDouble(Point p, dword keyflags)
|
|
{
|
|
RightDown(p, keyflags);
|
|
}
|
|
|
|
void Ctrl::RightTriple(Point p, dword keyflags)
|
|
{
|
|
RightDown(p, keyflags);
|
|
}
|
|
|
|
void Ctrl::ChildGotFocus()
|
|
{
|
|
GuiLock __;
|
|
Ctrl *parent = GetParent();
|
|
if(parent)
|
|
parent->ChildGotFocus();
|
|
}
|
|
|
|
void Ctrl::ChildLostFocus()
|
|
{
|
|
GuiLock __;
|
|
Ctrl *parent = GetParent();
|
|
if(parent)
|
|
parent->ChildLostFocus();
|
|
}
|
|
|
|
void Ctrl::ChildAdded(Ctrl *q)
|
|
{
|
|
GuiLock __;
|
|
Ctrl *parent = GetParent();
|
|
if(parent)
|
|
parent->ChildAdded(q);
|
|
}
|
|
|
|
void Ctrl::ChildRemoved(Ctrl *q)
|
|
{
|
|
GuiLock __;
|
|
Ctrl *parent = GetParent();
|
|
if(parent)
|
|
parent->ChildRemoved(q);
|
|
}
|
|
|
|
void Ctrl::ParentChange() {}
|
|
|
|
bool Ctrl::Key(dword key, int count)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
void Ctrl::GotFocus() {}
|
|
void Ctrl::LostFocus() {}
|
|
|
|
dword Ctrl::AccessKeyBit(int accesskey)
|
|
{
|
|
accesskey &= 255;
|
|
if(accesskey >= 'A' && accesskey <= 'Z')
|
|
return (uint64)2 << (accesskey - 'A');
|
|
return !!accesskey;
|
|
}
|
|
|
|
dword Ctrl::GetAccessKeysDeep() const
|
|
{
|
|
GuiLock __;
|
|
dword used = GetAccessKeys();
|
|
for(Ctrl *ctrl = GetFirstChild(); ctrl; ctrl = ctrl->GetNext())
|
|
used |= ctrl->GetAccessKeysDeep();
|
|
return used;
|
|
}
|
|
|
|
void Ctrl::AssignAccessKeys(dword used)
|
|
{
|
|
GuiLock __;
|
|
for(Ctrl *ctrl = GetFirstChild(); ctrl; ctrl = ctrl->GetNext()) {
|
|
ctrl->AssignAccessKeys(used);
|
|
used |= ctrl->GetAccessKeys();
|
|
}
|
|
}
|
|
|
|
dword Ctrl::GetAccessKeys() const
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
void Ctrl::DistributeAccessKeys()
|
|
{
|
|
AssignAccessKeys(GetAccessKeysDeep());
|
|
}
|
|
|
|
bool Ctrl::VisibleAccessKeys()
|
|
{
|
|
GuiLock __;
|
|
if(GUI_AltAccessKeys())
|
|
return GetAlt() && GetTopCtrl() == GetActiveCtrl();
|
|
return true;
|
|
}
|
|
|
|
void Ctrl::State(int) {}
|
|
|
|
void Ctrl::StateDeep(int reason)
|
|
{
|
|
GuiLock __;
|
|
if(destroying)
|
|
return;
|
|
for(Ctrl *q = GetFirstChild(); q; q = q->GetNext())
|
|
q->StateDeep(reason);
|
|
State(reason);
|
|
}
|
|
|
|
void Ctrl::StateH(int reason)
|
|
{
|
|
GuiLock __;
|
|
for(int i = 0; i < statehook().GetCount(); i++)
|
|
if((*statehook()[i])(this, reason))
|
|
return;
|
|
StateDeep(reason);
|
|
}
|
|
|
|
bool Ctrl::Accept()
|
|
{
|
|
GuiLock __;
|
|
if(!IsEnabled() || !IsShown())
|
|
return true;
|
|
if(DisplayError(GetData())) {
|
|
SetWantFocus();
|
|
return false;
|
|
}
|
|
for(Ctrl *q = GetFirstChild(); q; q = q->GetNext())
|
|
if(!q->Accept()) return false;
|
|
return true;
|
|
}
|
|
|
|
void Ctrl::Reject()
|
|
{
|
|
GuiLock __;
|
|
for(Ctrl *q = GetFirstChild(); q; q = q->GetNext())
|
|
q->Reject();
|
|
}
|
|
|
|
void Ctrl::Serialize(Stream& s)
|
|
{
|
|
GuiLock __;
|
|
Value x;
|
|
if(s.IsStoring())
|
|
x = GetData();
|
|
s % x;
|
|
if(s.IsLoading())
|
|
SetData(x);
|
|
for(Ctrl *q = GetFirstChild(); q; q = q->GetNext())
|
|
q->Serialize(s);
|
|
}
|
|
|
|
void Ctrl::Jsonize(JsonIO& jio)
|
|
{
|
|
GuiLock __;
|
|
Value x;
|
|
if(jio.IsStoring())
|
|
x = GetData();
|
|
x.Jsonize(jio);
|
|
if(jio.IsLoading())
|
|
SetData(x);
|
|
}
|
|
|
|
void Ctrl::Xmlize(XmlIO& xio)
|
|
{
|
|
GuiLock __;
|
|
Value x;
|
|
if(xio.IsStoring())
|
|
x = GetData();
|
|
x.Xmlize(xio);
|
|
if(xio.IsLoading())
|
|
SetData(x);
|
|
}
|
|
|
|
void Ctrl::Updated() {}
|
|
|
|
bool Ctrl::IsForeground() const
|
|
{
|
|
GuiLock __;
|
|
return GetTopCtrl()->IsWndForeground();
|
|
}
|
|
|
|
void Ctrl::SetForeground()
|
|
{
|
|
GuiLock __;
|
|
GetTopCtrl()->SetWndForeground();
|
|
}
|
|
|
|
bool Ctrl::IsOpen() const
|
|
{
|
|
GuiLock __;
|
|
const Ctrl *q = GetTopCtrl();
|
|
return q->isopen && q->IsWndOpen();
|
|
}
|
|
|
|
void Ctrl::Show(bool ashow) {
|
|
GuiLock __;
|
|
if(visible != ashow) {
|
|
visible = true;
|
|
fullrefresh = false;
|
|
RefreshFrame();
|
|
visible = ashow;
|
|
fullrefresh = false;
|
|
RefreshFrame();
|
|
Ctrl *parent = GetParent();
|
|
if(parent)
|
|
StateH(SHOW);
|
|
if(top)
|
|
WndShow(visible);
|
|
if(InFrame() && parent)
|
|
RefreshParentLayout();
|
|
}
|
|
}
|
|
|
|
bool Ctrl::IsVisible() const {
|
|
GuiLock __;
|
|
const Ctrl *q = this;
|
|
for(;;) {
|
|
if(!q->visible) return false;
|
|
Ctrl *p = q->GetParent();
|
|
if(!p) break;
|
|
q = p;
|
|
}
|
|
return q->visible;
|
|
}
|
|
|
|
void Ctrl::Enable(bool aenable) {
|
|
GuiLock __;
|
|
if(enabled != aenable) {
|
|
enabled = aenable;
|
|
if(top) WndEnable(enabled);
|
|
if(!enabled && GetParent() && HasFocusDeep())
|
|
IterateFocusForward(this, GetTopCtrl());
|
|
RefreshFrame();
|
|
StateH(ENABLE);
|
|
SyncCaret();
|
|
}
|
|
}
|
|
|
|
bool Ctrl::IsShowEnabled() const {
|
|
GuiLock __;
|
|
Ctrl *parent = GetParent();
|
|
return IsEnabled() && (!parent || parent->IsShowEnabled());
|
|
}
|
|
|
|
Ctrl& Ctrl::SetEditable(bool aeditable) {
|
|
GuiLock __;
|
|
if(editable != aeditable) {
|
|
editable = aeditable;
|
|
RefreshFrame();
|
|
StateH(EDITABLE);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
void Ctrl::SetModify()
|
|
{
|
|
GuiLock __;
|
|
modify = true;
|
|
CancelMyPreedit();
|
|
}
|
|
|
|
void Ctrl::ClearModify()
|
|
{
|
|
GuiLock __;
|
|
modify = false;
|
|
CancelMyPreedit();
|
|
}
|
|
|
|
void Ctrl::ClearModifyDeep()
|
|
{
|
|
GuiLock __;
|
|
ClearModify();
|
|
for(Ctrl& q : *this)
|
|
q.ClearModifyDeep();
|
|
}
|
|
|
|
|
|
bool Ctrl::IsModified() const
|
|
{
|
|
GuiLock __;
|
|
return modify;
|
|
}
|
|
|
|
bool Ctrl::IsModifiedDeep() const
|
|
{
|
|
GuiLock __;
|
|
if(IsModified()) return true;
|
|
for(const Ctrl& q : *this)
|
|
if(q.IsModified()) return true;
|
|
return false;
|
|
}
|
|
|
|
Rect Ctrl::GetCaret() const
|
|
{
|
|
return Null;
|
|
}
|
|
|
|
bool Ctrl::SetWantFocus() {
|
|
GuiLock __;
|
|
if(IsWantFocus() && IsEnabled() && IsVisible() && IsOpen())
|
|
return SetFocus();
|
|
return false;
|
|
}
|
|
|
|
void Ctrl::UpdateRefresh() {
|
|
Update();
|
|
Refresh();
|
|
}
|
|
|
|
void Ctrl::Update() {
|
|
SetModify();
|
|
Updated();
|
|
}
|
|
|
|
void Ctrl::Action()
|
|
{
|
|
Event<> h = WhenAction; // we make copy of action just in case widget is destroyed during the call
|
|
h();
|
|
}
|
|
|
|
void Ctrl::UpdateAction() {
|
|
Update();
|
|
Action();
|
|
}
|
|
|
|
void Ctrl::UpdateActionRefresh() {
|
|
Update();
|
|
Action();
|
|
Refresh();
|
|
};
|
|
|
|
void Ctrl::CancelModeDeep() {
|
|
GuiLock __;
|
|
CancelMode();
|
|
for(Ctrl& q : *this)
|
|
q.CancelModeDeep();
|
|
}
|
|
|
|
String Ctrl::GetDesc() const
|
|
{
|
|
return "";
|
|
}
|
|
|
|
|
|
String Name(const Ctrl *ctrl)
|
|
{
|
|
return ctrl ? ctrl->Name() : "NULL";
|
|
}
|
|
|
|
String Desc(const Ctrl *ctrl)
|
|
{
|
|
if(!ctrl)
|
|
return "NULL";
|
|
String s;
|
|
s << typeid(*ctrl).name();
|
|
String q = ctrl->GetDesc();
|
|
if(IsNull(q)) {
|
|
if(ctrl->GetPrev()) {
|
|
q = ctrl->GetPrev()->GetDesc();
|
|
if(!IsNull(q))
|
|
s << " <<\"" << q << "\">>";
|
|
}
|
|
}
|
|
else
|
|
s << " \"" << q << '\"';
|
|
const Ctrl *top = ctrl->GetTopWindow();
|
|
if(top && top != ctrl) {
|
|
String q = top->GetDesc();
|
|
if(IsNull(q))
|
|
s << " (" << typeid(*top).name() << ")";
|
|
else
|
|
s << " (\"" << q << "\")";
|
|
}
|
|
return s;
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
|
|
#define sFLAG(x) (x ? #x" " : "")
|
|
#define LG(x) s << x << '\n'
|
|
|
|
void Ctrl::Dump(Stream& s) const {
|
|
GuiLock __;
|
|
LG(Name());
|
|
LG(sFLAG(backpaint) << sFLAG(inframe) << sFLAG(visible) << sFLAG(enabled) <<
|
|
sFLAG(wantfocus) << sFLAG(editable) << sFLAG(IsModified()) << sFLAG(transparent));
|
|
LG("Rect: " << GetRect());
|
|
LG("View: " << GetView());
|
|
for(int i = 0; i < GetFrameCount(); i++)
|
|
LG("Frame " << i << ": " << typeid(decltype(*GetFrame0(i).frame)).name() << " - " << GetFrame0(i).GetView());
|
|
LG("Data: " << GetData().ToString());
|
|
if(children) {
|
|
LG("Children");
|
|
s << LOG_BEGIN;
|
|
for(const Ctrl& q : *this) {
|
|
q.Dump(s);
|
|
LG("------");
|
|
}
|
|
s << LOG_END;
|
|
}
|
|
else
|
|
LG("No child");
|
|
}
|
|
|
|
void Ctrl::Dump() const {
|
|
Dump(VppLog());
|
|
}
|
|
|
|
void Dump(const Ctrl *ctrl)
|
|
{
|
|
if(ctrl)
|
|
ctrl->Dump();
|
|
else
|
|
LOG("NULL");
|
|
}
|
|
|
|
void Ctrl::SetTitle(const char *s)
|
|
{
|
|
TopWindow *w = GetTopWindow();
|
|
if(w) w->Title(s);
|
|
}
|
|
|
|
#endif
|
|
|
|
bool Ctrl::IsOcxChild()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
Ctrl::Ctrl() {
|
|
ONCELOCK {
|
|
InstallPanicBox();
|
|
}
|
|
ASSERT_(IsMainRunning(), "GUI widgets cannot be global variables");
|
|
ASSERT_(ThreadHasGuiLock(), "GUI widgets cannot be initialized in non-main thread without GuiLock");
|
|
GuiLock __; // Beware: Even if we have ThreadHasGuiLock ASSERT, we still can be the main thread!
|
|
LLOG("Ctrl::Ctrl");
|
|
GuiPlatformConstruct();
|
|
destroying = false;
|
|
multi_frame = false;
|
|
frame.frame = &NullFrame();
|
|
frame.SetView(Null);
|
|
enabled = visible = wantfocus = initfocus = true;
|
|
editable = true;
|
|
backpaint = IsCompositedGui() ? FULLBACKPAINT : TRANSPARENTBACKPAINT;
|
|
inframe = false;
|
|
ignoremouse = transparent = false;
|
|
pos.x = PosLeft(0, 0);
|
|
pos.y = PosTop(0, 0);
|
|
rect = Rect(0, 0, 0, 0);
|
|
inloop = popup = isopen = false;
|
|
modify = false;
|
|
unicode = false;
|
|
popupgrab = false;
|
|
fullrefresh = false;
|
|
akv = false;
|
|
layout_id_literal = false;
|
|
top = false;
|
|
uparent = nullptr;
|
|
megarect = false;
|
|
}
|
|
|
|
void KillTimeCallbacks(void *id, void *idlim);
|
|
|
|
void Ctrl::DoRemove() {
|
|
GuiLock __;
|
|
if(!IsOpen()) return;
|
|
ReleaseCapture();
|
|
if(HasChildDeep(captureCtrl))
|
|
captureCtrl->ReleaseCapture();
|
|
CancelModeDeep();
|
|
if(HasChildDeep(mouseCtrl) || mouseCtrl == this)
|
|
mouseCtrl = NULL;
|
|
LLOG("DoRemove " << Name() << " focusCtrl: " << UPP::Name(focusCtrl));
|
|
GuiPlatformRemove();
|
|
Ctrl *parent = GetParent();
|
|
if(HasFocusDeep()) {
|
|
LLOG("DoRemove - HasFocusDeep");
|
|
if(destroying) {
|
|
if(parent) {
|
|
LLOG("parent - deferred SetFocus / ChildLostFocus; parent = " << UPP::Name(parent));
|
|
defferedSetFocus = parent;
|
|
defferedChildLostFocus.Add(parent);
|
|
}
|
|
else
|
|
if(IsPopUp()) {
|
|
LLOG("Remove Popup");
|
|
Ctrl *owner = GetOwner();
|
|
if(owner && owner->IsEnabled())
|
|
owner->ActivateWnd();
|
|
}
|
|
NoWantFocus();
|
|
}
|
|
else {
|
|
Ptr<Ctrl> fc = focusCtrl;
|
|
focusCtrl = NULL;
|
|
DoKillFocus(fc, NULL);
|
|
if(parent) {
|
|
LLOG("DoRemove -> SetFocus(" << UPP::Name(parent) << "), focusCtrl = " << UPP::Name(focusCtrl) << ", fc = " << UPP::Name(fc));
|
|
bool b = IsWantFocus();
|
|
NoWantFocus();
|
|
parent->SetFocus0(false);
|
|
WantFocus(b);
|
|
}
|
|
else
|
|
if(IsPopUp()) {
|
|
LLOG("Remove Popup");
|
|
Ctrl *owner = GetOwner();
|
|
if(owner && owner->IsEnabled()) {
|
|
LLOG("Remove popup -> owner->ActivateWnd");
|
|
owner->ActivateWnd();
|
|
}
|
|
}
|
|
}
|
|
SyncCaret();
|
|
}
|
|
LLOG("//DoRemove " << Name() << " focusCtrl: " << UPP::Name(focusCtrl));
|
|
}
|
|
|
|
void Ctrl::Close()
|
|
{
|
|
GuiLock __;
|
|
Ctrl *q = GetTopCtrl();
|
|
if(!q->top) return;
|
|
DoRemove();
|
|
if(GetParent()) return;
|
|
StateH(CLOSE);
|
|
USRLOG(" CLOSE " + Desc(this));
|
|
WndDestroy();
|
|
visible = true;
|
|
popup = false;
|
|
}
|
|
|
|
Ctrl::~Ctrl() {
|
|
GuiLock __;
|
|
LLOG("Ctrl::~Ctrl");
|
|
destroying = true;
|
|
while(GetFirstChild())
|
|
RemoveChild(GetFirstChild());
|
|
Ctrl *parent = GetParent();
|
|
if(parent)
|
|
parent->RemoveChild(this);
|
|
Close();
|
|
KillTimeCallbacks(this, (byte *) this + sizeof(Ctrl));
|
|
ClearInfo();
|
|
FreeFrames();
|
|
}
|
|
|
|
Vector<Ctrl::MouseHook>& Ctrl::mousehook() { static Vector<Ctrl::MouseHook> h; return h; }
|
|
Vector<Ctrl::KeyHook>& Ctrl::keyhook() { static Vector<Ctrl::KeyHook> h; return h; }
|
|
Vector<Ctrl::StateHook>& Ctrl::statehook() { static Vector<Ctrl::StateHook> h; return h; }
|
|
|
|
void Ctrl::InstallMouseHook(MouseHook hook)
|
|
{
|
|
GuiLock __;
|
|
mousehook().Add(hook);
|
|
}
|
|
|
|
void Ctrl::DeinstallMouseHook(MouseHook hook)
|
|
{
|
|
GuiLock __;
|
|
int q = FindIndex(mousehook(), hook);
|
|
if(q >= 0) mousehook().Remove(q);
|
|
}
|
|
|
|
void Ctrl::InstallKeyHook(KeyHook hook)
|
|
{
|
|
GuiLock __;
|
|
keyhook().Add(hook);
|
|
}
|
|
|
|
void Ctrl::DeinstallKeyHook(KeyHook hook)
|
|
{
|
|
GuiLock __;
|
|
int q = FindIndex(keyhook(), hook);
|
|
if(q >= 0) keyhook().Remove(q);
|
|
}
|
|
|
|
void Ctrl::InstallStateHook(StateHook hook)
|
|
{
|
|
GuiLock __;
|
|
statehook().Add(hook);
|
|
}
|
|
|
|
void Ctrl::DeinstallStateHook(StateHook hook)
|
|
{
|
|
GuiLock __;
|
|
int q = FindIndex(statehook(), hook);
|
|
if(q >= 0) statehook().Remove(q);
|
|
}
|
|
|
|
static char sZoomText[] = "OK Cancel Exit Retry";
|
|
|
|
const char *Ctrl::GetZoomText()
|
|
{
|
|
GuiLock __;
|
|
return sZoomText;
|
|
}
|
|
|
|
Size Ctrl::Bsize;
|
|
Size Ctrl::Dsize;
|
|
Size Ctrl::Csize;
|
|
bool Ctrl::IsNoLayoutZoom;
|
|
|
|
/*
|
|
void InitRichTextZoom()
|
|
{
|
|
SetRichTextStdScreenZoom(96 * GetTextSize(sZoomText, StdFont()).cy / 13, 600);
|
|
Ctrl::ReSkin();
|
|
}
|
|
*/
|
|
void InitRichTextZoom()
|
|
{
|
|
Size h = 96 * Ctrl::Bsize / Ctrl::Dsize;
|
|
SetRichTextStdScreenZoom(min(h.cx, h.cy), 600);
|
|
Ctrl::ReSkin();
|
|
}
|
|
|
|
|
|
void Ctrl::Csizeinit()
|
|
{
|
|
GuiLock __;
|
|
if(Csize.cx == 0 || Dsize.cx == 0) {
|
|
bool bigger = GetStdFontCy() > 20;
|
|
if(Csize.cx == 0) {
|
|
Csize = GetTextSize(sZoomText, StdFont());
|
|
Csize.cy += 4 * bigger; // this is intended to compensate for editfield / droplist edges - in any case looks better on UHD
|
|
}
|
|
Bsize = Csize;
|
|
if(Dsize.cx == 0)
|
|
Dsize = Size(99, 13 + 4 * bigger);
|
|
Csize.cx = max(Csize.cx, Dsize.cx);
|
|
Csize.cy = max(Csize.cy, Dsize.cy);
|
|
InitRichTextZoom();
|
|
}
|
|
}
|
|
|
|
void Ctrl::SetZoomSize(Size sz, Size bsz)
|
|
{
|
|
GuiLock __;
|
|
Csize = sz;
|
|
Dsize = bsz;
|
|
IsNoLayoutZoom = false;
|
|
ReSkin();
|
|
}
|
|
|
|
void Ctrl::NoLayoutZoom()
|
|
{
|
|
GuiLock __;
|
|
IsNoLayoutZoom = true;
|
|
Csize = Dsize = Size(1, 1);
|
|
ReSkin();
|
|
}
|
|
|
|
void Ctrl::GetZoomRatio(Size& m, Size& d)
|
|
{
|
|
GuiLock __;
|
|
m = Csize;
|
|
d = Dsize;
|
|
}
|
|
|
|
int Ctrl::HorzLayoutZoom(int cx)
|
|
{
|
|
Csizeinit();
|
|
return cx > -16000 ? Csize.cx * cx / Dsize.cx : cx;
|
|
}
|
|
|
|
double Ctrl::HorzLayoutZoomf(double cx)
|
|
{
|
|
Csizeinit();
|
|
return cx > -16000 ? Csize.cx * cx / Dsize.cx : cx;
|
|
}
|
|
|
|
int Ctrl::VertLayoutZoom(int cy)
|
|
{
|
|
Csizeinit();
|
|
return cy > -16000 ? Csize.cy * cy / Dsize.cy : cy;
|
|
}
|
|
|
|
Size Ctrl::LayoutZoom(int cx, int cy)
|
|
{
|
|
return Size(HorzLayoutZoom(cx), VertLayoutZoom(cy));
|
|
}
|
|
|
|
Size Ctrl::LayoutZoom(Size sz)
|
|
{
|
|
return LayoutZoom(sz.cx, sz.cy);
|
|
}
|
|
|
|
Font FontZ(int face, int height)
|
|
{
|
|
return Font(face, Ctrl::VertLayoutZoom(height));
|
|
}
|
|
|
|
bool ApplicationUHDEnabled = true;
|
|
|
|
void Ctrl::SetUHDEnabled(bool set)
|
|
{
|
|
ApplicationUHDEnabled = set;
|
|
ReSkin();
|
|
}
|
|
|
|
bool Ctrl::IsUHDEnabled()
|
|
{
|
|
if(GetEnv("UPP_DISABLE_UHD__") == "1")
|
|
return false;
|
|
return ApplicationUHDEnabled;
|
|
}
|
|
|
|
bool ApplicationDarkThemeEnabled = true;
|
|
|
|
void Ctrl::SetDarkThemeEnabled(bool set)
|
|
{
|
|
ApplicationDarkThemeEnabled = set;
|
|
ReSkin();
|
|
}
|
|
|
|
bool Ctrl::IsDarkThemeEnabled()
|
|
{
|
|
return ApplicationDarkThemeEnabled;
|
|
}
|
|
|
|
Font StdFontZ(int height) { return FontZ(Font::STDFONT, height); }
|
|
Font SansSerifZ(int height) { return FontZ(Font::SANSSERIF, height); }
|
|
Font SerifZ(int height) { return FontZ(Font::SERIF, height); }
|
|
Font MonospaceZ(int height) { return FontZ(Font::MONOSPACE, height); }
|
|
|
|
Font ScreenSansZ(int height) { return FontZ(Font::SCREEN_SANS, height); }
|
|
Font ScreenSerifZ(int height) { return FontZ(Font::SCREEN_SERIF, height); }
|
|
Font ScreenFixedZ(int height) { return FontZ(Font::SCREEN_FIXED, height); }
|
|
Font RomanZ(int height) { return FontZ(Font::ROMAN, height); }
|
|
Font ArialZ(int height) { return FontZ(Font::ARIAL, height); }
|
|
Font CourierZ(int height) { return FontZ(Font::COURIER, height); }
|
|
|
|
String Ctrl::appname;
|
|
|
|
void Ctrl::SetAppName(const String& nm)
|
|
{
|
|
GuiLock __;
|
|
appname = nm;
|
|
}
|
|
|
|
String Ctrl::GetAppName()
|
|
{
|
|
GuiLock __;
|
|
if(appname.IsEmpty())
|
|
appname = GetExeTitle();
|
|
return appname;
|
|
}
|
|
|
|
static bool _ClickFocus;
|
|
bool Ctrl::ClickFocus() { return _ClickFocus; }
|
|
void Ctrl::ClickFocus(bool cf) { _ClickFocus = cf; }
|
|
|
|
|
|
Vector<Ctrl *> Ctrl::GetTopWindows()
|
|
{
|
|
GuiLock __;
|
|
Vector<Ctrl *> c = GetTopCtrls();
|
|
Vector<Ctrl *> r;
|
|
for(int i = 0; i < c.GetCount(); i++)
|
|
if(!c[i]->IsPopUp())
|
|
r.Add(c[i]);
|
|
return r;
|
|
}
|
|
|
|
void Ctrl::CloseTopCtrls()
|
|
{
|
|
GuiLock __;
|
|
Vector<Ctrl *> tc = Ctrl::GetTopCtrls();
|
|
for(int i = 0; i < tc.GetCount(); i++)
|
|
tc[i]->Close();
|
|
}
|
|
|
|
bool xpstyle;
|
|
|
|
bool IsOrOwnedBy(Ctrl *q, Ctrl *window)
|
|
{
|
|
while(q) {
|
|
if(q == window)
|
|
return true;
|
|
q = q->GetOwner();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
Vector< Ptr<Ctrl> > DisableCtrls(const Vector<Ctrl *>& ctrl, Ctrl *exclude)
|
|
{
|
|
Vector< Ptr<Ctrl> > disabled;
|
|
for(int i = 0; i < ctrl.GetCount(); i++) {
|
|
Ctrl *q = ctrl[i];
|
|
if(q && q->IsEnabled() && !IsOrOwnedBy(q, exclude)) {
|
|
q->Disable();
|
|
disabled.Add(q);
|
|
}
|
|
}
|
|
return disabled;
|
|
}
|
|
|
|
void EnableCtrls(const Vector< Ptr<Ctrl> >& ctrl)
|
|
{
|
|
for(int i = ctrl.GetCount(); --i >= 0;) {
|
|
Ctrl *q = ctrl[i];
|
|
if(q) q->Enable();
|
|
}
|
|
}
|
|
|
|
void Modality::Begin(Ctrl *modal, bool fo)
|
|
{
|
|
active = Ctrl::GetFocusCtrl();
|
|
fore_only = fo;
|
|
LLOG("Active " << Name(active));
|
|
enable = DisableCtrls(Ctrl::GetTopWindows(), modal);
|
|
}
|
|
|
|
void Modality::End()
|
|
{
|
|
EnableCtrls(enable);
|
|
if(active && (!fore_only || active->IsForeground()))
|
|
active->SetFocus();
|
|
enable.Clear();
|
|
active = NULL;
|
|
}
|
|
|
|
extern void (*whenSetStdFont)();
|
|
|
|
INITBLOCK {
|
|
whenSetStdFont = &Ctrl::ReSkin;
|
|
}
|
|
|
|
void (*Ctrl::skin)();
|
|
|
|
void CtrlSetDefaultSkin(void (*_skin)())
|
|
{
|
|
Ctrl::skin = _skin;
|
|
}
|
|
|
|
void Ctrl::SetSkin(void (*_skin)())
|
|
{
|
|
GuiLock __;
|
|
skin = _skin;
|
|
ReSkin();
|
|
}
|
|
|
|
void Ctrl::ReSkin()
|
|
{
|
|
GuiLock __;
|
|
static int lock;
|
|
if(lock)
|
|
return;
|
|
lock++;
|
|
ChReset();
|
|
Iml::ResetAll();
|
|
Csize.cx = Dsize.cx = IsNoLayoutZoom;
|
|
if(skin)
|
|
(*skin)();
|
|
Csize.cx = Dsize.cx = IsNoLayoutZoom;
|
|
Csizeinit();
|
|
ChFinish();
|
|
Vector<Ctrl *> ctrl = GetTopCtrls();
|
|
for(int i = 0; i < ctrl.GetCount(); i++) {
|
|
ctrl[i]->RefreshLayoutDeep();
|
|
ctrl[i]->RefreshFrame();
|
|
}
|
|
lock--;
|
|
}
|
|
|
|
CH_INT(GUI_GlobalStyle, GUISTYLE_CLASSIC);
|
|
CH_INT(GUI_DragFullWindow, 1);
|
|
CH_INT(GUI_PopUpEffect, GUIEFFECT_SLIDE);
|
|
CH_INT(GUI_ToolTips, 1);
|
|
CH_INT(GUI_ToolTipDelay, 1000);
|
|
CH_INT(GUI_DropShadows, 1);
|
|
CH_INT(GUI_AltAccessKeys, 1);
|
|
CH_INT(GUI_AKD_Conservative, 0);
|
|
CH_INT(GUI_DragDistance, 4);
|
|
CH_INT(GUI_DblClickTime, 500);
|
|
CH_INT(GUI_WheelScrollLines, 3);
|
|
|
|
String Ctrl::Name0() const {
|
|
GuiLock __;
|
|
String s = CppDemangle(typeid(*this).name());
|
|
const Ctrl *q = this;
|
|
String path;
|
|
while(q) {
|
|
String id = q->GetLayoutId();
|
|
if(id.GetCount())
|
|
path = '.' + q->GetLayoutId() + path;
|
|
q = q->GetParent();
|
|
}
|
|
s << ' ' << path;
|
|
#ifdef CPU_64
|
|
s << " : 0x" + FormatIntHex(this);
|
|
#else
|
|
s << " : " + Format("0x%x", (int) this);
|
|
#endif
|
|
Ctrl *parent = GetParent();
|
|
if(IsChild())
|
|
s << " (parent " << CppDemangle(typeid(*parent).name()) << ")";
|
|
return s;
|
|
}
|
|
|
|
String Ctrl::Name(Ctrl *ctrl)
|
|
{
|
|
return Upp::Name(ctrl);
|
|
}
|
|
|
|
void Ctrl::EndLoop()
|
|
{
|
|
GuiLock __;
|
|
inloop = false;
|
|
SysEndLoop();
|
|
}
|
|
|
|
void Ctrl::EndLoop(int code)
|
|
{
|
|
GuiLock __;
|
|
ASSERT(!GetParent());
|
|
TopWindow *w = GetTopWindow();
|
|
if(w)
|
|
w->exitcode = code;
|
|
EndLoop();
|
|
}
|
|
|
|
bool Ctrl::InLoop() const
|
|
{
|
|
GuiLock __;
|
|
return inloop;
|
|
}
|
|
|
|
bool Ctrl::InCurrentLoop() const
|
|
{
|
|
GuiLock __;
|
|
return GetLoopCtrl() == this;
|
|
}
|
|
|
|
#ifdef HAS_TopFrameDraw
|
|
|
|
ViewDraw::ViewDraw(Ctrl *ctrl, const Rect& r)
|
|
: TopFrameDraw(ctrl, (ctrl->GetScreenView() & (r + ctrl->GetScreenView().TopLeft()))
|
|
- ctrl->GetTopCtrl()->GetScreenRect().TopLeft())
|
|
{
|
|
Point p = r.TopLeft();
|
|
Offset(min(p.x, 0), min(p.y, 0));
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|