mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-16 06:05:58 -06:00
434 lines
10 KiB
C++
434 lines
10 KiB
C++
#include "LayDes.h"
|
|
|
|
struct EnumProperty : public EditorProperty<DropList> {
|
|
String name_space;
|
|
|
|
virtual void SetData(const Value& v);
|
|
virtual String Save() const;
|
|
virtual void Read(CParser& p) { SetData(ReadPropertyParam(p)); }
|
|
|
|
EnumProperty(LayoutEnum& e) {
|
|
for(int i = 0; i < e.items.GetCount(); i++)
|
|
editor.Add(e.items.GetKey(i), e.items[i]);
|
|
if(e.items.GetCount())
|
|
SetData(defval = e.items.GetKey(0));
|
|
name_space = e.name_space;
|
|
}
|
|
};
|
|
|
|
void EnumProperty::SetData(const Value& v)
|
|
{
|
|
String s = ~v;
|
|
int q = s.ReverseFind(':');
|
|
if(q >= 0)
|
|
s = s.Mid(q + 1);
|
|
if(!editor.HasKey(s))
|
|
editor.Add(s, s);
|
|
editor <<= s;
|
|
}
|
|
|
|
String EnumProperty::Save() const
|
|
{
|
|
String s = ~~editor;
|
|
if(name_space.GetCount() && iscib(*s))
|
|
s = name_space + "::" + s;
|
|
return s;
|
|
}
|
|
|
|
bool ParseTemplate(String& type, String& temp)
|
|
{
|
|
int q = type.Find('<');
|
|
if(q < 0)
|
|
return false;
|
|
temp = type.Mid(q + 1);
|
|
type.Trim(q);
|
|
q = temp.Find('>');
|
|
if(q >= 0)
|
|
temp.Trim(q);
|
|
Swap(temp, type);
|
|
return true;
|
|
}
|
|
|
|
void LayoutItem::Create(const String& _type)
|
|
{
|
|
Invalidate();
|
|
property.Clear();
|
|
type = _type;
|
|
pos.x = Ctrl::PosLeft(0, 10);
|
|
pos.y = Ctrl::PosTop(0, 10);
|
|
String tp = type;
|
|
String tm;
|
|
if(ParseTemplate(tp, tm))
|
|
CreateProperties(tm, 0);
|
|
CreateProperties(tp, 1);
|
|
}
|
|
|
|
void LayoutItem::CreateProperties(const String& classname, int level)
|
|
{
|
|
int q = LayoutTypes().Find(classname);
|
|
if(q < 0)
|
|
q = LayoutTypes().Find("Unknown");
|
|
if(q < 0)
|
|
return;
|
|
const LayoutType& c = LayoutTypes()[q];
|
|
for(int i = 0; i < c.property.GetCount(); i++) {
|
|
const TypeProperty& r = c.property[i];
|
|
if(IsNull(r.type))
|
|
CreateProperties(r.name, level + 1);
|
|
else {
|
|
ItemProperty *n = ItemProperty::Create(r.type);
|
|
if(!n) {
|
|
q = LayoutEnums().Find(r.type);
|
|
if(q >= 0)
|
|
n = new EnumProperty(LayoutEnums()[q]);
|
|
}
|
|
if(!n)
|
|
n = new RawProperty;
|
|
n->SetCharset(charset);
|
|
int q = -1;
|
|
for(int i = 0; i < property.GetCount(); i++)
|
|
if(r.name == property[i].name)
|
|
q = i;
|
|
int l = IsNull(r.level) ? q >= 0 ? property[q].level : level : level + r.level;
|
|
ItemProperty& ip = q >= 0 ? property.Set(q, n) : property.Add(n);
|
|
ip.level = l;
|
|
ip.name = r.name;
|
|
if(!IsNull(r.defval))
|
|
try {
|
|
CParser p(r.defval);
|
|
ip.Read(p);
|
|
ip.defval = ~ip;
|
|
}
|
|
catch(CParser::Error e) {
|
|
PutConsole(e + "\n");
|
|
}
|
|
else
|
|
ip.defval = ~ip;
|
|
ip.help = r.help;
|
|
}
|
|
}
|
|
}
|
|
|
|
void LayoutItem::SetCharset(byte cs)
|
|
{
|
|
charset = cs;
|
|
for(int i = 0; i < property.GetCount(); i++)
|
|
property[i].SetCharset(charset);
|
|
}
|
|
|
|
void LayoutItem::ReadProperties(CParser& p, bool addunknown)
|
|
{
|
|
do {
|
|
if(p.Id("LeftPosZ") || p.Id("LeftPos")) {
|
|
Point pt = ReadPoint(p);
|
|
pos.x = Ctrl::PosLeft(pt.x, pt.y);
|
|
}
|
|
else
|
|
if(p.Id("RightPosZ") || p.Id("RightPos")) {
|
|
Point pt = ReadPoint(p);
|
|
pos.x = Ctrl::PosRight(pt.x, pt.y);
|
|
}
|
|
else
|
|
if(p.Id("HSizePosZ") || p.Id("HSizePos")) {
|
|
Point pt = ReadPoint(p);
|
|
pos.x = Ctrl::PosSize(pt.x, pt.y);
|
|
}
|
|
else
|
|
if(p.Id("HCenterPosZ") || p.Id("HCenterPos")) {
|
|
Point pt = ReadPoint(p);
|
|
pos.x = Ctrl::PosCenter(pt.x, pt.y);
|
|
}
|
|
else
|
|
if(p.Id("TopPosZ") || p.Id("TopPos")) {
|
|
Point pt = ReadPoint(p);
|
|
pos.y = Ctrl::PosLeft(pt.x, pt.y);
|
|
}
|
|
else
|
|
if(p.Id("BottomPosZ") || p.Id("BottomPos")) {
|
|
Point pt = ReadPoint(p);
|
|
pos.y = Ctrl::PosRight(pt.x, pt.y);
|
|
}
|
|
else
|
|
if(p.Id("VSizePosZ") || p.Id("VSizePos")) {
|
|
Point pt = ReadPoint(p);
|
|
pos.y = Ctrl::PosSize(pt.x, pt.y);
|
|
}
|
|
else
|
|
if(p.Id("VCenterPosZ") || p.Id("VCenterPos")) {
|
|
Point pt = ReadPoint(p);
|
|
pos.y = Ctrl::PosCenter(pt.x, pt.y);
|
|
}
|
|
else {
|
|
String name = p.ReadId();
|
|
int q = FindProperty(name);
|
|
if(q < 0) {
|
|
if(addunknown) {
|
|
q = property.GetCount();
|
|
ItemProperty& new_prop = property.Add(new RawProperty);
|
|
new_prop.SetCharset(charset);
|
|
new_prop.name = name;
|
|
}
|
|
else {
|
|
p.PassChar('(');
|
|
ReadPropertyParam(p);
|
|
p.PassChar(')');
|
|
}
|
|
}
|
|
if(q >= 0) {
|
|
ItemProperty& ip = property[q];
|
|
ip.SetCharset(charset);
|
|
p.PassChar('(');
|
|
ip.Read(p);
|
|
p.PassChar(')');
|
|
}
|
|
}
|
|
}
|
|
while(p.Char('.'));
|
|
}
|
|
|
|
int LayoutItem::FindProperty(const String& s) const
|
|
{
|
|
for(int i = 0; i < property.GetCount(); i++)
|
|
if(property[i].name == s)
|
|
return i;
|
|
return -1;
|
|
}
|
|
|
|
String LayoutItem::SaveProperties(int y) const
|
|
{
|
|
String out;
|
|
Vector<int> o = GetStableSortOrder(property, [](const ItemProperty& a, const ItemProperty& b) { return a.level < b.level; });
|
|
for(int i = 0; i < o.GetCount(); i++) {
|
|
const ItemProperty& ip = property[o[i]];
|
|
if(ip.GetData() != ip.defval)
|
|
out << '.' << ip.name << '(' << ip.Save() << ')';
|
|
}
|
|
switch(pos.x.GetAlign()) {
|
|
case Ctrl::LEFT: out << Format(".LeftPosZ(%d, %d)", pos.x.GetA(), pos.x.GetB()); break;
|
|
case Ctrl::RIGHT: out << Format(".RightPosZ(%d, %d)", pos.x.GetA(), pos.x.GetB()); break;
|
|
case Ctrl::SIZE: out << Format(".HSizePosZ(%d, %d)", pos.x.GetA(), pos.x.GetB()); break;
|
|
case Ctrl::CENTER: out << Format(".HCenterPosZ(%d, %d)", pos.x.GetB(), pos.x.GetA()); break;
|
|
}
|
|
switch(pos.y.GetAlign()) {
|
|
case Ctrl::TOP: out << Format(".TopPosZ(%d, %d)", pos.y.GetA() - y, pos.y.GetB()); break;
|
|
case Ctrl::BOTTOM: out << Format(".BottomPosZ(%d, %d)", pos.y.GetA(), pos.y.GetB()); break;
|
|
case Ctrl::SIZE: out << Format(".VSizePosZ(%d, %d)", pos.y.GetA(), pos.y.GetB()); break;
|
|
case Ctrl::CENTER: out << Format(".VCenterPosZ(%d, %d)", pos.y.GetB(), pos.y.GetA()); break;
|
|
}
|
|
out.Remove(0);
|
|
return out;
|
|
}
|
|
|
|
String LayoutItem::Save(int i, int y, const String& eol) const
|
|
{
|
|
String out;
|
|
if(type.IsEmpty())
|
|
out << "\tUNTYPED(";
|
|
else {
|
|
String s = type;
|
|
CParser p(type);
|
|
int q = -1;
|
|
if(p.IsId())
|
|
q = LayoutTypes().Find(p.ReadId());
|
|
if(q >= 0) {
|
|
String n = LayoutTypes()[q].name_space;
|
|
if(n.GetCount()) {
|
|
s.Clear();
|
|
CParser p(type);
|
|
while(!p.IsEof()) {
|
|
if(p.IsId())
|
|
s << n << "::" << p.ReadId();
|
|
else
|
|
if(p.Char('<'))
|
|
s << '<';
|
|
else
|
|
if(p.Char(':'))
|
|
s << ':';
|
|
else
|
|
if(p.Char('>'))
|
|
s << '>';
|
|
else
|
|
if(p.Char(','))
|
|
s << ',';
|
|
else
|
|
p.SkipTerm();
|
|
}
|
|
}
|
|
}
|
|
out << "\tITEM(" << s << ", ";
|
|
}
|
|
String var = variable.IsEmpty() ? Format("dv___%d", i) : variable;
|
|
out << var << ", " << SaveProperties(y) << ")" << eol;
|
|
return out;
|
|
}
|
|
|
|
void LayoutItem::UnknownPaint(Draw& w)
|
|
{
|
|
DrawFatFrame(w, 0, 0, csize.cx, csize.cy, SGray(), 2);
|
|
int q = FindProperty("SetLabel");
|
|
if(q >= 0 && IsString(~property[q]))
|
|
DrawSmartText(w, 0, 0, csize.cx, ToUtf8((WString)~property[q]));
|
|
Font fnt = LayFont();
|
|
String s = type;
|
|
Color ink = White();
|
|
if(IsNull(s)) {
|
|
s = "Untyped";
|
|
fnt.Italic();
|
|
ink = LtCyan();
|
|
}
|
|
Size tsz = GetTextSize(s, fnt);
|
|
w.DrawRect(csize.cx - tsz.cx - tsz.cy, csize.cy - tsz.cy, tsz.cx + tsz.cy, tsz.cy, SGray());
|
|
w.DrawText(csize.cx - tsz.cx - tsz.cy / 2, csize.cy - tsz.cy, s, fnt, ink);
|
|
}
|
|
|
|
void LayoutItem::CreateMethods(EscValue& ctrl, const String& type, bool copy) const
|
|
{
|
|
int q = LayoutTypes().Find(type);
|
|
if(q < 0)
|
|
q = LayoutTypes().Find("Unknown");
|
|
if(q < 0)
|
|
return;
|
|
const LayoutType& m = LayoutTypes()[q];
|
|
for(q = 0; q < m.property.GetCount(); q++)
|
|
if(IsNull(m.property[q].type))
|
|
CreateMethods(ctrl, m.property[q].name, copy);
|
|
for(q = 0; q < m.methods.GetCount(); q++) {
|
|
ctrl.MapSet(m.methods.GetKey(q), m.methods[q]);
|
|
if(copy)
|
|
ctrl.MapSet("Ctrl" + m.methods.GetKey(q), m.methods[q]);
|
|
}
|
|
}
|
|
|
|
EscValue LayoutItem::CreateEsc() const
|
|
{
|
|
EscValue ctrl;
|
|
String tp = type;
|
|
String tm;
|
|
if(ParseTemplate(tp, tm)) {
|
|
CreateMethods(ctrl, tp, true);
|
|
if(ctrl.IsMap())
|
|
ctrl.MapSet("CtrlPaint", ctrl.MapGet("Paint"));
|
|
CreateMethods(ctrl, tm, false);
|
|
}
|
|
else
|
|
CreateMethods(ctrl, tp, false);
|
|
for(int q = 0; q < property.GetCount(); q++) {
|
|
EscValue w;
|
|
const Value& v = ~property[q];
|
|
if(v.Is<Font>()) {
|
|
Font fnt = v;
|
|
if(fnt.GetHeight())
|
|
fnt.Height(Ctrl::VertLayoutZoom(fnt.GetHeight()));
|
|
w = EscFont(fnt);
|
|
}
|
|
if(IsString(v))
|
|
w = (WString)v;
|
|
if(IsNumber(v))
|
|
w = (double)v;
|
|
if(v.Is<Color>())
|
|
w = EscColor(v);
|
|
ctrl.MapSet(property[q].name, w);
|
|
}
|
|
ctrl.MapSet("type", (WString)type);
|
|
ctrl.MapSet("GetSize", ReadLambda(Format("() { return Size(%d, %d); }", csize.cx, csize.cy)));
|
|
ctrl.MapSet("GetRect", ReadLambda(Format("() { return Rect(0, 0, %d, %d); }", csize.cx, csize.cy)));
|
|
return ctrl;
|
|
}
|
|
|
|
EscValue LayoutItem::ExecuteMethod(const char *method, Vector<EscValue>& arg) const
|
|
{
|
|
try {
|
|
EscValue self = CreateEsc();
|
|
return ::Execute(UscGlobal(), &self, method, arg, 50000);
|
|
}
|
|
catch(CParser::Error& e) {
|
|
PutConsole(e + "\n");
|
|
}
|
|
return EscValue();
|
|
}
|
|
|
|
EscValue LayoutItem::ExecuteMethod(const char *method) const
|
|
{
|
|
Vector<EscValue> arg;
|
|
EscValue h = ExecuteMethod(method, arg);
|
|
return h;
|
|
}
|
|
|
|
Size LayoutItem::GetMinSize()
|
|
{
|
|
return SizeEsc(ExecuteMethod("GetMinSize"));
|
|
}
|
|
|
|
Size LayoutItem::GetStdSize()
|
|
{
|
|
return SizeEsc(ExecuteMethod("GetStdSize"));
|
|
}
|
|
|
|
void LayoutItem::Paint(Draw& w, Size sz, bool sample)
|
|
{
|
|
if(csize != sz) {
|
|
csize = sz;
|
|
DrawingDraw dw(csize);
|
|
int q = LayoutTypes().Find(type);
|
|
if(q < 0)
|
|
q = LayoutTypes().Find("Unknown");
|
|
if(q < 0)
|
|
UnknownPaint(dw);
|
|
else {
|
|
try {
|
|
EscValue ctrl = CreateEsc();
|
|
if(ctrl.MapGet("Paint").IsLambda()) {
|
|
if(sample) {
|
|
ctrl.MapSet("SetLabel", (WString)type);
|
|
Vector<EscValue> arg;
|
|
::Execute(UscGlobal(), &ctrl, "Sample", arg, 50000);
|
|
}
|
|
Vector<EscValue> arg;
|
|
EscValue draw;
|
|
new EscDraw(draw, dw);
|
|
arg.Add(draw);
|
|
::Execute(UscGlobal(), &ctrl, "Paint", arg, 50000);
|
|
}
|
|
else
|
|
UnknownPaint(dw);
|
|
cache = dw;
|
|
}
|
|
catch(CParser::Error e) {
|
|
PutConsole(e);
|
|
DrawingDraw edw(csize);
|
|
edw.DrawRect(0, 0, csize.cx, csize.cy, Red());
|
|
DrawSmartText(edw, 2, 2, csize.cx - 4, "\1[g@Y \1" + e, LayFont(), Yellow());
|
|
cache = edw;
|
|
}
|
|
}
|
|
}
|
|
w.DrawDrawing(sz, cache);
|
|
}
|
|
|
|
Image GetTypeIcon(const String& type, int cx, int cy, int i, Color bg)
|
|
{
|
|
ASSERT(i >= 0 && i < 2);
|
|
int q = LayoutTypes().Find(type);
|
|
if(q < 0)
|
|
return Null;
|
|
LayoutType& p = LayoutTypes()[q];
|
|
Image& icon = p.icon[i];
|
|
if(p.iconsize[i] != Size(cx, cy)) {
|
|
p.iconsize[i] = Size(cx, cy);
|
|
LayoutItem m;
|
|
m.Create(type);
|
|
Size stdsize = Zsz(m.GetStdSize());
|
|
if(stdsize.cx == 0 || stdsize.cy == 0)
|
|
return Null;
|
|
|
|
ImageDraw w(stdsize);
|
|
w.DrawRect(stdsize, bg);
|
|
m.Paint(w, stdsize, true);
|
|
if(stdsize.cx * cy > stdsize.cy * cx)
|
|
cy = stdsize.cy * cx / stdsize.cx;
|
|
else
|
|
cx = stdsize.cx * cy / stdsize.cy;
|
|
icon = Rescale(w, cx, cy);
|
|
}
|
|
return icon;
|
|
}
|