unit u_editor; {$I u_defines.inc} interface uses Classes, SysUtils, FileUtil, Forms, Controls, lcltype, Graphics, SynEditKeyCmds, ComCtrls, SynEditHighlighter, ExtCtrls, Menus, SynMacroRecorder, dialogs, LazFileUtils, SynPluginSyncroEdit, SynEdit, SynHighlighterMulti, AnchorDocking, u_dialogs, u_widget, u_interfaces, u_synmemo, u_dlang, u_common, u_dcd, u_observer, u_sharedres, u_controls, u_writableComponent, u_dsgncontrols, LMessages; type TEditorWidget = class; TPagesOptions = class(TWritableLfmTextComponent, IEditableOptions, IEditableShortCut) private fEditorWidget: TEditorWidget; fPageButtons: TPageControlButtons; fPageOptions: TPageControlOptions; fMoveLeft: TShortCut; fMoveRight: TShortCut; fNextPage: TShortCut; fPrevPage: TShortCut; fDetectModuleName: boolean; function optionedWantCategory(): string; function optionedWantEditorKind: TOptionEditorKind; function optionedWantContainer: TPersistent; procedure optionedEvent(event: TOptionEditorEvent); function optionedOptionsModified: boolean; function scedCount: integer; function scedGetItem(const index: integer): TEditableShortcut; procedure scedSetItem(const index: integer; constref item: TEditableShortcut); published property pageButtons: TPageControlButtons read fPageButtons write fPageButtons; property pageOptions: TPageControlOptions read fPageOptions write fPageOptions; property nextPage: TShortCut read fNextPage write fNextPage; property previousPage: TShortCut read fPrevPage write fPrevPage; property moveLeft: TShortCut read fMoveLeft write fMoveLeft; property moveRight: TShortCut read fMoveRight write fMoveRight; property detectModuleName: boolean read fDetectModuleName write fDetectModuleName default true; public procedure assign(source: TPersistent); override; procedure assignTo(target: TPersistent); override; constructor construct(editorWidg: TEditorWidget); destructor Destroy; override; end; { TEditorWidget } TEditorWidget = class(TDexedWidget, IDocumentObserver, IMultiDocHandler, IProjectObserver) MenuItem1: TMenuItem; MenuItem10: TMenuItem; MenuItem11: TMenuItem; MenuItem12: TMenuItem; MenuItem13: TMenuItem; MenuItem14: TMenuItem; MenuItem15: TMenuItem; MenuItem16: TMenuItem; mnuEdTabWidth2: TMenuItem; mnuEdTabWidth3: TMenuItem; mnuEdTabWidth4: TMenuItem; mnuEdTabWidth5: TMenuItem; mnuEdTabWidth6: TMenuItem; mnuEdTabWidth7: TMenuItem; mnuEdTabWidth8: TMenuItem; mnuEdShowSpec: TMenuItem; mnuEdSetSpaces: TMenuItem; mnuEdSetTabs: TMenuItem; mnuedGotoline: TMenuItem; mnuedPrevWarn: TMenuItem; mnuedNextWarn: TMenuItem; mnuedDdocTmp: TMenuItem; mnuedPrevProtGrp: TMenuItem; mnuedNextProtGrp: TMenuItem; MenuItem2: TMenuItem; mnuedSortLines: TMenuItem; mnuedNextCarea: TMenuItem; mnuedPrevCarea: TMenuItem; mnuedLowcase: TMenuItem; mnuedUpcase: TMenuItem; MenuItem3: TMenuItem; MenuItem5: TMenuItem; MenuItem6: TMenuItem; MenuItem8: TMenuItem; MenuItem9: TMenuItem; mnuedRename: TMenuItem; mnuedInvAllNone: TMenuItem; mnuedComm: TMenuItem; mnuedPrev: TMenuItem; mnuedNext: TMenuItem; mnuedCallTip: TMenuItem; mnuedDdoc: TMenuItem; mnuedCopy: TMenuItem; mnuedCut: TMenuItem; mnuedPaste: TMenuItem; MenuItem4: TMenuItem; mnuedUndo: TMenuItem; mnuedRedo: TMenuItem; MenuItem7: TMenuItem; mnuedJum2Decl: TMenuItem; macRecorder: TSynMacroRecorder; editorStatus: TStatusBar; mnuEditor: TPopupMenu; procedure FormShortCut(var Msg: TLMKey; var Handled: Boolean); procedure FormShow(Sender: TObject); procedure mnuedDdocTmpClick(Sender: TObject); procedure mnuedGotolineClick(Sender: TObject); procedure mnuedNextWarnClick(Sender: TObject); procedure mnuedPrevProtGrpClick(Sender: TObject); procedure mnuedNextProtGrpClick(Sender: TObject); procedure mnuedNextCareaClick(Sender: TObject); procedure mnuedPrevCareaClick(Sender: TObject); procedure mnuedLowcaseClick(Sender: TObject); procedure mnuedPrevWarnClick(Sender: TObject); procedure mnuEdSetSpacesClick(Sender: TObject); procedure mnuEdSetTabsClick(Sender: TObject); procedure mnuEdShowSpecClick(Sender: TObject); procedure mnuedSortLinesClick(Sender: TObject); procedure mnuEdTabWidth2Click(Sender: TObject); procedure mnuedUpcaseClick(Sender: TObject); procedure MenuItem5Click(Sender: TObject); procedure MenuItem6Click(Sender: TObject); procedure MenuItem8Click(Sender: TObject); procedure mnuedRenameClick(Sender: TObject); procedure mnuedInvAllNoneClick(Sender: TObject); procedure mnuedCommClick(Sender: TObject); procedure mnuedPrevClick(Sender: TObject); procedure mnuedNextClick(Sender: TObject); procedure mnuedCallTipClick(Sender: TObject); procedure mnuedCopyClick(Sender: TObject); procedure mnuedCutClick(Sender: TObject); procedure mnuedDdocClick(Sender: TObject); procedure mnuEditorPopup(Sender: TObject); procedure mnuedPasteClick(Sender: TObject); procedure mnuedUndoClick(Sender: TObject); procedure mnuedRedoClick(Sender: TObject); procedure mnuedJum2DeclClick(Sender: TObject); protected procedure updateDelayed; override; procedure updateImperative; override; procedure setToolBarFlat(value: boolean); override; private fDetectModuleName: boolean; fOptions: TPagesOptions; pageControl: TDexedPageControl; fKeyChanged: boolean; fDoc: TDexedMemo; fProj: ICommonProject; fTokList: TLexTokenList; fLastCommand: TSynEditorCommand; procedure PageControlButtonClick(sender: TObject; button: TPageControlButton); procedure PageControlChanged(Sender: TObject); procedure PageControlChanging(Sender: TObject; var AllowChange: Boolean); procedure updateStatusBar; procedure updatePageCaption(page: TDexedPage); procedure pageBtnAddCLick(Sender: TObject); procedure pageCloseBtnClick(Sender: TObject); procedure memoKeyPress(Sender: TObject; var Key: char); procedure memoKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); procedure memoKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); procedure memoMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure memoCtrlClick(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure memoMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); procedure getSymbolLoc; procedure focusedEditorChanged; procedure memoCmdProcessed(Sender: TObject; var Command: TSynEditorCommand; var AChar: TUTF8Char; Data: pointer); procedure setDetectModuleName(value: boolean); // procedure docNew(document: TDexedMemo); procedure docClosing(document: TDexedMemo); procedure docFocused(document: TDexedMemo); procedure docChanged(document: TDexedMemo); // procedure projNew(project: ICommonProject); procedure projChanged(project: ICommonProject); procedure projClosing(project: ICommonProject); procedure projFocused(project: ICommonProject); procedure projCompiling(project: ICommonProject); procedure projCompiled(project: ICommonProject; success: boolean); // function SingleServiceName: string; function documentCount: Integer; function getDocument(index: Integer): TDexedMemo; function findDocument(const fname: string): TDexedMemo; procedure openDocument(const fname: string); function closeDocument(index: Integer;promptOnChanged: boolean = true): boolean; function closeDocument(doc: TDexedMemo;promptOnChanged: boolean = true): boolean; public constructor create(aOwner: TComponent); override; destructor destroy; override; function closeQuery: boolean; override; end; implementation {$R *.lfm} uses u_lcldragdrop; const optname = 'editorpages.txt'; {$REGION TPagesOptions -------------------------------------------------------} constructor TPagesOptions.construct(editorWidg: TEditorWidget); var fname: string; begin fEditorWidget := editorWidg; inherited create(editorWidg); EntitiesConnector.addObserver(self); // fDetectModuleName := true; fname := getDocPath + optname; if fname.fileExists then begin loadFromFile(fname); assignTo(fEditorWidget); end else assign(fEditorWidget); end; destructor TPagesOptions.Destroy; begin saveToFile(getDocPath + optname); EntitiesConnector.removeObserver(self); inherited; end; procedure TPagesOptions.assign(source: TPersistent); begin if source = fEditorWidget then begin fPageButtons := fEditorWidget.pageControl.buttons; fPageOptions := fEditorWidget.pageControl.options; fDetectModuleName:= fEditorWidget.fDetectModuleName; end else inherited; end; procedure TPagesOptions.assignTo(target: TPersistent); begin if target = fEditorWidget then begin fEditorWidget.pageControl.buttons := fPageButtons; fEditorWidget.pageControl.options := fPageOptions; fEditorWidget.setDetectModuleName(fDetectModuleName); end else inherited; end; function TPagesOptions.optionedWantCategory(): string; begin exit('Editor pages') end; function TPagesOptions.optionedWantEditorKind: TOptionEditorKind; begin exit(oekGeneric); end; function TPagesOptions.optionedWantContainer: TPersistent; begin exit(self); end; procedure TPagesOptions.optionedEvent(event: TOptionEditorEvent); begin case event of oeeAccept: assignTo(fEditorWidget); oeeCancel: assign(fEditorWidget); end; end; function TPagesOptions.optionedOptionsModified: boolean; begin exit(false); end; function TPagesOptions.scedCount: integer; begin result := 4; end; function TPagesOptions.scedGetItem(const index: integer): TEditableShortcut; begin result.category := 'Editor pages'; with result do case index of 0: begin identifier := 'Select next page'; shortcut:= fNextPage; end; 1: begin identifier := 'Select previous page'; shortcut:= fPrevPage; end; 2: begin identifier := 'Move page left'; shortcut:= fMoveLeft; end; 3: begin identifier := 'Move page right'; shortcut:= fMoveRight; end; else raise Exception.CreateFmt( 'unexpected TPagesOptions editable shortcut index: %d', [index]); end; end; procedure TPagesOptions.scedSetItem(const index: integer; constref item: TEditableShortcut); begin case index of 0: fNextPage := item.shortcut; 1: fPrevPage := item.shortcut; 2: fMoveLeft := item.shortcut; 3: fMoveRight:= item.shortcut; else raise Exception.CreateFmt( 'unexpected TPagesOptions editable shortcut index: %d', [index]); end; end; {$ENDREGION} {$REGION Standard Comp/Obj------------------------------------------------------} constructor TEditorWidget.create(aOwner: TComponent); var s: TIconScaledSize; begin inherited; toolbarVisible:=false; fDetectModuleName:=true; pageControl := TDexedPageControl.Create(self); pageControl.Parent := Content; pageControl.align := alClient; pageControl.onChanged:= @PageControlChanged; pageControl.onChanging:=@PageControlChanging; pageControl.closeButton.OnClick:=@pageCloseBtnClick; pageControl.addButton.OnClick:=@pageBtnAddCLick; pageControl.OnDragDrop:= @ddHandler.DragDrop; pageControl.OnDragOver:= @ddHandler.DragOver; pageControl.onButtonClick:= @PageControlButtonClick; s := GetIconScaledSize; case s of iss16: begin AssignPng(pageControl.moveLeftButton, 'GO_PREVIOUS'); AssignPng(pageControl.moveRightButton, 'GO_NEXT'); AssignPng(pageControl.addButton, 'DOCUMENT_ADD'); AssignPng(pageControl.closeButton, 'DOCUMENT_DELETE'); AssignPng(pageControl.splitButton, 'SPLITTER'); AssignPng(mnuedCopy.Bitmap, 'COPY'); AssignPng(mnuedCut.Bitmap, 'CUT'); AssignPng(mnuedPaste.Bitmap, 'PASTE'); AssignPng(mnuedUndo.Bitmap, 'ARROW_UNDO'); AssignPng(mnuedRedo.Bitmap, 'ARROW_REDO'); AssignPng(mnuedJum2Decl.Bitmap, 'ARROW_SHOE'); AssignPng(mnuedCopy.Bitmap, 'COPY'); AssignPng(mnuedNext.Bitmap, 'GO_NEXT'); AssignPng(mnuedPrev.Bitmap, 'GO_PREVIOUS'); AssignPng(mnuedRename.Bitmap, 'PENCIL'); AssignPng(mnuedUpcase.Bitmap, 'CASE'); AssignPng(mnuedLowcase.Bitmap, 'CASE'); AssignPng(mnuedNextCarea.Bitmap, 'GO_NEXT'); AssignPng(mnuedPrevCarea.Bitmap, 'GO_PREVIOUS'); AssignPng(mnuedSortLines.Bitmap, 'SORT_AZ'); AssignPng(mnuedNextProtGrp.Bitmap, 'GO_NEXT'); AssignPng(mnuedPrevProtGrp.Bitmap, 'GO_PREVIOUS'); AssignPng(mnuedNextWarn.Bitmap, 'GO_NEXT'); AssignPng(mnuedPrevWarn.Bitmap, 'GO_PREVIOUS'); end; iss24: begin AssignPng(pageControl.moveLeftButton, 'GO_PREVIOUS24'); AssignPng(pageControl.moveRightButton, 'GO_NEXT24'); AssignPng(pageControl.addButton, 'DOCUMENT_ADD24'); AssignPng(pageControl.closeButton, 'DOCUMENT_DELETE24'); AssignPng(pageControl.splitButton, 'SPLITTER24'); AssignPng(mnuedCopy.Bitmap, 'COPY24'); AssignPng(mnuedCut.Bitmap, 'CUT24'); AssignPng(mnuedPaste.Bitmap, 'PASTE24'); AssignPng(mnuedUndo.Bitmap, 'ARROW_UNDO24'); AssignPng(mnuedRedo.Bitmap, 'ARROW_REDO24'); //AssignPng(mnuedJum2Decl.Bitmap, 'ARROW_SHOE24'); AssignPng(mnuedCopy.Bitmap, 'COPY24'); AssignPng(mnuedNext.Bitmap, 'GO_NEXT24'); AssignPng(mnuedPrev.Bitmap, 'GO_PREVIOUS24'); AssignPng(mnuedRename.Bitmap, 'PENCIL24'); AssignPng(mnuedUpcase.Bitmap, 'CASE24'); AssignPng(mnuedLowcase.Bitmap, 'CASE24'); AssignPng(mnuedNextCarea.Bitmap, 'GO_NEXT24'); AssignPng(mnuedPrevCarea.Bitmap, 'GO_PREVIOUS24'); AssignPng(mnuedSortLines.Bitmap, 'SORT_AZ24'); AssignPng(mnuedNextProtGrp.Bitmap, 'GO_NEXT24'); AssignPng(mnuedPrevProtGrp.Bitmap, 'GO_PREVIOUS24'); AssignPng(mnuedNextWarn.Bitmap, 'GO_NEXT24'); AssignPng(mnuedPrevWarn.Bitmap, 'GO_PREVIOUS24'); end; iss32: begin AssignPng(pageControl.moveLeftButton, 'GO_PREVIOUS32'); AssignPng(pageControl.moveRightButton, 'GO_NEXT32'); AssignPng(pageControl.addButton, 'DOCUMENT_ADD32'); AssignPng(pageControl.closeButton, 'DOCUMENT_DELETE32'); AssignPng(pageControl.splitButton, 'SPLITTER32'); AssignPng(mnuedCopy.Bitmap, 'COPY32'); AssignPng(mnuedCut.Bitmap, 'CUT32'); AssignPng(mnuedPaste.Bitmap, 'PASTE32'); AssignPng(mnuedUndo.Bitmap, 'ARROW_UNDO32'); AssignPng(mnuedRedo.Bitmap, 'ARROW_REDO32'); //AssignPng(mnuedJum2Decl.Bitmap, 'ARROW_SHOE32'); AssignPng(mnuedCopy.Bitmap, 'COPY32'); AssignPng(mnuedNext.Bitmap, 'GO_NEXT32'); AssignPng(mnuedPrev.Bitmap, 'GO_PREVIOUS32'); AssignPng(mnuedRename.Bitmap, 'PENCIL32'); AssignPng(mnuedUpcase.Bitmap, 'CASE32'); AssignPng(mnuedLowcase.Bitmap, 'CASE32'); AssignPng(mnuedNextCarea.Bitmap, 'GO_NEXT32'); AssignPng(mnuedPrevCarea.Bitmap, 'GO_PREVIOUS32'); AssignPng(mnuedSortLines.Bitmap, 'SORT_AZ32'); AssignPng(mnuedNextProtGrp.Bitmap, 'GO_NEXT32'); AssignPng(mnuedPrevProtGrp.Bitmap, 'GO_PREVIOUS32'); AssignPng(mnuedNextWarn.Bitmap, 'GO_NEXT32'); AssignPng(mnuedPrevWarn.Bitmap, 'GO_PREVIOUS32'); end; end; editorStatus.Panels[0].Width := ScaleX(115, 96); editorStatus.Panels[1].Width := ScaleX(85, 96); editorStatus.Panels[2].Width := ScaleX(125, 96); editorStatus.Panels[3].Width := ScaleX(105, 96); editorStatus.Panels[4].Width := ScaleX(2000, 96); fTokList := TLexTokenList.Create; EntitiesConnector.addObserver(self); EntitiesConnector.addSingleService(self); timedUpdateKind := tukDelay; fOptions:= TPagesOptions.construct(self); end; destructor TEditorWidget.destroy; var i: integer; begin EntitiesConnector.removeObserver(self); for i := PageControl.PageCount-1 downto 0 do if PageControl.Pages[i].ControlCount > 0 then if (PageControl.Pages[i].Controls[0] is TDexedMemo) then PageControl.Pages[i].Controls[0].Free; fTokList.Free; fOptions.Free; inherited; end; function TEditorWidget.closeQuery: boolean; begin result := inherited and (Parent.isNotAssigned or // already set as dockable but not docked // necessary because it has te closed programmatically during loading sequence // otherwise the layout reloading has no effect. Parent is TAnchorDockHostSite and Parent.Parent.isNotAssigned); end; procedure TEditorWidget.setToolBarFlat(value: boolean); begin inherited setToolBarFlat(value); if value then begin fOptions.pageOptions:= fOptions.pageOptions + [poFlatButtons]; pageControl.options := pageControl.options + [poFlatButtons] end else begin fOptions.pageOptions:= fOptions.pageOptions - [poFlatButtons]; pageControl.options := pageControl.options - [poFlatButtons]; end; end; {$ENDREGION} {$REGION IDocumentObserver ---------------------------------------------------} procedure TEditorWidget.docNew(document: TDexedMemo); var pge: TDexedPage; begin pge := pageControl.addPage; // document.Align := alClient; document.Parent := pge; // document.OnKeyDown := @memoKeyDown; document.OnKeyUp := @memoKeyUp; document.OnKeyPress := @memoKeyPress; document.OnMouseDown := @memoMouseDown; document.OnMouseMove := @memoMouseMove; document.OnClickLink := @memoCtrlClick; document.OnCommandProcessed:= @memoCmdProcessed; // fDoc := document; fDoc.Visible:=true; fDoc.setFocus; focusedEditorChanged; updateImperative; end; procedure TEditorWidget.docClosing(document: TDexedMemo); var i: integer; begin if document.isNotAssigned then exit; document.Parent := nil; if document = fDoc then fDoc := nil; pageControl.deletePage(pageControl.pageIndex); for i:= 0 to pageControl.pageCount-1 do updatePageCaption(pageControl.pages[i]); updateImperative; end; procedure TEditorWidget.docFocused(document: TDexedMemo); begin if fDoc.isAssigned and pageControl.currentPage.isAssigned and (pageControl.currentPage.Caption = newdocPageCaption) then updatePageCaption(pageControl.currentPage); if document = fDoc then exit; fDoc := document; fDoc.Visible:=true; focusedEditorChanged; updateImperative; end; procedure TEditorWidget.docChanged(document: TDexedMemo); begin if fDoc <> document then exit; fKeyChanged := true; beginDelayedUpdate; end; {$ENDREGION} {$REGION ICommonProject ------------------------------------------------------} procedure TEditorWidget.projNew(project: ICommonProject); begin end; procedure TEditorWidget.projChanged(project: ICommonProject); begin end; procedure TEditorWidget.projClosing(project: ICommonProject); begin if fProj = project then fProj := nil; end; procedure TEditorWidget.projFocused(project: ICommonProject); begin fProj := project; end; procedure TEditorWidget.projCompiling(project: ICommonProject); begin end; procedure TEditorWidget.projCompiled(project: ICommonProject; success: boolean); begin end; {$ENDREGION} {$REGION IMultiDocHandler ----------------------------------------------------} function TEditorWidget.SingleServiceName: string; begin exit('IMultiDocHandler'); end; function TEditorWidget.documentCount: Integer; begin exit(PageControl.PageCount); end; function TEditorWidget.getDocument(index: Integer): TDexedMemo; begin exit(TDexedMemo(pageControl.Pages[index].Controls[0])); end; function TEditorWidget.findDocument(const fname: string): TDexedMemo; var i: Integer; begin for i := 0 to PageControl.PageCount-1 do begin result := getDocument(i); if SameFileName(result.fileName, TrimFilename(fname)) then exit; end; result := nil; end; procedure TEditorWidget.openDocument(const fname: string); var doc: TDexedMemo; begin showWidget; doc := findDocument(fname); if doc.isAssigned then begin PageControl.currentPage := TDexedPage(doc.Parent); exit; end; doc := TDexedMemo.Create(nil); fDoc.loadFromFile(TrimFilename(fname)); if fProj.isAssigned and (fProj.filename = fDoc.fileName) then begin if fProj.getFormat = pfDEXED then fDoc.Highlighter := LfmSyn else fDoc.Highlighter := JsSyn; end; end; function TEditorWidget.closeDocument(index: Integer; promptOnChanged: boolean = true): boolean; var doc: TDexedMemo; begin doc := getDocument(index); if doc.isNotAssigned then exit(false); if promptOnChanged and (doc.modified or (doc.fileName = doc.tempFilename)) and (dlgFileChangeClose(doc.fileName, UnsavedFile) = mrCancel) then exit(false); showWidget; doc.disableFileDateCheck:=true; pageControl.pageIndex:=index; if doc.LCLRefCount > 0 then application.ReleaseComponent(doc) else doc.Free; result := true; end; function TEditorWidget.closeDocument(doc: TDexedMemo;promptOnChanged: boolean = true): boolean; var page: TDexedPage = nil; begin page := TDexedPage(doc.Parent); if page.isNotAssigned then exit(false); exit(closeDocument(page.index, promptOnChanged)); end; {$ENDREGION} {$REGION PageControl/Editor things ---------------------------------------------} procedure TEditorWidget.pageCloseBtnClick(Sender: TObject); begin closeDocument(PageControl.PageIndex); PageControlButtonClick(pageControl, pbClose); end; procedure TEditorWidget.pageBtnAddCLick(Sender: TObject); begin TDexedMemo.Create(nil); pageControl.currentPage.Caption := newdocPageCaption; end; procedure TEditorWidget.setDetectModuleName(value: boolean); var i: integer; begin if fDetectModuleName = value then exit; fDetectModuleName:=value; for i:= 0 to pageControl.pageCount-1 do updatePageCaption(pageControl.pages[i]); end; procedure TEditorWidget.focusedEditorChanged; begin if fDoc.isNotAssigned then exit; macRecorder.Editor:= fDoc; fDoc.PopupMenu := mnuEditor; fDoc.hideCallTips; fDoc.hideDDocs; if (pageControl.currentPage.Caption = '') or (pageControl.currentPage.Caption = newdocPageCaption) then begin fKeyChanged := true; beginDelayedUpdate; end; end; procedure TEditorWidget.PageControlChanged(Sender: TObject); begin if fDoc.isNotAssigned then exit; fDoc.hideCallTips; fDoc.hideDDocs; end; procedure TEditorWidget.PageControlChanging(Sender: TObject; var AllowChange: Boolean); begin if fDoc.isNotAssigned then exit; fDoc.hideCallTips; fDoc.hideDDocs; end; procedure TEditorWidget.memoKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin case Key of VK_CLEAR,VK_RETURN,VK_BACK : fKeyChanged := true; VK_UP, VK_DOWN, VK_LEFT, VK_RIGHT: if Shift = [] then updateImperative; end; if fKeyChanged then beginDelayedUpdate; end; procedure TEditorWidget.memoKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); begin case fLastCommand of ecSelectionStart..ecSelectionEnd: updateImperative; ecLeft..ecHalfWordRight: updateImperative; end; end; procedure TEditorWidget.memoCmdProcessed(Sender: TObject; var Command: TSynEditorCommand; var AChar: TUTF8Char; Data: pointer); begin fLastCommand := Command; // case Command of ecJumpToDeclaration: getSymbolLoc; ecRecordMacro: begin if macRecorder.State = msStopped then macRecorder.RecordMacro(fDoc) else macRecorder.Stop; updateImperative; end; ecPlayMacro: begin macRecorder.Stop; macRecorder.PlaybackMacro(fDoc); updateImperative; end; end; end; procedure TEditorWidget.memoKeyPress(Sender: TObject; var Key: char); begin fKeyChanged := true; beginDelayedUpdate; end; procedure TEditorWidget.memoMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin updateImperative; end; procedure TEditorWidget.memoMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); begin if not (ssLeft in Shift) then exit; beginDelayedUpdate; end; procedure TEditorWidget.memoCtrlClick(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin getSymbolLoc; end; procedure TEditorWidget.getSymbolLoc; var page: TDexedPage; srcpos, i, sum, linelen: Integer; fname: string; len: byte; begin if not DcdWrapper.available then exit; DcdWrapper.getDeclFromCursor(fname, srcpos); if (fname <> fDoc.fileName) and fname.fileExists then begin page := pageControl.splitPage; if page.isAssigned then begin fDoc := TDexedMemo(page.Controls[0]); if fDoc.fileName <> fname then openDocument(fname); end else openDocument(fname); end; if srcpos <> -1 then begin sum := 0; len := getLineEndingLength(fDoc.fileName); for i := 0 to fDoc.Lines.Count-1 do begin linelen := fDoc.Lines[i].length; if sum + linelen + len > srcpos then begin fDoc.CaretY := i + 1; fDoc.CaretX := srcpos - sum + len; fDoc.SelectWord; fDoc.EnsureCursorPosVisible; break; end; sum += linelen; sum += len; end; end; end; procedure TEditorWidget.updateStatusBar; const modstr: array[boolean] of string = ('...', 'MODIFIED'); begin if fDoc.isNotAssigned then begin editorStatus.Panels[0].Text := ''; editorStatus.Panels[1].Text := ''; editorStatus.Panels[2].Text := ''; editorStatus.Panels[3].Text := ''; editorStatus.Panels[4].Text := ''; end else begin editorStatus.Panels[0].Text := format('%d : %d | %d', [fDoc.CaretY, fDoc.CaretX, fDoc.SelEnd - fDoc.SelStart]); editorStatus.Panels[1].Text := modstr[fDoc.modified]; if macRecorder.State = msRecording then editorStatus.Panels[2].Text := 'recording macro' else if macRecorder.IsEmpty then editorStatus.Panels[2].Text := 'no macro' else editorStatus.Panels[2].Text := 'macro ready'; if fDoc.ReadOnly then begin editorStatus.Panels[3].Width:= 120; editorStatus.Panels[3].Text := '(read-only)'; end else editorStatus.Panels[3].Width:= 0; editorStatus.Panels[4].Text := fDoc.fileName; end; end; procedure TEditorWidget.updatePageCaption(page: TDexedPage); var txt: string = newdocPageCaption; dc1: TDexedMemo = nil; dc2: TDexedMemo = nil; begin if page.isNotAssigned or page.ControlCount.equals(0) then exit; if pageControl.splitPage.isAssigned and (page <> pageControl.splitPage) then begin txt := ''; dc1 := TDexedMemo(page.Controls[0]); dc2 := TDexedMemo(pageControl.splitPage.Controls[0]); if dc1.isAssigned and dc2.isAssigned then txt := dc1.pageCaption(fDetectModuleName) + ' - ' + dc2.pageCaption(fDetectModuleName); end else txt := TDexedMemo(page.Controls[0]).pageCaption(fDetectModuleName); page.Caption := txt; end; procedure TEditorWidget.PageControlButtonClick(sender: TObject; button: TPageControlButton); var i: integer; begin if (button = pbClose) or (button = pbSplit) then begin for i:= 0 to pageControl.pageCount-1 do updatePageCaption(pageControl.pages[i]); end; end; procedure TEditorWidget.updateImperative; begin updateStatusBar; if fDoc.isAssigned then updatePageCaption(pageControl.currentPage); end; procedure TEditorWidget.updateDelayed; begin if fDoc.isNotAssigned then exit; updateStatusBar; if not fKeyChanged then exit; if pageControl.currentPage.isAssigned then updatePageCaption(pageControl.currentPage); end; {$ENDREGION} {$REGION Editor context menu ---------------------------------------------------} procedure TEditorWidget.mnuedCopyClick(Sender: TObject); begin if fDoc.isAssigned then fDoc.ExecuteCommand(ecCopy, '', nil); end; procedure TEditorWidget.mnuedCallTipClick(Sender: TObject); begin if fDoc.isNotAssigned then exit; mnuEditor.Close; fDoc.hideDDocs; if not fDoc.IsDSource and not fDoc.alwaysAdvancedFeatures then exit; fDoc.showCallTips; end; procedure TEditorWidget.mnuedCommClick(Sender: TObject); begin if fDoc.isAssigned then fDoc.CommandProcessor(ecCommentSelection, '', nil); end; procedure TEditorWidget.mnuedPrevClick(Sender: TObject); begin if fDoc.isAssigned then fDoc.CommandProcessor(ecPreviousLocation, '', nil); end; procedure TEditorWidget.mnuedNextClick(Sender: TObject); begin if fDoc.isAssigned then fDoc.CommandProcessor(ecNextLocation, '', nil); end; procedure TEditorWidget.mnuedInvAllNoneClick(Sender: TObject); begin if fDoc.isNotAssigned then exit; if not fDoc.IsDSource and not fDoc.alwaysAdvancedFeatures then exit; fDoc.CommandProcessor(ecSwapVersionAllNone, '', nil); end; procedure TEditorWidget.MenuItem5Click(Sender: TObject); begin if fDoc.isNotAssigned then exit; if not fDoc.IsDSource and not fDoc.alwaysAdvancedFeatures then exit; with TSaveDialog.Create(nil) do try if execute then begin fTokList.Clear; lex(fDoc.Text, fTokList, nil); fTokList.saveToFile(FileName.normalizePath); fTokList.Clear; end; finally free; end; end; procedure TEditorWidget.mnuedUpcaseClick(Sender: TObject); begin if fDoc.isAssigned then fDoc.CommandProcessor(ecUpperCaseWordOrSel, #0, nil); end; procedure TEditorWidget.mnuedLowcaseClick(Sender: TObject); begin if fDoc.isAssigned then fDoc.CommandProcessor(ecLowerCaseWordOrSel, #0, nil); end; procedure TEditorWidget.mnuedPrevWarnClick(Sender: TObject); begin if fDoc.isAssigned then fDoc.previousWarning; end; procedure TEditorWidget.mnuEdSetSpacesClick(Sender: TObject); begin if fDoc.isAssigned then fDoc.Options := fDoc.Options + [eoTabsToSpaces]; end; procedure TEditorWidget.mnuEdSetTabsClick(Sender: TObject); begin if fDoc.isAssigned then fDoc.Options := fDoc.Options - [eoTabsToSpaces]; end; procedure TEditorWidget.mnuEdShowSpecClick(Sender: TObject); begin if fDoc.isNotAssigned then exit; if mnuEdShowSpec.Checked then fDoc.Options := fDoc.Options + [eoShowSpecialChars] else fDoc.Options := fDoc.Options - [eoShowSpecialChars]; end; procedure TEditorWidget.mnuedSortLinesClick(Sender: TObject); begin if fDoc.isAssigned then fDoc.CommandProcessor(ecSortLines, #0, nil); end; procedure TEditorWidget.mnuEdTabWidth2Click(Sender: TObject); begin if fDoc.isNotAssigned then exit; fDoc.TabWidth:= TMenuItem(sender).Tag; if not (eoTabsToSpaces in fDoc.options) then begin fDoc.BlockIndent := 0; fDoc.BlockTabIndent := 1; end else begin fDoc.BlockIndent := fDoc.TabWidth; fDoc.BlockTabIndent := 0; end; end; procedure TEditorWidget.mnuedNextCareaClick(Sender: TObject); begin if fDoc.isAssigned then fDoc.nextChangedArea; end; procedure TEditorWidget.mnuedPrevProtGrpClick(Sender: TObject); begin if fDoc.isAssigned then fDoc.previousProtectionGroup; end; procedure TEditorWidget.mnuedDdocTmpClick(Sender: TObject); begin if fDoc.isAssigned then fDoc.insertDdocTemplate; end; procedure TEditorWidget.FormShortCut(var Msg: TLMKey; var Handled: Boolean); var sh: TShortCut; begin Handled := false; sh := KeyToShortCut(Msg.CharCode, KeyDataToShiftState(Msg.KeyData)); if sh = fOptions.fNextPage then begin pageControl.pageIndex:= (pageControl.pageIndex + 1) mod pageControl.pageCount; Handled := true; end else if sh = fOptions.fPrevPage then begin if pageControl.pageIndex - 1 < 0 then pageControl.pageIndex:= pageControl.pageCount - 1 else pageControl.pageIndex:= pageControl.pageIndex - 1; Handled := true; end else if sh = fOptions.fMoveLeft then begin pageControl.movePageLeft; Handled := true; end else if sh = fOptions.fMoveRight then begin pageControl.movePageRight; Handled := true; end; end; procedure TEditorWidget.FormShow(Sender: TObject); begin if fDoc.isAssigned then fDoc.Visible:=true; end; procedure TEditorWidget.mnuedGotolineClick(Sender: TObject); begin if fDoc.isAssigned then fDoc.gotoLinePrompt; end; procedure TEditorWidget.mnuedNextWarnClick(Sender: TObject); begin if fDoc.isAssigned then fDoc.nextWarning; end; procedure TEditorWidget.mnuedNextProtGrpClick(Sender: TObject); begin if fDoc.isAssigned then fDoc.nextProtectionGroup; end; procedure TEditorWidget.mnuedPrevCareaClick(Sender: TObject); begin if fDoc.isAssigned then fDoc.previousChangedArea; end; procedure TEditorWidget.MenuItem8Click(Sender: TObject); var str: TStringList; begin if fDoc.isNotAssigned then exit; if not fDoc.IsDSource and not fDoc.alwaysAdvancedFeatures then exit; with TSaveDialog.Create(nil) do try if execute then begin str := TStringList.Create; fTokList.Clear; lex(fDoc.Text, fTokList, nil, [lxoNoComments]); getImports(fTOkList, str); str.SaveToFile(filename.normalizePath); fTokList.Clear; str.Free; end; finally free; end; end; procedure TEditorWidget.MenuItem6Click(Sender: TObject); begin if fDoc.isAssigned then fDoc.CommandProcessor(ecCommentIdentifier, '', nil); end; procedure TEditorWidget.mnuedRenameClick(Sender: TObject); begin if fDoc.isAssigned then fDoc.CommandProcessor(ecRenameIdentifier, '', nil); end; procedure TEditorWidget.mnuedCutClick(Sender: TObject); begin if fDoc.isAssigned then fDoc.ExecuteCommand(ecCut, '', nil); end; procedure TEditorWidget.mnuedDdocClick(Sender: TObject); begin if fDoc.isNotAssigned then exit; mnuEditor.Close; fDoc.hideCallTips; if not fDoc.IsDSource and not fDoc.alwaysAdvancedFeatures then exit; fDoc.showDDocs; end; procedure TEditorWidget.mnuedPasteClick(Sender: TObject); begin if fDoc.isAssigned then fDoc.ExecuteCommand(ecPaste, '', nil); end; procedure TEditorWidget.mnuedUndoClick(Sender: TObject); begin if fDoc.isAssigned then fDoc.ExecuteCommand(ecUndo, '', nil); end; procedure TEditorWidget.mnuedRedoClick(Sender: TObject); begin if fDoc.isAssigned then fDoc.ExecuteCommand(ecRedo, '', nil); end; procedure TEditorWidget.mnuedJum2DeclClick(Sender: TObject); begin if fDoc.isAssigned then getSymbolLoc; end; procedure TEditorWidget.mnuEditorPopup(Sender: TObject); begin if fDoc.isNotAssigned then exit; mnuedCut.Enabled:=fDoc.SelAvail; mnuedPaste.Enabled:=fDoc.CanPaste; mnuedCopy.Enabled:=fDoc.SelAvail; mnuedUndo.Enabled:=fDoc.CanUndo; mnuedRedo.Enabled:=fDoc.CanRedo; mnuedJum2Decl.Enabled:=fDoc.isDSource; mnuEdSetSpaces.Checked:= eoTabsToSpaces in fDoc.Options; mnuEdSetTabs.Checked:= not (eoTabsToSpaces in fDoc.Options); mnuEdShowSpec.Checked:=eoShowSpecialChars in fDoc.Options; case fDoc.TabWidth of 2: mnuEdTabWidth2.Checked:=true; 3: mnuEdTabWidth3.Checked:=true; 4: mnuEdTabWidth4.Checked:=true; 5: mnuEdTabWidth5.Checked:=true; 6: mnuEdTabWidth6.Checked:=true; 7: mnuEdTabWidth7.Checked:=true; 8: mnuEdTabWidth8.Checked:=true; end; end; {$ENDREGION} end.