mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-16 06:05:58 -06:00
412 lines
9.2 KiB
C++
412 lines
9.2 KiB
C++
#include <CtrlLib/CtrlLib.h>
|
|
#include <Esc/Esc.h>
|
|
|
|
struct FileTemplate {
|
|
String filename;
|
|
String condition;
|
|
String text;
|
|
};
|
|
|
|
enum { TEMPLATEITEM_ID, TEMPLATEITEM_FILENAME, TEMPLATEITEM_OPTION, TEMPLATEITEM_SELECT };
|
|
|
|
struct TemplateItem {
|
|
String label;
|
|
int type;
|
|
String id;
|
|
Vector<String> value;
|
|
String init;
|
|
};
|
|
|
|
struct PackageTemplate {
|
|
String name;
|
|
bool main;
|
|
Array<TemplateItem> item;
|
|
Array<FileTemplate> file;
|
|
};
|
|
|
|
int ReadTemplateType(CParser& p)
|
|
{
|
|
static char *nm[] = { "id", "filename", "option", "select" };
|
|
for(int i = 0; i < __countof(nm); i++)
|
|
if(p.Id(nm[i]))
|
|
return i;
|
|
p.ThrowError("Unknown type");
|
|
return 0;
|
|
}
|
|
|
|
PackageTemplate ReadTemplate(const char *filename)
|
|
{
|
|
PackageTemplate pt;
|
|
FileIn in(filename);
|
|
String header;
|
|
String l;
|
|
for(;;) {
|
|
if(in.IsEof())
|
|
break;
|
|
l = in.GetLine();
|
|
if(l[0] == '@' && l[1] == '@')
|
|
break;
|
|
header << l << '\n';
|
|
}
|
|
CParser p(header, filename);
|
|
p.PassId("template");
|
|
pt.name = p.ReadString();
|
|
pt.main = pt.sub = false;
|
|
for(;;) {
|
|
if(p.Id("main"))
|
|
pt.main = true;
|
|
else
|
|
if(p.Id("sub"))
|
|
pt.sub = true;
|
|
else
|
|
break;
|
|
}
|
|
p.PassChar(';');
|
|
while(!p.IsEof()) {
|
|
int type = ReadTemplateType(p);
|
|
TemplateItem& m = pt.item.Add();
|
|
m.type = type;
|
|
if(type == TEMPLATEITEM_SELECT) {
|
|
p.PassChar('(');
|
|
do
|
|
m.value.Add(p.ReadString());
|
|
while(p.Char(','));
|
|
p.PassChar(')');
|
|
}
|
|
m.label = p.ReadString();
|
|
m.id = p.ReadId();
|
|
if(p.Char('=')) {
|
|
const char *b = p.GetPtr();
|
|
while(!p.IsChar(';')) {
|
|
if(p.IsEof())
|
|
p.ThrowError("unexpected end of file");
|
|
p.SkipTerm();
|
|
}
|
|
m.init = String(b, p.GetPtr());
|
|
}
|
|
p.PassChar(';');
|
|
}
|
|
for(;;) {
|
|
pt.file.Add();
|
|
pt.file.Top().filename = l.Mid(2);
|
|
for(;;) {
|
|
if(in.IsEof())
|
|
return pt;
|
|
l = in.GetLine();
|
|
if(l[0] == '@' && l[1] == '@')
|
|
break;
|
|
if(l[0] == '?' && l[1] == '?')
|
|
pt.file.Top().condition = l.Mid(2);
|
|
else
|
|
pt.file.Top().text << l << "\r\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
struct AppPreview : Ctrl {
|
|
virtual void Paint(Draw& w);
|
|
virtual void Layout();
|
|
|
|
ScrollBar sb;
|
|
struct Line : Moveable<Line> {
|
|
String text;
|
|
bool header;
|
|
};
|
|
Vector<Line> line;
|
|
|
|
void Scroll() { Refresh(); }
|
|
|
|
void Clear() { line.Clear(); Refresh(); sb.Set(0); }
|
|
void Add(const String& data, bool header = false);
|
|
|
|
typedef AppPreview CLASSNAME;
|
|
|
|
AppPreview() { SetFrame(InsetFrame()); AddFrame(sb); sb <<= THISBACK(Scroll); NoWantFocus(); }
|
|
};
|
|
|
|
int NoCr(int c)
|
|
{
|
|
return c == '\r' ? 0 : c;
|
|
}
|
|
|
|
void AppPreview::Layout()
|
|
{
|
|
sb.SetTotal(line.GetCount());
|
|
sb.SetPage(GetSize().cy / ScreenInfo().GetFontInfo(Courier(12)).GetHeight());
|
|
}
|
|
|
|
void AppPreview::Paint(Draw& w)
|
|
{
|
|
Size sz = GetSize();
|
|
FontInfo fi = w.GetFontInfo(Courier(12));
|
|
int y = 0;
|
|
int i = sb;
|
|
while(y < sz.cy) {
|
|
bool hdr = i < line.GetCount() && line[i].header;
|
|
w.DrawRect(0, y, sz.cx, fi.GetHeight(), hdr ? SLtCyan : SWhite);
|
|
if(i < line.GetCount())
|
|
w.DrawText(0, y, line[i].text, hdr ? Arial(12).Bold().Italic() : Courier(12), SBlack);
|
|
y += fi.GetHeight();
|
|
i++;
|
|
}
|
|
}
|
|
|
|
void AppPreview::Add(const String& data, bool header)
|
|
{
|
|
Vector<String> l = Split(Filter(data, NoCr), '\n', false);
|
|
for(int i = 0; i < l.GetCount(); i++) {
|
|
Line& q = line.Add();
|
|
const char *s = l[i];
|
|
while(*s == '\t') {
|
|
q.text << " ";
|
|
s++;
|
|
}
|
|
q.text << s;
|
|
q.header = header;
|
|
}
|
|
Refresh();
|
|
Layout();
|
|
}
|
|
|
|
#define LAYOUTFILE <Creator/main.lay>
|
|
#include <CtrlCore/lay.h>
|
|
|
|
struct TemplateDlg : public WithTemplateLayout<TopWindow>
|
|
{
|
|
AppPreview preview;
|
|
|
|
Array<PackageTemplate> pt;
|
|
|
|
Array<Label> label;
|
|
Array<Ctrl> ctrl;
|
|
DelayCallback delay;
|
|
|
|
const PackageTemplate& ActualTemplate();
|
|
|
|
void Preview();
|
|
void EnterTemplate();
|
|
void LoadNest(const char *path);
|
|
void Load(const char *paths);
|
|
void EnableCreate() { ok.Enable(!IsNull(package)); Inits(); }
|
|
void Inits();
|
|
|
|
ArrayMap<String, EscValue> MakeVars();
|
|
void Create();
|
|
|
|
typedef TemplateDlg CLASSNAME;
|
|
TemplateDlg();
|
|
};
|
|
|
|
TemplateDlg::TemplateDlg()
|
|
{
|
|
CtrlLayoutOKCancel(*this, "Create new main package");
|
|
delay <<= THISBACK(Preview);
|
|
delay.SetDelay(300);
|
|
templist.AddColumn("Template");
|
|
templist.WhenEnterRow = THISBACK(EnterTemplate);
|
|
ok.Disable();
|
|
package <<= THISBACK(EnableCreate);
|
|
}
|
|
|
|
const PackageTemplate& TemplateDlg::ActualTemplate()
|
|
{
|
|
if(templist.GetCursor() > 0)
|
|
return pt[templist.GetCursor() - 1];
|
|
static PackageTemplate t;
|
|
return t;
|
|
}
|
|
|
|
int IdFilter(int c)
|
|
{
|
|
return c == '_' || IsAlNum(c) ? c : 0;
|
|
}
|
|
|
|
int FilenameFilter(int c)
|
|
{
|
|
return c == '_' || IsAlNum(c) || c == '.' ? c : 0;
|
|
}
|
|
|
|
ArrayMap<String, EscValue> TemplateDlg::MakeVars()
|
|
{
|
|
const PackageTemplate& tp = ActualTemplate();
|
|
ArrayMap<String, EscValue> var;
|
|
var.Add("PACKAGE", (String)~package);
|
|
for(int i = 0; i < tp.item.GetCount(); i++)
|
|
var.Add(tp.item[i].id, EscFromStdValue(~ctrl[i]));
|
|
StdLib(var);
|
|
return var;
|
|
}
|
|
|
|
void TemplateDlg::Preview()
|
|
{
|
|
const PackageTemplate& tp = ActualTemplate();
|
|
ArrayMap<String, EscValue> var = MakeVars();
|
|
int sc = preview.sb;
|
|
preview.Clear();
|
|
for(int i = 0; i < tp.file.GetCount(); i++) {
|
|
const FileTemplate& ft = tp.file[i];
|
|
if(IsNull(ft.condition) || IsTrue(Evaluate(ft.condition, var))) {
|
|
preview.Add(Expand(ft.filename, var), true);
|
|
preview.Add(Expand(ft.text, var));
|
|
}
|
|
}
|
|
preview.sb = sc;
|
|
}
|
|
|
|
void TemplateDlg::Create()
|
|
{
|
|
const PackageTemplate& tp = ActualTemplate();
|
|
ArrayMap<String, EscValue> var = MakeVars();
|
|
for(int i = 0; i < tp.file.GetCount(); i++) {
|
|
const FileTemplate& ft = tp.file[i];
|
|
if(IsNull(ft.condition) || IsTrue(Evaluate(ft.condition, var))) {
|
|
String fn = Expand(ft.filename, var);
|
|
if(!IsNull(fn)) {
|
|
fn = AppendFileName(AppendFileName(~nest, (String)~package), fn);
|
|
RealizePath(fn);
|
|
SaveFile(fn, Expand(ft.text, var));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void TemplateDlg::Inits()
|
|
{
|
|
const PackageTemplate& tp = ActualTemplate();
|
|
ArrayMap<String, EscValue> var;
|
|
var.Add("PACKAGE", (String)~package);
|
|
for(int i = 0; i < tp.item.GetCount(); i++) {
|
|
String init = tp.item[i].init;
|
|
if(!IsNull(init) && !ctrl[i].IsModified()) {
|
|
ctrl[i] <<= StdValueFromEsc(Evaluate(init, var));
|
|
ctrl[i].ClearModify();
|
|
}
|
|
}
|
|
}
|
|
|
|
void TemplateDlg::EnterTemplate()
|
|
{
|
|
const PackageTemplate& tp = ActualTemplate();
|
|
ArrayMap<String, EscValue> var;
|
|
var.Add("PACKAGE", (String)~package);
|
|
StdLib(var);
|
|
label.Clear();
|
|
ctrl.Clear();
|
|
Point pos = templist.GetRect().BottomLeft();
|
|
pos.y += 8;
|
|
int cx = cancel.GetRect().right - pos.x;
|
|
for(int i = 0; i < tp.item.GetCount(); i++) {
|
|
const TemplateItem& m = tp.item[i];
|
|
if(m.type == TEMPLATEITEM_OPTION)
|
|
ctrl.Add(new Option).SetLabelText(m.label);
|
|
else {
|
|
label.Add().SetLabel(m.label).LeftPos(pos.x, cx).TopPos(pos.y);
|
|
Add(label.Top());
|
|
pos.y += label.Top().GetMinSize().cy;
|
|
switch(m.type) {
|
|
case TEMPLATEITEM_ID: {
|
|
EditField *e = new EditField;
|
|
e->SetFilter(IdFilter);
|
|
ctrl.Add(e);
|
|
break;
|
|
}
|
|
case TEMPLATEITEM_FILENAME: {
|
|
EditField *e = new EditField;
|
|
e->SetFilter(FilenameFilter);
|
|
ctrl.Add(e);
|
|
break;
|
|
}
|
|
case TEMPLATEITEM_SELECT: {
|
|
DropList *d = new DropList;
|
|
for(int i = 0; i < m.value.GetCount(); i++)
|
|
d->Add(m.value[i]);
|
|
ctrl.Add(d);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
Add(ctrl.Top());
|
|
ctrl.Top() << delay;
|
|
ctrl.Top().LeftPos(pos.x, cx).TopPos(pos.y);
|
|
pos.y += ctrl.Top().GetMinSize().cy + 10;
|
|
ctrl.Top().ClearModify();
|
|
}
|
|
Preview();
|
|
Inits();
|
|
}
|
|
|
|
void TemplateDlg::LoadNest(const char *path, bool main, bool sub)
|
|
{
|
|
FindFile ff(AppendFileName(path, "*.*"));
|
|
while(ff) {
|
|
String p = AppendFileName(path, ff.GetName());
|
|
if(ff.IsFolder())
|
|
LoadNest(p);
|
|
else
|
|
if(ToLower(GetFileExt(ff.GetName())) == ".upt") {
|
|
try {
|
|
PackageTemplate t = ReadTemplate(p);
|
|
if(main && t.main || sub && t.sub)
|
|
pt.Add() = t;
|
|
}
|
|
catch(CParser::Error e) {
|
|
Exclamation("Package template [* " + DeQtf(p) + "] is invalid&[* " + e);
|
|
}
|
|
}
|
|
ff.Next();
|
|
}
|
|
}
|
|
|
|
void TemplateDlg::Load(const char *paths, bool main, bool sub)
|
|
{
|
|
pt.Clear();
|
|
Vector<String> p = Split(paths, ';');
|
|
for(int i = 0; i < p.GetCount(); i++) {
|
|
LoadNest(p[i], name, sub);
|
|
nest.Add(p[i]);
|
|
}
|
|
Sort(pt, FieldRelation(&PackageTemplate::name, StdLess<String>()));
|
|
templist.Clear();
|
|
templist.Add("<empty>");
|
|
for(int i = 0; i < pt.GetCount(); i++)
|
|
templist.Add(pt[i].name);
|
|
if(nest.GetCount())
|
|
nest.SetIndex(0);
|
|
templist.GoBegin();
|
|
ActiveFocus(package);
|
|
}
|
|
|
|
void AppMain()
|
|
{
|
|
PackageTemplate pt;
|
|
try {
|
|
pt = ReadTemplate("f:/test.upt");
|
|
}
|
|
catch(CParser::Error& e) {
|
|
DUMP(e);
|
|
return;
|
|
}
|
|
DUMP(pt.name);
|
|
for(int i = 0; i < pt.item.GetCount(); i++) {
|
|
DUMP(pt.item[i].type);
|
|
DUMP(pt.item[i].label);
|
|
DUMP(pt.item[i].id);
|
|
DUMP(pt.item[i].init);
|
|
}
|
|
AppPreview pw;
|
|
for(int i = 0; i < pt.file.GetCount(); i++) {
|
|
LOG("--------------");
|
|
FileTemplate ft = pt.file[i];
|
|
DUMP(pt.file[i].filename);
|
|
DUMP(pt.file[i].condition);
|
|
DUMP(pt.file[i].text);
|
|
pw.Add(ft.filename, true);
|
|
pw.Add(ft.text);
|
|
}
|
|
TemplateDlg d;
|
|
d.Load("F:\\uppdev");
|
|
if(d.Run() == IDOK)
|
|
d.Create();
|
|
String s;
|
|
s.
|
|
}
|