ultimatepp/uppsrc/CtrlCore/CtrlPos.cpp
2024-10-03 02:03:27 +02:00

481 lines
9.6 KiB
C++

#include "CtrlCore.h"
namespace Upp {
#define LLOG(x) // DLOG(x)
#define LTIMING(x) // RTIMING(x)
void Ctrl::LogPosSet(LogPos p)
{
if(p.CanPack()) {
packed_pos = p;
}
else {
packed_pos.x.a = 16001;
SetLogPosAttr(Ctrl::ATTR_LOGPOS, p);
}
}
Ctrl::LogPos Ctrl::GetPos() const
{
if(packed_pos.x.a == 16001)
return GetLogPosAttr(Ctrl::ATTR_LOGPOS);
return packed_pos;
}
void Ctrl::RectSet(const Rect& r)
{
auto CanPack = [](int a) { return a >= -32000 && a <= 32000; };
if(CanPack(r.left) && CanPack(r.right) && CanPack(r.top) && CanPack(r.bottom))
packed_rect = r;
else {
SetRectAttr(Ctrl::ATTR_RECT, r);
packed_rect.left = 32001;
}
}
Rect Ctrl::GetRect() const
{
if(packed_rect.left == 32001)
return GetRectAttr(Ctrl::ATTR_RECT);
return packed_rect;
}
Size Ctrl::PosVal(int v) const {
switch(v) {
case MINSIZE: return GetMinSize();
case STDSIZE: return GetStdSize();
case MAXSIZE: return GetMaxSize();
}
return Size(v, v);
}
void Ctrl::Lay1(int& pos, int& r, int align, int a, int b, int sz) const
{
pos = a;
int size = b;
switch(align) {
case CENTER:
pos = (sz - b) / 2 + a;
break;
case RIGHT:
pos = sz - (a + b);
break;
case SIZE:
size = sz - (a + b);
break;
}
r = pos + max(size, 0);
}
Rect Ctrl::CalcRect(LogPos pos, const Rect& prect, const Rect& pview) const
{
Rect r;
Size sz = InFrame() ? prect.Size() : pview.Size();
Lay1(r.left, r.right, pos.x.GetAlign(),
PosVal(pos.x.GetA()).cx, PosVal(pos.x.GetB()).cx, sz.cx);
Lay1(r.top, r.bottom, pos.y.GetAlign(),
PosVal(pos.y.GetA()).cy, PosVal(pos.y.GetB()).cy, sz.cy);
return r;
}
Rect Ctrl::CalcRect(const Rect& prect, const Rect& pview) const
{
return CalcRect(GetPos(), prect, pview);
}
Rect Ctrl::GetView() const
{
GuiLock __;
int n = GetFrameCount();
Rect vr = GetRect().Size();
return n == 0 ? vr : GetFrame0(n - 1).GetView();
}
Size Ctrl::GetSize() const
{
return GetView().GetSize();
}
Rect Ctrl::GetScreenRect() const
{
GuiLock __;
Rect r = GetRect();
Ctrl *parent = GetParent();
if(parent) {
Rect pr = inframe ? parent->GetScreenRect() : parent->GetScreenView();
r = r + pr.TopLeft();
}
else
GuiPlatformGetTopRect(r);
return r;
}
Rect Ctrl::GetScreenView() const
{
Rect r = GetScreenRect();
return GetView() + r.TopLeft();
}
Rect Ctrl::GetVisibleScreenRect() const
{
GuiLock __;
Rect r = GetRect();
Ctrl *parent = GetParent();
if(parent) {
Rect pr = inframe ? parent->GetVisibleScreenRect() : parent->GetVisibleScreenView();
Rect pr1 = inframe ? parent->GetScreenRect() : parent->GetScreenView();
r = (r + pr1.TopLeft()) & pr;
}
else
GuiPlatformGetTopRect(r);
return r & GetVirtualScreenArea();
}
Rect Ctrl::GetVisibleScreenView() const
{
Rect r = GetVisibleScreenRect();
return (GetView() + r.TopLeft()) & r;
}
Size Ctrl::AddFrameSize(int cx, int cy) const
{
GuiLock __;
Size sz = Size(cx, cy);
for(int i = GetFrameCount() - 1; i >= 0; i--)
GetFrame0(i).frame->FrameAddSize(sz);
return sz;
}
int EditFieldIsThin();
Size Ctrl::GetMinSize() const
{
int fcy = Draw::GetStdFontCy();
return AddFrameSize(fcy / 2, fcy + 2 + 2 * EditFieldIsThin());
}
Size Ctrl::GetStdSize() const
{
Size sz = GetMinSize();
sz.cx *= 10;
return sz;
}
Size Ctrl::GetMaxSize() const
{
return GetVirtualScreenArea().Size();
}
void Ctrl::SyncLayout(int force)
{
GuiLock __;
if(destroying)
return;
LLOG("SyncLayout " << Name() << " size: " << GetSize());
bool refresh = false;
Rect oview = GetView();
Rect view = GetRect().Size();
overpaint = OverPaint();
int n = GetFrameCount();
for(int i = 0; i < n; i++) {
Frame& f = GetFrame0(i);
f.frame->FrameLayout(view);
if(view != f.GetView()) {
f.SetView(view);
refresh = true;
}
int q = f.frame->OverPaint();
if(q > overpaint) overpaint = q;
}
if(oview.Size() != view.Size() || force > 1) {
for(Ctrl& q : *this) {
q.RectSet(q.CalcRect(GetRect(), view));
LLOG("Layout set rect " << q.Name() << " " << q.rect);
q.SyncLayout(force > 1 ? force : 0);
}
Refresh();
}
if(oview != view || force) {
State(LAYOUTPOS);
Layout();
}
if(refresh)
RefreshFrame();
}
void Ctrl::RefreshParentLayout()
{
Ctrl *parent = GetParent();
if(parent)
parent->RefreshLayout();
}
void Ctrl::UpdateParentLayout()
{
Ctrl *parent = GetParent();
if(parent)
parent->UpdateLayout();
}
int Ctrl::FindMoveCtrl(const VectorMap<Ctrl *, MoveCtrl>& m, Ctrl *x)
{
int q = m.Find(x);
return q >= 0 && m[q].ctrl ? q : -1;
}
Ctrl::MoveCtrl *Ctrl::FindMoveCtrlPtr(VectorMap<Ctrl *, MoveCtrl>& m, Ctrl *x)
{
int q = FindMoveCtrl(m, x);
return q >= 0 ? &m[q] : NULL;
}
void Ctrl::SetPos0(LogPos p, bool _inframe)
{
GuiLock __;
if(p == GetPos() && inframe == _inframe) return;
Ctrl *parent = GetParent();
if(parent && !IsDHCtrl()) {
if(!globalbackbuffer) {
Rect from = GetRect().Size();
Top *top = GetTopRect(from, true)->GetTop();
if(top) {
LTIMING("SetPos0 MoveCtrl");
LogPosSet(p);
inframe = _inframe;
Rect to = GetRect().Size();
UpdateRect0();
GetTopRect(to, true);
MoveCtrl *s = FindMoveCtrlPtr(top->scroll_move, this);
if(s && s->from == from && s->to == to) {
s->ctrl = NULL;
LLOG("SetPos Matched " << from << " -> " << to);
}
else {
MoveCtrl& m = top->move.Add(this);
m.ctrl = this;
m.from = from;
m.to = to;
LLOG("SetPos Add " << UPP::Name(this) << from << " -> " << to);
}
StateH(POSITION);
return;
}
}
RefreshFrame();
}
LogPosSet(p);
inframe = _inframe;
UpdateRect();
StateH(POSITION);
}
void Ctrl::UpdateRect0(bool sync)
{
GuiLock __;
LTIMING("UpdateRect0");
Ctrl *parent = GetParent();
if(parent)
RectSet(CalcRect(parent->GetRect(), parent->GetView()));
else {
static Rect pwa;
ONCELOCK {
pwa = GetPrimaryWorkArea();
}
RectSet(CalcRect(pwa, pwa));
}
LLOG("UpdateRect0 " << Name() << " to " << rect);
LTIMING("UpdateRect0 SyncLayout");
if(sync)
SyncLayout();
}
void Ctrl::UpdateRect(bool sync)
{
GuiLock __;
UpdateRect0(sync);
if(GetParent()) RefreshFrame();
}
Ctrl& Ctrl::SetPos(LogPos p, bool _inframe)
{
GuiLock __;
Ctrl *parent = GetParent();
if(p != GetPos() || inframe != _inframe) {
if(parent || !IsOpen())
SetPos0(p, _inframe);
else {
Rect wa = GetWorkArea();
WndSetPos(CalcRect(p, wa, wa));
StateH(POSITION);
}
}
return *this;
}
Ctrl& Ctrl::SetPos(LogPos p)
{
return SetPos(p, false);
}
Ctrl& Ctrl::SetPosX(Logc x)
{
return SetPos(LogPos(x, GetPos().y));
}
Ctrl& Ctrl::SetPosY(Logc y)
{
return SetPos(LogPos(GetPos().x, y));
}
Ctrl& Ctrl::SetFramePos(LogPos p)
{
return SetPos(p, true);
}
Ctrl& Ctrl::SetFramePosX(Logc x) {
return SetPos(LogPos(x, GetPos().y), true);
}
Ctrl& Ctrl::SetFramePosY(Logc y) {
return SetPos(LogPos(GetPos().x, y), true);
}
void Ctrl::SetRect(int x, int y, int cx, int cy)
{
LLOG("SetRect " << Name() << " rect: " << RectC(x, y, cx, cy));
SetPos(PosLeft(x, cx), PosTop(y, cy));
}
void Ctrl::SetWndRect(const Rect& r)
{
LLOG("SetWndRect " << Name() << " rect: " << r << " (Ctrl::GetRect = " << GetRect() << ")");
SetPos0(LogPos(PosLeft(r.left, r.Width()), PosTop(r.top, r.Height())), false);
}
void Ctrl::SetRect(const Rect& r)
{
LLOG("SetRect " << Name() << " rect: " << r << " (Ctrl::GetRect = " << GetRect() << ")");
SetRect(r.left, r.top, r.Width(), r.Height());
}
void Ctrl::SetRectX(int x, int cx) {
SetPosX(PosLeft(x, cx));
}
void Ctrl::SetRectY(int y, int cy) {
SetPosY(PosTop(y, cy));
}
void Ctrl::SetFrameRect(int x, int y, int cx, int cy) {
SetFramePos(PosLeft(x, cx), PosTop(y, cy));
}
void Ctrl::SetFrameRect(const Rect& r) {
SetFrameRect(r.left, r.top, r.Width(), r.Height());
}
void Ctrl::SetFrameRectX(int x, int cx) {
SetFramePosX(PosLeft(x, cx));
}
void Ctrl::SetFrameRectY(int y, int cy) {
SetFramePosY(PosTop(y, cy));
}
Ctrl& Ctrl::LeftPos(int a, int size) {
return SetPosX(PosLeft(a, size));
}
Ctrl& Ctrl::RightPos(int a, int size) {
return SetPosX(PosRight(a, size));
}
Ctrl& Ctrl::TopPos(int a, int size) {
return SetPosY(PosTop(a, size));
}
Ctrl& Ctrl::BottomPos(int a, int size) {
return SetPosY(PosBottom(a, size));
}
Ctrl& Ctrl::HSizePos(int a, int b) {
return SetPosX(PosSize(a, b));
}
Ctrl& Ctrl::VSizePos(int a, int b) {
return SetPosY(PosSize(a, b));
}
Ctrl& Ctrl::SizePos() {
return HSizePos().VSizePos();
}
Ctrl& Ctrl::HCenterPos(int size, int delta) {
return SetPosX(PosCenter(size, delta));
}
Ctrl& Ctrl::VCenterPos(int size, int delta) {
return SetPosY(PosCenter(size, delta));
}
Ctrl& Ctrl::LeftPosZ(int a, int size) {
return LeftPos(HorzLayoutZoom(a), HorzLayoutZoom(size));
}
Ctrl& Ctrl::RightPosZ(int a, int size) {
return RightPos(HorzLayoutZoom(a), HorzLayoutZoom(size));
}
Ctrl& Ctrl::TopPosZ(int a, int size) {
return TopPos(VertLayoutZoom(a), VertLayoutZoom(size));
}
Ctrl& Ctrl::BottomPosZ(int a, int size) {
return BottomPos(VertLayoutZoom(a), VertLayoutZoom(size));
}
Ctrl& Ctrl::HSizePosZ(int a, int b) {
return HSizePos(HorzLayoutZoom(a), HorzLayoutZoom(b));
}
Ctrl& Ctrl::VSizePosZ(int a, int b) {
return VSizePos(VertLayoutZoom(a), VertLayoutZoom(b));
}
Ctrl& Ctrl::HCenterPosZ(int size, int delta) {
return HCenterPos(HorzLayoutZoom(size), HorzLayoutZoom(delta));
}
Ctrl& Ctrl::VCenterPosZ(int size, int delta) {
return VCenterPos(VertLayoutZoom(size), VertLayoutZoom(delta));
}
Rect Ctrl::GetWorkArea(Point pt)
{
GuiLock __;
static Array<Rect> rc;
if (rc.IsEmpty())
GetWorkArea(rc);
for(int i = 0; i < rc.GetCount(); i++)
if(rc[i].Contains(pt))
return rc[i];
return GetPrimaryWorkArea();
}
Rect Ctrl::StdGetWorkArea() const
{
GuiLock __;
static Array<Rect> rc;
if(rc.IsEmpty())
GetWorkArea(rc);
const Ctrl *top = GetTopCtrl();
if(top && top->IsOpen())
return GetWorkArea(top->GetScreenRect().TopLeft());
return GetPrimaryWorkArea();
}
}