diff --git a/Ide/Code/LgiIde.cpp b/Ide/Code/LgiIde.cpp --- a/Ide/Code/LgiIde.cpp +++ b/Ide/Code/LgiIde.cpp @@ -1,4101 +1,4108 @@ #include #include #include #include "Lgi.h" #include "LgiIde.h" #include "GMdi.h" #include "GToken.h" #include "GXmlTree.h" #include "GPanel.h" #include "GProcess.h" #include "GButton.h" #include "GTabView.h" #include "FtpThread.h" #include "GClipBoard.h" #include "FindSymbol.h" #include "GBox.h" #include "GTextLog.h" #include "GEdit.h" #include "GTableLayout.h" #include "GTextLabel.h" #include "GCombo.h" #include "GCheckBox.h" #include "GDebugger.h" #include "LgiRes.h" #include "ProjectNode.h" #include "GBox.h" #include "GSubProcess.h" #include "GAbout.h" #define IDM_RECENT_FILE 1000 #define IDM_RECENT_PROJECT 1100 #define IDM_WINDOWS 1200 #define IDM_MAKEFILE_BASE 1300 #define USE_HAIKU_PULSE_HACK 1 #define OPT_ENTIRE_SOLUTION "SearchSolution" #define OPT_SPLIT_PX "SplitPos" #define OPT_OUTPUT_PX "OutputPx" #define OPT_FIX_RENAMED "FixRenamed" #define OPT_RENAMED_SYM "RenamedSym" #define IsSymbolChar(c) ( IsDigit(c) || IsAlpha(c) || strchr("-_", c) ) ////////////////////////////////////////////////////////////////////////////////////////// class FindInProject : public GDialog { AppWnd *App; LList *Lst; public: FindInProject(AppWnd *app) { Lst = NULL; App = app; if (LoadFromResource(IDC_FIND_PROJECT_FILE)) { MoveSameScreen(App); GViewI *v; if (GetViewById(IDC_TEXT, v)) v->Focus(true); if (!GetViewById(IDC_FILES, Lst)) return; RegisterHook(this, GKeyEvents, 0); } } bool OnViewKey(GView *v, GKey &k) { switch (k.vkey) { case VK_UP: case VK_DOWN: case VK_PAGEDOWN: case VK_PAGEUP: { return Lst->OnKey(k); break; } case VK_RETURN: { LListItem *i = Lst->GetSelected(); if (i) { char *Ref = i->GetText(0); App->GotoReference(Ref, 1, false); } EndModal(1); break; } case VK_ESCAPE: { EndModal(0); break; } } return false; } void Search(const char *s) { IdeProject *p = App->RootProject(); if (!p || !s) return; GArray Matches, Nodes; List All; p->GetChildProjects(All); All.Insert(p); for (p=All.First(); p; p=All.Next()) { p->GetAllNodes(Nodes); } FilterFiles(Matches, Nodes, s); Lst->Empty(); for (unsigned i=0; iSetText(Matches[i]->GetFileName()); Lst->Insert(li); } Lst->ResizeColumnsToContent(); } int OnNotify(GViewI *c, int f) { switch (c->GetId()) { case IDC_FILES: if (f == GNotifyItem_DoubleClick) { LListItem *i = Lst->GetSelected(); if (i) { App->GotoReference(i->GetText(0), 1, false); EndModal(1); } } break; case IDC_TEXT: if (f != GNotify_ReturnKey) Search(c->Name()); break; case IDCANCEL: EndModal(0); break; } return 0; } }; ////////////////////////////////////////////////////////////////////////////////////////// char AppName[] = "LgiIde"; char *dirchar(char *s, bool rev = false) { if (rev) { char *last = 0; while (s && *s) { if (*s == '/' || *s == '\\') last = s; s++; } return last; } else { while (s && *s) { if (*s == '/' || *s == '\\') return s; s++; } } return 0; } ////////////////////////////////////////////////////////////////////////////////////////// class Dependency : public GTreeItem { char *File; bool Loaded; GTreeItem *Fake; public: Dependency(const char *file) { File = NewStr(file); char *d = strrchr(File, DIR_CHAR); Loaded = false; Insert(Fake = new GTreeItem); if (FileExists(File)) { SetText(d?d+1:File); } else { char s[256]; sprintf(s, "%s (missing)", d?d+1:File); SetText(s); } } ~Dependency() { DeleteArray(File); } char *GetFile() { return File; } void Copy(GStringPipe &p, int Depth = 0) { { char s[1024]; ZeroObj(s); memset(s, ' ', Depth * 4); sprintf(s+(Depth*4), "[%c] %s\n", Expanded() ? '-' : '+', GetText(0)); p.Push(s); } if (Loaded) { for (GTreeItem *i=GetChild(); i; i=i->GetNext()) { ((Dependency*)i)->Copy(p, Depth+1); } } } char *Find(const char *Paths, char *e) { GToken Path(Paths, LGI_PATH_SEPARATOR); for (int p=0; pSunken(true); Root = new Dependency(File); if (Root) { t->Insert(Root); Root->Expanded(true); } Children.Insert(t); Children.Insert(new GButton(IDC_COPY, 10, t->GView::GetPos().y2 + 10, 60, 20, "Copy")); Children.Insert(new GButton(IDOK, 80, t->GView::GetPos().y2 + 10, 60, 20, "Ok")); } DoModal(); } int OnNotify(GViewI *c, int f) { switch (c->GetId()) { case IDC_COPY: { if (Root) { GStringPipe p; Root->Copy(p); char *s = p.NewStr(); if (s) { GClipBoard c(this); c.Text(s); DeleteArray(s); } break; } break; } case IDOK: { EndModal(0); break; } } return 0; } }; ////////////////////////////////////////////////////////////////////////////////////////// class DebugTextLog : public GTextLog { public: DebugTextLog(int id) : GTextLog(id) { } void PourText(size_t Start, ssize_t Len) override { GTextView3::PourText(Start, Len); for (GTextLine *l=Line.First(); l; l=Line.Next()) { char16 *t = Text + l->Start; if (l->Len > 5 && !StrnicmpW(t, L"(gdb)", 5)) { l->c.Rgb(0, 160, 0); } else if (l->Len > 1 && t[0] == '[') { l->c.Rgb(192, 192, 192); } } } }; WatchItem::WatchItem(IdeOutput *out, const char *Init) { Out = out; Expanded(false); if (Init) SetText(Init); Insert(PlaceHolder = new GTreeItem); } WatchItem::~WatchItem() { } bool WatchItem::SetValue(GVariant &v) { char *Str = v.CastString(); if (ValidStr(Str)) SetText(Str, 2); else GTreeItem::SetText(NULL, 2); return true; } bool WatchItem::SetText(const char *s, int i) { if (ValidStr(s)) { GTreeItem::SetText(s, i); if (i == 0 && Tree && Tree->GetWindow()) { GViewI *Tabs = Tree->GetWindow()->FindControl(IDC_DEBUG_TAB); if (Tabs) Tabs->SendNotify(GNotifyValueChanged); } return true; } if (i == 0) delete this; return false; } void WatchItem::OnExpand(bool b) { if (b && PlaceHolder) { // Do something } } class BuildLog : public GTextLog { public: BuildLog(int id) : GTextLog(id) { } void PourStyle(size_t Start, ssize_t Length) { List::I it = GTextView3::Line.begin(); for (GTextLine *ln = *it; ln; ln = *++it) { if (!ln->c.IsValid()) { char16 *t = Text + ln->Start; char16 *Err = Strnistr(t, L"error", ln->Len); char16 *Undef = Strnistr(t, L"undefined reference", ln->Len); char16 *Warn = Strnistr(t, L"warning", ln->Len); if ( (Err && strchr(":[", Err[5])) || (Undef != NULL) ) ln->c.Rgb(222, 0, 0); else if (Warn && strchr(":[", Warn[7])) ln->c.Rgb(255, 128, 0); else ln->c.Set(LC_TEXT, 24); } } } }; class IdeOutput : public GTabView { public: AppWnd *App; GTabPage *Build; GTabPage *Output; GTabPage *Debug; GTabPage *Find; GTabPage *Ftp; LList *FtpLog; GTextLog *Txt[3]; GArray Buf[3]; GFont Small; GFont Fixed; GTabView *DebugTab; GBox *DebugBox; GBox *DebugLog; LList *Locals, *CallStack, *Threads; GTree *Watch; GTextLog *ObjectDump, *MemoryDump, *Registers; GTableLayout *MemTable; GEdit *DebugEdit; GTextLog *DebuggerLog; IdeOutput(AppWnd *app) { App = app; Build = Output = Debug = Find = Ftp = 0; FtpLog = 0; DebugBox = NULL; Locals = NULL; Watch = NULL; DebugLog = NULL; DebugEdit = NULL; DebuggerLog = NULL; CallStack = NULL; ObjectDump = NULL; MemoryDump = NULL; MemTable = NULL; Threads = NULL; Registers = NULL; Small = *SysFont; Small.PointSize(Small.PointSize()-1); Small.Create(); LgiAssert(Small.Handle()); GFontType Type; if (Type.GetSystemFont("Fixed")) { Type.SetPointSize(SysFont->PointSize()-1); Fixed.Create(&Type); } else { Fixed.PointSize(SysFont->PointSize()-1); Fixed.Face("Courier"); Fixed.Create(); } GetCss(true)->MinHeight("60px"); Build = Append("Build"); Output = Append("Output"); Find = Append("Find"); Ftp = Append("Ftp"); Debug = Append("Debug"); SetFont(&Small); Build->SetFont(&Small); Output->SetFont(&Small); Find->SetFont(&Small); Ftp->SetFont(&Small); Debug->SetFont(&Small); if (Build) Build->Append(Txt[AppWnd::BuildTab] = new BuildLog(IDC_BUILD_LOG)); if (Output) Output->Append(Txt[AppWnd::OutputTab] = new GTextLog(IDC_OUTPUT_LOG)); if (Find) Find->Append(Txt[AppWnd::FindTab] = new GTextLog(IDC_FIND_LOG)); if (Ftp) Ftp->Append(FtpLog = new LList(104, 0, 0, 100, 100)); if (Debug) { Debug->Append(DebugBox = new GBox); if (DebugBox) { DebugBox->SetVertical(false); if ((DebugTab = new GTabView(IDC_DEBUG_TAB))) { DebugTab->GetCss(true)->Padding("0px"); DebugTab->SetFont(&Small); DebugBox->AddView(DebugTab); GTabPage *Page; if ((Page = DebugTab->Append("Locals"))) { Page->SetFont(&Small); if ((Locals = new LList(IDC_LOCALS_LIST, 0, 0, 100, 100, "Locals List"))) { Locals->SetFont(&Small); Locals->AddColumn("", 30); Locals->AddColumn("Type", 50); Locals->AddColumn("Name", 50); Locals->AddColumn("Value", 1000); Locals->SetPourLargest(true); Page->Append(Locals); } } if ((Page = DebugTab->Append("Object"))) { Page->SetFont(&Small); if ((ObjectDump = new GTextLog(IDC_OBJECT_DUMP))) { ObjectDump->SetFont(&Fixed); ObjectDump->SetPourLargest(true); Page->Append(ObjectDump); } } if ((Page = DebugTab->Append("Watch"))) { Page->SetFont(&Small); if ((Watch = new GTree(IDC_WATCH_LIST, 0, 0, 100, 100, "Watch List"))) { Watch->SetFont(&Small); Watch->ShowColumnHeader(true); Watch->AddColumn("Watch", 80); Watch->AddColumn("Type", 100); Watch->AddColumn("Value", 600); Watch->SetPourLargest(true); Page->Append(Watch); GXmlTag *w = App->GetOptions()->LockTag("watches", _FL); if (!w) { App->GetOptions()->CreateTag("watches"); w = App->GetOptions()->LockTag("watches", _FL); } if (w) { for (GXmlTag *c = w->Children.First(); c; c = w->Children.Next()) { if (c->IsTag("watch")) { Watch->Insert(new WatchItem(this, c->GetContent())); } } App->GetOptions()->Unlock(); } } } if ((Page = DebugTab->Append("Memory"))) { Page->SetFont(&Small); if ((MemTable = new GTableLayout(IDC_MEMORY_TABLE))) { GCombo *cbo; GCheckBox *chk; GTextLabel *txt; GEdit *ed; MemTable->SetFont(&Small); int x = 0, y = 0; GLayoutCell *c = MemTable->GetCell(x++, y); if (c) { c->VerticalAlign(GCss::VerticalMiddle); c->Add(txt = new GTextLabel(IDC_STATIC, 0, 0, -1, -1, "Address:")); txt->SetFont(&Small); } c = MemTable->GetCell(x++, y); if (c) { c->PaddingRight(GCss::Len("1em")); c->Add(ed = new GEdit(IDC_MEM_ADDR, 0, 0, 60, 20)); ed->SetFont(&Small); } c = MemTable->GetCell(x++, y); if (c) { c->PaddingRight(GCss::Len("1em")); c->Add(cbo = new GCombo(IDC_MEM_SIZE, 0, 0, 60, 20)); cbo->SetFont(&Small); cbo->Insert("1 byte"); cbo->Insert("2 bytes"); cbo->Insert("4 bytes"); cbo->Insert("8 bytes"); } c = MemTable->GetCell(x++, y); if (c) { c->VerticalAlign(GCss::VerticalMiddle); c->Add(txt = new GTextLabel(IDC_STATIC, 0, 0, -1, -1, "Page width:")); txt->SetFont(&Small); } c = MemTable->GetCell(x++, y); if (c) { c->PaddingRight(GCss::Len("1em")); c->Add(ed = new GEdit(IDC_MEM_ROW_LEN, 0, 0, 60, 20)); ed->SetFont(&Small); } c = MemTable->GetCell(x++, y); if (c) { c->VerticalAlign(GCss::VerticalMiddle); c->Add(chk = new GCheckBox(IDC_MEM_HEX, 0, 0, -1, -1, "Show Hex")); chk->SetFont(&Small); chk->Value(true); } int cols = x; x = 0; c = MemTable->GetCell(x++, ++y, true, cols); if ((MemoryDump = new GTextLog(IDC_MEMORY_DUMP))) { MemoryDump->SetFont(&Fixed); MemoryDump->SetPourLargest(true); c->Add(MemoryDump); } Page->Append(MemTable); } } if ((Page = DebugTab->Append("Threads"))) { Page->SetFont(&Small); if ((Threads = new LList(IDC_THREADS, 0, 0, 100, 100, "Threads"))) { Threads->SetFont(&Small); Threads->AddColumn("", 20); Threads->AddColumn("Thread", 1000); Threads->SetPourLargest(true); Threads->MultiSelect(false); Page->Append(Threads); } } if ((Page = DebugTab->Append("Call Stack"))) { Page->SetFont(&Small); if ((CallStack = new LList(IDC_CALL_STACK, 0, 0, 100, 100, "Call Stack"))) { CallStack->SetFont(&Small); CallStack->AddColumn("", 20); CallStack->AddColumn("Call Stack", 1000); CallStack->SetPourLargest(true); CallStack->MultiSelect(false); Page->Append(CallStack); } } if ((Page = DebugTab->Append("Registers"))) { Page->SetFont(&Small); if ((Registers = new GTextLog(IDC_REGISTERS))) { Registers->SetFont(&Small); Registers->SetPourLargest(true); Page->Append(Registers); } } } if ((DebugLog = new GBox)) { DebugLog->SetVertical(true); DebugBox->AddView(DebugLog); DebugLog->AddView(DebuggerLog = new DebugTextLog(IDC_DEBUGGER_LOG)); DebuggerLog->SetFont(&Small); DebugLog->AddView(DebugEdit = new GEdit(IDC_DEBUG_EDIT, 0, 0, 60, 20)); DebugEdit->GetCss(true)->Height(GCss::Len(GCss::LenPx, (float)(SysFont->GetHeight() + 8))); } } } if (FtpLog) { FtpLog->SetPourLargest(true); FtpLog->Sunken(true); FtpLog->AddColumn("Entry", 1000); FtpLog->ShowColumnHeader(false); } for (int n=0; nSetTabSize(8); Txt[n]->Sunken(true); } } ~IdeOutput() { } const char *GetClass() { return "IdeOutput"; } void Save() { if (Watch) { GXmlTag *w = App->GetOptions()->LockTag("watches", _FL); if (!w) { App->GetOptions()->CreateTag("watches"); w = App->GetOptions()->LockTag("watches", _FL); } if (w) { w->EmptyChildren(); for (GTreeItem *ti = Watch->GetChild(); ti; ti = ti->GetNext()) { GXmlTag *t = new GXmlTag("watch"); if (t) { t->SetContent(ti->GetText(0)); w->InsertTag(t); } } App->GetOptions()->Unlock(); } } } void OnCreate() { #if !USE_HAIKU_PULSE_HACK SetPulse(1000); #endif AttachChildren(); } void RemoveAnsi(GArray &a) { char *s = a.AddressOf(); char *e = s + a.Length(); while (s < e) { if (*s == 0x7) { a.DeleteAt(s - a.AddressOf(), true); s--; } else if ( *s == 0x1b && s[1] >= 0x40 && s[1] <= 0x5f ) { // ANSI seq char *end; if (s[1] == '[' && s[2] == '0' && s[3] == ';') end = s + 4; else { end = s + 2; while (end < e && !IsAlpha(*end)) { end++; } if (*end) end++; } auto len = end - s; memmove(s, end, e - end); a.Length(a.Length() - len); s--; } s++; } } void OnPulse() { int Changed = -1; for (int Channel = 0; Channel w(Utf8ToWide(Utf, (ssize_t)Size)); char16 *OldText = Txt[Channel]->NameW(); size_t OldLen = 0; if (OldText) OldLen = StrlenW(OldText); auto Cur = Txt[Channel]->GetCaret(); Txt[Channel]->Insert(OldLen, w, StrlenW(w)); if (Cur > OldLen - 1) { Txt[Channel]->SetCaret(OldLen + StrlenW(w), false); } Changed = Channel; Buf[Channel].Length(0); Txt[Channel]->Invalidate(); } } if (Changed >= 0) Value(Changed); } }; int DocSorter(IdeDoc *a, IdeDoc *b, NativeInt d) { char *A = a->GetFileName(); char *B = b->GetFileName(); if (A && B) { char *Af = strrchr(A, DIR_CHAR); char *Bf = strrchr(B, DIR_CHAR); return stricmp(Af?Af+1:A, Bf?Bf+1:B); } return 0; } struct FileLoc { GAutoString File; int Line; void Set(const char *f, int l) { File.Reset(NewStr(f)); Line = l; } }; class AppWndPrivate { public: AppWnd *App; GMdiParent *Mdi; GOptionsFile Options; GBox *HBox, *VBox; List Docs; List Projects; GImageList *Icons; GTree *Tree; IdeOutput *Output; bool Debugging; bool Running; bool Building; GSubMenu *WindowsMenu; GSubMenu *CreateMakefileMenu; GAutoPtr FindSym; GArray SystemIncludePaths; GArray BreakPoints; // Debugging GDebugContext *DbgContext; // Cursor history tracking int HistoryLoc; GArray CursorHistory; bool InHistorySeek; void SeekHistory(int Direction) { if (CursorHistory.Length()) { int Loc = HistoryLoc + Direction; if (Loc >= 0 && Loc < CursorHistory.Length()) { HistoryLoc = Loc; FileLoc &Loc = CursorHistory[HistoryLoc]; App->GotoReference(Loc.File, Loc.Line, false, false); App->DumpHistory(); } } } // Find in files GAutoPtr FindParameters; GAutoPtr Finder; int AppHnd; // Mru List RecentFiles; GSubMenu *RecentFilesMenu; List RecentProjects; GSubMenu *RecentProjectsMenu; // Object AppWndPrivate(AppWnd *a) : AppHnd(GEventSinkMap::Dispatch.AddSink(a)), Options(GOptionsFile::DesktopMode, AppName) { FindSym.Reset(new FindSymbolSystem(AppHnd)); HistoryLoc = 0; InHistorySeek = false; WindowsMenu = 0; App = a; HBox = VBox = NULL; Tree = 0; DbgContext = NULL; Output = 0; Debugging = false; Running = false; Building = false; RecentFilesMenu = 0; RecentProjectsMenu = 0; Icons = LgiLoadImageList("icons.png", 16, 16); Options.SerializeFile(false); App->SerializeState(&Options, "WndPos", true); SerializeStringList("RecentFiles", &RecentFiles, false); SerializeStringList("RecentProjects", &RecentProjects, false); } ~AppWndPrivate() { FindSym.Reset(); Finder.Reset(); Output->Save(); App->SerializeState(&Options, "WndPos", false); SerializeStringList("RecentFiles", &RecentFiles, true); SerializeStringList("RecentProjects", &RecentProjects, true); Options.SerializeFile(true); RecentFiles.DeleteArrays(); RecentProjects.DeleteArrays(); Docs.DeleteObjects(); Projects.DeleteObjects(); DeleteObj(Icons); } bool FindSource(GAutoString &Full, char *File, char *Context) { if (!LgiIsRelativePath(File)) { Full.Reset(NewStr(File)); } char *ContextPath = 0; if (Context && !Full) { char *Dir = strrchr(Context, DIR_CHAR); for (IdeProject *p=Projects.First(); p && !ContextPath; p=Projects.Next()) { ContextPath = p->FindFullPath(Dir?Dir+1:Context); } if (ContextPath) { LgiTrimDir(ContextPath); char p[300]; LgiMakePath(p, sizeof(p), ContextPath, File); if (FileExists(p)) { Full.Reset(NewStr(p)); } } else { LgiTrace("%s:%i - Context '%s' not found in project.\n", _FL, Context); } } if (!Full) { List::I Projs = Projects.begin(); for (IdeProject *p=*Projs; p; p=*++Projs) { GAutoString Base = p->GetBasePath(); if (Base) { char Path[MAX_PATH]; LgiMakePath(Path, sizeof(Path), Base, File); if (FileExists(Path)) { Full.Reset(NewStr(Path)); break; } } } } if (!Full) { char *Dir = dirchar(File, true); for (IdeProject *p=Projects.First(); p && !Full; p=Projects.Next()) { Full.Reset(p->FindFullPath(Dir?Dir+1:File)); } if (!Full) { if (FileExists(File)) { Full.Reset(NewStr(File)); } } } return ValidStr(Full); } void ViewMsg(char *File, int Line, char *Context) { GAutoString Full; if (FindSource(Full, File, Context)) { App->GotoReference(Full, Line, false); } } void GetContext(char16 *Txt, ssize_t &i, char16 *&Context) { static char16 NMsg[] = L"In file included "; static char16 FromMsg[] = L"from "; auto NMsgLen = StrlenW(NMsg); if (Txt[i] != '\n') return; if (StrncmpW(Txt + i + 1, NMsg, NMsgLen)) return; i += NMsgLen + 1; while (Txt[i]) { // Skip whitespace while (Txt[i] && strchr(" \t\r\n", Txt[i])) i++; // Check for 'from' if (StrncmpW(FromMsg, Txt + i, 5)) break; i += 5; char16 *Start = Txt + i; // Skip to end of doc or line char16 *Colon = 0; while (Txt[i] && Txt[i] != '\n') { if (Txt[i] == ':' && Txt[i+1] != '\n') { Colon = Txt + i; } i++; } if (Colon) { DeleteArray(Context); Context = NewStrW(Start, Colon-Start); } } } #define PossibleLineSep(ch) \ ( (ch) == ':' || (ch) == '(' ) void SeekMsg(int Direction) { GString Comp; IdeProject *p = App->RootProject(); if (p) p ->GetSettings()->GetStr(ProjCompiler); // bool IsIAR = Comp.Equals("IAR"); if (!Output) return; int64 Current = Output->Value(); GTextView3 *o = Current < CountOf(Output->Txt) ? Output->Txt[Current] : 0; if (!o) return; char16 *Txt = o->NameW(); if (!Txt) return; ssize_t Cur = o->GetCaret(); char16 *Context = NULL; // Scan forward to the end of file for the next filename/line number separator. ssize_t i; for (i=Cur; Txt[i]; i++) { GetContext(Txt, i, Context); if ( PossibleLineSep(Txt[i]) && isdigit(Txt[i+1]) ) { break; } } // If not found then scan from the start of the file for the next filename/line number separator. if (!PossibleLineSep(Txt[i])) { for (i=0; i 0 && !strchr("\n>", Txt[Line-1])) { Line--; } // Store the filename GAutoString File(WideToUtf8(Txt+Line, i-Line)); if (!File) return; // Scan over the line number.. auto NumIndex = ++i; while (isdigit(Txt[NumIndex])) NumIndex++; // Store the line number GAutoString NumStr(WideToUtf8(Txt + i, NumIndex - i)); if (!NumStr) return; // Convert it to an integer int LineNumber = atoi(NumStr); o->SetCaret(Line, false); o->SetCaret(NumIndex + 1, true); GString Context8 = Context; ViewMsg(File, LineNumber, Context8); } void UpdateMenus() { static const char *None = "(none)"; if (!App->GetMenu()) return; // This happens in GTK during window destruction if (RecentFilesMenu) { RecentFilesMenu->Empty(); int n=0; char *f=RecentFiles.First(); if (f) { for (; f; f=RecentFiles.Next()) { RecentFilesMenu->AppendItem(f, IDM_RECENT_FILE+n++, true); } } else { RecentFilesMenu->AppendItem(None, 0, false); } } if (RecentProjectsMenu) { RecentProjectsMenu->Empty(); int n=0; char *f=RecentProjects.First(); if (f) { for (; f; f=RecentProjects.Next()) { RecentProjectsMenu->AppendItem(f, IDM_RECENT_PROJECT+n++, true); } } else { RecentProjectsMenu->AppendItem(None, 0, false); } } if (WindowsMenu) { WindowsMenu->Empty(); Docs.Sort(DocSorter); int n=0; for (IdeDoc *d=Docs.First(); d; d=Docs.Next()) { const char *File = d->GetFileName(); if (!File) File = "(untitled)"; char *Dir = strrchr((char*)File, DIR_CHAR); WindowsMenu->AppendItem(Dir?Dir+1:File, IDM_WINDOWS+n++, true); } if (!Docs.First()) { WindowsMenu->AppendItem(None, 0, false); } } } void OnFile(const char *File, bool IsProject = false) { if (File) { List *Recent = IsProject ? &RecentProjects : &RecentFiles; for (char *f=Recent->First(); f; f=Recent->Next()) { if (stricmp(f, File) == 0) { Recent->Delete(f); Recent->Insert(f, 0); UpdateMenus(); return; } } Recent->Insert(NewStr(File), 0); while (Recent->Length() > 10) { char *f = Recent->Last(); Recent->Delete(f); DeleteArray(f); } UpdateMenus(); } } void RemoveRecent(char *File) { if (File) { List *Recent[3] = { &RecentProjects, &RecentFiles, 0 }; for (List **r = Recent; *r; r++) { for (char *f=(*r)->First(); f; f=(*r)->Next()) { if (stricmp(f, File) == 0) { // LgiTrace("Remove '%s'\n", f); (*r)->Delete(f); DeleteArray(f); break; } } } UpdateMenus(); } } IdeDoc *IsFileOpen(const char *File) { if (!File) { LgiTrace("%s:%i - No input File?\n", _FL); return NULL; } for (IdeDoc *Doc = Docs.First(); Doc; Doc = Docs.Next()) { if (Doc->IsFile(File)) { return Doc; } } // LgiTrace("%s:%i - '%s' not found in %i docs.\n", _FL, File, Docs.Length()); return 0; } IdeProject *IsProjectOpen(char *File) { if (File) { for (IdeProject *p = Projects.First(); p; p = Projects.Next()) { if (p->GetFileName() && stricmp(p->GetFileName(), File) == 0) { return p; } } } return 0; } void SerializeStringList(const char *Opt, List *Lst, bool Write) { GVariant v; if (Write) { GMemQueue p; for (char *s = Lst->First(); s; s = Lst->Next()) { p.Write((uchar*)s, strlen(s)+1); } ssize_t Size = (ssize_t)p.GetSize(); v.SetBinary(Size, p.New(), true); Options.SetValue(Opt, v); } else { Lst->DeleteArrays(); if (Options.GetValue(Opt, v) && v.Type == GV_BINARY) { char *Data = (char*)v.Value.Binary.Data; for (char *s=Data; (NativeInt)s<(NativeInt)Data+v.Value.Binary.Length; s += strlen(s) + 1) { auto ns = NewStr(s); Lst->Insert(ns); } } } } }; #ifdef COCOA #define Chk printf("%s:%i - Cnt=%i\n", LgiGetLeaf(__FILE__), __LINE__, (int)WindowHandle().p.retainCount) #else #define Chk #endif AppWnd::AppWnd() { #ifdef __GTK_H__ LgiGetResObj(true, AppName); #endif Chk; GRect r(0, 0, 1300, 900); #ifdef BEOS r.Offset(GdcD->X() - r.X() - 10, GdcD->Y() - r.Y() - 10); SetPos(r); #else SetPos(r); Chk; MoveToCenter(); #endif Chk; d = new AppWndPrivate(this); Name(AppName); SetQuitOnClose(true); Chk; #if WINNATIVE SetIcon((char*)MAKEINTRESOURCE(IDI_APP)); #else SetIcon("Icon64.png"); #endif Chk; if (Attach(0)) { Chk; Menu = new GMenu; if (Menu) { Menu->Attach(this); bool Loaded = Menu->Load(this, "IDM_MENU"); LgiAssert(Loaded); if (Loaded) { d->RecentFilesMenu = Menu->FindSubMenu(IDM_RECENT_FILES); d->RecentProjectsMenu = Menu->FindSubMenu(IDM_RECENT_PROJECTS); d->WindowsMenu = Menu->FindSubMenu(IDM_WINDOW_LST); d->CreateMakefileMenu = Menu->FindSubMenu(IDM_CREATE_MAKEFILE); if (d->CreateMakefileMenu) { d->CreateMakefileMenu->Empty(); for (int i=0; PlatformNames[i]; i++) { d->CreateMakefileMenu->AppendItem(PlatformNames[i], IDM_MAKEFILE_BASE + i); } } else LgiTrace("%s:%i - FindSubMenu failed.\n", _FL); GMenuItem *Debug = GetMenu()->FindItem(IDM_DEBUG_MODE); if (Debug) { Debug->Checked(true); } else LgiTrace("%s:%i - FindSubMenu failed.\n", _FL); d->UpdateMenus(); } } Chk; GToolBar *Tools; if (GdcD->Y() > 1200) Tools = LgiLoadToolbar(this, "cmds-32px.png", 32, 32); else Tools = LgiLoadToolbar(this, "cmds-16px.png", 16, 16); if (Tools) { Chk; Tools->AppendButton("New", IDM_NEW, TBT_PUSH, true, CMD_NEW); Tools->AppendButton("Open", IDM_OPEN, TBT_PUSH, true, CMD_OPEN); Tools->AppendButton("Save", IDM_SAVE_ALL, TBT_PUSH, true, CMD_SAVE_ALL); Tools->AppendSeparator(); Tools->AppendButton("Cut", IDM_CUT, TBT_PUSH, true, CMD_CUT); Tools->AppendButton("Copy", IDM_COPY, TBT_PUSH, true, CMD_COPY); Tools->AppendButton("Paste", IDM_PASTE, TBT_PUSH, true, CMD_PASTE); Tools->AppendSeparator(); Chk; Tools->AppendButton("Compile", IDM_COMPILE, TBT_PUSH, true, CMD_COMPILE); Tools->AppendButton("Build", IDM_BUILD, TBT_PUSH, true, CMD_BUILD); Tools->AppendButton("Stop", IDM_STOP_BUILD, TBT_PUSH, true, CMD_STOP_BUILD); // Tools->AppendButton("Execute", IDM_EXECUTE, TBT_PUSH, true, CMD_EXECUTE); Tools->AppendSeparator(); Tools->AppendButton("Debug", IDM_START_DEBUG, TBT_PUSH, true, CMD_DEBUG); Tools->AppendButton("Pause", IDM_PAUSE_DEBUG, TBT_PUSH, true, CMD_PAUSE); Tools->AppendButton("Restart", IDM_RESTART_DEBUGGING, TBT_PUSH, true, CMD_RESTART); Tools->AppendButton("Kill", IDM_STOP_DEBUG, TBT_PUSH, true, CMD_KILL); Tools->AppendButton("Step Into", IDM_STEP_INTO, TBT_PUSH, true, CMD_STEP_INTO); Tools->AppendButton("Step Over", IDM_STEP_OVER, TBT_PUSH, true, CMD_STEP_OVER); Tools->AppendButton("Step Out", IDM_STEP_OUT, TBT_PUSH, true, CMD_STEP_OUT); Tools->AppendButton("Run To", IDM_RUN_TO, TBT_PUSH, true, CMD_RUN_TO); Tools->AppendSeparator(); Tools->AppendButton("Find In Files", IDM_FIND_IN_FILES, TBT_PUSH, true, CMD_FIND_IN_FILES); Tools->GetCss(true)->Padding("4px"); Tools->Attach(this); } else LgiTrace("%s:%i - No tools obj?", _FL); Chk; GVariant v = 270, OutPx = 250; d->Options.GetValue(OPT_SPLIT_PX, v); d->Options.GetValue(OPT_OUTPUT_PX, OutPx); AddView(d->VBox = new GBox); d->VBox->SetVertical(true); d->HBox = new GBox; d->VBox->AddView(d->HBox); d->VBox->AddView(d->Output = new IdeOutput(this)); d->HBox->AddView(d->Tree = new IdeTree); if (d->Tree) { d->Tree->SetImageList(d->Icons, false); d->Tree->Sunken(false); } d->HBox->AddView(d->Mdi = new GMdiParent); if (d->Mdi) { d->Mdi->HasButton(true); } Chk; d->HBox->Value(MAX(v.CastInt32(), 20)); GRect c = GetClient(); if (c.Y() > OutPx.CastInt32()) { GCss::Len y(GCss::LenPx, OutPx.CastDouble()); d->Output->GetCss(true)->Height(y); } AttachChildren(); OnPosChange(); Chk; #ifdef LINUX GString f = LgiFindFile("lgiide.png"); if (f) { // Handle()->setIcon(f); } #endif UpdateState(); Chk; Visible(true); DropTarget(true); Chk; SetPulse(1000); } #ifdef LINUX LgiFinishXWindowsStartup(this); #endif #if USE_HAIKU_PULSE_HACK d->Output->SetPulse(1000); #endif Chk; } AppWnd::~AppWnd() { if (d->HBox) { GVariant v = d->HBox->Value(); d->Options.SetValue(OPT_SPLIT_PX, v); } if (d->Output) { GVariant v = d->Output->Y(); d->Options.SetValue(OPT_OUTPUT_PX, v); } ShutdownFtpThread(); CloseAll(); LgiApp->AppWnd = 0; DeleteObj(d); } void AppWnd::OnPulse() { IdeDoc *Top = TopDoc(); if (Top) Top->OnPulse(); } GDebugContext *AppWnd::GetDebugContext() { return d->DbgContext; } struct DumpBinThread : public LThread { GStream *Out; GString InFile; bool IsLib; public: DumpBinThread(GStream *out, GString file) : LThread("DumpBin.Thread") { Out = out; InFile = file; DeleteOnExit = true; auto Ext = LgiGetExtension(InFile); IsLib = Ext && !stricmp(Ext, "lib"); Run(); } bool DumpBin(GString Args, GStream *Str) { char Buf[256]; ssize_t Rd; GSubProcess s("c:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\VC\\bin\\amd64\\dumpbin.exe", Args); if (!s.Start(true, false)) return false; while ((Rd = s.Read(Buf, sizeof(Buf))) > 0) Str->Write(Buf, Rd); return true; } GString::Array Dependencies() { GString Args; GStringPipe p; Args.Printf("/dependents \"%s\"", InFile.Get()); DumpBin(Args, &p); auto Parts = p.NewGStr().Replace("\r", "").Split("\n\n"); auto Files = Parts[4].Strip().Split("\n"); auto Path = LGetPath(); for (auto &f : Files) { f = f.Strip(); bool Found = false; for (auto s : Path) { GFile::Path c(s); c += f.Get(); if (c.IsFile()) { f = c.GetFull(); Found = true; break; } } if (!Found) f += " (not found in path)"; } return Files; } GString GetArch() { GString Args; GStringPipe p; Args.Printf("/headers \"%s\"", InFile.Get()); DumpBin(Args, &p); const char *Key = " machine "; GString Arch; auto Lines = p.NewGStr().SplitDelimit("\r\n"); int64 Machine = 0; for (auto &Ln : Lines) { if (Ln.Find(Key) >= 0) { auto p = Ln.Strip().Split(Key); if (p.Length() == 2) { Arch = p[1].Strip("()"); Machine = p[0].Int(16); } } } if (Machine == 0x14c) Arch += " 32bit"; else if (Machine == 0x200) Arch += " 64bit Itanium"; else if (Machine == 0x8664) Arch += " 64bit"; return Arch; } GString GetExports() { GString Args; GStringPipe p; if (IsLib) Args.Printf("/symbols \"%s\"", InFile.Get()); else Args.Printf("/exports \"%s\"", InFile.Get()); DumpBin(Args, &p); GString Exp; auto Sect = p.NewGStr().Replace("\r", "").Split("\n\n"); if (IsLib) { GString::Array Lines, Funcs; for (auto &s : Sect) { if (s.Find("COFF", 0, 100) == 0) { Lines = s.Split("\n"); break; } } Funcs.SetFixedLength(false); for (auto &l : Lines) { if (l.Length() < 34) continue; const char *Type = l.Get() + 33; if (!Strnicmp(Type, "External", 8)) { auto Nm = l.RSplit("|",1).Last().Strip(); if (!strchr("@$.?", Nm(0))) Funcs.New() = Nm; } } Exp = GString("\n").Join(Funcs); } else { bool Ord = false; for (auto &s : Sect) { if (s.Strip().Find("ordinal") == 0) Ord = true; else if (Ord) { Exp = s; break; } else Ord = false; } } return Exp; } int Main() { if (!IsLib) { auto Deps = Dependencies(); Out->Print("Dependencies:\n\t%s\n\n", GString("\n\t").Join(Deps).Get()); } auto Arch = GetArch(); if (Arch) Out->Print("Arch: %s\n\n", Arch.Get()); auto Exp = GetExports(); if (Arch) Out->Print("Exports:\n%s\n\n", Exp.Get()); return 0; } }; void AppWnd::OnReceiveFiles(GArray &Files) { for (int i=0; iSetFileName(Docs, false); new DumpBinThread(Doc, Files[i]); } } else { OpenFile(f); } } Raise(); } void AppWnd::OnDebugState(bool Debugging, bool Running) { // Make sure this event is processed in the GUI thread. #if DEBUG_SESSION_LOGGING LgiTrace("AppWnd::OnDebugState(%i,%i) InThread=%i\n", Debugging, Running, InThread()); #endif PostEvent(M_DEBUG_ON_STATE, Debugging, Running); } bool IsVarChar(GString &s, int pos) { if (pos < 0) return false; if (pos >= s.Length()) return false; char i = s[pos]; return IsAlpha(i) || IsDigit(i) || i == '_'; } bool ReplaceWholeWord(GString &Ln, GString Word, GString NewWord) { int Pos = 0; bool Status = false; while (Pos >= 0) { Pos = Ln.Find(Word, Pos); if (Pos < 0) return Status; int End = Pos + Word.Length(); if (!IsVarChar(Ln, Pos-1) && !IsVarChar(Ln, End)) { GString NewLn = Ln(0,Pos) + NewWord + Ln(End,-1); Ln = NewLn; Status = true; } Pos++; } return Status; } struct LFileInfo { GString Path; GString::Array Lines; bool Dirty; LFileInfo() { Dirty = false; } bool Save() { GFile f; if (!f.Open(Path, O_WRITE)) return false; GString NewFile = GString("\n").Join(Lines); f.SetSize(0); f.Write(NewFile); f.Close(); return true; } }; void AppWnd::OnFixBuildErrors() { LHashTbl, GString> Map; GVariant v; if (GetOptions()->GetValue(OPT_RENAMED_SYM, v)) { auto Lines = GString(v.Str()).Split("\n"); for (auto Ln: Lines) { auto p = Ln.SplitDelimit(); if (p.Length() == 2) Map.Add(p[0], p[1]); } if (Map.Length() == 0) { LgiMsg(this, "No renamed symbols defined.", AppName); return; } } else return; GString Raw = d->Output->Txt[AppWnd::BuildTab]->Name(); GString::Array Lines = Raw.Split("\n"); - GProgressDlg Prog(this); - Prog.SetDescription("Parsing errors..."); - Prog.SetLimits(0, Lines.Length()); - Prog.SetYieldTime(300); + auto *Log = d->Output->Txt[AppWnd::OutputTab]; + + Log->Name(NULL); + Log->Print("Parsing errors...\n"); int i = 0; int Replacements = 0; GArray Files; for (auto Ln : Lines) { - if (Ln.Find("error") >= 0) + auto ErrPos = Ln.Find("error"); + if (ErrPos >= 0) { + Log->Print("Error pos = %i\n", (int)ErrPos); + #ifdef WINDOWS GString::Array p = Ln.SplitDelimit(">()"); + #else + GString::Array p = Ln(0, ErrPos).Strip().SplitDelimit(":"); + #endif + Log->Print("p.Len = %i\n", (int)p.Length()); if (p.Length() > 2) { + #ifdef WINDOWS int Base = p[0].IsNumeric() ? 1 : 0; GString Fn = p[Base]; if (Fn.Find("Program Files") >= 0) continue; + auto LineNo = p[Base+1].Int(); + #else + GString Fn = p[0]; + auto LineNo = p[1].Int(); + #endif GAutoString Full; - if (d->FindSource(Full, p[Base], NULL)) + if (d->FindSource(Full, Fn, NULL)) { - auto LineNo = p[Base+1].Int(); - LFileInfo *Fi = NULL; for (auto &i: Files) { if (i.Path.Equals(Full)) { Fi = &i; break; } } if (!Fi) { GFile f(Full, O_READ); if (f.IsOpen()) { Fi = &Files.New(); Fi->Path = Full.Get(); auto OldFile = f.Read(); Fi->Lines = OldFile.SplitDelimit("\n", -1, false); } } if (Fi) { if (LineNo <= Fi->Lines.Length()) { GString &s = Fi->Lines[LineNo-1]; for (auto i: Map) { if (ReplaceWholeWord(s, i.key, i.value)) { Fi->Dirty = true; Replacements++; } } } } else { int asd=0; } } } } - - Prog.Value(++i); - if (Prog.IsCancelled()) - break; } for (auto &Fi : Files) { if (Fi.Dirty) Fi.Save(); } - if (Replacements) - LgiMsg(this, "%i replacements made.", AppName, MB_OK, Replacements); + Log->Print("%i replacements made.\n", Replacements); + d->Output->Value(AppWnd::OutputTab); } void AppWnd::OnBuildStateChanged(bool NewState) { GVariant v; if (!NewState && GetOptions()->GetValue(OPT_FIX_RENAMED, v) && v.CastInt32()) { OnFixBuildErrors(); } } void AppWnd::UpdateState(int Debugging, int Building) { if (Debugging >= 0) d->Debugging = Debugging; if (Building >= 0) { if (d->Building != (Building != 0)) OnBuildStateChanged(Building); d->Building = Building; } SetCtrlEnabled(IDM_COMPILE, !d->Building); SetCtrlEnabled(IDM_BUILD, !d->Building); SetCtrlEnabled(IDM_STOP_BUILD, d->Building); // SetCtrlEnabled(IDM_RUN, !d->Building); // SetCtrlEnabled(IDM_TOGGLE_BREAKPOINT, !d->Building); SetCtrlEnabled(IDM_START_DEBUG, !d->Debugging && !d->Building); SetCtrlEnabled(IDM_PAUSE_DEBUG, d->Debugging); SetCtrlEnabled(IDM_RESTART_DEBUGGING, d->Debugging); SetCtrlEnabled(IDM_STOP_DEBUG, d->Debugging); SetCtrlEnabled(IDM_STEP_INTO, d->Debugging); SetCtrlEnabled(IDM_STEP_OVER, d->Debugging); SetCtrlEnabled(IDM_STEP_OUT, d->Debugging); SetCtrlEnabled(IDM_RUN_TO, d->Debugging); } void AppWnd::AppendOutput(char *Txt, AppWnd::Channels Channel) { if (!d->Output) { LgiTrace("%s:%i - No output panel.\n", _FL); return; } if (Channel < 0 || Channel >= CountOf(d->Output->Txt)) { LgiTrace("%s:%i - Channel range: %i, %i.\n", _FL, Channel, CountOf(d->Output->Txt)); return; } if (!d->Output->Txt[Channel]) { LgiTrace("%s:%i - No log for channel %i.\n", _FL, Channel); return; } if (Txt) { d->Output->Buf[Channel].Add(Txt, strlen(Txt)); } else { d->Output->Txt[Channel]->Name(""); } } void AppWnd::SaveAll() { List::I Docs = d->Docs.begin(); for (IdeDoc *Doc = *Docs; Doc; Doc = *++Docs) { Doc->SetClean(); d->OnFile(Doc->GetFileName()); } List::I Projs = d->Projects.begin(); for (IdeProject *Proj = *Projs; Proj; Proj = *++Projs) { Proj->SetClean(); d->OnFile(Proj->GetFileName(), true); } } void AppWnd::CloseAll() { SaveAll(); while (d->Docs.First()) delete d->Docs.First(); IdeProject *p = RootProject(); if (p) DeleteObj(p); while (d->Projects.First()) delete d->Projects.First(); DeleteObj(d->DbgContext); } bool AppWnd::OnRequestClose(bool IsClose) { SaveAll(); return GWindow::OnRequestClose(IsClose); } bool AppWnd::OnBreakPoint(GDebugger::BreakPoint &b, bool Add) { List::I it = d->Docs.begin(); for (IdeDoc *doc = *it; doc; doc = *++it) { char *fn = doc->GetFileName(); bool Match = !_stricmp(fn, b.File); if (Match) { doc->AddBreakPoint(b.Line, Add); } } if (d->DbgContext) { d->DbgContext->OnBreakPoint(b, Add); } return true; } bool AppWnd::LoadBreakPoints(IdeDoc *doc) { if (!doc) return false; char *fn = doc->GetFileName(); for (int i=0; iBreakPoints.Length(); i++) { GDebugger::BreakPoint &b = d->BreakPoints[i]; if (!_stricmp(fn, b.File)) { doc->AddBreakPoint(b.Line, true); } } return true; } bool AppWnd::LoadBreakPoints(GDebugger *db) { if (!db) return false; for (int i=0; iBreakPoints.Length(); i++) { GDebugger::BreakPoint &bp = d->BreakPoints[i]; db->SetBreakPoint(&bp); } return true; } bool AppWnd::ToggleBreakpoint(const char *File, ssize_t Line) { bool DeleteBp = false; for (int i=0; iBreakPoints.Length(); i++) { GDebugger::BreakPoint &b = d->BreakPoints[i]; if (!_stricmp(File, b.File) && b.Line == Line) { OnBreakPoint(b, false); d->BreakPoints.DeleteAt(i); DeleteBp = true; break; } } if (!DeleteBp) { GDebugger::BreakPoint &b = d->BreakPoints.New(); b.File = File; b.Line = Line; OnBreakPoint(b, true); } return true; } void AppWnd::DumpHistory() { #if 0 LgiTrace("History %i of %i\n", d->HistoryLoc, d->CursorHistory.Length()); for (int i=0; iCursorHistory.Length(); i++) { FileLoc &p = d->CursorHistory[i]; LgiTrace(" [%i] = %s, %i %s\n", i, p.File.Get(), p.Line, d->HistoryLoc == i ? "<-----":""); } #endif } /* void CheckHistory(GArray &CursorHistory) { if (CursorHistory.Length() > 0) { FileLoc *loc = &CursorHistory[0]; for (unsigned i=CursorHistory.Length(); iInHistorySeek) { if (d->CursorHistory.Length() > 0) { FileLoc &Last = d->CursorHistory.Last(); if (_stricmp(File, Last.File) == 0 && abs(Last.Line - Line) <= 1) { // Previous or next line... just update line number Last.Line = Line; DumpHistory(); return; } // Add new entry d->HistoryLoc++; FileLoc &loc = d->CursorHistory[d->HistoryLoc]; #ifdef WIN64 if ((NativeInt)loc.File.Get() == 0xcdcdcdcdcdcdcdcd) LgiAssert(0); // wtf? else #endif loc.Set(File, Line); } else { // Add new entry d->CursorHistory[0].Set(File, Line); } // Destroy any history after the current... d->CursorHistory.Length(d->HistoryLoc+1); DumpHistory(); } } void AppWnd::OnFile(char *File, bool IsProject) { d->OnFile(File, IsProject); } IdeDoc *AppWnd::NewDocWnd(const char *FileName, NodeSource *Src) { IdeDoc *Doc = new IdeDoc(this, Src, 0); if (Doc) { d->Docs.Insert(Doc); GRect p = d->Mdi->NewPos(); Doc->SetPos(p); Doc->Attach(d->Mdi); Doc->Focus(true); Doc->Raise(); if (FileName) d->OnFile(FileName); } return Doc; } IdeDoc *AppWnd::GetCurrentDoc() { if (d->Mdi) return dynamic_cast(d->Mdi->GetTop()); return NULL; } IdeDoc *AppWnd::GotoReference(const char *File, int Line, bool CurIp, bool WithHistory) { if (!WithHistory) d->InHistorySeek = true; IdeDoc *Doc = File ? OpenFile(File) : GetCurrentDoc(); if (Doc) Doc->SetLine(Line, CurIp); /* else LgiTrace("%s:%i - No file '%s' found.\n", _FL, File); */ if (!WithHistory) d->InHistorySeek = false; return Doc; } IdeDoc *AppWnd::FindOpenFile(char *FileName) { List::I it = d->Docs.begin(); for (IdeDoc *i=*it; i; i=*++it) { char *f = i->GetFileName(); if (f) { IdeProject *p = i->GetProject(); if (p) { GAutoString Base = p->GetBasePath(); if (Base) { char Path[MAX_PATH]; if (*f == '.') LgiMakePath(Path, sizeof(Path), Base, f); else strcpy_s(Path, sizeof(Path), f); if (stricmp(Path, FileName) == 0) return i; } } else { if (stricmp(f, FileName) == 0) return i; } } } return 0; } IdeDoc *AppWnd::OpenFile(const char *FileName, NodeSource *Src) { static bool DoingProjectFind = false; IdeDoc *Doc = 0; const char *File = Src ? Src->GetFileName() : FileName; if (!Src && !ValidStr(File)) { LgiTrace("%s:%i - No source or file?\n", _FL); return NULL; } GString FullPath; if (LgiIsRelativePath(File)) { IdeProject *Proj = Src && Src->GetProject() ? Src->GetProject() : RootProject(); if (Proj) { List Projs; Projs.Insert(Proj); Proj->CollectAllSubProjects(Projs); for (auto Project : Projs) { GAutoString ProjPath = Project->GetBasePath(); char p[MAX_PATH]; LgiMakePath(p, sizeof(p), ProjPath, File); if (FileExists(p)) { FullPath = p; File = FullPath; break; } } } } Doc = d->IsFileOpen(File); if (!Doc) { if (Src) { Doc = NewDocWnd(File, Src); } else if (!DoingProjectFind) { DoingProjectFind = true; List::I Proj = d->Projects.begin(); for (IdeProject *p=*Proj; p && !Doc; p=*++Proj) { p->InProject(LgiIsRelativePath(File), File, true, &Doc); } DoingProjectFind = false; d->OnFile(File); } } if (!Doc && FileExists(File)) { Doc = new IdeDoc(this, 0, File); if (Doc) { GRect p = d->Mdi->NewPos(); Doc->SetPos(p); d->Docs.Insert(Doc); d->OnFile(File); } } if (Doc) { #ifdef BEOS BView *h = Doc->Handle(); BWindow *w = h ? h->Window() : 0; bool att = Doc->IsAttached(); printf("%s:%i - att=%i h=%p w=%p\n", _FL, att, h, w); #endif if (!Doc->IsAttached()) { Doc->Attach(d->Mdi); } Doc->Focus(true); Doc->Raise(); } return Doc; } IdeProject *AppWnd::RootProject() { IdeProject *Root = 0; for (IdeProject *p=d->Projects.First(); p; p=d->Projects.Next()) { if (!p->GetParentProject()) { LgiAssert(Root == 0); Root = p; } } return Root; } IdeProject *AppWnd::OpenProject(char *FileName, IdeProject *ParentProj, bool Create, bool Dep) { if (!FileName) { LgiTrace("%s:%i - Error: No filename.\n", _FL); return NULL; } if (d->IsProjectOpen(FileName)) { LgiTrace("%s:%i - Warning: Project already open.\n", _FL); return NULL; } IdeProject *p = new IdeProject(this); if (!p) { LgiTrace("%s:%i - Error: mem alloc.\n", _FL); return NULL; } GString::Array Inc; p->BuildIncludePaths(Inc, false, false, PlatformCurrent); d->FindSym->SetIncludePaths(Inc); p->SetParentProject(ParentProj); ProjectStatus Status = p->OpenFile(FileName); if (Status == OpenOk) { d->Projects.Insert(p); d->OnFile(FileName, true); if (!Dep) { char *d = strrchr(FileName, DIR_CHAR); if (d++) { char n[256]; sprintf(n, "%s [%s]", AppName, d); Name(n); } } } else { LgiTrace("%s:%i - Failed to open '%s'\n", _FL, FileName); DeleteObj(p); if (Status == OpenError) d->RemoveRecent(FileName); } if (!GetTree()->Selection()) { GetTree()->Select(GetTree()->GetChild()); } GetTree()->Focus(true); return p; } GMessage::Result AppWnd::OnEvent(GMessage *m) { switch (MsgCode(m)) { case M_START_BUILD: { IdeProject *p = RootProject(); if (p) p->Build(true, IsReleaseMode()); else printf("%s:%i - No root project.\n", _FL); break; } case M_BUILD_DONE: { UpdateState(-1, false); IdeProject *p = RootProject(); if (p) p->StopBuild(); break; } case M_BUILD_ERR: { char *Msg = (char*)MsgB(m); if (Msg) { d->Output->Txt[AppWnd::BuildTab]->Print("Build Error: %s\n", Msg); DeleteArray(Msg); } break; } case M_APPEND_TEXT: { char *Text = (char*) MsgA(m); Channels Ch = (Channels) MsgB(m); AppendOutput(Text, Ch); DeleteArray(Text); break; } case M_DEBUG_ON_STATE: { bool Debugging = m->A(); bool Running = m->B(); if (d->Running != Running) { bool RunToNotRun = d->Running && !Running; d->Running = Running; if (RunToNotRun && d->Output && d->Output->DebugTab) { d->Output->DebugTab->SendNotify(GNotifyValueChanged); } } if (d->Debugging != Debugging) { d->Debugging = Debugging; if (!Debugging) { IdeDoc::ClearCurrentIp(); IdeDoc *c = GetCurrentDoc(); if (c) c->UpdateControl(); // Shutdown the debug context and free the memory DeleteObj(d->DbgContext); } } SetCtrlEnabled(IDM_START_DEBUG, !Debugging || !Running); SetCtrlEnabled(IDM_PAUSE_DEBUG, Debugging && Running); SetCtrlEnabled(IDM_RESTART_DEBUGGING, Debugging); SetCtrlEnabled(IDM_STOP_DEBUG, Debugging); SetCtrlEnabled(IDM_STEP_INTO, Debugging && !Running); SetCtrlEnabled(IDM_STEP_OVER, Debugging && !Running); SetCtrlEnabled(IDM_STEP_OUT, Debugging && !Running); SetCtrlEnabled(IDM_RUN_TO, Debugging && !Running); break; } default: { if (d->DbgContext) d->DbgContext->OnEvent(m); break; } } return GWindow::OnEvent(m); } bool AppWnd::OnNode(const char *Path, ProjectNode *Node, FindSymbolSystem::SymAction Action) { // This takes care of adding/removing files from the symbol search engine. if (!Path || !Node) return false; d->FindSym->OnFile(Path, Action, Node->GetPlatforms()); return true; } GOptionsFile *AppWnd::GetOptions() { return &d->Options; } class Options : public GDialog { AppWnd *App; GFontType Font; public: Options(AppWnd *a) { SetParent(App = a); if (LoadFromResource(IDD_OPTIONS)) { SetCtrlEnabled(IDC_FONT, false); MoveToCenter(); if (!Font.Serialize(App->GetOptions(), OPT_EditorFont, false)) { Font.GetSystemFont("Fixed"); } char s[256]; if (Font.GetDescription(s, sizeof(s))) { SetCtrlName(IDC_FONT, s); } GVariant v; if (App->GetOptions()->GetValue(OPT_Jobs, v)) SetCtrlValue(IDC_JOBS, v.CastInt32()); else SetCtrlValue(IDC_JOBS, 2); DoModal(); } } int OnNotify(GViewI *c, int f) { switch (c->GetId()) { case IDOK: { GVariant v; Font.Serialize(App->GetOptions(), OPT_EditorFont, true); App->GetOptions()->SetValue(OPT_Jobs, v = GetCtrlValue(IDC_JOBS)); } case IDCANCEL: { EndModal(c->GetId()); break; } case IDC_SET_FONT: { if (Font.DoUI(this)) { char s[256]; if (Font.GetDescription(s, sizeof(s))) { SetCtrlName(IDC_FONT, s); } } break; } } return 0; } }; void AppWnd::UpdateMemoryDump() { if (d->DbgContext) { char *sWord = GetCtrlName(IDC_MEM_SIZE); int iWord = sWord ? atoi(sWord) : 1; int64 RowLen = GetCtrlValue(IDC_MEM_ROW_LEN); bool InHex = GetCtrlValue(IDC_MEM_HEX) != 0; d->DbgContext->FormatMemoryDump(iWord, (int)RowLen, InHex); } } int AppWnd::OnNotify(GViewI *Ctrl, int Flags) { switch (Ctrl->GetId()) { case IDC_PROJECT_TREE: { if (Flags == GNotify_DeleteKey) { ProjectNode *n = dynamic_cast(d->Tree->Selection()); if (n) n->Delete(); } break; } case IDC_DEBUG_EDIT: { if (Flags == VK_RETURN && d->DbgContext) { char *Cmd = Ctrl->Name(); if (Cmd) { d->DbgContext->OnUserCommand(Cmd); Ctrl->Name(NULL); } } break; } case IDC_MEM_ADDR: { if (Flags == VK_RETURN) { if (d->DbgContext) { char *s = Ctrl->Name(); if (s) { char *sWord = GetCtrlName(IDC_MEM_SIZE); int iWord = sWord ? atoi(sWord) : 1; d->DbgContext->OnMemoryDump(s, iWord, (int)GetCtrlValue(IDC_MEM_ROW_LEN), GetCtrlValue(IDC_MEM_HEX) != 0); } else if (d->DbgContext->MemoryDump) { d->DbgContext->MemoryDump->Print("No address specified."); } else { LgiAssert(!"No MemoryDump."); } } else LgiAssert(!"No debug context."); } break; } case IDC_MEM_ROW_LEN: { if (Flags == VK_RETURN) UpdateMemoryDump(); break; } case IDC_MEM_HEX: case IDC_MEM_SIZE: { UpdateMemoryDump(); break; } case IDC_DEBUG_TAB: { if (d->DbgContext && Flags == GNotifyValueChanged) { switch (Ctrl->Value()) { case AppWnd::LocalsTab: { d->DbgContext->UpdateLocals(); break; } case AppWnd::WatchTab: { d->DbgContext->UpdateWatches(); break; } case AppWnd::RegistersTab: { d->DbgContext->UpdateRegisters(); break; } case AppWnd::CallStackTab: { d->DbgContext->UpdateCallStack(); break; } case AppWnd::ThreadsTab: { d->DbgContext->UpdateThreads(); break; } default: break; } } break; } case IDC_LOCALS_LIST: { if (d->Output->Locals && Flags == GNotifyItem_DoubleClick && d->DbgContext) { LListItem *it = d->Output->Locals->GetSelected(); if (it) { char *Var = it->GetText(2); char *Val = it->GetText(3); if (Var) { if (d->Output->DebugTab) d->Output->DebugTab->Value(AppWnd::ObjectTab); d->DbgContext->DumpObject(Var, Val); } } } break; } case IDC_CALL_STACK: { if (Flags == M_CHANGE) { if (d->Output->DebugTab) d->Output->DebugTab->Value(AppWnd::CallStackTab); } else if (Flags == GNotifyItem_Select) { // This takes the user to a given call stack reference if (d->Output->CallStack && d->DbgContext) { LListItem *item = d->Output->CallStack->GetSelected(); if (item) { GAutoString File; int Line; if (d->DbgContext->ParseFrameReference(item->GetText(1), File, Line)) { GAutoString Full; if (d->FindSource(Full, File, NULL)) { GotoReference(Full, Line, false); char *sFrame = item->GetText(0); if (sFrame && IsDigit(*sFrame)) d->DbgContext->SetFrame(atoi(sFrame)); } } } } } break; } case IDC_WATCH_LIST: { WatchItem *Edit = NULL; switch (Flags) { case GNotify_DeleteKey: { GArray Sel; for (GTreeItem *c = d->Output->Watch->GetChild(); c; c = c->GetNext()) { if (c->Select()) Sel.Add(c); } Sel.DeleteObjects(); break; } case GNotifyItem_Click: { Edit = dynamic_cast(d->Output->Watch->Selection()); break; } case GNotifyContainer_Click: { // Create new watch. Edit = new WatchItem(d->Output); if (Edit) d->Output->Watch->Insert(Edit); break; } } if (Edit) Edit->EditLabel(0); break; } case IDC_THREADS: { if (Flags == GNotifyItem_Select) { // This takes the user to a given thread if (d->Output->Threads && d->DbgContext) { LListItem *item = d->Output->Threads->GetSelected(); if (item) { GString sId = item->GetText(0); int ThreadId = (int)sId.Int(); if (ThreadId > 0) { d->DbgContext->SelectThread(ThreadId); } } } } break; } } return 0; } bool AppWnd::IsReleaseMode() { GMenuItem *Release = GetMenu()->FindItem(IDM_RELEASE_MODE); bool IsRelease = Release ? Release->Checked() : false; return IsRelease; } bool AppWnd::Build() { SaveAll(); IdeDoc *Top; IdeProject *p = RootProject(); if (p) { UpdateState(-1, true); GMenuItem *Release = GetMenu()->FindItem(IDM_RELEASE_MODE); bool IsRelease = Release ? Release->Checked() : false; p->Build(false, IsRelease); return true; } else if ((Top = TopDoc())) { return Top->Build(); } return false; } class RenameDlg : public GDialog { AppWnd *App; public: RenameDlg(AppWnd *a) { SetParent(App = a); MoveSameScreen(a); if (LoadFromResource(IDC_RENAME)) { GVariant v; if (App->GetOptions()->GetValue(OPT_FIX_RENAMED, v)) SetCtrlValue(IDC_FIX_RENAMED, v.CastInt32()); if (App->GetOptions()->GetValue(OPT_RENAMED_SYM, v)) SetCtrlName(IDC_SYM, v.Str()); } } int OnNotify(GViewI *c, int f) { switch (c->GetId()) { case IDOK: { GVariant v; App->GetOptions()->SetValue(OPT_RENAMED_SYM, v = GetCtrlName(IDC_SYM)); App->GetOptions()->SetValue(OPT_FIX_RENAMED, v = GetCtrlValue(IDC_FIX_RENAMED)); } case IDCANCEL: { EndModal(c->GetId() == IDOK); break; } } return 0; } }; bool AppWnd::ShowInProject(const char *Fn) { if (!Fn) return false; for (IdeProject *p=d->Projects.First(); p; p=d->Projects.Next()) { ProjectNode *Node = NULL; if (p->FindFullPath(Fn, &Node)) { for (GTreeItem *i = Node->GetParent(); i; i = i->GetParent()) { i->Expanded(true); } Node->Select(true); Node->ScrollTo(); return true; } } return false; } int AppWnd::OnCommand(int Cmd, int Event, OsView Wnd) { switch (Cmd) { case IDM_EXIT: { LgiCloseApp(); break; } case IDM_OPTIONS: { Options Dlg(this); break; } case IDM_HELP: { LgiExecute(APP_URL); break; } case IDM_ABOUT: { GAbout a(this, AppName, APP_VER, "\nLGI Integrated Development Environment", "icon128.png", APP_URL, "fret@memecode.com"); break; } case IDM_NEW: { IdeDoc *Doc; d->Docs.Insert(Doc = new IdeDoc(this, 0, 0)); if (Doc) { GRect p = d->Mdi->NewPos(); Doc->SetPos(p); Doc->Attach(d->Mdi); Doc->Focus(true); } break; } case IDM_OPEN: { GFileSelect s; s.Parent(this); if (s.Open()) { OpenFile(s.Name()); } break; } case IDM_SAVE_ALL: { SaveAll(); break; } case IDM_SAVE: { IdeDoc *Top = TopDoc(); if (Top) Top->SetClean(); break; } case IDM_SAVEAS: { IdeDoc *Top = TopDoc(); if (Top) { GFileSelect s; s.Parent(this); if (s.Save()) { Top->SetFileName(s.Name(), true); d->OnFile(s.Name()); } } break; } case IDM_CLOSE: { IdeDoc *Top = TopDoc(); if (Top) { if (Top->OnRequestClose(false)) { Top->Quit(); } } DeleteObj(d->DbgContext); break; } case IDM_CLOSE_ALL: { CloseAll(); Name(AppName); break; } // // Editor // case IDM_UNDO: { GTextView3 *Doc = FocusEdit(); if (Doc) { Doc->Undo(); } else LgiTrace("%s:%i - No focus doc.\n", _FL); break; } case IDM_REDO: { GTextView3 *Doc = FocusEdit(); if (Doc) { Doc->Redo(); } else LgiTrace("%s:%i - No focus doc.\n", _FL); break; } case IDM_FIND: { GTextView3 *Doc = FocusEdit(); if (Doc) { Doc->DoFind(); } else LgiTrace("%s:%i - No focus doc.\n", _FL); break; } case IDM_FIND_NEXT: { GTextView3 *Doc = FocusEdit(); if (Doc) { Doc->DoFindNext(); } else LgiTrace("%s:%i - No focus doc.\n", _FL); break; } case IDM_REPLACE: { GTextView3 *Doc = FocusEdit(); if (Doc) { Doc->DoReplace(); } else LgiTrace("%s:%i - No focus doc.\n", _FL); break; } case IDM_GOTO: { GTextView3 *Doc = FocusEdit(); if (Doc) Doc->DoGoto(); else { GInput Inp(this, NULL, LgiLoadString(L_TEXTCTRL_GOTO_LINE, "Goto [file:]line:"), "Goto"); if (Inp.DoModal()) { GString s = Inp.GetStr(); GString::Array p = s.SplitDelimit(":,"); if (p.Length() == 2) { GString file = p[0]; int line = (int)p[1].Int(); GotoReference(file, line, false, true); } else LgiMsg(this, "Error: Needs a file name as well.", AppName); } } break; } case IDM_CUT: { GTextView3 *Doc = FocusEdit(); if (Doc) Doc->PostEvent(M_CUT); break; } case IDM_COPY: { GTextView3 *Doc = FocusEdit(); if (Doc) Doc->PostEvent(M_COPY); break; } case IDM_PASTE: { GTextView3 *Doc = FocusEdit(); if (Doc) Doc->PostEvent(M_PASTE); break; } case IDM_FIND_IN_FILES: { if (!d->Finder) { d->Finder.Reset(new FindInFilesThread(d->AppHnd)); } if (d->Finder) { if (!d->FindParameters && d->FindParameters.Reset(new FindParams)) { GVariant var; if (GetOptions()->GetValue(OPT_ENTIRE_SOLUTION, var)) d->FindParameters->Type = var.CastInt32() ? FifSearchSolution : FifSearchDirectory; } FindInFiles Dlg(this, d->FindParameters); GViewI *Focus = GetFocus(); if (Focus) { GTextView3 *Edit = dynamic_cast(Focus); if (Edit && Edit->HasSelection()) { GAutoString a(Edit->GetSelection()); Dlg.Params->Text = a; } } IdeProject *p = RootProject(); if (p) { GAutoString Base = p->GetBasePath(); if (Base) Dlg.Params->Dir = Base; } if (Dlg.DoModal()) { if (p && Dlg.Params->Type == FifSearchSolution) { Dlg.Params->ProjectFiles.Length(0); List Projects; Projects.Insert(p); p->GetChildProjects(Projects); GArray Nodes; for (IdeProject *p = Projects.First(); p; p = Projects.Next()) p->GetAllNodes(Nodes); for (unsigned i=0; iGetFullPath(); if (s) Dlg.Params->ProjectFiles.Add(s); } } GVariant var = d->FindParameters->Type == FifSearchSolution; GetOptions()->SetValue(OPT_ENTIRE_SOLUTION, var); d->Finder->Stop(); d->Finder->PostEvent(FindInFilesThread::M_START_SEARCH, (GMessage::Param) new FindParams(d->FindParameters)); } } break; } case IDM_FIND_SYMBOL: { IdeDoc *Doc = FocusDoc(); if (Doc) { Doc->GotoSearch(IDC_SYMBOL_SEARCH); } else { FindSymResult r = d->FindSym->OpenSearchDlg(this); if (r.File) { GotoReference(r.File, r.Line, false); } } break; } case IDM_GOTO_SYMBOL: { IdeDoc *Doc = FocusDoc(); if (Doc) { Doc->SearchSymbol(); } break; } case IDM_FIND_PROJECT_FILE: { IdeDoc *Doc = FocusDoc(); if (Doc) { Doc->SearchFile(); } else { FindInProject Dlg(this); Dlg.DoModal(); } break; } case IDM_FIND_REFERENCES: { GViewI *f = LgiApp->GetFocus(); GDocView *doc = dynamic_cast(f); if (!doc) break; ssize_t c = doc->GetCaret(); if (c < 0) break; GString Txt = doc->Name(); char *s = Txt.Get() + c; char *e = s; while ( s > Txt.Get() && IsSymbolChar(s[-1])) s--; while (*e && IsSymbolChar(*e)) e++; if (e <= s) break; GString Word(s, e - s); if (!d->Finder) d->Finder.Reset(new FindInFilesThread(d->AppHnd)); if (!d->Finder) break; IdeProject *p = RootProject(); if (!p) break; List Projects; Projects.Insert(p); p->GetChildProjects(Projects); GArray Nodes; for (p = Projects.First(); p; p = Projects.Next()) p->GetAllNodes(Nodes); GAutoPtr Params(new FindParams); Params->Type = FifSearchSolution; Params->MatchWord = true; Params->Text = Word; for (unsigned i = 0; i < Nodes.Length(); i++) { Params->ProjectFiles.New() = Nodes[i]->GetFullPath(); } d->Finder->Stop(); d->Finder->PostEvent(FindInFilesThread::M_START_SEARCH, (GMessage::Param) Params.Release()); break; } case IDM_PREV_LOCATION: { d->SeekHistory(-1); break; } case IDM_NEXT_LOCATION: { d->SeekHistory(1); break; } // // Project // case IDM_NEW_PROJECT: { CloseAll(); IdeProject *p; d->Projects.Insert(p = new IdeProject(this)); if (p) { p->CreateProject(); } break; } case IDM_OPEN_PROJECT: { GFileSelect s; s.Parent(this); s.Type("Projects", "*.xml"); if (s.Open()) { CloseAll(); OpenProject(s.Name(), NULL, Cmd == IDM_NEW_PROJECT); if (d->Tree) { d->Tree->Focus(true); } } break; } case IDM_IMPORT_DSP: { IdeProject *p = RootProject(); if (p) { GFileSelect s; s.Parent(this); s.Type("Developer Studio Project", "*.dsp"); if (s.Open()) { p->ImportDsp(s.Name()); } } break; } case IDM_RUN: { SaveAll(); IdeProject *p = RootProject(); if (p) { p->Execute(); } break; } case IDM_VALGRIND: { SaveAll(); IdeProject *p = RootProject(); if (p) { p->Execute(ExeValgrind); } break; } case IDM_FIX_MISSING_FILES: { IdeProject *p = RootProject(); if (p) p->FixMissingFiles(); else LgiMsg(this, "No project loaded.", AppName); break; } case IDM_FIND_DUPE_SYM: { IdeProject *p = RootProject(); if (p) p->FindDuplicateSymbols(); else LgiMsg(this, "No project loaded.", AppName); break; } case IDM_RENAME_SYM: { RenameDlg Dlg(this); Dlg.DoModal(); break; } case IDM_START_DEBUG: { SaveAll(); IdeProject *p = RootProject(); if (!p) { LgiMsg(this, "No project loaded.", "Error"); break; } if (d->DbgContext) { d->DbgContext->OnCommand(IDM_CONTINUE); } else if ((d->DbgContext = p->Execute(ExeDebug))) { d->DbgContext->DebuggerLog = d->Output->DebuggerLog; d->DbgContext->Watch = d->Output->Watch; d->DbgContext->Locals = d->Output->Locals; d->DbgContext->CallStack = d->Output->CallStack; d->DbgContext->Threads = d->Output->Threads; d->DbgContext->ObjectDump = d->Output->ObjectDump; d->DbgContext->Registers = d->Output->Registers; d->DbgContext->MemoryDump = d->Output->MemoryDump; d->DbgContext->OnCommand(IDM_START_DEBUG); d->Output->Value(AppWnd::DebugTab); d->Output->DebugEdit->Focus(true); } break; } case IDM_TOGGLE_BREAKPOINT: { IdeDoc *Cur = GetCurrentDoc(); if (Cur) ToggleBreakpoint(Cur->GetFileName(), Cur->GetLine()); break; } case IDM_ATTACH_TO_PROCESS: case IDM_PAUSE_DEBUG: case IDM_RESTART_DEBUGGING: case IDM_RUN_TO: case IDM_STEP_INTO: case IDM_STEP_OVER: case IDM_STEP_OUT: { if (d->DbgContext) d->DbgContext->OnCommand(Cmd); break; } case IDM_STOP_DEBUG: { if (d->DbgContext && d->DbgContext->OnCommand(Cmd)) { DeleteObj(d->DbgContext); } break; } case IDM_BUILD: { Build(); break; } case IDM_STOP_BUILD: { IdeProject *p = RootProject(); if (p) p->StopBuild(); break; } case IDM_CLEAN: { SaveAll(); IdeProject *p = RootProject(); if (p) p->Clean(true, IsReleaseMode()); break; } case IDM_NEXT_MSG: { d->SeekMsg(1); break; } case IDM_PREV_MSG: { d->SeekMsg(-1); break; } case IDM_DEBUG_MODE: { GMenuItem *Debug = GetMenu()->FindItem(IDM_DEBUG_MODE); GMenuItem *Release = GetMenu()->FindItem(IDM_RELEASE_MODE); if (Debug && Release) { Debug->Checked(true); Release->Checked(false); } break; } case IDM_RELEASE_MODE: { GMenuItem *Debug = GetMenu()->FindItem(IDM_DEBUG_MODE); GMenuItem *Release = GetMenu()->FindItem(IDM_RELEASE_MODE); if (Debug && Release) { Debug->Checked(false); Release->Checked(true); } break; } // // Other // case IDM_LOOKUP_SYMBOLS: { IdeDoc *Cur = GetCurrentDoc(); if (Cur) { // LookupSymbols(Cur->Read()); } break; } case IDM_DEPENDS: { IdeProject *p = RootProject(); if (p) { GString Exe = p->GetExecutable(GetCurrentPlatform()); if (FileExists(Exe)) { Depends Dlg(this, Exe); } else { LgiMsg(this, "Couldn't find '%s'\n", AppName, MB_OK, Exe ? Exe.Get() : ""); } } break; } case IDM_SP_TO_TAB: { IdeDoc *Doc = FocusDoc(); if (Doc) Doc->ConvertWhiteSpace(true); break; } case IDM_TAB_TO_SP: { IdeDoc *Doc = FocusDoc(); if (Doc) Doc->ConvertWhiteSpace(false); break; } case IDM_ESCAPE: { IdeDoc *Doc = FocusDoc(); if (Doc) Doc->EscapeSelection(true); break; } case IDM_DESCAPE: { IdeDoc *Doc = FocusDoc(); if (Doc) Doc->EscapeSelection(false); break; } case IDM_EOL_LF: { IdeDoc *Doc = FocusDoc(); if (!Doc) break; Doc->SetCrLf(false); break; } case IDM_EOL_CRLF: { IdeDoc *Doc = FocusDoc(); if (!Doc) break; Doc->SetCrLf(true); break; } case IDM_LOAD_MEMDUMP: { NewMemDumpViewer(this); break; } case IDM_SYS_CHAR_SUPPORT: { new SysCharSupport(this); break; } default: { char *r = d->RecentFiles[Cmd - IDM_RECENT_FILE]; if (r) { IdeDoc *f = d->IsFileOpen(r); if (f) { f->Raise(); } else { OpenFile(r); } } char *p = d->RecentProjects[Cmd - IDM_RECENT_PROJECT]; if (p) { CloseAll(); OpenProject(p, NULL, false); if (d->Tree) { d->Tree->Focus(true); } } IdeDoc *Doc = d->Docs[Cmd - IDM_WINDOWS]; if (Doc) { Doc->Raise(); } IdePlatform PlatIdx = (IdePlatform) (Cmd - IDM_MAKEFILE_BASE); const char *Platform = PlatIdx >= 0 && PlatIdx < PlatformMax ? PlatformNames[Cmd - IDM_MAKEFILE_BASE] : NULL; if (Platform) { IdeProject *p = RootProject(); if (p) { p->CreateMakefile(PlatIdx, false); } } break; } } return 0; } GTree *AppWnd::GetTree() { return d->Tree; } IdeDoc *AppWnd::TopDoc() { return dynamic_cast(d->Mdi->GetTop()); } GTextView3 *AppWnd::FocusEdit() { return dynamic_cast(GetWindow()->GetFocus()); } IdeDoc *AppWnd::FocusDoc() { IdeDoc *Doc = TopDoc(); if (Doc) { if (Doc->HasFocus()) { return Doc; } else { GViewI *f = GetFocus(); LgiTrace("%s:%i - Edit doesn't have focus, f=%p %s doc.edit=%s\n", _FL, f, f ? f->GetClass() : 0, Doc->Name()); } } return 0; } void AppWnd::OnProjectDestroy(IdeProject *Proj) { d->Projects.Delete(Proj); } void AppWnd::OnProjectChange() { GArray Views; if (d->Mdi->GetChildren(Views)) { for (unsigned i=0; i(Views[i]); if (Doc) Doc->OnProjectChange(); } } } void AppWnd::OnDocDestroy(IdeDoc *Doc) { if (d) { d->Docs.Delete(Doc); d->UpdateMenus(); } } int AppWnd::GetBuildMode() { GMenuItem *Release = GetMenu()->FindItem(IDM_RELEASE_MODE); if (Release && Release->Checked()) { return BUILD_TYPE_RELEASE; } return BUILD_TYPE_DEBUG; } LList *AppWnd::GetFtpLog() { return d->Output->FtpLog; } GStream *AppWnd::GetBuildLog() { return d->Output->Txt[AppWnd::BuildTab]; } void AppWnd::FindSymbol(int ResultsSinkHnd, const char *Sym, bool AllPlatforms) { d->FindSym->Search(ResultsSinkHnd, Sym, AllPlatforms); } #include "GSubProcess.h" bool AppWnd::GetSystemIncludePaths(::GArray &Paths) { if (d->SystemIncludePaths.Length() == 0) { #if !defined(WINNATIVE) // echo | gcc -v -x c++ -E - GSubProcess sp1("echo"); GSubProcess sp2("gcc", "-v -x c++ -E -"); sp1.Connect(&sp2); sp1.Start(true, false); char Buf[256]; ssize_t r; GStringPipe p; while ((r = sp1.Read(Buf, sizeof(Buf))) > 0) { p.Write(Buf, r); } bool InIncludeList = false; while (p.Pop(Buf, sizeof(Buf))) { if (stristr(Buf, "#include")) { InIncludeList = true; } else if (stristr(Buf, "End of search")) { InIncludeList = false; } else if (InIncludeList) { GAutoString a(TrimStr(Buf)); d->SystemIncludePaths.New() = a; } } #else char p[MAX_PATH]; LGetSystemPath(LSP_USER_DOCUMENTS, p, sizeof(p)); LgiMakePath(p, sizeof(p), p, "Visual Studio 2008\\Settings\\CurrentSettings.xml"); if (FileExists(p)) { GFile f; if (f.Open(p, O_READ)) { GXmlTree t; GXmlTag r; if (t.Read(&r, &f)) { GXmlTag *Opts = r.GetChildTag("ToolsOptions"); if (Opts) { GXmlTag *Projects = NULL; char *Name; for (GXmlTag *c = Opts->Children.First(); c; c = Opts->Children.Next()) { if (c->IsTag("ToolsOptionsCategory") && (Name = c->GetAttr("Name")) && !stricmp(Name, "Projects")) { Projects = c; break; } } GXmlTag *VCDirectories = NULL; for (GXmlTag *c = Projects ? Projects->Children.First() : NULL; c; c = Projects->Children.Next()) { if (c->IsTag("ToolsOptionsSubCategory") && (Name = c->GetAttr("Name")) && !stricmp(Name, "VCDirectories")) { VCDirectories = c; break; } } for (GXmlTag *prop = VCDirectories ? VCDirectories->Children.First() : NULL; prop; prop = VCDirectories->Children.Next()) { if (prop->IsTag("PropertyValue") && (Name = prop->GetAttr("Name")) && !stricmp(Name, "IncludeDirectories")) { char *Bar = strchr(prop->GetContent(), '|'); GToken t(Bar ? Bar + 1 : prop->GetContent(), ";"); for (int i=0; iSystemIncludePaths.New().Reset(NewStr(s)); } } } } } } } #endif } for (int i=0; iSystemIncludePaths.Length(); i++) { Paths.Add(NewStr(d->SystemIncludePaths[i])); } return true; } /* #include "GSubProcess.h" void Test() { GDirectory d; for (int b = d.First("C:\\Users\\matthew\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\Cache"); b; b = d.Next()) { if (!d.IsDir()) { char p[MAX_PATH]; d.Path(p, sizeof(p)); GFile f; if (f.Open(p, O_READ)) { char Buf[256]; ssize_t Rd = f.Read(Buf, sizeof(Buf)); if (Rd > 3 && !strnicmp(Buf, "Ogg", 3)) { char out[MAX_PATH]; f.Close(); LgiMakePath(out, sizeof(out), "C:\\Users\\matthew\\Desktop\\new day", d.GetName()); strcat(out, ".ogg"); if (!FileDev->Copy(p, out)) { LgiTrace("%s:%i - Failed to copy '%s'\n", _FL, d.GetName()); } } else { LgiTrace("%s:%i - Not an ogg '%s'\n", _FL, d.GetName()); } } else { LgiTrace("%s:%i - Can't open '%s'\n", _FL, d.GetName()); } } } } */ int LgiMain(OsAppArguments &AppArgs) { printf("LgiIde v%s\n", APP_VER); GApp a(AppArgs, "LgiIde"); if (a.IsOk()) { /* GString mt = LGetAppForProtocol("mailto"); GString https = LGetAppForProtocol("https"); printf("%s\n%s\n", mt.Get(), https.Get()); GArray Out; if (GSocket::EnumInterfaces(Out)) { for (auto &i : Out) { printf("%s %s %s\n", i.Name.Get(), i.ToString().Get(), i.ToString(i.Netmask4).Get()); } } */ a.AppWnd = new AppWnd; a.Run(); } return 0; } diff --git a/Makefile.linux b/Makefile.linux --- a/Makefile.linux +++ b/Makefile.linux @@ -1,1584 +1,1584 @@ #!/usr/bin/make # # This makefile generated by LgiIde # http://www.memecode.com/lgi.php # .SILENT : CC = gcc CPP = g++ Target = lgi ifndef Build - Build = Release + Build = Debug endif BuildDir = $(Build) Flags = -fPIC -w -fno-inline -fpermissive ifeq ($(Build),Debug) Flags += -g -std=c++11 Tag = d Defs = -D_DEBUG -DLINUX -D_REENTRANT -D_FILE_OFFSET_BITS=64 -DPOSIX -DLGI_LIBRARY -DHAS_FILE_CMD=1 Libs = \ -lmagic \ -static-libgcc \ `pkg-config --libs gtk+-2.0` Inc = \ -I./include/common \ -I./include/linux/Gtk \ -I./src/common/Hash/md5 \ -I./src/common/Hash/sha1 \ -I/usr/include/gstreamer-1.0 \ -I/usr/lib/x86_64-linux-gnu/gstreamer-1.0/include \ `pkg-config --cflags gtk+-2.0` \ -Iinclude/common \ -Iinclude/linux \ -Iinclude/linux/Gtk else Flags += -s -Os -std=c++11 Defs = -DLINUX -D_REENTRANT -D_FILE_OFFSET_BITS=64 -DPOSIX -DLGI_LIBRARY -DHAS_FILE_CMD=1 Libs = \ -lmagic \ -static-libgcc \ `pkg-config --libs gtk+-2.0` Inc = \ -I./include/common \ -I./include/linux/Gtk \ -I./src/common/Hash/md5 \ -I./src/common/Hash/sha1 \ -I/usr/include/gstreamer-1.0 \ -I/usr/lib/x86_64-linux-gnu/gstreamer-1.0/include \ `pkg-config --cflags gtk+-2.0` \ -Iinclude/common \ -Iinclude/linux \ -Iinclude/linux/Gtk endif # Dependencies Depends = LDateTime.o \ GDragAndDrop.o \ GFile.o \ ShowFileProp_Linux.o \ GExeCheck.o \ GFileCommon.o \ GApp.o \ GGeneral.o \ GView.o \ GWindow.o \ LgiWidget.o \ GViewCommon.o \ GWindowCommon.o \ GLibrary.o \ GMem.o \ GProperties.o \ GContainers.o \ GMenuGtk.o \ GMenuCommon.o \ GProcess.o \ LgiRes.o \ Res.o \ Gel.o \ GPath.o \ GMemStream.o \ GStream.o \ LThread.o \ LMutex.o \ LThreadCommon.o \ LThreadEvent.o \ GVariant.o \ GGuiUtils.o \ GObject.o \ GToolTip.o \ GTrayIcon.o \ LgiCommon.o \ LgiMsg.o \ GFileSelect.o \ GAlert.o \ GFindReplace.o \ GFontSelect.o \ GInput.o \ Gdc2.o \ GColour.o \ GColourReduce.o \ GdcCommon.o \ GdcTools.o \ GDisplayString.o \ GFont.o \ GFont_W.o \ GFontCodePages.o \ GFontSystem.o \ LStringLayout.o \ 15Bit.o \ 16Bit.o \ 24Bit.o \ 32Bit.o \ 8Bit.o \ Alpha.o \ GFilter.o \ GRect.o \ GMemDC.o \ GPrintDC.o \ GScreenDC.o \ GPrinter.o \ GSurface.o \ GClipBoard.o \ GDataDlg.o \ GPassword.o \ md5.o \ sha1.o \ GMru.o \ Base64.o \ GOptionsFile.o \ LgiRand.o \ GString.o \ GToken.o \ GUnicode.o \ GUtf8.o \ GXmlTree.o \ GBitmap.o \ GButton.o \ GCheckBox.o \ GCombo.o \ GDocView.o \ GEdit.o \ GItemContainer.o \ GPanel.o \ GPopup.o \ GProgress.o \ GProgressDlg.o \ GRadioGroup.o \ GScrollBar.o \ GStatusBar.o \ GTabView.o \ GTextLabel.o \ GTextView3.o \ GToolBar.o \ GTree.o \ LList.o \ GCss.o \ GCssTools.o \ GLayout.o \ GWidgets.o \ GBox.o \ GSplitter.o \ GTableLayout.o \ GUri.o \ INet.o \ INetTools.o \ MDStringToDigest.o # Target TargetFile = lib$(Target)$(Tag).so $(TargetFile) : outputfolder $(Depends) @echo Linking $(TargetFile) [$(Build)]... $(CPP)$s -shared \ \ -o $(BuildDir)/$(TargetFile) \ $(addprefix $(BuildDir)/,$(Depends)) \ $(Libs) @echo Done. # Create the output folder outputfolder : -mkdir -p $(BuildDir) 2> /dev/null # Clean out targets clean : rm -f $(BuildDir)/*.o $(BuildDir)/$(TargetFile) @echo Cleaned $(BuildDir) LDateTime.o : ./src/common/General/LDateTime.cpp ./include/common/Lgi.h \ ./include/common/LDateTime.h \ ./include/common/GToken.h \ ./include/common/GDocView.h @echo $( #include "LgiResEdit.h" #include "LgiRes_Dialog.h" #include "LgiRes_Menu.h" #include "GAbout.h" #include "GTextLabel.h" #include "GEdit.h" #include "GCheckBox.h" #include "GProgressDlg.h" #include "GTextView3.h" #include "resdefs.h" #include "GToken.h" #include "GDataDlg.h" #include "GButton.h" char AppName[] = "Lgi Resource Editor"; char HelpFile[] = "Help.html"; char OptionsFileName[] = "Options.r"; char TranslationStrMagic[] = "LgiRes.String"; #define VIEW_PULSE_RATE 100 #ifndef DIALOG_X #define DIALOG_X 1.56 #define DIALOG_Y 1.85 #define CTRL_X 1.50 #define CTRL_Y 1.64 #endif enum Ctrls { IDC_HBOX = 100, IDC_VBOX, }; const char *TypeNames[] = { "", "Css", "Dialog", "String", "Menu", 0}; ////////////////////////////////////////////////////////////////////////////// ResFileFormat GetFormat(char *File) { ResFileFormat Format = Lr8File; char *Ext = LgiGetExtension(File); if (Ext) { if (stricmp(Ext, "lr") == 0) Format = CodepageFile; else if (stricmp(Ext, "xml") == 0) Format = XmlFile; } return Format; } char *EncodeXml(char *Str, int Len) { char *Ret = 0; if (Str) { GStringPipe p; char *s = Str; for (char *e = Str; e && *e && (Len < 0 || ((e-Str) < Len)); ) { switch (*e) { case '<': { p.Push(s, e-s); p.Push("<"); s = ++e; break; } case '>': { p.Push(s, e-s); p.Push(">"); s = ++e; break; } case '&': { p.Push(s, e-s); p.Push("&"); s = ++e; break; } case '\\': { if (e[1] == 'n') { // Newline p.Push(s, e-s); p.Push("\n"); s = (e += 2); break; } // fall thru } case '\'': case '\"': case '/': { // Convert to entity p.Push(s, e-s); char b[32]; sprintf(b, "&#%i;", *e); p.Push(b); s = ++e; break; } default: { // Regular character e++; break; } } } p.Push(s); Ret = p.NewStr(); } return Ret; } char *DecodeXml(char *Str, int Len) { if (Str) { GStringPipe p; char *s = Str; for (char *e = Str; e && *e && (Len < 0 || ((e-Str) < Len)); ) { switch (*e) { case '&': { // Store string up to here p.Push(s, e-s); e++; if (*e == '#') { // Numerical e++; if (*e == 'x' || *e == 'X') { // Hex e++; char16 c = htoi(e); char *c8 = WideToUtf8(&c, 1); if (c8) { p.Push(c8); DeleteArray(c8); } } else if (isdigit(*e)) { // Decimal char16 c = atoi(e); char *c8 = WideToUtf8(&c, 1); if (c8) { p.Push(c8); DeleteArray(c8); } } else { LgiAssert(0); } while (*e && *e != ';') e++; } else if (isalpha(*e)) { // named entity char *Name = e; while (*e && *e != ';') e++; int Len = e - Name; if (Len == 3 && strnicmp(Name, "amp", Len) == 0) { p.Push("&"); } else if (Len == 2 && strnicmp(Name, "gt", Len) == 0) { p.Push(">"); } else if (Len == 2 && strnicmp(Name, "lt", Len) == 0) { p.Push("<"); } else { // Unsupported entity LgiAssert(0); } } else { LgiAssert(0); while (*e && *e != ';') e++; } s = ++e; break; } case '\n': { p.Push(s, e-s); p.Push("\\n"); s = ++e; break; } default: { e++; break; } } } p.Push(s); return p.NewStr(); } return 0; } ////////////////////////////////////////////////////////////////////////////// Resource::Resource(AppWnd *w, int t, bool enabled) { AppWindow = w; ResType = t; Item = 0; SysObject = false; LgiAssert(AppWindow); } Resource::~Resource() { AppWindow->OnResourceDelete(this); if (Item) { Item->Obj = 0; DeleteObj(Item); } } bool Resource::IsSelected() { return Item?Item->Select():false; } bool Resource::Attach(GViewI *Parent) { GView *w = Wnd(); if (w) { return w->Attach(Parent); } return false; } ////////////////////////////////////////////////////////////////////////////// ResFolder::ResFolder(AppWnd *w, int t, bool enabled) : Resource(w, t, enabled) { Wnd()->Name(""); Wnd()->Enabled(enabled); } ////////////////////////////////////////////////////////////////////////////// ObjTreeItem::ObjTreeItem(Resource *Object) { if ((Obj = Object)) { Obj->Item = this; if (dynamic_cast(Object)) SetImage(ICON_FOLDER); else { int t = Object->Type(); switch (t) { case TYPE_CSS: SetImage(ICON_CSS); break; case TYPE_DIALOG: SetImage(ICON_DIALOG); break; case TYPE_STRING: SetImage(ICON_STRING); break; case TYPE_MENU: SetImage(ICON_MENU); break; } } } } ObjTreeItem::~ObjTreeItem() { if (Obj) { Obj->Item = 0; DeleteObj(Obj); } } char *ObjTreeItem::GetText(int i) { if (Obj) { int Type = Obj->Type(); if (Type > 0) { return Obj->Wnd()->Name(); } else { return (char*)TypeNames[-Type]; } } return (char*)"#NO_OBJ"; } void ObjTreeItem::OnSelect() { if (Obj) { Obj->App()->OnResourceSelect(Obj); } } void ObjTreeItem::OnMouseClick(GMouse &m) { if (!Obj) return; if (m.IsContextMenu()) { Tree->Select(this); GSubMenu RClick; if (Obj->Wnd()->Enabled()) { if (Obj->Type() > 0) { // Resource RClick.AppendItem("Delete", IDM_DELETE, !Obj->SystemObject()); RClick.AppendItem("Rename", IDM_RENAME, !Obj->SystemObject()); } else { // Folder RClick.AppendItem("New", IDM_NEW, true); RClick.AppendSeparator(); GSubMenu *Insert = RClick.AppendSub("Import from..."); if (Insert) { Insert->AppendItem("Lgi File", IDM_IMPORT, true); Insert->AppendItem("Win32 Resource Script", IDM_IMPORT_WIN32, false); } } // Custom entries if (!Obj->SystemObject()) { Obj->OnRightClick(&RClick); } } else { RClick.AppendItem("Not implemented", 0, false); } if (Tree->GetMouse(m, true)) { int Cmd = 0; switch (Cmd = RClick.Float(Tree, m.x, m.y)) { case IDM_NEW: { SerialiseContext Ctx; Obj->App()->NewObject(Ctx, 0, -Obj->Type()); break; } case IDM_DELETE: { Obj->App()->SetDirty(true); Obj->App()->DelObject(Obj); break; } case IDM_RENAME: { GInput Dlg(Tree, GetText(), "Enter the name for the object", "Object Name"); if (Dlg.DoModal()) { Obj->Wnd()->Name(Dlg.GetStr()); Update(); Obj->App()->SetDirty(true); } break; } case IDM_IMPORT: { GFileSelect Select; Select.Parent(Obj->App()); Select.Type("Text", "*.txt"); if (Select.Open()) { GFile F; if (F.Open(Select.Name(), O_READ)) { SerialiseContext Ctx; Resource *Res = Obj->App()->NewObject(Ctx, 0, -Obj->Type()); if (Res) { // TODO // Res->Read(); } } else { LgiMsg(Obj->App(), "Couldn't open file for reading."); } } break; } case IDM_IMPORT_WIN32: { /* List l; if (ImportWin32Dialogs(l, MainWnd)) { for (ResDialog *r = l.First(); r; r = l.Next()) { Obj->App()->InsertObject(TYPE_DIALOG, r); } } */ break; } default: { Obj->OnCommand(Cmd); break; } } } } } ////////////////////////////////////////////////////////////////////////////// FieldView::FieldView(AppWnd *app) : Fields(NextId, true) { NextId = 100; App = app; Source = 0; Ignore = true; SetTabStop(true); Sunken(true); #ifdef WIN32 SetExStyle(GetExStyle() | WS_EX_CONTROLPARENT); #endif } FieldView::~FieldView() { } void FieldView::Serialize(bool Write) { if (!Source) return; Ignore = !Write; Fields.SetMode(Write ? FieldTree::UiToObj : FieldTree::ObjToUi); Fields.SetView(this); Source->Serialize(Fields); /* for (DataDlgField *f=Fields.First(); f; f=Fields.Next()) { GViewI *v; if (GetViewById(f->GetCtrl(), v)) { switch (f->GetType()) { case DATA_STR: { if (Write) // Ctrl -> Options { char *s = v->Name(); Options->Set(f->GetOption(), s); } else // Options -> Ctrl { char *s = 0; Options->Get(f->GetOption(), s); v->Name(s?s:(char*)""); } break; } case DATA_BOOL: case DATA_INT: { if (Write) // Ctrl -> Options { char *s = v->Name(); if (s && (s = strchr(s, '\''))) { s++; char *e = strchr(s, '\''); int i = 0; if (e - s == 4) { memcpy(&i, s, 4); i = LgiSwap32(i); Options->Set(f->GetOption(), i); } } else { int i = v->Value(); Options->Set(f->GetOption(), i); } } else // Options -> Ctrl { int i = 0; Options->Get(f->GetOption(), i); if (i != -1 && (i & 0xff000000) != 0) { char m[8]; i = LgiSwap32(i); sprintf(m, "'%04.4s'", &i); v->Name(m); } else { v->Value(i); } } break; } case DATA_FLOAT: case DATA_PASSWORD: case DATA_STR_SYSTEM: default: { LgiAssert(0); break; } } } else LgiAssert(0); } */ Ignore = false; } class TextViewEdit : public GTextView3 { public: bool Multiline; TextViewEdit( int Id, int x, int y, int cx, int cy, GFontType *FontInfo = 0) : GTextView3(Id, x, y, cx, cy, FontInfo) { Multiline = false; #ifdef WIN32 SetDlgCode(DLGC_WANTARROWS | DLGC_WANTCHARS); #endif } bool OnKey(GKey &k) { if (!Multiline && (k.c16 == '\t' || k.c16 == VK_RETURN)) { return false; } return GTextView3::OnKey(k); } }; class Hr : public GView { public: Hr(int x1, int y, int x2) { GRect r(x1, y, x2, y+1); SetPos(r); } void OnPaint(GSurface *pDC) { GRect c = GetClient(); LgiThinBorder(pDC, c, DefaultSunkenEdge); } bool OnLayout(GViewLayoutInfo &Inf) { if (Inf.Width.Min) Inf.Height.Min = Inf.Height.Max = 2; else Inf.Width.Min = Inf.Width.Max = -1; return true; } }; void FieldView::OnDelete(FieldSource *s) { if (Source != NULL && Source == s) { // Clear fields Source->_FieldView = 0; Fields.Empty(); // remove all children for (GViewI *c = Children.First(); c; c = Children.First()) { c->Detach(); DeleteObj(c); } Source = NULL; } } void FieldView::OnSelect(FieldSource *s) { Ignore = true; OnDelete(Source); if (Source) { // Clear fields Source->_FieldView = 0; Fields.Empty(); // remove all children for (GViewI *c = Children.First(); c; c = Children.First()) { c->Detach(); DeleteObj(c); } Source = 0; } if (s) { // Add new fields Source = s; Source->_FieldView = Handle(); if (Source->GetFields(Fields)) { GFontType Sys; Sys.GetSystemFont("System"); GTableLayout *t = new GTableLayout(IDC_TABLE); int Row = 0; GLayoutCell *Cell; GArray a; Fields.GetAll(a); for (int i=0; iLength(); n++, Row++) { FieldTree::Field *c = (*b)[n]; switch (c->Type) { case DATA_STR: case DATA_FLOAT: case DATA_INT: case DATA_FILENAME: { Cell = t->GetCell(0, Row); Cell->Add(new GTextLabel(-1, 0, 0, -1, -1, c->Label)); TextViewEdit *Tv; Cell = t->GetCell(1, Row, true, c->Type == DATA_FILENAME ? 1 : 2); Cell->Add(Tv = new TextViewEdit(c->Id, 0, 0, 100, 20, &Sys)); if (Tv) { Tv->Multiline = c->Multiline; Tv->GetCss(true)->Height(GCss::Len(GCss::LenPx, c->Multiline ? SysFont->GetHeight() * 8 : SysFont->GetHeight() + 8)); Tv->SetWrapType(TEXTED_WRAP_NONE); Tv->Sunken(true); } if (c->Type == DATA_FILENAME) { Cell = t->GetCell(2, Row); Cell->Add(new GButton(-c->Id, 0, 0, 21, 21, "...")); } break; } case DATA_BOOL: { Cell = t->GetCell(1, Row, true, 2); Cell->Add(new GCheckBox(c->Id, 0, 0, -1, -1, c->Label)); break; } default: LgiAssert(!"Impl me."); break; } } if (i < a.Length() - 1) { Cell = t->GetCell(0, Row++, true, 3); Cell->Add(new Hr(0, 0, X()-1)); } } AddView(t); OnPosChange(); AttachChildren(); } Serialize(false); Ignore = false; } } void FieldView::OnPosChange() { GRect c = GetClient(); c.Size(6, 6); GViewI *v; if (GetViewById(IDC_TABLE, v)) v->SetPos(c); } GMessage::Result FieldView::OnEvent(GMessage *m) { switch (MsgCode(m)) { case M_OBJECT_CHANGED: { FieldSource *Src = (FieldSource*)MsgA(m); if (Src == Source) { Fields.SetMode(FieldTree::ObjToUi); Fields.SetView(this); Serialize(false); } else LgiAssert(0); break; } } return GLayout::OnEvent(m); } int FieldView::OnNotify(GViewI *Ctrl, int Flags) { if (!Ignore) { GTextView3 *Tv = dynamic_cast(Ctrl); if (Tv && Flags == GNotifyCursorChanged) { return 0; } GArray a; Fields.GetAll(a); for (int i=0; iLength(); n++) { FieldTree::Field *c = (*b)[n]; if (c->Id == Ctrl->GetId()) { // Write the value back to the objects Fields.SetMode(FieldTree::UiToObj); Fields.SetView(this); Source->Serialize(Fields); return 0; } else if (c->Id == -Ctrl->GetId()) { GFileSelect s; s.Parent(this); if (s.Open()) { char *File = App->GetCurFile(); if (File) { GFile::Path p = File; p--; GAutoString Rel = LgiMakeRelativePath(p, s.Name()); if (Rel) SetCtrlName(c->Id, Rel); else SetCtrlName(c->Id, s.Name()); } else SetCtrlName(c->Id, s.Name()); Fields.SetMode(FieldTree::UiToObj); Fields.SetView(this); Source->Serialize(Fields); return 0; } } } } } return 0; } void FieldView::OnPaint(GSurface *pDC) { pDC->Colour(LC_MED, 24); pDC->Rectangle(); } ////////////////////////////////////////////////////////////////////////////// ObjContainer::ObjContainer(AppWnd *w) : GTree(100, 0, 0, 100, 100, "LgiResObjTree") { Window = w; Sunken(true); Insert(Style = new ObjTreeItem( new ResFolder(Window, -TYPE_CSS))); Insert(Dialogs = new ObjTreeItem( new ResFolder(Window, -TYPE_DIALOG))); Insert(Strings = new ObjTreeItem( new ResFolder(Window, -TYPE_STRING))); Insert(Menus = new ObjTreeItem( new ResFolder(Window, -TYPE_MENU))); const char *IconFile = "_icons.gif"; GAutoString f(LgiFindFile(IconFile)); if (f) { Images = LgiLoadImageList(f, 16, 16); if (Images) SetImageList(Images, false); else LgiTrace("%s:%i - failed to load '%s'\n", _FL, IconFile); } } ObjContainer::~ObjContainer() { DeleteObj(Images); } bool ObjContainer::AppendChildren(ObjTreeItem *Res, List &Lst) { bool Status = true; if (Res) { GTreeItem *Item = Res->GetChild(); while (Item) { ObjTreeItem *i = dynamic_cast(Item); if (i) Lst.Insert(i->GetObj()); else Status = false; Item = Item->GetNext(); } } return Status; } Resource *ObjContainer::CurrentResource() { ObjTreeItem *Item = dynamic_cast(Selection()); if (!Item) return NULL; return Item->GetObj(); } bool ObjContainer::ListObjects(List &Lst) { bool Status = AppendChildren(Style, Lst); Status &= AppendChildren(Dialogs, Lst); Status &= AppendChildren(Strings, Lst); Status &= AppendChildren(Menus, Lst); return Status; } ////////////////////////////////////////////////////////////////////////////// #ifdef WIN32 const char *Icon = MAKEINTRESOURCE(IDI_ICON1); #else const char *Icon = "icon64.png"; #endif AppWnd::AppWnd() : GDocApp(AppName, Icon) { LastRes = 0; Fields = 0; ViewMenu = 0; ContentView = NULL; VBox = NULL; HBox = NULL; ShortCuts = 0; CurLang = -1; ShowLanguages.Add("en", true); if (_Create()) { GVariant Langs; if (GetOptions()->GetValue(OPT_ShowLanguages, Langs)) { ShowLanguages.Empty(); GToken L(Langs.Str(), ","); for (int i=0; iEmpty(); _Destroy(); } void AppWnd::OnCreate() { if (_LoadMenu("IDM_MENU")) { if (_FileMenu) { int n = 6; _FileMenu->AppendSeparator(n++); _FileMenu->AppendItem("Import Win32 Script", IDM_IMPORT_WIN32, true, n++); _FileMenu->AppendItem("Import LgiRes Language", IDM_IMPORT_LANG, true, n++); _FileMenu->AppendItem("Compare To File...", IDM_COMPARE, true, n++); _FileMenu->AppendSeparator(n++); _FileMenu->AppendItem("Properties", IDM_PROPERTIES, true, n++); } ViewMenu = Menu->FindSubMenu(IDM_VIEW); LgiAssert(ViewMenu); } else LgiTrace("%s:%i - _LoadMenu failed.\n", _FL); Status = 0; StatusInfo[0] = StatusInfo[1] = 0; HBox = new GBox(IDC_HBOX); if (HBox) { HBox->GetCss(true)->Padding("5px"); VBox = new GBox(IDC_VBOX, true); if (VBox) { HBox->AddView(VBox); VBox->AddView(Objs = new ObjContainer(this)); if (Objs) { Objs->AskImage(true); Objs->AskText(true); } VBox->AddView(Fields = new FieldView(this)); VBox->Value(200); } HBox->Value(240); HBox->Attach(this); } DropTarget(true); GString Open; if (LgiApp->GetOption("o", Open)) LoadLgi(Open); } void AppWnd::OnLanguagesChange(GLanguageId Lang, bool Add, bool Update) { bool Change = false; if (Lang) { // Update the list.... bool Has = false; for (int i=0; iId, Lang) == 0) { Has = true; if (!Add) { Languages.DeleteAt(i); Change = true; } break; } } if (Add && !Has) { Change = true; Languages.Add(GFindLang(Lang)); } } // Update the menu... if (ViewMenu && (Change || Update)) { // Remove existing language menu items while (ViewMenu->RemoveItem(2)); // Add new ones int n = 0; for (int i=0; iAppendItem(Lang->Name, IDM_LANG_BASE + n, true); if (Item) { if (CurLang == i) { Item->Checked(true); } } } } } } bool AppWnd::ShowLang(GLanguageId Lang) { return ShowLanguages.Find(Lang) != 0; } void AppWnd::ShowLang(GLanguageId Lang, bool Show) { // Apply change if (Show) { OnLanguagesChange(Lang, true); ShowLanguages.Add(Lang, true); } else { ShowLanguages.Delete(Lang); } // Store the setting for next time GStringPipe p; // const char *L; // for (bool i = ShowLanguages.First(&L); i; i = ShowLanguages.Next(&L)) for (auto i : ShowLanguages) { if (p.GetSize()) p.Push(","); p.Push(i.key); } char *Langs = p.NewStr(); if (Langs) { GVariant v; GetOptions()->SetValue(OPT_ShowLanguages, v = Langs); DeleteArray(Langs); } // Update everything List res; if (ListObjects(res)) { for (Resource *r = res.First(); r; r = res.Next()) { r->OnShowLanguages(); } } } GLanguage *AppWnd::GetCurLang() { if (CurLang >= 0 && CurLang < Languages.Length()) return Languages[CurLang]; return GFindLang("en"); } void AppWnd::SetCurLang(GLanguage *L) { for (int i=0; iId == L->Id) { // Set new current CurLang = i; // Update everything List res; if (ListObjects(res)) { for (Resource *r = res.First(); r; r = res.Next()) { r->OnShowLanguages(); } } break; } } } GArray *AppWnd::GetLanguages() { return &Languages; } class Test : public GView { COLOUR c; public: Test(COLOUR col, int x1, int y1, int x2, int y2) { c = col; GRect r(x1, y1, x2, y2); SetPos(r); _BorderSize = 1; Sunken(true); } void OnPaint(GSurface *pDC) { pDC->Colour(c, 24); pDC->Rectangle(); } }; GMessage::Result AppWnd::OnEvent(GMessage *m) { GMru::OnEvent(m); switch (MsgCode(m)) { case M_CHANGE: { return OnNotify((GViewI*) MsgA(m), MsgB(m)); } case M_DESCRIBE: { char *Text = (char*) MsgA(m); if (Text) { SetStatusText(Text, STATUS_NORMAL); } break; } } return GWindow::OnEvent(m); } #include "GToken.h" void _CountGroup(ResStringGroup *Grp, int &Words, int &Multi) { for (ResString *s = Grp->GetStrs()->First(); s; s=Grp->GetStrs()->Next()) { if (s->Items.Length() > 1) { Multi++; char *e = s->Get("en"); if (e) { GToken t(e, " "); Words += t.Length(); } } } } int AppWnd::OnCommand(int Cmd, int Event, OsView Handle) { SerialiseContext Ctx; switch (Cmd) { case IDM_SHOW_LANG: { ShowLanguagesDlg Dlg(this); break; } case IDM_NEW_CSS: { NewObject(Ctx, 0, TYPE_CSS); break; } case IDM_NEW_DIALOG: { NewObject(Ctx, 0, TYPE_DIALOG); break; } case IDM_NEW_STRING_GRP: { NewObject(Ctx, 0, TYPE_STRING); break; } case IDM_NEW_MENU: { NewObject(Ctx, 0, TYPE_MENU); break; } case IDM_CLOSE: { Empty(); break; } case IDM_IMPORT_WIN32: { LoadWin32(); break; } case IDM_IMPORT_LANG: { ImportLang(); break; } case IDM_COMPARE: { Compare(); break; } case IDM_PROPERTIES: { List l; if (Objs->ListObjects(l)) { int Dialogs = 0; int Strings = 0; int Menus = 0; int Words = 0; int MultiLingual = 0; for (Resource *r = l.First(); r; r = l.Next()) { switch (r->Type()) { case TYPE_DIALOG: { Dialogs++; break; } case TYPE_STRING: { ResStringGroup *Grp = dynamic_cast(r); if (Grp) { Strings += Grp->GetStrs()->Length(); _CountGroup(Grp, Words, MultiLingual); } break; } case TYPE_MENU: { Menus++; ResMenu *Menu = dynamic_cast(r); if (Menu) { if (Menu->Group) { Strings += Menu->Group->GetStrs()->Length(); _CountGroup(Menu->Group, Words, MultiLingual); } } break; } } } LgiMsg( this, "This file contains:\n" "\n" " Dialogs: %i\n" " Menus: %i\n" " Strings: %i\n" " Multi-lingual: %i\n" " Words: %i", AppName, MB_OK, Dialogs, Menus, Strings, MultiLingual, Words); } break; } case IDM_EXIT: { LgiCloseApp(); break; } case IDM_FIND: { Search s(this); if (s.DoModal()) { new Results(this, &s); } break; } case IDM_NEXT: { LgiMsg(this, "Not implemented :(", AppName); break; } case IDM_CUT: { Resource *r = Objs->CurrentResource(); if (r) r->Copy(true); break; } case IDM_COPY: { Resource *r = Objs->CurrentResource(); if (r) r->Copy(false); break; } case IDM_PASTE: { Resource *r = Objs->CurrentResource(); if (r) r->Paste(); break; } case IDM_TABLELAYOUT_TEST: { OpenTableLayoutTest(this); break; } case IDM_HELP: { char ExeName[256]; LgiGetExePath(ExeName, sizeof(ExeName)); while (strchr(ExeName, DIR_CHAR) && strlen(ExeName) > 3) { char p[256]; LgiMakePath(p, sizeof(p), ExeName, "index.html"); if (!FileExists(p)) { LgiMakePath(p, sizeof(p), ExeName, "help"); LgiMakePath(p, sizeof(p), p, "index.html"); } if (FileExists(p)) { LgiExecute(HelpFile, NULL, ExeName); break; } LgiTrimDir(ExeName); } break; } case IDM_SHOW_SHORTCUTS: { if (!ShortCuts) ShortCuts = new ShortCutView(this); break; } case IDM_ABOUT: { GAbout Dlg( this, AppName, APP_VER, "\nLgi Resource Editor (lr8 files).", "icon64.png", "http://www.memecode.com/lgi/res", "fret@memecode.com"); break; } default: { int Idx = Cmd - IDM_LANG_BASE; if (Idx >= 0 && Idx < Languages.Length()) { // Deselect the old lang GMenuItem *Item = ViewMenu ? ViewMenu->ItemAt(CurLang + 2) : 0; if (Item) { Item->Checked(false); } // Set the current CurLang = Idx; // Set the new lang's menu item Item = ViewMenu ? ViewMenu->ItemAt(CurLang + 2) : 0; if (Item) { Item->Checked(true); } // Update everything List res; if (ListObjects(res)) { for (Resource *r = res.First(); r; r = res.Next()) { r->OnShowLanguages(); } } } break; } } return GDocApp::OnCommand(Cmd, Event, Handle); } int AppWnd::OnNotify(GViewI *Ctrl, int Flags) { switch (Ctrl->GetId()) { default: { break; } } return 0; } void AppWnd::FindStrings(List &Strs, char *Define, int *CtrlId) { if (Objs) { List l; if (Objs->ListObjects(l)) { for (Resource *r = l.First(); r; r = l.Next()) { StringList *s = r->GetStrs(); if (s) { for (ResString *Str = s->First(); Str; Str = s->Next()) { if (Define && ValidStr(Str->GetDefine())) { if (strcmp(Define, Str->GetDefine()) == 0) { Strs.Insert(Str); continue; } } if (CtrlId) { if (*CtrlId == Str->GetId()) { Strs.Insert(Str); continue; } } } } } } } } int AppWnd::GetUniqueCtrlId() { int Max = 0; if (Objs) { List l; if (Objs->ListObjects(l)) { LHashTbl, int> t; for (Resource *r = l.First(); r; r = l.Next()) { StringList *sl = r->GetStrs(); if (sl) { for (ResString *s = sl->First(); s; s = sl->Next()) { if (s->GetId() > 0 && !t.Find(s->GetId())) { t.Add(s->GetId(), s->GetId()); } Max = MAX(s->GetId(), Max); } } } int i = 500; while (true) { if (t.Find(i)) { i++; } else { return i; } } } } return Max + 1; } int AppWnd::GetUniqueStrRef(int Start) { if (!Objs) return -1; List l; if (!Objs->ListObjects(l)) return -1; LHashTbl, ResString*> Map; GArray Dupes; for (Resource *r = l.First(); r; r = l.Next()) { ResStringGroup *Grp = r->GetStringGroup(); if (Grp) { List::I it = Grp->GetStrs()->begin(); for (ResString *s = *it; s; s = *++it) { if (s->GetRef()) { ResString *Existing = Map.Find(s->GetRef()); if (Existing) { // These get their ref's reset to a unique value as a side // effect of this function... Dupes.Add(s); } else { Map.Add(s->GetRef(), s); } } else { int Idx = Grp->GetStrs()->IndexOf(s); LgiAssert(!"No string ref?"); } } } } for (int i=Start; true; i++) { if (!Map.Find(i)) { if (Dupes.Length()) { ResString *s = Dupes[0]; Dupes.DeleteAt(0); s->SetRef(i); SetDirty(true); } else { return i; } } } return -1; } ResString *AppWnd::GetStrFromRef(int Ref) { ResString *Str = 0; if (Objs) { List l; if (Objs->ListObjects(l)) { for (Resource *r = l.First(); r && !Str; r = l.Next()) { ResStringGroup *Grp = dynamic_cast(r); if (Grp) { if ((Str = Grp->FindRef(Ref))) break; } } } } return Str; } ResStringGroup *AppWnd::GetDialogSymbols() { if (Objs) { List l; if (Objs->ListObjects(l)) { for (Resource *r = l.First(); r; r = l.Next()) { ResStringGroup *Grp = dynamic_cast(r); if (Grp) { char *ObjName = Grp->Wnd()->Name(); if (ObjName && stricmp(ObjName, StrDialogSymbols) == 0) { return Grp; } } } } } return NULL; } void AppWnd::OnReceiveFiles(GArray &Files) { char *f = Files.Length() ? Files[0] : 0; if (f) { _OpenFile(f, false); } } void AppWnd::SetStatusText(char *Text, int Pane) { if (Pane >= 0 && Pane < STATUS_MAX && StatusInfo[Pane]) { StatusInfo[Pane]->Name(Text); } } Resource *AppWnd::NewObject(SerialiseContext ctx, GXmlTag *load, int Type, bool Select) { Resource *r = 0; ObjTreeItem *Dir = 0; switch (Type) { case TYPE_CSS: { r = new ResCss(this); Dir = Objs->Style; break; } case TYPE_DIALOG: { r = new ResDialog(this); Dir = Objs->Dialogs; break; } case TYPE_STRING: { r = new ResStringGroup(this); Dir = Objs->Strings; break; } case TYPE_MENU: { r = new ResMenu(this); Dir = Objs->Menus; break; } } if (r) { ObjTreeItem *Item = new ObjTreeItem(r); if (Item) { Dir->Insert(Item); Dir->Update(); Dir->Expanded(true); if (Select) { Objs->Select(Item); } } r->Create(load, &ctx); if (Item) { Item->Update(); } SetDirty(true); } return r; } bool AppWnd::InsertObject(int Type, Resource *r, bool Select) { bool Status = false; if (r) { ObjTreeItem *Dir = 0; switch (Type) { case TYPE_CSS: { Dir = Objs->Style; break; } case TYPE_DIALOG: { Dir = Objs->Dialogs; break; } case TYPE_STRING: { Dir = Objs->Strings; break; } case TYPE_MENU: { Dir = Objs->Menus; break; } } if (Dir) { ObjTreeItem *Item = new ObjTreeItem(r); if (Item) { char *Name = Item->GetText(); r->Item = Item; Dir->Insert(Item, (Name && Name[0] == '_') ? 0 : -1); Dir->Update(); Dir->Expanded(true); if (Select) { Objs->Select(Item); } Status = true; } } } return Status; } void AppWnd::DelObject(Resource *r) { OnResourceSelect(0); DeleteObj(r); } ObjTreeItem *GetTreeItem(GTreeItem *ti, Resource *r) { for (GTreeItem *i=ti->GetChild(); i; i=i->GetNext()) { ObjTreeItem *o = dynamic_cast(i); if (o) { if (o->GetObj() == r) return o; } o = GetTreeItem(i, r); if (o) return o; } return 0; } ObjTreeItem *GetTreeItem(GTree *ti, Resource *r) { for (GTreeItem *i=ti->GetChild(); i; i=i->GetNext()) { ObjTreeItem *o = dynamic_cast(i); if (o) { if (o->GetObj() == r) return o; } o = GetTreeItem(i, r); if (o) return o; } return 0; } void AppWnd::GotoObject(ResString *s, ResStringGroup *g, ResDialog *d, ResMenuItem *m, ResDialogCtrl *c) { if (s) { Resource *Res = 0; if (g) { Res = g; } else if (d) { Res = d; } else if (m) { Res = m->GetMenu(); } if (Res) { ObjTreeItem *ti = GetTreeItem(Objs, Res); if (ti) { ti->Select(true); if (g) { s->GetList()->Select(0); s->ScrollTo(); LgiYield(); s->Select(true); } else if (d) { LgiYield(); d->SelectCtrl(c); } else if (m) { for (GTreeItem *i=m; i; i=i->GetParent()) { i->Expanded(true); } m->Select(true); m->ScrollTo(); } } else { printf("%s:%i - couldn't find resources tree item\n", _FL); } } } } bool AppWnd::ListObjects(List &Lst) { if (Objs) { return Objs->ListObjects(Lst); } return false; } void AppWnd::OnObjChange(FieldSource *r) { if (Fields) { Fields->Serialize(false); SetDirty(true); } } void AppWnd::OnObjSelect(FieldSource *r) { if (Fields) Fields->OnSelect(r); } void AppWnd::OnObjDelete(FieldSource *r) { if (Fields) { Fields->OnDelete(r); } } void AppWnd::OnResourceDelete(Resource *r) { } void AppWnd::OnResourceSelect(Resource *r) { if (LastRes) { OnObjSelect(NULL); if (ContentView) { ContentView->Detach(); DeleteObj(ContentView); } LastRes = NULL; } if (r) { ContentView = r->CreateUI(); if (ContentView) { if (HBox) ContentView->Attach(HBox); LastRes = r; } } } char *TagName(GXmlTag *t) { static char Buf[1024]; GArray Tags; for (; t; t = t->Parent) { Tags.AddAt(0, t); } Buf[0] = 0; for (int i=0; iGetTag()); } return Buf; } class ResCompare : public GWindow, public GLgiRes { LList *Lst; public: ResCompare(char *File1, char *File2) { Lst = 0; GRect p; GAutoString n; if (LoadFromResource(IDD_COMPARE, this, &p, &n)) { SetPos(p); Name(n); MoveToCenter(); GetViewById(IDC_DIFFS, Lst); if (Attach(0)) { Visible(true); AttachChildren(); GXmlTag *t1 = new GXmlTag; GXmlTag *t2 = new GXmlTag; if (t1 && File1) { GFile f; if (f.Open(File1, O_READ)) { GXmlTree x(GXT_NO_ENTITIES); if (!x.Read(t1, &f, 0)) { DeleteObj(t1); } } else { DeleteObj(t1); } } if (t2 && File2) { GFile f; if (f.Open(File2, O_READ)) { GXmlTree x(GXT_NO_ENTITIES); if (!x.Read(t2, &f, 0)) { DeleteObj(t2); } } else { DeleteObj(t2); } } if (Lst && t1 && t2) { Lst->Enabled(false); Compare(t1, t2); Lst->Enabled(true); } DeleteObj(t1); DeleteObj(t2); } } } void Compare(GXmlTag *t1, GXmlTag *t2) { char s[1024]; if (stricmp(t1->GetTag(), t2->GetTag()) != 0) { sprintf(s, "Different Tag: '%s' <-> '%s'", t1->GetTag(), t2->GetTag()); LListItem *i = new LListItem; if (i) { i->SetText(s); i->SetText(TagName(t1), 1); Lst->Insert(i); } } LHashTbl,GXmlAttr*> a; for (int i=0; iAttr.Length(); i++) { GXmlAttr *a1 = &t1->Attr[i]; a.Add(a1->GetName(), a1); } for (int n=0; nAttr.Length(); n++) { GXmlAttr *a2 = &t2->Attr[n]; GXmlAttr *a1 = (GXmlAttr*) a.Find(a2->GetName()); if (a1) { if (strcmp(a1->GetValue(), a2->GetValue()) != 0) { sprintf(s, "Different Attr Value: '%s' <-> '%s'", a1->GetValue(), a2->GetValue()); LListItem *i = new LListItem; if (i) { i->SetText(s); sprintf(s, "%s.%s", TagName(t1), a1->GetName()); i->SetText(s, 1); Lst->Insert(i); } } a.Delete(a2->GetName()); } else { sprintf(s, "[Right] Missing Attr: '%s' = '%s'", a2->GetName(), a2->GetValue()); LListItem *i = new LListItem; if (i) { i->SetText(s); i->SetText(TagName(t1), 1); Lst->Insert(i); } } } // char *Key; // for (void *v = a.First(&Key); v; v = a.Next(&Key)) for (auto v : a) { GXmlAttr *a1 = v.value; sprintf(s, "[Left] Missing Attr: '%s' = '%s'", a1->GetName(), a1->GetValue()); LListItem *i = new LListItem; if (i) { i->SetText(s); i->SetText(TagName(t1), 1); Lst->Insert(i); } } if (t1->IsTag("string-group")) { GXmlTag *t; GArray r1, r2; for (t = t1->Children.First(); t; t = t1->Children.Next()) { char *Ref; if ((Ref = t->GetAttr("ref"))) { int r = atoi(Ref); if (r) { r1[r] = t; } } } for (t = t2->Children.First(); t; t = t2->Children.Next()) { char *Ref; if ((Ref = t->GetAttr("ref"))) { int r = atoi(Ref); if (r) { r2[r] = t; } } } int Max = MAX(r1.Length(), r2.Length()); for (int i = 0; iGetAttr("ref"), r1[i]->GetAttr("Define")); LListItem *n = new LListItem; if (n) { n->SetText(s); n->SetText(TagName(r1[i]), 1); Lst->Insert(n); } } else if (r2[i]) { sprintf(s, "[Left] Missing String: Ref=%s, Def=%s", r2[i]->GetAttr("ref"), r2[i]->GetAttr("Define")); LListItem *n = new LListItem; if (n) { n->SetText(s); n->SetText(TagName(r2[i]), 1); Lst->Insert(n); } } } } else { GXmlTag *c1 = t1->Children.First(); GXmlTag *c2 = t2->Children.First(); while (c1 && c2) { Compare(c1, c2); c1 = t1->Children.Next(); c2 = t2->Children.Next(); } } LgiYield(); } void OnPosChange() { GRect c = GetClient(); if (Lst) { c.Size(7, 7); Lst->SetPos(c); } } }; void AppWnd::Compare() { GFileSelect s; s.Parent(this); s.Type("Lgi Resource", "*.lr8"); if (s.Open()) { new ResCompare(GetCurFile(), s.Name()); } } void AppWnd::ImportLang() { // open dialog GFileSelect Select; Select.Parent(this); Select.Type("Lgi Resources", "*.lr8;*.xml"); if (Select.Open()) { GFile F; if (F.Open(Select.Name(), O_READ)) { SerialiseContext Ctx; Ctx.Format = GetFormat(Select.Name()); // convert file to Xml objects GXmlTag *Root = new GXmlTag; if (Root) { GXmlTree Tree(GXT_NO_ENTITIES); if (Tree.Read(Root, &F, 0)) { List Menus; List Groups; GXmlTag *t; for (t = Root->Children.First(); t; t = Root->Children.Next()) { if (t->IsTag("menu")) { ResMenu *Menu = new ResMenu(this); if (Menu && Menu->Read(t, Ctx)) { Menus.Insert(Menu); } else break; } else if (t->IsTag("string-group")) { ResStringGroup *g = new ResStringGroup(this); if (g && g->Read(t, Ctx)) { Groups.Insert(g); } else break; } } Ctx.PostLoad(this); bool HasData = false; for (ResStringGroup *g=Groups.First(); g; g=Groups.Next()) { g->SetLanguages(); if (g->GetStrs()->Length() > 0 && g->GetLanguages() > 0) { HasData = true; } } if (HasData) { List Langs; for (ResStringGroup *g=Groups.First(); g; g=Groups.Next()) { for (int i=0; iGetLanguages(); i++) { GLanguage *Lang = g->GetLanguage(i); if (Lang) { bool Has = false; for (GLanguage *l=Langs.First(); l; l=Langs.Next()) { if (stricmp((char*)l, (char*)Lang) == 0) { Has = true; break; } } if (!Has) { Langs.Insert(Lang); } } } } LangDlg Dlg(this, Langs); if (Dlg.DoModal() == IDOK && Dlg.Lang) { GStringPipe Errors; int Matches = 0; int NotFound = 0; int Imported = 0; int Different = 0; for (ResStringGroup *g=Groups.First(); g; g=Groups.Next()) { List::I Strings = g->GetStrs()->begin(); for (ResString *s=*Strings; s; s=*++Strings) { ResString *d = GetStrFromRef(s->GetRef()); if (d) { Matches++; char *Str = s->Get(Dlg.Lang->Id); char *Dst = d->Get(Dlg.Lang->Id); if ( ( Str && Dst && strcmp(Dst, Str) != 0 ) || ( (Str != 0) ^ (Dst != 0) ) ) { Different++; d->Set(Str, Dlg.Lang->Id); Imported++; } } else { NotFound++; char e[256]; sprintf(e, "String ref=%i (%s)\n", s->GetRef(), s->GetDefine()); Errors.Push(e); } } } List Lst; if (ListObjects(Lst)) { for (ResMenu *m=Menus.First(); m; m=Menus.Next()) { // find matching menu in our list ResMenu *Match = 0; for (Resource *r=Lst.First(); r; r=Lst.Next()) { ResMenu *n = dynamic_cast(r); if (n && stricmp(n->Name(), m->Name()) == 0) { Match = n; break; } } if (Match) { // match strings List *Src = m->GetStrs(); List *Dst = Match->GetStrs(); for (ResString *s=Src->First(); s; s = Src->Next()) { bool FoundRef = false; for (ResString *d=Dst->First(); d; d=Dst->Next()) { if (s->GetRef() == d->GetRef()) { FoundRef = true; char *Str = s->Get(Dlg.Lang->Id); if (Str) { char *Dst = d->Get(Dlg.Lang->Id); if (!Dst || strcmp(Dst, Str)) { Different++; } d->Set(Str, Dlg.Lang->Id); Imported++; } break; } } if (!FoundRef) { NotFound++; char e[256]; sprintf(e, "MenuString ref=%i (%s)\n", s->GetRef(), s->GetDefine()); Errors.Push(e); } } Match->SetLanguages(); } } for (Resource *r=Lst.First(); r; r=Lst.Next()) { ResStringGroup *StrRes = dynamic_cast(r); if (StrRes) { StrRes->SetLanguages(); } } } char *ErrorStr = Errors.NewStr(); LgiMsg( this, "Imported: %i\n" "Matched: %i\n" "Not matched: %i\n" "Different: %i\n" "Total: %i\n" "\n" "Import complete.\n" "\n%s", AppName, MB_OK, Imported, Matches, NotFound, Different, Matches + NotFound, ErrorStr?ErrorStr:(char*)""); } } else { LgiMsg(this, "No language information to import", AppName, MB_OK); } // Groups.DeleteObjects(); // Menus.DeleteObjects(); } else { LgiMsg(this, "Failed to parse XML from file.\nError: %s", AppName, MB_OK, Tree.GetErrorMsg()); } DeleteObj(Root); } } } } void AppWnd::Empty() { // Delete any existing objects List l; if (ListObjects(l)) { Resource *r; for (r = l.First(); r; ) { if (r->SystemObject()) { l.Delete(r); r = l.Current(); } else { r=l.Next(); } } for (r = l.First(); r; r=l.Next()) { DelObject(r); } } } bool AppWnd::OpenFile(char *FileName, bool Ro) { if (stristr(FileName, ".lr8") || stristr(FileName, ".xml")) { return LoadLgi(FileName); } else if (stristr(FileName, ".rc")) { return LoadWin32(FileName); } return false; } bool AppWnd::SaveFile(char *FileName) { if (stristr(FileName, ".lr8") || stristr(FileName, ".xml")) { return SaveLgi(FileName); } else if (stristr(FileName, ".rc")) { } return false; } void AppWnd::GetFileTypes(GFileSelect *Dlg, bool Write) { Dlg->Type("Lgi Resources", "*.lr8;*.xml"); if (!Write) { Dlg->Type("All Files", LGI_ALL_FILES); } } // Lgi load/save bool AppWnd::TestLgi(bool Quite) { bool Status = true; List l; if (ListObjects(l)) { ErrorCollection Errors; for (Resource *r = l.First(); r; r = l.Next()) { Status &= r->Test(&Errors); } if (Errors.StrErr.Length() > 0) { GStringPipe Sample; for (int i=0; iGetRef(), s->GetDefine(), Errors.StrErr[i].Msg.Get()); } char *Sam = Sample.NewStr(); LgiMsg(this, "%i strings have errors.\n\n%s", AppName, MB_OK, Errors.StrErr.Length(), Sam); DeleteArray(Sam); } else if (!Quite) { LgiMsg(this, "Object are all ok.", AppName); } } return Status; } bool AppWnd::LoadLgi(char *FileName) { bool Status = false; Empty(); if (FileName) { ResFileFormat Format = GetFormat(FileName); GFile f; if (f.Open(FileName, O_READ)) { GProgressDlg Progress(this); Progress.SetDescription("Initializing..."); Progress.SetType("Tags"); GXmlTag *Root = new GXmlTag; if (Root) { // convert file to Xml objects GXmlTree Xml(0); Progress.SetDescription("Lexing..."); if (Xml.Read(Root, &f, 0)) { Progress.SetLimits(0, Root->Children.Length()-1); // convert Xml list into objects int i=0; DoEvery Timer(500); SerialiseContext Ctx; for (GXmlTag *t = Root->Children.First(); t; t = Root->Children.Next(), i++) { if (Timer.DoNow()) { Progress.Value(Root->Children.IndexOf(t)); LgiYield(); } int RType = 0; if (t->IsTag("dialog")) { RType = TYPE_DIALOG; } else if (t->IsTag("string-group")) { RType = TYPE_STRING; } else if (t->IsTag("menu")) { RType = TYPE_MENU; } else if (t->IsTag("style")) { RType = TYPE_CSS; } else { LgiAssert(!"Unexpected tag"); } if (RType > 0) { NewObject(Ctx, t, RType, false); } } Ctx.PostLoad(this); SortDialogs(); TestLgi(); // Scan for languages and update the view lang menu Languages.Length(0); LHashTbl, GLanguage*> Langs; if (ViewMenu) { // Remove existing language menu items while (ViewMenu->RemoveItem(1)); ViewMenu->AppendSeparator(); // Enumerate all languages List res; if (ListObjects(res)) { for (Resource *r = res.First(); r; r = res.Next()) { ResStringGroup *Sg = r->IsStringGroup(); if (Sg) { for (int i=0; iGetLanguages(); i++) { GLanguage *Lang = Sg->GetLanguage(i); if (Lang) { Langs.Add(Lang->Id, Lang); } } } } } // Update languages array int n = 0; for (auto i : Langs) { Languages.Add(i.value); GMenuItem *Item = ViewMenu->AppendItem(i.value->Name, IDM_LANG_BASE + n, true); if (Item && i.value->IsEnglish()) { Item->Checked(true); CurLang = n; } n++; } if (Languages.Length() == 0) { ViewMenu->AppendItem("(none)", -1, false); } } Status = true; } else { LgiMsg(this, "Xml read failed: %s", AppName, MB_OK, Xml.GetErrorMsg()); } DeleteObj(Root); } } } return Status; } void SerialiseContext::PostLoad(AppWnd *App) { for (int i=0; iGetUniqueCtrlId(); s->SetId(Id); Log.Print("Repaired CtrlId of string ref %i to %i\n", s->GetRef(), Id); } GAutoString a(Log.NewStr()); if (ValidStr(a)) { LgiMsg(App, "%s", "Load Warnings", MB_OK, a.Get()); } } int DialogNameCompare(ResDialog *a, ResDialog *b, NativeInt Data) { char *A = (a)?a->Name():0; char *B = (b)?b->Name():0; if (A && B) return stricmp(A, B); return -1; } void AppWnd::SortDialogs() { List Lst; if (ListObjects(Lst)) { List Dlgs; for (Resource *r = Lst.First(); r; r = Lst.Next()) { ResDialog *Dlg = dynamic_cast(r); if (Dlg) { Dlgs.Insert(Dlg); Dlg->Item->Remove(); } } Dlgs.Sort(DialogNameCompare); for (ResDialog *d = Dlgs.First(); d; d = Dlgs.Next()) { Objs->Dialogs->Insert(d->Item); } } } class ResTreeNode { public: char *Str; ResTreeNode *a, *b; ResTreeNode(char *s) { a = b = 0; Str = s; } ~ResTreeNode() { DeleteArray(Str); DeleteObj(a); DeleteObj(b); } void Enum(List &l) { if (a) { a->Enum(l); } if (Str) { l.Insert(Str); } if (b) { b->Enum(l); } } bool Add(char *s) { int Comp = (Str && s) ? stricmp(Str, s) : -1; if (Comp == 0) { return false; } if (Comp < 0) { if (a) { return a->Add(s); } else { a = new ResTreeNode(s); } } if (Comp > 0) { if (b) { return b->Add(s); } else { b = new ResTreeNode(s); } } return true; } }; class ResTree { ResTreeNode *Root; public: ResTree() { Root = 0; } ~ResTree() { DeleteObj(Root); } bool Add(char *s) { if (s) { if (!Root) { Root = new ResTreeNode(NewStr(s)); return true; } else { return Root->Add(NewStr(s)); } } return false; } void Enum(List &l) { if (Root) { Root->Enum(l); } } }; const char *HeaderStr = "// This file generated by LgiRes\r\n\r\n"; struct DefinePair { char *Name; int Value; }; int PairCmp(DefinePair *a, DefinePair *b) { return a->Value - b->Value; } bool AppWnd::WriteDefines(GFile &Defs) { bool Status = false; ResTree Tree; // Empty file Defs.Seek(0, SEEK_SET); Defs.SetSize(0); Defs.Write(HeaderStr, strlen(HeaderStr)); // make a unique list of #define's List Lst; if (ListObjects(Lst)) { LHashTbl,int> Def; LHashTbl,char*> Ident; for (Resource *r = Lst.First(); r; r = Lst.Next()) { List *StrList = r->GetStrs(); if (StrList) { Status = true; List::I sl = StrList->begin(); for (ResString *s = *sl; s; s = *++sl) { if (ValidStr(s->GetDefine())) { if (stricmp(s->GetDefine(), "IDOK") == 0) { s->SetId(IDOK); } else if (stricmp(s->GetDefine(), "IDCANCEL") == 0) { s->SetId(IDCANCEL); } else if (stricmp(s->GetDefine(), "IDC_STATIC") == 0) { s->SetId(-1); } else if (stricmp(s->GetDefine(), "-1") == 0) { s->SetDefine(0); } else { // Remove dupe ID's char IdStr[32]; sprintf(IdStr, "%i", s->GetId()); char *Define; if ((Define = Ident.Find(IdStr))) { if (strcmp(Define, s->GetDefine())) { List n; FindStrings(n, s->GetDefine()); int NewId = GetUniqueCtrlId(); for (ResString *Ns = n.First(); Ns; Ns = n.Next()) { Ns->SetId(NewId); } } } else { Ident.Add(IdStr, s->GetDefine()); } // Make all define's the same int CtrlId; if ((CtrlId = Def.Find(s->GetDefine()))) { // Already there... s->SetId(CtrlId); } else { // Add... LgiAssert(s->GetId()); if (s->GetId()) Def.Add(s->GetDefine(), s->GetId()); } } } } } } // write the list out GArray Pairs; // char *s = 0; // for (int i = Def.First(&s); i; i = Def.Next(&s)) for (auto i : Def) { if (ValidStr(i.key) && stricmp(i.key, "IDOK") != 0 && stricmp(i.key, "IDCANCEL") != 0 && stricmp(i.key, "IDC_STATIC") != 0 && stricmp(i.key, "-1") != 0) { DefinePair &p = Pairs.New(); p.Name = i.key; p.Value = i.value; } } Pairs.Sort(PairCmp); for (int n=0; n=' ' && (uint8)(c) <= 127) + #define IsPrintable(c) ((uint8_t)(c)>=' ' && (uint8_t)(c) <= 127) if (IsPrintable(s[0]) && IsPrintable(s[1]) && IsPrintable(s[2]) && IsPrintable(s[3])) { #ifndef __BIG_ENDIAN__ int32 i = LgiSwap32(p.Value); memcpy(s, &i, 4); #endif Defs.Print("#define %s%s'%04.4s'\r\n", p.Name, Tab, s); } else Defs.Print("#define %s%s%i\r\n", p.Name, Tab, p.Value); } } return Status; } bool AppWnd::SaveLgi(char *FileName) { bool Status = false; if (!TestLgi()) { if (LgiMsg(this, "Do you want to save the file with errors?", AppName, MB_YESNO) == IDNO) { return false; } } // Rename the existing file to 'xxxxxx.bak' if (FileExists(FileName)) { char Bak[MAX_PATH]; strcpy_s(Bak, sizeof(Bak), FileName); char *e = LgiGetExtension(Bak); if (e) { strcpy(e, "bak"); if (FileExists(Bak)) FileDev->Delete(Bak, false); FileDev->Move(FileName, Bak); } } // Save the file to xml if (FileName) { GFile f; GFile Defs; ResFileFormat Format = GetFormat(FileName); char DefsName[256]; strcpy(DefsName, FileName); LgiTrimDir(DefsName); strcat(DefsName, DIR_STR); strcat(DefsName, "resdefs.h"); if (f.Open(FileName, O_WRITE) && Defs.Open(DefsName, O_WRITE)) { SerialiseContext Ctx; f.SetSize(0); Defs.SetSize(0); Defs.Print("// Generated by LgiRes\r\n\r\n"); List l; if (ListObjects(l)) { // Remove all duplicate symbol Id's from the dialogs Resource *r; for (r = l.First(); r; r = l.Next()) { ResDialog *Dlg = dynamic_cast(r); if (Dlg) { Dlg->CleanSymbols(); } } // write defines WriteDefines(Defs); GXmlTag Root("resources"); // Write all string lists out first so that when we load objects // back in again the strings will already be loaded and can // be referenced for (r = l.First(); r; r = l.Next()) { if (r->Type() == TYPE_STRING) { GXmlTag *c = new GXmlTag; if (c && r->Write(c, Ctx)) { Root.InsertTag(c); } else { LgiAssert(0); DeleteObj(c); } } } // now write the rest of the objects out for (r = l.First(); r; r = l.Next()) { if (r->Type() != TYPE_STRING) { GXmlTag *c = new GXmlTag; if (c && r->Write(c, Ctx)) { Root.InsertTag(c); } else { r->Write(c, Ctx); LgiAssert(0); DeleteObj(c); } } } // Set the offset type. // // Older versions of LgiRes stored the dialog's controls at a fixed // offset (3,17) from where they shouldv'e been. That was fixed, but // to differentiate between the 2 systems, we store a tag at the // root element. Root.SetAttr("Offset", 1); GXmlTree Tree(GXT_NO_ENTITIES); Status = Tree.Write(&Root, &f); } } else { LgiMsg(this, "Couldn't open these files for output:\n" "\t%s\n" "\t%s\n" "\n" "Maybe they are read only or locked by another application.", AppName, MB_OK, FileName, DefsName); } } return Status; } // Win32 load/save #define ADJUST_CTRLS_X 2 #define ADJUST_CTRLS_Y 12 #define IMP_MODE_SEARCH 0 #define IMP_MODE_DIALOG 1 #define IMP_MODE_DLG_CTRLS 2 #define IMP_MODE_STRINGS 3 #define IMP_MODE_MENU 4 #include "GToken.h" class ImportDefine { public: char *Name; char *Value; ImportDefine() { Name = Value = 0; } ImportDefine(char *Line) { Name = Value = 0; if (Line && *Line == '#') { Line++; if (strnicmp(Line, "define", 6) == 0) { Line += 6; Line = LgiSkipDelim(Line); char *Start = Line; const char *WhiteSpace = " \r\n\t"; while (*Line && !strchr(WhiteSpace, *Line)) { Line++; } Name = NewStr(Start, Line-Start); Line = LgiSkipDelim(Line); Start = Line; while (*Line && !strchr(WhiteSpace, *Line)) { Line++; } if (Start != Line) { Value = NewStr(Start, Line-Start); } } } } ~ImportDefine() { DeleteArray(Name); DeleteArray(Value); } }; class DefineList : public List { int NestLevel; public: bool Defined; List IncludeDirs; DefineList() { Defined = true; NestLevel = 0; } ~DefineList() { for (ImportDefine *i = First(); i; i = Next()) { DeleteObj(i); } for (char *c = IncludeDirs.First(); c; c = IncludeDirs.Next()) { DeleteArray(c); } } void DefineSymbol(const char *Name, const char *Value = 0) { ImportDefine *Def = new ImportDefine; if (Def) { Def->Name = NewStr(Name); if (Value) Def->Value = NewStr(Value); Insert(Def); } } ImportDefine *GetDefine(char *Name) { if (Name) { for (ImportDefine *i = First(); i; i = Next()) { if (i->Name && stricmp(i->Name, Name) == 0) { return i; } } } return NULL; } void ProcessLine(char *Line) { if (NestLevel > 16) { return; } if (Line && *Line == '#') { Line++; GToken T(Line); if (T.Length() > 0) { if (stricmp(T[0], "define") == 0) // #define { ImportDefine *Def = new ImportDefine(Line-1); if (Def) { if (Def->Name) { Insert(Def); } else { DeleteObj(Def); } } } else if (stricmp(T[0], "include") == 0) // #include { NestLevel++; GFile F; if (T.Length() > 1) { for (char *IncPath = IncludeDirs.First(); IncPath; IncPath = IncludeDirs.Next()) { char FullPath[256]; strcpy(FullPath, IncPath); if (FullPath[strlen(FullPath)-1] != DIR_CHAR) { strcat(FullPath, DIR_STR); } strcat(FullPath, T[1]); if (F.Open(FullPath, O_READ)) { char Line[1024]; while (!F.Eof()) { F.ReadStr(Line, sizeof(Line)); char *p = LgiSkipDelim(Line); if (*p == '#') { ProcessLine(p); } } break; } } } NestLevel--; } else if (stricmp(T[0], "if") == 0) // #if { } else if (stricmp(T[0], "ifdef") == 0) // #if { if (T.Length() > 1) { Defined = GetDefine(T[1]) != 0; } } else if (stricmp(T[0], "endif") == 0) // #endif { Defined = true; } else if (stricmp(T[0], "pragma") == 0) { ImportDefine *Def = new ImportDefine; if (Def) { char *Str = Line + 7; char *First = strchr(Str, '('); char *Second = (First) ? strchr(First+1, ')') : 0; if (First && Second) { Insert(Def); Def->Name = NewStr(Str, First-Str); First++; Def->Value = NewStr(First, Second-First); } else { DeleteObj(Def); } } } else if (stricmp(T[0], "undef") == 0) { } } } // else it's not for us anyway } }; void TokLine(GArray &T, char *Line) { if (Line) { // Exclude comments for (int k=0; Line[k]; k++) { if (Line[k] == '/' && Line[k+1] == '/') { Line[k] = 0; break; } } // Break into tokens for (const char *s = Line; s && *s; ) { while (*s && strchr(" \t", *s)) s++; char *t = LgiTokStr(s); if (t) T.Add(t); else break; } } } bool AppWnd::LoadWin32(char *FileName) { bool Status = false; GFileSelect Select; LHashTbl,bool> CtrlNames; CtrlNames.Add("LTEXT", true); CtrlNames.Add("EDITTEXT", true); CtrlNames.Add("COMBOBOX", true); CtrlNames.Add("SCROLLBAR", true); CtrlNames.Add("GROUPBOX", true); CtrlNames.Add("PUSHBUTTON", true); CtrlNames.Add("DEFPUSHBUTTON", true); CtrlNames.Add("CONTROL", true); CtrlNames.Add("ICON", true); CtrlNames.Add("LISTBOX", true); Empty(); if (!FileName) { Select.Parent(this); Select.Type("Win32 Resource Script", "*.rc"); if (Select.Open()) { FileName = Select.Name(); } } if (FileName) { GProgressDlg Progress(this); Progress.SetDescription("Initializing..."); Progress.SetType("K"); Progress.SetScale(1.0/1024.0); char *FileTxt = ReadTextFile(Select.Name()); if (FileTxt) { GToken Lines(FileTxt, "\r\n"); DeleteArray(FileTxt); DefineList Defines; ResStringGroup *String = new ResStringGroup(this); int Mode = IMP_MODE_SEARCH; // Language char *Language = 0; GLanguageId LanguageId = 0; // Dialogs List DlLList; CtrlDlg *Dlg = 0; // Menus ResDialog *Dialog = 0; ResMenu *Menu = 0; List Menus; ResMenuItem *MenuItem[32]; int MenuLevel = 0; bool MenuNewLang = false; int MenuNextItem = 0; // Include defines char IncPath[256]; strcpy(IncPath, Select.Name()); LgiTrimDir(IncPath); Defines.IncludeDirs.Insert(NewStr(IncPath)); Defines.DefineSymbol("_WIN32"); Defines.DefineSymbol("IDC_STATIC", "-1"); DoEvery Ticker(200); Progress.SetDescription("Reading resources..."); Progress.SetLimits(0, Lines.Length()-1); if (String) { InsertObject(TYPE_STRING, String, false); } for (int CurLine = 0; CurLine < Lines.Length(); CurLine++) { if (Ticker.DoNow()) { Progress.Value(CurLine); LgiYield(); } // Skip white space char *Line = Lines[CurLine]; char *p = LgiSkipDelim(Line); Defines.ProcessLine(Line); // Tokenize GArray T; TokLine(T, Line); // Process line if (Defines.Defined) { switch (Mode) { case IMP_MODE_SEARCH: { DeleteObj(Dialog); Dlg = 0; if (*p != '#') { if (T.Length() > 1 && (stricmp(T[1], "DIALOG") == 0 || stricmp(T[1], "DIALOGEX") == 0)) { Mode = IMP_MODE_DIALOG; Dialog = new ResDialog(this); if (Dialog) { Dialog->Create(NULL, NULL); Dialog->Name(T[0]); GAutoPtr It(Dialog->IterateViews()); Dlg = dynamic_cast(It->First()); if (Dlg) { int Pos[4] = {0, 0, 0, 0}; int i = 0; for (; iResDialogCtrl::SetPos(r); Dlg->Str->SetDefine(T[0]); ImportDefine *Def = Defines.GetDefine(T[0]); if (Def) { Dlg->Str->SetId(atoi(Def->Value)); } } } break; } if (T.Length() > 1 && stricmp(T[1], "MENU") == 0) { ZeroObj(MenuItem); Mode = IMP_MODE_MENU; Menu = 0; // Check for preexisting menu in another language MenuNewLang = false; for (ResMenu *m = Menus.First(); m; m = Menus.Next()) { if (stricmp(m->Name(), T[0]) == 0) { MenuNewLang = true; Menu = m; break; } } // If it doesn't preexist then create it if (!Menu) { Menu = new ResMenu(this); if (Menu) { Menus.Insert(Menu); Menu->Create(NULL, NULL); Menu->Name(T[0]); } } break; } if (T.Length() > 0 && stricmp(T[0], "STRINGTABLE") == 0) { Mode = IMP_MODE_STRINGS; if (String) { String->Name("_Win32 Imports_"); } break; } if (T.Length() > 2 && stricmp(T[0], "LANGUAGE") == 0) { LanguageId = 0; DeleteArray(Language); char *Language = NewStr(T[1]); if (Language) { GLanguage *Info = GFindLang(0, Language); if (Info) { LanguageId = Info->Id; ResDialog::AddLanguage(Info->Id); } } break; } } break; } case IMP_MODE_DIALOG: { if (T.Length() > 0 && Dlg) { if (stricmp(T[0], "CAPTION") == 0) { char *Caption = T[1]; if (Caption) { Dlg->Str->Set(Caption, LanguageId); } } else if (stricmp(T[0], "BEGIN") == 0) { Mode = IMP_MODE_DLG_CTRLS; } } break; } case IMP_MODE_DLG_CTRLS: { char *Type = T[0]; if (!Type) break; if (stricmp(Type, "end") != 0) { // Add wrapped content to the token array. char *Next = Lines[CurLine+1]; if (Next) { Next = LgiSkipDelim(Next); char *NextTok = LgiTokStr((const char*&)Next); if (NextTok) { if (stricmp(NextTok, "END") != 0 && !CtrlNames.Find(NextTok)) { TokLine(T, Lines[++CurLine]); } DeleteArray(NextTok); } } } // Process controls if (stricmp(Type, "LTEXT") == 0) { if (T.Length() >= 7) { CtrlText *Ctrl = new CtrlText(Dialog, 0); if (Ctrl) { Ctrl->Str->Set(T[1], LanguageId); Ctrl->Str->SetDefine(T[2]); ImportDefine *Def = Defines.GetDefine(T[2]); if (Def) { Ctrl->Str->SetId(atoi(Def->Value)); } GRect r; r.ZOff(atoi(T[5])*CTRL_X, atoi(T[6])*CTRL_Y); r.Offset(atoi(T[3])*CTRL_X+ADJUST_CTRLS_X, atoi(T[4])*CTRL_Y+ADJUST_CTRLS_Y); Ctrl->ResDialogCtrl::SetPos(r); Dlg->AddView(Ctrl); } } } else if (stricmp(Type, "EDITTEXT") == 0) { if (T.Length() >= 7) { CtrlEditbox *Ctrl = new CtrlEditbox(Dialog, 0); if (Ctrl) { Ctrl->Str->SetDefine(T[1]); ImportDefine *Def = Defines.GetDefine(T[1]); if (Def) { Ctrl->Str->SetId(atoi(Def->Value)); } GRect r; r.ZOff(atoi(T[4])*CTRL_X, atoi(T[5])*CTRL_Y); r.Offset(atoi(T[2])*CTRL_X+ADJUST_CTRLS_X, atoi(T[3])*CTRL_Y+ADJUST_CTRLS_Y); Ctrl->ResDialogCtrl::SetPos(r); Dlg->AddView(Ctrl); } } } else if (stricmp(Type, "COMBOBOX") == 0) { if (T.Length() >= 6) { CtrlComboBox *Ctrl = new CtrlComboBox(Dialog, 0); if (Ctrl) { Ctrl->Str->SetDefine(T[1]); ImportDefine *Def = Defines.GetDefine(T[1]); if (Def) { Ctrl->Str->SetId(atoi(Def->Value)); } GRect r; r.ZOff(atoi(T[4])*CTRL_X, atoi(T[5])*CTRL_Y); r.Offset(atoi(T[2])*CTRL_X+ADJUST_CTRLS_X, atoi(T[3])*CTRL_Y+ADJUST_CTRLS_Y); Ctrl->ResDialogCtrl::SetPos(r); Dlg->AddView(Ctrl); } } } else if (stricmp(Type, "SCROLLBAR") == 0) { if (T.Length() == 6) { CtrlScrollBar *Ctrl = new CtrlScrollBar(Dialog, 0); if (Ctrl) { Ctrl->Str->SetDefine(T[1]); ImportDefine *Def = Defines.GetDefine(T[1]); if (Def) { Ctrl->Str->SetId(atoi(Def->Value)); } GRect r; r.ZOff(atoi(T[4])*CTRL_X, atoi(T[5])*CTRL_Y); r.Offset(atoi(T[2])*CTRL_X+ADJUST_CTRLS_X, atoi(T[3])*CTRL_Y+ADJUST_CTRLS_Y); Ctrl->ResDialogCtrl::SetPos(r); Dlg->AddView(Ctrl); } } } else if (stricmp(Type, "GROUPBOX") == 0) { if (T.Length() >= 7) { CtrlGroup *Ctrl = new CtrlGroup(Dialog, 0); if (Ctrl) { Ctrl->Str->Set(T[1], LanguageId); Ctrl->Str->SetDefine(T[2]); ImportDefine *Def = Defines.GetDefine(T[2]); if (Def) { Ctrl->Str->SetId(atoi(Def->Value)); } GRect r; r.ZOff(atoi(T[5])*CTRL_X, atoi(T[6])*CTRL_Y); r.Offset(atoi(T[3])*CTRL_X+ADJUST_CTRLS_X, atoi(T[4])*CTRL_Y+ADJUST_CTRLS_Y); Ctrl->ResDialogCtrl::SetPos(r); Dlg->AddView(Ctrl); } } } else if (stricmp(Type, "PUSHBUTTON") == 0 || stricmp(Type, "DEFPUSHBUTTON") == 0) { if (T.Length() >= 7) { CtrlButton *Ctrl = new CtrlButton(Dialog, 0); if (Ctrl) { Ctrl->Str->Set(T[1], LanguageId); Ctrl->Str->SetDefine(T[2]); ImportDefine *Def = Defines.GetDefine(T[2]); if (Def) { Ctrl->Str->SetId(atoi(Def->Value)); } GRect r; r.ZOff(atoi(T[5])*CTRL_X, atoi(T[6])*CTRL_Y); r.Offset(atoi(T[3])*CTRL_X+ADJUST_CTRLS_X, atoi(T[4])*CTRL_Y+ADJUST_CTRLS_Y); Ctrl->ResDialogCtrl::SetPos(r); Dlg->AddView(Ctrl); } } } else if (stricmp(Type, "CONTROL") == 0) { if (T.Length() >= 7) { char *Caption = T[1]; char *Id = T[2]; char *Type = T[3]; bool Checkbox = false; bool Radio = false; bool Done = false; // loop through styles int i; for (i=4; !Done && iSetPos(r); if (Caption) Ctrl->Str->Set(Caption, LanguageId); if (Id) Ctrl->Str->SetDefine(Id); ImportDefine *Def = Defines.GetDefine(Id); if (Def) { Ctrl->Str->SetId(atoi(Def->Value)); } Dlg->AddView(Ctrl->View()); } } } } else if (stricmp(Type, "ICON") == 0) { if (T.Length() >= 7) { CtrlBitmap *Ctrl = new CtrlBitmap(Dialog, 0); if (Ctrl) { Ctrl->Str->SetDefine(T[1]); ImportDefine *Def = Defines.GetDefine(T[1]); if (Def) { Ctrl->Str->SetId(atoi(Def->Value)); } GRect r; r.ZOff(atoi(T[5])*CTRL_X, atoi(T[6])*CTRL_Y); r.Offset(atoi(T[3])*CTRL_X+ADJUST_CTRLS_X, atoi(T[4])*CTRL_Y+ADJUST_CTRLS_Y); Ctrl->ResDialogCtrl::SetPos(r); Dlg->AddView(Ctrl->View()); } } } else if (stricmp(Type, "LISTBOX") == 0) { if (T.Length() >= 7) { CtrlList *Ctrl = new CtrlList(Dialog, 0); if (Ctrl) { Ctrl->Str->SetDefine(T[1]); ImportDefine *Def = Defines.GetDefine(T[1]); if (Def) { Ctrl->Str->SetId(atoi(Def->Value)); } GRect r; r.ZOff(atoi(T[4])*CTRL_X, atoi(T[5])*CTRL_Y); r.Offset(atoi(T[2])*CTRL_X+ADJUST_CTRLS_X, atoi(T[3])*CTRL_Y+ADJUST_CTRLS_Y); Ctrl->ResDialogCtrl::SetPos(r); Dlg->AddView(Ctrl); } } } else if (stricmp(Type, "END") == 0) { // search for an existing dialog resource in // another language ResDialog *Match = 0; CtrlDlg *MatchObj = 0; for (ResDialog *d = DlLList.First(); d; d = DlLList.Next()) { GAutoPtr It(d->IterateViews()); GViewI *Wnd = It->First(); if (Wnd) { CtrlDlg *Obj = dynamic_cast(Wnd); if (Obj) { if (Obj->Str->GetId() == Dlg->Str->GetId()) { MatchObj = Obj; Match = d; break; } } } } if (Match) { // Merge the controls from "Dlg" to "MatchObj" List Old; List New; Dlg->ListChildren(New); MatchObj->ListChildren(Old); // add the language strings for the caption // without clobbering the languages already // present for (StrLang *s = Dlg->Str->Items.First(); s; s = Dlg->Str->Items.Next()) { if (!MatchObj->Str->Get(s->GetLang())) { MatchObj->Str->Set(s->GetStr(), s->GetLang()); } } for (ResDialogCtrl *c = New.First(); c; c = New.Next()) { ResDialogCtrl *MatchCtrl = 0; // try matching by Id { for (ResDialogCtrl *Mc = Old.First(); Mc; Mc = Old.Next()) { if (Mc->Str->GetId() == c->Str->GetId() && Mc->Str->GetId() > 0) { MatchCtrl = Mc; break; } } } // ok no Id match, match by location and type if (!MatchCtrl) { List Overlapping; for (ResDialogCtrl *Mc = Old.First(); Mc; Mc = Old.Next()) { GRect a = Mc->View()->GetPos(); GRect b = c->View()->GetPos(); GRect c = a; c.Bound(&b); if (c.Valid()) { int Sa = a.X() * a.Y(); int Sb = b.X() * b.Y(); int Sc = c.X() * c.Y(); int Total = Sa + Sb - Sc; double Amount = (double) Sc / (double) Total; if (Amount > 0.5) { // mostly similar in size Overlapping.Insert(Mc); } } } if (Overlapping.Length() == 1) { MatchCtrl = Overlapping.First(); } } if (MatchCtrl) { // woohoo we are cool for (StrLang *s = c->Str->Items.First(); s; s = c->Str->Items.Next()) { MatchCtrl->Str->Set(s->GetStr(), s->GetLang()); } } } // Delete the duplicate OnObjSelect(0); DeleteObj(Dialog); } else { // Insert the dialog InsertObject(TYPE_DIALOG, Dialog, false); DlLList.Insert(Dialog); } Dialog = 0; Dlg = 0; Status = true; Mode = IMP_MODE_SEARCH; } break; } case IMP_MODE_STRINGS: { if (stricmp(T[0], "BEGIN") == 0) { } else if (stricmp(T[0], "END") == 0) { Status = true; Mode = IMP_MODE_SEARCH; } else { if (T.Length() > 1) { ResString *Str = String->FindName(T[0]); if (!Str) { Str = String->CreateStr(); if (Str) { ImportDefine *Def = Defines.GetDefine(T[0]); if (Def) { Str->SetId(atoi(Def->Value)); } Str->SetDefine(T[0]); Str->UnDuplicate(); } } if (Str) { // get the language GLanguage *Lang = GFindLang(Language); GLanguageId SLang = (Lang) ? Lang->Id : (char*)"en"; StrLang *s = 0; // look for language present in string object for (s = Str->Items.First(); s && *s != SLang; s = Str->Items.Next()); // if not present then add it if (!s) { s = new StrLang; if (s) { Str->Items.Insert(s); s->SetLang(SLang); } } // set the value if (s) { s->SetStr(T[1]); } } } } break; } case IMP_MODE_MENU: { if (T.Length() >= 1) { if (stricmp(T[0], "BEGIN") == 0) { MenuLevel++; } else if (stricmp(T[0], "END") == 0) { MenuLevel--; if (MenuLevel == 0) { Status = true; Mode = IMP_MODE_SEARCH; Menu->SetLanguages(); if (!MenuNewLang) { InsertObject(TYPE_MENU, Menu, false); } Menu = 0; } } else { ResMenuItem *i = 0; char *Text = T[1]; if (Text) { if (stricmp(T[0], "POPUP") == 0) { if (MenuNewLang) { GTreeItem *Ri = 0; if (MenuItem[MenuLevel]) { Ri = MenuItem[MenuLevel]->GetNext(); } else { if (MenuLevel == 1) { Ri = Menu->ItemAt(0); } else if (MenuItem[MenuLevel-1]) { Ri = MenuItem[MenuLevel-1]->GetChild(); } } if (Ri) { // Seek up to the next submenu while (!Ri->GetChild()) { Ri = Ri->GetNext(); } i = dynamic_cast(Ri); // char *si = i->Str.Get("en"); if (i) { MenuItem[MenuLevel] = i; } } } else { MenuItem[MenuLevel] = i = new ResMenuItem(Menu); } if (i) { GLanguage *Lang = GFindLang(Language); i->GetStr()->Set(Text, (Lang) ? Lang->Id : (char*)"en"); } MenuNextItem = 0; } else if (stricmp(T[0], "MENUITEM") == 0) { if (MenuNewLang) { if (MenuItem[MenuLevel-1] && T.Length() > 2) { ImportDefine *id = Defines.GetDefine(T[2]); if (id) { int Id = atoi(id->Value); int n = 0; for (GTreeItem *o = MenuItem[MenuLevel-1]->GetChild(); o; o = o->GetNext(), n++) { ResMenuItem *Res = dynamic_cast(o); if (Res && Res->GetStr()->GetId() == Id) { i = Res; break; } } } } MenuNextItem++; } else { i = new ResMenuItem(Menu); } if (i) { if (stricmp(Text, "SEPARATOR") == 0) { // Set separator i->Separator(true); } else { if (!MenuNewLang) { // Set Id i->GetStr()->SetDefine(T[2]); if (i->GetStr()->GetDefine()) { ImportDefine *id = Defines.GetDefine(i->GetStr()->GetDefine()); if (id) { i->GetStr()->SetId(atoi(id->Value)); i->GetStr()->UnDuplicate(); } } } // Set Text GLanguage *Lang = GFindLang(Language); i->GetStr()->Set(Text, (Lang) ? Lang->Id : (char*)"en"); } } } } if (i && !MenuNewLang) { if (MenuLevel == 1) { Menu->Insert(i); } else if (MenuItem[MenuLevel-1]) { MenuItem[MenuLevel-1]->Insert(i); } } } } break; } } } T.DeleteArrays(); } DeleteObj(Dialog); if (String->Length() > 0) { String->SetLanguages(); } } Invalidate(); } return Status; } bool AppWnd::SaveWin32() { return false; } ///////////////////////////////////////////////////////////////////////// ResFrame::ResFrame(Resource *child) { Child = child; Name("ResFrame"); } ResFrame::~ResFrame() { if (Child) { Child->App()->OnObjSelect(NULL); Child->Wnd()->Detach(); } } void ResFrame::OnFocus(bool b) { Child->Wnd()->Invalidate(); } bool ResFrame::Attach(GViewI *p) { bool Status = GLayout::Attach(p); if (Status && Child) { Child->Attach(this); Child->Wnd()->Visible(true); } return Status; } bool ResFrame::Pour(GRegion &r) { GRect *Best = FindLargest(r); if (Best) { SetPos(*Best); return true; } return false; } bool ResFrame::OnKey(GKey &k) { bool Status = false; if (k.Down() && Child) { switch (k.c16) { case VK_DELETE: { if (k.Shift()) { Child->Copy(true); } else { Child->Delete(); } Status = true; break; } case 'x': case 'X': { if (k.Ctrl()) { Child->Copy(true); Status = true; } break; } case 'c': case 'C': { if (k.Ctrl()) { Child->Copy(); Status = true; } break; } case VK_INSERT: { if (k.Ctrl()) { Child->Copy(); } else if (k.Shift()) { Child->Paste(); } Status = true; break; } case 'v': case 'V': { if (k.Ctrl()) { Child->Paste(); Status = true; } break; } } } return Child->Wnd()->OnKey(k) || Status; } void ResFrame::OnPaint(GSurface *pDC) { // Draw nice frame GRect r(0, 0, X()-1, Y()-1); LgiThinBorder(pDC, r, DefaultRaisedEdge); pDC->Colour(LC_MED, 24); LgiFlatBorder(pDC, r, 4); LgiWideBorder(pDC, r, DefaultSunkenEdge); // Set the child to the client area Child->Wnd()->SetPos(r); // Draw the dialog & controls GView::OnPaint(pDC); } //////////////////////////////////////////////////////////////////// LgiFunc char *_LgiGenLangLookup(); #include "GAutoPtr.h" #include "GVariant.h" #include "GCss.h" #include "GTableLayout.h" class Foo : public GLayoutCell { public: Foo() { TextAlign(AlignLeft); } bool Add(GView *v) { return false; } bool Remove(GView *v) { return false; } }; ////////////////////////////////////////////////////////////////////// ShortCutView::ShortCutView(AppWnd *app) { App = app; GRect r(0, 0, 300, 600); SetPos(r); MoveSameScreen(App); Name("Dialog Shortcuts"); if (Attach(0)) { Lst = new LList(100, 0, 0, 100, 100); Lst->Attach(this); Lst->SetPourLargest(true); Lst->AddColumn("Key", 50); Lst->AddColumn("Ref", 80); Lst->AddColumn("Control", 150); Visible(true); } } ShortCutView::~ShortCutView() { App->OnCloseView(this); } void FindShortCuts(LList *Out, GViewI *In) { GAutoPtr it(In->IterateViews()); for (GViewI *c = it->First(); c; c = it->Next()) { ResDialogCtrl *rdc = dynamic_cast(c); if (!rdc || !rdc->Str) continue; char *n = rdc->Str->Get(); if (n) { char *a = strchr(n, '&'); if (a && a[1] != '&') { LListItem *li = new LListItem; GString s(++a, 1); GString id; id.Printf("%i", rdc->Str->GetRef()); li->SetText(s.Upper(), 0); li->SetText(id, 1); li->SetText(rdc->GetClass(), 2); li->_UserPtr = rdc; Out->Insert(li); } } FindShortCuts(Out, c); } } int ShortCutView::OnNotify(GViewI *Ctrl, int Flags) { if (Ctrl->GetId() == Lst->GetId()) { switch (Flags) { case GNotifyItem_Click: { LListItem *li = Lst->GetSelected(); if (li) { GString s = li->GetText(1); ResDialogCtrl *c = (ResDialogCtrl*) li->_UserPtr; if (c) App->GotoObject(c->Str, NULL, c->GetDlg(), NULL, c); } break; } } } return GWindow::OnNotify(Ctrl, Flags); } void ShortCutView::OnDialogChange(ResDialog *Dlg) { Lst->Empty(); if (!Dlg) return; FindShortCuts(Lst, Dlg); Lst->Sort(NULL); } ShortCutView *AppWnd::GetShortCutView() { return ShortCuts; } void AppWnd::OnCloseView(ShortCutView *v) { if (v == ShortCuts) ShortCuts = NULL; } ////////////////////////////////////////////////////////////////////// void TestFunc() { /* Foo c; uint32 *p = (uint32*)&c; p++; p = (uint32*)(*p); void *method = (void*)p[2]; for (int i=0; i<16; i++) { printf("[%i]=%p\n", i, p[i]); } c.OnChange(GCss::PropBackground); */ } int LgiMain(OsAppArguments &AppArgs) { GApp a(AppArgs, "LgiRes"); if (a.IsOk()) { if ((a.AppWnd = new AppWnd)) { TestFunc(); a.AppWnd->Visible(true); a.Run(); } } return 0; } diff --git a/ResourceEditor/Code/LgiRes_Dialog.cpp b/ResourceEditor/Code/LgiRes_Dialog.cpp --- a/ResourceEditor/Code/LgiRes_Dialog.cpp +++ b/ResourceEditor/Code/LgiRes_Dialog.cpp @@ -1,4315 +1,4315 @@ /* ** FILE: LgiRes_Dialog.cpp ** AUTHOR: Matthew Allen ** DATE: 5/8/1999 ** DESCRIPTION: Dialog Resource Editor ** ** ** Copyright (C) 1999, Matthew Allen ** fret@memecode.com */ // Old control offset 3,17 //////////////////////////////////////////////////////////////////// #include #include "LgiResEdit.h" #include "LgiRes_Dialog.h" #include "GButton.h" #include "GVariant.h" #include "GToken.h" #include "GDisplayString.h" #include "GClipBoard.h" #include "resdefs.h" //////////////////////////////////////////////////////////////////// #define IDC_UP 101 #define IDC_DOWN 102 // Name mapping table class LgiObjectName { public: int Type; const char *ObjectName; char *ResourceName; bool ToolbarBtn; } NameMap[] = { // ID Lgi's name Resource editor name {UI_DIALOG, "GDialog", Res_Dialog, false}, {UI_TABLE, "GTableLayout", Res_Table, true}, {UI_TEXT, "GText", Res_StaticText, true}, {UI_EDITBOX, "GEdit", Res_EditBox, true}, {UI_CHECKBOX, "GCheckBox", Res_CheckBox, true}, {UI_BUTTON, "GButton", Res_Button, true}, {UI_GROUP, "GRadioGroup", Res_Group, true}, {UI_RADIO, "GRadioButton", Res_RadioBox, true}, {UI_TABS, "GTabView", Res_TabView, true}, {UI_TAB, "GTabPage", Res_Tab, false}, {UI_LIST, "LList", Res_ListView, true}, {UI_COLUMN, "LListColumn", Res_Column, false}, {UI_COMBO, "GCombo", Res_ComboBox, true}, {UI_TREE, "GTree", Res_TreeView, true}, {UI_BITMAP, "GBitmap", Res_Bitmap, true}, {UI_PROGRESS, "GProgress", Res_Progress, true}, {UI_SCROLL_BAR, "GScrollBar", Res_ScrollBar, true}, {UI_CUSTOM, "GCustom", Res_Custom, true}, {UI_CONTROL_TREE, "GControlTree", Res_ControlTree, true}, // If you add a new control here update ResDialog::CreateCtrl(int Tool) as well {0, 0, 0, 0} }; class CtrlItem : public LListItem { friend class TabOrder; ResDialogCtrl *Ctrl; public: CtrlItem(ResDialogCtrl *ctrl) { Ctrl = ctrl; } char *GetText(int Col) { switch (Col) { case 0: { if (Ctrl && Ctrl->Str && Ctrl->Str->GetDefine()) { return Ctrl->Str->GetDefine(); } break; } case 1: { if (Ctrl && Ctrl->Str && Ctrl->Str->Get()) { return Ctrl->Str->Get(); } break; } } return (char*)""; } }; class TabOrder : public GDialog { ResDialogCtrl *Top; LList *Lst; GButton *Ok; GButton *Cancel; GButton *Up; GButton *Down; public: TabOrder(GView *Parent, ResDialogCtrl *top) { Top = top; SetParent(Parent); Children.Insert(Lst = new LList(IDC_LIST, 10, 10, 350, 300)); Children.Insert(Ok = new GButton(IDOK, Lst->GetPos().x2 + 10, 10, 60, 20, "Ok")); Children.Insert(Cancel = new GButton(IDCANCEL, Lst->GetPos().x2 + 10, Ok->GetPos().y2 + 5, 60, 20, "Cancel")); Children.Insert(Up = new GButton(IDC_UP, Lst->GetPos().x2 + 10, Cancel->GetPos().y2 + 15, 60, 20, "Up")); Children.Insert(Down = new GButton(IDC_DOWN, Lst->GetPos().x2 + 10, Up->GetPos().y2 + 5, 60, 20, "Down")); GRect r(0, 0, Ok->GetPos().x2 + 17, Lst->GetPos().y2 + 40); SetPos(r); MoveToCenter(); Lst->AddColumn("#define", 150); Lst->AddColumn("Text", 150); Lst->MultiSelect(false); if (Top) { GAutoPtr It(Top->View()->IterateViews()); for (ResDialogCtrl *Ctrl=dynamic_cast(It->First()); Ctrl; Ctrl=dynamic_cast(It->Next())) { if (Ctrl->GetType() != UI_TEXT) { Lst->Insert(new CtrlItem(Ctrl)); } } char s[256]; sprintf(s, "Set Tab Order: %s", Top->Str->GetDefine()); Name(s); DoModal(); } } int OnNotify(GViewI *Ctrl, int Flags) { int MoveDir = 1; switch (Ctrl->GetId()) { case IDC_UP: { MoveDir = -1; // fall through } case IDC_DOWN: { if (Lst) { CtrlItem *Sel = dynamic_cast(Lst->GetSelected()); if (Sel) { int Index = Lst->IndexOf(Sel); CtrlItem *Up = dynamic_cast(Lst->ItemAt(Index+MoveDir)); if (Up) { Lst->Remove(Sel); Lst->Insert(Sel, Index+MoveDir); Sel->Select(true); Sel->ScrollTo(); } } } break; } case IDOK: { if (Lst) { int i=0; List All; Lst->GetAll(All); for (CtrlItem *n=All.First(); n; n=All.Next()) { Top->View()->DelView(n->Ctrl->View()); Top->View()->AddView(n->Ctrl->View(), i++); } } // fall through } case IDCANCEL: { EndModal(0); break; } } return 0; } }; //////////////////////////////////////////////////////////////////// void DrawGoobers(GSurface *pDC, GRect &r, GRect *Goobers, COLOUR c) { int Mx = (r.x2 + r.x1) / 2 - (GOOBER_SIZE / 2); int My = (r.y2 + r.y1) / 2 - (GOOBER_SIZE / 2); pDC->Colour(c, 24); Goobers[0].x1 = r.x1 - GOOBER_BORDER; Goobers[0].y1 = r.y1 - GOOBER_BORDER; Goobers[0].x2 = r.x1 - (GOOBER_BORDER - GOOBER_SIZE); Goobers[0].y2 = r.y1 - (GOOBER_BORDER - GOOBER_SIZE); Goobers[1].x1 = Mx; Goobers[1].y1 = r.y1 - GOOBER_BORDER; Goobers[1].x2 = Mx + GOOBER_SIZE; Goobers[1].y2 = r.y1 - (GOOBER_BORDER - GOOBER_SIZE); Goobers[2].x1 = r.x2 + (GOOBER_BORDER - GOOBER_SIZE); Goobers[2].y1 = r.y1 - GOOBER_BORDER; Goobers[2].x2 = r.x2 + GOOBER_BORDER; Goobers[2].y2 = r.y1 - (GOOBER_BORDER - GOOBER_SIZE); Goobers[3].x1 = r.x2 + (GOOBER_BORDER - GOOBER_SIZE); Goobers[3].y1 = My; Goobers[3].x2 = r.x2 + GOOBER_BORDER; Goobers[3].y2 = My + GOOBER_SIZE; Goobers[4].x1 = r.x2 + (GOOBER_BORDER - GOOBER_SIZE); Goobers[4].y1 = r.y2 + (GOOBER_BORDER - GOOBER_SIZE); Goobers[4].x2 = r.x2 + GOOBER_BORDER; Goobers[4].y2 = r.y2 + GOOBER_BORDER; Goobers[5].x1 = Mx; Goobers[5].y1 = r.y2 + (GOOBER_BORDER - GOOBER_SIZE); Goobers[5].x2 = Mx + GOOBER_SIZE; Goobers[5].y2 = r.y2 + GOOBER_BORDER; Goobers[6].x1 = r.x1 - GOOBER_BORDER; Goobers[6].y1 = r.y2 + (GOOBER_BORDER - GOOBER_SIZE); Goobers[6].x2 = r.x1 - (GOOBER_BORDER - GOOBER_SIZE); Goobers[6].y2 = r.y2 + GOOBER_BORDER; Goobers[7].x1 = r.x1 - GOOBER_BORDER; Goobers[7].y1 = My; Goobers[7].x2 = r.x1 - (GOOBER_BORDER - GOOBER_SIZE); Goobers[7].y2 = My + GOOBER_SIZE; for (int i=0; i<8; i++) { pDC->Box(Goobers+i); } } //////////////////////////////////////////////////////////////////// int ResDialogCtrl::TabDepth = 0; ResDialogCtrl::ResDialogCtrl(ResDialog *dlg, char *CtrlTypeName, GXmlTag *load) : ResObject(CtrlTypeName) { Dlg = dlg; DragCtrl = -1; AcceptChildren = false; Movable = true; MoveCtrl = false; Vis = true; Client.ZOff(-1, -1); SelectMode = SelNone; SelectStart.ZOff(-1, -1); if (load) { // Base a string off the xml int r = load->GetAsInt("ref"); if (Dlg) { Str = Dlg->Symbols->FindRef(r); LgiAssert(Str); if (!Str) // oh well we should have one anyway... fix things up so to speak. Dlg->Symbols->CreateStr(); } LgiAssert(Str); } else if (Dlg->CreateSymbols) { // We create a symbol for this resource Str = (Dlg && Dlg->Symbols) ? Dlg->Symbols->CreateStr() : 0; if (Str) { char Def[256]; sprintf(Def, "IDC_%i", Str->GetRef()); Str->SetDefine(Def); } } else { // Someone else is going to create the symbol Str = 0; } LgiAssert(Str); } ResDialogCtrl::~ResDialogCtrl() { if (ResDialog::Symbols) { ResDialog::Symbols->DeleteStr(Str); } if (Dlg) { Dlg->App()->OnObjDelete(this); Dlg->OnDeselect(this); } } char *ResDialogCtrl::GetRefText() { static char Buf[64]; if (Str) { sprintf(Buf, "Ref=%i", Str->GetRef()); } else { Buf[0] = 0; } return Buf; } void ResDialogCtrl::ListChildren(List &l, bool Deep) { GAutoPtr it(View()->IterateViews()); for (GViewI *w = it->First(); w; w = it->Next()) { ResDialogCtrl *c = dynamic_cast(w); LgiAssert(c); if (c) { l.Insert(c); if (Deep) { c->ListChildren(l); } } } } GRect ResDialogCtrl::GetMinSize() { GRect m(0, 0, GRID_X-1, GRID_Y-1); if (IsContainer()) { GRect cli = View()->GetClient(false); GAutoPtr it(View()->IterateViews()); for (GViewI *c=it->First(); c; c=it->Next()) { GRect cpos = c->GetPos(); cpos.Offset(cli.x1, cli.y1); m.Union(&cpos); } } return m; } bool ResDialogCtrl::SetPos(GRect &p, bool Repaint) { GRect m = GetMinSize(); if (m.X() > p.X()) p.x2 = p.x1 + m.X() - 1; if (m.Y() > p.Y()) p.y2 = p.y1 + m.Y() - 1; if (p != View()->GetPos()) { /* if (ParentCtrl) { if (p.x1 < ParentCtrl->Client.x1) { p.Offset(ParentCtrl->Client.x1 - p.x1, 0); } if (p.y1 < ParentCtrl->Client.y1) { p.Offset(0, ParentCtrl->Client.y1 - p.y1); } } */ // set our size bool Status = View()->SetPos(p, Repaint); // tell everyone else about the change OnFieldChange(); GRect r(0, 0, p.X()-1, p.Y()-1); r.Size(-GOOBER_BORDER, -GOOBER_BORDER); View()->Invalidate(&r, false, true); // check our parents are big enough to show us... ResDialogCtrl *Par = ParentCtrl(); if (Par) { GRect t = Par->View()->GetPos(); Par->ResDialogCtrl::SetPos(t, true); } return Status; } return true; } void ResDialogCtrl::TabString(char *Str) { if (Str) { for (int i=0; iGetPos(); r.Offset(-r.x1, -r.y1); for (; w && w != Dlg; w = w->GetParent()) { GRect pos = w->GetPos(); if (w->GetParent()) { // GView *Ctrl = w->GetParent()->GetGView(); GRect client = w->GetParent()->GetClient(false); r.Offset(pos.x1 + client.x1, pos.y1 + client.y1); } else { r.Offset(pos.x1, pos.y1); } } return r; } void ResDialogCtrl::StrFromRef(int Ref) { // get the string object Str = Dlg->App()->GetStrFromRef(Ref); if (!Str) { LgiTrace("%s:%i - String with ref '%i' missing.\n", _FL, Ref); LgiAssert(0); if ((Str = Dlg->App()->GetDialogSymbols()->CreateStr())) { Str->SetRef(Ref); } } // if this assert fails then the Ref doesn't exist // and the string can't be found // if this assert fails then the Str is already // associated with a control, and thus we would // duplicate the pointer to the string if we let // it go by // LgiAssert(Str->UpdateWnd == 0); // set the string's control to us Str->UpdateWnd = View(); // make the strings refid unique Str->UnDuplicate(); View()->Name(Str->Get()); } bool ResDialogCtrl::GetFields(FieldTree &Fields) { if (Str) { Str->GetFields(Fields); } int Id = 101; Fields.Insert(this, DATA_STR, Id++, VAL_Pos, "Pos"); Fields.Insert(this, DATA_BOOL, Id++, VAL_Visible, "Visible"); Fields.Insert(this, DATA_BOOL, Id++, VAL_Enabled, "Enabled"); Fields.Insert(this, DATA_STR, Id++, VAL_Class, "Class", -1); Fields.Insert(this, DATA_STR, Id++, VAL_Style, "Style", -1, true); return true; } bool ResDialogCtrl::Serialize(FieldTree &Fields) { if ((Fields.GetMode() == FieldTree::ObjToUi || Fields.GetMode() == FieldTree::UiToObj) && Str) { Str->Serialize(Fields); } GRect r = View()->GetPos(), Old = View()->GetPos(); bool e = true; if (Fields.GetMode() == FieldTree::ObjToUi || Fields.GetMode() == FieldTree::ObjToStore) { r = View()->GetPos(); e = View()->Enabled(); } Fields.Serialize(this, VAL_Pos, r); Fields.Serialize(this, VAL_Visible, Vis, true); Fields.Serialize(this, VAL_Enabled, e, true); Fields.Serialize(this, VAL_Class, CssClass); Fields.Serialize(this, VAL_Style, CssStyle); if (Fields.GetMode() == FieldTree::UiToObj || Fields.GetMode() == FieldTree::StoreToObj) { View()->Enabled(e); SetPos(r); r.Union(&Old); r.Size(-GOOBER_BORDER, -GOOBER_BORDER); if (View()->GetParent()) { View()->GetParent()->Invalidate(&r); } } if (Dlg && Dlg->Item) Dlg->Item->Update(); return true; } void ResDialogCtrl::CopyText() { if (Str) { Str->CopyText(); } } void ResDialogCtrl::PasteText() { if (Str) { Str->PasteText(); View()->Invalidate(); } } bool ResDialogCtrl::AttachCtrl(ResDialogCtrl *Ctrl, GRect *r) { bool Status = false; if (Ctrl) { Ctrl->View()->Visible(true); View()->AddView(Ctrl->View()); Ctrl->View()->SetParent(View()); if (r) { if (!dynamic_cast(Ctrl->View()->GetParent())) { Dlg->SnapRect(r, this); } Ctrl->SetPos(*r); } if (Dlg->Resource::IsSelected()) { Dlg->OnSelect(Ctrl); } Status = true; } return Status; } void ResDialogCtrl::OnPaint(GSurface *pDC) { if (DragCtrl >= 0) { GRect r = DragRgn; r.Normal(); pDC->Colour(LC_FOCUS_SEL_BACK, 24); pDC->Box(&r); } } void ResDialogCtrl::OnMouseClick(GMouse &m) { if (m.Down()) { if (m.Left()) { if (Dlg) { bool Processed = false; GRect c = View()->GetClient(); bool ClickedThis = c.Overlap(m.x, m.y); GRect Cli = View()->GetClient(false); GMouse Ms = m; GdcPt2 Off; View()->WindowVirtualOffset(&Off); Ms.x += Off.x + Cli.x1; Ms.y += Off.y + Cli.y1; Dlg->OnMouseClick(Ms); if (ClickedThis && !Dlg->IsDraging()) { DragCtrl = Dlg->CurrentTool(); if ((DragCtrl > 0 && AcceptChildren) || ((DragCtrl == 0) && !Movable)) { GdcPt2 p(m.x, m.y); Dlg->SnapPoint(&p, ParentCtrl()); DragStart.x = DragRgn.x1 = DragRgn.x2 = p.x; DragStart.y = DragRgn.y1 = DragRgn.y2 = p.y; View()->Capture(true); Processed = true; } else { DragCtrl = -1; if (Movable) { DragRgn.x1 = m.x; DragRgn.y1 = m.y; MoveCtrl = true; Processed = true; View()->Capture(true); } } SelectMode = (m.Shift()) ? SelAdd : SelSet; SelectStart = View()->GetPos(); } } } else if (m.IsContextMenu()) { GSubMenu RClick; bool PasteData = false; bool PasteTranslations = false; { GClipBoard c(Dlg); char *Clip = c.Text(); if (Clip) { PasteTranslations = strstr(Clip, TranslationStrMagic); char *p = Clip; while (*p && strchr(" \r\n\t", *p)) p++; PasteData = *p == '<'; } } RClick.AppendItem("Cu&t", IDM_CUT, Dlg->Selection.Length()>0); RClick.AppendItem("&Copy Control", IDM_COPY, Dlg->Selection.Length()>0); RClick.AppendItem("&Paste", IDM_PASTE, PasteData); RClick.AppendSeparator(); RClick.AppendItem("Copy Text", IDM_COPY_TEXT, Dlg->Selection.Length()==1); RClick.AppendItem("Paste Text", IDM_PASTE_TEXT, PasteTranslations); RClick.AppendSeparator(); RClick.AppendItem("&Delete", IDM_DELETE, Dlg->Selection.Length()>0); if (Dlg->GetMouse(m, true)) { int Cmd = 0; switch (Cmd = RClick.Float(Dlg, m.x, m.y)) { case IDM_DELETE: { Dlg->Delete(); break; } case IDM_CUT: { Dlg->Copy(true); break; } case IDM_COPY: { Dlg->Copy(); break; } case IDM_PASTE: { Dlg->Paste(); break; } case IDM_COPY_TEXT: { ResDialogCtrl *Ctrl = Dlg->Selection.First(); if (Ctrl) { Ctrl->CopyText(); } break; } case IDM_PASTE_TEXT: { PasteText(); break; } } } } } else { if (DragCtrl >= 0) { bool Exit = false; if (Dlg && (DragRgn.X() > 1 || DragRgn.Y() > 1)) { if (DragCtrl == 0) { Dlg->SelectRect(this, &DragRgn, SelectMode != SelAdd); } else { ResDialogCtrl *Ctrl = Dlg->CreateCtrl(DragCtrl, 0); if (Ctrl) { AttachCtrl(Ctrl, &DragRgn); } } Exit = true; } DragCtrl = -1; View()->Invalidate(); View()->Capture(false); if (Exit) { return; } } if (MoveCtrl) { View()->Capture(false); MoveCtrl = false; } if (SelectMode > SelNone) { GRect r = View()->GetPos(); if (SelectStart == r) { Dlg->OnSelect(this, SelectMode != SelAdd); } SelectMode = SelNone; } } } void ResDialogCtrl::OnMouseMove(GMouse &m) { // Drag a rubber band... if (DragCtrl >= 0) { GRect Old = DragRgn; DragRgn.x1 = DragStart.x; DragRgn.y1 = DragStart.y; DragRgn.x2 = m.x; DragRgn.y2 = m.y; DragRgn.Normal(); Dlg->SnapRect(&DragRgn, this); Old.Union(&DragRgn); Old.Size(-1, -1); View()->Invalidate(&Old); } // Move some ctrl(s) if (MoveCtrl && !m.Shift()) { int Dx = m.x - DragRgn.x1; int Dy = m.y - DragRgn.y1; if (Dx != 0 || Dy != 0) { if (!Dlg->IsSelected(this)) { Dlg->OnSelect(this); } GRect Old = View()->GetPos(); GRect New = Old; New.Offset( m.x - DragRgn.x1, m.y - DragRgn.y1); GdcPt2 p(New.x1, New.y1); Dlg->SnapPoint(&p, ParentCtrl()); New.Set(p.x, p.y, p.x + New.X() - 1, p.y + New.Y() - 1); if (New != Old) { Dlg->MoveSelection(New.x1 - Old.x1, New.y1 - Old.y1); } } } } char *ReadInt(char *s, int &Value) { char *c = strchr(s, ','); if (c) { *c = 0; Value = atoi(s); return c+1; } Value = atoi(s); return 0; } void ResDialogCtrl::ReadPos(char *Str) { if (Str) { char *s = NewStr(Str); if (s) { GRect r = View()->GetPos(); char *p = ReadInt(s, r.x1); if (p) p = ReadInt(p, r.y1); if (p) p = ReadInt(p, r.x2); if (p) p = ReadInt(p, r.y2); DeleteArray(s); } } } //////////////////////////////////////////////////////////////////// CtrlDlg::CtrlDlg(ResDialog *dlg, GXmlTag *load) : ResDialogCtrl(dlg, Res_Dialog, load) { Movable = false; AcceptChildren = true; Str->UpdateWnd = View(); View()->Name("CtrlDlg"); } IMPL_DIALOG_CTRL(CtrlDlg) void CtrlDlg::OnPaint(GSurface *pDC) { // Draw any rubber band ResDialogCtrl::OnPaint(pDC); } GRect &CtrlDlg::GetClient(bool InClientSpace) { static GRect r; Client.Set(0, 0, View()->X()-1, View()->Y()-1); Client.Size(3, 3); Client.y1 += LgiApp->GetMetric(LGI_MET_DECOR_CAPTION); if (Client.y1 > Client.y2) Client.y1 = Client.y2; r = Client; if (InClientSpace) r.Offset(-r.x1, -r.y1); return r; } void CtrlDlg::_Paint(GSurface *pDC, GdcPt2 *Offset, GRegion *Update) { Client = GetClient(false); // Draw the border GRect r(0, 0, View()->X()-1, View()->Y()-1); LgiWideBorder(pDC, r, DefaultRaisedEdge); pDC->Colour(LC_MED, 24); LgiFlatBorder(pDC, r, 1); // Draw the title bar Title = r; Title.y2 = Client.y1 - 1; pDC->Colour(LC_ACTIVE_TITLE, 24); pDC->Rectangle(&Title); if (Str) { GDisplayString ds(SysFont, Str->Get()); SysFont->Fore(LC_ACTIVE_TITLE_TEXT); SysFont->Transparent(true); ds.Draw(pDC, Title.x1 + 10, Title.y1 + ((Title.Y()-ds.Y())/2)); } // Draw the client area GRect c = Client; GdcPt2 o; if (Offset) o = *Offset; c.Offset(o.x, o.y); pDC->SetClient(&c); // Draw the grid pDC->Colour(LC_MED, 24); pDC->Rectangle(0, 0, Client.X()-1, Client.Y()-1); pDC->Colour(Rgb24(0x80, 0x80, 0x80), 24); for (int y=0; ySet(x, y); } } // Paint children GdcPt2 co(c.x1, c.y1); GView::_Paint(pDC, &co); pDC->SetOrigin(o.x, o.y); } ///////////////////////////////////////////////////////////////////// // Text box CtrlText::CtrlText(ResDialog *dlg, GXmlTag *load) : ResDialogCtrl(dlg, Res_StaticText, load) { if (Str && !load) { Str->SetDefine("IDC_STATIC"); } } IMPL_DIALOG_CTRL(CtrlText) void CtrlText::OnPaint(GSurface *pDC) { Client.ZOff(X()-1, Y()-1); char *Text = Str->Get(); SysFont->Fore(0); SysFont->Transparent(true); if (Text) { GRect Client = GetClient(); int y = 0; char *Start = Text; for (char *s = Text; 1; s++) { if ((*s == '\\' && *(s+1) == 'n') || (*s == 0)) { GDisplayString ds(SysFont, Start, s - Start); ds.Draw(pDC, 0, y, &Client); y += 15; Start = s + 2; if (*s == '\\') s++; } if (*s == 0) break; } } } // Editbox CtrlEditbox::CtrlEditbox(ResDialog *dlg, GXmlTag *load) : ResDialogCtrl(dlg, Res_EditBox, load) { Password = false; MultiLine = false; } IMPL_DIALOG_CTRL(CtrlEditbox) void CtrlEditbox::OnPaint(GSurface *pDC) { GRect r(0, 0, X()-1, Y()-1); Client = r; // Draw the ctrl LgiWideBorder(pDC, r, DefaultSunkenEdge); pDC->Colour(Enabled() ? LC_WORKSPACE : LC_MED, 24); pDC->Rectangle(&r); char *Text = Str->Get(); SysFont->Fore(Enabled() ? 0 : LC_LOW); SysFont->Transparent(true); if (Text) { if (Password) { char *t = NewStr(Text); if (t) { for (char *p = t; *p; p++) *p = '*'; GDisplayString ds(SysFont, t); ds.Draw(pDC, 4, 4); DeleteArray(t); } } else { GDisplayString ds(SysFont, Text); ds.Draw(pDC, 4, 4); } } // Draw any rubber band ResDialogCtrl::OnPaint(pDC); } #define VAL_Password "Pw" #define VAL_MultiLine "MultiLine" bool CtrlEditbox::GetFields(FieldTree &Fields) { bool Status = ResDialogCtrl::GetFields(Fields); if (Status) { Fields.Insert(this, DATA_BOOL, 300, VAL_Password, "Password"); Fields.Insert(this, DATA_BOOL, 301, VAL_MultiLine, "MultiLine"); } return Status; } bool CtrlEditbox::Serialize(FieldTree &Fields) { bool Status = ResDialogCtrl::Serialize(Fields); if (Status) { Fields.Serialize(this, VAL_Password, Password, false); Fields.Serialize(this, VAL_MultiLine, MultiLine, false); } return Status; } // Check box CtrlCheckbox::CtrlCheckbox(ResDialog *dlg, GXmlTag *load) : ResDialogCtrl(dlg, Res_CheckBox, load) { } IMPL_DIALOG_CTRL(CtrlCheckbox) void CtrlCheckbox::OnPaint(GSurface *pDC) { Client.ZOff(X()-1, Y()-1); GRect r(0, 0, 12, 12); // Draw the ctrl LgiWideBorder(pDC, r, DefaultSunkenEdge); pDC->Colour(LC_WORKSPACE, 24); pDC->Rectangle(&r); GdcPt2 Pt[6] = { GdcPt2(3, 4), GdcPt2(3, 7), GdcPt2(5, 10), GdcPt2(10, 5), GdcPt2(10, 2), GdcPt2(5, 7)}; pDC->Colour(0); pDC->Polygon(6, Pt); pDC->Set(3, 5); char *Text = Str->Get(); if (Text) { SysFont->Fore(LC_TEXT); SysFont->Transparent(true); GDisplayString ds(SysFont, Text); ds.Draw(pDC, r.x2 + 10, r.y1-2); } // Draw any rubber band ResDialogCtrl::OnPaint(pDC); } // Button CtrlButton::CtrlButton(ResDialog *dlg, GXmlTag *load) : ResDialogCtrl(dlg, Res_Button, load) { } IMPL_DIALOG_CTRL(CtrlButton) bool CtrlButton::GetFields(FieldTree &Fields) { bool Status = ResDialogCtrl::GetFields(Fields); int Id = 160; Fields.Insert(this, DATA_FILENAME, Id++, VAL_Image, "Image"); return Status; } bool CtrlButton::Serialize(FieldTree &Fields) { bool Status = ResDialogCtrl::Serialize(Fields); if (Status) Fields.Serialize(this, VAL_Image, Image); return Status; } void CtrlButton::OnPaint(GSurface *pDC) { Client.ZOff(X()-1, Y()-1); GRect r = Client; char *Text = Str->Get(); // Draw the ctrl LgiWideBorder(pDC, r, DefaultRaisedEdge); SysFont->Fore(LC_TEXT); if (ValidStr(Text)) { SysFont->Back(LC_MED); SysFont->Transparent(false); GDisplayString ds(SysFont, Text); ds.Draw(pDC, r.x1 + ((r.X()-ds.X())/2), r.y1 + ((r.Y()-ds.Y())/2), &r); } else { pDC->Colour(LC_MED, 24); pDC->Rectangle(&r); } // Draw any rubber band ResDialogCtrl::OnPaint(pDC); } // Group CtrlGroup::CtrlGroup(ResDialog *dlg, GXmlTag *load) : ResDialogCtrl(dlg, Res_Group, load) { AcceptChildren = true; if (Str && !load) { Str->SetDefine("IDC_STATIC"); } } IMPL_DIALOG_CTRL(CtrlGroup) void CtrlGroup::OnPaint(GSurface *pDC) { Client.ZOff(X()-1, Y()-1); GRect r = Client; // Draw the ctrl r.y1 += 5; LgiWideBorder(pDC, r, EdgeXpChisel); r.y1 -= 5; SysFont->Fore(LC_TEXT); SysFont->Back(LC_MED); SysFont->Transparent(false); char *Text = Str->Get(); GDisplayString ds(SysFont, Text); ds.Draw(pDC, r.x1 + 8, r.y1 - 2); // Draw children //GWindow::OnPaint(pDC); // Draw any rubber band ResDialogCtrl::OnPaint(pDC); } //Radio button -uint32 RadioBmp[] = { +uint32_t RadioBmp[] = { 0xC0C0C0C0, 0xC0C0C0C0, 0xC0C0C0C0, 0x80808080, 0x80808080, 0x80808080, 0xC0C0C0C0, 0xC0C0C0C0, 0xC0C0C0C0, 0xC0C0C0C0, 0x8080C0C0, 0x80808080, 0x00000000, 0x00000000, 0x00000000, 0x80808080, 0xC0C08080, 0xC0C0C0C0, 0x80C0C0C0, 0x00008080, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFF0000, 0xC0C0C0FF, 0x80C0C0C0, 0x00008080, 0xFFFFFF00, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xDFFFFFFF, 0xFFFFDFDF, 0xC0C0C0FF, 0x00808080, 0xFFFF0000, 0xFFFFFFFF, 0x00FFFFFF, 0x00000000, 0xFFFFFF00, 0xFFFFFFFF, 0xDFDFFFFF, 0xFFFFFFDF, 0x00808080, 0xFFFF0000, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xDFDFFFFF, 0xFFFFFFDF, 0x00808080, 0xFFFF0000, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xDFDFFFFF, 0xFFFFFFDF, 0x00808080, 0xFFFF0000, 0xFFFFFFFF, 0x00FFFFFF, 0x00000000, 0xFFFFFF00, 0xFFFFFFFF, 0xDFDFFFFF, 0xFFFFFFDF, 0x80C0C0C0, 0x00008080, 0xFFFFFF00, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xDFFFFFFF, 0xFFFFDFDF, 0xC0C0C0FF, 0x80C0C0C0, 0xDFDF8080, 0xDFDFDFDF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xDFDFDFDF, 0xFFFFDFDF, 0xC0C0C0FF, 0xC0C0C0C0, 0xFFFFC0C0, 0xFFFFFFFF, 0xDFDFDFDF, 0xDFDFDFDF, 0xDFDFDFDF, 0xFFFFFFFF, 0xC0C0FFFF, 0xC0C0C0C0, 0xC0C0C0C0, 0xC0C0C0C0, 0xC0C0C0C0, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xC0C0C0C0, 0xC0C0C0C0, 0xC0C0C0C0}; CtrlRadio::CtrlRadio(ResDialog *dlg, GXmlTag *load) : ResDialogCtrl(dlg, Res_RadioBox, load) { Bmp = new GMemDC; if (Bmp && Bmp->Create(12, 12, GdcD->GetColourSpace())) { int Len = ((Bmp->X()*24)+31)/32*4; for (int y=0; yY(); y++) { for (int x=0; xX(); x++) { uchar *s = ((uchar*) RadioBmp) + (y * Len) + (x * 3); Bmp->Colour(Rgb24(s[0], s[1], s[2]), 24); Bmp->Set(x, y); } } } } CtrlRadio::~CtrlRadio() { DeleteObj(Bmp); } IMPL_DIALOG_CTRL(CtrlRadio) void CtrlRadio::OnPaint(GSurface *pDC) { Client.ZOff(X()-1, Y()-1); GRect r(0, 0, 12, 12); // Draw the ctrl if (RadioBmp) { pDC->Blt(r.x1, r.y1, Bmp); } char *Text = Str->Get(); if (Text) { SysFont->Fore(LC_TEXT); SysFont->Transparent(true); GDisplayString ds(SysFont, Text); ds.Draw(pDC, r.x2 + 10, r.y1-2); } // Draw any rubber band ResDialogCtrl::OnPaint(pDC); } // Tab CtrlTab::CtrlTab(ResDialog *dlg, GXmlTag *load) : ResDialogCtrl(dlg, Res_Tab, load) { Str->UpdateWnd = this; } IMPL_DIALOG_CTRL(CtrlTab) void CtrlTab::OnPaint(GSurface *pDC) { } void CtrlTab::ListChildren(List &l, bool Deep) { ResDialogCtrl *Ctrl = dynamic_cast(GetParent()); CtrlTabs *Par = dynamic_cast(Ctrl); LgiAssert(Par); int MyIndex = Par->Tabs.IndexOf(this); LgiAssert(MyIndex >= 0); List *CList = (Par->Current == MyIndex) ? &Par->Children : &Children; for (GViewI *w = CList->First(); w; w = CList->Next()) { ResDialogCtrl *c = dynamic_cast(w); if (c) { l.Insert(c); if (Deep) { c->ListChildren(l, Deep); } } } } // Tab control CtrlTabs::CtrlTabs(ResDialog *dlg, GXmlTag *load) : ResDialogCtrl(dlg, Res_TabView, load) { AcceptChildren = true; Current = 0; if (!load) { for (int i=0; i<3; i++) { CtrlTab *t = new CtrlTab(dlg, load); if (t) { char Text[256]; sprintf(Text, "Tab %i", i+1); if (t->Str) { t->Str->Set(Text); t->SetParent(this); Tabs.Insert(t); } else { DeleteObj(t); } } } } } CtrlTabs::~CtrlTabs() { Empty(); } void CtrlTabs::OnMouseMove(GMouse &m) { ResDialogCtrl::OnMouseMove(m); } void CtrlTabs::ShowMe(ResDialogCtrl *Child) { CtrlTab *t = dynamic_cast(Child); if (t) { int Idx = Tabs.IndexOf(t); if (Idx >= 0) { ToTab(); Current = Idx; FromTab(); } } } void CtrlTabs::EnumCtrls(List &Ctrls) { List::I it = Tabs.begin(); for (CtrlTab *t = *it; t; t = *++it) { t->EnumCtrls(Ctrls); } ResDialogCtrl::EnumCtrls(Ctrls); } GRect CtrlTabs::GetMinSize() { List l; ListChildren(l, false); GRect r(0, 0, GRID_X-1, GRID_Y-1); /* // don't resize smaller than the tabs for (CtrlTab *t = Tabs.First(); t; t = Tabs.Next()) { r.x2 = max(r.x2, t->r.x2 + 10); r.y2 = max(r.y2, t->r.y2 + 10); } */ // don't resize smaller than any of the children // on any of the tabs GRect cli = GetClient(false); for (ResDialogCtrl *c=l.First(); c; c=l.Next()) { GRect cpos = c->View()->GetPos(); cpos.Offset(cli.x1, cli.y1); r.Union(&cpos); } return r; } void CtrlTabs::ListChildren(List &l, bool Deep) { int n=0; for (CtrlTab *t = Tabs.First(); t; t = Tabs.Next(), n++) { l.Add(t); GAutoPtr It((Current == n ? (GViewI*)this : (GViewI*)t)->IterateViews()); for (GViewI *w = It->First(); w; w = It->Next()) { ResDialogCtrl *c = dynamic_cast(w); if (c) { l.Insert(c); c->ListChildren(l, Deep); } } } } void CtrlTabs::Empty() { ToTab(); Tabs.DeleteObjects(); } void CtrlTabs::OnPaint(GSurface *pDC) { // Draw the ctrl Title.ZOff(X()-1, 17); Client.ZOff(X()-1, Y()-1); Client.y1 = Title.y2; GRect r = Client; LgiWideBorder(pDC, r, DefaultRaisedEdge); // Draw the tabs int i = 0; int x = 2; for (CtrlTab *Tab = Tabs.First(); Tab; Tab = Tabs.Next(), i++) { char *Str = Tab->Str ? Tab->Str->Get() : 0; GDisplayString ds(SysFont, Str); int Width = 12 + ds.X(); GRect t(x, Title.y1 + 2, x + Width - 1, Title.y2 - 1); if (Current == i) { t.Size(-2, -2); GAutoPtr It(Tab->IterateViews()); if (It->Length() > 0) { FromTab(); } } Tab->View()->SetPos(t); pDC->Colour(LC_LIGHT, 24); pDC->Line(t.x1, t.y1+2, t.x1, t.y2); pDC->Set(t.x1+1, t.y1+1); pDC->Line(t.x1+2, t.y1, t.x2-2, t.y1); pDC->Colour(LC_MED, 24); pDC->Line(t.x1+1, t.y1+2, t.x1+1, t.y2); pDC->Line(t.x1+2, t.y1+1, t.x2-2, t.y1+1); pDC->Colour(LC_LOW, 24); pDC->Line(t.x2-1, t.y1, t.x2-1, t.y2); pDC->Colour(0, 24); pDC->Line(t.x2, t.y1+2, t.x2, t.y2); t.Size(2, 2); t.y2 += 2; SysFont->Fore(LC_TEXT); SysFont->Back(LC_MED); SysFont->Transparent(false); ds.Draw(pDC, t.x1 + ((t.X()-ds.X())/2), t.y1 + ((t.Y()-ds.Y())/2), &t); x += Width + ((Current == i) ? 2 : 1); } // Draw children //GWindow::OnPaint(pDC); // Draw any rubber band ResDialogCtrl::OnPaint(pDC); } void CtrlTabs::ToTab() { CtrlTab *Cur = Tabs.ItemAt(Current); if (Cur) { // move all our children into the tab losing focus GAutoPtr CurIt(Cur->IterateViews()); GAutoPtr ThisIt(IterateViews()); GViewI *v; while ((v = CurIt->First())) { Cur->DelView(v); } while ((v = ThisIt->First())) { DelView(v); Cur->AddView(v); } } } void CtrlTabs::FromTab() { CtrlTab *Cur = Tabs.ItemAt(Current); if (Cur) { // load all our children from the new tab GAutoPtr CurIt(Cur->IterateViews()); GAutoPtr ThisIt(IterateViews()); GViewI *v; while ((v = ThisIt->First())) { DelView(v); } while ((v = CurIt->First())) { Cur->DelView(v); AddView(v); } } } void CtrlTabs::OnMouseClick(GMouse &m) { if (m.Down()) { if (Title.Overlap(m.x, m.y)) { // select current tab int i = 0; for (CtrlTab *Tab = Tabs.First(); Tab; Tab = Tabs.Next(), i++) { if (Tab->View()->GetPos().Overlap(m.x, m.y) /* && i != Current*/) { ToTab(); Current = i; FromTab(); Dlg->OnSelect(Tab); Invalidate(); break; } } } if (m.IsContextMenu() && Title.Overlap(m.x, m.y)) { GSubMenu *RClick = new GSubMenu; if (RClick) { bool HasTab = Tabs.ItemAt(Current); RClick->AppendItem("New tab", IDM_NEW, true); RClick->AppendItem("Delete tab", IDM_DELETE, HasTab); RClick->AppendItem("Rename tab", IDM_RENAME, HasTab); RClick->AppendItem("Move tab left", IDM_MOVE_LEFT, HasTab); RClick->AppendItem("Move tab right", IDM_MOVE_RIGHT, HasTab); RClick->AppendSeparator(); RClick->AppendItem("Copy Text", IDM_COPY_TEXT, Dlg->Selection.Length()==1); RClick->AppendItem("Paste Text", IDM_PASTE_TEXT, true); if (GetMouse(m, true)) { switch (RClick->Float(this, m.x, m.y, false)) { case IDM_NEW: { CtrlTab *t = new CtrlTab(Dlg, 0); if (t) { char Text[256]; sprintf(Text, "Tab " LPrintfSizeT, Tabs.Length()+1); t->Str->Set(Text); t->SetParent(this); Tabs.Insert(t); } break; } case IDM_DELETE: { CtrlTab *t = Tabs.ItemAt(Current); if (t) { ToTab(); Tabs.Delete(t); DeleteObj(t); FromTab(); } break; } case IDM_RENAME: { CtrlTab *t = Tabs.ItemAt(Current); if (t) { if (!t->Str) t->Str = Dlg->CreateSymbol(); GInput Input(this, t->Str->Get(), "Enter tab name:", "Rename"); Input.SetParent(Dlg); if (Input.DoModal() && Input.GetStr()) { t->Str->Set(Input.GetStr()); } } break; } case IDM_MOVE_LEFT: { CtrlTab *t = Tabs.ItemAt(Current); if (t && Current > 0) { Tabs.Delete(t); Tabs.Insert(t, --Current); } break; } case IDM_MOVE_RIGHT: { CtrlTab *t = Tabs.ItemAt(Current); if (t && Current < Tabs.Length()-1) { Tabs.Delete(t); Tabs.Insert(t, ++Current); } break; } case IDM_COPY_TEXT: { CtrlTab *t = Tabs.ItemAt(Current); if (t) { t->CopyText(); } break; } case IDM_PASTE_TEXT: { CtrlTab *t = Tabs.ItemAt(Current); if (t) { t->PasteText(); } break; } } Invalidate(); } } return; } } else { int asd=0; } ResDialogCtrl::OnMouseClick(m); } // List column ListCol::ListCol(ResDialog *dlg, GXmlTag *load, char *s, int Width) : ResDialogCtrl(dlg, Res_Column, load) { if (s && Str) { Str->Set(s); } GRect r(0, 0, Width-1, 18); ResDialogCtrl::SetPos(r); } IMPL_DIALOG_CTRL(ListCol) void ListCol::OnPaint(GSurface *pDC) { } // List control CtrlList::CtrlList(ResDialog *dlg, GXmlTag *load) : ResDialogCtrl(dlg, Res_ListView, load) { DragCol = -1; } CtrlList::~CtrlList() { Empty(); } void CtrlList::ListChildren(List &l, bool Deep) { if (Deep) { for (GView *w = Cols.First(); w; w = Cols.Next()) { ResDialogCtrl *c = dynamic_cast(w); if (c) { l.Insert(c); c->ListChildren(l); } } } } void CtrlList::Empty() { for (ListCol *c = Cols.First(); c; c = Cols.Next()) { DeleteObj(c); } Cols.Empty(); } void CtrlList::OnMouseClick(GMouse &m) { if (m.Down()) { if (Title.Overlap(m.x, m.y)) { int x=0; ListCol *c = 0; int DragOver = -1; for (ListCol *Col = Cols.First(); Col; Col = Cols.Next()) { if (m.x >= Col->r().x1 && m.x <= Col->r().x2) { if (m.x > Col->r().x2 - 6) { DragOver = Cols.IndexOf(Col); } if (m.x < Col->r().x1 + 6) { DragOver = Cols.IndexOf(Col) - 1; } c = Col; break; } x += Col->r().X(); } if (m.Left()) { if (DragOver >= 0) { DragCol = DragOver; Capture(true); } } else if (m.IsContextMenu()) { GSubMenu *RClick = new GSubMenu; if (RClick) { bool HasCol = c != 0; RClick->AppendItem("New column", IDM_NEW, true); RClick->AppendItem("Delete column", IDM_DELETE, HasCol); RClick->AppendItem("Rename column", IDM_RENAME, HasCol); RClick->AppendItem("Move column left", IDM_MOVE_LEFT, HasCol); RClick->AppendItem("Move column right", IDM_MOVE_RIGHT, HasCol); RClick->AppendSeparator(); RClick->AppendItem("Copy Text", IDM_COPY_TEXT, HasCol); RClick->AppendItem("Paste Text", IDM_PASTE_TEXT, HasCol); if (GetMouse(m, true)) { switch (RClick->Float(this, m.x, m.y, false)) { case IDM_COPY_TEXT: { if (c && c->Str) { c->Str->CopyText(); } break; } case IDM_PASTE_TEXT: { if (c && c->Str) { c->Str->PasteText(); } break; } case IDM_NEW: { ListCol *c = dynamic_cast(Dlg->CreateCtrl(UI_COLUMN,0)); if (c) { char Text[256]; sprintf(Text, "Col " LPrintfSizeT, Cols.Length()+1); c->Str->Set(Text); Cols.Insert(c); } break; } case IDM_DELETE: { Cols.Delete(c); DeleteObj(c); break; } case IDM_RENAME: { if (c) { GInput Input(this, c->Str->Get(), "Enter column name:", "Rename"); Input.SetParent(Dlg); if (Input.DoModal()) { c->Str->Set(Input.GetStr()); } } break; } case IDM_MOVE_LEFT: { int Current = Cols.IndexOf(c); if (c && Current > 0) { Cols.Delete(c); Cols.Insert(c, --Current); } break; } case IDM_MOVE_RIGHT: { int Current = Cols.IndexOf(c); if (c && Current < Cols.Length()-1) { Cols.Delete(c); Cols.Insert(c, ++Current); } break; } } Invalidate(); } DeleteObj(RClick); return; } } return; } } else { if (DragCol >= 0) { Capture(false); DragCol = -1; } } ResDialogCtrl::OnMouseClick(m); } void CtrlList::OnMouseMove(GMouse &m) { if (DragCol >= 0) { int i=0, x=0;; for (ListCol *Col = Cols.First(); Col; Col = Cols.Next(), i++) { if (i == DragCol) { int Dx = (m.x - x - Title.x1); GRect r = Col->GetPos(); r.x2 = r.x1 + Dx; Col->ResDialogCtrl::SetPos(r); break; } x += Col->r().X(); } Invalidate(); } ResDialogCtrl::OnMouseMove(m); } void CtrlList::OnPaint(GSurface *pDC) { GRect r(0, 0, X()-1, Y()-1); // Draw the ctrl LgiWideBorder(pDC, r, DefaultSunkenEdge); Title = r; Title.y2 = Title.y1 + 15; Client = r; Client.y1 = Title.y2 + 1; pDC->Colour(LC_WORKSPACE, 24); pDC->Rectangle(&Client); int x = Title.x1; for (ListCol *c = Cols.First(); c; c = Cols.Next()) { int Width = c->r().X(); c->r().Set(x, Title.y1, x + Width - 1, Title.y2); GRect r = c->r(); r.x2 = MIN(r.x2, Title.x2); x = r.x2 + 1; if (r.Valid()) { LgiWideBorder(pDC, r, DefaultRaisedEdge); SysFont->Fore(LC_TEXT); SysFont->Back(LC_MED); SysFont->Transparent(false); const char *Str = c->Str->Get(); if (!Str) Str = ""; GDisplayString ds(SysFont, Str); ds.Draw(pDC, r.x1 + 2, r.y1 + ((r.Y()-ds.Y())/2) - 1, &r); } } GRect Client(x, Title.y1, Title.x2, Title.y2); if (Client.Valid()) { LgiWideBorder(pDC, Client, DefaultRaisedEdge); pDC->Colour(LC_MED, 24);; pDC->Rectangle(&Client); } // Draw any rubber band ResDialogCtrl::OnPaint(pDC); } // Combo box CtrlComboBox::CtrlComboBox(ResDialog *dlg, GXmlTag *load) : ResDialogCtrl(dlg, Res_ComboBox, load) { } IMPL_DIALOG_CTRL(CtrlComboBox) void CtrlComboBox::OnPaint(GSurface *pDC) { GRect r(0, 0, X()-1, Y()-1); Client = r; // Draw the ctrl LgiWideBorder(pDC, r, DefaultSunkenEdge); // Allocate space GRect e = r; e.x2 -= 15; GRect d = r; d.x1 = e.x2 + 1; // Draw edit pDC->Colour(LC_WORKSPACE, 24); pDC->Rectangle(&e); // Draw drap down LgiWideBorder(pDC, d, DefaultRaisedEdge); pDC->Colour(LC_MED, 24); pDC->Rectangle(&d); pDC->Colour(0, 24); int Size = 4; int cx = (d.X()/2) + d.x1 - 4; int cy = (d.Y()/2) + d.y1 - 3; for (int i=1; i<=Size; i++) { pDC->Line(cx+i, cy+i, cx+(Size*2)-i, cy+i); } // Text char *Text = Str->Get(); SysFont->Fore(0); SysFont->Transparent(true); if (Text) { GDisplayString ds(SysFont, Text); ds.Draw(pDC, 4, 4); } // Draw any rubber band ResDialogCtrl::OnPaint(pDC); } //////////////////////////////////////////////////////////////////// CtrlScrollBar::CtrlScrollBar(ResDialog *dlg, GXmlTag *load) : ResDialogCtrl(dlg, Res_ScrollBar, load) { } IMPL_DIALOG_CTRL(CtrlScrollBar) void CtrlScrollBar::OnPaint(GSurface *pDC) { GRect r(0, 0, X()-1, Y()-1); Client = r; // Draw the ctrl bool Vertical = r.Y() > r.X(); int ButSize = Vertical ? r.X() : r.Y(); GRect a, b, c; if (Vertical) { a.Set(r.x1, r.y1, r.x2, r.y1 + ButSize); c.Set(r.x1, r.y2 - ButSize, r.x2, r.y2); b.Set(r.x1, a.y2 + 1, r.x2, c.y1 - 1); } else { a.Set(r.x1, r.y1, r.x1 + ButSize, r.y2); c.Set(r.x2 - ButSize, r.y1, r.x2, r.y2); b.Set(a.x2 + 1, r.y1, c.x1 - 1, r.y2); } // Buttons LgiWideBorder(pDC, a, DefaultRaisedEdge); LgiWideBorder(pDC, c, DefaultRaisedEdge); pDC->Colour(LC_MED, 24); pDC->Rectangle(&a); pDC->Rectangle(&c); // Arrows pDC->Colour(0); int x = a.x1 + (a.X()/2) - 2; int y = a.y1 + (a.Y()/2); int i; for (i=0; i<5; i++) { pDC->Line(x+i, y-i, x+i, y+i); } x = c.x1 + (c.X()/2) - 2; y = c.y1 + (c.Y()/2); for (i=0; i<5; i++) { pDC->Line(x+i, y-(4-i), x+i, y+(4-i)); } // Slider pDC->Colour(0xd0d0d0, 24); pDC->Rectangle(&b); // Draw any rubber band ResDialogCtrl::OnPaint(pDC); } //////////////////////////////////////////////////////////////////// CtrlTree::CtrlTree(ResDialog *dlg, GXmlTag *load) : ResDialogCtrl(dlg, Res_TreeView, load) { } IMPL_DIALOG_CTRL(CtrlTree) void CtrlTree::OnPaint(GSurface *pDC) { GRect r(0, 0, X()-1, Y()-1); Client = r; LgiWideBorder(pDC, r, DefaultSunkenEdge); pDC->Colour(Rgb24(255, 255, 255), 24); pDC->Rectangle(&r); SysFont->Colour(0, 0xffffff); SysFont->Transparent(true); GDisplayString ds(SysFont, "Tree"); ds.Draw(pDC, r.x1 + 3, r.y1 + 3, &r); // Draw any rubber band ResDialogCtrl::OnPaint(pDC); } //////////////////////////////////////////////////////////////////// CtrlBitmap::CtrlBitmap(ResDialog *dlg, GXmlTag *load) : ResDialogCtrl(dlg, Res_Bitmap, load) { } IMPL_DIALOG_CTRL(CtrlBitmap) void CtrlBitmap::OnPaint(GSurface *pDC) { GRect r(0, 0, X()-1, Y()-1); Client = r; LgiWideBorder(pDC, r, DefaultSunkenEdge); pDC->Colour(Rgb24(255, 255, 255), 24); pDC->Rectangle(&r); pDC->Colour(0, 24); pDC->Line(r.x1, r.y1, r.x2, r.y2); pDC->Line(r.x2, r.y1, r.x1, r.y2); // Draw any rubber band ResDialogCtrl::OnPaint(pDC); } //////////////////////////////////////////////////////////////////// CtrlProgress::CtrlProgress(ResDialog *dlg, GXmlTag *load) : ResDialogCtrl(dlg, Res_Progress, load) { } IMPL_DIALOG_CTRL(CtrlProgress) void CtrlProgress::OnPaint(GSurface *pDC) { GRect r(0, 0, X()-1, Y()-1); Client = r; LgiWideBorder(pDC, r, DefaultSunkenEdge); COLOUR Flat = Rgb24(0x7f, 0x7f, 0x7f); COLOUR White = Rgb24(0xff, 0xff, 0xff); int Pos = 60; int x = Pos * r.X() / 100; pDC->Colour(Flat, 24); pDC->Rectangle(r.x1, r.y1, r.x1 + x, r.y2); pDC->Colour(White, 24); pDC->Rectangle(r.x1 + x + 1, r.y1, r.x2, r.y2); // Draw any rubber band ResDialogCtrl::OnPaint(pDC); } //////////////////////////////////////////////////////////////////// CtrlCustom::CtrlCustom(ResDialog *dlg, GXmlTag *load) : ResDialogCtrl(dlg, Res_Custom, load) { Control = 0; } IMPL_DIALOG_CTRL(CtrlCustom) CtrlCustom::~CtrlCustom() { DeleteArray(Control); } void CtrlCustom::OnPaint(GSurface *pDC) { GRect r(0, 0, X()-1, Y()-1); Client = r; LgiWideBorder(pDC, r, DefaultSunkenEdge); COLOUR White = Rgb24(0xff, 0xff, 0xff); pDC->Colour(White, 24); pDC->Rectangle(&r); char s[256] = "Custom: "; if (Control) { strcat(s, Control); } SysFont->Colour(LC_TEXT, LC_WORKSPACE); GDisplayString ds(SysFont, s); ds.Draw(pDC, r.x1+2, r.y1+1, &r); // Draw any rubber band ResDialogCtrl::OnPaint(pDC); } #define VAL_Control "Ctrl" bool CtrlCustom::GetFields(FieldTree &Fields) { bool Status = ResDialogCtrl::GetFields(Fields); if (Status) { Fields.Insert(this, DATA_STR, 320, VAL_Control, "Control", 1); } return Status; } bool CtrlCustom::Serialize(FieldTree &Fields) { bool Status = ResDialogCtrl::Serialize(Fields); if (Status) { Fields.Serialize(this, VAL_Control, Control); } return Status; } //////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////// ResStringGroup *ResDialog::Symbols = 0; int ResDialog::SymbolRefs = 0; bool ResDialog::CreateSymbols = true; void ResDialog::AddLanguage(const char *Id) { if (Symbols) { Symbols->AppendLanguage(Id); } } void ResDialogCtrl::EnumCtrls(List &Ctrls) { Ctrls.Insert(this); ChildIterator It(View()->IterateViews()); for (GViewI *c = It->First(); c; c = It->Next()) { ResDialogCtrl *dc = dynamic_cast(c); LgiAssert(dc); dc->EnumCtrls(Ctrls); } } void ResDialog::EnumCtrls(List &Ctrls) { for (ResDialogCtrl *c = dynamic_cast(Children.First()); c; c = dynamic_cast(Children.Next())) { c->EnumCtrls(Ctrls); } } int GooberCaps[] = { RESIZE_X1 | RESIZE_Y1, RESIZE_Y1, RESIZE_X2 | RESIZE_Y1, RESIZE_X2, RESIZE_X2 | RESIZE_Y2, RESIZE_Y2, RESIZE_X1 | RESIZE_Y2, RESIZE_X1}; ResDialog::ResDialog(AppWnd *w, int type) : Resource(w, type) { // Maintain a string group just for our dialog // defines if (!Symbols && w) { // First check to see of the symbols have been loaded from a file // and we don't have a pointer to it yet Symbols = App()->GetDialogSymbols(); if (!Symbols) { // else we need to create the symbols object Symbols = new ResStringGroup(w); if (Symbols) { Symbols->Name(StrDialogSymbols); w->InsertObject(TYPE_STRING, Symbols); } } if (Symbols) { Symbols->SystemObject(true); } } SymbolRefs++; // Init dialog resource Ui = 0; DlgPos.ZOff(500-1, 400-1); DragGoober = -1; DragX = 0; DragY = 0; DragCtrl = 0; } ResDialog::~ResDialog() { // Decrement and delete the shared string group SymbolRefs--; if (SymbolRefs < 1) { App()->DelObject(Symbols); Symbols = 0; } // Delete our Ui DeleteObj(Ui); } void ResDialog::OnShowLanguages() { // Current language changed. OnSelect(Selection.First()); Invalidate(); OnLanguageChange(); } char *ResDialog::Name() { GViewI *v = Children.First(); ResDialogCtrl *Ctrl = dynamic_cast(v); if (Ctrl && Ctrl->Str && Ctrl->Str->GetDefine()) { return Ctrl->Str->GetDefine(); } return (char*)""; } bool ResDialog::Name(const char *n) { ResDialogCtrl *Ctrl = dynamic_cast(Children.First()); if (Ctrl && Ctrl->Str) { Ctrl->Str->SetDefine((n)?n:""); return Ctrl->Str->GetDefine() != 0; } return false; } char *ResDialog::StringFromRef(int Ref) { if (Symbols) { ResString *Str = Symbols->FindRef(Ref); if (Str) { return Str->Get(); } } return 0; } bool ResDialog::Res_GetProperties(ResObject *Obj, GDom *Props) { ResDialogCtrl *Ctrl = dynamic_cast(Obj); if (Ctrl && Props) { int Next = -1000; FieldTree t(Next, false); t.SetStore(Props); t.SetMode(FieldTree::ObjToStore); Ctrl->GetFields(t); Ctrl->Serialize(t); return true; } return false; } GDom *ResDialog::Res_GetDom(ResObject *Obj) { return dynamic_cast(Obj); } bool ResDialog::Res_SetProperties(ResObject *Obj, GDom *Props) { ResDialogCtrl *Ctrl = dynamic_cast(Obj); if (Ctrl && Props) { int Next = -1000; FieldTree t(Next, false); t.SetStore(Props); t.SetMode(FieldTree::StoreToObj); Ctrl->GetFields(t); Ctrl->Serialize(t); return true; } return false; } ResObject *ResDialog::CreateObject(GXmlTag *Tag, ResObject *Parent) { return dynamic_cast(CreateCtrl(Tag)); } void ResDialog::Res_SetPos(ResObject *Obj, int x1, int y1, int x2, int y2) { if (Obj) { ResDialogCtrl *Ctrl = dynamic_cast((ResDialogCtrl*)Obj); if (Ctrl) { GRect r(x1, y1, x2, y2); Ctrl->SetPos(r); } } } void ResDialog::Res_SetPos(ResObject *Obj, char *s) { if (Obj) { ResDialogCtrl *Ctrl = dynamic_cast((ResDialogCtrl*)Obj); if (Ctrl) { Ctrl->ReadPos(s); } } } GRect ResDialog::Res_GetPos(ResObject *Obj) { if (Obj) { ResDialogCtrl *Ctrl = dynamic_cast((ResDialogCtrl*)Obj); LgiAssert(Ctrl); if (Ctrl) { return Ctrl->View()->GetPos(); } } return GRect(0, 0, 0, 0); } int ResDialog::Res_GetStrRef(ResObject *Obj) { if (Obj) { ResDialogCtrl *Ctrl = dynamic_cast((ResDialogCtrl*)Obj); if (Ctrl) { return Ctrl->Str->GetRef(); } } return -1; } bool ResDialog::Res_SetStrRef(ResObject *Obj, int Ref, ResReadCtx *Ctx) { ResDialogCtrl *Ctrl = 0; if (!Obj || !Symbols) return false; Ctrl = dynamic_cast((ResDialogCtrl*)Obj); if (!Ctrl) return false; Ctrl->StrFromRef(Ref); LgiAssert(Ctrl && Ctrl->Str); return Ctrl->Str != 0; } void ResDialog::Res_Attach(ResObject *Obj, ResObject *Parent) { if (Obj && Parent) { ResDialogCtrl *Ctrl = dynamic_cast((ResDialogCtrl*)Obj); ResDialogCtrl *Par = dynamic_cast((ResDialogCtrl*)Parent); if (Ctrl && Par) { Par->AttachCtrl(Ctrl); } } } bool ResDialog::Res_GetChildren(ResObject *Obj, List *l, bool Deep) { bool Status = false; if (Obj) { ResDialogCtrl *Ctrl = dynamic_cast((ResDialogCtrl*)Obj); if (Ctrl) { Status = true; List Child; Ctrl->ListChildren(Child, Deep); for (ResDialogCtrl *o = Child.First(); o; o = Child.Next()) { l->Insert(o); } } } return Status; } void ResDialog::Res_Append(ResObject *Obj, ResObject *Parent) { if (Obj && Parent) { CtrlTabs *Tabs = dynamic_cast(Obj); CtrlTab *Tab = dynamic_cast(Parent); if (Tabs && Tab) { Tab->SetParent(Tabs); Tabs->Tabs.Insert(Tab); if (Tabs->Tabs.Length() == 1) { Tabs->FromTab(); } return; } CtrlList *Lst = dynamic_cast(Obj); ListCol *Col = dynamic_cast(Parent); if (Lst && Col) { Lst->Cols.Insert(Col); return; } } } bool ResDialog::Res_GetItems(ResObject *Obj, List *l) { if (Obj && l) { CtrlTabs *Tabs = dynamic_cast(Obj); if (Tabs) { for ( CtrlTab *Tab = Tabs->Tabs.First(); Tab; Tab = Tabs->Tabs.Next()) { l->Insert(Tab); } return true; } CtrlList *Lst = dynamic_cast(Obj); if (Lst) { for ( ListCol *Col = Lst->Cols.First(); Col; Col = Lst->Cols.Next()) { l->Insert(Col); } return true; } } return false; } void ResDialog::Create(GXmlTag *load, SerialiseContext *Ctx) { CtrlDlg *Dlg = new CtrlDlg(this, load); if (Dlg) { GRect r = DlgPos; r.Offset(GOOBER_BORDER, GOOBER_BORDER); Children.Insert(Dlg); Dlg->SetParent(this); if (load) { if (Ctx) Read(load, *Ctx); else LgiAssert(0); } else { Dlg->ResDialogCtrl::SetPos(r); if (Dlg->Str) Dlg->Str->Set("Dialog"); } } } void ResDialog::Delete() { // Deselect the dialog ctrl OnDeselect(dynamic_cast(Children.First())); // Delete selected controls for (ResDialogCtrl *c = Selection.First(); c; c = Selection.First()) { c->View()->Detach(); DeleteObj(c); } // Repaint GView::Invalidate(); } bool IsChild(ResDialogCtrl *Parent, ResDialogCtrl *Child) { if (Parent && Child) { for ( ResDialogCtrl *c = Child->ParentCtrl(); c; c = c->ParentCtrl()) { if (c == Parent) { return true; } } } return false; } void GetTopCtrls(List &Top, List &Selection) { // all children will automatically be cut as well for (ResDialogCtrl *c = Selection.First(); c; c = Selection.Next()) { // is c a child of an item already in Top? bool Ignore = false; for (ResDialogCtrl *p = Top.First(); p; p = Top.Next()) { if (IsChild(p, c)) { Ignore = true; break; } } if (!Ignore) { // is not a child Top.Insert(c); } } } void ResDialog::Copy(bool Delete) { bool Status = false; // Deselect the dialog... can't cut that OnDeselect(dynamic_cast(Children.First())); // Get top level list List Top; GetTopCtrls(Top, Selection); // ok we have a top level list of ctrls // write them to the file List All; ResDialogCtrl *c; GXmlTag *Root = new GXmlTag("Resources"); if (Root) { if (Delete) { // remove selection from UI AppWindow->OnObjSelect(0); } // write the string resources first for (c = Top.First(); c; c = Top.Next()) { All.Insert(c); c->ListChildren(All, true); } // write the strings out at the top of the block // so that we can reference them from the objects // below. SerialiseContext Ctx; for (c = All.First(); c; c = All.Next()) { // Write the string out GXmlTag *t = new GXmlTag; if (t && c->Str->Write(t, Ctx)) { Root->InsertTag(t); } else { DeleteObj(t); } } // write the objects themselves for (c = Top.First(); c; c = Top.Next()) { GXmlTag *t = new GXmlTag; if (t && Res_Write(c, t)) { Root->InsertTag(t); } else { DeleteObj(t); } } // Read the file in and copy to the clipboard GStringPipe Xml; GXmlTree Tree; if (Tree.Write(Root, &Xml)) { char *s = Xml.NewStr(); { GClipBoard Clip(Ui); char16 *w = Utf8ToWide(s); Clip.TextW(w); Status = Clip.Text(s, false); DeleteObj(w); } DeleteArray(s); } DeleteObj(Root); if (Delete && Status) { // delete them for (c = Selection.First(); c; c = Selection.First()) { c->View()->Detach(); Selection.Delete(c); DeleteObj(c); } } // Repaint GView::Invalidate(); } } class StringId { public: ResString *Str; int OldRef; int NewRef; }; void RemapAllRefs(GXmlTag *t, List &Strs) { char *RefStr; if ((RefStr = t->GetAttr("Ref"))) { int r = atoi(RefStr); for (StringId *i=Strs.First(); i; i=Strs.Next()) { if (i->OldRef == r) { // this string ref is to be remapped char Buf[32]; sprintf(Buf, "%i", i->NewRef); t->SetAttr("Ref", Buf); // delete the string ref map // it's not needed anymore Strs.Delete(i); DeleteObj(i); // leave the loop RefStr = 0; break; } } if (RefStr) { // if this assert failes then no map for this // string was found. every incomming string needs // to be remapped LgiAssert(0); } } for (GXmlTag *c = t->Children.First(); c; c = t->Children.Next()) { RemapAllRefs(c, Strs); } } void ResDialog::Paste() { // Get the clipboard data char *Mem = 0; char *Data = 0; { GClipBoard Clip(Ui); char16 *w = Clip.TextW(); if (w) Data = Mem = WideToUtf8(w); else Data = Clip.Text(); } if (Data) { ResDialogCtrl *Container = 0; // Find a container to plonk the controls in ResDialogCtrl *c = Selection.First(); if (c && c->IsContainer()) { Container = c; } if (!Container) { // Otherwise just use the dialog as the container Container = dynamic_cast(Children.First()); } if (Container) { // remap list List Strings; int NextRef = 0; // Deselect everything OnSelect(NULL); // Parse the data List NewStrs; GXmlTree Tree; GStringPipe p; p.Push(Data); // Create the new controls, strings first // that way we can setup the remapping properly to avoid // string ref duplicates GXmlTag Root; if (Tree.Read(&Root, &p, 0)) { GXmlTag *t; for (t = Root.Children.First(); t; t = Root.Children.Next()) { if (t->IsTag("string")) { // string tag LgiAssert(Symbols); ResString *Str = Symbols->CreateStr(); SerialiseContext Ctx; if (Str && Str->Read(t, Ctx)) { // setup remap object, so that we can make all the strings // unique StringId *Id = new StringId; LgiAssert(Id); Id->Str = Str; Id->OldRef = Str->GetRef(); NextRef = Str->SetRef(Id->NewRef = AppWindow->GetUniqueStrRef(NextRef + 1)); Strings.Insert(Id); // insert out new string NewStrs.Insert(Str); } else { break; } } else { // object tag // all strings should have been processed by the time // we get in here. We remap the incomming string refs to // unique values so that we don't get conflicts later. RemapAllRefs(t, Strings); } } // load all the objects now List NewCtrls; for (t = Root.Children.First(); t; t = Root.Children.Next()) { if (!t->IsTag("string")) { // object (not string) CreateSymbols = false; ResDialogCtrl *Ctrl = dynamic_cast(CreateCtrl(t)); CreateSymbols = true; ResReadCtx Ctx; if (Ctrl && Res_Read(Ctrl, t, Ctx)) { NewCtrls.Insert(Ctrl); } else { break; } } } // calculate the new control set's dimensions so we // can paste them in at the top of the container ResDialogCtrl *c = NewCtrls.First(); if (c) { GRect All = c->View()->GetPos(); while ((c = NewCtrls.Next())) { All.Union(&c->View()->GetPos()); } // now paste in the controls for (c = NewCtrls.First(); c; c = NewCtrls.Next()) { GRect *Preference = Container->GetPasteArea(); GRect p = c->View()->GetPos(); p.Offset(-All.x1, -All.y1); p.Offset(Preference ? Preference->x1 : Container->Client.x1 + GRID_X, Preference ? Preference->y1 : Container->Client.y1 + GRID_Y); c->SetPos(p); Container->AttachCtrl(c, &c->View()->GetPos()); OnSelect(c, false); } // reset parent size to fit GRect cp = Container->View()->GetPos(); Container->SetPos(cp, true); } // Deduplicate all these new strings for (ResString *s = NewStrs.First(); s; s = NewStrs.Next()) { s->UnDuplicate(); } } // Repaint GView::Invalidate(); } } DeleteArray(Mem); } void ResDialog::SnapPoint(GdcPt2 *p, ResDialogCtrl *From) { ResDialogCtrl *Ctrl = dynamic_cast(Children.First()); if (p && Ctrl) { int Ox = 0; // -Ctrl->Client.x1; int Oy = 0; // -Ctrl->Client.y1; GView *Parent = dynamic_cast(Ctrl); if (From) { for (GViewI *w = From->View(); w && w != Parent; w = w->GetParent()) { Ox += w->GetPos().x1; Oy += w->GetPos().y1; } } p->x += Ox; p->y += Oy; p->x = ((p->x + (GRID_X / 2)) / GRID_X * GRID_X); p->y = ((p->y + (GRID_X / 2)) / GRID_X * GRID_X); p->x -= Ox; p->y -= Oy; } } void ResDialog::SnapRect(GRect *r, ResDialogCtrl *From) { ResDialogCtrl *Ctrl = dynamic_cast(Children.First()); if (r && Ctrl) { int Ox = 0; // -Ctrl->Client.x1; int Oy = 0; // -Ctrl->Client.y1; GView *Parent = dynamic_cast(Ctrl); for (GViewI *w = From->View(); w && w != Parent; w = w->GetParent()) { Ox += w->GetPos().x1; Oy += w->GetPos().y1; } r->Normal(); r->Offset(Ox, Oy); r->x1 = ((r->x1 + (GRID_X / 2)) / GRID_X * GRID_X); r->y1 = ((r->y1 + (GRID_X / 2)) / GRID_X * GRID_X); r->x2 = ((r->x2 + (GRID_X / 2)) / GRID_X * GRID_X) - 1; r->y2 = ((r->y2 + (GRID_X / 2)) / GRID_X * GRID_X) - 1; r->Offset(-Ox, -Oy); } } bool ResDialog::IsDraging() { return DragGoober >= 0; } int ResDialog::CurrentTool() { return (Ui) ? Ui->CurrentTool() : 0; } void ResDialog::MoveSelection(int Dx, int Dy) { ResDialogCtrl *w = Selection.First(); if (w) { ResDialogCtrl *Parent = w->ParentCtrl(); if (Parent) { // find dimensions of group GRect All = w->View()->GetPos(); for (; w; w = Selection.Next()) { All.Union(&w->View()->GetPos()); } // limit the move to the top-left corner of the parent's client GRect ParentClient = Parent->Client; if (dynamic_cast(Parent)) ParentClient.ZOff(-ParentClient.x1, -ParentClient.y1); if (All.x1 + Dx < ParentClient.x1) { Dx = ParentClient.x1 - All.x1; } if (All.y1 + Dy < ParentClient.y1) { Dy = ParentClient.y1 - All.y1; } // move the ctrls GRegion Update; for (w = Selection.First(); w; w = Selection.Next()) { GRect Old = w->View()->GetPos(); GRect New = Old; New.Offset(Dx, Dy); // optionally limit the move to the containers bounds GRect *b = w->ParentCtrl()->GetChildArea(w); if (b) { if (New.x1 < b->x1) { New.Offset(b->x1 - New.x1, 0); } else if (New.x2 > b->x2) { New.Offset(b->x2 - New.x2, 0); } if (New.y1 < b->y1) { New.Offset(0, b->y1 - New.y1); } else if (New.y2 > b->y2) { New.Offset(0, b->y2 - New.y2); } } GRect Up = w->AbsPos(); Up.Size(-GOOBER_BORDER, -GOOBER_BORDER); Update.Union(&Up); w->SetPos(New, false); Up = w->AbsPos(); Up.Size(-GOOBER_BORDER, -GOOBER_BORDER); Update.Union(&Up); } Invalidate(&Update); } } } void ResDialog::SelectCtrl(ResDialogCtrl *c) { Selection.Empty(); if (c) { bool IsMine = false; for (GViewI *p = c->View(); p; p = p->GetParent()) { if ((GViewI*)this == p) { IsMine = true; break; } } if (IsMine) { Selection.Insert(c); // int TabIdx = -1; ResDialogCtrl *Prev = 0; for (GViewI *p = c->View()->GetParent(); p; p = p->GetParent()) { ResDialogCtrl *c = dynamic_cast(p); if (c) { c->ShowMe(Prev); Prev = c; } else break; } } else { printf("%s:%i - Ctrl doesn't belong to me.\n", __FILE__, __LINE__); } } else { printf("Selecting '0'\n"); } Invalidate(); if (AppWindow) { AppWindow->OnObjSelect(c); } } void ResDialog::SelectNone() { Selection.Empty(); Invalidate(); if (AppWindow) { AppWindow->OnObjSelect(0); } } void ResDialog::SelectRect(ResDialogCtrl *Parent, GRect *r, bool ClearPrev) { if (ClearPrev) { Selection.Empty(); } if (Parent && r) { GAutoPtrIt(Parent->View()->IterateViews()); for (GViewI *c = It->First(); c; c = It->Next()) { if (c->GetPos().Overlap(r)) { ResDialogCtrl *Ctrl = dynamic_cast(c); if (Ctrl) { if (Selection.IndexOf(Ctrl) >= 0) { Selection.Delete(Ctrl); } else { Selection.Insert(Ctrl); } } } } } Invalidate(); if (AppWindow) { AppWindow->OnObjSelect((Selection.Length() == 1) ? Selection.First() : 0); } } bool ResDialog::IsSelected(ResDialogCtrl *Ctrl) { return Selection.IndexOf(Ctrl) >= 0; } void ResDialog::OnSelect(ResDialogCtrl *Wnd, bool ClearPrev) { if (ClearPrev) { Selection.Empty(); } if (Wnd) { ResDialogCtrl *Ctrl = dynamic_cast(Wnd); if (Ctrl) { if (!Selection.HasItem(Ctrl)) { Selection.Insert(Ctrl); } if (Ui) { Ui->SelectTool(UI_CURSOR); } Invalidate(); } if (AppWindow) { AppWindow->OnObjSelect((Selection.Length() == 1) ? Selection.First() : 0); } } } void ResDialog::OnDeselect(ResDialogCtrl *Wnd) { if (Selection.HasItem(Wnd)) { Selection.Delete(Wnd); AppWindow->OnObjSelect(0); } } ResDialogCtrl *ResDialog::CreateCtrl(GXmlTag *t) { if (t) { for (LgiObjectName *o = NameMap; o->Type; o++) { if (t->IsTag(o->ResourceName)) { return CreateCtrl(o->Type, t); } } } return 0; } ResDialogCtrl *ResDialog::CreateCtrl(int Tool, GXmlTag *load) { ResDialogCtrl *Ctrl = 0; switch (Tool) { case UI_DIALOG: { Ctrl = new CtrlDlg(this, load); break; } case UI_TABLE: { Ctrl = new CtrlTable(this, load); break; } case UI_TEXT: { Ctrl = new CtrlText(this, load); if (Ctrl && Ctrl->Str && !load) { Ctrl->Str->Set("Some text"); } break; } case UI_EDITBOX: { Ctrl = new CtrlEditbox(this, load); break; } case UI_CHECKBOX: { Ctrl = new CtrlCheckbox(this, load); if (Ctrl && Ctrl->Str && !load) { Ctrl->Str->Set("Checkbox"); } break; } case UI_BUTTON: { Ctrl = new CtrlButton(this, load); if (Ctrl && Ctrl->Str && !load) { static int i = 1; char Text[256]; sprintf(Text, "Button %i", i++); Ctrl->Str->Set(Text); } break; } case UI_GROUP: { Ctrl = new CtrlGroup(this, load); if (Ctrl && Ctrl->Str && !load) { Ctrl->Str->Set("Text"); } break; } case UI_RADIO: { Ctrl = new CtrlRadio(this, load); if (Ctrl && Ctrl->Str && !load) { Ctrl->Str->Set("Radio"); } break; } case UI_TAB: { Ctrl = new CtrlTab(this, load); break; } case UI_TABS: { Ctrl = new CtrlTabs(this, load); break; } case UI_LIST: { Ctrl = new CtrlList(this, load); break; } case UI_COLUMN: { Ctrl = new ListCol(this, load); break; } case UI_COMBO: { Ctrl = new CtrlComboBox(this, load); break; } case UI_TREE: { Ctrl = new CtrlTree(this, load); break; } case UI_BITMAP: { Ctrl = new CtrlBitmap(this, load); break; } case UI_SCROLL_BAR: { Ctrl = new CtrlScrollBar(this, load); break; } case UI_PROGRESS: { Ctrl = new CtrlProgress(this, load); break; } case UI_CUSTOM: { Ctrl = new CtrlCustom(this, load); break; } case UI_CONTROL_TREE: { Ctrl = new CtrlControlTree(this, load); break; } default: { LgiAssert(!"No control factory handler."); break; } } if (Ctrl && Ctrl->Str) { Ctrl->Str->UpdateWnd = Ctrl->View(); } return Ctrl; } GView *ResDialog::CreateUI() { return Ui = new ResDialogUi(this); } void ResDialog::DrawSelection(GSurface *pDC) { if (Selection.Length() == 0) return; // Draw selection for (ResDialogCtrl *Ctrl = Selection.First(); Ctrl; Ctrl = Selection.Next()) { GRect r = Ctrl->AbsPos(); COLOUR s = Rgb24(255, 0, 0); COLOUR c = GetParent()->Focus() ? s : GdcMixColour(s, LC_MED, 0.4); DrawGoobers(pDC, r, Ctrl->Goobers, c); } } void ResDialog::_Paint(GSurface *pDC, GdcPt2 *Offset, GRegion *Update) { #ifndef MAC GScreenDC DC(this); pDC = &DC; #endif ResDialogCtrl *Ctrl = dynamic_cast(Children.First()); if (Ctrl) { GRect c = Ctrl->View()->GetPos(); c.Size(-GOOBER_BORDER, -GOOBER_BORDER); #ifdef MAC GSurface *pMemDC = pDC; if (pMemDC) #else GAutoPtr pMemDC(new GMemDC); if (pMemDC && pMemDC->Create(c.X(), c.Y(), GdcD->GetColourSpace())) #endif { #ifdef MAC GScreenDC *Scr = dynamic_cast(pDC); if (Scr) Scr->PushState(); #endif // Draw client pMemDC->Colour(LC_WORKSPACE, 24); // pMemDC->Colour(Rgb24(0, 128, 0), 24); pMemDC->Rectangle(); // Paint children GRect Pos = Ctrl->View()->GetPos(); pMemDC->SetClient(&Pos); GView::_Paint(pMemDC); pMemDC->SetClient(0); if (GetParent()) { #ifdef MAC if (Scr) Scr->PopState(); #endif // Draw selection DrawSelection(pMemDC); } #ifndef MAC // Put on screen pMemDC->SetOrigin(0, 0); pDC->Blt(0, 0, pMemDC); // Draw other non Mem-DC regions pDC->Colour(LC_WORKSPACE, 24); if (X() > c.X()) { pDC->Rectangle(c.x2 + 1, 0, X()-1, c.y2); } if (Y() > c.Y()) { pDC->Rectangle(0, c.y2 + 1, X()-1, Y()-1); } #endif } else { // error SysFont->Colour(LC_TEXT, LC_WORKSPACE); SysFont->Transparent(false); GDisplayString Ds(SysFont, "Can't create memory bitmap."); Ds.Draw(pDC, 2, 0, &GetClient()); } } else { pDC->Colour(LC_WORKSPACE, 24); pDC->Rectangle(); } } void ResDialog::OnLanguageChange() { if (Ui && Ui->StatusInfo) { GLanguage *l = Symbols->GetLanguage(App()->GetCurLang()->Id); if (l) { char Str[256]; sprintf(Str, "Current Language: %s (Id: %s)", l->Name, l->Id); Ui->StatusInfo->Name(Str); } } } bool ResDialog::OnKey(GKey &k) { if (k.Ctrl()) { switch (k.c16) { case VK_UP: { if (k.Down()) { int Idx = Symbols->GetLangIdx(App()->GetCurLang()->Id); if (Idx > 0) { GLanguage *l = Symbols->GetLanguage(Idx - 1); if (l) { App()->SetCurLang(l); } } Invalidate(); OnLanguageChange(); } return true; break; } case VK_DOWN: { if (k.Down()) { int Idx = Symbols->GetLangIdx(App()->GetCurLang()->Id); if (Idx < Symbols->GetLanguages() - 1) { GLanguage *l = Symbols->GetLanguage(Idx + 1); if (l) { App()->SetCurLang(l); } } Invalidate(); OnLanguageChange(); } return true; break; } } } return false; } void ResDialog::OnMouseClick(GMouse &m) { if (m.Down()) { if (GetParent()) GetParent()->Focus(true); if (m.Left()) { DragGoober = -1; for (ResDialogCtrl *c = Selection.First(); c; c = Selection.Next()) { for (int i=0; i<8; i++) { if (c->Goobers[i].Overlap(m.x, m.y)) { DragGoober = i; DragCtrl = c; break; } } } if (DragGoober >= 0) { DragRgn = DragCtrl->View()->GetPos(); DragX = DragY = 0; int Cap = GooberCaps[DragGoober]; // Lock the dialog to the top left corner if (dynamic_cast(DragCtrl)) { Cap &= ~(RESIZE_X1|RESIZE_Y1); } if (!Cap) { // Can't move the object anyway so abort the drag DragGoober = -1; } else { // Allow movement along the appropriate edge if (Cap & RESIZE_X1) { DragX = &DragRgn.x1; } if (Cap & RESIZE_Y1) { DragY = &DragRgn.y1; } if (Cap & RESIZE_X2) { DragX = &DragRgn.x2; } if (Cap & RESIZE_Y2) { DragY = &DragRgn.y2; } // Remember the offset to the mouse from the egdes if (DragX) DragOx = m.x - *DragX; if (DragY) DragOy = m.y - *DragY; Capture(true); } } } } else { if (DragGoober >= 0) { Capture(false); DragGoober = -1; DragX = 0; DragY = 0; } } } void ResDialog::OnMouseMove(GMouse &m) { if (DragGoober >= 0) { if (DragX) { *DragX = m.x - DragOx; } if (DragY) { *DragY = m.y - DragOy; } // DragRgn in real coords GRect Old = DragCtrl->View()->GetPos(); GRect New = DragRgn; GAutoPtr It(IterateViews()); if (DragCtrl->View() != It->First()) { SnapRect(&New, DragCtrl->ParentCtrl()); } // New now in snapped coords // If that means the dragging control changes then if (New != Old) { GRegion Update; // change everyone else by the same amount for (ResDialogCtrl *c = Selection.First(); c; c = Selection.Next()) { GRect OldPos = c->View()->GetPos(); GRect NewPos = OldPos; NewPos.x1 += New.x1 - Old.x1; NewPos.y1 += New.y1 - Old.y1; NewPos.x2 += New.x2 - Old.x2; NewPos.y2 += New.y2 - Old.y2; GRect Up = c->AbsPos(); Up.Size(-GOOBER_BORDER, -GOOBER_BORDER); Update.Union(&Up); c->SetPos(NewPos); Up = c->AbsPos(); Up.Size(-GOOBER_BORDER, -GOOBER_BORDER); Update.Union(&Up); } Invalidate(&Update); } } } bool ResDialog::Test(ErrorCollection *e) { return true; } bool ResDialog::Read(GXmlTag *t, SerialiseContext &Ctx) { bool Status = false; // turn symbol creation off so that ctrls find their // symbol via Id matching instead of creating their own CreateSymbols = false; ResDialogCtrl *Dlg = dynamic_cast(Children.First()); if (Dlg) { // Load the resource ResReadCtx Ctx; Status = Res_Read(Dlg, t, Ctx); Item->Update(); } CreateSymbols = true; return Status; } void ResDialog::CleanSymbols() { // removed unreferenced dialog strings if (Symbols) { Symbols->RemoveUnReferenced(); } // re-ID duplicate entries ResDialogCtrl *Ctrl = dynamic_cast(Children.First()); if (Ctrl) { // list all the entries List l; Ctrl->ListChildren(l); l.Insert(Ctrl); // insert the dialog too // remove duplicate string entries for (ResDialogCtrl *c = l.First(); c; c = l.Next()) { LgiAssert(c->Str); c->Str->UnDuplicate(); } } // sort list (cause I need to read the file myself) if (Symbols) { Symbols->Sort(); } } bool ResDialog::Write(GXmlTag *t, SerialiseContext &Ctx) { bool Status = false; ResDialogCtrl *Ctrl = dynamic_cast(Children.First()); if (Ctrl) { // duplicates symbols should have been removed before the // strings were written out // so we don't have to do it here. // write the resources out if (Ctrl) { Status = Res_Write(Ctrl, t); } } else LgiTrace("%s:%i - Not a ResDialogCtrl.\n", _FL); return Status; } void ResDialog::OnRightClick(GSubMenu *RClick) { if (RClick) { if (Enabled()) { RClick->AppendSeparator(); if (Type() > 0) { RClick->AppendItem("Dump to C++", IDM_DUMP, true); GSubMenu *Export = RClick->AppendSub("Export to..."); if (Export) { Export->AppendItem("Lgi File", IDM_EXPORT, true); Export->AppendItem("Win32 Resource Script", IDM_EXPORT_WIN32, false); } } } } } const char *TypeOfRes(ResDialogCtrl *Ctrl) { // the default return "GWindow"; } const char *TextOfCtrl(ResDialogCtrl *Ctrl) { static char Buf[256]; switch (Ctrl->GetType()) { // Has text case UI_TEXT: case UI_EDITBOX: case UI_CHECKBOX: case UI_BUTTON: case UI_GROUP: case UI_RADIO: case UI_COMBO: { char *s = Ctrl->Str->Get(); sprintf(Buf, ", \"%s\"", s?s:""); return Buf; } // Not processed case UI_COLUMN: case UI_TAB: { LgiAssert(0); break; } // No text... case UI_BITMAP: case UI_PROGRESS: case UI_TABS: case UI_LIST: case UI_TREE: case UI_SCROLL_BAR: { break; } } return ""; } void OutputCtrl(GStringPipe &Def, GStringPipe &Var, GStringPipe &Inst, ResDialogCtrl *Ctrl, ResDialogCtrl *Parent, int &Index) { char Str[256]; const char *Type = "GView"; for (LgiObjectName *on=NameMap; on->Type; on++) { if (Ctrl->GetType() == on->Type) { Type = on->ObjectName; break; } } if (stricmp(Type, "GDialog")) { if (ValidStr(Ctrl->Str->GetDefine()) && stricmp(Ctrl->Str->GetDefine(), "IDOK") && stricmp(Ctrl->Str->GetDefine(), "IDCANCEL") && stricmp(Ctrl->Str->GetDefine(), "IDC_STATIC")) { char Tab[8]; int Tabs = (32 - strlen(Ctrl->Str->GetDefine()) - 1) / 4; memset(Tab, '\t', Tabs); Tab[Tabs] = 0; sprintf(Str, "#define %s%s%i\n", Ctrl->Str->GetDefine(), Tab, 1000 + Index); Def.Push(Str); } sprintf(Str, "\t%s *Ctrl%i;\n", Type, Index); Var.Push(Str); sprintf(Str, "\tChildren.Insert(Ctrl%i = new %s(%s, %i, %i, %i, %i%s));\n", Index, Type, Ctrl->Str->GetDefine(), Ctrl->View()->GetPos().x1 - 3, Ctrl->View()->GetPos().y1 - 17, Ctrl->View()->X(), Ctrl->View()->Y(), TextOfCtrl(Ctrl)); Inst.Push(Str); CtrlList *List = dynamic_cast(Ctrl); if (List) { // output columns for (ListCol *c=List->Cols.First(); c; c=List->Cols.Next()) { sprintf(Str, "\tCtrl%i->AddColumn(\"%s\", %i);\n", Index, c->Str->Get(), c->X()); Inst.Push(Str); } } Index++; } GAutoPtr It(Ctrl->View()->IterateViews()); for ( ResDialogCtrl *c=dynamic_cast(It->First()); c; c=dynamic_cast(It->Next())) { OutputCtrl(Def, Var, Inst, c, Ctrl, Index); } } void ResDialog::OnCommand(int Cmd) { switch (Cmd) { case IDM_DUMP: { GStringPipe Def, Var, Inst; GStringPipe Buf; char Str[256]; ResDialogCtrl *Dlg = dynamic_cast(Children.First()); if (Dlg) { // List controls int i=0; OutputCtrl(Def, Var, Inst, Dlg, 0, i); // #define's char *Defs = Def.NewStr(); if (Defs) { Buf.Push(Defs); Def.Empty(); } // Class def Buf.Push( "\nclass Dlg : public GDialog\n" "{\n"); // Variables char *Vars = Var.NewStr(); if (Vars) { Buf.Push(Vars); Var.Empty(); } // Member functions Buf.Push( "\n" "public:\n" "\tDlg(GView *Parent);\n" "\t~Dlg();\n" "\n" "\tint OnNotify(GViewI *Ctrl, int Flags);\n" "};\n" "\n"); // Class impl Buf.Push( "Dlg::Dlg(GView *Parent)\n" "{\n" "\tSetParent(Parent);\n"); sprintf(Str, "\tName(\"%s\");\n" "\tGRegion r(0, 0, %i, %i);\n" "\tSetPos(r);\n", Dlg->Str->Get(), Dlg->View()->X(), Dlg->View()->Y()); Buf.Push(Str); Buf.Push("\tMoveToCenter();\n\n"); // Ctrl instancing char *NewCtrls = Inst.NewStr(); if (NewCtrls) { Buf.Push(NewCtrls); Inst.Empty(); } Buf.Push( "}\n" "\n"); // Destructor Buf.Push( "Dlg::~Dlg()\n" "{\n" "}\n" "\n"); // ::OnNotify Buf.Push( "int Dlg::OnNotify(GViewI *Ctrl, int Flags)\n" "{\n" "\tswitch (Ctrl->GetId())\n" "\t{\n" "\t\tcase IDOK:\n" "\t\t{\n" "\t\t\t// Do something here\n" "\t\t\t// fall thru\n" "\t\t}\n" "\t\tcase IDCANCEL:\n" "\t\t{\n" "\t\t\tEndModal(Ctrl->GetId());\n" "\t\t\tbreak;\n" "\t\t}\n" "\t}\n" "\n" "\treturn 0;\n" "}\n"); // Output to clipboard char *Text = Buf.NewStr(); if (Text) { GClipBoard Clip(Ui); Clip.Text(Text); DeleteArray(Text); } } break; } case IDM_EXPORT: { GFileSelect Select; Select.Parent(AppWindow); Select.Type("Text", "*.txt"); if (Select.Save()) { GFile F; if (F.Open(Select.Name(), O_WRITE)) { F.SetSize(0); // Serialize(F, true); } else { LgiMsg(AppWindow, "Couldn't open file for writing."); } } break; } case IDM_EXPORT_WIN32: { break; } } } int ResDialog::OnCommand(int Cmd, int Event, OsView hWnd) { switch (Cmd) { /* case IDM_SET_LANG: { Symbols->SetCurrent(); OnSelect(Selection.First()); Invalidate(); OnLanguageChange(); break; } */ case IDM_TAB_ORDER: { ResDialogCtrl *Top = 0; if (Selection.Length() == 1 && Selection.First()->IsContainer()) { Top = Selection.First(); } if (!Top) { Top = dynamic_cast(Children.First()); } if (Top) { TabOrder Dlg(this, Top); } break; } } return 0; } ResString *ResDialog::CreateSymbol() { return (Symbols) ? Symbols->CreateStr() : 0; } //////////////////////////////////////////////////////////////////// ResDialogUi::ResDialogUi(ResDialog *Res) { Dialog = Res; Tools = 0; Status = 0; StatusInfo = 0; Name("ResDialogUi"); if (Res) { Res->OnSelect(Res->Selection.First()); ShortCutView *scv = Res->App()->GetShortCutView(); if (scv) scv->OnDialogChange(Res); } } ResDialogUi::~ResDialogUi() { if (Dialog) { ShortCutView *scv = Dialog->App()->GetShortCutView(); if (scv) scv->OnDialogChange(NULL); Dialog->Ui = 0; } } void ResDialogUi::OnPaint(GSurface *pDC) { GRegion Client(0, 0, X()-1, Y()-1); for (GViewI *w = Children.First(); w; w = Children.Next()) { GRect r = w->GetPos(); Client.Subtract(&r); } pDC->Colour(LC_MED, 24); for (GRect *r = Client.First(); r; r = Client.Next()) { pDC->Rectangle(r); } } void ResDialogUi::PourAll() { GRegion Client(GetClient()); GRegion Update; for (GViewI *v = Children.First(); v; v = Children.Next()) { GRect OldPos = v->GetPos(); Update.Union(&OldPos); if (v->Pour(Client)) { if (!v->Visible()) { v->Visible(true); } if (OldPos != v->GetPos()) { // position has changed update... v->Invalidate(); } Client.Subtract(&v->GetPos()); Update.Subtract(&v->GetPos()); } else { // make the view not visible v->Visible(false); } } for (int i=0; iSetBitmap(FileName, 16, 16)) { Tools->Attach(this); Tools->AppendButton("Cursor", 0, TBT_RADIO); for (LgiObjectName *o=NameMap; o->Type; o++) { if (o->ToolbarBtn) { Tools->AppendButton(o->ObjectName, o->Type, TBT_RADIO); } } Tools->AppendSeparator(); // Tools->AppendButton("Change language", IDM_SET_LANG, TBT_PUSH); Tools->AppendButton("Tab Order", IDM_TAB_ORDER, TBT_PUSH, true, 17); } else { DeleteObj(Tools); } DeleteArray(FileName); } Status = new GStatusBar; if (Status) { Status->Attach(this); StatusInfo = Status->AppendPane("", 2); } ResFrame *Frame = new ResFrame(Dialog); if (Frame) { Frame->Attach(this); } PourAll(); } int ResDialogUi::CurrentTool() { if (Tools) { int i=0; GAutoPtr It(Tools->IterateViews()); for (GViewI *w = It->First(); w; w = It->Next(), i++) { GToolButton *But = dynamic_cast(w); if (But) { if (But->Value()) { return But->GetId(); } } } } return -1; } void ResDialogUi::SelectTool(int i) { if (Tools) { GAutoPtr It(Tools->IterateViews()); GViewI *w = (*It)[i]; if (w) { GToolButton *But = dynamic_cast(w); if (But) { But->Value(true); } } } } GMessage::Result ResDialogUi::OnEvent(GMessage *Msg) { switch (MsgCode(Msg)) { case M_COMMAND: { Dialog->OnCommand(MsgA(Msg)&0xffff, MsgA(Msg)>>16, (OsView) MsgB(Msg)); break; } case M_DESCRIBE: { char *Text = (char*) MsgB(Msg); if (Text) { StatusInfo->Name(Text); } break; } } return GView::OnEvent(Msg); } diff --git a/include/linux/Gtk/LgiOsDefs.h b/include/linux/Gtk/LgiOsDefs.h --- a/include/linux/Gtk/LgiOsDefs.h +++ b/include/linux/Gtk/LgiOsDefs.h @@ -1,554 +1,554 @@ /** \file \author Matthew Allen \brief GTK specific types and defines. */ #ifndef __LGI_OS_DEFS_H #define __LGI_OS_DEFS_H #include #include "assert.h" #include "LgiDefs.h" #include #include #include #include #include #include #ifdef WIN32 #include "winsock2.h" #define WIN32GTK 1 #define WINNATIVE 0 #ifdef _WIN64 #define LGI_64BIT 1 #else #define LGI_32BIT 1 #endif #else #define _MULTI_THREADED #include #define LINUX 1 #define XP_CTRLS 1 #define POSIX 1 #ifdef __arm__ #define LGI_RPI 1 #define LGI_32BIT 1 #elif __GNUC__ #if __x86_64__ || __ppc64__ #define LGI_64BIT 1 #else #define LGI_32BIT 1 #endif #endif #endif #undef stricmp #include "LgiInc.h" namespace Gtk { #include #ifdef WIN32 #include #endif } // System #undef Status #undef Success #undef None #undef Above #undef Below #define XStatus int #define XSuccess 0 #define XAbove 0 #define XBelow 1 #define XNone 0L class LgiClass OsAppArguments { struct OsAppArgumentsPriv *d; public: int Args; char **Arg; OsAppArguments(int args, const char **arg); ~OsAppArguments(); void Set(char *CmdLine); OsAppArguments &operator =(OsAppArguments &a); }; // Process #ifdef WIN32 typedef HANDLE OsProcess; #else typedef int OsProcess; #endif typedef int OsProcessId; typedef Gtk::GtkWidget *OsView; typedef Gtk::GtkWindow *OsWindow; typedef char OsChar; typedef Gtk::cairo_t *OsPainter; typedef Gtk::PangoFontDescription *OsFont; typedef void *OsBitmap; #define LgiGetCurrentProcess() getpid() // Because of namespace issues you can't use the built in GTK casting macros. // So this is basically the same thing: // e.g. // Gtk::GtkContainer *c = GtkCast(widget, gtk_container, GtkContainer); // #define GtkCast(obj, gtype, ctype) ((Gtk::ctype*)g_type_check_instance_cast( (Gtk::GTypeInstance*)obj, Gtk::gtype##_get_type() )) #define GtkVer(major, minor) ( (GTK_MAJOR_VERSION > major) || (GTK_MAJOR_VERSION == major && GTK_MINOR_VERSION >= minor) ) class OsApplication { class OsApplicationPriv *d; protected: static OsApplication *Inst; public: OsApplication(int Args, char **Arg); ~OsApplication(); static OsApplication *GetInst() { LgiAssert(Inst); return Inst; } }; #define XcbConn() (OsApplication::GetInst()->GetConn()) #define XcbScreen() (OsApplication::GetInst()->GetScreen()) #define XcbCheck(cookie) (OsApplication::GetInst()->Check(cookie, __FILE__, __LINE__)) #ifdef _DEBUG #define XcbDebug(cookie) (OsApplication::GetInst()->Check(cookie, __FILE__, __LINE__)) #else #define XcbDebug(cookie) cookie #endif // Threads #ifdef WIN32 typedef HANDLE OsThread; typedef DWORD OsThreadId; typedef CRITICAL_SECTION OsSemaphore; #define LgiGetCurrentThread() GetCurrentThreadId() #else typedef pthread_t OsThread; typedef pid_t OsThreadId; typedef pthread_mutex_t OsSemaphore; #define LgiGetCurrentThread() pthread_self() LgiFunc OsThreadId GetCurrentThreadId(); #endif #include "GMessage.h" // Sockets #define ValidSocket(s) ((s)>=0) #ifndef WIN32 #define INVALID_SOCKET -1 #endif typedef int OsSocket; /// Sleep the current thread for i milliseconds. #ifdef WIN32 LgiFunc void LgiSleep(DWORD i); #else -LgiFunc void LgiSleep(uint32 i); +LgiFunc void LgiSleep(uint32_t i); #endif #ifndef WIN32 #define atoi64 atoll #else #define atoi64 _atoi64 #endif #define _snprintf snprintf #define _vsnprintf vsnprintf #define wcscpy_s(dst, len, src) wcsncpy(dst, src, len) /// Process any pending messages in the applications message que and then return. #define LgiYield() LgiApp->Run(false) #define K_CHAR 0x0 /// Drag and drop format for a file #define LGI_FileDropFormat "text/uri-list" #define LGI_StreamDropFormat "application/x-file-stream" // FIXME #define LGI_IllegalFileNameChars "\t\r\n/\\:*?\"<>|" #ifdef WINDOWS #define LGI_WideCharset "ucs-2" #else #define LGI_WideCharset "utf-32" #endif #define LPrintfInt64 "%Li" #define LPrintfHex64 "%Lx" #define LPrintfSizeT "%zu" #define LPrintfSSizeT "%zi" #ifndef SND_ASYNC #define SND_ASYNC 0x0001 #endif #define DOUBLE_CLICK_THRESHOLD 5 #define DOUBLE_CLICK_TIME 400 // Window flags #define GWF_VISIBLE 0x00000001 #define GWF_DISABLED 0x00000002 #define GWF_FOCUS 0x00000004 #define GWF_OVER 0x00000008 #define GWF_DROP_TARGET 0x00000010 #define GWF_SUNKEN 0x00000020 #define GWF_FLAT 0x00000040 #define GWF_RAISED 0x00000080 #define GWF_BORDER 0x00000100 #define GWF_DIALOG 0x00000200 #define GWF_DESTRUCTOR 0x00000400 #define GWF_QUIT_WND 0x00000800 // Menu flags #ifndef WIN32 #define ODS_SELECTED 0x1 #define ODS_DISABLED 0x2 #define ODS_CHECKED 0x4 #endif /// Edge type: Sunken #define SUNKEN 1 /// Edge type: Raised #define RAISED 2 /// Edge type: Chiseled #define CHISEL 3 /// Edge type: Flat #define FLAT 4 #ifdef WIN32 /// The directory separator character on Linux as a char #define DIR_CHAR '\\' /// The directory separator character on Linux as a string #define DIR_STR "\\" /// The path list separator character for Linux #define LGI_PATH_SEPARATOR ";" /// The pattern that matches all files in Linux #define LGI_ALL_FILES "*.*" /// The stardard extension for dynamically linked code #define LGI_LIBRARY_EXT "dll" /// The standard executable extension #define LGI_EXECUTABLE_EXT ".exe" #else /// The directory separator character on Linux as a char #define DIR_CHAR '/' /// The directory separator character on Linux as a string #define DIR_STR "/" /// The path list separator character for Linux #define LGI_PATH_SEPARATOR ":" /// The pattern that matches all files in Linux #define LGI_ALL_FILES "*" /// The stardard extension for dynamically linked code #define LGI_LIBRARY_EXT "so" /// The standard executable extension #define LGI_EXECUTABLE_EXT "" #endif /// The standard end of line string for Linux #define EOL_SEQUENCE "\n" /// Tests a char for being a slash #define IsSlash(c) (((c)=='/')||((c)=='\\')) /// Tests a char for being a quote #define IsQuote(c) (((c)=='\"')||((c)=='\'')) /// ID's returned by LgiMsg. /// \sa LgiMsg enum MessageBoxResponse { IDOK = 1, IDCANCEL = 2, IDABORT = 3, IDRETRY = 4, IDIGNORE = 5, IDYES = 6, IDNO = 7, IDTRYAGAIN = 10, IDCONTINUE = 11, }; /// Standard message box types. /// \sa LgiMsg enum MessageBoxType { MB_OK = 0, MB_OKCANCEL = 1, MB_ABORTRETRYIGNORE = 2, MB_YESNOCANCEL = 3, MB_YESNO = 4, MB_RETRYCANCEL = 5, MB_CANCELTRYCONTINUE = 6 }; #define MB_SYSTEMMODAL 0x1000 /// The CTRL key is pressed /// \sa GKey #define LGI_VKEY_CTRL 0x001 /// The ALT key is pressed /// \sa GKey #define LGI_VKEY_ALT 0x002 /// The SHIFT key is pressed /// \sa GKey #define LGI_VKEY_SHIFT 0x004 /// The left mouse button is pressed /// \sa GMouse #define LGI_VMOUSE_LEFT 0x008 /// The middle mouse button is pressed /// \sa GMouse #define LGI_VMOUSE_MIDDLE 0x010 /// The right mouse button is pressed /// \sa GMouse #define LGI_VMOUSE_RIGHT 0x020 /// The ctrl key is pressed /// \sa GMouse #define LGI_VMOUSE_CTRL 0x040 /// The alt key is pressed /// \sa GMouse #define LGI_VMOUSE_ALT 0x080 /// The shift key is pressed /// \sa GMouse #define LGI_VMOUSE_SHIFT 0x100 /// The mouse event is a down click /// \sa GMouse #define LGI_VMOUSE_DOWN 0x200 /// The mouse event is a double click /// \sa GMouse #define LGI_VMOUSE_DOUBLE 0x400 #define abs(a) ( (a) < 0 ? -(a) : (a) ) #ifndef WIN32 #include typedef enum { /* The keyboard syms have been cleverly chosen to map to ASCII */ VK_UNKNOWN = 0, VK_FIRST = 0, VK_BACKSPACE = 8, VK_TAB = 9, VK_CLEAR = GDK_Clear, VK_RETURN = 13, VK_PAUSE = GDK_Pause, VK_ESCAPE = GDK_Escape, VK_SPACE = 32, VK_EXCLAIM = 33, VK_QUOTEDBL = 34, VK_HASH = 35, VK_DOLLAR = 36, VK_AMPERSAND = 38, VK_QUOTE = 39, VK_LEFTPAREN = 40, VK_RIGHTPAREN = 41, VK_ASTERISK = 42, VK_PLUS = 43, VK_COMMA = 44, VK_MINUS = 45, VK_PERIOD = 46, VK_SLASH = 47, VK_0 = 48, VK_1 = 49, VK_2 = 50, VK_3 = 51, VK_4 = 52, VK_5 = 53, VK_6 = 54, VK_7 = 55, VK_8 = 56, VK_9 = 57, VK_COLON = 58, VK_SEMICOLON = 59, VK_LESS = 60, VK_EQUALS = 61, VK_GREATER = 62, VK_QUESTION = 63, VK_AT = 64, /* Skip uppercase letters */ VK_LEFTBRACKET = GDK_bracketleft, VK_BACKSLASH = GDK_backslash, VK_RIGHTBRACKET = GDK_bracketright, VK_CARET = 94, VK_UNDERSCORE = GDK_underscore, VK_BACKQUOTE = 96, VK_a = GDK_a, VK_b = GDK_b, VK_c = GDK_c, VK_d = GDK_d, VK_e = GDK_e, VK_f = GDK_f, VK_g = GDK_g, VK_h = GDK_h, VK_i = GDK_i, VK_j = GDK_j, VK_k = GDK_k, VK_l = GDK_l, VK_m = GDK_m, VK_n = GDK_n, VK_o = GDK_o, VK_p = GDK_p, VK_q = GDK_q, VK_r = GDK_r, VK_s = GDK_s, VK_t = GDK_t, VK_u = GDK_u, VK_v = GDK_v, VK_w = GDK_w, VK_x = GDK_x, VK_y = GDK_y, VK_z = GDK_z, /* End of ASCII mapped keysyms */ /* Numeric keypad */ VK_KP_ENTER = GDK_KP_Enter, VK_KP0 = GDK_KP_0, VK_KP1 = GDK_KP_1, VK_KP2 = GDK_KP_2, VK_KP3 = GDK_KP_3, VK_KP4 = GDK_KP_4, VK_KP5 = GDK_KP_5, VK_KP6 = GDK_KP_6, VK_KP7 = GDK_KP_7, VK_KP8 = GDK_KP_8, VK_KP9 = GDK_KP_9, VK_KP_PERIOD = GDK_KP_Decimal, VK_KP_DELETE = GDK_KP_Delete, VK_KP_MULTIPLY = GDK_KP_Multiply, VK_KP_PLUS = GDK_KP_Add, VK_KP_MINUS = GDK_KP_Subtract, VK_KP_DIVIDE = GDK_KP_Divide, VK_KP_EQUALS = GDK_KP_Equal, /* Arrows + Home/End pad */ VK_HOME = GDK_Home, VK_LEFT = GDK_Left, VK_UP = GDK_Up, VK_RIGHT = GDK_Right, VK_DOWN = GDK_Down, VK_PAGEUP = GDK_Page_Up, VK_PAGEDOWN = GDK_Page_Down, VK_END = GDK_End, VK_INSERT = GDK_Insert, /* Function keys */ VK_F1 = GDK_F1, VK_F2 = GDK_F2, VK_F3 = GDK_F3, VK_F4 = GDK_F4, VK_F5 = GDK_F5, VK_F6 = GDK_F6, VK_F7 = GDK_F7, VK_F8 = GDK_F8, VK_F9 = GDK_F9, VK_F10 = GDK_F10, VK_F11 = GDK_F11, VK_F12 = GDK_F12, VK_F13 = GDK_F13, VK_F14 = GDK_F14, VK_F15 = GDK_F15, /* Key state modifier keys */ VK_NUMLOCK = GDK_Num_Lock, VK_CAPSLOCK = GDK_Caps_Lock, VK_SCROLLOCK = GDK_Scroll_Lock, VK_LSHIFT = GDK_Shift_L, VK_RSHIFT = GDK_Shift_R, VK_LCTRL = GDK_Control_L, VK_RCTRL = GDK_Control_R, VK_LALT = GDK_Alt_L, VK_RALT = GDK_Alt_R, VK_LMETA = GDK_Hyper_L, VK_RMETA = GDK_Hyper_R, VK_LSUPER = GDK_Super_L, /* "Windows" key */ VK_RSUPER = GDK_Super_R, /* Miscellaneous function keys */ VK_HELP = GDK_Help, VK_PRINT = GDK_Print, VK_SYSREQ = GDK_Sys_Req, VK_BREAK = GDK_Break, VK_MENU = GDK_Menu, VK_UNDO = GDK_Undo, VK_REDO = GDK_Redo, VK_EURO = GDK_EuroSign, /* Some european keyboards */ VK_COMPOSE = GDK_Multi_key, /* Multi-key compose key */ VK_MODE = GDK_Mode_switch, /* "Alt Gr" key (could be wrong) */ VK_DELETE = GDK_Delete, VK_POWER = 0x10000, /* Power Macintosh power key */ VK_CONTEXTKEY = GDK_Menu, /* Add any other keys here */ VK_LAST } LgiKey; #else #define VK_BACKSPACE VK_BACK #define VK_PAGEUP VK_PRIOR #define VK_PAGEDOWN VK_NEXT #define VK_RALT VK_MENU #define VK_LALT VK_MENU #define VK_RCTRL VK_CONTROL #define VK_LCTRL VK_CONTROL #endif ///////////////////////////////////////////////////////////////////////////////////// // Externs #define vsprintf_s vsnprintf #define swprintf_s swprintf #ifndef WIN32 // __CYGWIN__ // LgiFunc char *strnistr(char *a, char *b, int n); #define _strnicmp strncasecmp // LgiFunc int _strnicmp(char *a, char *b, int i); LgiFunc char *strupr(char *a); LgiFunc char *strlwr(char *a); LgiFunc int stricmp(const char *a, const char *b); #define _stricmp strcasecmp // LgiFunc int _stricmp(const char *a, const char *b); #define sprintf_s snprintf #else LgiFunc class GViewI *GWindowFromHandle(OsView hWnd); LgiFunc int GetMouseWheelLines(); LgiFunc int WinPointToHeight(int Pt, HDC hDC = NULL); LgiFunc int WinHeightToPoint(int Ht, HDC hDC = NULL); LgiExtern class GString WinGetSpecialFolderPath(int Id); typedef BOOL (__stdcall *pSHGetSpecialFolderPathA)(HWND hwndOwner, LPSTR lpszPath, int nFolder, BOOL fCreate); typedef BOOL (__stdcall *pSHGetSpecialFolderPathW)(HWND hwndOwner, LPWSTR lpszPath, int nFolder, BOOL fCreate); typedef int (__stdcall *pSHFileOperationA)(LPSHFILEOPSTRUCTA lpFileOp); typedef int (__stdcall *pSHFileOperationW)(LPSHFILEOPSTRUCTW lpFileOp); typedef int (__stdcall *p_vscprintf)(const char *format, va_list argptr); #if _MSC_VER >= 1400 #define snprintf sprintf_s #endif /// Convert a string d'n'd format to an OS dependant integer. LgiFunc int FormatToInt(char *s); /// Convert a Os dependant integer d'n'd format to a string. LgiFunc char *FormatToStr(int f); #endif #endif diff --git a/src/common/Gdc2/Font/LEmojiFont.cpp b/src/common/Gdc2/Font/LEmojiFont.cpp --- a/src/common/Gdc2/Font/LEmojiFont.cpp +++ b/src/common/Gdc2/Font/LEmojiFont.cpp @@ -1,195 +1,195 @@ #include "Lgi.h" #include "LEmojiFont.h" #include "Emoji.h" #include "GFontPriv.h" #include "GdcTools.h" #define FILE_NAME "EmojiMap.png" // 200,960-219,979 struct LEmojiFontPriv { GAutoString Fn; GAutoPtr Img, Scaled; GArray Resampled; int Cell; LEmojiFontPriv() { Cell = EMOJI_CELL_SIZE; } }; LEmojiFont::LEmojiFont() { priv = new LEmojiFontPriv; } LEmojiFont::~LEmojiFont() { delete priv; } void LEmojiFont::_Measure(int &x, int &y, OsChar *Str, int len) { ssize_t Len = len * sizeof(*Str); x = 0; y = priv->Cell; for (auto s = (const uint16*)Str; *s && Len > 0; ) { - uint32 u32 = LgiUtf16To32(s, Len); + uint32_t u32 = LgiUtf16To32(s, Len); if (u32) x += priv->Cell; } } int LEmojiFont::_CharAt(int xPos, OsChar *Str, int len, LgiPxToIndexType Type) { ssize_t Len = len * sizeof(*Str); int x = 0; int Char = 0; for (auto s = (const uint16*)Str; *s && Len > 0; ) { - uint32 u32 = LgiUtf16To32(s, Len); + uint32_t u32 = LgiUtf16To32(s, Len); if (u32) { if (xPos >= x && xPos < x + priv->Cell) return Char; x += priv->Cell; Char++; } else break; } return -1; } void LEmojiFont::_Draw(GSurface *pDC, int x, int y, OsChar *Str, int len, GRect *r, GColour &fore) { if (!priv->Img) return; ssize_t Bytes = len * sizeof(*Str); pDC->Op(GDC_ALPHA); pDC->Colour(Back()); for (auto s = (const uint16*)Str; *s && Bytes > 0; ) { - uint32 u32 = LgiUtf16To32(s, Bytes); + uint32_t u32 = LgiUtf16To32(s, Bytes); if (!u32) break; GSurface *Src = priv->Scaled ? priv->Scaled : priv->Img; auto Idx = EmojiToIconIndex(&u32, 1); if (Idx >= 0) { int Cx = Idx % EMOJI_GROUP_X; int Cy = Idx / EMOJI_GROUP_X; GRect Icon(0, 0, priv->Cell-1, priv->Cell-1); Icon.Offset(Cx * priv->Cell, Cy * priv->Cell); if (!Transparent()) { if (r) pDC->Rectangle(r); else pDC->Rectangle(x, y, x + priv->Cell - 1, y + priv->Cell - 1); } if (priv->Scaled && !priv->Resampled[Idx]) { priv->Resampled[Idx] = true; GAutoPtr s(priv->Scaled->SubImage(Icon)); GRect Src(0, 0, EMOJI_CELL_SIZE-1, EMOJI_CELL_SIZE-1); Src.Offset(Cx * EMOJI_CELL_SIZE, Cy * EMOJI_CELL_SIZE); ResampleDC(s, priv->Img.Get(), &Src); } pDC->Blt(x, y, Src, &Icon); x += priv->Cell; } else LgiAssert(!"Invalid char"); } } int LEmojiFont::GetHeight() { return priv->Cell; } bool LEmojiFont::Create(const char *Face, GCss::Len Sz, GSurface *pSurface) { if (Sz.IsValid()) Size(Sz); if (!priv->Fn) { priv->Fn.Reset(LgiFindFile(FILE_NAME)); if (!priv->Fn) { GFile::Path p(LSP_APP_INSTALL); p += "..\\Lgi\\trunk\\src\\common\\Text\\Emoji\\EmojiMap.png"; if (p.Exists()) priv->Fn.Reset(NewStr(p)); } } if (priv->Fn && !priv->Img) { if (priv->Img.Reset(LoadDC(priv->Fn))) { LgiAssert(priv->Img->GetBits() == 32); } else return false; } if (!d->GlyphMap) { uint Bytes = (MAX_UNICODE + 1) >> 3; d->GlyphMap = new uchar[Bytes]; if (d->GlyphMap) { memset(d->GlyphMap, 0, Bytes); - for (uint32 u=0x203c; u<=0x3299; u++) + for (uint32_t u=0x203c; u<=0x3299; u++) { if (EmojiToIconIndex(&u, 1) >= 0) d->GlyphMap[u>>3] |= 1 << (u & 7); } - for (uint32 u=0x1f004; u<=0x1f6c5; u++) + for (uint32_t u=0x1f004; u<=0x1f6c5; u++) { if (EmojiToIconIndex(&u, 1) >= 0) d->GlyphMap[u>>3] |= 1 << (u & 7); } } } auto Dpi = LgiScreenDpi(); Sz = Size(); if (Sz.IsValid() && priv->Img) { int NewCell = (int) (Sz.Value * Dpi / 50); int Cx = priv->Img->X() / EMOJI_CELL_SIZE; int Cy = priv->Img->Y() / EMOJI_CELL_SIZE; int Nx = Cx * NewCell; int Ny = Cy * NewCell; if ( NewCell != EMOJI_CELL_SIZE && !priv->Scaled && priv->Scaled.Reset(new GMemDC(Nx, Ny, priv->Img->GetColourSpace())) ) { priv->Cell = NewCell; } } return priv->Img != NULL; } diff --git a/src/common/Gdc2/Gradient.cpp b/src/common/Gdc2/Gradient.cpp --- a/src/common/Gdc2/Gradient.cpp +++ b/src/common/Gdc2/Gradient.cpp @@ -1,363 +1,363 @@ #include #include "Gdc2.h" class GGradient : public GApplicator { protected: int Sx, Sy; uchar *Ptr; int Bytes; COLOUR Background; int Angle; GRect Rect; public: const char *GetClass() { return "GGradient"; } bool SetSurface(GBmpMem *d, GPalette *p = 0, GBmpMem *a = 0) { Ptr = 0; Bytes = 0; Background = 0; Angle = 0; Rect.ZOff(0, 0); Sx = Sy = 0; if (d) { Dest = d; Pal = p; Alpha = 0; Ptr = d->Base; Bytes = GColourSpaceToBits(d->Cs) / 8; return true; } return false; } void SetPtr(int x, int y) { Sx = x; Sy = y; Ptr = Dest->Base + (y * Dest->Line) + (x * Bytes); } void IncX() { Ptr += Bytes; } void IncY() { Ptr += Dest->Line; } void IncPtr(int X, int Y) { Ptr += (Y * Dest->Line) + (X * Bytes); } void Set() { } COLOUR Get() { switch (Bytes) { case 2: { ushort *p = (ushort*)Ptr; return *p; break; } case 3: { uchar *p = (uchar*)Ptr; return Rgb24(p[2], p[1], p[0]); break; } case 4: { ulong *p = (ulong*)Ptr; return *p; break; } } return -1; } void VLine(int height) { } bool Blt(GBmpMem *Src, GPalette *SPal, GBmpMem *SrcAlpha = 0) { return false; } int GetVar(int Var) { switch (Var) { case GAPP_ANGLE: { return Angle; } case GAPP_BOUNDS: { return (int)&Rect; } case GAPP_BACKGROUND: { return Background; } } return -1; } int SetVar(int Var, int Value) { int o = GetVar(Var); switch (Var) { case GAPP_ANGLE: { Angle = Value; break; } case GAPP_BOUNDS: { if (Value) { Rect = *((GRect*)Value); } break; } case GAPP_BACKGROUND: { Background = Value; break; } } return o; } }; class GLinearGradient : public GGradient { public: void Rectangle(int X, int Y) { COLOUR Fore = CBit(24, c, GColourSpaceToBits(Dest->Cs)); int Fr = R24(Fore); int Fg = G24(Fore); int Fb = B24(Fore); COLOUR Back = CBit(24, Background, GColourSpaceToBits(Dest->Cs)); int Br = R24(Back); int Bg = G24(Back); int Bb = B24(Back); double Ang = LGI_DegToRad(Angle); while (Ang > LGI_PI) Ang -= LGI_PI; while (Ang < 0) Ang += LGI_PI; uchar *Div255 = Div255Lut; int a, oma, r, g, b; int Cx = (Rect.X() / 2); int Cy = (Rect.Y() / 2); #define Rx(x, y) ((cos(Ang)*(x-Cx)) - (sin(Ang)*(y-Cy))) #define Ry(x, y) ((sin(Ang)*(x-Cx)) + (cos(Ang)*(y-Cy))) GdcPt2 p[4] = { GdcPt2(0, 0), GdcPt2(Rect.X()-1, 0), GdcPt2(0, Rect.Y()-1), GdcPt2(Rect.X()-1, Rect.Y()-1) }; int MinX = 100000, MaxX = -100000; int MinY = 100000, MaxY = -100000; for (int i=0; i<4; i++) { p[i].x = Rx(p[i].x, p[i].y); p[i].y = Ry(p[i].x, p[i].y); MinX = MIN(MinX, p[i].x); MaxX = MAX(MaxX, p[i].x); MinY = MIN(MinY, p[i].y); MaxY = MAX(MaxY, p[i].y); } int Scale = MaxX - MinX; int Offset = -MinX; if (Scale == 0) { return; } for (int y=0; yCs)) { case 16: { for (int x=0; xLine; } } }; class GRadialGradient : public GGradient { public: const char *GetClass() { return "GRadialGradient"; } void Rectangle(int X, int Y) { COLOUR Fore = CBit(24, c, GColourSpaceToBits(Dest->Cs)); int Fr = R24(Fore); int Fg = G24(Fore); int Fb = B24(Fore); COLOUR Back = CBit(24, Background, GColourSpaceToBits(Dest->Cs)); int Br = R24(Back); int Bg = G24(Back); int Bb = B24(Back); uchar *Div255 = Div255Lut; int a, oma, r, g, b; double Cx = Rect.X() / 2; double Cy = Rect.Y() / 2; double Radius = sqrt(Cx*Cx + Cy*Cy); for (int y=0; yCs)) { case 16: { for (int x=0; xLine; } } }; class GGradientFactory : public GApplicatorFactory { public: GApplicator *Create(GColourSpace Cs, int Op) { if (Op == 5) { return new GLinearGradient; } else if (Op == 6) { return new GRadialGradient; } return 0; } } GradientFactory; diff --git a/src/common/Lgi/GFileSelect.cpp b/src/common/Lgi/GFileSelect.cpp --- a/src/common/Lgi/GFileSelect.cpp +++ b/src/common/Lgi/GFileSelect.cpp @@ -1,2101 +1,2101 @@ /*hdr ** FILE: GFileSelect.cpp ** AUTHOR: Matthew Allen ** DATE: 20/5/2002 ** DESCRIPTION: Common file/directory selection dialog ** ** Copyright (C) 1998-2002, Matthew Allen ** fret@memecode.com */ #include #include #include "Lgi.h" #include "GPopup.h" #include "GToken.h" #include "LList.h" #include "GTextLabel.h" #include "GEdit.h" #include "GButton.h" #include "GCheckBox.h" #include "GCombo.h" #include "GTree.h" #include "GTableLayout.h" #include "GBox.h" #define FSI_FILE 0 #define FSI_DIRECTORY 1 #define FSI_BACK 2 #define FSI_UPDIR 3 #define FSI_NEWDIR 4 #define FSI_DESKTOP 5 #define FSI_HARDDISK 6 #define FSI_CDROM 7 #define FSI_FLOPPY 8 #define FSI_NETWORK 9 enum DlgType { TypeNone, TypeOpenFile, TypeOpenFolder, TypeSaveFile }; char ModuleName[] = "File Select"; -uint32 IconBits[] = { +uint32_t IconBits[] = { 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0x0000F81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xC980FA8A, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0x738E738E, 0xF81F738E, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0x8430F81F, 0x84308430, 0x84308430, 0xF81F8430, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0x00000000, 0x00000000, 0x00000000, 0xF81F0000, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0x9CE09CE0, 0x9CE09CE0, 0x00009CE0, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xCCE0F81F, 0x9800FCF9, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0x738E738E, 0xCE6C9E73, 0x738EC638, 0xF81F738E, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0x9FFF738E, 0x9FFF9FFF, 0x9FFF9FFF, 0x00009FFF, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xFFFF0000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0x9CE0F81F, 0xFFF9F7BE, 0xFFF3FFF9, 0x9CE0FFF3, 0xF81F0000, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0x9CE09CE0, 0x9CE09CE0, 0x00009CE0, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0x0000F81F, 0xF81FF81F, 0xF81FF81F, 0x04F904F9, 0x04F904F9, 0xAD720313, 0xAD72AD72, 0xAD72AD72, 0xFE60CCE0, 0x00009B00, 0x0000AD72, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0x738EF81F, 0x667334F3, 0xCE6C9E73, 0xC638B5B6, 0x3186C638, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xFFFF738E, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xF81FF81F, 0x738E738E, 0x738E738E, 0x738E738E, 0x738E738E, 0x738E738E, 0x738E738E, 0xF81F738E, 0xFFFF0000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFF0000, 0xF81F0000, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xCE6C9CE0, 0xCE6CCE6C, 0xCE6CCE6C, 0xCE6CCE6C, 0x9CE09CE0, 0x9CE09CE0, 0x9CE09CE0, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0x0000F81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0x9CE0F81F, 0xFFF9F7BE, 0xFFF3FFF9, 0x9CE0FFF3, 0xF81F0000, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81F0000, 0xF81FF81F, 0xF81FF81F, 0xF81F0000, 0x667F04F9, 0x031304F9, 0xFFFFCE73, 0xFFF9FFFF, 0xCCE0FFFF, 0x9B00FFF3, 0x04F90000, 0x00000313, 0xF81FF81F, 0x738E738E, 0x738E738E, 0x738E738E, 0x738E738E, 0x738E738E, 0x738E738E, 0xF81F738E, 0xF81FF81F, 0xF81FF81F, 0x6673738E, 0x34F36673, 0xCE736673, 0xB5B6C638, 0xB5B6DEFB, 0xF81F3186, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xFFFF738E, 0xFFFFFFFF, 0xCFFFCFFF, 0x0000CFFF, 0x738EF81F, 0xB5B6B5B6, 0xB5B6B5B6, 0xB5B6B5B6, 0xB5B6B5B6, 0xB5B6B5B6, 0xB5B6B5B6, 0x0000738E, 0xFFFF0000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFF0000, 0x0000FFFF, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xFFF99CE0, 0xFFF9FFF9, 0xFFF9FFF9, 0xFFF9FFF9, 0xFFF9FFF9, 0xFFF9FFF9, 0xCE6CFFF3, 0xF81F0000, 0xF81FF81F, 0xF81FF81F, 0x00000000, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xCE6C9CE0, 0xCE6CCE6C, 0xCE6CCE6C, 0xCE6CCE6C, 0x9CE09CE0, 0x9CE09CE0, 0x9CE09CE0, 0xF81FF81F, 0xF81FF81F, 0x9CE09CE0, 0x9CE09CE0, 0xF81F0000, 0x0000F81F, 0x0000F81F, 0x0000F81F, 0xF81FF81F, 0x04F904F9, 0xCE730313, 0xFFFFFFFF, 0xFFF9FFF9, 0xFE60CCE0, 0x00009B00, 0x667F3313, 0x00000313, 0x738EF81F, 0xB5B6B5B6, 0xB5B6B5B6, 0xB5B6B5B6, 0xB5B6B5B6, 0xB5B6B5B6, 0xB5B6B5B6, 0x0000738E, 0xF81FF81F, 0xF81FF81F, 0x34F98430, 0x667364F9, 0x84306679, 0xD6BAB5B6, 0xB5B6C638, 0xF81F3186, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xCFFF738E, 0xCFFFCFFF, 0xCFFFCFFF, 0x0000CFFF, 0xFFFF738E, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x9CF3FFFF, 0x0000738E, 0xFFFF0000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, 0xF81F0000, 0xF81FF81F, 0xF81FF81F, 0xFFF99CE0, 0xFFF3FFF3, 0xFFF3FFF3, 0xFFF3FFF3, 0xFFF3FFF3, 0xFFF3FFF3, 0xCE6CFE73, 0xF81F0000, 0xF81FF81F, 0x0000F81F, 0x000007FF, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xFFF99CE0, 0xFFF9FFF9, 0xFFF9FFF9, 0xFFF9FFF9, 0xFFF9FFF9, 0xFFF9FFF9, 0xCE6CFFF3, 0xF81F0000, 0x9CE0F81F, 0xFFF9F7BE, 0xFFF3FFF3, 0x00009CE0, 0xF81FF81F, 0xF81F0000, 0xF81F0000, 0xF81FF81F, 0x031304F9, 0xFFFFCE73, 0x94B294B2, 0xCCE094B2, 0x9B00FFF3, 0xAD720000, 0x3313FFF9, 0x00000313, 0xFFFF738E, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x9CF3FFFF, 0x0000738E, 0xF81FF81F, 0x738EF81F, 0xA53494B2, 0x667964F3, 0x00008430, 0xA5348430, 0xCE79B5B6, 0x3186CE79, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xCE79738E, 0xCE79C638, 0xC638B5B6, 0x0000B5B6, 0xD6BA738E, 0xC638C638, 0xC638C638, 0xC638C638, 0xB5B6C638, 0x04200660, 0x94B2B5B6, 0x0000738E, 0xFFFF0000, 0xFFFFFFFF, 0xFFFFFFFF, 0xD699FFFF, 0xD699D699, 0xF81F0000, 0xF81FF81F, 0xF81FF81F, 0xFFF99CE0, 0xFFF3FFF3, 0xFFF3FFF3, 0xFFF3FFF3, 0xFE73FFF3, 0xFE73FFF3, 0xCE6CFFF3, 0xF81F0000, 0xF81FF81F, 0x07FF0000, 0x000007FF, 0x00000000, 0x00000000, 0x00000000, 0xF81F0000, 0xF81FF81F, 0xFFF99CE0, 0xFFF3FFF3, 0x0000FFF3, 0xFFF3FFF3, 0xFFF3FFF3, 0xFFF3FFF3, 0xCE6CFE73, 0xF81F0000, 0xCE6C9CE0, 0xCE6CCE6C, 0xCE6CCE6C, 0x9CE0CE6C, 0x9CE09CE0, 0xF81F9CE0, 0x0000F81F, 0x0000F81F, 0xCE730313, 0xFFFFFFFF, 0xFFFF94B2, 0xFE60CCE0, 0x00009B00, 0xFFF9AD72, 0xCE73CE73, 0x00003313, 0xD6BA738E, 0xC638C638, 0xC638C638, 0xC638C638, 0xB5B6C638, 0x04200660, 0x94B2B5B6, 0x0000738E, 0xF81FF81F, 0x738EF81F, 0xB5B6B5B6, 0x8430CE79, 0xF81F0000, 0x84300000, 0xCE79CE79, 0x3186CE79, 0xF81FF81F, 0x84308430, 0x84308430, 0x84308430, 0xC638738E, 0x84308430, 0x84308430, 0x0000C638, 0xDEFB738E, 0xC638B5B6, 0xC638C638, 0xC638C638, 0xB5B6B5B6, 0xB5B6B5B6, 0x94B2B5B6, 0x0000738E, 0xFFFF0000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xD699FFFF, 0xF81F0000, 0xF81FF81F, 0xF81FF81F, 0xFFF99CE0, 0xFFF3FFF3, 0xFFF3FFF3, 0xFFF3FFF3, 0xFFF3FFF3, 0xFFF3FE73, 0xCE6CFE73, 0xF81F0000, 0x0000F81F, 0x07FF07FF, 0x07FF07FF, 0x07FF07FF, 0x07FF07FF, 0x07FF07FF, 0xF81F0000, 0xF81FF81F, 0xFFF99CE0, 0xFFF3FFF3, 0x00000000, 0xFFF30000, 0xFE73FFF3, 0xFE73FFF3, 0xCE6CFFF3, 0xF81F0000, 0xFFF99CE0, 0xFFF9FFF9, 0xFFF9FFF9, 0xFFF9FFF9, 0xFFF3FFF9, 0x0000CE6C, 0xF81F0000, 0xF81FF81F, 0xFFFFAD72, 0xFFF9FFFF, 0xFFFF94B2, 0x9B009CEC, 0x00000000, 0xCE73FFF9, 0xAD72FFF9, 0x000094B2, 0xDEFB738E, 0xC638B5B6, 0xC638C638, 0xC638C638, 0xB5B6B5B6, 0xB5B6B5B6, 0x94B2B5B6, 0x0000738E, 0xF81FF81F, 0x738EF81F, 0xF7BEE73C, 0xB5B6E73C, 0x00008430, 0xB5B68430, 0xF7BEEF7D, 0x3186CE79, 0x8430F81F, 0xC638C638, 0xC638C638, 0xC638C638, 0xCE79738E, 0x0000738E, 0xFFFF738E, 0x0000B5B6, 0xDEFB738E, 0x738E738E, 0x738E738E, 0x738E738E, 0x738E738E, 0x738E738E, 0x94B2B5B6, 0x0000738E, 0xFFFF0000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xD699FFFF, 0xF81F0000, 0xF81FF81F, 0xF81FF81F, 0xFFF99CE0, 0xFFF3FFF3, 0xFFF3FFF3, 0xFE73FFF3, 0xFE73FFF3, 0xFE73FFF3, 0xCE6CFFF3, 0xF81F0000, 0x0000F81F, 0x07FF07FF, 0x07FF07FF, 0x07FF07FF, 0x07FF07FF, 0x07FF07FF, 0xF81F0000, 0xF81FF81F, 0xFFF99CE0, 0x0000FFF3, 0x00000000, 0x00000000, 0xFFF3FFF3, 0xFFF3FE73, 0xCE6CFE73, 0xF81F0000, 0xFFF99CE0, 0xFFF3FFF3, 0xFFF3FFF3, 0xFFF3FFF3, 0xFE73FFF3, 0x0000CE6C, 0x0000F81F, 0xF81FF81F, 0xFFFFAD72, 0xFFF9FFF9, 0xFFFF94B2, 0xFFFF0000, 0x0000FFF9, 0xFFF9CE73, 0xCE73AD72, 0x000094B2, 0xDEFB738E, 0x738E738E, 0x738E738E, 0x738E738E, 0x738E738E, 0x738E738E, 0x94B2B5B6, 0x0000738E, 0x8430F81F, 0x84308430, 0xA5348430, 0xA534B5B6, 0x8430A534, 0xDEFB34F3, 0xFFFFE73C, 0xF81F3186, 0xFFFF8430, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0000FFFF, 0x00000000, 0x00000000, 0xF81F0000, 0xD6BA738E, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x94B2B5B6, 0x0000738E, 0xFFFF0000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xD699FFFF, 0xF81F0000, 0xF81FF81F, 0xF81FF81F, 0xFFF99CE0, 0xFFF3FFF3, 0xFFF3FFF3, 0xFFF3FFF3, 0xFFF3FE73, 0xFFF3FE73, 0xCE6CFE73, 0xF81F0000, 0xF81FF81F, 0x07FF0000, 0x000007FF, 0x00000000, 0x00000000, 0x00000000, 0xF81F0000, 0xF81FF81F, 0xFFF99CE0, 0xFFF3FFF3, 0x0000FFF3, 0xFE73FFF3, 0xFE73FFF3, 0xFE73FFF3, 0xCE6CFFF3, 0xF81F0000, 0xFFF99CE0, 0xFFF3FFF3, 0xFFF3FFF3, 0xFFF3FFF3, 0xFFF3FE73, 0x0000CE6C, 0xF81FF81F, 0xF81F0000, 0xFFF9AD72, 0xFFF9FFF9, 0xFFFF94B2, 0xFFFFFFFF, 0x0000FFF9, 0xCE73FFF9, 0xAD72CE73, 0x000094B2, 0xD6BA738E, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x94B2B5B6, 0x0000738E, 0xFFFF8430, 0xFFFFFFFF, 0xA534738E, 0xB5B6A534, 0xCE73D6BA, 0x34F96673, 0xB5B6CFFF, 0xF81F3186, 0xC6388430, 0xC638C638, 0xC638C638, 0xC638C638, 0xC638C638, 0xC638F800, 0x738E8430, 0xF81F0000, 0x738E738E, 0x738E738E, 0x738E738E, 0x738E738E, 0x738E738E, 0x738E738E, 0x738E738E, 0xF81F0000, 0xFFFF0000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xD699FFFF, 0xF81F0000, 0xF81FF81F, 0xF81FF81F, 0xFFF99CE0, 0xFFF3FFF3, 0xFE73FFF3, 0xFE73FFF3, 0xFE73FFF3, 0xFE73FFF3, 0xCE6CFE73, 0xF81F0000, 0xF81FF81F, 0x0000F81F, 0x000007FF, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xFFF99CE0, 0xFFF3FFF3, 0x0000FFF3, 0xFFF3FFF3, 0xFFF3FE73, 0xFFF3FE73, 0xCE6CFE73, 0xF81F0000, 0xFFF99CE0, 0xFFF3FFF3, 0xFFF3FFF3, 0xFE73FFF3, 0xFE73FFF3, 0x0000CE6C, 0xF81FF81F, 0xF81FF81F, 0xFFF9AD72, 0xFFF9FFF9, 0xFFFF94B2, 0xFFFFFFFF, 0x0000FFF9, 0xCE73CE73, 0xCE73AD72, 0x000094B2, 0x738E738E, 0x738E738E, 0x738E738E, 0x738E738E, 0x738E738E, 0x738E738E, 0x738E738E, 0xF81F0000, 0xFFFF8430, 0xC638C638, 0x738EC638, 0xB5B6A534, 0xCE73CE79, 0x04F99E73, 0x000004F9, 0xF81FF81F, 0xC6388430, 0xC638C638, 0x84308430, 0x84308430, 0xC638C638, 0xC638C638, 0x738E8430, 0xF81F0000, 0x0000F81F, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xF81FF81F, 0xFFFF0000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xD699FFFF, 0xF81F0000, 0xF81FF81F, 0xF81FF81F, 0xFFF99CE0, 0xFFF3FE73, 0xFFF3FE73, 0xFFF3FE73, 0xFFF3FE73, 0xFE73FE73, 0xCE6CFE73, 0xF81F0000, 0xF81FF81F, 0xF81FF81F, 0x00000000, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xFFF99CE0, 0xFFF3FFF3, 0x0000FFF3, 0x00000000, 0x00000000, 0xFE730000, 0xCE6CFE73, 0xF81F0000, 0xFFF99CE0, 0xFFF3FFF3, 0xFFF3FE73, 0xFFF3FE73, 0xFFF3FE73, 0x0000CE6C, 0xF81FF81F, 0xF81FF81F, 0xFFF904F9, 0xFFF9FFF9, 0xFFF994B2, 0xFFF9FFF9, 0x0000FFF9, 0xAD72CE73, 0xAD72CE73, 0x00003313, 0x0000F81F, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xF81FF81F, 0xFFFF8430, 0x31863186, 0x31863186, 0x84308430, 0xCE73CE79, 0x31869E73, 0x00003186, 0xF81FF81F, 0xC6388430, 0x84308430, 0x00000000, 0x00000000, 0x84308430, 0xC6388430, 0x738E8430, 0xF81F0000, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xB5B6F81F, 0xF81F0000, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xFFFF0000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xD699FFFF, 0xF81F0000, 0xF81FF81F, 0xF81FF81F, 0xCE6C9CE0, 0xCE6CCE6C, 0xCE6CCE6C, 0xCE6CCE6C, 0xCE6CCE6C, 0xCE6CCE6C, 0xCE6CCE6C, 0xF81F0000, 0xF81FF81F, 0xF81FF81F, 0x0000F81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xFFF99CE0, 0xFFF3FE73, 0xFFF3FE73, 0xFFF3FE73, 0xFFF3FE73, 0xFE73FE73, 0xCE6CFE73, 0xF81F0000, 0xFFF99CE0, 0xFFF3FE73, 0xFE73FFF3, 0xFE73FFF3, 0xFE73FFF3, 0x0000CE6C, 0xF81FF81F, 0xF81FF81F, 0x04F904F9, 0xFFF9FFF9, 0x00000000, 0x00000000, 0x00000000, 0xCE73AD72, 0x3313AD72, 0x00003313, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xFFFF8430, 0x042007E0, 0xFFFFFFFF, 0xC638C638, 0x31863186, 0xC6383186, 0x0000738E, 0xF81FF81F, 0xC6388430, 0xC638C638, 0xFFFFFFFF, 0xFFFFFFFF, 0xC638C638, 0xC638C638, 0x738E8430, 0xF81F0000, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xB5B6F81F, 0xF81F0000, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xFFFF0000, 0xD699D699, 0xD699D699, 0xD699D699, 0xD699D699, 0xF81F0000, 0xF81FF81F, 0xF81FF81F, 0x0000F81F, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xF81F0000, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xCE6C9CE0, 0xCE6CCE6C, 0xCE6CCE6C, 0xCE6CCE6C, 0xCE6CCE6C, 0xCE6CCE6C, 0xCE6CCE6C, 0xF81F0000, 0xCE6C9CE0, 0xCE6CCE6C, 0xCE6CCE6C, 0xCE6CCE6C, 0xCE6CCE6C, 0x0000CE6C, 0xF81FF81F, 0xF81FF81F, 0x667F04F9, 0xFFF904F9, 0xCE73FFF9, 0xCE73FFF9, 0xAD72CE73, 0xAD72CE73, 0x667F3313, 0x00003313, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0x8430738E, 0x84308430, 0x84308430, 0x84308430, 0x84308430, 0x84308430, 0x00008430, 0xF81FF81F, 0x84308430, 0x84308430, 0x84308430, 0x84308430, 0x84308430, 0x84308430, 0x00008430, 0xF81FF81F, 0xB5B6F81F, 0xB5B6F81F, 0xB5B6B5B6, 0xB5B6B5B6, 0xB5B6B5B6, 0xB5B6B5B6, 0xF81FB5B6, 0xF81FB5B6, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xF81F0000, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0x0000F81F, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xF81F0000, 0x0000F81F, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xF81FF81F, 0xF81FF81F, 0x03130313, 0x04F90313, 0x94B294B2, 0x94B294B2, 0x94B294B2, 0x331394B2, 0x33133313, 0x00003313, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0x0000F81F, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xF81F0000, 0xF81FF81F, 0x0000F81F, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xF81F0000, 0xF81FF81F, 0x0000F81F, 0x0000F81F, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xF81F0000, 0xF81F0000, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F, 0xF81FF81F}; GInlineBmp FileSelectIcons = { 160, 16, 16, IconBits }; ////////////////////////////////////////////////////////////////////////// char *GFileType::DefaultExtension() { char *Status = 0; GToken T(Extension(), ";"); if (T.Length()) { char s[256]; strcpy(s, T[0]); char *Dir = strchr(s, '.'); if (Dir) { Status = NewStr(Dir+1); if (Status) strlwr(Status); } } return Status; } ////////////////////////////////////////////////////////////////////////// class GFolderItem : public LListItem { class GFileSelectDlg *Dlg; char *Path; public: char *File; bool IsDir; GFolderItem(GFileSelectDlg *dlg, char *FullPath, GDirectory *Dir); ~GFolderItem(); void OnActivate(); char *GetText(int i); int GetImage(int Flags); void OnSelect(); void OnDelete(bool Ask = true); void OnRename(); void OnMouseClick(GMouse &m); }; ////////////////////////////////////////////////////////////////////////// // This is just a private data container to make it easier to change the // implementation of this class without effecting headers and applications. class GFileSelectPrivate { friend class GFileSelect; friend class GFileSelectDlg; friend class GFolderList; GView *Parent; GFileSelect *Select; DlgType Type; char *Title; char *DefExt; bool MultiSelect; List Files; int CurrentType; List Types; List History; bool ShowReadOnly; bool ReadOnly; bool EatClose; public: static GImageList *Icons; static char *InitPath; static bool InitShowHiddenFiles; static GRect InitSize; GFileSelectPrivate(GFileSelect *select) { ShowReadOnly = false; ReadOnly = false; EatClose = false; Select = select; Type = TypeNone; Title = 0; DefExt = 0; MultiSelect = false; Parent = 0; CurrentType = -1; if (!Icons) Icons = new GImageList(16, 16, FileSelectIcons.Create(0xF81F)); } virtual ~GFileSelectPrivate() { DeleteArray(Title); DeleteArray(DefExt); Types.DeleteObjects(); Files.DeleteArrays(); History.DeleteArrays(); } }; GImageList *GFileSelectPrivate::Icons = 0; char *GFileSelectPrivate::InitPath = 0; bool GFileSelectPrivate::InitShowHiddenFiles = false; GRect GFileSelectPrivate::InitSize(0, 0, 600, 500); ////////////////////////////////////////////////////////////////////////// // This class implements the UI for the selector. class GFileSelectDlg; class GFolderView { protected: GFileSelectDlg *Dlg; public: GFolderView(GFileSelectDlg *dlg) { Dlg = dlg; } virtual void OnFolder() {} }; class GFolderDrop : public GDropDown, public GFolderView { public: GFolderDrop(GFileSelectDlg *dlg, int Id, int x, int y, int cx, int cy); void OnFolder(); bool OnLayout(GViewLayoutInfo &Inf) { Inf.Width.Min = Inf.Width.Max = 18; return true; } }; class GIconButton : public GLayout { GImageList *Icons; int Icon; bool Down; public: GIconButton(int Id, int x, int y, int cx, int cy, GImageList *icons, int icon) { Icons = icons; Icon = icon; SetId(Id); GRect r(x, y, x+cx, y+cy); SetPos(r); Down = false; SetTabStop(true); } void OnPaint(GSurface *pDC) { GRect c = GetClient(); GColour Background(LC_MED, 24); c.Offset(-c.x1, -c.y1); LgiWideBorder(pDC, c, Down ? DefaultSunkenEdge : DefaultRaisedEdge); pDC->Colour(Background); pDC->Rectangle(&c); int x = (c.X()-Icons->TileX()) / 2; int y = (c.Y()-Icons->TileY()) / 2; if (Focus()) { #if WINNATIVE RECT r = c; DrawFocusRect(pDC->Handle(), &r); #endif } Icons->Draw(pDC, c.x1+x+Down, c.y1+y+Down, Icon, Background, !Enabled()); } void OnFocus(bool f) { Invalidate(); } void OnMouseClick(GMouse &m) { if (Enabled()) { bool Trigger = Down && !m.Down(); Capture(Down = m.Down()); if (Down) Focus(true); Invalidate(); if (Trigger) { GViewI *n=GetNotify()?GetNotify():GetParent(); if (n) n->OnNotify(this, 0); } } } void OnMouseEnter(GMouse &m) { if (IsCapturing()) { Down = true; Invalidate(); } } void OnMouseExit(GMouse &m) { if (IsCapturing()) { Down = false; Invalidate(); } } bool OnKey(GKey &k) { if (k.c16 == ' ' || k.c16 == VK_RETURN) { if (Enabled() && Down ^ k.Down()) { Down = k.Down(); Invalidate(); if (!Down) { GViewI *n=GetNotify()?GetNotify():GetParent(); if (n) n->OnNotify(this, 0); } } return true; } return false; } bool OnLayout(GViewLayoutInfo &Inf) { Inf.Width.Min = Inf.Width.Max = Icons->TileX() + 4; Inf.Width.Max += 4; Inf.Height.Min = Inf.Height.Max = Icons->TileY() + 4; Inf.Height.Max += 4; return true; } }; class GFolderList : public LList, public GFolderView { GString FilterKey; public: GFolderList(GFileSelectDlg *dlg, int Id, int x, int y, int cx, int cy); ~GFolderList() { } void OnFolder(); bool OnKey(GKey &k); void SetFilterKey(GString s) { FilterKey = s; OnFolder(); } }; #define IDC_STATIC -1 #define IDD_FILE_SELECT 1000 #define IDC_PATH 1002 #define IDC_DROP 1003 #define IDC_BACK 1004 #define IDC_UP 1005 #define IDC_NEW 1006 #define IDC_VIEW 1007 #define IDC_FILE 1010 #define IDC_TYPE 1011 #define IDC_SHOWHIDDEN 1012 #define IDC_SUB_TBL 1013 #define IDC_BOOKMARKS 1014 #define IDC_FILTER 1015 #define IDC_FILTER_CLEAR 1016 #if 1 #define USE_FOLDER_CTRL 1 enum FolderCtrlMessages { M_DELETE_EDIT = M_USER + 100, M_NOTIFY_VALUE_CHANGED, }; class FolderCtrl : public GView { struct Part { GAutoPtr ds; GRect Arrow; GRect Text; }; GEdit *e; GArray p; Part *Over; int Cursor; Part *HitPart(int x, int y, int *Sub = NULL) { for (unsigned i=0; iGetHeight() + 4; Inf.Height.Max = Inf.Height.Min; } return true; } GString NameAt(int Level) { GString n; #ifndef WINDOWS n += "/"; #endif for (unsigned i=0; i<=Level && iTransparent(false); GDisplayString Arrow(f, ">"); for (unsigned i=0; iArrow.ZOff(Arrow.X()+1, c.Y()-1); n->Arrow.Offset(c.x1, c.y1); f->Colour(Rgb24(192,192,192), Bk); Arrow.DrawCenter(pDC, &n->Arrow); c.x1 = n->Arrow.x2 + 1; if (n->ds) { // Layout and draw text n->Text.ZOff(n->ds->X() + 4, c.Y()-1); n->Text.Offset(c.x1, c.y1); f->Colour(Fore, Bk); n->ds->DrawCenter(pDC, &n->Text); c.x1 = n->Text.x2 + 1; } } pDC->Colour(LC_WORKSPACE, 24); pDC->Rectangle(&c); } void OnMouseClick(GMouse &m) { if (m.IsContextMenu()) { } else if (m.Left()) { if (m.Down()) { if (p.PtrCheck(Over)) { // Over a path node... Cursor = Over - p.AddressOf(0); Part &o = p[Cursor]; Invalidate(); SendNotify(GNotifyValueChanged); if (o.Arrow.Overlap(m.x, m.y)) { // Show sub-menu at this level ShowMenu(Cursor); } } else { // In empty space if (!e) { GRect c = GetClient(); e = new GEdit(GetId()+1, c.x1, c.y1, c.X()-1, c.Y()-1); if (e) { e->Attach(this); GString s = Name(); e->Name(s); e->SetCaret(s.Length()); e->Focus(true); } } } } } } void OnMouseMove(GMouse &m) { Part *o = Over; Over = HitPart(m.x, m.y); if (o != Over) Invalidate(); } void OnMouseExit(GMouse &m) { if (Over) { Over = NULL; Invalidate(); } } int OnNotify(GViewI *c, int f) { if (e != NULL && c->GetId() == e->GetId()) { if (f == VK_RETURN) { GString s = e->Name(); Name(s); PostEvent(M_DELETE_EDIT); PostEvent(M_NOTIFY_VALUE_CHANGED); } } return 0; } GMessage::Result OnEvent(GMessage *m) { switch (m->Msg()) { case M_DELETE_EDIT: { DeleteObj(e); break; } case M_NOTIFY_VALUE_CHANGED: { SendNotify(GNotifyValueChanged); break; } } return GView::OnEvent(m); } virtual bool ShowMenu(int Level) { if (Level <= 0) return false; GString dir = NameAt(Level-1); GSubMenu s; GDirectory d; GString::Array Opts; for (int b = d.First(dir); b; b = d.Next()) { if (d.IsDir()) { Opts.New() = d.GetName(); s.AppendItem(d.GetName(), Opts.Length()); } } Part &i = p[Level]; GdcPt2 pt(i.Arrow.x1, i.Arrow.y2+1); PointToScreen(pt); int Cmd = s.Float(this, pt.x, pt.y, true); if (Cmd) { GString np; np = dir + DIR_STR + Opts[Cmd-1]; Name(np); PostEvent(M_NOTIFY_VALUE_CHANGED); } else return false; return true; } }; #else #define USE_FOLDER_CTRL 0 #endif class GFileSelectDlg : public GDialog { GRect OldPos; GRect MinSize; GArray Links; GArray Hidden; public: GFileSelectPrivate *d; GTableLayout *Tbl; GBox *Sub; GTree *Bookmarks; GTextLabel *Ctrl1; #if USE_FOLDER_CTRL FolderCtrl *Ctrl2; #else GEdit *Ctrl2; #endif GFolderDrop *Ctrl3; GIconButton *BackBtn; GIconButton *UpBtn; GIconButton *NewDirBtn; GFolderList *FileLst; GTextLabel *Ctrl8; GTextLabel *Ctrl9; GEdit *FileNameEdit; GCombo *FileTypeCbo; GButton *SaveBtn; GButton *CancelBtn; GCheckBox *ShowHidden; GEdit *FilterEdit; GFileSelectDlg(GFileSelectPrivate *Select); ~GFileSelectDlg(); int OnNotify(GViewI *Ctrl, int Flags); void OnUpFolder(); void SetFolder(char *f); void OnFolder(); void OnFile(char *f); void OnFilter(const char *Key); bool OnViewKey(GView *v, GKey &k) { if (k.vkey == VK_UP && k.Alt()) { if (k.Down()) { UpBtn->SendNotify(); } return true; } return false; } void Add(GTreeItem *i, GVolume *v) { if (!i || !v) return; i->SetText(v->Name(), 0); i->SetText(v->Path(), 1); for (unsigned n=0; nPath() && !_stricmp(v->Path(), Links[n])) { Links.DeleteAt(n--); break; } } for (GVolume *cv = v->First(); cv; cv = cv->Next()) { GTreeItem *ci = new GTreeItem; if (ci) { i->Insert(ci); i->Expanded(true); Add(ci, cv); } } } }; GFileSelectDlg::GFileSelectDlg(GFileSelectPrivate *select) { SaveBtn = 0; BackBtn = 0; CancelBtn = 0; ShowHidden = 0; FileTypeCbo = 0; FileNameEdit = 0; Ctrl8 = 0; Ctrl9 = 0; FileLst = 0; Ctrl3 = 0; BackBtn = 0; UpBtn = 0; NewDirBtn = 0; Ctrl2 = 0; Sub = NULL; Bookmarks = NULL; FilterEdit = NULL; d = select; SetParent(d->Parent); MinSize.ZOff(450, 300); OldPos.Set(0, 0, 475, 350 + LgiApp->GetMetric(LGI_MET_DECOR_Y) ); SetPos(OldPos); int x = 0, y = 0; AddView(Tbl = new GTableLayout); // Top Row GLayoutCell *c = Tbl->GetCell(x++, y); c->Add(Ctrl1 = new GTextLabel(IDC_STATIC, 0, 0, -1, -1, "Look in:")); c->VerticalAlign(GCss::Len(GCss::VerticalMiddle)); c = Tbl->GetCell(x++, y); #if USE_FOLDER_CTRL c->Add(Ctrl2 = new FolderCtrl(IDC_PATH)); #else c->Add(Ctrl2 = new GEdit(IDC_PATH, 0, 0, 245, 21, "")); #endif c = Tbl->GetCell(x++, y); c->Add(Ctrl3 = new GFolderDrop(this, IDC_DROP, 336, 7, 16, 21)); c = Tbl->GetCell(x++, y); c->Add(BackBtn = new GIconButton(IDC_BACK, 378, 7, 27, 21, d->Icons, FSI_BACK)); c = Tbl->GetCell(x++, y); c->Add(UpBtn = new GIconButton(IDC_UP, 406, 7, 27, 21, d->Icons, FSI_UPDIR)); c = Tbl->GetCell(x++, y); c->Add(NewDirBtn = new GIconButton(IDC_NEW, 434, 7, 27, 21, d->Icons, FSI_NEWDIR)); // Folders/items row x = 0; y++; c = Tbl->GetCell(x, y, true, 6, 1); c->Add(Sub = new GBox(IDC_SUB_TBL)); Sub->AddView(Bookmarks = new GTree(IDC_BOOKMARKS, 0, 0, -1, -1)); Bookmarks->GetCss(true)->Width(GCss::Len(GCss::LenPx, 150.0)); GTableLayout *t; Sub->AddView(t = new GTableLayout(11)); // Filter / search row c = t->GetCell(0, 0); c->Add(new GCheckBox(IDC_FILTER_CLEAR, 0, 0, -1, -1, "Filter items:")); c->VerticalAlign(GCss::Len(GCss::VerticalMiddle)); c = t->GetCell(1, 0); c->Add(FilterEdit = new GEdit(IDC_FILTER, 0, 0, 60, 20)); c = t->GetCell(0, 1, true, 2); c->Add(FileLst = new GFolderList(this, IDC_VIEW, 14, 35, 448, 226)); // File name row x = 0; y++; c = Tbl->GetCell(x++, y); c->Add(Ctrl8 = new GTextLabel(IDC_STATIC, 14, 275, -1, -1, "File name:")); c = Tbl->GetCell(x, y, true, 2); x += 2; c->Add(FileNameEdit = new GEdit(IDC_FILE, 100, 268, 266, 21, "")); c = Tbl->GetCell(x, y, true, 3); c->Add(SaveBtn = new GButton(IDOK, 392, 268, 70, 21, "Ok")); // 4th row x = 0; y++; c = Tbl->GetCell(x++, y); c->Add(Ctrl9 = new GTextLabel(IDC_STATIC, 14, 303, -1, -1, "Files of type:")); c = Tbl->GetCell(x, y, true, 2); x += 2; c->Add(FileTypeCbo = new GCombo(IDC_TYPE, 100, 296, 266, 21, "")); c = Tbl->GetCell(x++, y, true, 3); c->Add(CancelBtn = new GButton(IDCANCEL, 392, 296, 70, 21, "Cancel")); // 5th row x = 0; y++; c = Tbl->GetCell(x++, y, true, 6); c->Add(ShowHidden = new GCheckBox(IDC_SHOWHIDDEN, 14, 326, -1, -1, "Show hidden files.")); // Init if (BackBtn) BackBtn->Enabled(false); if (SaveBtn) SaveBtn->Enabled(false); if (FileLst) FileLst->MultiSelect(d->MultiSelect); if (ShowHidden) ShowHidden->Value(d->InitShowHiddenFiles); // Load types if (!d->Types.First()) { GFileType *t = new GFileType; if (t) { t->Description("All Files"); t->Extension(LGI_ALL_FILES); d->Types.Insert(t); } } for (GFileType *t=d->Types.First(); t; t=d->Types.Next()) { char s[256]; sprintf(s, "%s (%s)", t->Description(), t->Extension()); if (FileTypeCbo) FileTypeCbo->Insert(s); } d->CurrentType = 0; // File + Path char *File = d->Files.First(); if (File) { char *Dir = strrchr(File, DIR_CHAR); if (Dir) { OnFile(Dir + 1); } else { OnFile(File); } } if (d->InitPath) { SetFolder(d->InitPath); } else { char Str[256]; LgiGetExePath(Str, sizeof(Str)); SetFolder(Str); } OnFolder(); // Size/layout SetPos(d->InitSize); MoveToCenter(); RegisterHook(this, GKeyEvents); FileLst->Focus(true); LgiGetUsersLinks(Links); GTreeItem *RootItem = new GTreeItem; if (RootItem) { Bookmarks->Insert(RootItem); Add(RootItem, FileDev->GetRootVolume()); } for (unsigned n=0; nSetText(leaf?leaf+1:p, 0); ci->SetText(p, 1); RootItem->Insert(ci); } } } GFileSelectDlg::~GFileSelectDlg() { UnregisterHook(this); d->InitShowHiddenFiles = ShowHidden ? ShowHidden->Value() : false; d->InitSize = GetPos(); char *CurPath = GetCtrlName(IDC_PATH); if (ValidStr(CurPath)) { DeleteArray(d->InitPath); d->InitPath = NewStr(CurPath); } } void GFileSelectDlg::OnFile(char *f) { if (d->Type != TypeOpenFolder) { FileNameEdit->Name(f ? f : (char*)""); SaveBtn->Enabled(ValidStr(f)); } } void GFileSelectDlg::SetFolder(char *f) { char *CurPath = GetCtrlName(IDC_PATH); if (CurPath) { d->History.Insert(NewStr(CurPath)); SetCtrlEnabled(IDC_BACK, true); } SetCtrlName(IDC_PATH, f); } void GFileSelectDlg::OnFolder() { if (Ctrl3) Ctrl3->OnFolder(); if (FileLst) FileLst->OnFolder(); char *CurPath = GetCtrlName(IDC_PATH); if (CurPath && UpBtn) { UpBtn->Enabled(strlen(CurPath)>3); } } void GFileSelectDlg::OnUpFolder() { char *Cur = GetCtrlName(IDC_PATH); if (Cur) { char Dir[MAX_PATH]; strcpy(Dir, Cur); if (strlen(Dir) > 3) { LgiTrimDir(Dir); if (!strchr(Dir, DIR_CHAR)) strcat(Dir, DIR_STR); SetFolder(Dir); OnFolder(); } } } void GFileSelectDlg::OnFilter(const char *Key) { if (FileLst) FileLst->SetFilterKey(Key); } int GFileSelectDlg::OnNotify(GViewI *Ctrl, int Flags) { switch (Ctrl->GetId()) { case IDC_BOOKMARKS: { if (Flags == GNotifyItem_Select && Bookmarks) { GTreeItem *s = Bookmarks->Selection(); if (s) { char *p = s->GetText(1); if (DirExists(p)) { SetCtrlName(IDC_PATH, p); OnFolder(); } } } break; } case IDC_PATH: { // if (Flags == VK_RETURN) if (Flags == GNotifyValueChanged) { // Skip the IDOK message generated by the default button // d->EatClose = true; // printf("%s:%i - eat close true\n", _FL); OnFolder(); } break; } case IDC_VIEW: { if (FileLst) { /* These functions are handled by the list control's OnKey implementation if (Flags == GLIST_NOTIFY_RETURN) { List s; if (FileLst->GetSelection(s)) { GFolderItem *i = dynamic_cast(s.First()); if (i) { i->OnActivate(); } } } else if (Flags == GLIST_NOTIFY_BACKSPACE) { OnUpFolder(); } */ } break; } case IDC_FILE: { char *f = Ctrl->Name(); if (!f) break; if (Flags == VK_RETURN) { // allow user to insert new type by typing the pattern into the file name edit box and // hitting enter if (strchr(f, '?') || strchr(f, '*')) { // it's a mask, push the new type on the the type stack and // refilter the content int TypeIndex = -1; int n = 0; for (GFileType *t = d->Types.First(); t; t = d->Types.Next(), n++) { if (t->Extension() && stricmp(t->Extension(), f) == 0) { TypeIndex = n; break; } } // insert the new type if not already there if (TypeIndex < 0) { GFileType *n = new GFileType; if (n) { n->Description(f); n->Extension(f); TypeIndex = d->Types.Length(); d->Types.Insert(n); FileTypeCbo->Insert(f); } } // select the new type if (TypeIndex >= 0) { FileTypeCbo->Value(d->CurrentType = TypeIndex); } // clear the edit box Ctrl->Name(""); // Update and don't do normal save btn processing. OnFolder(); // Skip the IDOK message generated by the default button d->EatClose = true; printf("%s:%i - eat close true\n", _FL); break; } if (DirExists(f)) { // Switch to the folder... SetCtrlName(IDC_PATH, f); OnFolder(); Ctrl->Name(NULL); d->EatClose = true; } else if (FileExists(f)) { // Select the file... d->Files.Insert(NewStr(f)); EndModal(IDOK); break; } } bool HasFile = ValidStr(f); bool BtnEnabled = SaveBtn->Enabled(); if (HasFile ^ BtnEnabled) { SaveBtn->Enabled(HasFile); } break; } case IDC_BACK: { char *Dir = d->History.Last(); if (Dir) { d->History.Delete(Dir); SetCtrlName(IDC_PATH, Dir); OnFolder(); DeleteArray(Dir); if (!d->History.First()) { SetCtrlEnabled(IDC_BACK, false); } } break; } case IDC_SHOWHIDDEN: { FileLst->OnFolder(); break; } case IDC_TYPE: { d->CurrentType = FileTypeCbo->Value(); FileLst->OnFolder(); if (d->Type == TypeSaveFile) { // change extension of current file GFileType *Type = d->Types.ItemAt(d->CurrentType); char *File = FileNameEdit->Name(); if (Type && File) { char *Ext = strchr(File, '.'); if (Ext) { char *DefExt = Type->DefaultExtension(); if (DefExt) { Ext++; char s[256]; ZeroObj(s); memcpy(s, File, (int)Ext-(int)File); strcat(s, DefExt); OnFile(s); DeleteArray(DefExt); } } } } break; } case IDC_UP: { OnUpFolder(); break; } case IDC_FILTER: { const char *n = Ctrl->Name(); SetCtrlValue(IDC_FILTER_CLEAR, ValidStr(n)); OnFilter(n); break; } case IDC_FILTER_CLEAR: { if (!Ctrl->Value()) { SetCtrlName(IDC_FILTER, NULL); OnFilter(NULL); } break; } case IDC_NEW: { GInput Dlg(this, "", "Create new folder:", "New Folder"); if (Dlg.DoModal()) { char New[256]; strcpy(New, GetCtrlName(IDC_PATH)); if (New[strlen(New)-1] != DIR_CHAR) strcat(New, DIR_STR); strcat(New, Dlg.GetStr()); FileDev->CreateFolder(New); OnFolder(); } break; } case IDOK: { if (d->EatClose) { printf("%s:%i - SKIPPING eat close false\n", _FL); d->EatClose = false; break; } char *Path = GetCtrlName(IDC_PATH); char *File = GetCtrlName(IDC_FILE); if (Path) { char f[MAX_PATH]; d->Files.DeleteArrays(); if (d->Type == TypeOpenFolder) { d->Files.Insert(NewStr(Path)); } else { List Sel; if (d->Type != TypeSaveFile && FileLst && FileLst->GetSelection(Sel) && Sel.Length() > 1) { for (LListItem *i=Sel.First(); i; i=Sel.Next()) { LgiMakePath(f, sizeof(f), Path, i->GetText(0)); d->Files.Insert(NewStr(f)); } } else if (ValidStr(File)) { if (strchr(File, DIR_CHAR)) strcpy_s(f, sizeof(f), File); else LgiMakePath(f, sizeof(f), Path, File); d->Files.Insert(NewStr(f)); } } } // fall thru } case IDCANCEL: { EndModal(Ctrl->GetId()); break; } } return 0; } ////////////////////////////////////////////////////////////////////////// class GFileSystemItem : public GTreeItem { class GFileSystemPopup *Popup; char *Path; public: GFileSystemItem(GFileSystemPopup *popup, GVolume *vol, char *path = 0); char *GetPath() { return Path; } void OnPath(char *p); void OnMouseClick(GMouse &m); bool OnKey(GKey &k); }; #define IDC_TREE 100 class GFileSystemPopup : public GPopup { friend class GFileSystemItem; GFileSelectDlg *Dlg; GTree *Tree; GFileSystemItem *Root; public: GFileSystemPopup(GView *owner, GFileSelectDlg *dlg, int x) : GPopup(owner) { Dlg = dlg; GRect r(0, 0, x, 150); SetPos(r); Children.Insert(Tree = new GTree(IDC_TREE, 1, 1, X()-3, Y()-3)); if (Tree) { Tree->Sunken(false); GVolume *v = FileDev->GetRootVolume(); if (v) { Tree->SetImageList(Dlg->d->Icons, false); Tree->Insert(Root = new GFileSystemItem(this, v)); } } } ~GFileSystemPopup() { } void Visible(bool i) { if (i && Root) { Root->OnPath(Dlg->GetCtrlName(IDC_PATH)); } GPopup::Visible(i); } void OnPaint(GSurface *pDC) { // Draw border GRect c = GetClient(); c.Offset(-c.x1, -c.y1); pDC->Colour(LC_BLACK, 24); pDC->Box(&c); c.Size(1, 1); } void OnActivate(GFileSystemItem *i) { if (i) { Dlg->SetFolder(i->GetPath()); Dlg->OnFolder(); Visible(false); } } }; GFileSystemItem::GFileSystemItem(GFileSystemPopup *popup, GVolume *Vol, char *path) { Popup = popup; Expanded(true); if (Vol) { Path = NewStr(Vol->Path()); SetText(Vol->Name()); switch (Vol->Type()) { case VT_3_5FLOPPY: case VT_5_25FLOPPY: case VT_REMOVABLE: SetImage(FSI_FLOPPY); break; case VT_HARDDISK: case VT_RAMDISK: SetImage(FSI_HARDDISK); break; case VT_CDROM: SetImage(FSI_CDROM); break; case VT_NETWORK_SHARE: SetImage(FSI_NETWORK); break; case VT_DESKTOP: SetImage(FSI_DESKTOP); break; default: SetImage(FSI_DIRECTORY); break; } for (GVolume *v=Vol->First(); v; v=Vol->Next()) { Insert(new GFileSystemItem(Popup, v)); } } else { Path = NewStr(path); SetText(strrchr(Path, DIR_CHAR)+1); SetImage(FSI_DIRECTORY); } } void GFileSystemItem::OnPath(char *p) { switch (GetImage()) { case FSI_DESKTOP: { if (p && Path && stricmp(Path, p) == 0) { Select(true); p = 0; } break; } case FSI_DIRECTORY: { return; } default: { GTreeItem *Old = Items.First(); if (Old) { Old->Remove(); DeleteObj(Old); } break; } } if (p) { int PathLen = strlen(Path); if (Path && strnicmp(Path, p, PathLen) == 0 && (p[PathLen] == DIR_CHAR || p[PathLen] == 0) #ifdef LINUX && strcmp(Path, "/") != 0 #endif ) { GTreeItem *Item = this; if (GetImage() != FSI_DESKTOP && strlen(p) > 3) { char *Start = p + strlen(Path); if (Start) { char s[256]; strcpy(s, Path); GToken T(Start, DIR_STR); for (int i=0; iInsert(New); Item = New; } } } } if (Item) { Item->Select(true); } } } for (GFileSystemItem *i=dynamic_cast(Items.First()); i; i=dynamic_cast(Items.Next())) { i->OnPath(p); } } void GFileSystemItem::OnMouseClick(GMouse &m) { if (m.Left() && m.Down()) { Popup->OnActivate(this); } } bool GFileSystemItem::OnKey(GKey &k) { if ((k.c16 == ' ' || k.c16 == VK_RETURN)) { if (k.Down() && k.IsChar) { Popup->OnActivate(this); } return true; } return false; } GFolderDrop::GFolderDrop(GFileSelectDlg *dlg, int Id, int x, int y, int cx, int cy) : GDropDown(Id, x, y, cx, cy, 0), GFolderView(dlg) { SetPopup(new GFileSystemPopup(this, dlg, cx + (dlg->Ctrl2 ? dlg->Ctrl2->X() : 0) )); } void GFolderDrop::OnFolder() { } ////////////////////////////////////////////////////////////////////////// #define IDM_OPEN 1000 #define IDM_CUT 1001 #define IDM_COPY 1002 #define IDM_RENAME 1003 #define IDM_PROPERTIES 1004 #define IDM_CREATE_SHORTCUT 1005 #define IDM_DELETE 1006 GFolderItem::GFolderItem(GFileSelectDlg *dlg, char *FullPath, GDirectory *Dir) { Dlg = dlg; Path = NewStr(FullPath); File = strrchr(Path, DIR_CHAR); if (File) File++; IsDir = Dir->IsDir(); } GFolderItem::~GFolderItem() { DeleteArray(Path); } char *GFolderItem::GetText(int i) { return File; } int GFolderItem::GetImage(int Flags) { return IsDir ? 1 : 0; } void GFolderItem::OnSelect() { if (!IsDir && File) { Dlg->OnFile(Select() ? File : 0); } } void GFolderItem::OnDelete(bool Ask) { if (!Ask || LgiMsg(Parent, "Do you want to delete '%s'?", ModuleName, MB_YESNO, Path) == IDYES) { bool Status = false; if (IsDir) { Status = FileDev->RemoveFolder(Path, true); } else { Status = FileDev->Delete(Path); } if (Status) { Parent->Remove(this); delete this; } } } void GFolderItem::OnRename() { GInput Inp(Dlg, File, "New name:", Dlg->Name()); if (Inp.DoModal()) { char Old[256]; strcpy(Old, Path); char New[256]; File[0] = 0; LgiMakePath(New, sizeof(New), Path, Inp.GetStr()); if (FileDev->Move(Old, New)) { DeleteArray(Path); Path = NewStr(New); File = strrchr(Path, DIR_CHAR); if (File) File++; Update(); } else { LgiMsg(Dlg, "Renaming '%s' failed.", Dlg->Name(), MB_OK); } } } void GFolderItem::OnActivate() { if (File) { if (IsDir) { char Dir[256]; strcpy(Dir, Dlg->GetCtrlName(IDC_PATH)); if (Dir[strlen(Dir)-1] != DIR_CHAR) strcat(Dir, DIR_STR); strcat(Dir, File); Dlg->SetFolder(Dir); Dlg->OnFolder(); } else // Is file { Dlg->OnNotify(Dlg->SaveBtn, 0); } } } void GFolderItem::OnMouseClick(GMouse &m) { if (m.Down()) { if (m.Left()) { if (m.Double()) { OnActivate(); } } else if (m.Right()) { GSubMenu *RClick = new GSubMenu; if (RClick) { RClick->AppendItem("Select", IDM_OPEN, true); RClick->AppendSeparator(); RClick->AppendItem("Cut", IDM_CUT, false); RClick->AppendItem("Copy", IDM_COPY, false); RClick->AppendSeparator(); RClick->AppendItem("Create Shortcut", IDM_CREATE_SHORTCUT, false); RClick->AppendItem("Delete", IDM_DELETE, true); RClick->AppendItem("Rename", IDM_RENAME, true); RClick->AppendSeparator(); RClick->AppendItem("Properties", IDM_PROPERTIES, false); if (Parent->GetMouse(m, true)) { switch (RClick->Float(Parent, m.x, m.y)) { case IDM_OPEN: { break; } case IDM_DELETE: { OnDelete(); break; } case IDM_RENAME: { OnRename(); break; } } } DeleteObj(RClick); } } } } int GFolderItemCompare(LListItem *A, LListItem *B, NativeInt Data) { GFolderItem *a = dynamic_cast(A); GFolderItem *b = dynamic_cast(B); if (a && b) { if (a->IsDir ^ b->IsDir) { if (a->IsDir) return -1; else return 1; } else if (a->File && b->File) { return stricmp(a->File, b->File); } } return 0; } GFolderList::GFolderList(GFileSelectDlg *dlg, int Id, int x, int y, int cx, int cy) : LList(Id, x, y, cx, cy), GFolderView(dlg) { SetImageList(Dlg->d->Icons, false); ShowColumnHeader(false); AddColumn("Name", cx-20); SetMode(LListColumns); } bool GFolderList::OnKey(GKey &k) { bool Status = LList::OnKey(k); switch (k.vkey) { case VK_BACKSPACE: { if (k.Down() && GetWindow()) { // Go up a directory GViewI *v = GetWindow()->FindControl(IDC_UP); if (v) { GetWindow()->OnNotify(v, 0); } } Status = true; break; } case VK_RETURN: #ifdef VK_KP_ENTER case VK_KP_ENTER: #endif { if (k.Down() && GetWindow()) { GFolderItem *Sel = dynamic_cast(GetSelected()); if (Sel) { if (Sel->IsDir) { char *Cur = GetWindow()->GetCtrlName(IDC_PATH); if (Cur) { char Path[256]; LgiMakePath(Path, sizeof(Path), Cur, Sel->GetText(0)); if (DirExists(Path)) { GetWindow()->SetCtrlName(IDC_PATH, Path); Dlg->OnFolder(); } } } else { GViewI *Ok = GetWindow()->FindControl(IDOK); if (Ok) { GetWindow()->SetCtrlName(IDC_FILE, Sel->GetText(0)); GetWindow()->OnNotify(Ok, 0); } } } } Status = true; break; } case VK_DELETE: { if (k.Down() && !k.IsChar && GetWindow()) { List Sel; if (GetSelection(Sel)) { GStringPipe Msg; Msg.Push("Do you want to delete:\n\n"); List Delete; for (LListItem *i=Sel.First(); i; i=Sel.Next()) { GFolderItem *s = dynamic_cast(i); if (s) { Delete.Insert(s); Msg.Push("\t"); Msg.Push(s->GetText(0)); Msg.Push("\n"); } } char *Mem = Msg.NewStr(); if (Mem) { if (LgiMsg(this, Mem, ModuleName, MB_YESNO) == IDYES) { for (GFolderItem *d=Delete.First(); d; d=Delete.Next()) { d->OnDelete(false); } } DeleteArray(Mem); } } } Status = true; break; } } // LgiTrace("%s:%i GFolderList::OnKey, key=%i down=%i status=%i\n", _FL, k.vkey, k.Down(), Status); return Status; } void GFolderList::OnFolder() { Empty(); GDirectory Dir; List New; // Get current type GFileType *Type = Dlg->d->Types.ItemAt(Dlg->d->CurrentType); List Ext; if (Type) { GToken T(Type->Extension(), ";"); for (int i=0; iCtrl2) return; bool ShowHiddenFiles = Dlg->ShowHidden ? Dlg->ShowHidden->Value() : false; for (bool Found = Dir.First(Dlg->Ctrl2->Name()); Found; Found = Dir.Next()) { char Name[MAX_PATH]; Dir.Path(Name, sizeof(Name)); bool Match = true; if (!ShowHiddenFiles && Dir.IsHidden()) { Match = false; } else if (!Dir.IsDir() && Ext.Length() > 0) { Match = false; for (char *e=Ext.First(); e && !Match; e=Ext.Next()) { bool m = MatchStr(e, Name); if (m) Match = true; } } if (FilterKey && Match) Match = stristr(Dir.GetName(), FilterKey) != NULL; if (Match) New.Insert(new GFolderItem(Dlg, Name, &Dir)); } // Sort items... New.Sort(GFolderItemCompare); // Display items... Insert(New); } ////////////////////////////////////////////////////////////////////////// GFileSelect::GFileSelect() { d = new GFileSelectPrivate(this); } GFileSelect::~GFileSelect() { DeleteObj(d); } void GFileSelect::ShowReadOnly(bool b) { d->ShowReadOnly = b;; } bool GFileSelect::ReadOnly() { return d->ReadOnly; } char *GFileSelect::Name() { return d->Files.First(); } bool GFileSelect::Name(const char *n) { d->Files.DeleteArrays(); if (n) { d->Files.Insert(NewStr(n)); } return true; } char *GFileSelect::operator [](size_t i) { return d->Files.ItemAt(i); } size_t GFileSelect::Length() { return d->Files.Length(); } size_t GFileSelect::Types() { return d->Types.Length(); } void GFileSelect::ClearTypes() { d->Types.DeleteObjects(); } GFileType *GFileSelect::TypeAt(ssize_t n) { return d->Types.ItemAt(n); } bool GFileSelect::Type(const char *Description, const char *Extension, int Data) { GFileType *Type = new GFileType; if (Type) { Type->Description(Description); Type->Extension(Extension); d->Types.Insert(Type); } return Type != 0; } ssize_t GFileSelect::SelectedType() { return d->CurrentType; } GViewI *GFileSelect::Parent() { return d->Parent; } void GFileSelect::Parent(GViewI *Window) { d->Parent = dynamic_cast(Window); } bool GFileSelect::MultiSelect() { return d->MultiSelect; } void GFileSelect::MultiSelect(bool Multi) { d->MultiSelect = Multi; } #define CharPropImpl(Func, Var) \ char *GFileSelect::Func() \ { \ return Var; \ } \ void GFileSelect::Func(const char *i) \ { \ DeleteArray(Var); \ if (i) \ { \ Var = NewStr(i); \ } \ } CharPropImpl(InitialDir, d->InitPath); CharPropImpl(Title, d->Title); CharPropImpl(DefaultExtension, d->DefExt); bool GFileSelect::Open() { GFileSelectDlg Dlg(d); d->Type = TypeOpenFile; Dlg.Name("Open"); if (Dlg.SaveBtn) Dlg.SaveBtn->Name("Open"); return Dlg.DoModal() == IDOK; } bool GFileSelect::OpenFolder() { GFileSelectDlg Dlg(d); d->Type = TypeOpenFolder; Dlg.SaveBtn->Enabled(true); Dlg.FileNameEdit->Enabled(false); Dlg.Name("Open Folder"); Dlg.SaveBtn->Name("Open"); return Dlg.DoModal() == IDOK; } bool GFileSelect::Save() { GFileSelectDlg Dlg(d); d->Type = TypeSaveFile; Dlg.Name("Save As"); Dlg.SaveBtn->Name("Save As"); return Dlg.DoModal() == IDOK; } /////////////////////////////////////////////////////////////////////////////////// #if defined(LINUX) #include "INet.h" #endif bool LgiGetUsersLinks(GArray &Links) { GString Folder = LGetSystemPath(LSP_USER_LINKS); if (!Folder) return false; #if defined(WINDOWS) GDirectory d; for (int b = d.First(Folder); b; b = d.Next()) { char *s = d.GetName(); if (s && stristr(s, ".lnk")) { char lnk[MAX_PATH]; if (d.Path(lnk, sizeof(lnk)) && ResolveShortcut(lnk, lnk, sizeof(lnk))) { Links.New() = lnk; } } } #elif defined(LINUX) char p[MAX_PATH]; if (!LgiMakePath(p, sizeof(p), Folder, "bookmarks")) { LgiTrace("%s:%i - Failed to make path '%s'\n", _FL, Folder.Get()); return false; } GAutoString Txt(ReadTextFile(p)); if (!Txt) { LgiTrace("%s:%i - failed to read '%s'\n", _FL, p); return false; } GString s = Txt.Get(); GString::Array a = s.Split("\n"); for (unsigned i=0; i #include "Lgi.h" #include "StoreCommon.h" /// \brief This class can limit the reading/writing to a specific sub section of a file /// Which should protect the application using the storage system from overwriting parts /// of the file is shouldn't have access to. The default region is the whole file. GSubFilePtr::GSubFilePtr(GSubFile *Parent, const char *file, int line) { File = Parent; SrcFile = NewStr(file); SrcLine = line; OurStatus = true; Pos = 0; SetSwap(Parent->GetSwap()); ClearSub(); } GSubFilePtr::~GSubFilePtr() { File->Detach(this); DeleteArray(SrcFile); } bool GSubFilePtr::SaveState() { ActualPos = File->GetPos(); ActualStatus = File->GetStatus(); ActualSwap = File->GetSwap(); File->SetSwap(GetSwap()); File->SetStatus(OurStatus); int64 p = File->SetPos(Start + Pos); if (p == Start + Pos) { return true; } else { printf("%s:%i SaveState failed Pos=" LPrintfInt64 " OurPos=" LPrintfInt64 "\n", _FL, Pos, Pos); } return false; } bool GSubFilePtr::RestoreState() { SetSwap(File->GetSwap()); OurStatus = File->GetStatus(); Pos = File->GetPos() - Start; File->SetStatus(ActualStatus); File->SetSwap(ActualSwap); return File->SetPos(ActualPos) == ActualPos; } bool GSubFilePtr::GetSub(int64 &start, int64 &len) { start = Start; len = Len; return Sub; } bool GSubFilePtr::SetSub(int64 start, int64 len) { Sub = true; Start = start; Len = len; Pos = 0; return true; } void GSubFilePtr::ClearSub() { Sub = false; Start = Len = 0; } int GSubFilePtr::Open(const char *Str, int Int) { LgiAssert(0); return 0; } bool GSubFilePtr::IsOpen() { return true; } int GSubFilePtr::Close() { LgiAssert(0); return 0; } int64 GSubFilePtr::GetSize() { int64 s = -1; if (Sub) { s = Len; } else { GSubFile::SubLock Lock = File->Lock(_FL); s = File->GetSize(); } return s; } int64 GSubFilePtr::SetSize(int64 Size) { LgiAssert(0); return -1; } int64 GSubFilePtr::GetPos() { return Pos; } int64 GSubFilePtr::SetPos(int64 pos) { if (pos < 0) { printf("%s:%i - Pos < 0???\n", __FILE__, __LINE__); } return Pos = pos; } int64 GSubFilePtr::Seek(int64 To, int Whence) { switch (Whence) { case SEEK_SET: SetPos(To); break; case SEEK_CUR: SetPos(GetPos() + To); break; case SEEK_END: SetPos(GetSize() + To); break; } return GetPos(); } GStreamI *GSubFilePtr::Clone() { LgiAssert(0); return 0; } bool GSubFilePtr::Eof() { bool Status = false; if (Sub) { Status = Pos < 0 || Pos >= Len; } else { GSubFile::SubLock Lock = File->Lock(_FL); Status = File->Eof(); } return Status; } bool GSubFilePtr::GetStatus() { return OurStatus; } void GSubFilePtr::SetStatus(bool s) { OurStatus = s; } ssize_t GSubFilePtr::Read(void *Buffer, ssize_t Size, int Flags) { int Status = 0; GSubFile::SubLock Lock = File->Lock(_FL); if (!Sub || (Pos >= 0 && Pos <= Len)) { if (SaveState()) { int64 Remaining = Len - Pos; - uint32 RdSize = (int) (Sub ? MIN(Remaining, Size) : Size); + uint32_t RdSize = (int) (Sub ? MIN(Remaining, Size) : Size); Status = File->Read(Buffer, RdSize, Flags); RestoreState(); } } else { LgiAssert(0); } return Status; } ssize_t GSubFilePtr::Write(const void *Buffer, ssize_t Size, int Flags) { int Status = 0; GSubFile::SubLock Lock = File->Lock(_FL); int64 End = Pos + Size; if (!Sub || (Pos >= 0 && End <= Len)) { if (SaveState()) { Status = File->Write(Buffer, Size, Flags); RestoreState(); } } else { LgiTrace("GSubFilePtr error, Pos=" LPrintfInt64 " Start=" LPrintfInt64 " End=" LPrintfInt64 " Len=" LPrintfInt64 "\n", Pos, Start, End, Len); } return Status; } ssize_t GSubFilePtr::ReadStr(char *Buf, ssize_t Size) { LgiAssert(0); return 0; } ssize_t GSubFilePtr::WriteStr(char *Buf, ssize_t Size) { LgiAssert(0); return 0; } /////////////////////////////////////////////////////////////////////// GSubFile::GSubFile(LMutex *lock, bool Buffering) { Lck = lock; #if GSUBFILE_NOBUFFERING Buffer = Buffering; Block = 0; Buf = 0; Shift = 0; Cur = -1; Pos = -1; Dirty = false; #endif } GSubFile::~GSubFile() { while (Ptrs.Length()) { GSubFilePtr *p = Ptrs[0]; if (p) { printf("%s:%i - GSubFilePtr not released.\n", p->SrcFile, p->SrcLine); DeleteObj(p); } else break; } #if GSUBFILE_NOBUFFERING DeleteArray(Buf); #endif } GSubFilePtr *GSubFile::Create(const char *file, int line) { GSubFilePtr *p = 0; p = new GSubFilePtr(this, file, line); if (p) { SubLock Lck = Lock(_FL); Ptrs[Ptrs.Length()] = p; } return p; } void GSubFile::Detach(GSubFilePtr *Ptr) { SubLock Lck = Lock(_FL); LgiAssert(Ptrs.HasItem(Ptr)); Ptrs.Delete(Ptr); } GSubFile::SubLock GSubFile::Lock(const char *file, int line) { return SubLock(new LMutex::Auto(Lck, file, line)); } #if GSUBFILE_NOBUFFERING int GSubFile::Open(char *Str, int Int) { int s = GFile::Open(Str, Int | (!Buffer ? O_NO_CACHE : 0)); if (s && !Buffer) { Block = GetBlockSize(); Shift = 1; while ((1 << Shift) < Block) Shift++; Buf = new uint8[Block]; Pos = 0; } return s; } int GSubFile::Read(void *OutBuf, int Size, int Flags) { int Status = 0; if (!Buffer && Buf) { uint8 *Out = (uint8*)OutBuf; int64 Blk = Pos >> Shift; int Mask = Block - 1; while (Size) { if (Blk != Cur) { SetBlock(Blk); } int Off = Pos & Mask; int Len = Block - Off; if (Len > Size) Len = Size; memcpy(Out, Buf + Off, Len); Pos += Len; Out += Len; Size -= Len; Status += Len; Blk++; } } else { Status = GFile::Read(OutBuf, Size, Flags); if (Status > 0) { Pos += Status; } } return Status; } int GSubFile::Write(const void *InBuf, int Size, int Flags) { int Status = 0; if (!Buffer && Buf) { uint8 *In = (uint8*)InBuf; int64 Blk = Pos >> Shift; int Mask = Block - 1; while (Size) { if (Blk != Cur) { SetBlock(Blk); } int Off = Pos & Mask; int Len = Block - Off; if (Len > Size) Len = Size; memcpy(Buf + Off, In, Len); Dirty = true; Pos += Len; In += Len; Size -= Len; Status += Len; Blk++; } } else { Status = GFile::Write(InBuf, Size, Flags); if (Status > 0) { Pos += Status; } } return Status; } int64 GSubFile::GetPos() { return Pos; } int64 GSubFile::SetPos(int64 pos) { return Pos = pos; } bool GSubFile::SetBlock(int64 Blk) { if (Blk != Cur) { int64 p, n; if (Dirty) { p = GFile::SetPos(Cur << Shift); n = GFile::Write(Buf, Block); if (n != Block) return false; Dirty = false; } Cur = Blk; p = GFile::SetPos(Cur << Shift); n = GFile::Read(Buf, Block); return n > 0; } return true; } #endif diff --git a/src/linux/General/GFile.cpp b/src/linux/General/GFile.cpp --- a/src/linux/General/GFile.cpp +++ b/src/linux/General/GFile.cpp @@ -1,1668 +1,1668 @@ /*hdr ** FILE: File.cpp ** AUTHOR: Matthew Allen ** DATE: 8/10/2000 ** DESCRIPTION: The new file subsystem ** ** Copyright (C) 2000, Matthew Allen ** fret@memecode.com */ /****************************** Includes **********************************/ #include #include #include #include #include #include #include #include #include #include "LgiDefs.h" #include "GFile.h" #include "GContainers.h" #include "GToken.h" #include "Gdc2.h" #include "LgiCommon.h" #include "GString.h" #include "LDateTime.h" /****************************** Defines ***********************************/ // #define FILEDEBUG #define FLOPPY_360K 0x0001 #define FLOPPY_720K 0x0002 #define FLOPPY_1_2M 0x0004 #define FLOPPY_1_4M 0x0008 #define FLOPPY_5_25 (FLOPPY_360K | FLOPPY_1_2M) #define FLOPPY_3_5 (FLOPPY_720K | FLOPPY_1_4M) /****************************** Globals ***********************************/ struct ErrorCodeType { char *Name; int Code; char *Desc; } ErrorCodes[] = { #if defined(WIN32) {"EPERM", 1, "Not owner"}, {"ENOENT", 2, "No such file"}, {"ESRCH", 3, "No such process"}, {"EINTR", 4, "Interrupted system"}, {"EIO", 5, "I/O error"}, {"ENXIO", 6, "No such device"}, {"E2BIG", 7, "Argument list too long"}, {"ENOEXEC", 8, "Exec format error"}, {"EBADF", 9, "Bad file number"}, {"ECHILD", 10, "No children"}, {"EAGAIN", 11, "No more processes"}, {"ENOMEM", 12, "Not enough core"}, {"EACCES", 13, "Permission denied"}, {"EFAULT", 14, "Bad address"}, {"ENOTBLK", 15, "Block device required"}, {"EBUSY", 16, "Mount device busy"}, {"EEXIST", 17, "File exists"}, {"EXDEV", 18, "Cross-device link"}, {"ENODEV", 19, "No such device"}, {"ENOTDIR", 20, "Not a directory"}, {"EISDIR", 21, "Is a directory"}, {"EINVAL", 22, "Invalid argument"}, {"ENFILE", 23, "File table overflow"}, {"EMFILE", 24, "Too many open file"}, {"ENOTTY", 25, "Not a typewriter"}, {"ETXTBSY", 26, "Text file busy"}, {"EFBIG", 27, "File too large"}, {"ENOSPC", 28, "No space left on"}, {"ESPIPE", 29, "Illegal seek"}, {"EROFS", 30, "Read-only file system"}, {"EMLINK", 31, "Too many links"}, {"EPIPE", 32, "Broken pipe"}, {"EWOULDBLOCK", 35, "Operation would block"}, {"EINPROGRESS", 36, "Operation now in progress"}, {"EALREADY", 37, "Operation already in progress"}, {"ENOTSOCK", 38, "Socket operation on"}, {"EDESTADDRREQ", 39, "Destination address required"}, {"EMSGSIZE", 40, "Message too long"}, {"EPROTOTYPE", 41, "Protocol wrong type"}, {"ENOPROTOOPT", 42, "Protocol not available"}, {"EPROTONOSUPPORT", 43, "Protocol not supported"}, {"ESOCKTNOSUPPORT", 44, "Socket type not supported"}, {"EOPNOTSUPP", 45, "Operation not supported"}, {"EPFNOSUPPORT", 46, "Protocol family not supported"}, {"EAFNOSUPPORT", 47, "Address family not supported"}, {"EADDRINUSE", 48, "Address already in use"}, {"EADDRNOTAVAIL", 49, "Can't assign requested address"}, {"ENETDOWN", 50, "Network is down"}, {"ENETUNREACH", 51, "Network is unreachable"}, {"ENETRESET", 52, "Network dropped connection"}, {"ECONNABORTED", 53, "Software caused connection"}, {"ECONNRESET", 54, "Connection reset by peer"}, {"ENOBUFS", 55, "No buffer space available"}, {"EISCONN", 56, "Socket is already connected"}, {"ENOTCONN", 57, "Socket is not connected" }, {"ESHUTDOWN", 58, "Can't send after shutdown"}, {"ETOOMANYREFS", 59, "Too many references"}, {"ETIMEDOUT", 60, "Connection timed out"}, {"ECONNREFUSED", 61, "Connection refused"}, {"ELOOP", 62, "Too many levels of nesting"}, {"ENAMETOOLONG", 63, "File name too long" }, {"EHOSTDOWN", 64, "Host is down"}, {"EHOSTUNREACH", 65, "No route to host"}, {"ENOTEMPTY", 66, "Directory not empty"}, {"EPROCLIM", 67, "Too many processes"}, {"EUSERS", 68, "Too many users"}, {"EDQUOT", 69, "Disc quota exceeded"}, {"ESTALE", 70, "Stale NFS file handle"}, {"EREMOTE", 71, "Too many levels of remote in the path"}, {"ENOSTR", 72, "Device is not a stream"}, {"ETIME", 73, "Timer expired"}, {"ENOSR", 74, "Out of streams resources"}, {"ENOMSG", 75, "No message"}, {"EBADMSG", 76, "Trying to read unreadable message"}, {"EIDRM", 77, "Identifier removed"}, {"EDEADLK", 78, "Deadlock condition"}, {"ENOLCK", 79, "No record locks available"}, {"ENONET", 80, "Machine is not on network"}, {"ERREMOTE", 81, "Object is remote"}, {"ENOLINK", 82, "The link has been severed"}, {"EADV", 83, "ADVERTISE error"}, {"ESRMNT", 84, "SRMOUNT error"}, {"ECOMM", 85, "Communication error"}, {"EPROTO", 86, "Protocol error"}, {"EMULTIHOP", 87, "Multihop attempted"}, {"EDOTDOT", 88, "Cross mount point"}, {"EREMCHG", 89, "Remote address change"}, #elif defined(LINUX) {"EPERM", EPERM, "Operation not permitted"}, {"ENOENT", ENOENT, "No such file or directory"}, {"ESRCH", ESRCH, "No such process"}, {"EINTR", EINTR, "Interrupted system call"}, {"EIO", EIO, "I/O error"}, {"ENXIO", ENXIO, "No such device or address"}, {"E2BIG", E2BIG, "Argument list too long"}, {"ENOEXEC", ENOEXEC, "Exec format error"}, {"EBADF", EBADF, "Bad file number"}, {"ECHILD", ECHILD, "No child processes"}, {"EAGAIN", EAGAIN, "Try again"}, {"ENOMEM", ENOMEM, "Out of memory"}, {"EACCES", EACCES, "Permission denied"}, {"EFAULT", EFAULT, "Bad address"}, {"ENOTBLK", ENOTBLK, "Block device required"}, {"EBUSY", EBUSY, "Device or resource busy"}, {"EEXIST", EEXIST, "File exists"}, {"EXDEV", EXDEV, "Cross-device link"}, {"ENODEV", ENODEV, "No such device"}, {"ENOTDIR", ENOTDIR, "Not a directory"}, {"EISDIR", EISDIR, "Is a directory"}, {"EINVAL", EINVAL, "Invalid argument"}, {"ENFILE", ENFILE, "File table overflow"}, {"EMFILE", EMFILE, "Too many open files"}, {"ENOTTY", ENOTTY, "Not a typewriter"}, {"ETXTBSY", ETXTBSY, "Text file busy"}, {"EFBIG", EFBIG, "File too large"}, {"ENOSPC", ENOSPC, "No space left on device"}, {"ESPIPE", ESPIPE, "Illegal seek"}, {"EROFS", EROFS, "Read-only file system"}, {"EMLINK", EMLINK, "Too many links"}, {"EPIPE", EPIPE, "Broken pipe"}, {"EDOM", EDOM, "Math argument out of domain of func"}, {"ERANGE", ERANGE, "Math result not representable"}, {"EDEADLK", EDEADLK, "Resource deadlock would occur"}, {"ENAMETOOLONG", ENAMETOOLONG, "File name too long"}, {"ENOLCK", ENOLCK, "No record locks available"}, {"ENOSYS", ENOSYS, "Function not implemented"}, {"ENOTEMPTY", ENOTEMPTY, "Directory not empty"}, {"ELOOP", ELOOP, "Too many symbolic links encountered"}, {"EWOULDBLOCK", EWOULDBLOCK, "Operation would block"}, {"ENOMSG", ENOMSG, "No message of desired type"}, {"EIDRM", EIDRM, "Identifier removed"}, {"ECHRNG", ECHRNG, "Channel number out of range"}, {"EL2NSYNC", EL2NSYNC, "Level 2 not synchronized"}, {"EL3HLT", EL3HLT, "Level 3 halted"}, {"EL3RST", EL3RST, "Level 3 reset"}, {"ELNRNG", ELNRNG, "Link number out of range"}, {"EUNATCH", EUNATCH, "Protocol driver not attached"}, {"ENOCSI", ENOCSI, "No CSI structure available"}, {"EL2HLT", EL2HLT, "Level 2 halted"}, {"EBADE", EBADE, "Invalid exchange"}, {"EBADR", EBADR, "Invalid request descriptor"}, {"EXFULL", EXFULL, "Exchange full"}, {"ENOANO", ENOANO, "No anode"}, {"EBADRQC", EBADRQC, "Invalid request code"}, {"EBADSLT", EBADSLT, "Invalid slot"}, {"EBFONT", EBFONT, "Bad font file format"}, {"ENOSTR", ENOSTR, "Device not a stream"}, {"ENODATA", ENODATA, "No data available"}, {"ETIME", ETIME, "Timer expired"}, {"ENOSR", ENOSR, "Out of streams resources"}, {"ENONET", ENONET, "Machine is not on the network"}, {"ENOPKG", ENOPKG, "Package not installed"}, {"EREMOTE", EREMOTE, "Object is remote"}, {"ENOLINK", ENOLINK, "Link has been severed"}, {"EADV", EADV, "Advertise error"}, {"ESRMNT", ESRMNT, "Srmount error"}, {"ECOMM", ECOMM, "Communication error on send"}, {"EPROTO", EPROTO, "Protocol error"}, {"EMULTIHOP", EMULTIHOP, "Multihop attempted"}, {"EDOTDOT", EDOTDOT, "RFS specific error"}, {"EBADMSG", EBADMSG, "Not a data message"}, {"EOVERFLOW", EOVERFLOW, "Value too large for defined data type"}, {"ENOTUNIQ", ENOTUNIQ, "Name not unique on network"}, {"EBADFD", EBADFD, "File descriptor in bad state"}, {"EREMCHG", EREMCHG, "Remote address changed"}, {"ELIBACC", ELIBACC, "Can not access a needed shared library"}, {"ELIBBAD", ELIBBAD, "Accessing a corrupted shared library"}, {"ELIBSCN", ELIBSCN, ".lib section in a.out corrupted"}, {"ELIBMAX", ELIBMAX, "Attempting to link in too many shared libraries"}, {"ELIBEXEC", ELIBEXEC, "Cannot exec a shared library directly"}, {"EILSEQ", EILSEQ, "Illegal byte sequence"}, {"ERESTART", ERESTART, "Interrupted system call should be restarted"}, {"ESTRPIPE", ESTRPIPE, "Streams pipe error"}, {"EUSERS", EUSERS, "Too many users"}, {"ENOTSOCK", ENOTSOCK, "Socket operation on non-socket"}, {"EDESTADDRREQ", EDESTADDRREQ, "Destination address required"}, {"EMSGSIZE", EMSGSIZE, "Message too long"}, {"EPROTOTYPE", EPROTOTYPE, "Protocol wrong type for socket"}, {"ENOPROTOOPT", ENOPROTOOPT, "Protocol not available"}, {"EPROTONOSUPPORT", EPROTONOSUPPORT, "Protocol not supported"}, {"ESOCKTNOSUPPORT", ESOCKTNOSUPPORT, "Socket type not supported"}, {"EOPNOTSUPP", EOPNOTSUPP, "Operation not supported on transport endpoint"}, {"EPFNOSUPPORT", EPFNOSUPPORT, "Protocol family not supported"}, {"EAFNOSUPPORT", EAFNOSUPPORT, "Address family not supported by protocol"}, {"EADDRINUSE", EADDRINUSE, "Address already in use"}, {"EADDRNOTAVAIL", EADDRNOTAVAIL, "Cannot assign requested address"}, {"ENETDOWN", ENETDOWN, "Network is down"}, {"ENETUNREACH", ENETUNREACH, "Network is unreachable"}, {"ENETRESET", ENETRESET, "Network dropped connection because of reset"}, {"ECONNABORTED", ECONNABORTED, "Software caused connection abort"}, {"ECONNRESET", ECONNRESET, "Connection reset by peer"}, {"ENOBUFS", ENOBUFS, "No buffer space available"}, {"EISCONN", EISCONN, "Transport endpoint is already connected"}, {"ENOTCONN", ENOTCONN, "Transport endpoint is not connected"}, {"ESHUTDOWN", ESHUTDOWN, "Cannot send after transport endpoint shutdown"}, {"ETOOMANYREFS", ETOOMANYREFS, "Too many references: cannot splice"}, {"ETIMEDOUT", ETIMEDOUT, "Connection timed out"}, {"ECONNREFUSED", ECONNREFUSED, "Connection refused"}, {"EHOSTDOWN", EHOSTDOWN, "Host is down"}, {"EHOSTUNREACH", EHOSTUNREACH, "No route to host"}, {"EALREADY", EALREADY, "Operation already in progress"}, {"EINPROGRESS", EINPROGRESS, "Operation now in progress"}, {"ESTALE", ESTALE, "Stale NFS file handle"}, {"EUCLEAN", EUCLEAN, "Structure needs cleaning"}, {"ENOTNAM", ENOTNAM, "Not a XENIX named type file"}, {"ENAVAIL", ENAVAIL, "No XENIX semaphores available"}, {"EISNAM", EISNAM, "Is a named type file"}, {"EREMOTEIO", EREMOTEIO, "Remote I/O error"}, {"EDQUOT", EDQUOT, "Quota exceeded"}, {"ENOMEDIUM", ENOMEDIUM, "No medium found"}, {"EMEDIUMTYPE", EMEDIUMTYPE, "Wrong medium type"}, #else #error impl me #endif {"NONE", 0, "No error"}, }; const char *GetErrorName(int e) { for (ErrorCodeType *c=ErrorCodes; c->Code; c++) { if (e == c->Code) { return c->Name; } } static char s[32]; sprintf(s, "Unknown(%i)", e); return s; } char *GetErrorDesc(int e) { for (ErrorCodeType *c=ErrorCodes; c->Code; c++) { if (e == c->Code) { return c->Desc; } } return 0; } /****************************** Helper Functions **************************/ char *ReadTextFile(const char *File) { char *s = 0; GFile f; if (File && f.Open(File, O_READ)) { int Len = f.GetSize(); s = new char[Len+1]; if (s) { int Read = f.Read(s, Len); s[Read] = 0; } } return s; } int64 LgiFileSize(const char *FileName) { struct stat64 s; if (FileName && stat64(FileName, &s) == 0) { return s.st_size; } return 0; } bool DirExists(const char *FileName, char *CorrectCase) { bool Status = false; if (FileName) { struct stat s; // Check for exact match... int r = lstat(FileName, &s); if (r == 0) { Status = S_ISDIR(s.st_mode) || S_ISLNK(s.st_mode); // printf("DirStatus(%s) lstat = %i, %i\n", FileName, Status, s.st_mode); } else { r = stat(FileName, &s); if (r == 0) { Status = S_ISDIR(s.st_mode) || S_ISLNK(s.st_mode); // printf("DirStatus(%s) stat ok = %i, %i\n", FileName, Status, s.st_mode); } else { // printf("DirStatus(%s) lstat and stat failed, r=%i, errno=%i\n", FileName, r, errno); } } } return Status; } bool FileExists(const char *FileName, char *CorrectCase) { bool Status = false; if (FileName) { struct stat s; // Check for exact match... if (stat(FileName, &s) == 0) { Status = !S_ISDIR(s.st_mode); } else if (CorrectCase) { // Look for altenate case by enumerating the directory char d[256]; strcpy(d, FileName); char *e = strrchr(d, DIR_CHAR); if (e) { *e++ = 0; DIR *Dir = opendir(d); if (Dir) { dirent *De; while (De = readdir(Dir)) { if (De->d_type != DT_DIR && stricmp(De->d_name, e) == 0) { try { // Tell the calling program the actual case of the file... e = strrchr(FileName, DIR_CHAR); // If this crashes because the argument is read only then we get caught by the try catch strcpy(e+1, De->d_name); // It worked! Status = true; } catch (...) { // It didn't work :( #ifdef _DEBUG printf("%s,%i - FileExists(%s) found an alternate case version but couldn't return it to the caller.\n", __FILE__, __LINE__, FileName); #endif } break; } } closedir(Dir); } } } } return Status; } bool ResolveShortcut(const char *LinkFile, char *Path, ssize_t Len) { bool Status = false; return Status; } void WriteStr(GFile &f, const char *s) { ulong Len = (s) ? strlen(s) : 0; f << Len; if (Len > 0) { f.Write(s, Len); } } char *ReadStr(GFile &f DeclDebugArgs) { char *s = 0; // read the strings length... - uint32 Len; + uint32_t Len; f >> Len; if (Len > 0) { // 16mb sanity check.... anything over this // is _probably_ an error if (Len >= (16 << 20)) { // LgiAssert(0); return 0; } // allocate the memory buffer #if defined(_DEBUG) && defined MEMORY_DEBUG s = new(_file, _line) char[Len+1]; #else s = new char[Len+1]; #endif if (s) { // read the bytes from disk f.Read(s, Len); s[Len] = 0; } else { // memory allocation error, skip the data // on disk so the caller is where they think // they are in the file. f.Seek(Len, SEEK_CUR); } } return s; } ssize_t SizeofStr(const char *s) { return sizeof(ulong) + ((s) ? strlen(s) : 0); } bool LgiGetDriveInfo ( char *Path, uint64 *Free, uint64 *Size, uint64 *Available ) { bool Status = false; if (Path) { struct stat s; if (lstat(Path, &s) == 0) { // printf("LgiGetDriveInfo dev=%i\n", s.st_dev); } } return Status; } /****************************** Classes *************************************************************************************/ GVolume::GVolume() { _Type = VT_NONE; _Flags = 0; _Size = 0; _Free = 0; } ///////////////////////////////////////////////////////////////////////// #include #include class GLinuxVolume : public GVolume { int Which; List _Sub; public: GLinuxVolume(int w) { Which = w; _Type = VT_NONE; _Flags = 0; _Size = 0; _Free = 0; if (Which < 0) { _Name = "Desktop"; _Type = VT_DESKTOP; _Path = LGetSystemPath(LSP_DESKTOP); } } ~GLinuxVolume() { _Sub.DeleteObjects(); } bool IsMounted() { return false; } bool SetMounted(bool Mount) { return Mount; } void Insert(GAutoPtr v) { LgiAssert(0); } GVolume *First() { if (Which < 0 && !_Sub.Length()) { // Get various shortcuts to points of interest GLinuxVolume *v = new GLinuxVolume(0); if (v) { v->_Path = "/"; v->_Name = "Root"; v->_Type = VT_HARDDISK; _Sub.Insert(v); } struct passwd *pw = getpwuid(getuid()); if (pw) { v = new GLinuxVolume(0); if (v) { v->_Path = pw->pw_dir; v->_Name = "Home"; v->_Type = VT_HARDDISK; _Sub.Insert(v); } } // Get mount list // this is just a hack at this stage to establish some base // functionality. I would appreciate someone telling me how // to do this properly. Till then... GFile f; if (f.Open("/etc/fstab", O_READ)) { int Len = f.GetSize(); GAutoString Buf(new char[Len+1]); if (Buf) { f.Read(Buf, Len); Buf[Len] = 0; f.Close(); GToken L(Buf, "\r\n"); for (int l=0; l 2) { char *Mount = M[1]; if (Mount && strnicmp(M[0], "/dev/", 5) == 0 && strlen(M[1]) > 1 && stricmp(M[2], "swap") != 0) { v = new GLinuxVolume(0); if (v) { char *MountName = strrchr(Mount, '/'); v->_Name = (MountName ? MountName + 1 : Mount); v->_Path = Mount; v->_Type = VT_HARDDISK; char *Device = M[0]; char *FileSys = M[2]; if (stristr(Device, "fd")) { v->_Type = VT_3_5FLOPPY; } else if (stristr(Device, "cdrom")) { v->_Type = VT_CDROM; } _Sub.Insert(v); } } } } } } } return _Sub.First(); } GVolume *Next() { return _Sub.Next(); } GDirectory *GetContents() { GDirectory *Dir = 0; if (Which >= 0 && _Path) { Dir = new GDirectory; if (Dir) { if (!Dir->First(_Path)) { DeleteObj(Dir); } } } return Dir; } }; /////////////////////////////////////////////////////////////////////////////// GFileSystem *GFileSystem::Instance = 0; GFileSystem::GFileSystem() { Instance = this; Root = 0; } GFileSystem::~GFileSystem() { DeleteObj(Root); } void GFileSystem::OnDeviceChange(char *Reserved) { } GVolume *GFileSystem::GetRootVolume() { if (!Root) { Root = new GLinuxVolume(-1); } return Root; } int FloppyType(int Letter) { uchar MaxTrack; uchar SecPerTrack; /* _asm { mov eax, 0800h mov edx, Letter int 13h mov MaxTrack, ch mov SecPerTrack, cl } if (MaxTrack > 39) { switch (SecPerTrack) { case 9: { return FLOPPY_720K; } case 15: { return FLOPPY_1_2M; } case 18: { return FLOPPY_1_4M; } } } else { return FLOPPY_360K; } */ return 0; } bool GFileSystem::Copy(const char *From, const char *To, LError *Status, CopyFileCallback Callback, void *Token) { GArray Buf; if (Status) *Status = 0; if (Buf.Length(2 << 20)) { GFile In, Out; if (!In.Open(From, O_READ)) { if (Status) *Status = In.GetError(); return false; } if (!Out.Open(To, O_WRITE)) { if (Status) *Status = Out.GetError(); return false; } int64 Size = In.GetSize(), Done = 0; for (int64 i=0; i 0) { int w = Out.Write(&Buf[0], r); if (w <= 0) break; r -= w; Done += w; if (Callback) Callback(Token, Done, Size); } if (r > 0) break; } return Done == Size; } return false; } bool GFileSystem::Delete(GArray &Files, GArray *Status, bool ToTrash) { bool Error = false; if (ToTrash) { char p[MAX_PATH]; if (LGetSystemPath(LSP_TRASH, p, sizeof(p))) { for (int i=0; i f; f.Add(FileName); return Delete(f, 0, ToTrash); } return false; } bool GFileSystem::CreateFolder(const char *PathName, bool CreateParentTree, LError *ErrorCode) { int r = mkdir(PathName, S_IRWXU | S_IXGRP | S_IXOTH); if (r) { if (ErrorCode) *ErrorCode = errno; printf("%s:%i - mkdir('%s') failed with %i, errno=%i\n", _FL, PathName, r, errno); } return r == 0; } bool GFileSystem::RemoveFolder(const char *PathName, bool Recurse) { if (Recurse) { GDirectory *Dir = new GDirectory; if (Dir && Dir->First(PathName)) { do { char Str[256]; Dir->Path(Str, sizeof(Str)); if (Dir->IsDir()) { RemoveFolder(Str, Recurse); } else { Delete(Str, false); } } while (Dir->Next()); } DeleteObj(Dir); } return rmdir(PathName) == 0; } bool GFileSystem::Move(const char *OldName, const char *NewName, LError *Err) { if (rename(OldName, NewName)) { printf("%s:%i - rename failed, error: %s(%i)\n", _FL, GetErrorName(errno), errno); return false; } return true; } /* bool Match(char *Name, char *Mask) { strupr(Name); strupr(Mask); while (*Name && *Mask) { if (*Mask == '*') { if (*Name == *(Mask+1)) { Mask++; } else { Name++; } } else if (*Mask == '?' || *Mask == *Name) { Mask++; Name++; } else { return false; } } while (*Mask && ((*Mask == '*') || (*Mask == '.'))) Mask++; return (*Name == 0 && *Mask == 0); } */ short DaysInMonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; int LeapYear(int year) { if (year & 3) { return 0; } if ((year % 100 == 0) && !(year % 400 == 0)) { return 0; } return 1; } ///////////////////////////////////////////////////////////////////////////////// bool GDirectory::ConvertToTime(char *Str, int SLen, uint64 Time) const { time_t k = Time; struct tm *t = localtime(&k); if (t) { strftime(Str, SLen, "%I:%M:%S", t); return true; } return false; } bool GDirectory::ConvertToDate(char *Str, int SLen, uint64 Time) const { time_t k = Time; struct tm *t = localtime(&k); if (t) { strftime(Str, SLen, "%d/%m/%y", t); return true; } return false; } ///////////////////////////////////////////////////////////////////////////////// //////////////////////////// Directory ////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////// class GDirectoryPriv { public: char BasePath[MAX_PATH]; DIR *Dir; struct dirent *De; struct stat Stat; char *Pattern; GDirectoryPriv() { Dir = 0; De = 0; BasePath[0] = 0; Pattern = 0; } ~GDirectoryPriv() { DeleteArray(Pattern); } bool Ignore() { return De && ( strcmp(De->d_name, ".") == 0 || strcmp(De->d_name, "..") == 0 || ( Pattern && !MatchStr(Pattern, De->d_name) ) ); } }; GDirectory::GDirectory() { d = new GDirectoryPriv; } GDirectory::~GDirectory() { Close(); DeleteObj(d); } GDirectory *GDirectory::Clone() { return new GDirectory; } int GDirectory::First(const char *Name, const char *Pattern) { Close(); if (Name) { strcpy(d->BasePath, Name); if (!Pattern || stricmp(Pattern, LGI_ALL_FILES) == 0) { struct stat S; if (lstat(Name, &S) == 0) { if (S_ISREG(S.st_mode)) { char *Dir = strrchr(d->BasePath, DIR_CHAR); if (Dir) { *Dir++ = 0; d->Pattern = NewStr(Dir); } } } } else { d->Pattern = NewStr(Pattern); } d->Dir = opendir(d->BasePath); if (d->Dir) { d->De = readdir(d->Dir); if (d->De) { char s[256]; LgiMakePath(s, sizeof(s), d->BasePath, GetName()); lstat(s, &d->Stat); if (d->Ignore()) { if (!Next()) { return false; } } } } } return d->Dir != 0 && d->De != 0; } int GDirectory::Next() { int Status = false; while (d->Dir && d->De) { if (d->De = readdir(d->Dir)) { char s[256]; LgiMakePath(s, sizeof(s), d->BasePath, GetName()); lstat(s, &d->Stat); if (!d->Ignore()) { Status = true; break; } } } return Status; } int GDirectory::Close() { if (d->Dir) { closedir(d->Dir); d->Dir = 0; } d->De = 0; return true; } const char *GDirectory::FullPath() { static char s[MAX_PATH]; #warning this should really be optimized, and thread safe... Path(s, sizeof(s)); return s; } GString GDirectory::FileName() const { return GetName(); } bool GDirectory::Path(char *s, int BufLen) const { if (!s) { return false; } return LgiMakePath(s, BufLen, d->BasePath, GetName()); } int GDirectory::GetType() const { return IsDir() ? VT_FOLDER : VT_FILE; } int GDirectory::GetUser(bool Group) const { if (Group) { return d->Stat.st_gid; } else { return d->Stat.st_uid; } } bool GDirectory::IsReadOnly() const { if (getuid() == d->Stat.st_uid) { // Check user perms return !TestFlag(GetAttributes(), S_IWUSR); } else if (getgid() == d->Stat.st_gid) { // Check group perms return !TestFlag(GetAttributes(), S_IWGRP); } // Check global perms return !TestFlag(GetAttributes(), S_IWOTH); } bool GDirectory::IsHidden() const { return GetName() && GetName()[0] == '.'; } bool GDirectory::IsDir() const { int a = GetAttributes(); return !S_ISLNK(a) && S_ISDIR(a); } bool GDirectory::IsSymLink() const { int a = GetAttributes(); return S_ISLNK(a); } long GDirectory::GetAttributes() const { return d->Stat.st_mode; } char *GDirectory::GetName() const { return (d->De) ? d->De->d_name : 0; } uint64 GDirectory::GetCreationTime() const { return (uint64) d->Stat.st_ctime * LDateTime::Second64Bit; } uint64 GDirectory::GetLastAccessTime() const { return (uint64) d->Stat.st_atime * LDateTime::Second64Bit; } uint64 GDirectory::GetLastWriteTime() const { return (uint64) d->Stat.st_mtime * LDateTime::Second64Bit; } uint64 GDirectory::GetSize() const { - return (uint32)d->Stat.st_size; + return (uint32_t)d->Stat.st_size; } int64 GDirectory::GetSizeOnDisk() { - return (uint32)d->Stat.st_size; + return (uint32_t)d->Stat.st_size; } ///////////////////////////////////////////////////////////////////////////////// //////////////////////////// File /////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////// class GFilePrivate { public: int hFile; char *Name; bool Swap; int Status; int Attributes; int ErrorCode; GFilePrivate() { hFile = INVALID_HANDLE; Name = 0; Swap = false; Status = true; Attributes = 0; ErrorCode = 0; } ~GFilePrivate() { DeleteArray(Name); } }; GFile::GFile(const char *Path, int Mode) { d = new GFilePrivate; if (Path) Open(Path, Mode); } GFile::~GFile() { if (d && ValidHandle(d->hFile)) { Close(); } DeleteObj(d); } OsFile GFile::Handle() { return d->hFile; } int GFile::GetError() { return d->ErrorCode; } bool GFile::IsOpen() { return ValidHandle(d->hFile); } #define DEBUG_OPEN_FILES 0 #if DEBUG_OPEN_FILES LMutex Lck; GArray OpenFiles; #endif int GFile::Open(const char *File, int Mode) { int Status = false; if (File) { if (TestFlag(Mode, O_WRITE) || TestFlag(Mode, O_READWRITE)) { Mode |= O_CREAT; } Close(); d->hFile = open(File, Mode | O_LARGEFILE, S_IRUSR | S_IWUSR); if (ValidHandle(d->hFile)) { d->Attributes = Mode; d->Name = new char[strlen(File)+1]; if (d->Name) { strcpy(d->Name, File); } Status = true; d->Status = true; #if DEBUG_OPEN_FILES if (Lck.Lock(_FL)) { if (!OpenFiles.HasItem(this)) OpenFiles.Add(this); Lck.Unlock(); } #endif } else { d->ErrorCode = errno; #if DEBUG_OPEN_FILES if (Lck.Lock(_FL)) { for (unsigned i=0; iGetName()); Lck.Unlock(); } #endif printf("GFile::Open failed\n\topen(%s,%08.8x) = %i\n\terrno=%s (%s)\n", File, Mode, d->hFile, GetErrorName(d->ErrorCode), GetErrorDesc(d->ErrorCode)); } } return Status; } int GFile::Close() { if (ValidHandle(d->hFile)) { close(d->hFile); d->hFile = INVALID_HANDLE; DeleteArray(d->Name); #if DEBUG_OPEN_FILES if (Lck.Lock(_FL)) { OpenFiles.Delete(this); Lck.Unlock(); } #endif } return true; } /* int GFile::Print(char *Format, ...) { int Chars = 0; if (Format) { va_list Arg; va_start(Arg, Format); int Size = vsnprintf(0, 0, Format, Arg); char *Buffer = new char[Size+1]; if (Buffer) { vsprintf(Buffer, Format, Arg); } va_end(Arg); if (Size > 0) { Write(Buffer, Size); } DeleteArray(Buffer); } return Chars; } */ #define CHUNK 0xFFF0 ssize_t GFile::Read(void *Buffer, ssize_t Size, int Flags) { int Red = 0; if (Buffer && Size > 0) { Red = read(d->hFile, Buffer, Size); } d->Status = Red == Size; return MAX(Red, 0); } ssize_t GFile::Write(const void *Buffer, ssize_t Size, int Flags) { int Written = 0; if (Buffer && Size > 0) { Written = write(d->hFile, Buffer, Size); } d->Status = Written == Size; return MAX(Written, 0); } #define LINUX64 1 int64 GFile::Seek(int64 To, int Whence) { #if LINUX64 return lseek64(d->hFile, To, Whence); // If this doesn't compile, switch off LINUX64 #else return lseek(d->hFile, To, Whence); #endif } int64 GFile::SetPos(int64 Pos) { #if LINUX64 int64 p = lseek64(d->hFile, Pos, SEEK_SET); if (p < 0) { int e = errno; printf("%s:%i - lseek64(%Lx) failed (error %i: %s).\n", __FILE__, __LINE__, Pos, e, GetErrorName(e)); } #else return lseek(d->hFile, Pos, SEEK_SET); #endif } int64 GFile::GetPos() { #if LINUX64 int64 p = lseek64(d->hFile, 0, SEEK_CUR); if (p < 0) { int e = errno; printf("%s:%i - lseek64 failed (error %i: %s).\n", __FILE__, __LINE__, e, GetErrorName(e)); } return p; #else return lseek(d->hFile, 0, SEEK_CUR); #endif } int64 GFile::GetSize() { int64 Here = GetPos(); #if LINUX64 int64 Ret = lseek64(d->hFile, 0, SEEK_END); #else int64 Ret = lseek(d->hFile, 0, SEEK_END); #endif SetPos(Here); return Ret; } int64 GFile::SetSize(int64 Size) { if (ValidHandle(d->hFile)) { int64 Pos = GetPos(); /* close(d->hFile); if (d->Name) { #if LINUX64 truncate64(Name, Size); #else truncate(Name, Size); #endif } d->hFile = open(Name, Attributes, 0); */ #if LINUX64 ftruncate64(d->hFile, Size); #else ftruncate(d->hFile, Size); #endif if (d->hFile) { SetPos(Pos); } } return GetSize(); } bool GFile::Eof() { return GetPos() >= GetSize(); } ssize_t GFile::SwapRead(uchar *Buf, ssize_t Size) { ssize_t i = 0; ssize_t r = 0; Buf = &Buf[Size-1]; while (Size--) { r = read(d->hFile, Buf--, 1); i += r; } return i; } ssize_t GFile::SwapWrite(uchar *Buf, ssize_t Size) { ssize_t i = 0; ssize_t w = 0; Buf = &Buf[Size-1]; while (Size--) { w = write(d->hFile, Buf--, 1); i += w; } return i; } ssize_t GFile::ReadStr(char *Buf, ssize_t Size) { ssize_t i = 0; ssize_t r = 0; if (Buf && Size > 0) { char c; Size--; do { r = read(d->hFile, &c, 1); if (Eof()) { break; } *Buf++ = c; i++; } while (i < Size - 1 && c != '\n'); *Buf = 0; } return i; } ssize_t GFile::WriteStr(char *Buf, ssize_t Size) { ssize_t i = 0; ssize_t w; while (i <= Size) { w = write(d->hFile, Buf, 1); Buf++; i++; if (*Buf == '\n') break; } return i; } void GFile::SetStatus(bool s) { d->Status = s; } bool GFile::GetStatus() { return d->Status; } void GFile::SetSwap(bool s) { d->Swap = s; } bool GFile::GetSwap() { return d->Swap; } int GFile::GetOpenMode() { return d->Attributes; } char *GFile::GetName() { return d->Name; } #define RdIO { d->Status |= ((d->Swap) ? SwapRead((uchar*) &i, sizeof(i)) : Read(&i, sizeof(i))) != sizeof(i); return *this; } #define WrIO { d->Status |= ((d->Swap) ? SwapWrite((uchar*) &i, sizeof(i)) : Write(&i, sizeof(i))) != sizeof(i); return *this; } #define GFilePre GFile &GFile::operator >> ( #define GFilePost &i) RdIO GFileOps(); #undef GFilePre #undef GFilePost #define GFilePre GFile &GFile::operator << ( #define GFilePost i) WrIO GFileOps(); #undef GFilePre #undef GFilePost diff --git a/src/linux/Gtk/GPrintDC.cpp b/src/linux/Gtk/GPrintDC.cpp --- a/src/linux/Gtk/GPrintDC.cpp +++ b/src/linux/Gtk/GPrintDC.cpp @@ -1,317 +1,317 @@ #include "Lgi.h" // #include // #include #define PS_SCALE 10 /////////////////////////////////////////////////////////////////////////////////////// class GPrintDCPrivate // : public GCups { public: class PrintPainter *p; Gtk::GtkPrintContext *Handle; GString PrintJobName; GString PrinterName; int Pages; GColour c; GRect Clip; GPrintDCPrivate(Gtk::GtkPrintContext *handle) { p = 0; Pages = 0; Handle = handle; } ~GPrintDCPrivate() { } bool IsOk() { return this != 0; } }; ///////////////////////////////////////////////////////////////////////////////////// GPrintDC::GPrintDC(void *Handle, const char *PrintJobName, const char *PrinterName) { d = new GPrintDCPrivate((Gtk::GtkPrintContext*)Handle); d->PrintJobName = PrintJobName; d->PrinterName = PrinterName; Cairo = gtk_print_context_get_cairo_context(d->Handle); ColourSpace = CsRgb24; d->Clip = Bounds(); } GPrintDC::~GPrintDC() { Cairo = NULL; DeleteObj(d); } -Gtk::GtkPrintContext *GPrintDC::GetPrintContext() -{ - return d->Handle; -} - +Gtk::GtkPrintContext *GPrintDC::GetPrintContext() +{ + return d->Handle; +} + int GPrintDC::X() { return gtk_print_context_get_width(d->Handle); } int GPrintDC::Y() { return gtk_print_context_get_height(d->Handle); } int GPrintDC::GetBits() { return 24; -} - -int GPrintDC::DpiX() -{ - return Gtk::gtk_print_context_get_dpi_x(d->Handle); -} - -int GPrintDC::DpiY() -{ - return Gtk::gtk_print_context_get_dpi_y(d->Handle); -} - -GRect GPrintDC::ClipRgn(GRect *Rgn) -{ - GRect Prev = d->Clip; - if (Rgn) - d->Clip = *Rgn; - else - d->Clip = Bounds(); - return Prev; -} - -GRect GPrintDC::ClipRgn() -{ - return d->Clip; -} - -COLOUR GPrintDC::Colour() -{ - return d->c.c24(); -} - -COLOUR GPrintDC::Colour(COLOUR c, int Bits) -{ - GColour col(c, Bits); - return Colour(col).c24(); -} - -GColour GPrintDC::Colour(GColour c) -{ - GColour Prev = d->c; - d->c = c; - if (Cairo) - cairo_set_source_rgb(Cairo, - (double)d->c.r() / 255.0, - (double)d->c.g() / 255.0, - (double)d->c.b() / 255.0); - return Prev; -} - -void GPrintDC::Set(int x, int y) -{ - if (Cairo) - { - cairo_new_path(Cairo); - cairo_rectangle(Cairo, x, y, x+1, y+1); - cairo_fill(Cairo); - } -} - -void GPrintDC::HLine(int x1, int x2, int y) -{ - Line(x1, y, x2, y); -} - -void GPrintDC::VLine(int x, int y1, int y2) -{ - Line(x, y1, x, y2); -} - -void GPrintDC::Line(int x1, int y1, int x2, int y2) -{ - if (Cairo) - { +} + +int GPrintDC::DpiX() +{ + return Gtk::gtk_print_context_get_dpi_x(d->Handle); +} + +int GPrintDC::DpiY() +{ + return Gtk::gtk_print_context_get_dpi_y(d->Handle); +} + +GRect GPrintDC::ClipRgn(GRect *Rgn) +{ + GRect Prev = d->Clip; + if (Rgn) + d->Clip = *Rgn; + else + d->Clip = Bounds(); + return Prev; +} + +GRect GPrintDC::ClipRgn() +{ + return d->Clip; +} + +COLOUR GPrintDC::Colour() +{ + return d->c.c24(); +} + +COLOUR GPrintDC::Colour(COLOUR c, int Bits) +{ + GColour col(c, Bits); + return Colour(col).c24(); +} + +GColour GPrintDC::Colour(GColour c) +{ + GColour Prev = d->c; + d->c = c; + if (Cairo) + cairo_set_source_rgb(Cairo, + (double)d->c.r() / 255.0, + (double)d->c.g() / 255.0, + (double)d->c.b() / 255.0); + return Prev; +} + +void GPrintDC::Set(int x, int y) +{ + if (Cairo) + { + cairo_new_path(Cairo); + cairo_rectangle(Cairo, x, y, x+1, y+1); + cairo_fill(Cairo); + } +} + +void GPrintDC::HLine(int x1, int x2, int y) +{ + Line(x1, y, x2, y); +} + +void GPrintDC::VLine(int x, int y1, int y2) +{ + Line(x, y1, x, y2); +} + +void GPrintDC::Line(int x1, int y1, int x2, int y2) +{ + if (Cairo) + { cairo_set_line_width(Cairo, 0.5); - cairo_new_path(Cairo); + cairo_new_path(Cairo); cairo_move_to(Cairo, x1, y1); cairo_line_to(Cairo, x2, y2); - cairo_stroke(Cairo); - } -} - -void GPrintDC::Circle(double cx, double cy, double radius) -{ - LgiAssert(!"Not impl."); -} - -void GPrintDC::FilledCircle(double cx, double cy, double radius) -{ - LgiAssert(!"Not impl."); -} - -void GPrintDC::Arc(double cx, double cy, double radius, double start, double end) -{ - LgiAssert(!"Not impl."); -} - -void GPrintDC::FilledArc(double cx, double cy, double radius, double start, double end) -{ - LgiAssert(!"Not impl."); -} - -void GPrintDC::Ellipse(double cx, double cy, double x, double y) -{ - LgiAssert(!"Not impl."); -} - -void GPrintDC::FilledEllipse(double cx, double cy, double x, double y) -{ - LgiAssert(!"Not impl."); -} - -void GPrintDC::Box(int x1, int y1, int x2, int y2) -{ - GRect r(x1, y1, x2, y2); - Box(&r); -} - -void GPrintDC::Box(GRect *a) -{ - GRect r; - if (a) - r = *a; - else - r = Bounds(); - if (Cairo) - { - double Half = 0.5; + cairo_stroke(Cairo); + } +} + +void GPrintDC::Circle(double cx, double cy, double radius) +{ + LgiAssert(!"Not impl."); +} + +void GPrintDC::FilledCircle(double cx, double cy, double radius) +{ + LgiAssert(!"Not impl."); +} + +void GPrintDC::Arc(double cx, double cy, double radius, double start, double end) +{ + LgiAssert(!"Not impl."); +} + +void GPrintDC::FilledArc(double cx, double cy, double radius, double start, double end) +{ + LgiAssert(!"Not impl."); +} + +void GPrintDC::Ellipse(double cx, double cy, double x, double y) +{ + LgiAssert(!"Not impl."); +} + +void GPrintDC::FilledEllipse(double cx, double cy, double x, double y) +{ + LgiAssert(!"Not impl."); +} + +void GPrintDC::Box(int x1, int y1, int x2, int y2) +{ + GRect r(x1, y1, x2, y2); + Box(&r); +} + +void GPrintDC::Box(GRect *a) +{ + GRect r; + if (a) + r = *a; + else + r = Bounds(); + if (Cairo) + { + double Half = 0.5; cairo_set_line_width(Cairo, Half); - cairo_new_path(Cairo); - cairo_rectangle(Cairo, - Half + r.x1, - Half + r.y1, - -Half + r.X(), - -Half + r.Y()); - cairo_stroke(Cairo); - } -} - -void GPrintDC::Rectangle(int x1, int y1, int x2, int y2) -{ - GRect r(x1, y1, x2, y2); - Rectangle(&r); -} - -void GPrintDC::Rectangle(GRect *a) -{ - GRect r; - if (a) - r = *a; - else - r = Bounds(); - if (Cairo) - { - cairo_new_path(Cairo); - cairo_rectangle(Cairo, r.x1, r.y1, r.X(), r.Y()); - cairo_fill(Cairo); - } -} - -void GPrintDC::Blt(int x, int y, GSurface *Src, GRect *SrcClip) -{ - GRect s = SrcClip ? *SrcClip : Src->Bounds(); - GRect d = s; - d.ZOff(x, y); - StretchBlt(&d, Src, &s); -} - -void GPrintDC::StretchBlt(GRect *d, GSurface *Src, GRect *s) -{ - if (!Cairo) - { - LgiAssert(0); - return; - } - - uint8 *Scan0 = (*Src)[0]; - if (!Scan0) - { - LgiAssert(0); - return; - } - - Gtk::cairo_format_t Fmt = Gtk::CAIRO_FORMAT_INVALID; - switch (Src->GetBits()) - { - case 16: - Fmt = Gtk::CAIRO_FORMAT_RGB16_565; - break; - case 24: - Fmt = Gtk::CAIRO_FORMAT_RGB24; - break; - case 32: - Fmt = Gtk::CAIRO_FORMAT_ARGB32; - break; - } - if (Fmt == Gtk::CAIRO_FORMAT_INVALID) - { - LgiAssert(0); - return; - } - - Gtk::cairo_surface_t *Img = cairo_image_surface_create_for_data(Scan0, - Fmt, - Src->X(), - Src->Y(), - Src->GetRowStep()); - if (!Img) - { - LgiAssert(0); - return; - } - - Gtk::cairo_pattern_t *Pat = cairo_pattern_create_for_surface(Img); - if (Pat) - { - Gtk::cairo_matrix_t m; - double Sx = (double) s->X() / d->X(); - double Sy = (double) s->Y() / d->Y(); + cairo_new_path(Cairo); + cairo_rectangle(Cairo, + Half + r.x1, + Half + r.y1, + -Half + r.X(), + -Half + r.Y()); + cairo_stroke(Cairo); + } +} + +void GPrintDC::Rectangle(int x1, int y1, int x2, int y2) +{ + GRect r(x1, y1, x2, y2); + Rectangle(&r); +} + +void GPrintDC::Rectangle(GRect *a) +{ + GRect r; + if (a) + r = *a; + else + r = Bounds(); + if (Cairo) + { + cairo_new_path(Cairo); + cairo_rectangle(Cairo, r.x1, r.y1, r.X(), r.Y()); + cairo_fill(Cairo); + } +} + +void GPrintDC::Blt(int x, int y, GSurface *Src, GRect *SrcClip) +{ + GRect s = SrcClip ? *SrcClip : Src->Bounds(); + GRect d = s; + d.ZOff(x, y); + StretchBlt(&d, Src, &s); +} + +void GPrintDC::StretchBlt(GRect *d, GSurface *Src, GRect *s) +{ + if (!Cairo) + { + LgiAssert(0); + return; + } + + uint8_t *Scan0 = (*Src)[0]; + if (!Scan0) + { + LgiAssert(0); + return; + } + + Gtk::cairo_format_t Fmt = Gtk::CAIRO_FORMAT_INVALID; + switch (Src->GetBits()) + { + case 16: + Fmt = Gtk::CAIRO_FORMAT_RGB16_565; + break; + case 24: + Fmt = Gtk::CAIRO_FORMAT_RGB24; + break; + case 32: + Fmt = Gtk::CAIRO_FORMAT_ARGB32; + break; + } + if (Fmt == Gtk::CAIRO_FORMAT_INVALID) + { + LgiAssert(0); + return; + } + + Gtk::cairo_surface_t *Img = cairo_image_surface_create_for_data(Scan0, + Fmt, + Src->X(), + Src->Y(), + Src->GetRowStep()); + if (!Img) + { + LgiAssert(0); + return; + } + + Gtk::cairo_pattern_t *Pat = cairo_pattern_create_for_surface(Img); + if (Pat) + { + Gtk::cairo_matrix_t m; + double Sx = (double) s->X() / d->X(); + double Sy = (double) s->Y() / d->Y(); cairo_matrix_init_scale(&m, Sx, Sy); cairo_matrix_translate(&m, -d->x1,-d->y1); - cairo_pattern_set_matrix(Pat, &m); - - cairo_save(Cairo); - cairo_set_source(Cairo, Pat); - - cairo_new_path(Cairo); - cairo_rectangle(Cairo, d->x1, d->y1, d->X(), d->Y()); - cairo_fill(Cairo); - - cairo_restore(Cairo); - cairo_pattern_destroy(Pat); - } - - cairo_surface_destroy(Img); -} - -void GPrintDC::Polygon(int Points, GdcPt2 *Data) -{ - LgiAssert(!"Not impl."); -} - -void GPrintDC::Bezier(int Threshold, GdcPt2 *Pt) -{ - LgiAssert(!"Not impl."); -} - + cairo_pattern_set_matrix(Pat, &m); + + cairo_save(Cairo); + cairo_set_source(Cairo, Pat); + + cairo_new_path(Cairo); + cairo_rectangle(Cairo, d->x1, d->y1, d->X(), d->Y()); + cairo_fill(Cairo); + + cairo_restore(Cairo); + cairo_pattern_destroy(Pat); + } + + cairo_surface_destroy(Img); +} + +void GPrintDC::Polygon(int Points, GdcPt2 *Data) +{ + LgiAssert(!"Not impl."); +} + +void GPrintDC::Bezier(int Threshold, GdcPt2 *Pt) +{ + LgiAssert(!"Not impl."); +} + diff --git a/src/linux/Gtk/GScreenDC.cpp b/src/linux/Gtk/GScreenDC.cpp --- a/src/linux/Gtk/GScreenDC.cpp +++ b/src/linux/Gtk/GScreenDC.cpp @@ -1,693 +1,693 @@ /*hdr ** FILE: GScreenDC.cpp ** AUTHOR: Matthew Allen ** DATE: 14/10/2000 ** DESCRIPTION: GDC v2.xx header ** ** Copyright (C) 2000, Matthew Allen ** fret@memecode.com */ #include #include #include "Lgi.h" using namespace Gtk; class GScreenPrivate { public: int x, y, Bits; bool Own; GColour Col; GRect Client; GView *View; OsView v; GdkDrawable *d; GdkGC *gc; GScreenPrivate() { View = NULL; x = y = Bits = 0; Own = false; v = 0; d = NULL; gc = NULL; Client.ZOff(-1, -1); } ~GScreenPrivate() { if (gc) g_object_unref((Gtk::GObject*)g_type_check_instance_cast((Gtk::GTypeInstance*)gc, G_TYPE_OBJECT)); } }; // Translates are cumulative... so we undo the last one before resetting it. #define UnTranslate() // d->p.translate(OriginX, OriginY); #define Translate() // d->p.translate(-OriginX, -OriginY); ///////////////////////////////////////////////////////////////////////////////////////////////////// GScreenDC::GScreenDC() { d = new GScreenPrivate; d->x = GdcD->X(); d->y = GdcD->Y(); } /* GScreenDC::GScreenDC(OsView View) { d = new GScreenPrivate; d->v = View; d->d = View->window; d->x = View->allocation.width; d->y = View->allocation.height; if (d->gc = gdk_gc_new(View->window)) { GdkScreen *s = gdk_gc_get_screen(d->gc); if (s) { GdkVisual *v = gdk_screen_get_system_visual(s); if (v) { d->Bits = v->depth; ColourSpace = GdkVisualToColourSpace(v, v->depth); } } } // printf("%s:%i %p, %ix%i, %i\n", _FL, View, d->x, d->y, d->Bits); } */ GScreenDC::GScreenDC(int x, int y, int bits) { d = new GScreenPrivate; d->x = x; d->y = y; d->Bits = bits; } GScreenDC::GScreenDC(Gtk::GdkDrawable *Drawable) { d = new GScreenPrivate; d->Own = false; d->d = Drawable; if (d->gc = gdk_gc_new(Drawable)) { GdkScreen *s = gdk_gc_get_screen(d->gc); if (s) { GdkVisual *v = gdk_screen_get_system_visual(s); if (v) { d->Bits = v->depth; ColourSpace = GdkVisualToColourSpace(v, v->depth); } } } } GScreenDC::GScreenDC(GView *view, void *param) { d = new GScreenPrivate; d->View = view; if (view) { OsView v = view->Handle(); if (v) { d->v = v; d->d = v->window; d->x = v->allocation.width; d->y = v->allocation.height; if (d->gc = gdk_gc_new(v->window)) { GdkScreen *s = gdk_gc_get_screen(d->gc); if (s) { GdkVisual *v = gdk_screen_get_system_visual(s); if (v) { d->Bits = v->depth; ColourSpace = GdkVisualToColourSpace(v, v->depth); } } } /* d->d = v->window; if (d->gc = gdk_gc_new(v->window)) { GdkScreen *s = gdk_gc_get_screen(d->gc); if (s) { GdkVisual *v = gdk_screen_get_system_visual(s); if (v) { d->Bits = v->depth; ColourSpace = GdkVisualToColourSpace(v, v->depth); } } } */ } else { d->x = view->X(); d->y = view->Y(); d->Bits = 0; d->Own = false; GdkScreen *s = gdk_display_get_default_screen(gdk_display_get_default()); if (s) { GdkVisual *v = gdk_screen_get_system_visual(s); if (v) { d->Bits = v->depth; ColourSpace = GdkVisualToColourSpace(v, v->depth); } } } } else { printf("%s:%i - No view?\n", _FL); } } GScreenDC::~GScreenDC() { UnTranslate(); DeleteObj(d); } OsPainter GScreenDC::Handle() { if (!Cairo) { Cairo = gdk_cairo_create(d->d); if (Cairo) { // cairo_reset_clip(Cairo); double x1, y1, x2, y2; cairo_clip_extents (Cairo, &x1, &y1, &x2, &y2); #ifdef _DEBUG int x = (int) (x2 - x1); int y = (int) (y2 - y1); if (d->View && d->View->_Debug) { int width, height; gdk_drawable_get_size (d->d, &width, &height); printf("%s:%i %s %g,%g,%g,%g %i,%i %i,%i %i,%i\n", _FL, d->View ? d->View->GetClass() : NULL, x1,y1,x2,y2, x,y, d->x, d->y, width, height); } #endif } } return Cairo; } bool GScreenDC::SupportsAlphaCompositing() { // GTK/X11 doesn't seem to support alpha compositing. return false; } GdcPt2 GScreenDC::GetSize() { return GdcPt2(d->x, d->y); } bool GScreenDC::GetClient(GRect *c) { if (!c) return false; *c = d->Client; return true; } void GScreenDC::SetClient(GRect *c) { if (c) { d->Client = *c; GdkRectangle r = {c->x1, c->y1, c->X(), c->Y()}; gdk_gc_set_clip_rectangle(d->gc, &r); OriginX = -c->x1; OriginY = -c->y1; } else { OriginX = 0; OriginY = 0; d->Client.ZOff(-1, -1); GdkRectangle r = {0, 0, X(), Y()}; gdk_gc_set_clip_rectangle(d->gc, &r); } } GRect *GScreenDC::GetClient() { return &d->Client; } uint GScreenDC::LineStyle() { return GSurface::LineStyle(); } -uint GScreenDC::LineStyle(uint32 Bits, uint32 Reset) +uint GScreenDC::LineStyle(uint32_t Bits, uint32_t Reset) { return GSurface::LineStyle(Bits); } int GScreenDC::GetFlags() { return 0; } void GScreenDC::GetOrigin(int &x, int &y) { return GSurface::GetOrigin(x, y); } void GScreenDC::SetOrigin(int x, int y) { UnTranslate(); GSurface::SetOrigin(x, y); Translate(); } GRect GScreenDC::ClipRgn() { return Clip; } GRect GScreenDC::ClipRgn(GRect *c) { GRect Prev = Clip; UnTranslate(); if (c) { Clip = *c; // LgiTrace("Setting clip %s client=%s\n", Clip.GetStr(), d->Client.GetStr()); GdkRectangle r = {c->x1+d->Client.x1, c->y1+d->Client.y1, c->X(), c->Y()}; gdk_gc_set_clip_rectangle(d->gc, &r); } else { Clip.ZOff(-1, -1); // LgiTrace("Removing clip\n"); GdkRectangle r = {d->Client.x1, d->Client.y1, X(), Y()}; gdk_gc_set_clip_rectangle(d->gc, &r); } Translate(); return Prev; } COLOUR GScreenDC::Colour() { return d->Col.Get(GetBits()); } COLOUR GScreenDC::Colour(COLOUR c, int Bits) { GColour col(c, Bits ? Bits : GetBits()); return Colour(col).Get(GetBits()); } GColour GScreenDC::Colour(GColour c) { GColour Prev = d->Col; d->Col = c; if (d->gc) { GdkColor col; col.pixel = 0; col.red = c.r(); col.red |= col.red << 8; col.green = c.g(); col.green |= col.green << 8; col.blue = c.b(); col.blue |= col.blue << 8; // printf("Setting Col %x, %x, %x\n", col.red, col.green, col.blue); gdk_gc_set_rgb_fg_color(d->gc, &col); gdk_gc_set_rgb_bg_color(d->gc, &col); } return Prev; } int GScreenDC::Op(int ROP, NativeInt Param) { int Prev = Op(); switch (ROP) { case GDC_SET: { //d->p.setRasterOp(XPainter::CopyROP); break; } case GDC_OR: { //d->p.setRasterOp(XPainter::OrROP); break; } case GDC_AND: { //d->p.setRasterOp(XPainter::AndROP); break; } case GDC_XOR: { //d->p.setRasterOp(XPainter::XorROP); break; } } return Prev; } int GScreenDC::Op() { /* switch (d->p.rasterOp()) { case XPainter::CopyROP: { return GDC_SET; break; } case XPainter::OrROP: { return GDC_OR; break; } case XPainter::AndROP: { return GDC_AND; break; } case XPainter::XorROP: { return GDC_XOR; break; } } */ return GDC_SET; } int GScreenDC::X() { return d->Client.Valid() ? d->Client.X() : d->x; } int GScreenDC::Y() { return d->Client.Valid() ? d->Client.Y() : d->y; } int GScreenDC::GetBits() { return d->Bits; } GPalette *GScreenDC::Palette() { return 0; } void GScreenDC::Palette(GPalette *pPal, bool bOwnIt) { } void GScreenDC::Set(int x, int y) { gdk_draw_point(d->d, d->gc, x-OriginX, y-OriginY); } COLOUR GScreenDC::Get(int x, int y) { return 0; } void GScreenDC::HLine(int x1, int x2, int y) { gdk_draw_line(d->d, d->gc, x1-OriginX, y-OriginY, x2-OriginX, y-OriginY); } void GScreenDC::VLine(int x, int y1, int y2) { gdk_draw_line(d->d, d->gc, x-OriginX, y1-OriginY, x-OriginX, y2-OriginY); } void GScreenDC::Line(int x1, int y1, int x2, int y2) { gdk_draw_line(d->d, d->gc, x1-OriginX, y1-OriginY, x2-OriginX, y2-OriginY); } void GScreenDC::Circle(double cx, double cy, double radius) { gdk_draw_arc(d->d, d->gc, false, cx - radius, cy - radius, radius * 2.0, radius * 2.0, 0, 360 * 64); } void GScreenDC::FilledCircle(double cx, double cy, double radius) { gdk_draw_arc(d->d, d->gc, true, cx - radius, cy - radius, radius * 2.0, radius * 2.0, 0, 360 * 64); } void GScreenDC::Arc(double cx, double cy, double radius, double start, double end) { gdk_draw_arc(d->d, d->gc, false, cx - radius, cy - radius, radius * 2.0, radius * 2.0, start * 64.0, end * 64.0); } void GScreenDC::FilledArc(double cx, double cy, double radius, double start, double end) { gdk_draw_arc(d->d, d->gc, true, cx - radius, cy - radius, radius * 2.0, radius * 2.0, start * 64.0, end * 64.0); } void GScreenDC::Ellipse(double cx, double cy, double x, double y) { gdk_draw_arc(d->d, d->gc, false, cx - (x / 2), cy - (y / 2), x, y, 0, 360 * 64); } void GScreenDC::FilledEllipse(double cx, double cy, double x, double y) { gdk_draw_arc(d->d, d->gc, true, cx - (x / 2), cy - (y / 2), x, y, 0, 360 * 64); } void GScreenDC::Box(int x1, int y1, int x2, int y2) { gdk_draw_rectangle(d->d, d->gc, false, x1-OriginX, y1-OriginY, x2-x1, y2-y1); } void GScreenDC::Box(GRect *a) { if (a) { Box(a->x1, a->y1, a->x2, a->y2); } else { Box(0, 0, X()-1, Y()-1); } } void GScreenDC::Rectangle(int x1, int y1, int x2, int y2) { if (x2 >= x1 && y2 >= y1) { gdk_draw_rectangle(d->d, d->gc, true, x1-OriginX, y1-OriginY, x2-x1+1, y2-y1+1); } } void GScreenDC::Rectangle(GRect *a) { if (a) { if (a->X() > 0 && a->Y() > 0) { gdk_draw_rectangle(d->d, d->gc, true, a->x1-OriginX, a->y1-OriginY, a->X(), a->Y()); } } else { gdk_draw_rectangle(d->d, d->gc, true, -OriginX, -OriginY, X(), Y()); } } void GScreenDC::Polygon(int Points, GdcPt2 *Data) { if (Data) { ::GArray pt; for (int p=0; pd, d->gc, true, &pt.First(), pt.Length()); } } void GScreenDC::Blt(int x, int y, GSurface *Src, GRect *a) { if (!Src) { LgiTrace("%s:%i - No source.\n", _FL); return; } if (Src->IsScreen()) { LgiTrace("%s:%i - Can't do screen->screen blt.\n", _FL); return; } // memory -> screen blt GRect RealClient = d->Client; int Dx, Dy; Dx = x - OriginX; Dy = y - OriginY; d->Client.ZOff(-1, -1); // Clear this so the blit rgn calculation uses the // full context size rather than just the client. GBlitRegions br(this, Dx, Dy, Src, a); d->Client = RealClient; if (!br.Valid()) { return; } GMemDC *Mem; if (Mem = dynamic_cast(Src)) { GMemDC Tmp; if (Mem->GetCreateCs() != GetColourSpace() && Mem->GetBits() > 16 && GetBits() <= 16) { // Do an on the fly colour space conversion... this is slow though if (Tmp.Create(br.SrcClip.X(), br.SrcClip.Y(), GetColourSpace())) { Tmp.Blt(0, 0, Mem, &br.SrcClip); printf("On the fly Mem->Scr conversion: %s->%s\n", GColourSpaceToString(Mem->GetColourSpace()), GColourSpaceToString(GetColourSpace())); Mem = &Tmp; br.SrcClip = Tmp.Bounds(); } else { printf("Failed to Mem->Scr Blt: %s->%s\n", GColourSpaceToString(Mem->GetColourSpace()), GColourSpaceToString(GetColourSpace())); return; } } if (d->d && d->gc && Mem->GetImage()) { gdk_draw_image( d->d, d->gc, Mem->GetImage(), br.SrcClip.x1, br.SrcClip.y1, Dx, Dy, br.SrcClip.X(), br.SrcClip.Y()); } else { LgiTrace("%s:%i - Error missing d=%p, gc=%p, img=%p\n", _FL, d->d, d->gc, Mem->GetImage()); } } } void GScreenDC::StretchBlt(GRect *d, GSurface *Src, GRect *s) { LgiAssert(0); } void GScreenDC::Bezier(int Threshold, GdcPt2 *Pt) { LgiAssert(0); } void GScreenDC::FloodFill(int x, int y, int Mode, COLOUR Border, GRect *Bounds) { LgiAssert(0); } diff --git a/src/linux/Gtk/Gdc2.cpp b/src/linux/Gtk/Gdc2.cpp --- a/src/linux/Gtk/Gdc2.cpp +++ b/src/linux/Gtk/Gdc2.cpp @@ -1,999 +1,999 @@ /// \file /// \author Matthew Allen, fret@memecode.com #include #include #include #include #include "Lgi.h" #include "GPalette.h" #define LGI_PI 3.141592654 #define LGI_RAD (360/(2*LGI_PI)) /****************************** Classes *************************************************************************************/ GPalette::GPalette() { Data = 0; Size = 0; } GPalette::GPalette(GPalette *pPal) { // printf("%s:%i - %p::new(%p) %i\n", _FL, this, pPal, pPal?pPal->GetSize():0); Size = 0; Data = 0; Set(pPal); } GPalette::GPalette(uchar *pPal, int s) { // printf("%s:%i - %p::new(%p) %i\n", _FL, this, pPal, s); Size = 0; Data = 0; Set(pPal, s); } GPalette::~GPalette() { DeleteArray(Data); Size = 0; } void GPalette::Set(GPalette *pPal) { if (pPal == this) return; // printf("%s:%i - %p::Set(%p) %i\n", _FL, this, pPal, pPal?pPal->GetSize():0); DeleteArray(Data); Size = 0; if (pPal) { LgiAssert(pPal->GetSize() > 0); if (pPal->Data) { Data = new GdcRGB[pPal->Size]; if (Data) { memcpy(Data, pPal->Data, sizeof(GdcRGB) * pPal->Size); } } Size = pPal->Size; } } void GPalette::Set(int Index, int r, int g, int b) { GdcRGB *rgb = (*this)[Index]; if (rgb) { rgb->r = r; rgb->g = g; rgb->b = b; } } void GPalette::Set(uchar *pPal, int s) { // printf("%s:%i - SetPal %p %i\n", _FL, pPal, s); DeleteArray(Data); Size = 0; Data = new GdcRGB[s]; if (Data) { if (pPal) { for (int i=0; ir; (*this)[i]->r = (*this)[i]->b; (*this)[i]->b = n; } } Update(); } uchar *GPalette::MakeLut(int Bits) { uchar *Lut = 0; GdcRGB *p = (*this)[0]; int Size = 1 << Bits; switch (Bits) { case 15: { Lut = new uchar[Size]; if (Lut) { for (int i=0; i> 2); int g = (G15(i) << 3) | (G15(i) >> 2); int b = (B15(i) << 3) | (B15(i) >> 2); Lut[i] = MatchRgb(Rgb24(r, g, b)); } } break; } case 16: { Lut = new uchar[Size]; if (Lut) { for (int i=0; i> 2); int g = (G16(i) << 2) | (G16(i) >> 3); int b = (B16(i) << 3) | (B16(i) >> 2); Lut[i] = MatchRgb(Rgb24(r, g, b)); } } break; } } return Lut; } int GPalette::MatchRgb(COLOUR Rgb) { if (Data) { GdcRGB *Entry = (*this)[0]; int r = (R24(Rgb) & 0xF8) + 4; int g = (G24(Rgb) & 0xF8) + 4; int b = (B24(Rgb) & 0xF8) + 4; ulong *squares = GdcD->GetCharSquares(); ulong mindist = 200000; ulong bestcolor; ulong curdist; long rdist; long gdist; long bdist; for (int i = 0; i < Size; i++) { rdist = Entry[i].r - r; gdist = Entry[i].g - g; bdist = Entry[i].b - b; curdist = squares[rdist] + squares[gdist] + squares[bdist]; if (curdist < mindist) { mindist = curdist; bestcolor = i; } } return bestcolor; } return 0; } void GPalette::CreateGreyScale() { SetSize(256); GdcRGB *p = (*this)[0]; for (int i=0; i<256; i++) { p->r = i; p->g = i; p->b = i; p->a = 0; p++; } } void GPalette::CreateCube() { SetSize(256); GdcRGB *p = (*this)[0]; for (int r=0; r<6; r++) { for (int g=0; g<6; g++) { for (int b=0; b<6; b++) { p->r = r * 51; p->g = g * 51; p->b = b * 51; p->a = 0; p++; } } } for (int i=216; i<256; i++) { (*this)[i]->r = 0; (*this)[i]->g = 0; (*this)[i]->b = 0; } } void TrimWhite(char *s) { char *White = " \r\n\t"; char *c = s; while (*c && strchr(White, *c)) c++; if (c != s) { strcpy(s, c); } c = s + strlen(s) - 1; while (c > s && strchr(White, *c)) { *c = 0; c--; } } bool GPalette::Load(GFile &F) { bool Status = false; char Buf[256]; F.ReadStr(Buf, sizeof(Buf)); TrimWhite(Buf); if (strcmp(Buf, "JASC-PAL") == 0) { // is JASC palette // skip hex length F.ReadStr(Buf, sizeof(Buf)); // read decimal length F.ReadStr(Buf, sizeof(Buf)); SetSize(atoi(Buf)); for (int i=0; ir = atoi(strtok(Buf, " ")); p->g = atoi(strtok(NULL, " ")); p->b = atoi(strtok(NULL, " ")); } Status = true; } } else { // check for microsoft format } return Status; } bool GPalette::Save(GFile &F, int Format) { bool Status = false; switch (Format) { case GDCPAL_JASC: { char Buf[256]; sprintf(Buf, "JASC-PAL\r\n%04.4X\r\n%i\r\n", GetSize(), GetSize()); F.Write(Buf, strlen(Buf)); for (int i=0; ir, p->g, p->b); F.Write(Buf, strlen(Buf)); } } Status = true; break; } } return Status; } bool GPalette::operator ==(GPalette &p) { if (GetSize() == p.GetSize()) { GdcRGB *a = (*this)[0]; GdcRGB *b = p[0]; for (int i=0; ir != b->r || a->g != b->g || a->b != b->b) { return false; } a++; b++; } return true; } return false; } bool GPalette::operator !=(GPalette &p) { return !((*this) == p); } //////////////////////////////////////////////////////////////////////////////////////////////////// GBmpMem::GBmpMem() { Base = 0; Flags = 0; } GBmpMem::~GBmpMem() { if (Base && (Flags & BmpOwnMemory)) { delete [] Base; } } //////////////////////////////////////////////////////////////////////////////////////////// class GdcDevicePrivate { public: GdcDevice *Device; // Current mode info int ScrX; int ScrY; int ScrBits; GColourSpace ScrColourSpace; // Palette double GammaCorrection; uchar GammaTable[256]; GPalette *pSysPal; GGlobalColour *GlobalColour; // Data ulong *CharSquareData; uchar *Div255; // Options int OptVal[GDC_MAX_OPTION]; GdcDevicePrivate(GdcDevice *d) { Device = d; GlobalColour = 0; ZeroObj(OptVal); ScrX = ScrY = 0; ScrBits = 0; // Palette information GammaCorrection = 1.0; // Get mode stuff Gtk::GdkDisplay *Dsp = Gtk::gdk_display_get_default(); Gtk::gint Screens = Gtk::gdk_display_get_n_screens(Dsp); for (Gtk::gint i=0; idepth; ScrColourSpace = GdkVisualToColourSpace(Vis, Vis->depth); } } } printf("Screen: %i x %i @ %i bpp (%s)\n", ScrX, ScrY, ScrBits, GColourSpaceToString(ScrColourSpace)); #if !LGI_RPI OptVal[GDC_PROMOTE_ON_LOAD] = ScrBits; #endif // Calcuate lookups CharSquareData = new ulong[255+255+1]; if (CharSquareData) { for (int i = -255; i <= 255; i++) { CharSquareData[i+255] = i*i; } } // Divide by 255 lookup, real handy for alpha blending 8 bit components int Size = (255 * 255) * 2; Div255 = new uchar[Size]; if (Div255) { for (int i=0; i= 0 && Opt < GDC_MAX_OPTION) { return d->OptVal[Opt]; } LgiAssert(0); return 0; } int GdcDevice::SetOption(int Opt, int Value) { int Prev = d->OptVal[Opt]; if (Opt >= 0 && Opt < GDC_MAX_OPTION) { d->OptVal[Opt] = Value; } else { LgiAssert(0); } return Prev; } ulong *GdcDevice::GetCharSquares() { return (d->CharSquareData) ? d->CharSquareData + 255 : 0; } uchar *GdcDevice::GetDiv255() { return d->Div255; } GGlobalColour *GdcDevice::GetGlobalColour() { return d->GlobalColour; } GColourSpace GdcDevice::GetColourSpace() { return d->ScrColourSpace; } int GdcDevice::GetBits() { return d->ScrBits; } int GdcDevice::X() { return d->ScrX; } int GdcDevice::Y() { return d->ScrY; } void GdcDevice::SetGamma(double Gamma) { d->GammaCorrection = Gamma; for (int i=0; i<256; i++) { d->GammaTable[i] = (uchar) (pow(((double)i)/256, Gamma) * 256); } } double GdcDevice::GetGamma() { return d->GammaCorrection; } void GdcDevice::SetSystemPalette(int Start, int Size, GPalette *pPal) { /* if (pPal) { uchar Pal[768]; uchar *Temp = Pal; uchar *System = Palette + (Start * 3); GdcRGB *P = (*pPal)[Start]; for (int i=0; iR] >> PalShift; *Temp++ = GammaTable[*System++ = P->G] >> PalShift; *Temp++ = GammaTable[*System++ = P->B] >> PalShift; } SetPaletteBlockDirect(Pal, Start, Size * 3); } */ } GPalette *GdcDevice::GetSystemPalette() { return d->pSysPal; } void GdcDevice::SetColourPaletteType(int Type) { bool SetOpt = true; /* switch (Type) { case PALTYPE_ALLOC: { SetPalIndex(0, 0, 0, 0); SetPalIndex(255, 255, 255, 255); break; } case PALTYPE_RGB_CUBE: { uchar Pal[648]; uchar *p = Pal; for (int r=0; r<6; r++) { for (int g=0; g<6; g++) { for (int b=0; b<6; b++) { *p++ = r * 51; *p++ = g * 51; *p++ = b * 51; } } } SetPalBlock(0, 216, Pal); SetPalIndex(255, 0xFF, 0xFF, 0xFF); break; } case PALTYPE_HSL: { for (int h = 0; h<16; h++) { } break; } default: { SetOpt = false; } } if (SetOpt) { SetOption(GDC_PALETTE_TYPE, Type); } */ } COLOUR GdcDevice::GetColour(COLOUR Rgb24, GSurface *pDC) { int Bits = (pDC) ? pDC->GetBits() : GetBits(); COLOUR C; switch (Bits) { case 8: { switch (GetOption(GDC_PALETTE_TYPE)) { case PALTYPE_ALLOC: { static uchar Current = 1; Rgb24 &= 0xFFFFFF; if (Rgb24 == 0xFFFFFF) { C = 0xFF; } else if (Rgb24 == 0) { C = 0; } else { GdcRGB *p = (*d->pSysPal)[Current]; p->r = R24(Rgb24); p->g = G24(Rgb24); p->b = B24(Rgb24); C = Current++; if (Current == 255) Current = 1; } break; } case PALTYPE_RGB_CUBE: { uchar r = (R24(Rgb24) + 25) / 51; uchar g = (G24(Rgb24) + 25) / 51; uchar b = (B24(Rgb24) + 25) / 51; C = (r*36) + (g*6) + b; break; } case PALTYPE_HSL: { C = 0; break; } } break; } case 16: { C = Rgb24To16(Rgb24); break; } case 24: { C = Rgb24; break; } case 32: { C = Rgb24To32(Rgb24); break; } } return C; } ////////////////////////////////////////////////////////////////////////////////////////////// static int _Factories; static GApplicatorFactory *_Factory[16]; GApp8 Factory8; GApp15 Factory15; GApp16 Factory16; GApp24 Factory24; GApp32 Factory32; GAlphaFactory FactoryAlpha; GApplicatorFactory::GApplicatorFactory() { LgiAssert(_Factories >= 0 && _Factories < CountOf(_Factory)); if (_Factories < CountOf(_Factory) - 1) { _Factory[_Factories++] = this; } } GApplicatorFactory::~GApplicatorFactory() { LgiAssert(_Factories >= 0 && _Factories < CountOf(_Factory)); for (int i=0; i<_Factories; i++) { if (_Factory[i] == this) { _Factory[i] = _Factory[_Factories-1]; _Factories--; break; } } } GApplicator *GApplicatorFactory::NewApp(GColourSpace Cs, int Op) { LgiAssert(_Factories >= 0 && _Factories < CountOf(_Factory)); for (int i=0; i<_Factories; i++) { GApplicator *a = _Factory[i]->Create(Cs, Op); if (a) return a; } return 0; } /////////////////////////////////////////////////////////////////////////////////////////////// class GlobalColourEntry { public: COLOUR c24; bool Fixed; bool Used; GlobalColourEntry() { c24 = 0; Fixed = false; Used = false; } }; class GGlobalColourPrivate { public: GlobalColourEntry c[256]; GPalette *Global; List Cache; int FirstUnused; int FreeColours() { int f = 0; for (int i=0; i<256; i++) { if (!c[i].Used) { f++; } } return f; } GGlobalColourPrivate() { } ~GGlobalColourPrivate() { Cache.DeleteObjects(); } }; GGlobalColour::GGlobalColour() { d = new GGlobalColourPrivate; } GGlobalColour::~GGlobalColour() { DeleteObj(d); } COLOUR GGlobalColour::AddColour(COLOUR c24) { return c24; } bool GGlobalColour::AddBitmap(GSurface *pDC) { return false; } bool GGlobalColour::AddBitmap(GImageList *il) { return false; } bool GGlobalColour::MakeGlobalPalette() { return 0; } GPalette *GGlobalColour::GetPalette() { return 0; } COLOUR GGlobalColour::GetColour(COLOUR c24) { return c24; } bool GGlobalColour::RemapBitmap(GSurface *pDC) { return false; } //////////////////////////////////////////////////////////////////////////////////////////// union EndianTest { char b[2]; short s; }; #define VisualToColourSpaceDebug 0 GColourSpace GdkVisualToColourSpace(Gtk::GdkVisual *v, int output_bits) { - uint32 c = CsNone; + uint32_t c = CsNone; if (v) { EndianTest Test; Test.b[0] = 1; Test.b[1] = 0; bool LittleEndian = Test.s == 1; #if VisualToColourSpaceDebug printf("GdkVisualToColourSpace, Type: %i, LittleEndian=%i\n", v->type, LittleEndian); #endif switch (v->type) { default: { LgiAssert(!"impl me"); c = GBitsToColourSpace(v->depth); break; } case Gtk::GDK_VISUAL_PSEUDO_COLOR: case Gtk::GDK_VISUAL_STATIC_COLOR: { LgiAssert(v->depth <= 16); c = (CtIndex << 4) | (v->depth != 16 ? v->depth : 0); break; } case Gtk::GDK_VISUAL_TRUE_COLOR: case Gtk::GDK_VISUAL_DIRECT_COLOR: { int red = (CtRed << 4) | v->red_prec; int green = (CtGreen << 4) | v->green_prec; int blue = (CtBlue << 4) | v->blue_prec; #ifdef __arm__ if ( (v->depth == 16 && v->red_shift < v->blue_shift) || (v->depth != 16 && v->red_shift > v->blue_shift) ) #else if (v->red_shift > v->blue_shift) #endif { c = (red << 16) | (green << 8) | blue; } else { c = (blue << 16) | (green << 8) | red; } int bits = GColourSpaceToBits((GColourSpace) c); #if VisualToColourSpaceDebug printf("GdkVisualToColourSpace, rgb: %i/%i, %i/%i, %i/%i bits: %i output_bits: %i\n", v->red_prec, v->red_shift, v->green_prec, v->green_shift, v->blue_prec, v->blue_shift, bits, output_bits ); #endif if (bits != output_bits) { int remaining_bits = output_bits - bits; LgiAssert(remaining_bits <= 16); if (remaining_bits <= 16) { c |= ( ( (CtAlpha << 4) | (remaining_bits < 16 ? remaining_bits : 0) ) ) << 24; } } break; } } } GColourSpace Cs; if (v->depth != 16) { if (v->byte_order == Gtk::GDK_LSB_FIRST) { #if VisualToColourSpaceDebug printf("GdkVisualToColourSpace swapping\n"); #endif c = LgiSwap32(c); while (!(c & 0xff)) c >>= 8; } } Cs = (GColourSpace)c; #if VisualToColourSpaceDebug printf("GdkVisualToColourSpace %x %s\n", Cs, GColourSpaceToString(Cs)); #endif return Cs; } diff --git a/src/linux/Gtk/LgiWidget.cpp b/src/linux/Gtk/LgiWidget.cpp --- a/src/linux/Gtk/LgiWidget.cpp +++ b/src/linux/Gtk/LgiWidget.cpp @@ -1,959 +1,959 @@ #include "Lgi.h" #include "GDragAndDrop.h" #define DEBUG_KEY_EVENT 0 using namespace Gtk; #include "LgiWidget.h" #include "gdk/gdkkeysyms.h" static void lgi_widget_class_init(LgiWidgetClass *klass); static void lgi_widget_init(LgiWidget *w); static void lgi_widget_forall( GtkContainer *container, gboolean include_internals, GtkCallback callback, gpointer callback_data) { LgiWidget *w = LGI_WIDGET(container); for (int i=0; ichild.Length(); i++) (*callback)(w->child[i].w, callback_data); } static GType lgi_widget_child_type(GtkContainer *container) { return GTK_TYPE_WIDGET; } GtkType lgi_widget_get_type(void) { static GtkType lgi_widget_type = 0; if (!lgi_widget_type) { static const GtkTypeInfo lgi_widget_info = { "LgiWidget", sizeof(LgiWidget), sizeof(LgiWidgetClass), (GtkClassInitFunc) lgi_widget_class_init, (GtkObjectInitFunc) lgi_widget_init, NULL, NULL, (GtkClassInitFunc) NULL }; lgi_widget_type = gtk_type_unique(GTK_TYPE_CONTAINER, &lgi_widget_info); } return lgi_widget_type; } GtkWidget *lgi_widget_new(GViewI *target, int w, int h, bool pour_largest) { LgiWidget *p = LGI_WIDGET(gtk_type_new(lgi_widget_get_type())); if (p) { // printf("Created %p for %s:%p\n", p, target->GetClass(), target); p->target = target; p->w = w; p->h = h; p->pour_largest = pour_largest; g_object_set_data(G_OBJECT(p), "GViewI", target); if (target->GetTabStop()) { #if GtkVer(2, 18) gtk_widget_set_can_focus(GTK_WIDGET(p), TRUE); #else GTK_OBJECT_FLAGS(GTK_WIDGET(p)) |= GTK_CAN_FOCUS; #endif } gtk_widget_add_events(GTK_WIDGET(p), GDK_ALL_EVENTS_MASK); } return GTK_WIDGET(p); } static void lgi_widget_remove(GtkContainer *wid, GtkWidget *child) { LgiWidget *p = LGI_WIDGET(wid); if (p) { for (int i=0; ichild.Length(); i++) { _LgiWidget::ChildInfo &c = p->child[i]; if (c.w == child) { bool widget_was_visible = GTK_WIDGET_VISIBLE(child); LgiWidget *cw = LGI_WIDGET(c.w); // if (cw) // printf("Unparenting %p, %s.%p\n", cw, cw->target->GetClass(), cw->target); gtk_widget_unparent(child); p->child.DeleteAt(i, true); if (widget_was_visible) gtk_widget_queue_resize(GTK_WIDGET(wid)); break; } } } } static gboolean lgi_widget_click(GtkWidget *widget, GdkEventButton *ev) { bool BtnDown = ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS; LgiWidget *p = LGI_WIDGET(widget); GView *v = dynamic_cast(p->target); if (v) { GMouse m; m.Target = v; m.x = ev->x; m.y = ev->y; m.Double(ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS); m.Down( ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS); m.Left(ev->button == 1); m.Middle(ev->button == 2); m.Right(ev->button == 3); m.Alt((ev->state & GDK_MOD1_MASK) != 0); m.Shift((ev->state & GDK_SHIFT_MASK) != 0); m.Ctrl((ev->state & GDK_CONTROL_MASK) != 0); #if 0 char s[256]; sprintf_s(s, sizeof(s), "%s::MouseClick", v->GetClass()); m.Trace(s); #endif v->_Mouse(m, false); } return TRUE; } static gboolean lgi_widget_motion(GtkWidget *widget, GdkEventMotion *ev) { LgiWidget *p = LGI_WIDGET(widget); GView *v = dynamic_cast(p->target); if (v) { GMouse m; m.Target = v; m.x = ev->x; m.y = ev->y; m.Flags |= LGI_EF_MOVE; m.Down((ev->state & GDK_BUTTON_PRESS_MASK) != 0); m.Left(ev->state & GDK_BUTTON1_MASK); m.Middle(ev->state & GDK_BUTTON2_MASK); m.Right(ev->state & GDK_BUTTON3_MASK); #if 0 char s[256]; sprintf_s(s, sizeof(s), "%s::MouseMove", v->GetClass()); m.Trace(s); #endif v->_Mouse(m, true); } return TRUE; } static gboolean lgi_widget_scroll(GtkWidget *widget, GdkEventScroll *ev) { LgiWidget *p = LGI_WIDGET(widget); GView *v = dynamic_cast(p->target); if (v) { double Lines = ev->direction == GDK_SCROLL_DOWN ? 3 : -3; // LgiTrace("%s::OnMouseWheel %g\n", v->GetClass(), Lines); v->OnMouseWheel(Lines); } return TRUE; } static gboolean lgi_widget_mouse_enter_leave(GtkWidget *widget, GdkEventCrossing *ev) { LgiWidget *p = LGI_WIDGET(widget); GView *v = dynamic_cast(p->target); if (v) { GMouse m; m.Target = v; m.x = ev->x; m.y = ev->y; if (ev->type == GDK_LEAVE_NOTIFY) { // LgiTrace("%s::OnMouseExit %i,%i\n", v->GetClass(), m.x, m.y); v->OnMouseExit(m); } else { // LgiTrace("%s::OnMouseEnter %i,%i\n", v->GetClass(), m.x, m.y); v->OnMouseEnter(m); } } return TRUE; } static gboolean lgi_widget_client_event(GtkWidget *wid, GdkEventClient *ev) { LgiWidget *p = LGI_WIDGET(wid); GView *v = dynamic_cast(p->target); if (v) { GMessage m(ev->data.l[0], ev->data.l[1], ev->data.l[2]); v->OnEvent(&m); } return TRUE; } static gboolean lgi_widget_focus_event(GtkWidget *wid, GdkEventFocus *e) { LgiWidget *p = LGI_WIDGET(wid); GView *v = dynamic_cast(p->target); if (v) v->OnFocus(e->in); else LgiAssert(0); return TRUE; } void BuildTabStops(GViewI *v, ::GArray &a) { if (v->Enabled() && v->Visible() && v->GetTabStop()) a.Add(v); GAutoPtr it(v->IterateViews()); for (GViewI *c = it->First(); c; c = it->Next()) { if (c->Enabled() && c->Visible()) BuildTabStops(c, a); } } static gboolean lgi_widget_key_event(GtkWidget *wid, GdkEventKey *e) { #if 0 // This is useful for debugging... if (e->keyval == GDK_Shift_L || e->keyval == GDK_Shift_R || e->keyval == GDK_Control_L || e->keyval == GDK_Control_R || e->keyval == GDK_Alt_L || e->keyval == GDK_Alt_R) { return TRUE; } #endif LgiWidget *p = LGI_WIDGET(wid); GView *v = dynamic_cast(p->target); if (!v) printf("%s:%i - No target??\n", _FL); else { GKey k; k.Down(e->type == GDK_KEY_PRESS); k.c16 = k.vkey = e->keyval; k.Shift((e->state & 1) != 0); k.Ctrl((e->state & 4) != 0); k.Alt((e->state & 8) != 0); // k.IsChar = !k.Ctrl() && (k.c16 >= ' ' && k.c16 <= 0x7f); k.IsChar = !k.Ctrl() && !k.Alt() && (k.c16 >= ' ') && (k.c16 >> 8 != 0xff); if (e->keyval > 0xff && e->string != NULL) { // Convert string to unicode char - uint8 *i = e->string; + uint8_t *i = e->string; ptrdiff_t len = strlen(i); k.c16 = LgiUtf8To32(i, len); } switch (k.vkey) { case GDK_ISO_Left_Tab: case GDK_Tab: k.IsChar = true; k.c16 = k.vkey = VK_TAB; break; case GDK_Return: case GDK_KP_Enter: k.IsChar = true; k.c16 = k.vkey = VK_RETURN; break; case GDK_BackSpace: k.c16 = k.vkey = VK_BACKSPACE; k.IsChar = !k.Ctrl() && !k.Alt(); break; case GDK_Left: k.vkey = k.c16 = VK_LEFT; break; case GDK_Right: k.vkey = k.c16 = VK_RIGHT; break; case GDK_Up: k.vkey = k.c16 = VK_UP; break; case GDK_Down: k.vkey = k.c16 = VK_DOWN; break; case GDK_Home: k.vkey = k.c16 = VK_HOME; break; case GDK_End: k.vkey = k.c16 = VK_END; break; #define KeyPadMap(gdksym, ch, is) \ case gdksym: k.c16 = ch; k.IsChar = is; break; KeyPadMap(GDK_KP_0, '0', true) KeyPadMap(GDK_KP_1, '1', true) KeyPadMap(GDK_KP_2, '2', true) KeyPadMap(GDK_KP_3, '3', true) KeyPadMap(GDK_KP_4, '4', true) KeyPadMap(GDK_KP_5, '5', true) KeyPadMap(GDK_KP_6, '6', true) KeyPadMap(GDK_KP_7, '7', true) KeyPadMap(GDK_KP_8, '8', true) KeyPadMap(GDK_KP_9, '9', true) KeyPadMap(GDK_KP_Space, ' ', true) KeyPadMap(GDK_KP_Tab, '\t', true) KeyPadMap(GDK_KP_F1, VK_F1, false) KeyPadMap(GDK_KP_F2, VK_F2, false) KeyPadMap(GDK_KP_F3, VK_F3, false) KeyPadMap(GDK_KP_F4, VK_F4, false) KeyPadMap(GDK_KP_Home, VK_HOME, false) KeyPadMap(GDK_KP_Left, VK_LEFT, false) KeyPadMap(GDK_KP_Up, VK_UP, false) KeyPadMap(GDK_KP_Right, VK_RIGHT, false) KeyPadMap(GDK_KP_Down, VK_DOWN, false) KeyPadMap(GDK_KP_Page_Up, VK_PAGEUP, false) KeyPadMap(GDK_KP_Page_Down, VK_PAGEDOWN, false) KeyPadMap(GDK_KP_End, VK_END, false) KeyPadMap(GDK_KP_Begin, VK_HOME, false) KeyPadMap(GDK_KP_Insert, VK_INSERT, false) KeyPadMap(GDK_KP_Delete, VK_DELETE, false) KeyPadMap(GDK_KP_Equal, '=', true) KeyPadMap(GDK_KP_Multiply, '*', true) KeyPadMap(GDK_KP_Add, '+', true) KeyPadMap(GDK_KP_Separator, '|', true) // is this right? KeyPadMap(GDK_KP_Subtract, '-', true) KeyPadMap(GDK_KP_Decimal, '.', true) KeyPadMap(GDK_KP_Divide, '/', true) } #if DEBUG_KEY_EVENT k.Trace("lgi_widget_key_event"); #endif GWindow *w = v->GetWindow(); if (w) { if (!w->HandleViewKey(v, k) && (k.vkey == VK_TAB || k.vkey == GDK_ISO_Left_Tab) && k.Down()) { // Do tab between controls ::GArray a; BuildTabStops(w, a); int idx = a.IndexOf((GViewI*)v); if (idx >= 0) { idx += k.Shift() ? -1 : 1; int next_idx = idx == 0 ? a.Length() -1 : idx % a.Length(); GViewI *next = a[next_idx]; if (next) { // LgiTrace("Setting focus to %i of %i: %s, %s, %i\n", next_idx, a.Length(), next->GetClass(), next->GetPos().GetStr(), next->GetId()); next->Focus(true); } } } } else v->OnKey(k); } return true; } static void lgi_widget_drag_begin(GtkWidget *widget, GdkDragContext *context) { LgiTrace("lgi_widget_drag_begin\n"); } static void lgi_widget_drag_end(GtkWidget *widget, GdkDragContext *drag_context) { LgiTrace("lgi_widget_drag_end\n"); } static void lgi_widget_drag_data_get(GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection_data, guint info, guint time_) { LgiTrace("lgi_widget_drag_data_get\n"); } static void lgi_widget_drag_data_delete(GtkWidget *widget, GdkDragContext *context) { LgiTrace("lgi_widget_drag_data_delete\n"); } static void lgi_widget_drag_leave(GtkWidget *widget, GdkDragContext *context, guint time) { LgiWidget *v = LGI_WIDGET(widget); if (!v || !v->target) { // printf("%s:%i - LGI_WIDGET failed.\n", _FL); return; } GDragDropTarget *Target = v->target->DropTarget(); if (!Target) { // printf("%s:%i - View '%s' doesn't have drop target.\n", _FL, v->target->GetClass()); return; } v->drag_over_widget = false; Target->OnDragExit(); } static gboolean lgi_widget_drag_motion(GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time_) { LgiWidget *v = LGI_WIDGET(widget); if (!v || !v->target) { printf("%s:%i - LGI_WIDGET failed.\n", _FL); return false; } GViewI *view = v->target; #if DEBUG_DND printf("%s:%i - DragMotion %s\n", _FL, view->GetClass()); #endif GDragDropTarget *Target = view->DropTarget(); while (view && !Target) { view = view->GetParent(); if (!view) break; Target = view->DropTarget(); #if DEBUG_DND printf("\t%s = %p\n", view->GetClass(), Target); #endif } if (!Target) { #if DEBUG_DND printf("%s:%i - View '%s' doesn't have drop target.\n", _FL, v->target->GetClass()); #endif return false; } #if DEBUG_DND // printf("%s:%i - DragMotion(%s): ", _FL, v->target->GetClass()); #endif List Formats; for (Gtk::GList *Types = gdk_drag_context_list_targets(context); Types; Types = Types->next) { gchar *Type = gdk_atom_name((GdkAtom)Types->data); if (Type) { Formats.Insert(NewStr(Type)); #if DEBUG_DND // printf("%s, ", Type); #endif } } #if DEBUG_DND // printf("\n"); #endif if (!v->drag_over_widget) { v->drag_over_widget = true; Target->OnDragEnter(); } GdcPt2 p(x, y); int Result = Target->WillAccept(Formats, p, 0); Formats.DeleteArrays(); if (Result != DROPEFFECT_NONE) { GdkDragAction action = DropEffectToAction(Result); gdk_drag_status(context, action, time_); } return Result != DROPEFFECT_NONE; } static gboolean lgi_widget_drag_drop(GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time_) { LgiWidget *v = LGI_WIDGET(widget); if (!v || !v->target) { printf("%s:%i - LGI_WIDGET failed.\n", _FL); return false; } GViewI *view = v->target; GDragDropTarget *Target = view->DropTarget(); while (view && !Target) { view = view->GetParent(); if (view) Target = view->DropTarget(); } if (!Target) { #if DEBUG_DND printf("%s:%i - View '%s' doesn't have drop target.\n", _FL, v->target->GetClass()); #endif return false; } // Convert the GTK list of formats to our own List List Formats; for (Gtk::GList *Types = gdk_drag_context_list_targets(context); Types; Types = Types->next) { gchar *Type = gdk_atom_name((GdkAtom)Types->data); if (Type) Formats.Insert(NewStr(Type)); } // Select a format from the supplied types GdcPt2 p(x, y); int Result = Target->WillAccept(Formats, p, 0); if (Result == DROPEFFECT_NONE) return false; char *drop_format = Formats.First(); Formats.Delete(drop_format); Formats.DeleteArrays(); #if DEBUG_DND LgiTrace("lgi_widget_drag_drop, fmt=%s\n", drop_format); #endif // Request the data... gtk_drag_get_data ( widget, context, gdk_atom_intern(drop_format, false), time_ ); DeleteArray(drop_format); return true; } static void lgi_widget_drag_data_received( GtkWidget *widget, GdkDragContext *context, gint x, gint y, GtkSelectionData *data, guint info, guint time) { // LgiTrace("lgi_widget_drag_data_received\n"); LgiWidget *v = LGI_WIDGET(widget); if (!v || !v->target) { // printf("%s:%i - LGI_WIDGET failed.\n", _FL); return; } GViewI *view = v->target; GDragDropTarget *Target = view->DropTarget(); while (view && !Target) { view = view->GetParent(); if (view) Target = view->DropTarget(); } if (!Target) { #if DEBUG_DND printf("%s:%i - View '%s' doesn't have drop target.\n", _FL, v->target->GetClass()); #endif return; } gchar *Type = gdk_atom_name(gtk_selection_data_get_data_type(data)); #if DEBUG_DND printf("%s:%i - Type=%s, Target=%s\n", _FL, Type, v->target->GetClass()); #endif GdcPt2 p(x, y); gint Len = gtk_selection_data_get_length(data); #if DEBUG_DND printf("%s:%i - Len=%i\n", _FL, Len); #endif const guchar *Ptr = gtk_selection_data_get_data(data); #if DEBUG_DND printf("%s:%i - Ptr=%p\n", _FL, Ptr); #endif if (!Ptr || Len <= 0) { #if DEBUG_DND printf("%s:%i - gtk_selection_data_get_[data/len] failed.\n", _FL); #endif return; } ::GArray dd; dd[0].Format = Type; dd[0].Data[0].SetBinary(Len, (void*)Ptr); // Give the data to the App Target->OnDrop(dd, p, 0); } static void lgi_widget_destroy(GtkObject *object) { g_return_if_fail(object != NULL); g_return_if_fail(LGI_IS_WIDGET(object)); LgiWidget *p = LGI_WIDGET(object); void *klass = gtk_type_class(gtk_widget_get_type()); if (GTK_OBJECT_CLASS(klass)->destroy) { (* GTK_OBJECT_CLASS(klass)->destroy)(object); } } static void lgi_widget_size_allocate(GtkWidget *widget, GtkAllocation *allocation) { g_return_if_fail(widget != NULL); g_return_if_fail(LGI_IS_WIDGET(widget)); g_return_if_fail(allocation != NULL); widget->allocation = *allocation; if (GTK_WIDGET_REALIZED(widget)) { gdk_window_move_resize( widget->window, allocation->x, allocation->y, allocation->width, allocation->height); LgiWidget *w = LGI_WIDGET(widget); GtkAllocation child_allocation; GtkRequisition child_requisition; guint16 border_width = GTK_CONTAINER(w)->border_width; for (int i=0; ichild.Length(); i++) { _LgiWidget::ChildInfo &c = w->child[i]; if (GTK_WIDGET_VISIBLE(c.w)) { gtk_widget_size_request(c.w, &child_requisition); child_allocation.x = c.x + border_width; child_allocation.y = c.y + border_width; if (GTK_WIDGET_NO_WINDOW(widget)) { child_allocation.x += widget->allocation.x; child_allocation.y += widget->allocation.y; } child_allocation.width = MAX(child_requisition.width, 1); child_allocation.height = MAX(child_requisition.height, 1); gtk_widget_size_allocate(c.w, &child_allocation); } } } } static void lgi_widget_realize(GtkWidget *widget) { GdkWindowAttr attributes; guint attributes_mask; g_return_if_fail(widget != NULL); g_return_if_fail(LGI_IS_WIDGET(widget)); GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED); LgiWidget *w = LGI_WIDGET(widget); attributes.window_type = GDK_WINDOW_CHILD; attributes.x = widget->allocation.x; attributes.y = widget->allocation.y; attributes.width = w->w; attributes.height = w->h; attributes.wclass = GDK_INPUT_OUTPUT; attributes.event_mask = gtk_widget_get_events(widget) | GDK_EXPOSURE_MASK; attributes_mask = GDK_WA_X | GDK_WA_Y; widget->window = gdk_window_new(gtk_widget_get_parent_window(widget), &attributes, attributes_mask); gdk_window_set_user_data(widget->window, widget); widget->style = gtk_style_attach(widget->style, widget->window); gtk_style_set_background(widget->style, widget->window, GTK_STATE_NORMAL); lgi_widget_size_allocate(widget, &widget->allocation); GView *v = dynamic_cast(w->target); if (v) v->OnGtkRealize(); else LgiTrace("%s:%i - Failed to cast target to GView.\n", _FL); } static gboolean lgi_widget_expose(GtkWidget *widget, GdkEventExpose *event) { g_return_val_if_fail(widget != NULL, FALSE); g_return_val_if_fail(LGI_IS_WIDGET(widget), FALSE); g_return_val_if_fail(event != NULL, FALSE); LgiWidget *p = LGI_WIDGET(widget); if (GTK_WIDGET_DRAWABLE(widget)) { if (p && p->target) { GScreenDC Dc(p->target->GetGView()); GView *v = dynamic_cast(p->target); if (v) v->_Paint(&Dc); else p->target->OnPaint(&Dc); } else printf("%s:%i - No view to paint widget.\n", _FL); } return FALSE; } void lgi_widget_setsize(GtkWidget *wid, int width, int height) { LgiWidget *p = LGI_WIDGET(wid); if (p) { if (p->w != width || p->h != height) { p->w = width; p->h = height; wid->requisition.width = width; wid->requisition.height = height; } } } void lgi_widget_setchildpos(GtkWidget *parent, GtkWidget *child, int x, int y) { if (!LGI_IS_WIDGET(parent)) { LgiAssert(0); // should this ever happen? return; } LgiWidget *p = LGI_WIDGET(parent); if (p) { for (int i=0; ichild.Length(); i++) { _LgiWidget::ChildInfo &c = p->child[i]; if (c.w == child) { c.x = x; c.y = y; if (GTK_WIDGET_REALIZED(c.w)) { LgiWidget *child_wid = LGI_WIDGET(c.w); GtkAllocation a; a.x = c.x; a.y = c.y; a.width = MAX(1, child_wid->w); a.height = MAX(1, child_wid->h); gtk_widget_size_allocate(c.w, &a); gdk_window_invalidate_rect( #if GtkVer(2, 14) gtk_widget_get_window(c.w) #else c.w->window #endif , &a, FALSE); } return; } } } } void lgi_widget_add(GtkContainer *wid, GtkWidget *child) { LgiWidget *p = LGI_WIDGET(wid); if (p) { for (int i=0; ichild.Length(); i++) { _LgiWidget::ChildInfo &c = p->child[i]; if (c.w == child) { printf("%s:%i - Already a child.\n", _FL); return; } } _LgiWidget::ChildInfo &c = p->child.New(); c.w = child; c.x = 0; c.y = 0; gtk_widget_set_parent(child, GTK_WIDGET(wid)); } } static void lgi_widget_size_request(GtkWidget *widget, GtkRequisition *requisition) { g_return_if_fail(widget != NULL); g_return_if_fail(LGI_IS_WIDGET(widget)); g_return_if_fail(requisition != NULL); LgiWidget *p = LGI_WIDGET(widget); if (p->pour_largest) { requisition->width = 10; requisition->height = 10; } else { requisition->width = p->w; requisition->height = p->h; } // LgiTrace("%s::req %i,%i\n", p->target->GetClass(), requisition->width, requisition->height); } gboolean lgi_widget_configure(GtkWidget *widget, GdkEventConfigure *ev) { LgiWidget *p = LGI_WIDGET(widget); printf("lgi_widget_configure %p\n", p); if (p) { p->target->OnPosChange(); } return TRUE; } static void lgi_widget_class_init(LgiWidgetClass *klass) { GtkObjectClass *object_class = (GtkObjectClass *)klass; object_class->destroy = lgi_widget_destroy; GtkWidgetClass *widget_class = (GtkWidgetClass *)klass; widget_class->realize = lgi_widget_realize; // widget_class->configure_event = lgi_widget_configure; widget_class->size_request = lgi_widget_size_request; widget_class->size_allocate = lgi_widget_size_allocate; widget_class->expose_event = lgi_widget_expose; widget_class->button_press_event = lgi_widget_click; widget_class->button_release_event = lgi_widget_click; widget_class->motion_notify_event = lgi_widget_motion; widget_class->scroll_event = lgi_widget_scroll; widget_class->enter_notify_event = lgi_widget_mouse_enter_leave; widget_class->leave_notify_event = lgi_widget_mouse_enter_leave; widget_class->client_event = lgi_widget_client_event; widget_class->focus_in_event = lgi_widget_focus_event; widget_class->focus_out_event = lgi_widget_focus_event; widget_class->key_press_event = lgi_widget_key_event; widget_class->key_release_event = lgi_widget_key_event; widget_class->drag_begin = lgi_widget_drag_begin; widget_class->drag_end = lgi_widget_drag_end; widget_class->drag_data_get = lgi_widget_drag_data_get; widget_class->drag_data_delete = lgi_widget_drag_data_delete; widget_class->drag_leave = lgi_widget_drag_leave; widget_class->drag_motion = lgi_widget_drag_motion; widget_class->drag_drop = lgi_widget_drag_drop; widget_class->drag_data_received = lgi_widget_drag_data_received; GtkContainerClass *container_class = (GtkContainerClass*)klass; container_class->add = lgi_widget_add; container_class->remove = lgi_widget_remove; container_class->forall = lgi_widget_forall; container_class->child_type = lgi_widget_child_type; } static void lgi_widget_init(LgiWidget *w) { GTK_WIDGET_UNSET_FLAGS(w, GTK_NO_WINDOW); w->target = 0; w->w = 0; w->h = 0; w->pour_largest = false; w->drag_over_widget = false; w->drop_format = NULL; w->debug = false; } diff --git a/src/linux/Lgi/GClipBoard.cpp b/src/linux/Lgi/GClipBoard.cpp --- a/src/linux/Lgi/GClipBoard.cpp +++ b/src/linux/Lgi/GClipBoard.cpp @@ -1,317 +1,317 @@ // Clipboard Implementation #include "Lgi.h" #include "GVariant.h" #include "GClipBoard.h" #define DEBUG_CLIPBOARD 0 #define VAR_COUNT 16 #define LGI_CLIP_BINARY "lgi.binary" #define LGI_RECEIVE_CLIPBOARD_TIMEOUT 4000 using namespace Gtk; struct ClipData : public LMutex { ::GVariant v[VAR_COUNT]; ClipData() : LMutex("ClipData") { } } Data; class GClipBoardPriv { public: GtkClipboard *c; }; /////////////////////////////////////////////////////////////////////////////////////////////// GClipBoard::GClipBoard(GView *o) { d = new GClipBoardPriv; Owner = o; Open = false; pDC = 0; d->c = gtk_clipboard_get(GDK_NONE); // gdk_atom_intern("CLIPBOARD", false) if (d->c) Open = true; #if DEBUG_CLIPBOARD printf("d->c = %i\n", d->c); #endif } GClipBoard::~GClipBoard() { d->c = 0; DeleteObj(d); } bool GClipBoard::Empty() { if (d->c) { gtk_clipboard_clear(d->c); #if DEBUG_CLIPBOARD printf("gtk_clipboard_clear(%i)\n", d->c); #endif return true; } return false; } bool GClipBoard::EnumFormats(::GArray &Formats) { return false; } bool GClipBoard::Html(const char *doc, bool AutoEmpty) { return false; } ::GString GClipBoard::Html() { return ::GString(); } bool GClipBoard::Text(char *Str, bool AutoEmpty) { bool Status = false; if (AutoEmpty) { Empty(); } if (Str && d->c) { gtk_clipboard_set_text(d->c, Str, strlen(Str)); #if DEBUG_CLIPBOARD printf("gtk_clipboard_set_text(%i,%s,%i)\n", d->c, Str, strlen(Str)); #endif Status = true; } return Status; } char *GClipBoard::Text() { char *t = 0; if (d->c) { gchar *txt = gtk_clipboard_wait_for_text(d->c); #if DEBUG_CLIPBOARD printf("gtk_clipboard_wait_for_text(%i)='%s'\n", d->c, txt); #endif if (txt) { t = NewStr(txt); g_free(txt); } } return t; } bool GClipBoard::TextW(char16 *Str, bool AutoEmpty) { GAutoString u(WideToUtf8(Str)); return Text(u, AutoEmpty); } char16 *GClipBoard::TextW() { GAutoString u(Text()); return Utf8ToWide(u); } bool GClipBoard::Bitmap(GSurface *pDC, bool AutoEmpty) { bool Status = false; if (pDC && d->c) { GMemDC *Mem = dynamic_cast(pDC); if (Mem) { /* GdkPixbuf *pb = gdk_pixbuf_new_from_data ( const guchar *data, GDK_COLORSPACE_RGB, gboolean has_alpha, int bits_per_sample, int width, int height, int rowstride, GdkPixbufDestroyNotify destroy_fn, gpointer destroy_fn_data); // gtk_clipboard_set_image(d->c, pb); */ } } return Status; } GSurface *GClipBoard::Bitmap() { return pDC; } void LgiClipboardGetFunc(GtkClipboard *clipboard, GtkSelectionData *data, guint info, gpointer user_data) { if (Data.Lock(_FL)) { ::GVariant *p = (::GVariant*)user_data; #if DEBUG_CLIPBOARD printf("%s:%i - LgiClipboardGetFunc: %p, %i\n", _FL, p, info); #endif switch (info) { case GV_BINARY: { if (p->Type == info) { data->data = p->Value.Binary.Data; data->length = p->Value.Binary.Length; } else LgiTrace("%s:%i - Variant is the wrong type: %i\n", _FL, p->Type); break; } default: { LgiTrace("%s:%i - Undefined data type: %i\n", _FL, info); break; } } Data.Unlock(); } } void LgiClipboardClearFunc(GtkClipboard *clipboard, gpointer user_data) { if (Data.Lock(_FL)) { ::GVariant *p = (::GVariant*)user_data; #if DEBUG_CLIPBOARD printf("%s:%i - LgiClipboardClearFunc: %i\n", _FL, p->Type); #endif p->Empty(); Data.Unlock(); } } bool GClipBoard::Binary(FormatType Format, uchar *Ptr, ssize_t Len, bool AutoEmpty) { if (!Ptr || Len <= 0) return false; ::GVariant *p = NULL; if (Data.Lock(_FL)) { for (int i=0; iSetBinary(Len, Ptr); break; } } Data.Unlock(); } GtkTargetEntry te; te.target = LGI_CLIP_BINARY; te.flags = 0; // GTK_TARGET_SAME_APP? te.info = GV_BINARY; // App defined data type ID Gtk::gboolean r = gtk_clipboard_set_with_data(d->c, &te, 1, LgiClipboardGetFunc, LgiClipboardClearFunc, p); #if DEBUG_CLIPBOARD printf("%s:%i - gtk_clipboard_set_with_data = %i\n", _FL, r); #endif return r; } ::GString::Array GClipBoard::Files() { ::GString::Array a; return a; } bool GClipBoard::Files(::GString::Array &a, bool AutoEmpty) { return false; } struct ReceiveData { - GAutoPtr *Ptr; + GAutoPtr *Ptr; ssize_t *Len; }; void LgiClipboardReceivedFunc(GtkClipboard *clipboard, GtkSelectionData *data, gpointer user_data) { ReceiveData *r = (ReceiveData*) user_data; if (data && r) { - uint8 *d = new uint8[data->length]; + uint8_t *d = new uint8_t[data->length]; if (d) { memcpy(d, data->data, data->length); if (r->Len) *r->Len = data->length; r->Ptr->Reset(d); #if DEBUG_CLIPBOARD printf("%s:%i - LgiClipboardReceivedFunc\n", _FL); #endif } else LgiTrace("%s:%i - Alloc failed %i\n", _FL, data->length); } else LgiTrace("%s:%i - Missing ptr: %p %p\n", _FL, data, r); } -bool GClipBoard::Binary(FormatType Format, GAutoPtr &Ptr, ssize_t *Len) +bool GClipBoard::Binary(FormatType Format, GAutoPtr &Ptr, ssize_t *Len) { ReceiveData r = {&Ptr, Len}; gtk_clipboard_request_contents( d->c, gdk_atom_intern(LGI_CLIP_BINARY, false), LgiClipboardReceivedFunc, &r); uint64 Start = LgiCurrentTime(); do { if (r.Ptr->Get()) break; LgiYield(); LgiSleep(1); } while (LgiCurrentTime() - Start > LGI_RECEIVE_CLIPBOARD_TIMEOUT); #if DEBUG_CLIPBOARD printf("%s:%i - GClipBoard::Binary %p, %i\n", _FL, r.Ptr->Get(), Len ? *Len : -1); #endif return r.Ptr->Get() != NULL; } diff --git a/src/linux/Lgi/GGeneral.cpp b/src/linux/Lgi/GGeneral.cpp --- a/src/linux/Lgi/GGeneral.cpp +++ b/src/linux/Lgi/GGeneral.cpp @@ -1,653 +1,653 @@ // Linux Implementation of General LGI functions #include #include #include #include #include #define _POSIX_TIMERS #include #include "Lgi.h" #include "GProcess.h" #include "GTextLabel.h" #include "GButton.h" #ifndef LGI_SDL #include "LgiWinManGlue.h" #endif #include "GToken.h" #include #include #define DEBUG_GET_APPS_FOR_MIMETYPE 0 //////////////////////////////////////////////////////////////// // Local helper functions bool _lgi_check_file(char *Path) { if (Path) { if (FileExists(Path)) { // file is there return true; } else { // shortcut? char *e = Path + strlen(Path); strcpy(e, ".lnk"); if (FileExists(Path)) { // resolve shortcut char Link[256]; if (ResolveShortcut(Path, Link, sizeof(Link))) { // check destination of link if (FileExists(Link)) { strcpy(Path, Link); return true; } } } *e = 0; } } return false; } GString LCurrentUserName() { struct passwd *pw = getpwuid(geteuid()); if (pw) return pw->pw_name; return ""; } -void LgiSleep(uint32 i) +void LgiSleep(uint32_t i) { struct timespec request, remain; ZeroObj(request); ZeroObj(remain); request.tv_sec = i / 1000; request.tv_nsec = (i % 1000) * 1000000; //printf("%i LgiSleep(%i)\n", LgiGetCurrentThread(), i); while (nanosleep(&request, &remain) == -1) { request = remain; //printf("\t%i Resleeping=%i\n", LgiGetCurrentThread(), request.tv_sec*1000 + request.tv_nsec/1000); } } int GtkAssertDlg(const char *File, int Line, const char *Msg) { Gtk::GtkWidget *dialog = Gtk::gtk_message_dialog_new ( NULL, Gtk::GTK_DIALOG_DESTROY_WITH_PARENT, Gtk::GTK_MESSAGE_ERROR, Gtk::GTK_BUTTONS_NONE, "%s:%i - Assert failed:\n%s", File, Line, Msg ); Gtk::GtkDialog *dlg = GtkCast(dialog, gtk_dialog, GtkDialog); Gtk::gtk_dialog_add_buttons(dlg, "Break", 1, "Quit", 2, "Ignore", 3, NULL); int Result = Gtk::gtk_dialog_run(dlg); Gtk::gtk_widget_destroy(dialog); return Result; } void _lgi_assert(bool b, const char *test, const char *file, int line) { static bool Asserting = false; if (!b && !Asserting) { Asserting = true; printf("%s:%i - Assert failed:\n%s\n", file, line, test); #ifdef LGI_SDL exit(-1); #else Gtk::gint Result = Gtk::GTK_RESPONSE_NO; #if 1 if (LgiApp->InThread()) Result = GtkAssertDlg(file, line, test); else Result = 1; #endif switch (Result) { case 1: { int *i = NULL; *i = 0; break; } case 2: { exit(-1); break; } } #endif Asserting = false; } } //////////////////////////////////////////////////////////////////////// // Implementations GMessage CreateMsg(int m, int a, int b) { static GMessage Msg(0); Msg.Set(m, a, b); return Msg; } bool LgiGetMimeTypeExtensions(const char *Mime, GArray &Ext) { int Start = Ext.Length(); char *e; #define HardCodeExtention(Mime, Ext1, Ext2) \ else if (!stricmp(Mime, Mime)) \ { if (Ext1) Ext.Add(Ext1); \ if (Ext2) Ext.Add(Ext2); } if (!Mime); HardCodeExtention("text/calendar", "ics", 0) HardCodeExtention("text/x-vcard", "vcf", 0) HardCodeExtention("text/mbox", "mbx", "mbox"); return Ext.Length() > Start; } GString LGetFileMimeType(const char *File) { GAutoString s = LgiApp->GetFileMimeType(File); return GString(s.Get()); } bool _GetSystemFont(char *FontType, char *Font, int FontBufSize, int &PointSize) { bool Status = false; #ifndef LGI_SDL GLibrary *WmLib = LgiApp->GetWindowManagerLib(); if (WmLib) { Proc_LgiWmGetSysFont GetSysFont = (Proc_LgiWmGetSysFont) WmLib->GetAddress("LgiWmGetSysFont"); if (GetSysFont) { Status = GetSysFont(FontType, Font, FontBufSize, PointSize); if (!Status) { printf("%s:%i - GetSysFont failed\n", _FL); } } else { printf("%s:%i - Entry point doesn't exist\n", _FL); } } else #endif { static bool Warn = true; if (Warn) { printf("%s:%i - GetWindowManagerLib failed\n", _FL); Warn = false; } } return Status; } bool LgiGetAppsForMimeType(const char *Mime, GArray &Apps, int Limit) { bool Status = false; char Args[MAX_PATH]; sprintf(Args, "query default %s", Mime); GProcess p; GStringPipe Output; GLanguage *CurLang = LgiGetLanguageId(); char LangName[64]; sprintf_s(LangName, sizeof(LangName), "Name[%s]", CurLang ? CurLang->Id : "en"); #if DEBUG_GET_APPS_FOR_MIMETYPE printf("LgiGetAppsForMimeType('%s', ..., %i)\nRunning 'xdg-mime %s'\n", Mime, Limit, Args); #endif if (p.Run("xdg-mime", Args, 0, true, 0, &Output)) { GAutoString o(Output.NewStr()); #if DEBUG_GET_APPS_FOR_MIMETYPE printf("Output:\n%s\n", o.Get()); #endif if (o) { char *e = o + strlen(o); while (e > o && strchr(" \t\r\n", e[-1])) *(--e) = 0; char p[MAX_PATH]; if (LgiMakePath(p, sizeof(p), "/usr/share/applications", o)) { if (FileExists(p)) { GAutoString txt(ReadTextFile(p)); GAutoString Section; #if DEBUG_GET_APPS_FOR_MIMETYPE printf("Reading '%s', got %i bytes\n", p, strlen(txt)); #endif if (txt) { GAppInfo *ai = new GAppInfo; Apps.Add(ai); GToken t(txt, "\n"); for (int i=0; iPath.Reset(NewStr(exe, sp-exe)); else ai->Path = exe; Status = true; } else if (!stricmp(Var, "Name") || !stricmp(Var, LangName)) { ai->Name.Reset(TrimStr(Value)); } } } } #if DEBUG_GET_APPS_FOR_MIMETYPE printf(" ai='%s' '%s'\n", ai->Name.Get(), ai->Path.Get()); #endif } else LgiTrace("%s:%i - Can't read from '%s'\n", _FL, p); } else LgiTrace("%s:%i - '%s' doesn't exist.", _FL, p); } else LgiTrace("%s:%i - Failed to create path.\n", _FL); } else LgiTrace("%s:%i - No output from xdg-mime\n", _FL); } else LgiTrace("%s:%i - Failed to execute xdg-mime\n", _FL); return Status; } GString LGetAppForMimeType(const char *Mime) { GString App; GArray Apps; if (LgiGetAppsForMimeType(Mime, Apps, 1)) App = Apps[0]->Path.Get(); Apps.DeleteObjects(); return App; } int LgiRand(int Limit) { return rand() % Limit; } -GAutoString LgiErrorCodeToString(uint32 ErrorCode) +GAutoString LgiErrorCodeToString(uint32_t ErrorCode) { GAutoString e; char *s = strerror(ErrorCode); if (s) { e.Reset(NewStr(s)); } else { char buf[256]; sprintf_s(buf, sizeof(buf), "UnknownError(%i)", ErrorCode); e.Reset(NewStr(buf)); } return e; } bool LgiExecute(const char *File, const char *Args, const char *Dir, GAutoString *Error) { if (File) { bool IsUrl = false; char App[MAX_PATH] = ""; if (strnicmp(File, "http://", 7) == 0 || strnicmp(File, "https://", 8) == 0) { IsUrl = true; LGetAppForMimeType("text/html", App, sizeof(App)); } else { struct stat f; char Path[MAX_PATH]; // see if the file is executable bool InPath = false; bool Ok = stat(File, &f) == 0; if (Ok) { strcpy_s(Path, sizeof(Path), File); } else { // look in the path InPath = true; GToken p(getenv("PATH"), LGI_PATH_SEPARATOR); for (int i=0; iReset(NewStr(m)); } } if (App[0]) { bool FileAdded = false; GString AppPath; GString EscFile = GString::Escape(File, -1, " &"); GString a = App; int Pos; while ((Pos = a.Find("%")) >= 0) { char *s = a.Get() + Pos; printf("a='%s'\n", a.Get()); switch (s[1]) { case 'f': case 'F': { a = a(0,Pos) + EscFile + a(Pos+2,-1); FileAdded = true; break; } case 'u': case 'U': { if (IsUrl) a = a(0,Pos) + EscFile + a(Pos+2,-1); else a = a(0,Pos) + GString("file:") + EscFile + a(Pos+2,-1); FileAdded = true; break; } default: { // we don't understand this command a = a(0,Pos) + a(Pos+2,-1); break; } } printf("a='%s'\n", a.Get()); } if (!FileAdded) { a += " "; a += EscFile; } a += " > /dev/null 2> /dev/null &"; int e; if (Dir) chdir(Dir); if (e = system(a)) { if (Error) *Error = LgiErrorCodeToString(errno); return false; } return true; } } return false; } ////////////////////////////////////////////////////////////////////////// WindowManager LgiGetWindowManager() { static WindowManager Status = WM_Unknown; if (Status == WM_Unknown) { GDirectory d; for (bool b=d.First("/proc"); b && Status == WM_Unknown; b=d.Next()) { if (d.IsDir() && isdigit(d.GetName()[0])) { char Path[256]; d.Path(Path, sizeof(Path)); LgiMakePath(Path, sizeof(Path), Path, "status"); GFile s; if (s.Open(Path, O_READ)) { char Buf[256]; Buf[sizeof(Buf)-1] = 0; s.Read(Buf, sizeof(Buf)-1); char *n = strchr(Buf, '\n'); if (n) { *n = 0; if (stristr(Buf, "gnome-settings") != 0 || stristr(Buf, "gnome-session") != 0 || stristr(Buf, "gnome-panel") != 0) { Status = WM_Gnome; } else if (stristr(Buf, "startkde") != 0 || stristr(Buf, "kdesktop") != 0) { Status = WM_Kde; } } } else printf("%s:%i - error\n", __FILE__, __LINE__); } } } return Status; } void LgiFinishXWindowsStartup(GViewI *Wnd) { // Get the startup ID const char *EnvStartId = "DESKTOP_STARTUP_ID"; char *DesktopStartupId = getenv(EnvStartId); if (ValidStr(DesktopStartupId)) { GStringPipe oss; // Create remove string oss.Push("remove: ID="); // Quote the id string for (char *c = DesktopStartupId; *c; c++) { if (*c == ' ' || *c == '"' || *c == '\\') { oss.Write((char*)"\\", 1); } oss.Write(c, 1); } char *Str = oss.NewStr(); // Get the window and display /* XWidget *View = Wnd->Handle(); if (!View) return; Display *display = View->XDisplay(); Window xroot_window = DefaultRootWindow(display); XSetWindowAttributes attrs; attrs.override_redirect = True; attrs.event_mask = PropertyChangeMask | StructureNotifyMask; // Get the atoms Atom type_atom = XInternAtom(display, "_NET_STARTUP_INFO", false); Atom type_atom_begin = XInternAtom(display, "_NET_STARTUP_INFO_BEGIN", false); // Create the event we will send XEvent xevent; xevent.xclient.type = ClientMessage; xevent.xclient.message_type = type_atom_begin; xevent.xclient.display = display; xevent.xclient.window = View->handle(); xevent.xclient.format = 8; const char* src = Str; const char* src_end = src + strlen(Str) + 1; // Include trailing NUL. // Loop over the string and send it. while (src != src_end) { char* dest = &xevent.xclient.data.b[0]; char* dest_end = dest + 20; while (dest != dest_end && src != src_end) { *dest++ = *src++; } while (dest != dest_end) { *dest++ = 0; } printf("%s:%i - XSendEvent\n", __FILE__, __LINE__); XSendEvent(display, xroot_window, False, PropertyChangeMask, &xevent); xevent.xclient.message_type = type_atom; } // Clear the event ID so it's not inherited by child processes. unsetenv(EnvStartId); */ } } #if HAS_GSTREAMER // sudo apt-get install libgstreamer1.0-dev using namespace Gtk; #include #endif bool LgiPlaySound(const char *FileName, int ASync) { #if HAS_GSTREAMER #else return LgiExecute(FileName); #endif } diff --git a/src/linux/Lgi/GView.cpp b/src/linux/Lgi/GView.cpp --- a/src/linux/Lgi/GView.cpp +++ b/src/linux/Lgi/GView.cpp @@ -1,1041 +1,1041 @@ /*hdr ** FILE: GView.cpp ** AUTHOR: Matthew Allen ** DATE: 23/4/98 ** DESCRIPTION: Linux GView Implementation ** ** Copyright (C) 1998-2003, Matthew Allen ** fret@memecode.com */ #include #include #include "Lgi.h" #include "GDragAndDrop.h" #include "GEdit.h" #include "GViewPriv.h" #include "GPopup.h" #include "GCss.h" using namespace Gtk; #include "LgiWidget.h" #define DEBUG_MOUSE_EVENTS 0 #define ADJ_LEFT 1 #define ADJ_RIGHT 2 #define ADJ_UP 3 #define ADJ_DOWN 4 #if GtkVer(2, 14) #else #define gtk_widget_get_window(widget) ((widget)->window) #endif struct CursorInfo { public: GRect Pos; GdcPt2 HotSpot; } CursorMetrics[] = { // up arrow { GRect(0, 0, 8, 15), GdcPt2(4, 0) }, // cross hair { GRect(20, 0, 38, 18), GdcPt2(29, 9) }, // hourglass { GRect(40, 0, 51, 15), GdcPt2(45, 8) }, // I beam { GRect(60, 0, 66, 17), GdcPt2(63, 8) }, // N-S arrow { GRect(80, 0, 91, 16), GdcPt2(85, 8) }, // E-W arrow { GRect(100, 0, 116, 11), GdcPt2(108, 5) }, // NW-SE arrow { GRect(120, 0, 132, 12), GdcPt2(126, 6) }, // NE-SW arrow { GRect(140, 0, 152, 12), GdcPt2(146, 6) }, // 4 way arrow { GRect(160, 0, 178, 18), GdcPt2(169, 9) }, // Blank { GRect(0, 0, 0, 0), GdcPt2(0, 0) }, // Vertical split { GRect(180, 0, 197, 16), GdcPt2(188, 8) }, // Horizontal split { GRect(200, 0, 216, 17), GdcPt2(208, 8) }, // Hand { GRect(220, 0, 233, 13), GdcPt2(225, 0) }, // No drop { GRect(240, 0, 258, 18), GdcPt2(249, 9) }, // Copy drop { GRect(260, 0, 279, 19), GdcPt2(260, 0) }, // Move drop { GRect(280, 0, 299, 19), GdcPt2(280, 0) }, }; // CursorData is a bitmap in an array of uint32's. This is generated from a graphics file: // ./Code/cursors.png // // The pixel values are turned into C code by a program called i.Mage: // http://www.memecode.com/image.php // // Load the graphic into i.Mage and then go Edit->CopyAsCode // Then paste the text into the CursorData variable at the bottom of this file. // // This saves a lot of time finding and loading an external resouce, and even having to // bundle extra files with your application. Which have a tendancy to get lost along the // way etc. -extern uint32 CursorData[]; +extern uint32_t CursorData[]; GInlineBmp Cursors = { 300, 20, 8, CursorData }; //////////////////////////////////////////////////////////////////////////// void _lgi_yield() { LgiApp->Run(false); } bool LgiIsKeyDown(int Key) { LgiAssert(0); return false; } GKey::GKey(int vkey, int flags) { } //////////////////////////////////////////////////////////////////////////////////////////////////// GViewPrivate::GViewPrivate() { Parent = 0; ParentI = 0; Notify = 0; CtrlId = -1; DropTarget = 0; Font = 0; FontOwnType = GV_FontPtr; Popup = 0; TabStop = 0; Pulse = 0; InPaint = false; GotOnCreate = false; WantsFocus = false; SinkHnd = -1; } GViewPrivate::~GViewPrivate() { LgiAssert(Pulse == 0); } void GView::OnGtkRealize() { // printf("%s::OnGtkRealize %i\n", GetClass(), d->GotOnCreate); if (!d->GotOnCreate) { d->GotOnCreate = true; if (d->WantsFocus && _View) { d->WantsFocus = false; gtk_widget_grab_focus(_View); } OnCreate(); } } void GView::_Focus(bool f) { ThreadCheck(); if (f) SetFlag(WndFlags, GWF_FOCUS); else ClearFlag(WndFlags, GWF_FOCUS); OnFocus(f); Invalidate(); if (f) { if (_View) { // printf("%s:%i - grabbing focus on %s.%p\n", _FL, GetClass(), _View); gtk_widget_grab_focus(_View); } else d->WantsFocus = f; } } void GView::_Delete() { ThreadCheck(); SetPulse(); // Remove static references to myself if (_Over == this) _Over = 0; if (_Capturing == this) _Capturing = 0; GWindow *Wnd = GetWindow(); if (Wnd && Wnd->GetFocus() == static_cast(this)) Wnd->SetFocus(this, GWindow::ViewDelete); if (LgiApp && LgiApp->AppWnd == this) { LgiApp->AppWnd = 0; } // Misc Pos.ZOff(-1, -1); // Heirarchy GViewI *c; while (c = Children.First()) { if (c->GetParent() != (GViewI*)this) { printf("%s:%i - ~GView error, %s not attached correctly: %p(%s) Parent: %p(%s)\n", _FL, c->GetClass(), c, c->Name(), c->GetParent(), c->GetParent() ? c->GetParent()->Name() : ""); Children.Delete(c); } DeleteObj(c); } Detach(); LgiAssert(_View == NULL); } GView *&GView::PopupChild() { return d->Popup; } void LgiToGtkCursor(GViewI *v, LgiCursor c) { static LgiCursor CurrentCursor = LCUR_Normal; if (!v || c == CurrentCursor) return; CurrentCursor = c; GdkCursorType type = GDK_ARROW; switch (c) { // No cursor #ifdef GDK_BLANK_CURSOR case LCUR_Blank: type = GDK_BLANK_CURSOR; break; #endif /// Normal arrow case LCUR_Normal: type = GDK_ARROW; break; /// Upwards arrow case LCUR_UpArrow: type = GDK_SB_UP_ARROW; break; /// Downwards arrow case LCUR_DownArrow: type = GDK_SB_DOWN_ARROW; break; /// Left arrow case LCUR_LeftArrow: type = GDK_SB_LEFT_ARROW; break; /// Right arrow case LCUR_RightArrow: type = GDK_SB_RIGHT_ARROW; break; /// Crosshair case LCUR_Cross: type = GDK_CROSSHAIR; break; /// Hourglass/watch case LCUR_Wait: type = GDK_WATCH; break; /// Ibeam/text entry case LCUR_Ibeam: type = GDK_XTERM; break; /// Vertical resize (|) case LCUR_SizeVer: type = GDK_DOUBLE_ARROW; break; /// Horizontal resize (-) case LCUR_SizeHor: type = GDK_SB_H_DOUBLE_ARROW; break; /// Diagonal resize (/) case LCUR_SizeBDiag: type = GDK_BOTTOM_LEFT_CORNER; break; /// Diagonal resize (\) case LCUR_SizeFDiag: type = GDK_BOTTOM_RIGHT_CORNER; break; /// All directions resize case LCUR_SizeAll: type = GDK_FLEUR; break; /// A pointing hand case LCUR_PointingHand: type = GDK_HAND2; break; /// A slashed circle case LCUR_Forbidden: type = GDK_X_CURSOR; break; default: type = GDK_ARROW; break; /* case LCUR_SplitV: case LCUR_SplitH: case LCUR_DropCopy: case LCUR_DropMove: LgiAssert(0); break; */ } GWindow *Wnd = v->GetWindow(); OsView h = Wnd ? Wnd->Handle() : v->Handle(); LgiAssert(v->InThread()); LgiAssert(h->window); if (type == GDK_ARROW) { gdk_window_set_cursor(h->window, NULL); // printf("gdk_window_set_cursor(%s, NULL)\n", v->GetClass()); } else { GdkCursor *cursor = gdk_cursor_new_for_display(gdk_display_get_default(), type); if (cursor) { gdk_window_set_cursor(h->window, cursor); // printf("gdk_window_set_cursor(%s, cursor)\n", v->GetClass()); } else { gdk_window_set_cursor(h->window, NULL); // printf("gdk_window_set_cursor(%s, gdk_cursor_new_for_display fail)\n", v->GetClass()); } } } bool GView::_Mouse(GMouse &m, bool Move) { ThreadCheck(); #if 0 if (!Move) { m.Trace("_Mouse"); ::GArray _m; for (GViewI *i=this; i; i=i->GetParent()) { _m.Add(i); } for (int n=0; n<_m.Length(); n++) { GViewI *i=_m[_m.Length()-1-n]; char s[256]; ZeroObj(s); memset(s, ' ', (n+1)*2); LgiTrace("%s%s %s\n", s, i->GetClass(), i->GetPos().GetStr()); } } #endif #if DEBUG_MOUSE_EVENTS LgiTrace("%s:%i - _Mouse([%i,%i], %i)\n", _FL, m.x, m.y, Move); #endif if ( !_View || ( GetWindow() && !GetWindow()->HandleViewMouse(this, m) ) ) { #if DEBUG_MOUSE_EVENTS LgiTrace("%s:%i - HandleViewMouse consumed event, _View=%p\n", _FL, _View); #endif return false; } GViewI *cap = _Capturing; #if DEBUG_MOUSE_EVENTS LgiTrace("%s:%i - _Capturing=%p/%s\n", _FL, _Capturing, _Capturing ? _Capturing->GetClass() : NULL); #endif if (_Capturing) { if (Move) { GMouse Local = lgi_adjust_click(m, _Capturing); LgiToGtkCursor(_Capturing, _Capturing->GetCursor(Local.x, Local.y)); #if DEBUG_MOUSE_EVENTS LgiTrace("%s:%i - Local=%i,%i\n", _FL, Local.x, Local.y); #endif _Capturing->OnMouseMove(Local); // This can set _Capturing to NULL } else { _Capturing->OnMouseClick(lgi_adjust_click(m, _Capturing)); } } else { if (Move) { bool Change = false; GViewI *o = WindowFromPoint(m.x, m.y); if (_Over != o) { #if DEBUG_MOUSE_EVENTS LgiTrace("%s:%i - _Over changing from %p/%s to %p/%s\n", _FL, _Over, _Over ? _Over->GetClass() : NULL, o, o ? o->GetClass() : NULL); #endif if (_Over) _Over->OnMouseExit(lgi_adjust_click(m, _Over)); _Over = o; if (_Over) _Over->OnMouseEnter(lgi_adjust_click(m, _Over)); } } GView *Target = dynamic_cast(_Over ? _Over : this); GRect Client = Target->GView::GetClient(false); m = lgi_adjust_click(m, Target, !Move); if (!Client.Valid() || Client.Overlap(m.x, m.y)) { LgiToGtkCursor(Target, Target->GetCursor(m.x, m.y)); if (Move) { Target->OnMouseMove(m); } else { #if 0 if (!Move) { char Msg[256]; sprintf(Msg, "_Mouse Target %s", Target->GetClass()); m.Trace(Msg); } #endif Target->OnMouseClick(m); } } else if (!Move) { #if DEBUG_MOUSE_EVENTS LgiTrace("%s:%i - Click outside %s %s %i,%i\n", _FL, Target->GetClass(), Client.GetStr(), m.x, m.y); #endif } } return true; } gboolean GtkViewCallback(GtkWidget *widget, GdkEvent *event, GView *This) { #if 0 printf("GtkViewCallback, widget=%p, event=%p, event=%x, This=%p(%s\"%s\")\n", widget, event, event->type, This, (NativeInt)This > 0x1000 ? This->GetClass() : 0, (NativeInt)This > 0x1000 ? This->Name() : 0); #endif if (event->type < 0 || event->type > 1000) { printf("%s:%i - CORRUPT EVENT %i\n", _FL, event->type); return false; } return This->OnGtkEvent(widget, event); } gboolean GView::OnGtkEvent(GtkWidget *widget, GdkEvent *event) { printf("GView::OnGtkEvent ?????\n"); return false; } GRect &GView::GetClient(bool ClientSpace) { int Edge = (Sunken() || Raised()) ? _BorderSize : 0; static GRect c; if (ClientSpace) { c.ZOff(Pos.X() - 1 - (Edge<<1), Pos.Y() - 1 - (Edge<<1)); } else { c.ZOff(Pos.X()-1, Pos.Y()-1); c.Size(Edge, Edge); } return c; } void GView::Quit(bool DontDelete) { ThreadCheck(); if (DontDelete) { Visible(false); } else { delete this; } } bool GView::SetPos(GRect &p, bool Repaint) { ThreadCheck(); Pos = p; if (_View) { int o = 0; GView *Par = d->GetParent(); if (Par && (Par->Sunken() || Par->Raised())) { o = Par->_BorderSize; } GtkWidget *GtkPar; if (GTK_IS_WINDOW(_View)) { gtk_window_move(GTK_WINDOW(_View), Pos.x1, Pos.y1); gtk_window_resize(GTK_WINDOW(_View), Pos.X(), Pos.Y()); } else if (GtkPar = gtk_widget_get_parent(_View)) { if (LGI_IS_WIDGET(GtkPar)) { lgi_widget_setsize(_View, Pos.X(), Pos.Y()); lgi_widget_setchildpos( GtkPar, _View, Pos.x1 + o, Pos.y1 + o); } else { // LgiTrace("%s:%i - Error: Can't set object position, parent is: %s\n", _FL, G_OBJECT_TYPE_NAME(GtkPar)); } } } OnPosChange(); return true; } bool GView::Invalidate(GRect *r, bool Repaint, bool Frame) { if (IsAttached()) { if (InThread() && !d->InPaint) { GRect Client; if (Frame) Client.ZOff(Pos.X()-1, Pos.Y()-1); else Client = GView::GetClient(false); static bool Repainting = false; if (!Repainting) { Repainting = true; GdkWindow *hnd = gtk_widget_get_window(_View); if (hnd) { if (r) { GRect cr = *r; cr.Offset(Client.x1, Client.y1); Gtk::GdkRectangle gr = cr; gdk_window_invalidate_rect(hnd, &gr, FALSE); } else { Gtk::GdkRectangle r = {0, 0, Pos.X(), Pos.Y()}; gdk_window_invalidate_rect(hnd, &r, FALSE); } } Repainting = false; } } else { PostEvent( M_INVALIDATE, (GMessage::Param)(r ? new GRect(r) : NULL), (GMessage::Param)(GView*)this); } return true; } else { GRect Up; GViewI *p = this; if (r) { Up = *r; } else { Up.Set(0, 0, Pos.X()-1, Pos.Y()-1); } while (p && !p->IsAttached()) { GRect pos = p->GetPos(); Up.Offset(pos.x1, pos.y1); p = p->GetParent(); } if (p && p->IsAttached()) { return p->Invalidate(&Up, Repaint); } } return false; } void GView::SetPulse(int Length) { ThreadCheck(); if (d->Pulse) { DeleteObj(d->Pulse); } if (Length > 0) { d->Pulse = new GPulseThread(this, Length); } } GMessage::Param GView::OnEvent(GMessage *Msg) { ThreadCheck(); int Id; switch (Id = Msg->Msg()) { case M_INVALIDATE: { if ((GView*)this == (GView*)Msg->B()) { GAutoPtr r((GRect*)Msg->A()); Invalidate(r); } break; } case M_PULSE: { OnPulse(); break; } case M_CHANGE: { GViewI *Ctrl; if (GetViewById(MsgA(Msg), Ctrl)) return OnNotify(Ctrl, MsgB(Msg)); break; } case M_COMMAND: { return OnCommand(MsgA(Msg), 0, (OsView) MsgB(Msg)); } } return 0; } void GView::PointToScreen(GdcPt2 &p) { ThreadCheck(); GViewI *c = this; // Find real parent while (c->GetParent() && !dynamic_cast(c)) { GRect n = c->GetPos(); p.x += n.x1; p.y += n.y1; c = c->GetParent(); } if (c && c->WindowHandle()) { gint x = 0, y = 0; // GdkRectangle rect; Gtk::GtkWindow *wnd = c->WindowHandle(); Gtk::GtkWidget *w = GTK_WIDGET(wnd); // Gtk::GdkWindow *gdk_wnd = gtk_widget_get_window(w); // gdk_window_get_frame_extents(gdk_wnd, &rect); gdk_window_get_origin(w->window, &x, &y); // int DecorX = x - rect.x; // int DecorY = y - rect.y; // printf("%s:%i - rect=%i,%i-%i,%i origin=%i,%i\n", _FL, rect.x, rect.y, rect.width, rect.height, x, y); p.x += x; p.y += y; } else { printf("%s:%i - No real view to map to screen.\n", _FL); } } void GView::PointToView(GdcPt2 &p) { ThreadCheck(); if (_View) { gint x = 0, y = 0; gdk_window_get_origin(GetWindow()->Handle()->window, &x, &y); p.x -= x; p.y -= y; GViewI *w = GetWindow(); for (GViewI *i = this; i && i != w; i = i->GetParent()) { GRect pos = i->GetPos(); const char *cls = i->GetClass(); p.x -= pos.x1; p.y -= pos.y1; } GRect cli = GetClient(false); p.x -= cli.x1; p.y -= cli.y1; } else if (GetParent()) { // Virtual window int Sx = 0, Sy = 0; GViewI *v; // Work out the virtual offset for (v = this; v && !v->Handle(); v = v->GetParent()) { Sx += v->GetPos().x1; Sy += v->GetPos().y1; } if (v && v->Handle()) { // Get the point relative to the first real parent v->PointToView(p); // Move point back into virtual space p.x -= Sx; p.y -= Sy; } else LgiTrace("%s:%i - No Real view for %s\n", _FL, GetClass()); } } bool GView::GetMouse(GMouse &m, bool ScreenCoords) { ThreadCheck(); if (_View) { gint x = 0, y = 0; GdkModifierType mask; GdkScreen *wnd_scr = gtk_window_get_screen(GTK_WINDOW(WindowHandle())); GdkDisplay *wnd_dsp = wnd_scr ? gdk_screen_get_display(wnd_scr) : NULL; gdk_display_get_pointer(wnd_dsp, &wnd_scr, &x, &y, &mask); if (!ScreenCoords) { GdcPt2 p(x, y); PointToView(p); m.x = p.x; m.y = p.y; } else { m.x = x; m.y = y; } m.SetModifer(mask); m.Left((mask & GDK_BUTTON1_MASK) != 0); m.Middle((mask & GDK_BUTTON2_MASK) != 0); m.Right((mask & GDK_BUTTON3_MASK) != 0); return true; } else if (GetParent()) { bool s = GetParent()->GetMouse(m, ScreenCoords); if (s) { if (!ScreenCoords) { m.x -= Pos.x1; m.y -= Pos.y1; } return true; } } return false; } bool GView::IsAttached() { return _View && _View->parent; } const char *GView::GetClass() { return "GView"; } bool GView::Attach(GViewI *parent) { ThreadCheck(); bool Status = false; SetParent(parent); GView *Parent = d->GetParent(); _Window = Parent ? Parent->_Window : this; if (!_View) { _View = lgi_widget_new(this, Pos.X(), Pos.Y(), false); } if (_View) { int o = 0; { GView *Par = d->GetParent(); if (Par && (Par->Sunken() || Par->Raised())) { o = Par->_BorderSize; } } if (parent) { GtkWidget *p = parent->Handle(); GWindow *w; if (w = dynamic_cast(parent)) p = w->_Root; if (p && gtk_widget_get_parent(_View) != p) { lgi_widget_add(GTK_CONTAINER(p), _View); lgi_widget_setchildpos(p, _View, Pos.x1 + o, Pos.y1 + o); // printf("%s:%i - Attach %s @ %i,%i - %i,%i\n", _FL, GetClass(), Pos.x1 + o, Pos.y1 + o, Pos.X(), Pos.Y()); } } if (Visible()) { gtk_widget_show(_View); } if (DropTarget()) { DropTarget(true); } if (TestFlag(WndFlags, GWF_FOCUS)) { // LgiTrace("OnCreate Focus %s\n", GetClass()); gtk_widget_grab_focus(_View); } OnAttach(); Status = true; } if (d->Parent && !d->Parent->HasView(this)) { if (!d->Parent->HasView(this)) d->Parent->AddView(this); d->Parent->OnChildrenChanged(this, true); } return Status; } bool GView::Detach() { ThreadCheck(); // Detach view if (_Window) { GWindow *Wnd = dynamic_cast(_Window); if (Wnd) Wnd->SetFocus(this, GWindow::ViewDelete); _Window = NULL; } GViewI *Par = GetParent(); if (Par) { // Events Par->DelView(this); Par->OnChildrenChanged(this, false); } d->Parent = 0; d->ParentI = 0; { int Count = Children.Length(); if (Count) { int Detached = 0; GViewI *c, *prev = NULL; while (c = Children.First()) { LgiAssert(!prev || c != prev); if (c->GetParent()) c->Detach(); else Children.Delete(c); Detached++; prev = c; } LgiAssert(Count == Detached); } } if (_View) { LgiAssert(_View->object.parent_instance.g_type_instance.g_class); LgiApp->OnDetach(this); gtk_widget_destroy(_View); _View = 0; } return true; } GViewI *GView::FindControl(OsView hCtrl) { ThreadCheck(); if (Handle() == hCtrl) { return this; } List::I it = Children.begin(); for (GViewI *c = *it; c; c = *++it) { GViewI *Ctrl = c->FindControl(hCtrl); if (Ctrl) { return Ctrl; } } return 0; } LgiCursor GView::GetCursor(int x, int y) { return LCUR_Normal; } void GView::OnGtkDelete() { _View = NULL; List::I it = Children.begin(); for (GViewI *c = *it; c; c = *++it) { GView *v = c->GetGView(); if (v) v->OnGtkDelete(); } } /////////////////////////////////////////////////////////////////// bool LgiIsMounted(char *Name) { return false; } bool LgiMountVolume(char *Name) { return false; } //////////////////////////////// -uint32 CursorData[] = { +uint32_t CursorData[] = { 0x02020202, 0x02020201, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020102, 0x02020202, 0x02020202, 0x01010101, 0x01010101, 0x01010101, 0x02020202, 0x02020202, 0x02010101, 0x02010101, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02010102, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020102, 0x01020202, 0x02020202, 0x02020202, 0x02020202, 0x01010101, 0x01010101, 0x02020201, 0x02020202, 0x01010101, 0x01010101, 0x02020201, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020102, 0x02020202, 0x02020202, 0x02020202, 0x01020202, 0x02010101, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020201, 0x02020202, 0x02020202, 0x02020202, 0x02010102, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x01020202, 0x01010101, 0x02020202, 0x02020202, 0x02020101, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020101, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x01020202, 0x02020100, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02010001, 0x02020202, 0x02020202, 0x00000001, 0x00000000, 0x01000000, 0x02020202, 0x02020202, 0x01000001, 0x02010000, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x01000001, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020101, 0x01020202, 0x02020201, 0x02020202, 0x02020202, 0x00000102, 0x00000000, 0x02020201, 0x02020202, 0x00000001, 0x01000000, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02010001, 0x02020202, 0x02020202, 0x02020202, 0x01020202, 0x02010000, 0x02020202, 0x02020202, 0x02020202, 0x01020202, 0x02020100, 0x02020202, 0x02020202, 0x02020202, 0x01000001, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x00010102, 0x00000000, 0x02020101, 0x02020202, 0x02010001, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02010001, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x01020202, 0x02020100, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02010001, 0x02020202, 0x02020202, 0x00010001, 0x00010001, 0x01000001, 0x02020202, 0x02020202, 0x00010102, 0x02020101, 0x02020202, 0x02020202, 0x02020202, 0x01020202, 0x00000000, 0x02020201, 0x02020202, 0x02020202, 0x01020202, 0x02020100, 0x01020202, 0x02020100, 0x02020202, 0x02020202, 0x00010202, 0x00000000, 0x02020201, 0x02020202, 0x00000001, 0x02010000, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x01020202, 0x01000000, 0x02020202, 0x02020202, 0x02020202, 0x01020202, 0x02010000, 0x02020202, 0x02020202, 0x02020202, 0x00010202, 0x02010000, 0x02020202, 0x02020202, 0x02020202, 0x01000001, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x00000001, 0x00000000, 0x02010000, 0x02020202, 0x01000001, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x01000001, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x00010202, 0x02010000, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02010001, 0x02020202, 0x02020202, 0x01000102, 0x00000100, 0x02010000, 0x02020202, 0x02020202, 0x00010202, 0x02020201, 0x02020202, 0x02020202, 0x02020202, 0x00010202, 0x00000000, 0x02020100, 0x02020202, 0x02020202, 0x00010202, 0x02020100, 0x01020202, 0x02010000, 0x02020202, 0x02020202, 0x01020202, 0x00000000, 0x02020201, 0x02020202, 0x00000001, 0x02020100, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x00010202, 0x00000000, 0x02020201, 0x02020202, 0x02020202, 0x01020202, 0x02010000, 0x02020202, 0x02020202, 0x02020202, 0x00000102, 0x01000000, 0x02020202, 0x02020202, 0x02020202, 0x01000001, 0x02020202, 0x02020202, 0x02020202, 0x01020202, 0x00000000, 0x00010101, 0x01000000, 0x02020202, 0x00000001, 0x02020201, 0x02020202, 0x02020202, 0x02020202, 0x00000001, 0x02020201, 0x02020202, 0x02020202, 0x02020202, 0x00010202, 0x02010000, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02010001, 0x02020202, 0x02020202, 0x00010202, 0x00000001, 0x02020100, 0x02020202, 0x02020202, 0x00010202, 0x02020201, 0x02020202, 0x02020202, 0x02020202, 0x00000102, 0x00000000, 0x02010000, 0x02020202, 0x02020202, 0x00000102, 0x01010100, 0x01010101, 0x01000000, 0x02020202, 0x02020201, 0x00010202, 0x00000000, 0x02020201, 0x02020202, 0x00000001, 0x02010000, 0x02020202, 0x02020201, 0x02020202, 0x02020202, 0x01010102, 0x01010001, 0x02020101, 0x02020202, 0x02020202, 0x01020201, 0x02010000, 0x02020102, 0x02020202, 0x02020202, 0x01010101, 0x01010100, 0x02020201, 0x02020202, 0x02020202, 0x01000001, 0x02020101, 0x02020202, 0x02020202, 0x00010202, 0x01010000, 0x01020202, 0x00000001, 0x02020201, 0x00000001, 0x02020100, 0x02020202, 0x02020202, 0x02020202, 0x00000001, 0x02020100, 0x02020202, 0x02020202, 0x02020202, 0x00000102, 0x01000000, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02010001, 0x02020202, 0x02020202, 0x01020202, 0x00000000, 0x02020201, 0x02020202, 0x02020202, 0x00010202, 0x02020201, 0x02020202, 0x02020202, 0x02020202, 0x01010101, 0x01000001, 0x01010101, 0x02020202, 0x02020202, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x02020201, 0x02020101, 0x00000102, 0x00000100, 0x02020201, 0x02020202, 0x01000001, 0x01000000, 0x01020202, 0x02020201, 0x02020202, 0x02020202, 0x02020201, 0x02010001, 0x02010202, 0x02020202, 0x01020202, 0x01020201, 0x02010000, 0x02010102, 0x02020202, 0x02020202, 0x01020202, 0x02020100, 0x02020202, 0x02020202, 0x02020202, 0x00000001, 0x01010000, 0x02020101, 0x02020202, 0x00000102, 0x01000000, 0x02020202, 0x00000102, 0x02020100, 0x00000001, 0x02010000, 0x02020202, 0x02020202, 0x02020202, 0x00000001, 0x02010000, 0x02020202, 0x02020202, 0x02020202, 0x00000102, 0x01000000, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02010001, 0x02020202, 0x02020202, 0x02020202, 0x01000001, 0x02020202, 0x02020202, 0x02020202, 0x00010202, 0x02020201, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x01000001, 0x02020202, 0x02020202, 0x02020202, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x02020201, 0x02010001, 0x00000001, 0x00010201, 0x02020201, 0x02020202, 0x02010001, 0x00000001, 0x00010201, 0x02020201, 0x02020202, 0x01020202, 0x02020201, 0x02010001, 0x01010202, 0x02020202, 0x00010202, 0x01020201, 0x02010000, 0x01000102, 0x02020202, 0x02020202, 0x01020202, 0x02020100, 0x02020202, 0x02020202, 0x02010102, 0x00000001, 0x00000000, 0x02010000, 0x02020202, 0x00000102, 0x00000001, 0x02020201, 0x00010202, 0x02020100, 0x00000001, 0x01000000, 0x02020202, 0x02020202, 0x02020202, 0x00000001, 0x01000000, 0x02020202, 0x02020202, 0x02020202, 0x00000001, 0x00000000, 0x02020201, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02010001, 0x02020202, 0x02020202, 0x02020202, 0x01000001, 0x02020202, 0x02020202, 0x02020202, 0x00010202, 0x02020201, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x01000001, 0x02020202, 0x02020202, 0x02020202, 0x00000102, 0x01010100, 0x01010101, 0x01000000, 0x02020202, 0x01000001, 0x01000000, 0x01020202, 0x02020201, 0x02020202, 0x02020101, 0x00000102, 0x00000100, 0x02020201, 0x02020202, 0x00010202, 0x02020201, 0x02010001, 0x00010202, 0x02020201, 0x00000102, 0x01010101, 0x01010000, 0x00000101, 0x02020201, 0x01010101, 0x01010101, 0x01010100, 0x01010101, 0x02020201, 0x01000001, 0x00000001, 0x00000000, 0x02010000, 0x02020202, 0x00000001, 0x00000101, 0x02020100, 0x00010202, 0x02010000, 0x00000001, 0x00000000, 0x02020201, 0x02020202, 0x02020202, 0x00000001, 0x00000000, 0x02020201, 0x02020202, 0x02020202, 0x00000001, 0x00000000, 0x02020201, 0x02020202, 0x02020202, 0x01010102, 0x01010101, 0x01010001, 0x01010101, 0x02020101, 0x02020202, 0x01000001, 0x02020202, 0x02020202, 0x02020202, 0x00010202, 0x02020201, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x01000001, 0x02020202, 0x02020202, 0x02020202, 0x00010202, 0x02020100, 0x01020202, 0x02010000, 0x02020202, 0x00000001, 0x02010000, 0x02020202, 0x02020201, 0x02020202, 0x02020201, 0x00010202, 0x00000000, 0x02020201, 0x02020202, 0x00000102, 0x01010101, 0x01010001, 0x00010101, 0x02020100, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x02020100, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x02020201, 0x00000001, 0x00000000, 0x00000000, 0x02010000, 0x02020202, 0x01000001, 0x00010202, 0x02010000, 0x01020202, 0x02010000, 0x00000001, 0x00000000, 0x02020100, 0x02020202, 0x02020202, 0x00000001, 0x00000000, 0x02020100, 0x02020202, 0x02020202, 0x01010101, 0x01010100, 0x02020201, 0x02020202, 0x02020202, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x02010000, 0x02020202, 0x01000001, 0x02020202, 0x02020202, 0x02020202, 0x00010202, 0x02020201, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x01000001, 0x02020202, 0x02020202, 0x02020202, 0x01020202, 0x02020100, 0x01020202, 0x02020100, 0x02020202, 0x00000001, 0x02020100, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x01020202, 0x00000000, 0x02020201, 0x02020202, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x02010000, 0x00000102, 0x01010101, 0x01010000, 0x00000101, 0x02020201, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x02020201, 0x00000102, 0x00000000, 0x00000000, 0x02010000, 0x02020202, 0x01000001, 0x01020202, 0x01000000, 0x01020202, 0x02010000, 0x00000001, 0x00000000, 0x02010000, 0x02020202, 0x02020202, 0x00000001, 0x00000000, 0x02010000, 0x02020202, 0x02020202, 0x01020202, 0x02020100, 0x02020202, 0x02020202, 0x02020202, 0x01010102, 0x01010101, 0x01010001, 0x01010101, 0x02020101, 0x01020202, 0x00000000, 0x02020201, 0x02020202, 0x02020202, 0x00010202, 0x02020201, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x01000001, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020101, 0x01020202, 0x02020201, 0x02020202, 0x00000001, 0x02010000, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x00010202, 0x00000000, 0x02020201, 0x02020202, 0x00000102, 0x01010101, 0x01010001, 0x00010101, 0x02020100, 0x00010202, 0x01020201, 0x02010000, 0x01000102, 0x02020202, 0x01010101, 0x01010101, 0x01010100, 0x01010101, 0x02020201, 0x00010202, 0x00000000, 0x00000000, 0x02010000, 0x02020202, 0x01000001, 0x02020202, 0x00000001, 0x01020201, 0x02010000, 0x00000001, 0x01000000, 0x02010101, 0x02020202, 0x02020202, 0x00000001, 0x01000000, 0x02010101, 0x02020202, 0x02020202, 0x01020202, 0x02020100, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02010001, 0x02020202, 0x02020202, 0x00010202, 0x01000001, 0x02020100, 0x02020202, 0x02020202, 0x00010202, 0x02020201, 0x02020202, 0x02020202, 0x02020202, 0x01010101, 0x01000001, 0x01010101, 0x02020202, 0x02020202, 0x02020202, 0x02020102, 0x01020202, 0x02020202, 0x02020202, 0x00000001, 0x01000000, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x00000102, 0x00000000, 0x02020201, 0x02020202, 0x00010202, 0x02020201, 0x02010001, 0x00010202, 0x02020201, 0x01020202, 0x01020201, 0x02010000, 0x02010102, 0x02020202, 0x02020202, 0x01020202, 0x02020100, 0x02020202, 0x02020202, 0x01020202, 0x00000000, 0x00000000, 0x02010000, 0x02020202, 0x00000001, 0x02020201, 0x00000102, 0x00010100, 0x02010000, 0x00000001, 0x01000001, 0x01020202, 0x01010101, 0x01010101, 0x00000001, 0x01000001, 0x01020202, 0x01010101, 0x01010101, 0x01020202, 0x02020100, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02010001, 0x02020202, 0x02020202, 0x01000102, 0x01000001, 0x02010001, 0x02020202, 0x02020202, 0x00010202, 0x02020201, 0x02020202, 0x02020202, 0x02020202, 0x00000102, 0x00000000, 0x02010000, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x01010101, 0x01010101, 0x02020201, 0x02020202, 0x02020202, 0x02020202, 0x01010101, 0x01010101, 0x02020201, 0x02020202, 0x01020202, 0x02020201, 0x02010001, 0x01010202, 0x02020202, 0x02020202, 0x01020201, 0x02010000, 0x02020102, 0x02020202, 0x02020202, 0x01020202, 0x02020100, 0x02020202, 0x02020202, 0x02020202, 0x00000001, 0x00000000, 0x02020100, 0x02020202, 0x00000102, 0x02020201, 0x00010202, 0x00010000, 0x02020100, 0x01000001, 0x01000001, 0x01020202, 0x00000000, 0x01000000, 0x01000001, 0x01000001, 0x01020202, 0x00000000, 0x01000000, 0x01020202, 0x02020100, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02010001, 0x02020202, 0x02020202, 0x00010001, 0x00000000, 0x01000100, 0x02020202, 0x02020202, 0x00010202, 0x02020201, 0x02020202, 0x02020202, 0x02020202, 0x00010202, 0x00000000, 0x02020100, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020201, 0x02010001, 0x02010202, 0x02020202, 0x02020202, 0x01020202, 0x02010000, 0x02020202, 0x02020202, 0x02020202, 0x01010101, 0x01010100, 0x02020201, 0x02020202, 0x02020202, 0x00000102, 0x00000000, 0x02020201, 0x02020202, 0x00000102, 0x02020100, 0x01020202, 0x00000000, 0x02020100, 0x02010001, 0x00000102, 0x01020201, 0x01010000, 0x01000001, 0x02010001, 0x00000102, 0x01020201, 0x01010100, 0x01000001, 0x01020202, 0x02020100, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02010001, 0x02020202, 0x02020202, 0x00000001, 0x00000000, 0x01000000, 0x02020202, 0x02020202, 0x00010202, 0x02020201, 0x02020202, 0x02020202, 0x02020202, 0x01020202, 0x00000000, 0x02020201, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x01010102, 0x01010001, 0x02020101, 0x02020202, 0x02020202, 0x01020202, 0x02010000, 0x02020202, 0x02020202, 0x02020202, 0x00000102, 0x01000000, 0x02020202, 0x02020202, 0x02020202, 0x01010202, 0x01010101, 0x02020202, 0x02020202, 0x00010202, 0x01010000, 0x01020202, 0x00000001, 0x02020201, 0x02020101, 0x00000102, 0x01020201, 0x00000100, 0x01000100, 0x02020101, 0x00000102, 0x01020201, 0x01000100, 0x01000100, 0x01020202, 0x02020101, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02010001, 0x02020202, 0x02020202, 0x01010101, 0x01010101, 0x01010101, 0x02020202, 0x02020202, 0x00010102, 0x02020101, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x01000001, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x00010202, 0x00000000, 0x02020201, 0x02020202, 0x02020202, 0x01020202, 0x02010000, 0x02020202, 0x02020202, 0x02020202, 0x00010202, 0x02010000, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x01020202, 0x00000000, 0x00010101, 0x01000000, 0x02020202, 0x02020202, 0x00010202, 0x01020100, 0x00000100, 0x01000000, 0x02020202, 0x00010202, 0x01020100, 0x01000100, 0x01000100, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02010001, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x01000001, 0x02010000, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02010102, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x01020202, 0x01000000, 0x02020202, 0x02020202, 0x02020202, 0x01020202, 0x02010101, 0x02020202, 0x02020202, 0x02020202, 0x01020202, 0x02020100, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x00000001, 0x00000000, 0x02010000, 0x02020202, 0x02020202, 0x00010202, 0x01020100, 0x00000100, 0x01000100, 0x02020202, 0x00010202, 0x01020100, 0x01000100, 0x01000100, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02010001, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02010101, 0x02010101, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02010001, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020201, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x00010102, 0x00000000, 0x02020101, 0x02020202, 0x02020202, 0x01020202, 0x01020201, 0x01010000, 0x01000001, 0x02020202, 0x01020202, 0x01020201, 0x01000100, 0x01000100, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020102, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020102, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x01020202, 0x01010101, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x01020202, 0x00000000, 0x01000000, 0x02020202, 0x02020202, 0x01020202, 0x00000000, 0x01000000, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x01020202, 0x01010101, 0x01010101, 0x02020202, 0x02020202, 0x01020202, 0x01010101, 0x01010101, };