/* egui.cpp * * Copyright (c) 1994-1996, Marko Macek * * You may distribute under the terms of either the GNU General Public * License or the Artistic License, as specified in the README file. * */ #include "fte.h" int LastEventChar = -1; EFrame::EFrame(int XSize, int YSize): GFrame(XSize, YSize) { CMap = 0; CModel = 0; frames = this; } EFrame::~EFrame() { } void EFrame::Update() { GxView *V = (GxView *)Active; if (V) { if (CModel != ActiveModel && ActiveModel) { char Title[256] = ""; //fte: "; char STitle[256] = ""; //"fte: "; ActiveModel->GetTitle((char *)(Title + 0), sizeof(Title) - 0, (char *)(STitle + 0), sizeof(STitle) - 0); ConSetTitle(Title, STitle); CModel = ActiveModel; } } GFrame::Update(); } void EFrame::UpdateMenu() { GxView *V = (GxView *)Active; EEventMap *Map = 0; if (V) Map = V->GetEventMap(); if (Map != CMap || CMap == 0) { const char *Menu = 0; const char *OMenu = 0; // set menu if (CMap) OMenu = CMap->GetMenu(EM_MainMenu); if (Map) Menu = Map->GetMenu(EM_MainMenu); if (Menu == 0) Menu = "Main"; CMap = Map; if (OMenu && strcmp(OMenu, Menu) == 0) { // ok } else { SetMenu(Menu); } } /*else if (CMap == 0 && Map == 0) { SetMenu("Main"); }*/ GFrame::UpdateMenu(); } EGUI::EGUI(int &argc, char **argv, int XSize, int YSize): GUI(argc, argv, XSize, YSize) { ActiveMap = 0; OverrideMap = 0; strcpy(CharMap, ""); } EGUI::~EGUI() { } int EGUI::ExecCommand(GxView *view, int Command, ExState &State) { if (Command & CMD_EXT) return ExecMacro(view, Command & ~CMD_EXT); if (Command == ExFail) return ErFAIL; if (view->IsModelView()) { ExModelView *V = (ExModelView *)view->Top; EView *View = V->View; switch (Command) { case ExFileClose: return FileClose(View, State); case ExFileCloseAll: return FileCloseAll(View, State); case ExExitEditor: return ExitEditor(View); case ExIncrementalSearch: #ifdef CONFIG_I_SEARCH return View->MView->Win->IncrementalSearch(View); #else return ErFAIL; #endif } } switch (Command) { case ExWinRefresh: view->Repaint(); return 1; case ExWinNext: return WinNext(view); case ExWinPrev: return WinPrev(view); case ExShowEntryScreen: return ShowEntryScreen(); case ExRunProgram: return RunProgram(State, view); case ExRunProgramAsync: return RunProgramAsync(State, view); case ExMainMenu: return MainMenu(State, view); case ExShowMenu: return ShowMenu(State, view); case ExLocalMenu: return LocalMenu(view); case ExFrameNew: return FrameNew(); case ExFrameNext: return FrameNext(view); case ExFramePrev: return FramePrev(view); case ExWinHSplit: return WinHSplit(view); case ExWinClose: return WinClose(view); case ExWinZoom: return WinZoom(view); case ExWinResize: return WinResize(State, view); case ExDesktopSaveAs: return DesktopSaveAs(State, view); case ExDesktopSave: if (DesktopFileName[0] != 0) return SaveDesktop(DesktopFileName); return 0; case ExChangeKeys: { char kmaps[64] = ""; EEventMap *m; if (State.GetStrParam(0, kmaps, sizeof(kmaps)) == 0) { SetOverrideMap(0, 0); return 0; } m = FindEventMap(kmaps); if (m == 0) return 0; SetOverrideMap(m->KeyMap, m->Name); return 1; } } return view->ExecCommand(Command, State); } int EGUI::BeginMacro(GxView *view) { view->BeginMacro(); return 1; } int EGUI::ExecMacro(GxView *view, int Macro) { int i, j; ExMacro *m; ExState State; if (Macro == -1) return ErFAIL; if (BeginMacro(view) == -1) return ErFAIL; State.Macro = Macro; State.Pos = 0; m = &Macros[State.Macro]; for (; State.Pos < m->Count; State.Pos++) { i = State.Pos; if (m->cmds[i].type != CT_COMMAND || m->cmds[i].u.num == ExNop) continue; for (j = 0; j < m->cmds[i].repeat; j++) { State.Pos = i + 1; if (ExecCommand(view, m->cmds[i].u.num, State) == 0 && !m->cmds[i].ign) { return ErFAIL; } } State.Pos = i; } return ErOK; } void EGUI::SetMsg(char *Msg) { static char CharMap[128] = ""; if (Msg == 0) { strcpy(CharMap, ""); } else { strcat(CharMap, "["); strcat(CharMap, Msg); strcat(CharMap, "]"); } if (ActiveModel) ActiveModel->Msg(S_INFO, CharMap); } void EGUI::SetOverrideMap(EKeyMap *aMap, char *ModeName) { OverrideMap = aMap; if (aMap == 0) SetMsg(0); else SetMsg(ModeName); } void EGUI::SetMap(EKeyMap *aMap, KeySel *ks) { char key[32] = ""; ActiveMap = aMap; if (ActiveMap == 0) { SetMsg(0); } else { if (ks != 0) { GetKeyName(key, *ks); SetMsg(key); } } } void EGUI::DispatchKey(GxView *view, TEvent &Event) { EEventMap *EventMap; EKeyMap *map; EKey *key = 0; char Ch; if (Event.Key.Code & kfModifier) return; LastEventChar = -1; if (GetCharFromEvent(Event, &Ch)) LastEventChar = Ch; if ((EventMap = view->GetEventMap()) == 0) return; map = EventMap->KeyMap; if (ActiveMap || OverrideMap) { map = ActiveMap; if (OverrideMap) map = OverrideMap; while (map) { if ((key = map->FindKey(Event.Key.Code)) != 0) { if (key->fKeyMap) { SetMap(key->fKeyMap, &key->fKey); Event.What = evNone; return ; } else { SetMap(0, &key->fKey); ExecMacro(view, key->Cmd); Event.What = evNone; return ; } } // printf("Going up\n"); map = map->fParent; } if (!OverrideMap) { SetMap(0, 0); Event.What = evNone; } return ; } while (EventMap) { if (map) { if ((key = map->FindKey(Event.Key.Code)) != 0) { if (key->fKeyMap) { SetMap(key->fKeyMap, &key->fKey); Event.What = evNone; return ; } else { ExecMacro(view, key->Cmd); Event.What = evNone; return ; } } } EventMap = EventMap->Parent; if (EventMap == 0) break; map = EventMap->KeyMap; } // if (GetCharFromEvent(Event, &Ch)) // CharEvent(view, Event, Ch); SetMap(0, 0); } void EGUI::DispatchCommand(GxView *view, TEvent &Event) { if (Event.Msg.Command > 65536 + 16384) { // hack for PM toolbar Event.Msg.Command -= 65536 + 16384; BeginMacro(view); ExState State; State.Macro = 0; State.Pos = 0; ExecCommand(view, Event.Msg.Command, State); Event.What = evNone; } else if (Event.Msg.Command >= 65536) { Event.Msg.Command -= 65536; ExecMacro(view, Event.Msg.Command); Event.What = evNone; } } void EGUI::DispatchEvent(GFrame *frame, GView *view, TEvent &Event) { GxView *xview = (GxView *) view; if (Event.What == evNone || (Event.What == evMouseMove && Event.Mouse.Buttons == 0)) return ; if (Event.What == evNotify && Event.Msg.Command == cmPipeRead) { Event.Msg.Model->NotifyPipe(Event.Msg.Param1); return; } if (xview->GetEventMap() != 0) { switch (Event.What) { case evKeyDown: DispatchKey(xview, Event); break; case evCommand: if (Event.Msg.Command >= 65536) { DispatchCommand(xview, Event); } else { switch (Event.Msg.Command) { case cmClose: { assert(ActiveView != 0); FrameClose(ActiveView->MView->Win); return; } } } } } GUI::DispatchEvent(frame, view, Event); #if defined(OS2) && !defined(DBMALLOC) && defined(CHECKHEAP) if (_heapchk() != _HEAPOK) DieError(0, "Heap memory is corrupt."); #endif } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// int EGUI::WinNext(GxView *view) { view->Parent->SelectNext(0); return 1; } int EGUI::WinPrev(GxView *view) { view->Parent->SelectNext(1); return 1; } int EGUI::FileCloseX(EView *View, int CreateNew, int XClose) { char Path[MAXPATH]; // this should never fail! if (GetDefaultDirectory(View->Model, Path, sizeof(Path)) == 0) return 0; if (View->Model->ConfQuit(View->MView->Win)) { View->Model->DeleteRelated(); // close everything that can be closed without confirmation if closing all if (XClose) while (View->Model->Next != View->Model && View->Model->Next->CanQuit()) delete View->Model->Next; View->DeleteModel(View->Model); #ifdef CONFIG_OBJ_DIRECTORY if (ActiveModel == 0 && CreateNew) { EView *V = ActiveView; EModel *m = new EDirectory(0, &ActiveModel, Path); assert(m != 0); do { V = V->Next; V->SelectModel(ActiveModel); } while (V != ActiveView); return 0; } #endif if (ActiveModel == 0) { StopLoop(); } return 1; } return 0; } int EGUI::FileClose(EView *View, ExState &State) { int x = 0; if (State.GetIntParam(View, &x) == 0) x = OpenAfterClose; return FileCloseX(View, x); } int EGUI::FileCloseAll(EView *View, ExState &State) { int x = 0; if (State.GetIntParam(View, &x) == 0) x = OpenAfterClose; while (ActiveModel) if (FileCloseX(View, x, 1) == 0) return 0; return 1; } int EGUI::WinHSplit(GxView *View) { GxView *view; ExModelView *edit; EView *win; int W, H; View->ConQuerySize(&W, &H); if (H < 8) return 0; view = new GxView(View->Parent); if (view == 0) return 0; win = new EView(ActiveModel); if (win == 0) return 0; edit = new ExModelView(win); if (edit == 0) return 0; view->PushView(edit); view->Parent->SelectNext(0); return 1; } int EGUI::WinClose(GxView *V) { EView *View = ActiveView; if (View->Next == View) { // when closing last window, close all files if (ExitEditor(View) == 0) return 0; } else { View->MView->Win->Parent->SelectNext(0); delete View->MView->Win; } return 1; } int EGUI::WinZoom(GxView *View) { GView *V = View->Next; GView *V1; while (V) { V1 = V; if (V == View) break; V = V->Next; delete V1; } return 1; } int EGUI::WinResize(ExState &State, GxView *View) { int Delta = 1; if (State.GetIntParam(0, &Delta)) { if (View->ExpandHeight(Delta) == 0) return 1; } return 0; } int EGUI::ExitEditor(EView *View) { EModel *B = ActiveModel; // check/save modified files while (ActiveModel) { if (ActiveModel->CanQuit()) ; else { View->SelectModel(ActiveModel); int rc = ActiveModel->ConfQuit(View->MView->Win, 1); if (rc == -2) { View->FileSaveAll(); break; } if (rc == 0) return 0; } ActiveModel = ActiveModel->Next; if (ActiveModel == B) break; } #ifdef CONFIG_DESKTOP if (SaveDesktopOnExit && DesktopFileName[0] != 0) SaveDesktop(DesktopFileName); else if (LoadDesktopMode == 2) { // Ask about saving? GxView* gx = View->MView->Win; if (gx->GetStr("Save desktop As", sizeof(DesktopFileName), DesktopFileName, HIST_DEFAULT) != 0) { SaveDesktop(DesktopFileName); } } #endif while (ActiveModel) { View->Model->DeleteRelated(); // delete related views first while (View->Model->Next != View->Model && View->Model->Next->CanQuit()) delete View->Model->Next; View->DeleteModel(View->Model); } StopLoop(); return 1; } int EGUI::ShowEntryScreen() { return gui->ShowEntryScreen(); } int EGUI::RunProgram(ExState &State, GxView *view) { static char Cmd[512] = ""; if (ActiveModel) SetDefaultDirectory(ActiveModel); if (State.GetStrParam(ActiveView, Cmd, sizeof(Cmd)) == 0) if (view->GetStr("Run", sizeof(Cmd), Cmd, HIST_COMPILE) == 0) return 0; gui->RunProgram(RUN_WAIT, Cmd); return 1; } int EGUI::RunProgramAsync(ExState &State, GxView *view) { static char Cmd[512] = ""; if (ActiveModel) SetDefaultDirectory(ActiveModel); if (State.GetStrParam(ActiveView, Cmd, sizeof(Cmd)) == 0) if (view->GetStr("Run", sizeof(Cmd), Cmd, HIST_COMPILE) == 0) return 0; gui->RunProgram(RUN_ASYNC, Cmd); return 1; } int EGUI::MainMenu(ExState &State, GxView *View) { char s[3]; if (State.GetStrParam(0, s, sizeof(s)) == 0) s[0] = 0; View->Parent->ExecMainMenu(s[0]); return 1; } int EGUI::ShowMenu(ExState &State, GxView *View) { char MName[32] = ""; if (State.GetStrParam(0, MName, sizeof(MName)) == 0) return 0; View->Parent->PopupMenu(MName); return 0; } int EGUI::LocalMenu(GxView *View) { EEventMap *Map = View->GetEventMap(); const char *MName = 0; if (Map) MName = Map->GetMenu(EM_LocalMenu); if (MName == 0) MName = "Local"; View->Parent->PopupMenu(MName); return 0; } int EGUI::DesktopSaveAs(ExState &State, GxView *view) { if (State.GetStrParam(0, DesktopFileName, sizeof(DesktopFileName)) == 0) if (view->GetFile("Save Desktop", sizeof(DesktopFileName), DesktopFileName, HIST_PATH, GF_SAVEAS) == 0) return 0; if (DesktopFileName[0] != 0) return SaveDesktop(DesktopFileName); return 0; } int EGUI::FrameNew() { GxView *view; ExModelView *edit; if (!multiFrame() && frames) return 0; (void)new EFrame(ScreenSizeX, ScreenSizeY); assert(frames != 0); //frames->SetMenu("Main"); //?? view = new GxView(frames); assert(view != 0); (void)new EView(ActiveModel); assert(ActiveView != 0); edit = new ExModelView(ActiveView); assert(edit != 0); view->PushView(edit); frames->Show(); return 1; } int EGUI::FrameClose(GxView *View) { assert(frames != 0); assert(View != 0); if (!frames->isLastFrame()) { deleteFrame(frames); } else { if (ExitEditor(ActiveView) == 0) return 0; deleteFrame(frames); } return 1; } int EGUI::FrameNext(GxView *View) { if (!frames->isLastFrame()) { frames->Next->Activate(); return 1; } return 0; } int EGUI::FramePrev(GxView *View) { if (!frames->isLastFrame()) { frames->Prev->Activate(); return 1; } return 0; } #ifdef CONFIG_DESKTOP int EGUI::findDesktop(char *argv[]) { /* * Locates the desktop file depending on the load desktop mode flag: * 0: Try the "current" directory, then the FTE .exe directory (PC) or * the user's homedir (Unix). Fail if not found (original FTE * algorithm). * 1: Try the current directory, then loop {go one directory UP and try} * If not found, don't load a desktop! * 2: As above, but asks to save the desktop if one was not found. * This is called if the desktop is not spec'd on the command line. */ switch (LoadDesktopMode) { default: //** 0: try curdir then "homedir".. // fprintf(stderr, "ld: Mode 0\n"); if (FileExists(DESKTOP_NAME)) ExpandPath(DESKTOP_NAME, DesktopFileName); else { //** Use homedir, #ifdef UNIX ExpandPath("~/" DESKTOP_NAME, DesktopFileName); #else JustDirectory(argv[0], DesktopFileName); strcat(DesktopFileName, DESKTOP_NAME); #endif } return FileExists(DesktopFileName); case 1: case 2: //** Try curdir, then it's owner(s).. ExpandPath(".", DesktopFileName); //fprintf(stderr, "ld: Mode 1 (start at %s)\n", DesktopFileName); for (;;) { //** Try current location, char *pe = DesktopFileName + strlen(DesktopFileName); Slash(DesktopFileName, 1); // Add appropriate slash strcat(DesktopFileName, DESKTOP_NAME); //fprintf(stderr, "ld: Mode 1 (trying %s)\n", DesktopFileName); if (FileExists(DesktopFileName)) { //fprintf(stderr, "ld: Mode 1 (using %s)\n", DesktopFileName); return 1; } //** Not found. Remove added stuff, then go level UP, *pe = 0; // Remove the current part, char *p = SepRChr(DesktopFileName); if (p == NULL) { //** No desktop! Set default name in current directory, ExpandPath(".", DesktopFileName); Slash(DesktopFileName, 1); strcat(DesktopFileName, DESKTOP_NAME); SaveDesktopOnExit = 0; // Don't save, return 0; // NOT found!! } *p = 0; // Truncate name at last } } } void EGUI::DoLoadDesktopOnEntry(int &/*argc*/, char **argv) { if (DesktopFileName[0] == 0) findDesktop(argv); if (DesktopFileName[0] != 0) { if (IsDirectory(DesktopFileName)) { Slash(DesktopFileName, 1); strcat(DesktopFileName, DESKTOP_NAME); } if (LoadDesktopOnEntry && FileExists(DesktopFileName)) LoadDesktop(DesktopFileName); } } #endif void EGUI::EditorInit() { SSBuffer = new EBuffer(0, (EModel **)&SSBuffer, "Scrap"); assert(SSBuffer != 0); BFI(SSBuffer, BFI_Undo) = 0; // disable undo for clipboard ActiveModel = 0; } int EGUI::InterfaceInit(int &argc, char **argv) { if (FrameNew() == 0) DieError(1, "Failed to create window\n"); return 0; } #ifdef CONFIG_HISTORY void EGUI::DoLoadHistoryOnEntry(int &argc, char **argv) { if (HistoryFileName[0] == 0) { #ifdef UNIX ExpandPath("~/.fte-history", HistoryFileName); #else JustDirectory(argv[0], HistoryFileName); strcat(HistoryFileName, "fte.his"); #endif } else { char p[256]; ExpandPath(HistoryFileName, p); if (IsDirectory(p)) { Slash(p, 1); strcat(p, HISTORY_NAME); } strcpy(HistoryFileName, p); } if (KeepHistory && FileExists(HistoryFileName)) LoadHistory(HistoryFileName); } void EGUI::DoSaveHistoryOnExit() { if (KeepHistory && HistoryFileName[0] != 0) SaveHistory(HistoryFileName); // since we are exiting, free history ClearHistory(); } #endif int EGUI::CmdLoadFiles(int &argc, char **argv) { int QuoteNext = 0; int QuoteAll = 0; int GotoLine = 0; int LineNum = 1; int ColNum = 1; int ModeOverride = 0; char Mode[32]; int LCount = 0; int ReadOnly = 0; for (int Arg = 1; Arg < argc; Arg++) { if (!QuoteAll && !QuoteNext && (argv[Arg][0] == '-')) { if (argv[Arg][1] == '-') { QuoteAll = 1; } else if (argv[Arg][1] == '!') { // handled before } else if (argv[Arg][1] == 'c' || argv[Arg][1] == 'C') { // ^ } else if (argv[Arg][1] == 'D' || argv[Arg][1] == 'd') { // ^ } else if (argv[Arg][1] == 'H') { // ^ } else if (argv[Arg][1] == '+') { QuoteNext = 1; } else if (argv[Arg][1] == '#' || argv[Arg][1] == 'l') { LineNum = 1; ColNum = 1; if (strchr(argv[Arg], ',')) { GotoLine = (2 == sscanf(argv[Arg] + 2, "%d,%d", &LineNum, &ColNum)); } else { GotoLine = (1 == sscanf(argv[Arg] + 2, "%d", &LineNum)); } // printf("Gotoline = %d, line = %d, col = %d\n", GotoLine, LineNum, ColNum); } else if (argv[Arg][1] == 'r') { ReadOnly = 1; } else if (argv[Arg][1] == 'm') { if (argv[Arg][2] == 0) { ModeOverride = 0; } else { ModeOverride = 1; strcpy(Mode, argv[Arg] + 2); } } else if (argv[Arg][1] == 'T') { TagsAdd(argv[Arg] + 2); } else if (argv[Arg][1] == 't') { TagGoto(ActiveView, argv[Arg] + 2); } else { DieError(2, "Invalid command line option %s", argv[Arg]); return 0; } } else { char Path[MAXPATH]; QuoteNext = 0; if (ExpandPath(argv[Arg], Path) == 0 && IsDirectory(Path)) { EModel *m = new EDirectory(cfAppend, &ActiveModel, Path); assert(ActiveModel != 0 && m != 0); } else { if (LCount != 0) suspendLoads = 1; if (MultiFileLoad(cfAppend, argv[Arg], ModeOverride ? Mode : 0, ActiveView) == 0) { suspendLoads = 0; return 0; } suspendLoads = 0; if (GotoLine) { if (((EBuffer *)ActiveModel)->Loaded == 0) ((EBuffer *)ActiveModel)->Load(); if (GotoLine) { GotoLine = 0; ((EBuffer *)ActiveModel)->SetNearPosR(ColNum - 1, LineNum - 1); } else { int r, c; if (RetrieveFPos(((EBuffer *)ActiveModel)->FileName, r, c) == 1) ((EBuffer *)ActiveModel)->SetNearPosR(c, r); } //ActiveView->SelectModel(ActiveModel); } if (ReadOnly) { ReadOnly = 0; BFI(((EBuffer *)ActiveModel), BFI_ReadOnly) = 1; } } suspendLoads = 1; ActiveView->SelectModel(ActiveModel->Next); suspendLoads = 0; LCount++; } } EModel *P = ActiveModel; while (LCount-- > 0) P = P->Prev; ActiveView->SelectModel(P); return 1; } int EGUI::Start(int &argc, char **argv) { { int rc; rc = GUI::Start(argc, argv); if (rc) return rc; } if (InterfaceInit(argc, argv) != 0) return 2; EditorInit(); #ifdef CONFIG_HISTORY DoLoadHistoryOnEntry(argc, argv); #endif #ifdef CONFIG_DESKTOP DoLoadDesktopOnEntry(argc, argv); #endif if (CmdLoadFiles(argc, argv) == 0) return 3; if (ActiveModel == 0) { #ifdef CONFIG_OBJ_DIRECTORY char Path[MAXPATH]; GetDefaultDirectory(0, Path, sizeof(Path)); EModel *m = new EDirectory(0, &ActiveModel, Path); assert(ActiveModel != 0 && m != 0); ActiveView->SwitchToModel(ActiveModel); #else Usage(); return 1; #endif } return 0; } void EGUI::EditorCleanup() { if (ActiveModel) { EModel *B, *N, *A; B = A = ActiveModel; do { N = B->Next; delete B; B = N; } while (B != A); } ActiveModel = 0; delete SSBuffer; SSBuffer = 0; if (ActiveView) { EView *BW, *NW, *AW; BW = AW = ActiveView; do { NW = BW->Next; delete BW; BW = NW; } while (BW != AW); } ActiveView = 0; } void EGUI::InterfaceCleanup() { while (frames) delete frames; } void EGUI::Stop() { #ifdef CONFIG_HISTORY DoSaveHistoryOnExit(); #endif // free macros if (Macros!=NULL) { int i; while (CMacros--) { free(Macros[CMacros].Name); for (i=0; iNext; delete p; } } // free event maps { EEventMap *em; while ((em = EventMaps) != NULL) { EventMaps = EventMaps->Next; delete em; } } // free modes { EMode *m; while ((m = Modes) != NULL) { Modes = Modes->fNext; delete m; } } // free menus if (Menus) { int mc, c; while(MenuCount--) { mc = MenuCount; free(Menus[mc].Name); while(Menus[mc].Count--) { c = Menus[mc].Count; free(Menus[mc].Items[c].Name); } free(Menus[MenuCount].Items); } free(Menus); Menus = NULL; } // free completion rexexp filter { extern RxNode *CompletionFilter; RxFree(CompletionFilter); } // free CRegexp array from o_messages.cpp { FreeCRegexp(); } // free configuration file path { free(ConfigSourcePath); ConfigSourcePath = NULL; } EditorCleanup(); InterfaceCleanup(); GUI::Stop(); }