/* manager.cpp Переключение между несколькими file panels, viewers, editors, dialogs */ /* Copyright (c) 1996 Eugene Roshal Copyright (c) 2000 Far Group All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "headers.hpp" #include "manager.hpp" #include "lang.hpp" #include "keys.hpp" #include "frame.hpp" #include "vmenu.hpp" #include "filepanels.hpp" #include "panel.hpp" #include "savescr.hpp" #include "cmdline.hpp" #include "ctrlobj.hpp" #include "syslog.hpp" #include "interf.hpp" #include "keyboard.hpp" #include "grabber.hpp" #include "message.hpp" #include "config.hpp" #include "plist.hpp" #include "pathmix.hpp" #include "strmix.hpp" #include "exitcode.hpp" #include "scrbuf.hpp" #include "console.hpp" #include "InterThreadCall.hpp" Manager *FrameManager; Manager::Manager(): ModalStack(nullptr), ModalStackCount(0), ModalStackSize(0), FrameCount(0), FrameList(reinterpret_cast(malloc(sizeof(Frame*)*(FrameCount+1)))), FrameListSize(0), FramePos(-1), InsertedFrame(nullptr), DeletedFrame(nullptr), ActivatedFrame(nullptr), RefreshedFrame(nullptr), ModalizedFrame(nullptr), UnmodalizedFrame(nullptr), DeactivatedFrame(nullptr), ExecutedFrame(nullptr), CurrentFrame(nullptr), ModalEVCount(0), EndLoop(FALSE), StartManager(FALSE) { } Manager::~Manager() { if (FrameList) free(FrameList); if (ModalStack) free(ModalStack); /*if (SemiModalBackFrames) free(SemiModalBackFrames);*/ } /* $ 29.12.2000 IS Аналог CloseAll, но разрешает продолжение полноценной работы в фаре, если пользователь продолжил редактировать файл. Возвращает TRUE, если все закрыли и можно выходить из фара. */ BOOL Manager::ExitAll() { _MANAGER(CleverSysLog clv(L"Manager::ExitAll()")); for (int i=this->ModalStackCount-1; i>=0; i--) { Frame *iFrame=this->ModalStack[i]; if (!iFrame->GetCanLoseFocus(TRUE)) { int PrevFrameCount=ModalStackCount; iFrame->ProcessKey(KEY_ESC); Commit(); if (PrevFrameCount==ModalStackCount) { return FALSE; } } } for (int i=FrameCount-1; i>=0; i--) { Frame *iFrame=FrameList[i]; if (!iFrame->GetCanLoseFocus(TRUE)) { ActivateFrame(iFrame); Commit(); int PrevFrameCount=FrameCount; iFrame->ProcessKey(KEY_ESC); Commit(); if (PrevFrameCount==FrameCount) { return FALSE; } } } return TRUE; } void Manager::CloseAll() { _MANAGER(CleverSysLog clv(L"Manager::CloseAll()")); Frame *iFrame; for (int i=ModalStackCount-1; i>=0; i--) { iFrame=ModalStack[i]; DeleteFrame(iFrame); DeleteCommit(); DeletedFrame=nullptr; } for (int i=FrameCount-1; i>=0; i--) { iFrame=(*this)[i]; DeleteFrame(iFrame); DeleteCommit(); DeletedFrame=nullptr; } free(FrameList); FrameList=nullptr; FrameCount=FramePos=0; } BOOL Manager::IsAnyFrameModified(int Activate) { for (int I=0; IIsFileModified()) { if (Activate) { ActivateFrame(I); Commit(); } return TRUE; } return FALSE; } void Manager::InsertFrame(Frame *Inserted, int Index) { _MANAGER(CleverSysLog clv(L"Manager::InsertFrame(Frame *Inserted, int Index)")); _MANAGER(SysLog(L"Inserted=%p, Index=%i",Inserted, Index)); if (Index==-1) Index=FramePos; InsertedFrame=Inserted; } void Manager::DeleteFrame(Frame *Deleted) { _MANAGER(CleverSysLog clv(L"Manager::DeleteFrame(Frame *Deleted)")); _MANAGER(SysLog(L"Deleted=%p",Deleted)); for (int i=0; iRemoveModal(Deleted)) { return; } } if (!Deleted) { DeletedFrame=CurrentFrame; } else { DeletedFrame=Deleted; } } void Manager::DeleteFrame(int Index) { _MANAGER(CleverSysLog clv(L"Manager::DeleteFrame(int Index)")); _MANAGER(SysLog(L"Index=%i",Index)); DeleteFrame(this->operator[](Index)); } void Manager::ModalizeFrame(Frame *Modalized, int Mode) { _MANAGER(CleverSysLog clv(L"Manager::ModalizeFrame (Frame *Modalized, int Mode)")); _MANAGER(SysLog(L"Modalized=%p",Modalized)); ModalizedFrame=Modalized; ModalizeCommit(); } void Manager::UnmodalizeFrame(Frame *Unmodalized) { _MANAGER(CleverSysLog clv(L"Manager::UnmodalizeFrame (Frame *Unmodalized)")); _MANAGER(SysLog(L"Unmodalized=%p",Unmodalized)); UnmodalizedFrame=Unmodalized; UnmodalizeCommit(); } void Manager::ExecuteNonModal() { _MANAGER(CleverSysLog clv(L"Manager::ExecuteNonModal ()")); _MANAGER(SysLog(L"ExecutedFrame=%p, InsertedFrame=%p, DeletedFrame=%p",ExecutedFrame, InsertedFrame, DeletedFrame)); Frame *NonModal=InsertedFrame?InsertedFrame:(ExecutedFrame?ExecutedFrame:ActivatedFrame); if (!NonModal) { return; } /* $ 14.05.2002 SKV Положим текущий фрэйм в список "родителей" полумодальных фрэймов */ //Frame *SaveFrame=CurrentFrame; //AddSemiModalBackFrame(SaveFrame); int NonModalIndex=IndexOf(NonModal); if (-1==NonModalIndex) { InsertedFrame=NonModal; ExecutedFrame=nullptr; InsertCommit(); InsertedFrame=nullptr; } else { ActivateFrame(NonModalIndex); } //Frame* ModalStartLevel=NonModal; for (;;) { Commit(); if (CurrentFrame!=NonModal || EndLoop) { break; } ProcessMainLoop(); } //ExecuteModal(NonModal); /* $ 14.05.2002 SKV ... и уберём его же. */ //RemoveSemiModalBackFrame(SaveFrame); } void Manager::ExecuteModal(Frame *Executed) { _MANAGER(CleverSysLog clv(L"Manager::ExecuteModal (Frame *Executed)")); _MANAGER(SysLog(L"Executed=%p, ExecutedFrame=%p",Executed,ExecutedFrame)); if (!Executed && !ExecutedFrame) { fprintf(stderr, "ExecuteModal1\n"); return; } if (Executed) { if (ExecutedFrame) { fprintf(stderr, "ExecuteModal2\n"); _MANAGER(SysLog(L"WARNING! Попытка в одном цикле запустить в модальном режиме два фрейма. Executed=%p, ExecitedFrame=%p",Executed, ExecutedFrame)); return;// nullptr; //?? Определить, какое значение правильно возвращать в этом случае } else { ExecutedFrame=Executed; } } int ModalStartLevel=ModalStackCount; int OriginalStartManager=StartManager; StartManager=TRUE; for (;;) { Commit(); if (ModalStackCount<=ModalStartLevel) { break; } ProcessMainLoop(); } StartManager=OriginalStartManager; return;// GetModalExitCode(); } int Manager::GetModalExitCode() { return ModalExitCode; } /* $ 11.10.2001 IS Подсчитать количество фреймов с указанным именем. */ int Manager::CountFramesWithName(const wchar_t *Name, BOOL IgnoreCase) { int Counter=0; typedef int (__cdecl *cmpfunc_t)(const wchar_t *s1, const wchar_t *s2); cmpfunc_t cmpfunc=IgnoreCase ? StrCmpI : StrCmp; FARString strType, strCurName; for (int I=0; IGetTypeAndName(strType, strCurName); if (!cmpfunc(Name, strCurName)) ++Counter; } return Counter; } /*! \return Возвращает nullptr если нажат "отказ" или если нажат текущий фрейм. Другими словами, если немодальный фрейм не поменялся. Если же фрейм поменялся, то тогда функция должна возвратить указатель на предыдущий фрейм. */ Frame *Manager::FrameMenu() { /* $ 28.04.2002 KM Флаг для определения того, что меню переключения экранов уже активировано. */ static int AlreadyShown=FALSE; if (AlreadyShown) return nullptr; int ExitCode, CheckCanLoseFocus=CurrentFrame->GetCanLoseFocus(); { MenuItemEx ModalMenuItem; VMenu ModalMenu(Msg::ScreensTitle,nullptr,0,ScrY-4); ModalMenu.SetHelp(L"ScrSwitch"); ModalMenu.SetFlags(VMENU_WRAPMODE); ModalMenu.SetPosition(-1,-1,0,0); if (!CheckCanLoseFocus) ModalMenuItem.SetDisable(TRUE); for (int I=0; IGetTypeAndName(strType, strName); ModalMenuItem.Clear(); if (I<10) strNumText.Format(L"&%d. ",I); else if (I<36) strNumText.Format(L"&%lc. ",I+55); // 55='A'-10 else strNumText = L"& "; //TruncPathStr(strName,ScrX-24); ReplaceStrings(strName,L"&",L"&&",-1); /* добавляется "*" если файл изменен */ ModalMenuItem.strName.Format(L"%ls%-10.10ls %lc %ls", strNumText.CPtr(), strType.CPtr(),(FrameList[I]->IsFileModified()?L'*':L' '), strName.CPtr()); ModalMenuItem.SetSelect(I==FramePos); ModalMenu.AddItem(&ModalMenuItem); } AlreadyShown=TRUE; ModalMenu.Process(); AlreadyShown=FALSE; ExitCode=ModalMenu.Modal::GetExitCode(); } if (CheckCanLoseFocus) { if (ExitCode>=0) { ActivateFrame(ExitCode); return (ActivatedFrame==CurrentFrame || !CurrentFrame->GetCanLoseFocus()?nullptr:CurrentFrame); } return (ActivatedFrame==CurrentFrame?nullptr:CurrentFrame); } return nullptr; } int Manager::GetFrameCountByType(int Type) { int ret=0; for (int I=0; IGetExitCode() == XC_QUIT) continue; if (FrameList[I]->GetType()==Type) ret++; } return ret; } void Manager::SetFramePos(int NewPos) { _MANAGER(CleverSysLog clv(L"Manager::SetFramePos(int NewPos)")); _MANAGER(SysLog(L"NewPos=%i",NewPos)); FramePos=NewPos; } /*$ 11.05.2001 OT Теперь можно искать файл не только по полному имени, но и отдельно - путь, отдельно имя */ int Manager::FindFrameByFile(int ModalType,const wchar_t *FileName, const wchar_t *Dir) { FARString strBufFileName; FARString strFullFileName = FileName; if (Dir) { strBufFileName = Dir; AddEndSlash(strBufFileName); strBufFileName += FileName; strFullFileName = strBufFileName; } for (int I=0; IGetType()==ModalType) { FrameList[I]->GetTypeAndName(strType, strName); if (!StrCmpI(strName, strFullFileName)) return(I); } } return -1; } BOOL Manager::ShowBackground() { if (CtrlObject->CmdLine) { CtrlObject->CmdLine->ShowBackground(); return TRUE; } return FALSE; } void Manager::ActivateFrame(Frame *Activated) { _MANAGER(CleverSysLog clv(L"Manager::ActivateFrame(Frame *Activated)")); _MANAGER(SysLog(L"Activated=%i",Activated)); if (IndexOf(Activated)==-1 && IndexOfStack(Activated)==-1) return; if (!ActivatedFrame) { ActivatedFrame=Activated; } } void Manager::ActivateFrame(int Index) { _MANAGER(CleverSysLog clv(L"Manager::ActivateFrame(int Index)")); _MANAGER(SysLog(L"Index=%i",Index)); ActivateFrame((*this)[Index]); } void Manager::DeactivateFrame(Frame *Deactivated,int Direction) { _MANAGER(CleverSysLog clv(L"Manager::DeactivateFrame (Frame *Deactivated,int Direction)")); _MANAGER(SysLog(L"Deactivated=%p, Direction=%d",Deactivated,Direction)); if (Direction) { FramePos+=Direction; if (Direction>0) { if (FramePos>=FrameCount) { FramePos=0; } } else { if (FramePos<0) { FramePos=FrameCount-1; } } ActivateFrame(FramePos); } else { // Direction==0 // Direct access from menu or (in future) from plugin } DeactivatedFrame=Deactivated; } void Manager::SwapTwoFrame(int Direction) { if (Direction) { int OldFramePos=FramePos; FramePos+=Direction; if (Direction>0) { if (FramePos>=FrameCount) { FramePos=0; } } else { if (FramePos<0) { FramePos=FrameCount-1; } } Frame *TmpFrame=FrameList[OldFramePos]; FrameList[OldFramePos]=FrameList[FramePos]; FrameList[FramePos]=TmpFrame; ActivateFrame(OldFramePos); } DeactivatedFrame=CurrentFrame; } void Manager::RefreshFrame(Frame *Refreshed) { _MANAGER(CleverSysLog clv(L"Manager::RefreshFrame(Frame *Refreshed)")); _MANAGER(SysLog(L"Refreshed=%p",Refreshed)); if (ActivatedFrame) return; if (Refreshed) { RefreshedFrame=Refreshed; } else { RefreshedFrame=CurrentFrame; } if (IndexOf(Refreshed)==-1 && IndexOfStack(Refreshed)==-1) return; /* $ 13.04.2002 KM - Вызываем принудительный Commit() для фрейма имеющего члена NextModal, это означает что активным сейчас является VMenu, а значит Commit() сам не будет вызван после возврата из функции. Устраняет ещё один момент неперерисовки, когда один над другим находится несколько объектов VMenu. Пример: настройка цветов. Теперь AltF9 в диалоге настройки цветов корректно перерисовывает меню. */ if (RefreshedFrame && RefreshedFrame->NextModal) Commit(); } void Manager::RefreshFrame(int Index) { _MANAGER(CleverSysLog clv(L"Manager::RefreshFrame(int Index)")); _MANAGER(SysLog(L"Index=%d",Index)); RefreshFrame((*this)[Index]); } void Manager::ExecuteFrame(Frame *Executed) { _MANAGER(CleverSysLog clv(L"Manager::ExecuteFrame(Frame *Executed)")); _MANAGER(SysLog(L"Executed=%p",Executed)); ExecutedFrame=Executed; } /* $ 10.05.2001 DJ переключается на панели (фрейм с номером 0) */ void Manager::SwitchToPanels() { _MANAGER(CleverSysLog clv(L"Manager::SwitchToPanels()")); ActivateFrame(0); } int Manager::HaveAnyFrame() { if (FrameCount || InsertedFrame || DeletedFrame || ActivatedFrame || RefreshedFrame || ModalizedFrame || DeactivatedFrame || ExecutedFrame || CurrentFrame) return 1; return 0; } void Manager::EnterMainLoop() { WaitInFastFind=0; StartManager=TRUE; for (;;) { Commit(); if (EndLoop || !HaveAnyFrame()) { break; } ProcessMainLoop(); } } void Manager::SetLastInputRecord(INPUT_RECORD *Rec) { if (&LastInputRecord != Rec) LastInputRecord=*Rec; } void Manager::ProcessMainLoop() { if ( CurrentFrame ) CtrlObject->Macro.SetMode(CurrentFrame->GetMacroMode()); DispatchInterThreadCalls(); if ( CurrentFrame && !CurrentFrame->ProcessEvents() ) { ProcessKey(KEY_IDLE); } else { // Mantis#0000073: Не работает автоскролинг в QView WaitInMainLoop=IsPanelsActive() && ((FilePanels*)CurrentFrame)->ActivePanel->GetType()!=QVIEW_PANEL; //WaitInFastFind++; int Key=GetInputRecord(&LastInputRecord); //WaitInFastFind--; WaitInMainLoop=FALSE; if (EndLoop) return; if (LastInputRecord.EventType==MOUSE_EVENT) { // используем копию структуры, т.к. LastInputRecord может внезапно измениться во время выполнения ProcessMouse MOUSE_EVENT_RECORD mer=LastInputRecord.Event.MouseEvent; ProcessMouse(&mer); } else ProcessKey(Key); } } static bool ConfirmExit() { int r; if (WINPORT(ConsoleBackgroundMode)(FALSE)) { r = Message(0,3,Msg::Quit,Msg::AskQuit,Msg::Yes,Msg::No,Msg::Background); if (r == 2) { WINPORT(ConsoleBackgroundMode)(TRUE); } } else { r = Message(0,2,Msg::Quit,Msg::AskQuit,Msg::Yes,Msg::No); } return r == 0; } void Manager::ExitMainLoop(int Ask) { if (CloseFAR) { CloseFAR=FALSE; CloseFARMenu=TRUE; }; if (!Ask || ((!Opt.Confirm.Exit || ConfirmExit()) && CtrlObject->Plugins.MayExitFar())) { /* $ 29.12.2000 IS + Проверяем, сохранены ли все измененные файлы. Если нет, то не выходим из фара. */ if (ExitAll()) { //TODO: при закрытии по x нужно делать форсированный выход. Иначе могут быть // глюки, например, при перезагрузке FilePanels *cp; if (!(cp = CtrlObject->Cp()) || (!cp->LeftPanel->ProcessPluginEvent(FE_CLOSE,nullptr) && !cp->RightPanel->ProcessPluginEvent(FE_CLOSE,nullptr))) { EndLoop=TRUE; } } else { CloseFARMenu=FALSE; } } } #if defined(FAR_ALPHA_VERSION) #include #if defined(_MSC_VER) #pragma warning( push ) #pragma warning( disable : 4717) //#ifdef __cplusplus //#if defined(_MSC_VER < 1500) // TODO: See REMINDER file, section intrin.h #ifndef _M_IA64 extern "C" void __ud2(); #else extern "C" void __setReg(int, uint64_t); #endif //#endif // TODO: See REMINDER file, section intrin.h //#endif #endif static void Test_EXCEPTION_STACK_OVERFLOW(char* target) { char Buffer[1024]; /* чтобы быстрее рвануло */ strcpy(Buffer, "zzzz"); Test_EXCEPTION_STACK_OVERFLOW(Buffer); } #if defined(_MSC_VER) #pragma warning( pop ) #endif #endif int Manager::ProcessKey(DWORD Key) { int ret=FALSE; if (CurrentFrame) { DWORD KeyM=(Key&(~KEY_CTRLMASK)); if (!((KeyM >= KEY_MACRO_BASE && KeyM <= KEY_MACRO_ENDBASE) || (KeyM >= KEY_OP_BASE && KeyM <= KEY_OP_ENDBASE))) // пропустим макро-коды { switch (CurrentFrame->GetType()) { case MODALTYPE_PANELS: { _ALGO(CleverSysLog clv(L"Manager::ProcessKey()")); _ALGO(SysLog(L"Key=%ls",_FARKEY_ToName(Key))); if (CtrlObject->Cp()->ActivePanel->SendKeyToPlugin(Key,TRUE)) return TRUE; break; } case MODALTYPE_VIEWER: //if(((FileViewer*)CurrentFrame)->ProcessViewerInput(FrameManager->GetLastInputRecord())) // return TRUE; break; case MODALTYPE_EDITOR: //if(((FileEditor*)CurrentFrame)->ProcessEditorInput(FrameManager->GetLastInputRecord())) // return TRUE; break; case MODALTYPE_DIALOG: //((Dialog*)CurrentFrame)->CallDlgProc(DN_KEY,((Dialog*)CurrentFrame)->GetDlgFocusPos(),Key); break; case MODALTYPE_VMENU: case MODALTYPE_HELP: case MODALTYPE_COMBOBOX: case MODALTYPE_USER: case MODALTYPE_FINDFOLDER: default: break; } } /*** БЛОК ПРИВЕЛЕГИРОВАННЫХ КЛАВИШ ! ***/ /*** КОТОРЫЕ НЕЛЬЗЯ НАМАКРОСИТЬ ***/ switch (Key) { case KEY_ALT|KEY_NUMPAD0: case KEY_ALTINS: { RunGraber(); return TRUE; } case KEY_CONSOLE_BUFFER_RESIZE: WINPORT(Sleep)(10); ResizeAllFrame(); return TRUE; } /*** А вот здесь - все остальное! ***/ if (!IsProcessAssignMacroKey) // в любом случае если кому-то ненужны все клавиши или { switch (Key) { // <Удалить после появления макрофункции Scroll> case KEY_CTRLALTUP: if(Opt.WindowMode) { Console.ScrollWindow(-1); return TRUE; } break; case KEY_CTRLALTDOWN: if(Opt.WindowMode) { Console.ScrollWindow(1); return TRUE; } break; case KEY_CTRLALTPGUP: if(Opt.WindowMode) { Console.ScrollWindow(-ScrY); return TRUE; } break; case KEY_CTRLALTHOME: if(Opt.WindowMode) { while(Console.ScrollWindow(-ScrY)); return TRUE; } break; case KEY_CTRLALTPGDN: if(Opt.WindowMode) { Console.ScrollWindow(ScrY); return TRUE; } break; case KEY_CTRLALTEND: if(Opt.WindowMode) { while(Console.ScrollWindow(ScrY)); return TRUE; } break; // case KEY_CTRLW: ShowProcessList(); return TRUE; case KEY_F11: PluginsMenu(); FrameManager->RefreshFrame(); //_MANAGER(SysLog(-1)); return TRUE; case KEY_ALTF9: { //_MANAGER(SysLog(1,"Manager::ProcessKey, KEY_ALTF9 pressed...")); WINPORT(Sleep)(10); SetVideoMode(); WINPORT(Sleep)(10); /* В процессе исполнения Alt-F9 (в нормальном режиме) в очередь консоли попадает WINDOW_BUFFER_SIZE_EVENT, формируется в ChangeVideoMode(). В режиме исполнения макросов ЭТО не происходит по вполне понятным причинам. */ if (CtrlObject->Macro.IsExecuting()) { int PScrX=ScrX; int PScrY=ScrY; WINPORT(Sleep)(10); GetVideoMode(CurSize); if (PScrX+1 == CurSize.X && PScrY+1 == CurSize.Y) { //_MANAGER(SysLog(-1,"GetInputRecord(WINDOW_BUFFER_SIZE_EVENT); return KEY_NONE")); return TRUE; } else { PrevScrX=PScrX; PrevScrY=PScrY; //_MANAGER(SysLog(-1,"GetInputRecord(WINDOW_BUFFER_SIZE_EVENT); return KEY_CONSOLE_BUFFER_RESIZE")); WINPORT(Sleep)(10); return ProcessKey(KEY_CONSOLE_BUFFER_RESIZE); } } //_MANAGER(SysLog(-1)); return TRUE; } case KEY_F12: { int TypeFrame=FrameManager->GetCurrentFrame()->GetType(); if (TypeFrame != MODALTYPE_HELP && TypeFrame != MODALTYPE_DIALOG) { DeactivateFrame(FrameMenu(),0); //_MANAGER(SysLog(-1)); return TRUE; } break; // отдадим F12 дальше по цепочке } case KEY_CTRLALTSHIFTPRESS: case KEY_RCTRLALTSHIFTPRESS: { if (!(Opt.CASRule&1) && Key == KEY_CTRLALTSHIFTPRESS) break; if (!(Opt.CASRule&2) && Key == KEY_RCTRLALTSHIFTPRESS) break; if (!Opt.OnlyEditorViewerUsed) { if (CurrentFrame->FastHide()) { int isPanelFocus=CurrentFrame->GetType() == MODALTYPE_PANELS; if (isPanelFocus) { int LeftVisible=CtrlObject->Cp()->LeftPanel->IsVisible(); int RightVisible=CtrlObject->Cp()->RightPanel->IsVisible(); int CmdLineVisible=CtrlObject->CmdLine->IsVisible(); int KeyBarVisible=CtrlObject->Cp()->MainKeyBar.IsVisible(); CtrlObject->CmdLine->ShowBackground(); CtrlObject->Cp()->LeftPanel->Hide0(); CtrlObject->Cp()->RightPanel->Hide0(); switch (Opt.PanelCtrlAltShiftRule) { case 0: CtrlObject->CmdLine->Show(); CtrlObject->Cp()->MainKeyBar.Refresh(true); break; case 1: CtrlObject->Cp()->MainKeyBar.Refresh(true); break; } WaitKey(Key==KEY_CTRLALTSHIFTPRESS?KEY_CTRLALTSHIFTRELEASE:KEY_RCTRLALTSHIFTRELEASE); if (LeftVisible) CtrlObject->Cp()->LeftPanel->Show(); if (RightVisible) CtrlObject->Cp()->RightPanel->Show(); if (CmdLineVisible) CtrlObject->CmdLine->Show(); CtrlObject->Cp()->MainKeyBar.Refresh(KeyBarVisible); } else { ImmediateHide(); WaitKey(Key==KEY_CTRLALTSHIFTPRESS?KEY_CTRLALTSHIFTRELEASE:KEY_RCTRLALTSHIFTRELEASE); } FrameManager->RefreshFrame(); } return TRUE; } break; } case KEY_CTRLTAB: case KEY_CTRLSHIFTTAB: if (CurrentFrame->GetCanLoseFocus()) { DeactivateFrame(CurrentFrame,Key==KEY_CTRLTAB?1:-1); } _MANAGER(SysLog(-1)); return TRUE; } } CurrentFrame->UpdateKeyBar(); CurrentFrame->ProcessKey(Key); } _MANAGER(SysLog(-1)); return ret; } int Manager::ProcessMouse(MOUSE_EVENT_RECORD *MouseEvent) { // При каптюренной мыши отдаем управление заданному объекту // if (ScreenObject::CaptureMouseObject) // return ScreenObject::CaptureMouseObject->ProcessMouse(MouseEvent); int ret=FALSE; // _D(SysLog(1,"Manager::ProcessMouse()")); if (CurrentFrame) ret=CurrentFrame->ProcessMouse(MouseEvent); // _D(SysLog(L"Manager::ProcessMouse() ret=%i",ret)); _MANAGER(SysLog(-1)); return ret; } void Manager::PluginsMenu() { _MANAGER(SysLog(1)); int curType = CurrentFrame->GetType(); if (curType == MODALTYPE_PANELS || curType == MODALTYPE_EDITOR || curType == MODALTYPE_VIEWER || curType == MODALTYPE_DIALOG) { /* 02.01.2002 IS ! Вывод правильной помощи по Shift-F1 в меню плагинов в редакторе/вьюере/диалоге ! Если на панели QVIEW или INFO открыт файл, то считаем, что это полноценный вьюер и запускаем с соответствующим параметром плагины */ if (curType==MODALTYPE_PANELS) { int pType=CtrlObject->Cp()->ActivePanel->GetType(); if (pType==QVIEW_PANEL || pType==INFO_PANEL) { FARString strType, strCurFileName; CtrlObject->Cp()->GetTypeAndName(strType, strCurFileName); if (!strCurFileName.IsEmpty()) { DWORD Attr=apiGetFileAttributes(strCurFileName); // интересуют только обычные файлы if (Attr!=INVALID_FILE_ATTRIBUTES && !(Attr&FILE_ATTRIBUTE_DIRECTORY)) curType=MODALTYPE_VIEWER; } } } // в редакторе, вьюере или диалоге покажем свою помощь по Shift-F1 const wchar_t *Topic=curType==MODALTYPE_EDITOR?L"Editor": curType==MODALTYPE_VIEWER?L"Viewer": curType==MODALTYPE_DIALOG?L"Dialog":nullptr; CtrlObject->Plugins.CommandsMenu(curType,0,Topic); } _MANAGER(SysLog(-1)); } BOOL Manager::IsPanelsActive() { if (FramePos>=0) { return CurrentFrame?CurrentFrame->GetType() == MODALTYPE_PANELS:FALSE; } else { return FALSE; } } Frame *Manager::operator[](int Index) { if (Index<0 || Index>=FrameCount || !FrameList) { return nullptr; } return FrameList[Index]; } int Manager::IndexOfStack(Frame *Frame) { int Result=-1; for (int i=0; iOnChangeFocus(0); } int modalIndex=IndexOfStack(DeactivatedFrame); if (-1 != modalIndex && modalIndex== ModalStackCount-1) { /*if (IsSemiModalBackFrame(ActivatedFrame)) { // Является ли "родителем" полумодального фрэйма? ModalStackCount--; } else {*/ if (IndexOfStack(ActivatedFrame)==-1) { ModalStack[ModalStackCount-1]=ActivatedFrame; } else { ModalStackCount--; } // } } } void Manager::ActivateCommit() { _MANAGER(CleverSysLog clv(L"Manager::ActivateCommit()")); _MANAGER(SysLog(L"ActivatedFrame=%p",ActivatedFrame)); if (CurrentFrame==ActivatedFrame) { RefreshedFrame=ActivatedFrame; return; } int FrameIndex=IndexOf(ActivatedFrame); if (-1!=FrameIndex) { FramePos=FrameIndex; } /* 14.05.2002 SKV Если мы пытаемся активировать полумодальный фрэйм, то надо его вытащит на верх стэка модалов. */ for (int I=0; IFrameToBack=CurrentFrame; DeleteCommit(); } else { _MANAGER(SysLog(L"ERROR! DeletedFrame not found")); } } //! Удаляет DeletedFrame изо всех очередей! //! Назначает следующий активный, (исходя из своих представлений) //! Но только в том случае, если активный фрейм еще не назначен заранее. void Manager::DeleteCommit() { _MANAGER(CleverSysLog clv(L"Manager::DeleteCommit()")); _MANAGER(SysLog(L"DeletedFrame=%p",DeletedFrame)); if (!DeletedFrame) { return; } // //BOOL ifDoubI=ifDoubleInstance(DeletedFrame); // int ModalIndex=IndexOfStack(DeletedFrame); if (ModalIndex!=-1) { /* $ 14.05.2002 SKV Надёжнее найти и удалить именно то, что нужно, а не просто верхний. */ for (int i=0; iFrameToBack==DeletedFrame) { FrameList[i]->FrameToBack=CtrlObject->Cp(); } } int FrameIndex=IndexOf(DeletedFrame); if (-1!=FrameIndex) { DeletedFrame->DestroyAllModal(); for (int j=FrameIndex; j= FrameCount) { FramePos=0; } if (DeletedFrame->FrameToBack==CtrlObject->Cp()) { ActivateFrame(FrameList[FramePos]); } else { ActivateFrame(DeletedFrame->FrameToBack); } } /* $ 14.05.2002 SKV Долго не мог понять, нужен всё же этот код или нет. Но вроде как нужен. SVS> Когда понадобится - в некоторых местах расскомментить куски кода помеченные скобками if (ifDoubI && IsSemiModalBackFrame(ActivatedFrame)){ for(int i=0;iOnDestroy(); if (DeletedFrame->GetDynamicallyBorn()) { _MANAGER(SysLog(L"delete DeletedFrame %p, CurrentFrame=%p",DeletedFrame,CurrentFrame)); if (CurrentFrame==DeletedFrame) CurrentFrame=0; /* $ 14.05.2002 SKV Так как в деструкторе фрэйма неявно может быть вызван commit, то надо подстраховаться. */ Frame *tmp=DeletedFrame; DeletedFrame=nullptr; delete tmp; } // Полагаемся на то, что в ActevateFrame не будет переписан уже // присвоенный ActivatedFrame if (ModalStackCount) { ActivateFrame(ModalStack[ModalStackCount-1]); } else { ActivateFrame(FramePos); } } void Manager::InsertCommit() { _MANAGER(CleverSysLog clv(L"Manager::InsertCommit()")); _MANAGER(SysLog(L"InsertedFrame=%p",InsertedFrame)); if (InsertedFrame) { if (FrameListSize <= FrameCount) { FrameList=(Frame **)realloc(FrameList,sizeof(*FrameList)*(FrameCount+1)); FrameListSize++; } InsertedFrame->FrameToBack=CurrentFrame; FrameList[FrameCount]=InsertedFrame; if (!ActivatedFrame) { ActivatedFrame=InsertedFrame; } FrameCount++; } } void Manager::RefreshCommit() { _MANAGER(CleverSysLog clv(L"Manager::RefreshCommit()")); _MANAGER(SysLog(L"RefreshedFrame=%p",RefreshedFrame)); if (!RefreshedFrame) return; if (IndexOf(RefreshedFrame)==-1 && IndexOfStack(RefreshedFrame)==-1) return; if (!RefreshedFrame->Locked()) { if (!IsRedrawFramesInProcess) RefreshedFrame->ShowConsoleTitle(); if (RefreshedFrame) RefreshedFrame->Refresh(); if (!RefreshedFrame) return; CtrlObject->Macro.SetMode(RefreshedFrame->GetMacroMode()); } if ((Opt.ViewerEditorClock && (RefreshedFrame->GetType() == MODALTYPE_EDITOR || RefreshedFrame->GetType() == MODALTYPE_VIEWER)) || (WaitInMainLoop && Opt.Clock)) ShowTime(1); } void Manager::ExecuteCommit() { _MANAGER(CleverSysLog clv(L"Manager::ExecuteCommit()")); _MANAGER(SysLog(L"ExecutedFrame=%p",ExecutedFrame)); if (!ExecutedFrame) { return; } if (ModalStackCount == ModalStackSize) { ModalStack = (Frame **) realloc(ModalStack, ++ModalStackSize * sizeof(Frame *)); } ModalStack [ModalStackCount++] = ExecutedFrame; ActivatedFrame=ExecutedFrame; } /*$ 26.06.2001 SKV Для вызова из плагинов посредством ACTL_COMMIT */ BOOL Manager::PluginCommit() { return Commit(); } /* $ Введена для нужд CtrlAltShift OT */ void Manager::ImmediateHide() { if (FramePos<0) return; // Сначала проверяем, есть ли у прятываемого фрейма SaveScreen if (CurrentFrame->HasSaveScreen()) { CurrentFrame->Hide(); return; } // Фреймы перерисовываются, значит для нижних // не выставляем заголовок консоли, чтобы не мелькал. if (ModalStackCount>0) { /* $ 28.04.2002 KM Проверим, а не модальный ли редактор или вьювер на вершине модального стека? И если да, покажем User screen. */ if (ModalStack[ModalStackCount-1]->GetType()==MODALTYPE_EDITOR || ModalStack[ModalStackCount-1]->GetType()==MODALTYPE_VIEWER) { if (CtrlObject->CmdLine) CtrlObject->CmdLine->ShowBackground(); } else { int UnlockCount=0; IsRedrawFramesInProcess++; while ((*this)[FramePos]->Locked()) { (*this)[FramePos]->Unlock(); UnlockCount++; } RefreshFrame((*this)[FramePos]); Commit(); for (int i=0; iLock(); } if (ModalStackCount>1) { for (int i=0; iFastHide() & CASR_HELP)) { RefreshFrame(ModalStack[i]); Commit(); } else { break; } } } /* $ 04.04.2002 KM Перерисуем заголовок только у активного фрейма. Этим мы предотвращаем мелькание заголовка консоли при перерисовке всех фреймов. */ IsRedrawFramesInProcess--; CurrentFrame->ShowConsoleTitle(); } } else { if (CtrlObject->CmdLine) CtrlObject->CmdLine->ShowBackground(); } } void Manager::ModalizeCommit() { CurrentFrame->Push(ModalizedFrame); ModalizedFrame=nullptr; } void Manager::UnmodalizeCommit() { Frame *iFrame; for (int i=0; iRemoveModal(UnmodalizedFrame)) { break; } } for (int i=0; iRemoveModal(UnmodalizedFrame)) { break; } } UnmodalizedFrame=nullptr; } BOOL Manager::ifDoubleInstance(Frame *frame) { // /* if (ModalStackCount<=0) return FALSE; if(IndexOfStack(frame)==-1) return FALSE; if(IndexOf(frame)!=-1) return TRUE; */ // return FALSE; } /* Вызов ResizeConsole для всех NextModal у модального фрейма. KM */ void Manager::ResizeAllModal(Frame *ModalFrame) { if (!ModalFrame->NextModal) return; Frame *iModal=ModalFrame->NextModal; while (iModal) { iModal->ResizeConsole(); iModal=iModal->NextModal; } } void Manager::ResizeAllFrame() { ScrBuf.Lock(); for (int i=0; i < FrameCount; i++) { FrameList[i]->ResizeConsole(); } for (int i=0; i < ModalStackCount; i++) { ModalStack[i]->ResizeConsole(); /* $ 13.04.2002 KM - А теперь проресайзим все NextModal... */ ResizeAllModal(ModalStack[i]); } ImmediateHide(); FrameManager->RefreshFrame(); //RefreshFrame(); ScrBuf.Unlock(); } void Manager::InitKeyBar() { for (int I=0; I < FrameCount; I++) FrameList[I]->InitKeyBar(); } /*void Manager::AddSemiModalBackFrame(Frame* frame) { if(SemiModalBackFramesCount>=SemiModalBackFramesSize) { SemiModalBackFramesSize+=4; SemiModalBackFrames= (Frame**)realloc(SemiModalBackFrames,sizeof(Frame*)*SemiModalBackFramesSize); } SemiModalBackFrames[SemiModalBackFramesCount]=frame; SemiModalBackFramesCount++; } BOOL Manager::IsSemiModalBackFrame(Frame *frame) { if(!SemiModalBackFrames)return FALSE; for(int i=0;iGetTopModal(); } if (!f) f=fo; return f; } ///////// LockBottomFrame::LockBottomFrame() : _frame(FrameManager ? FrameManager->GetBottomFrame() : nullptr) { if (_frame) { if (_frame->Locked()) _frame = nullptr; else _frame->Lock(); } } LockBottomFrame::~LockBottomFrame() { if (_frame) _frame->Unlock(); }