From 611f282114b0070c9615f6ffb3201a0404228393 Mon Sep 17 00:00:00 2001 From: Roland Bengtsson Date: Wed, 16 Sep 2026 20:46:38 +0300 Subject: [PATCH] fix: never focus the editor while it is hidden Preview only mode hides the editor, and the VCL refuses to focus a control that is not visible. Clicking Bold, Italic, Link or Code then raised EInvalidOperation with 'Cannot focus a disabled or invisible window', and so did every command on the shared format path, clicking an entry in the contents list, and the palette's undo, redo, select all, indent, outdent and delete word. Route every path that returns focus to the editor through a FocusEditor helper carrying the CanFocus guard that the zen mode code already used. The VCL applied that guard in four places out of sixteen. The FMX studio applied it nowhere, so it could raise from leaving zen mode and from closing the command palette as well. --- .../Markdown4DStudioFMX.Main.pas | 44 +++++++++++------- .../Markdown4DStudioVCL.Main.pas | 46 +++++++++++-------- 2 files changed, 53 insertions(+), 37 deletions(-) diff --git a/Examples/Markdown4DStudioFMX/Markdown4DStudioFMX.Main.pas b/Examples/Markdown4DStudioFMX/Markdown4DStudioFMX.Main.pas index 19635cd..c20fe3f 100644 --- a/Examples/Markdown4DStudioFMX/Markdown4DStudioFMX.Main.pas +++ b/Examples/Markdown4DStudioFMX/Markdown4DStudioFMX.Main.pas @@ -152,6 +152,7 @@ TMarkdown4DStudioFMXForm = class(TForm, IPadEditorView, IPadShell) procedure CopyHtmlToClipboard(const Fragment: string); procedure CloseApplication; procedure BuildToolbar; + procedure FocusEditor; function ResolveIconFontName: string; function AddIconButton(const Glyph: string; const Hint: string; const Handler: TNotifyEvent): TRectangle; procedure AddSeparator; @@ -392,6 +393,15 @@ destructor TMarkdown4DStudioFMXForm.Destroy; FLightTheme.Free; end; +procedure TMarkdown4DStudioFMXForm.FocusEditor; +begin + // Preview only mode hides the editor, and focusing a control that is not + // visible raises. Every path that returns focus to the editor goes through + // here so none of them can. + if FEditor.CanFocus then + FEditor.SetFocus; +end; + procedure TMarkdown4DStudioFMXForm.BuildToolbar; begin FToolbar := TRectangle.Create(Self); @@ -940,17 +950,17 @@ function TMarkdown4DStudioFMXForm.BuildCommandActions: TPadCommandActions; Result.ShowFind := procedure begin ShowFindBar; end; Result.ShowReplace := procedure begin ShowReplaceBar; end; Result.FindInPreview := procedure begin ExecuteFind; end; - Result.Undo := procedure begin FEditor.Undo; FEditor.SetFocus; end; - Result.Redo := procedure begin FEditor.Redo; FEditor.SetFocus; end; - Result.SelectAll := procedure begin FEditor.SelectAll; FEditor.SetFocus; end; - Result.Indent := procedure begin FEditor.Indent; FEditor.SetFocus; end; - Result.Outdent := procedure begin FEditor.Outdent; FEditor.SetFocus; end; - Result.DeleteWordLeft := procedure begin FEditor.DeleteWordLeft; FEditor.SetFocus; end; + Result.Undo := procedure begin FEditor.Undo; FocusEditor; end; + Result.Redo := procedure begin FEditor.Redo; FocusEditor; end; + Result.SelectAll := procedure begin FEditor.SelectAll; FocusEditor; end; + Result.Indent := procedure begin FEditor.Indent; FocusEditor; end; + Result.Outdent := procedure begin FEditor.Outdent; FocusEditor; end; + Result.DeleteWordLeft := procedure begin FEditor.DeleteWordLeft; FocusEditor; end; Result.ExecuteFormat := procedure(const Command: TEditorCommand) begin FEditor.ExecuteCommand(Command); - FEditor.SetFocus; + FocusEditor; end; end; @@ -1137,7 +1147,7 @@ function TMarkdown4DStudioFMXForm.TryHandleGlobalKey(const Key: Word): Boolean; procedure TMarkdown4DStudioFMXForm.ExecuteFormatCommand(const Command: TEditorCommand); begin FEditor.ExecuteCommand(Command); - FEditor.SetFocus; + FocusEditor; end; procedure TMarkdown4DStudioFMXForm.DoShow; @@ -1241,7 +1251,7 @@ procedure TMarkdown4DStudioFMXForm.CloseFindBar; FFindBar.Visible := False; FEditor.ClearHighlights; - FEditor.SetFocus; + FocusEditor; end; @@ -1288,7 +1298,7 @@ procedure TMarkdown4DStudioFMXForm.ClosePalette; begin FPalette.Visible := False; - FEditor.SetFocus; + FocusEditor; end; procedure TMarkdown4DStudioFMXForm.RefreshPaletteList; @@ -1409,7 +1419,7 @@ procedure TMarkdown4DStudioFMXForm.EnterZen; UpdateZenPadding; FZenActive := True; - FEditor.SetFocus; + FocusEditor; end; procedure TMarkdown4DStudioFMXForm.ExitZen; @@ -1428,7 +1438,7 @@ procedure TMarkdown4DStudioFMXForm.ExitZen; ApplyViewMode; FZenActive := False; - FEditor.SetFocus; + FocusEditor; end; procedure TMarkdown4DStudioFMXForm.UpdateZenPadding; @@ -1587,25 +1597,25 @@ procedure TMarkdown4DStudioFMXForm.CopyHtmlToClipboard(const Fragment: string); procedure TMarkdown4DStudioFMXForm.HandleBoldClick(Sender: TObject); begin FEditor.ExecuteCommand(TEditorCommand.Bold); - FEditor.SetFocus; + FocusEditor; end; procedure TMarkdown4DStudioFMXForm.HandleItalicClick(Sender: TObject); begin FEditor.ExecuteCommand(TEditorCommand.Italic); - FEditor.SetFocus; + FocusEditor; end; procedure TMarkdown4DStudioFMXForm.HandleLinkClick(Sender: TObject); begin FEditor.ExecuteCommand(TEditorCommand.Link); - FEditor.SetFocus; + FocusEditor; end; procedure TMarkdown4DStudioFMXForm.HandleCodeClick(Sender: TObject); begin FEditor.ExecuteCommand(TEditorCommand.CodeBlock); - FEditor.SetFocus; + FocusEditor; end; procedure TMarkdown4DStudioFMXForm.HandleThemeClick(Sender: TObject); @@ -1733,7 +1743,7 @@ procedure TMarkdown4DStudioFMXForm.HandleTocChange(Sender: TObject); FTocFollowing := False; end; - FEditor.SetFocus; + FocusEditor; end; procedure TMarkdown4DStudioFMXForm.HandleTick(Sender: TObject); diff --git a/Examples/Markdown4DStudioVCL/Markdown4DStudioVCL.Main.pas b/Examples/Markdown4DStudioVCL/Markdown4DStudioVCL.Main.pas index a6d90c2..947d877 100644 --- a/Examples/Markdown4DStudioVCL/Markdown4DStudioVCL.Main.pas +++ b/Examples/Markdown4DStudioVCL/Markdown4DStudioVCL.Main.pas @@ -153,6 +153,7 @@ TPadChrome = record procedure ShowSaveError(const FileName, ErrorMessage: string); procedure CloseApplication; procedure ConfigureControls; + procedure FocusEditor; procedure BuildToolbar; function ResolveIconFontName: string; function AddIconButton(const Glyph: string; const Hint: string; const Handler: TNotifyEvent): TSpeedButton; @@ -370,6 +371,15 @@ procedure TMarkdown4DStudioVCLForm.ConfigureControls; lblFindCount.Caption := EmptyFindCaption; end; +procedure TMarkdown4DStudioVCLForm.FocusEditor; +begin + // Preview only mode hides the editor, and the VCL refuses to focus a control + // that is not visible. Every path that returns focus to the editor goes + // through here so none of them can raise. + if mdEditor.CanFocus then + mdEditor.SetFocus; +end; + procedure TMarkdown4DStudioVCLForm.BuildToolbar; begin FIconFontName := ResolveIconFontName; @@ -736,25 +746,25 @@ procedure TMarkdown4DStudioVCLForm.HandleRecentItemClick(Sender: TObject); procedure TMarkdown4DStudioVCLForm.HandleBoldClick(Sender: TObject); begin mdEditor.ExecuteCommand(TEditorCommand.Bold); - mdEditor.SetFocus; + FocusEditor; end; procedure TMarkdown4DStudioVCLForm.HandleItalicClick(Sender: TObject); begin mdEditor.ExecuteCommand(TEditorCommand.Italic); - mdEditor.SetFocus; + FocusEditor; end; procedure TMarkdown4DStudioVCLForm.HandleLinkClick(Sender: TObject); begin mdEditor.ExecuteCommand(TEditorCommand.Link); - mdEditor.SetFocus; + FocusEditor; end; procedure TMarkdown4DStudioVCLForm.HandleCodeClick(Sender: TObject); begin mdEditor.ExecuteCommand(TEditorCommand.CodeBlock); - mdEditor.SetFocus; + FocusEditor; end; procedure TMarkdown4DStudioVCLForm.HandleExportClick(Sender: TObject); @@ -770,7 +780,7 @@ procedure TMarkdown4DStudioVCLForm.HandleCopyHtmlClick(Sender: TObject); procedure TMarkdown4DStudioVCLForm.ExecuteFormatCommand(const Command: TEditorCommand); begin mdEditor.ExecuteCommand(Command); - mdEditor.SetFocus; + FocusEditor; end; procedure TMarkdown4DStudioVCLForm.DoExportHtml; @@ -1138,7 +1148,7 @@ procedure TMarkdown4DStudioVCLForm.HandleTocListClick(Sender: TObject); mdEditor.ScrollToSourceLine(SourceLine); lstToc.ItemIndex := Index; - mdEditor.SetFocus; + FocusEditor; end; procedure TMarkdown4DStudioVCLForm.HandleTick(Sender: TObject); @@ -1691,12 +1701,12 @@ function TMarkdown4DStudioVCLForm.BuildCommandActions: TPadCommandActions; Result.ShowFind := procedure begin ShowFindBar; end; Result.ShowReplace := procedure begin ShowReplaceBar; end; Result.FindInPreview := procedure begin ExecuteFind; end; - Result.Undo := procedure begin mdEditor.Undo; mdEditor.SetFocus; end; - Result.Redo := procedure begin mdEditor.Redo; mdEditor.SetFocus; end; - Result.SelectAll := procedure begin mdEditor.SelectAll; mdEditor.SetFocus; end; - Result.Indent := procedure begin mdEditor.Indent; mdEditor.SetFocus; end; - Result.Outdent := procedure begin mdEditor.Outdent; mdEditor.SetFocus; end; - Result.DeleteWordLeft := procedure begin mdEditor.DeleteWordLeft; mdEditor.SetFocus; end; + Result.Undo := procedure begin mdEditor.Undo; FocusEditor; end; + Result.Redo := procedure begin mdEditor.Redo; FocusEditor; end; + Result.SelectAll := procedure begin mdEditor.SelectAll; FocusEditor; end; + Result.Indent := procedure begin mdEditor.Indent; FocusEditor; end; + Result.Outdent := procedure begin mdEditor.Outdent; FocusEditor; end; + Result.DeleteWordLeft := procedure begin mdEditor.DeleteWordLeft; FocusEditor; end; Result.ExecuteFormat := procedure(const Command: TEditorCommand) begin @@ -1829,8 +1839,7 @@ procedure TMarkdown4DStudioVCLForm.CloseFindBar; EnforceTopBarOrder; - if mdEditor.CanFocus then - mdEditor.SetFocus; + FocusEditor; end; procedure TMarkdown4DStudioVCLForm.FindInEditor; @@ -1866,8 +1875,7 @@ procedure TMarkdown4DStudioVCLForm.ClosePalette; begin FPalette.Visible := False; - if mdEditor.CanFocus then - mdEditor.SetFocus; + FocusEditor; end; procedure TMarkdown4DStudioVCLForm.RefreshPaletteList; @@ -2018,8 +2026,7 @@ procedure TMarkdown4DStudioVCLForm.EnterZen; FZenActive := True; - if mdEditor.CanFocus then - mdEditor.SetFocus; + FocusEditor; end; procedure TMarkdown4DStudioVCLForm.ExitZen; @@ -2039,8 +2046,7 @@ procedure TMarkdown4DStudioVCLForm.ExitZen; FZenActive := False; - if mdEditor.CanFocus then - mdEditor.SetFocus; + FocusEditor; end; procedure TMarkdown4DStudioVCLForm.UpdateZenPadding;