mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-15 02:59:33 +07:00
[Markdown][IJPL-92156] Add the ability to change markdown preview font size
GitOrigin-RevId: 996ec1f34319107ae437d69866328c47ac6cb346
This commit is contained in:
committed by
intellij-monorepo-bot
parent
71c20d85f7
commit
4a576602a8
@@ -55,7 +55,7 @@ public abstract class KeymapsTestCase extends KeymapsTestCaseBase {
|
||||
{"control 1", "FileChooser.GotoHome", "GotoBookmark1", "DuplicatesForm.SendToLeft"},
|
||||
{"control 2", "FileChooser.GotoProject", "GotoBookmark2", "DuplicatesForm.SendToRight"},
|
||||
{"control 3", "GotoBookmark3", "FileChooser.GotoModule"},
|
||||
{"control ADD", "ExpandAll", "ExpandExpandableComponent", "ExpandRegion"},
|
||||
{"control ADD", "ExpandAll", "ExpandExpandableComponent", "ExpandRegion", "Markdown.Preview.IncreaseFontSize"},
|
||||
{"control A", "$SelectAll", "Terminal.MoveCaretToLineStart"},
|
||||
{"control B", "GotoDeclaration", "org.intellij.plugins.markdown.ui.actions.styling.ToggleBoldAction"},
|
||||
{"control C", "$Copy", "Terminal.ClearPrompt", "Terminal.CopySelectedText", "org.jetbrains.r.console.RConsoleView.RInterruptAction",
|
||||
@@ -69,19 +69,19 @@ public abstract class KeymapsTestCase extends KeymapsTestCaseBase {
|
||||
{"control ENTER", "Console.Execute.Multiline", "DirDiffMenu.SynchronizeDiff.All", "EditorSplitLine", "NotebookRunCellAction",
|
||||
"PyExecuteCellAction", "SplitChooser.Duplicate", "Terminal.SmartCommandExecution.Run", "ViewSource",
|
||||
"org.jetbrains.r.actions.RunSelection", "Docker.RemoteServers.StartComposeService", "GraphQLExecuteEditor"},
|
||||
{"control EQUALS", "ExpandAll", "ExpandExpandableComponent", "ExpandRegion"},
|
||||
{"control EQUALS", "ExpandAll", "ExpandExpandableComponent", "ExpandRegion", "Markdown.Preview.IncreaseFontSize"},
|
||||
{"control F5", "Refresh", "Rerun"},
|
||||
{"control I", "ImplementMethods", "org.intellij.plugins.markdown.ui.actions.styling.ToggleItalicAction"},
|
||||
{"control INSERT", "$Copy", "Terminal.CopySelectedText"},
|
||||
{"control M", "EditorScrollToCenter", "Vcs.ShowMessageHistory"},
|
||||
{"control MINUS", "CollapseAll", "CollapseExpandableComponent", "CollapseRegion"},
|
||||
{"control MINUS", "CollapseAll", "CollapseExpandableComponent", "CollapseRegion", "Markdown.Preview.DecreaseFontSize"},
|
||||
{"control N", "FileChooser.NewFolder", "GotoClass"},
|
||||
{"control P", "FileChooser.TogglePathBar", "ParameterInfo"},
|
||||
{"control PERIOD", "EditorChooseLookupItemDot", "CollapseSelection"},
|
||||
{"control R", "Replace", "Terminal.SearchInCommandHistory", "org.jetbrains.plugins.ruby.rails.console.ReloadSources"},
|
||||
{"control SLASH", "CommentByLineComment", "Graph.ActualSize"},
|
||||
{"control SPACE", "CodeCompletion", "ChangesView.SetDefault"},
|
||||
{"control SUBTRACT", "CollapseAll", "CollapseExpandableComponent", "CollapseRegion"},
|
||||
{"control SUBTRACT", "CollapseAll", "CollapseExpandableComponent", "CollapseRegion", "Markdown.Preview.DecreaseFontSize"},
|
||||
{"control U", "GotoSuperMethod", "CommanderSwapPanels", "org.intellij.plugins.markdown.ui.actions.styling.InsertImageAction"},
|
||||
{"control UP", "EditorScrollUp", "EditorLookupUp", "MethodOverloadSwitchUp", "NotebookSelectCellAboveAction",
|
||||
"Terminal.SelectLastBlock", "Terminal.SelectBlockAbove"},
|
||||
@@ -290,13 +290,13 @@ public abstract class KeymapsTestCase extends KeymapsTestCaseBase {
|
||||
{"ctrl H", "Replace", "Vcs.ShowMessageHistory"},
|
||||
{"ctrl I", "IncrementalSearch", "org.intellij.plugins.markdown.ui.actions.styling.ToggleItalicAction"},
|
||||
{"ctrl L", "EditorDeleteLine", "Terminal.ClearBuffer"},
|
||||
{"ctrl MINUS", "Back", "CollapseAll", "CollapseExpandableComponent"},
|
||||
{"ctrl MINUS", "Back", "CollapseAll", "CollapseExpandableComponent", "Markdown.Preview.DecreaseFontSize"},
|
||||
{"ctrl N", "FileChooser.NewFolder", "NewElement"},
|
||||
{"ctrl P", "FileChooser.TogglePathBar", "Print"},
|
||||
{"ctrl PERIOD", "EditorChooseLookupItemDot", "ShowIntentionActions"},
|
||||
{"ctrl R", SECOND_STROKE, "Terminal.SearchInCommandHistory", "org.jetbrains.plugins.ruby.rails.console.ReloadSources"},
|
||||
{"ctrl R,R", "ChangesView.Rename", "Git.Rename.Local.Branch", "Git.Reword.Commit", "RenameElement", "ShelvedChanges.Rename"},
|
||||
{"ctrl SUBTRACT", "Back", "CollapseAll", "CollapseExpandableComponent"},
|
||||
{"ctrl SUBTRACT", "Back", "CollapseAll", "CollapseExpandableComponent", "Markdown.Preview.DecreaseFontSize"},
|
||||
{"ctrl alt B", "ViewBreakpoints", "org.jetbrains.r.rendering.chunk.RunChunksAboveAction"},
|
||||
{"ctrl alt ENTER", "ReformatCode", "org.jetbrains.r.actions.DebugSelection"},
|
||||
{"ctrl alt F", "ActivateStructureToolWindow", "ShowFilterPopup"},
|
||||
@@ -333,8 +333,8 @@ public abstract class KeymapsTestCase extends KeymapsTestCaseBase {
|
||||
{"ctrl alt LEFT", "GotoSuperMethod", "ResizeToolWindowLeft"},
|
||||
{"meta Y", "$Redo", "QuickImplementations"},
|
||||
{"meta alt B", "ViewBreakpoints", "org.jetbrains.r.rendering.chunk.RunChunksAboveAction"},
|
||||
{"meta SUBTRACT", "Back", "CollapseAll", "CollapseExpandableComponent"},
|
||||
{"meta MINUS", "Back", "CollapseAll", "CollapseExpandableComponent"},
|
||||
{"meta SUBTRACT", "Back", "CollapseAll", "CollapseExpandableComponent", "Markdown.Preview.DecreaseFontSize"},
|
||||
{"meta MINUS", "Back", "CollapseAll", "CollapseExpandableComponent", "Markdown.Preview.DecreaseFontSize"},
|
||||
{"shift F5", "Graph.ApplyCurrentLayout", "Stop"},
|
||||
{"shift meta alt R", "ChooseRunConfiguration", "ForceRefresh"},
|
||||
{"ctrl alt F", "ActivateStructureToolWindow", "EditorNextWord", "ShowFilterPopup"},
|
||||
@@ -423,6 +423,8 @@ public abstract class KeymapsTestCase extends KeymapsTestCaseBase {
|
||||
{"shift ctrl alt LEFT", "NextEditorTab", "Diff.NextChange"},
|
||||
{"shift ctrl alt RIGHT", "PreviousEditorTab", "Diff.PrevChange"},
|
||||
{"shift ctrl DIVIDE", "CollapseAll", "CollapseAllRegions"},
|
||||
{"ctrl MINUS", "EditorDecreaseFontSizeGlobal", "Markdown.Preview.DecreaseFontSize"},
|
||||
{"ctrl EQUALS", "EditorIncreaseFontSizeGlobal", "Markdown.Preview.IncreaseFontSize"},
|
||||
}),
|
||||
Map.entry("NetBeans 6.5", new String[][]{
|
||||
{"F4", "RunToCursor", "EditSource"},
|
||||
@@ -495,6 +497,8 @@ public abstract class KeymapsTestCase extends KeymapsTestCaseBase {
|
||||
{"shift meta U", "FindUsagesInFile", "ShelveChanges.UnshelveWithDialog", "Markdown.Styling.CreateLink"},
|
||||
{"shift meta X", "EditorToggleCase", "com.jetbrains.php.framework.FrameworkRunConsoleAction"},
|
||||
{"shift meta DIVIDE", "CollapseAll", "CollapseAllRegions"},
|
||||
{"meta MINUS", "EditorDecreaseFontSizeGlobal", "Markdown.Preview.DecreaseFontSize"},
|
||||
{"meta EQUALS", "EditorIncreaseFontSizeGlobal", "Markdown.Preview.IncreaseFontSize"},
|
||||
}),
|
||||
Map.entry("Sublime Text", new String[][]{
|
||||
{"F2", "ChangesView.Rename", "Console.TableResult.EditValue", "Git.Reword.Commit", "Git.Rename.Local.Branch",
|
||||
@@ -502,22 +506,22 @@ public abstract class KeymapsTestCase extends KeymapsTestCaseBase {
|
||||
"XDebugger.SetValue", "Table-startEditing", "Tree-startEditing", "Console.TableResult.GotoReferencedResult"},
|
||||
{"F12", "GotoDeclaration", "WebInspector.Browser.Selection.Toggle"},
|
||||
{"alt MINUS", "Back", "RInsertAssignmentAction"},
|
||||
{"ctrl ADD", "EditorIncreaseFontSize", "ExpandAll", "ExpandExpandableComponent"},
|
||||
{"ctrl ADD", "EditorIncreaseFontSize", "ExpandAll", "ExpandExpandableComponent", "Markdown.Preview.IncreaseFontSize"},
|
||||
{"ctrl B", "Compile", "org.intellij.plugins.markdown.ui.actions.styling.ToggleBoldAction"},
|
||||
{"ctrl D", "CompareTwoFiles", "Diff.ShowDiff", "FileChooser.GotoDesktop", "SelectNextOccurrence", "SendEOF",
|
||||
"Terminal.CloseSession", "org.jetbrains.r.console.RConsoleView.REofAction"},
|
||||
{"ctrl ENTER", "Console.Execute.Multiline", "DirDiffMenu.SynchronizeDiff.All", "EditorStartNewLine", "NotebookRunCellAction",
|
||||
"PyExecuteCellAction", "ViewSource", "org.jetbrains.r.actions.RunSelection", "Terminal.SmartCommandExecution.Run",
|
||||
"SplitChooser.Duplicate", "Docker.RemoteServers.StartComposeService", "GraphQLExecuteEditor"},
|
||||
{"ctrl EQUALS", "EditorIncreaseFontSize", "ExpandAll", "ExpandExpandableComponent"},
|
||||
{"ctrl EQUALS", "EditorIncreaseFontSize", "ExpandAll", "ExpandExpandableComponent", "Markdown.Preview.IncreaseFontSize"},
|
||||
{"ctrl I", "IncrementalSearch", "org.intellij.plugins.markdown.ui.actions.styling.ToggleItalicAction"},
|
||||
{"ctrl L", "EditorSelectLine", "Terminal.ClearBuffer"},
|
||||
{"ctrl M", "EditorMatchBrace", "Vcs.ShowMessageHistory"},
|
||||
{"ctrl MINUS", "CollapseAll", "CollapseExpandableComponent", "EditorDecreaseFontSize"},
|
||||
{"ctrl MINUS", "CollapseAll", "CollapseExpandableComponent", "EditorDecreaseFontSize", "Markdown.Preview.DecreaseFontSize"},
|
||||
{"ctrl N", "FileChooser.NewFolder", "NewElement"},
|
||||
{"ctrl P", "FileChooser.TogglePathBar", "GotoFile"},
|
||||
{"ctrl R", "FileStructurePopup", "Terminal.SearchInCommandHistory", "org.jetbrains.plugins.ruby.rails.console.ReloadSources"},
|
||||
{"ctrl SUBTRACT", "CollapseAll", "CollapseExpandableComponent", "EditorDecreaseFontSize"},
|
||||
{"ctrl SUBTRACT", "CollapseAll", "CollapseExpandableComponent", "EditorDecreaseFontSize", "Markdown.Preview.DecreaseFontSize"},
|
||||
{"ctrl V", "EditorPasteSimple", "Terminal.Paste", "JupyterNotebookPasteCellCommandModeAction"},
|
||||
{"ctrl W", "CloseContent", "Terminal.DeletePreviousWord"},
|
||||
{"ctrl alt DOWN", "Console.TableResult.NextPage", "EditorCloneCaretBelow"},
|
||||
@@ -539,7 +543,7 @@ public abstract class KeymapsTestCase extends KeymapsTestCaseBase {
|
||||
"XDebugger.SetValue", "Table-startEditing", "Tree-startEditing", "Console.TableResult.GotoReferencedResult"},
|
||||
{"F12", "GotoDeclaration", "WebInspector.Browser.Selection.Toggle"},
|
||||
{"ctrl R", "GotoNextBookmark", "Terminal.SearchInCommandHistory"},
|
||||
{"meta ADD", "EditorIncreaseFontSize", "ExpandAll", "ExpandExpandableComponent"},
|
||||
{"meta ADD", "EditorIncreaseFontSize", "ExpandAll", "ExpandExpandableComponent", "Markdown.Preview.IncreaseFontSize"},
|
||||
{"meta B", "Compile", "org.intellij.plugins.markdown.ui.actions.styling.ToggleBoldAction"},
|
||||
{"meta BACK_SPACE", "EditorDeleteToLineStart", "$Delete"},
|
||||
{"meta D", "CompareTwoFiles", "Diff.ShowDiff", "FileChooser.GotoDesktop", "SelectNextOccurrence", "SendEOF"},
|
||||
@@ -547,14 +551,14 @@ public abstract class KeymapsTestCase extends KeymapsTestCaseBase {
|
||||
{"meta ENTER", "Console.Execute.Multiline", "DirDiffMenu.SynchronizeDiff.All", "EditorStartNewLine", "ViewSource",
|
||||
"org.jetbrains.r.actions.RunSelection", "Terminal.SmartCommandExecution.Run", "SplitChooser.Duplicate",
|
||||
"Docker.RemoteServers.StartComposeService", "GraphQLExecuteEditor"},
|
||||
{"meta EQUALS", "EditorIncreaseFontSize", "ExpandAll", "ExpandExpandableComponent"},
|
||||
{"meta EQUALS", "EditorIncreaseFontSize", "ExpandAll", "ExpandExpandableComponent", "Markdown.Preview.IncreaseFontSize"},
|
||||
{"meta I", "DatabaseView.PropertiesAction", "IncrementalSearch", "org.intellij.plugins.markdown.ui.actions.styling.ToggleItalicAction"},
|
||||
{"meta K", SECOND_STROKE, "Terminal.ClearBuffer"},
|
||||
{"meta L", "EditorSelectLine", "Terminal.ClearBuffer"},
|
||||
{"meta MINUS", "CollapseAll", "CollapseExpandableComponent", "EditorDecreaseFontSize"},
|
||||
{"meta MINUS", "CollapseAll", "CollapseExpandableComponent", "EditorDecreaseFontSize", "Markdown.Preview.DecreaseFontSize"},
|
||||
{"meta P", "FileChooser.TogglePathBar", "GotoFile"},
|
||||
{"meta R", "FileStructurePopup", "Refresh", "Rerun", "org.jetbrains.plugins.ruby.rails.console.ReloadSources"},
|
||||
{"meta SUBTRACT", "CollapseAll", "CollapseExpandableComponent", "EditorDecreaseFontSize"},
|
||||
{"meta SUBTRACT", "CollapseAll", "CollapseExpandableComponent", "EditorDecreaseFontSize", "Markdown.Preview.DecreaseFontSize"},
|
||||
{"meta T", "GotoFile", "Terminal.NewTab"},
|
||||
{"meta UP", "EditorTextStart", "FileChooser.GoToParent", "Terminal.SelectLastBlock", "Terminal.SelectBlockAbove"},
|
||||
{"meta V", "EditorPasteSimple", "Terminal.Paste", "JupyterNotebookPasteCellCommandModeAction"},
|
||||
|
||||
@@ -595,13 +595,25 @@
|
||||
class="org.intellij.plugins.markdown.extensions.CleanupExtensionsExternalFilesAction"
|
||||
icon="AllIcons.Actions.GC"/>
|
||||
|
||||
<group id="Markdown.Preview.FontSize" popup="true" compact="true">
|
||||
<group id="Markdown.Preview.FontSize" popup="true">
|
||||
<action id="Markdown.Preview.IncreaseFontSize"
|
||||
class="org.intellij.plugins.markdown.ui.actions.ChangeFontSizeAction$Increase"/>
|
||||
class="org.intellij.plugins.markdown.ui.actions.ChangeFontSizeAction$Increase">
|
||||
<keyboard-shortcut first-keystroke="control ADD" keymap="$default"/>
|
||||
<keyboard-shortcut first-keystroke="control EQUALS" keymap="$default"/>
|
||||
</action>
|
||||
<action id="Markdown.Preview.DecreaseFontSize"
|
||||
class="org.intellij.plugins.markdown.ui.actions.ChangeFontSizeAction$Decrease"/>
|
||||
<action id="Markdown.Preview.ResetFontSize"
|
||||
class="org.intellij.plugins.markdown.ui.actions.ChangeFontSizeAction$Reset"/>
|
||||
class="org.intellij.plugins.markdown.ui.actions.ChangeFontSizeAction$Decrease">
|
||||
<keyboard-shortcut first-keystroke="control MINUS" keymap="$default"/>
|
||||
<keyboard-shortcut first-keystroke="control SUBTRACT" keymap="$default"/>
|
||||
</action>
|
||||
</group>
|
||||
|
||||
<group id="Markdown.PreviewGroup">
|
||||
<action id="Markdown.Preview.AdjustFontSize"
|
||||
class="org.intellij.plugins.markdown.ui.actions.AdjustFontSizeAction"/>
|
||||
</group>
|
||||
|
||||
<action id="Markdown.Preview.ResetFontSize"
|
||||
class="org.intellij.plugins.markdown.ui.actions.ResetFontSizeAction"/>
|
||||
</actions>
|
||||
</idea-plugin>
|
||||
|
||||
@@ -367,3 +367,6 @@ group.Markdown.Preview.FontSize.text=Preview Font Size
|
||||
action.Markdown.Preview.IncreaseFontSize.text=Increase Preview Font Size
|
||||
action.Markdown.Preview.DecreaseFontSize.text=Decrease Preview Font Size
|
||||
action.Markdown.Preview.ResetFontSize.text=Reset Preview Font Size
|
||||
|
||||
action.Markdown.Preview.AdjustFontSize.text=Adjust Font Size\u2026
|
||||
action.Markdown.Preview.FontSize.label.text=Font size:
|
||||
@@ -19,6 +19,7 @@ import com.intellij.openapi.fileTypes.UnknownFileType
|
||||
import com.intellij.openapi.options.BoundSearchableConfigurable
|
||||
import com.intellij.openapi.options.ex.Settings
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.ui.ComboBox
|
||||
import com.intellij.openapi.ui.DialogPanel
|
||||
import com.intellij.openapi.ui.TextFieldWithBrowseButton
|
||||
import com.intellij.openapi.ui.ValidationInfo
|
||||
@@ -27,7 +28,6 @@ import com.intellij.ui.EnumComboBoxModel
|
||||
import com.intellij.ui.SimpleListCellRenderer
|
||||
import com.intellij.ui.components.ActionLink
|
||||
import com.intellij.ui.components.JBCheckBox
|
||||
import com.intellij.ui.components.JBTextField
|
||||
import com.intellij.ui.dsl.builder.*
|
||||
import com.intellij.ui.layout.ValidationInfoBuilder
|
||||
import com.intellij.util.application
|
||||
@@ -159,15 +159,19 @@ internal class MarkdownSettingsConfigurable(private val project: Project): Bound
|
||||
}
|
||||
}
|
||||
|
||||
private fun Row.previewFontSizeField(): Cell<JBTextField> {
|
||||
return intTextField(range = 0..300).bindIntText(
|
||||
private fun Row.previewFontSizeField(): Cell<ComboBox<Int>> {
|
||||
return comboBox(fontSizeOptions).bindItem(
|
||||
getter = { service<MarkdownPreviewSettings>().state.fontSize },
|
||||
setter = { value ->
|
||||
service<MarkdownPreviewSettings>().update { settings ->
|
||||
settings.state.fontSize = value
|
||||
if (value != null) {
|
||||
settings.state.fontSize = value
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
).applyToComponent {
|
||||
isEditable = true
|
||||
}
|
||||
}
|
||||
|
||||
private fun validateCustomStylesheetPath(builder: ValidationInfoBuilder, textField: TextFieldWithBrowseButton): ValidationInfo? {
|
||||
@@ -374,5 +378,7 @@ internal class MarkdownSettingsConfigurable(private val project: Project): Bound
|
||||
else -> ""
|
||||
}
|
||||
}
|
||||
|
||||
val fontSizeOptions = listOf(8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28, 36, 48, 72)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.intellij.plugins.markdown.ui.actions
|
||||
|
||||
import com.intellij.icons.AllIcons
|
||||
import com.intellij.openapi.actionSystem.ActionUpdateThread
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.project.DumbAwareAction
|
||||
import com.intellij.openapi.ui.popup.JBPopupFactory
|
||||
import com.intellij.openapi.util.IconLoader
|
||||
import com.intellij.ui.components.JBLabel
|
||||
import com.intellij.util.ui.JBUI
|
||||
import org.intellij.plugins.markdown.MarkdownBundle
|
||||
import org.intellij.plugins.markdown.settings.MarkdownPreviewSettings
|
||||
import org.intellij.plugins.markdown.settings.MarkdownSettingsConfigurable.Companion.fontSizeOptions
|
||||
import org.intellij.plugins.markdown.ui.preview.MarkdownPreviewFileEditor
|
||||
import org.intellij.plugins.markdown.ui.preview.MarkdownPreviewFileEditor.Companion.PREVIEW_POPUP_POINT
|
||||
import org.intellij.plugins.markdown.ui.preview.jcef.MarkdownJCEFHtmlPanel
|
||||
import java.awt.FlowLayout
|
||||
import javax.swing.BorderFactory
|
||||
import javax.swing.JButton
|
||||
import javax.swing.JPanel
|
||||
import javax.swing.SwingConstants
|
||||
|
||||
class AdjustFontSizeAction: DumbAwareAction() {
|
||||
private val previewSettings
|
||||
get() = service<MarkdownPreviewSettings>()
|
||||
|
||||
override fun actionPerformed(event: AnActionEvent) {
|
||||
val editor = MarkdownActionUtil.findMarkdownPreviewEditor(event)
|
||||
checkNotNull(editor) { "Preview editor should be obtainable from the action event" }
|
||||
val preview = editor.getUserData(MarkdownPreviewFileEditor.PREVIEW_BROWSER)?.get() ?: return
|
||||
if (preview !is MarkdownJCEFHtmlPanel) {
|
||||
return
|
||||
}
|
||||
|
||||
val fontSizeLabel = JBLabel(previewSettings.state.fontSize.toString(), SwingConstants.CENTER).apply {
|
||||
preferredSize = JBUI.size(22, 22)
|
||||
}
|
||||
val decreaseButton = JButton(AllIcons.General.Remove).apply {
|
||||
border = BorderFactory.createEmptyBorder()
|
||||
isContentAreaFilled = false
|
||||
preferredSize = JBUI.size(22, 22)
|
||||
|
||||
setDisabledIcon(IconLoader.getDisabledIcon(AllIcons.General.Remove))
|
||||
isEnabled = previewSettings.state.fontSize != fontSizeOptions.first()
|
||||
}
|
||||
val increaseButton = JButton(AllIcons.General.Add).apply {
|
||||
border = BorderFactory.createEmptyBorder()
|
||||
isContentAreaFilled = false
|
||||
preferredSize = JBUI.size(22, 22)
|
||||
|
||||
setDisabledIcon(IconLoader.getDisabledIcon(AllIcons.General.Add))
|
||||
isEnabled = previewSettings.state.fontSize != fontSizeOptions.last()
|
||||
}
|
||||
|
||||
fun updateFontSize(transform: (Int) -> Int?) {
|
||||
val currentSize = preview.getCurrentFontSize()
|
||||
val newSize = transform(currentSize) ?: currentSize
|
||||
previewSettings.state.fontSize = newSize
|
||||
preview.changeFontSize(newSize)
|
||||
|
||||
fontSizeLabel.text = newSize.toString()
|
||||
decreaseButton.isEnabled = newSize != fontSizeOptions.first()
|
||||
increaseButton.isEnabled = newSize != fontSizeOptions.last()
|
||||
}
|
||||
|
||||
val hintComponent = JPanel(FlowLayout(FlowLayout.LEFT, 10, 5))
|
||||
hintComponent.add(JBLabel(MarkdownBundle.message("action.Markdown.Preview.FontSize.label.text")))
|
||||
hintComponent.add(decreaseButton.apply { addActionListener { updateFontSize { fontSizeOptions.findLast { step -> step < it } } } })
|
||||
hintComponent.add(fontSizeLabel.apply { text = preview.getCurrentFontSize().toString() })
|
||||
hintComponent.add(increaseButton.apply { addActionListener { updateFontSize { fontSizeOptions.find { step -> step > it } } } })
|
||||
|
||||
val popup = JBPopupFactory.getInstance().createComponentPopupBuilder(hintComponent, hintComponent).setRequestFocus(true).createPopup()
|
||||
val point = event.dataContext.getData(PREVIEW_POPUP_POINT)
|
||||
if (point != null) {
|
||||
popup.show(point)
|
||||
} else {
|
||||
popup.showInFocusCenter()
|
||||
}
|
||||
}
|
||||
|
||||
private fun MarkdownJCEFHtmlPanel.getCurrentFontSize() = getTemporaryFontSize() ?: previewSettings.state.fontSize
|
||||
|
||||
override fun update(event: AnActionEvent) {
|
||||
val editor = MarkdownActionUtil.findMarkdownPreviewEditor(event)
|
||||
event.presentation.isEnabledAndVisible = editor != null
|
||||
}
|
||||
|
||||
override fun getActionUpdateThread(): ActionUpdateThread {
|
||||
return ActionUpdateThread.EDT
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,23 +2,20 @@ package org.intellij.plugins.markdown.ui.actions
|
||||
|
||||
import com.intellij.openapi.actionSystem.ActionUpdateThread
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.project.DumbAwareAction
|
||||
import com.intellij.openapi.util.Key
|
||||
import com.intellij.ui.jcef.JBCefApp
|
||||
import com.intellij.openapi.ui.popup.Balloon
|
||||
import com.intellij.ui.awt.RelativePoint
|
||||
import org.intellij.plugins.markdown.ui.preview.MarkdownPreviewFileEditor
|
||||
import org.intellij.plugins.markdown.ui.preview.PreviewLAFThemeStyles
|
||||
import org.intellij.plugins.markdown.ui.preview.jcef.MarkdownJCEFHtmlPanel
|
||||
import org.intellij.plugins.markdown.ui.preview.jcef.impl.executeJavaScript
|
||||
|
||||
private val FontSize = Key.create<Int>("Markdown.Preview.FontSize")
|
||||
import org.intellij.plugins.markdown.ui.preview.jcef.zoomIndicator.PreviewZoomIndicatorManager
|
||||
|
||||
internal sealed class ChangeFontSizeAction(private val transform: (Int) -> Int): DumbAwareAction() {
|
||||
class Increase: ChangeFontSizeAction(transform = { it + 1 })
|
||||
|
||||
class Decrease: ChangeFontSizeAction(transform = { (it - 1).coerceAtLeast(1) })
|
||||
|
||||
class Reset: ChangeFontSizeAction(transform = { PreviewLAFThemeStyles.defaultFontSize })
|
||||
|
||||
override fun actionPerformed(event: AnActionEvent) {
|
||||
val editor = MarkdownActionUtil.findMarkdownPreviewEditor(event)
|
||||
checkNotNull(editor) { "Preview editor should be obtainable from the action event" }
|
||||
@@ -26,10 +23,12 @@ internal sealed class ChangeFontSizeAction(private val transform: (Int) -> Int):
|
||||
if (preview !is MarkdownJCEFHtmlPanel) {
|
||||
return
|
||||
}
|
||||
val currentSize = preview.getUserData(FontSize) ?: PreviewLAFThemeStyles.defaultFontSize
|
||||
val currentSize = preview.getTemporaryFontSize() ?: PreviewLAFThemeStyles.defaultFontSize
|
||||
val newSize = transform(currentSize)
|
||||
preview.putUserData(FontSize, newSize)
|
||||
preview.changeFontSize(newSize)
|
||||
preview.changeFontSize(newSize, temporary = true)
|
||||
val project = event.project
|
||||
val balloon = project?.service<PreviewZoomIndicatorManager>()?.createOrGetBalloon(preview)
|
||||
balloon?.show(RelativePoint.getSouthOf(preview.component), Balloon.Position.below)
|
||||
}
|
||||
|
||||
override fun update(event: AnActionEvent) {
|
||||
@@ -41,18 +40,3 @@ internal sealed class ChangeFontSizeAction(private val transform: (Int) -> Int):
|
||||
return ActionUpdateThread.EDT
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param size Unscaled font size.
|
||||
*/
|
||||
internal fun MarkdownJCEFHtmlPanel.changeFontSize(size: Int) {
|
||||
val scaled = JBCefApp.normalizeScaledSize(size)
|
||||
// language=JavaScript
|
||||
val code = """
|
||||
|(function() {
|
||||
| const styles = document.querySelector(":root").style;
|
||||
| styles.setProperty("${PreviewLAFThemeStyles.Variables.FontSize}", "${scaled}px");
|
||||
|})();
|
||||
""".trimMargin()
|
||||
executeJavaScript(code)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.intellij.plugins.markdown.ui.actions
|
||||
|
||||
import com.intellij.ide.IdeBundle
|
||||
import com.intellij.openapi.actionSystem.ActionPlaces
|
||||
import com.intellij.openapi.actionSystem.ActionUpdateThread
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent
|
||||
import com.intellij.openapi.project.DumbAwareAction
|
||||
import org.intellij.plugins.markdown.ui.preview.MarkdownPreviewFileEditor.Companion.PREVIEW_JCEF_PANEL
|
||||
import org.intellij.plugins.markdown.ui.preview.PreviewLAFThemeStyles
|
||||
|
||||
internal class ResetFontSizeAction: DumbAwareAction() {
|
||||
override fun actionPerformed(event: AnActionEvent) {
|
||||
val preview = event.getRequiredData(PREVIEW_JCEF_PANEL).get() ?: return
|
||||
preview.changeFontSize(PreviewLAFThemeStyles.defaultFontSize, temporary = true)
|
||||
}
|
||||
|
||||
override fun update(event: AnActionEvent) {
|
||||
if (event.place == ActionPlaces.POPUP) {
|
||||
event.presentation.text = IdeBundle.message("action.reset.font.size", PreviewLAFThemeStyles.defaultFontSize)
|
||||
val toReset = PreviewLAFThemeStyles.defaultFontSize
|
||||
val preview = event.dataContext.getData(PREVIEW_JCEF_PANEL)?.get() ?: return
|
||||
val currentSize = preview.getTemporaryFontSize()
|
||||
event.presentation.setEnabled(currentSize != toReset)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getActionUpdateThread(): ActionUpdateThread {
|
||||
return ActionUpdateThread.EDT
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
package org.intellij.plugins.markdown.ui.preview
|
||||
|
||||
import com.intellij.CommonBundle
|
||||
import com.intellij.ide.DataManager
|
||||
import com.intellij.openapi.actionSystem.DataKey
|
||||
import com.intellij.openapi.actionSystem.ex.ActionUtil
|
||||
import com.intellij.openapi.actionSystem.impl.SimpleDataContext
|
||||
import com.intellij.openapi.application.EDT
|
||||
import com.intellij.openapi.application.readAction
|
||||
import com.intellij.openapi.editor.Document
|
||||
@@ -14,13 +18,16 @@ import com.intellij.openapi.fileEditor.FileEditorState
|
||||
import com.intellij.openapi.fileEditor.TextEditorWithPreview
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.ui.Messages
|
||||
import com.intellij.openapi.ui.popup.JBPopupFactory
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.openapi.util.Key
|
||||
import com.intellij.openapi.util.UserDataHolder
|
||||
import com.intellij.openapi.util.UserDataHolderBase
|
||||
import com.intellij.openapi.util.registry.Registry
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.ui.awt.RelativePoint
|
||||
import com.intellij.util.concurrency.annotations.RequiresEdt
|
||||
import com.intellij.util.ui.StartupUiUtil
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
@@ -30,16 +37,21 @@ import org.intellij.plugins.markdown.MarkdownBundle
|
||||
import org.intellij.plugins.markdown.settings.MarkdownExtensionsSettings
|
||||
import org.intellij.plugins.markdown.settings.MarkdownSettings
|
||||
import org.intellij.plugins.markdown.ui.preview.html.MarkdownUtil.generateMarkdownHtml
|
||||
import org.intellij.plugins.markdown.ui.preview.jcef.MarkdownJCEFHtmlPanel
|
||||
import org.intellij.plugins.markdown.util.MarkdownPluginScope
|
||||
import org.jetbrains.annotations.ApiStatus.Internal
|
||||
import java.awt.AWTEvent
|
||||
import java.awt.BorderLayout
|
||||
import java.awt.Point
|
||||
import java.awt.event.ComponentAdapter
|
||||
import java.awt.event.ComponentEvent
|
||||
import java.awt.event.MouseEvent
|
||||
import java.beans.PropertyChangeListener
|
||||
import java.lang.ref.WeakReference
|
||||
import javax.swing.JComponent
|
||||
import javax.swing.JPanel
|
||||
|
||||
|
||||
@Internal
|
||||
class MarkdownPreviewFileEditor(
|
||||
private val project: Project,
|
||||
@@ -78,6 +90,33 @@ class MarkdownPreviewFileEditor(
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
StartupUiUtil.addAwtListener(AWTEvent.MOUSE_EVENT_MASK, this) { event ->
|
||||
if (event is MouseEvent && event.id == MouseEvent.MOUSE_CLICKED && event.button == MouseEvent.BUTTON3
|
||||
&& event.component.isShowing() && htmlPanelWrapper.isShowing()
|
||||
&& component.containsScreenLocation(event.locationOnScreen)
|
||||
) {
|
||||
val context = SimpleDataContext.builder()
|
||||
.setParent(DataManager.getInstance().getDataContext(event.component))
|
||||
.add(PREVIEW_POPUP_POINT, RelativePoint.fromScreen(event.locationOnScreen))
|
||||
.build()
|
||||
val group = requireNotNull(ActionUtil.getActionGroup("Markdown.PreviewGroup"))
|
||||
val popup = JBPopupFactory.getInstance().createActionGroupPopup(
|
||||
null,
|
||||
group,
|
||||
context,
|
||||
JBPopupFactory.ActionSelectionAid.MNEMONICS,
|
||||
true
|
||||
)
|
||||
popup.showInScreenCoordinates(event.component, event.locationOnScreen)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun JComponent.containsScreenLocation(screenLocation: Point): Boolean {
|
||||
val relativeX = screenLocation.x - locationOnScreen.x
|
||||
val relativeY = screenLocation.y - locationOnScreen.y
|
||||
return (relativeX >= 0 && relativeX < size.width && relativeY >= 0 && relativeY < size.height)
|
||||
}
|
||||
|
||||
private suspend fun setupScrollHelper() {
|
||||
@@ -238,5 +277,8 @@ class MarkdownPreviewFileEditor(
|
||||
|
||||
companion object {
|
||||
val PREVIEW_BROWSER: Key<WeakReference<MarkdownHtmlPanel>> = Key.create("PREVIEW_BROWSER")
|
||||
|
||||
internal val PREVIEW_POPUP_POINT: DataKey<RelativePoint> = DataKey.create("PREVIEW_POPUP_POINT")
|
||||
internal val PREVIEW_JCEF_PANEL: DataKey<WeakReference<MarkdownJCEFHtmlPanel>> = DataKey.create("PREVIEW_JCEF_PANEL")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.intellij.plugins.markdown.ui.preview
|
||||
|
||||
import com.intellij.ide.ui.UISettings
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.editor.colors.EditorColorsManager
|
||||
import com.intellij.openapi.editor.colors.EditorColorsScheme
|
||||
@@ -19,6 +20,7 @@ internal object PreviewLAFThemeStyles {
|
||||
@Suppress("ConstPropertyName", "CssInvalidHtmlTagReference")
|
||||
object Variables {
|
||||
const val FontSize = "--default-font-size"
|
||||
const val Scale = "--scale"
|
||||
}
|
||||
|
||||
val defaultFontSize: Int
|
||||
@@ -43,15 +45,19 @@ internal object PreviewLAFThemeStyles {
|
||||
val markdownFenceBackground = JBColor(Color(212, 222, 231, 255 / 4), Color(212, 222, 231, 25))
|
||||
val fontSize = JBCefApp.normalizeScaledSize(defaultFontSize)
|
||||
val backgroundColor = scheme.defaultBackground.webRgba()
|
||||
val scale = service<UISettings>().currentIdeScale
|
||||
// language=CSS
|
||||
return """
|
||||
:root {
|
||||
${Variables.FontSize}: ${fontSize}px;
|
||||
${Variables.Scale}: ${scale};
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: ${backgroundColor};
|
||||
font-size: var(${Variables.FontSize}) !important;
|
||||
transform: scale(var(${Variables.Scale})) !important;
|
||||
transform-origin: 0 0;
|
||||
}
|
||||
|
||||
body, p, blockquote, ul, ol, dl, table, pre, code, tr {
|
||||
|
||||
@@ -1,16 +1,23 @@
|
||||
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.intellij.plugins.markdown.ui.preview.jcef
|
||||
|
||||
import com.intellij.ide.ui.UISettingsListener
|
||||
import com.intellij.openapi.application.readAction
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.diagnostic.logger
|
||||
import com.intellij.openapi.project.BaseProjectDirectories
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.ui.popup.Balloon
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.openapi.util.Key
|
||||
import com.intellij.openapi.util.UserDataHolder
|
||||
import com.intellij.openapi.util.UserDataHolderBase
|
||||
import com.intellij.openapi.util.registry.Registry
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.ui.awt.RelativePoint
|
||||
import com.intellij.ui.components.JBLoadingPanel
|
||||
import com.intellij.ui.components.JBViewport
|
||||
import com.intellij.ui.components.Magnificator
|
||||
import com.intellij.ui.jcef.JBCefApp
|
||||
import com.intellij.ui.jcef.JBCefClient
|
||||
import com.intellij.ui.jcef.JCEFHtmlPanel
|
||||
@@ -32,16 +39,19 @@ import org.intellij.markdown.html.HtmlGenerator
|
||||
import org.intellij.plugins.markdown.extensions.MarkdownBrowserPreviewExtension
|
||||
import org.intellij.plugins.markdown.extensions.MarkdownConfigurableExtension
|
||||
import org.intellij.plugins.markdown.settings.MarkdownPreviewSettings
|
||||
import org.intellij.plugins.markdown.ui.actions.changeFontSize
|
||||
import org.intellij.plugins.markdown.settings.MarkdownSettingsConfigurable.Companion.fontSizeOptions
|
||||
import org.intellij.plugins.markdown.ui.preview.*
|
||||
import org.intellij.plugins.markdown.ui.preview.jcef.impl.*
|
||||
import org.intellij.plugins.markdown.ui.preview.jcef.zoomIndicator.PreviewZoomIndicatorManager
|
||||
import org.intellij.plugins.markdown.util.MarkdownApplicationScope
|
||||
import org.intellij.plugins.markdown.util.MarkdownPluginScope
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import java.awt.BorderLayout
|
||||
import java.awt.Point
|
||||
import java.net.URL
|
||||
import javax.swing.JComponent
|
||||
import kotlin.math.round
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
|
||||
class MarkdownJCEFHtmlPanel(
|
||||
@@ -120,7 +130,7 @@ class MarkdownJCEFHtmlPanel(
|
||||
data class Update(
|
||||
val content: String,
|
||||
val initialScrollOffset: Int,
|
||||
val document: VirtualFile?
|
||||
val document: VirtualFile?,
|
||||
) : PreviewRequest
|
||||
|
||||
data class ReloadWithOffset(val offset: Int) : PreviewRequest
|
||||
@@ -159,6 +169,17 @@ class MarkdownJCEFHtmlPanel(
|
||||
connection.subscribe(MarkdownPreviewSettings.ChangeListener.TOPIC, MarkdownPreviewSettings.ChangeListener { settings ->
|
||||
changeFontSize(settings.state.fontSize)
|
||||
})
|
||||
connection.subscribe(UISettingsListener.TOPIC, UISettingsListener { settings ->
|
||||
val scale = settings.currentIdeScale
|
||||
// language=JavaScript
|
||||
val code = """
|
||||
|(function() {
|
||||
| const styles = document.querySelector(":root").style;
|
||||
| styles.setProperty("${PreviewLAFThemeStyles.Variables.Scale}", "${scale}");
|
||||
|})();
|
||||
""".trimMargin()
|
||||
executeJavaScript(code)
|
||||
})
|
||||
|
||||
coroutineScope.launch {
|
||||
val projectRoot = projectRoot.await()
|
||||
@@ -272,20 +293,68 @@ class MarkdownJCEFHtmlPanel(
|
||||
executeJavaScript("window.scrollController?.scrollBy($horizontal, $vertical)")
|
||||
}
|
||||
|
||||
private var previewInnerComponent: JComponent? = null
|
||||
private val TEMPORARY_FONT_SIZE = Key.create<Int>("Markdown.Preview.FontSize")
|
||||
|
||||
private fun createComponent(): JComponent {
|
||||
val component = super.getComponent()
|
||||
if (project == null || virtualFile == null) return component
|
||||
previewInnerComponent = super.getComponent()
|
||||
if (project == null || virtualFile == null) return previewInnerComponent!!
|
||||
|
||||
val panel = JBLoadingPanel(BorderLayout(), this)
|
||||
|
||||
previewInnerComponent!!.putClientProperty(Magnificator.CLIENT_PROPERTY_KEY, object: Magnificator {
|
||||
override fun magnify(scale: Double, at: Point): Point {
|
||||
val currentSize = this@MarkdownJCEFHtmlPanel.getTemporaryFontSize() ?: PreviewLAFThemeStyles.defaultFontSize
|
||||
var fontSize = round(currentSize * scale).toInt()
|
||||
fontSize = maxOf(fontSize, fontSizeOptions.first())
|
||||
fontSize = minOf(fontSize, fontSizeOptions.last())
|
||||
changeFontSize(fontSize, temporary = true)
|
||||
|
||||
return at
|
||||
}
|
||||
})
|
||||
|
||||
previewInnerComponent!!.addPropertyChangeListener(TEMPORARY_FONT_SIZE.toString()) {
|
||||
val balloon = project.service<PreviewZoomIndicatorManager>().createOrGetBalloon(this@MarkdownJCEFHtmlPanel)
|
||||
balloon?.show(RelativePoint.getSouthOf(previewInnerComponent!!), Balloon.Position.below)
|
||||
}
|
||||
|
||||
coroutineScope.async(context = Dispatchers.Default, start = CoroutineStart.UNDISPATCHED) {
|
||||
panel.startLoading()
|
||||
panel.add(component)
|
||||
val viewPort = JBViewport()
|
||||
viewPort.add(previewInnerComponent)
|
||||
panel.add(viewPort)
|
||||
projectRoot.await()
|
||||
panel.stopLoading()
|
||||
}
|
||||
return panel
|
||||
}
|
||||
|
||||
fun getTemporaryFontSize() = getUserData(TEMPORARY_FONT_SIZE)
|
||||
|
||||
/**
|
||||
* @param size Unscaled font size.
|
||||
*/
|
||||
internal fun changeFontSize(size: Int, temporary: Boolean = false) {
|
||||
if (temporary) {
|
||||
val previousSize = getUserData(TEMPORARY_FONT_SIZE) ?: PreviewLAFThemeStyles.defaultFontSize
|
||||
putUserData(TEMPORARY_FONT_SIZE, size)
|
||||
previewInnerComponent?.firePropertyChange(TEMPORARY_FONT_SIZE.toString(), previousSize, size)
|
||||
} else {
|
||||
putUserData(TEMPORARY_FONT_SIZE, null)
|
||||
}
|
||||
|
||||
val scaled = JBCefApp.normalizeScaledSize(size)
|
||||
// language=JavaScript
|
||||
val code = """
|
||||
|(function() {
|
||||
| const styles = document.querySelector(":root").style;
|
||||
| styles.setProperty("${PreviewLAFThemeStyles.Variables.FontSize}", "${scaled}px");
|
||||
|})();
|
||||
""".trimMargin()
|
||||
executeJavaScript(code)
|
||||
}
|
||||
|
||||
private fun createFileSchemeResourcesProcessor(projectRoot: VirtualFile?): ResourceProvider? {
|
||||
if (projectRoot == null) return null
|
||||
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.intellij.plugins.markdown.ui.preview.jcef.zoomIndicator
|
||||
|
||||
import com.intellij.openapi.actionSystem.ActionPlaces
|
||||
import com.intellij.openapi.actionSystem.AnAction
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent
|
||||
import com.intellij.openapi.actionSystem.AnActionResult
|
||||
import com.intellij.openapi.actionSystem.ex.AnActionListener
|
||||
import com.intellij.openapi.application.EDT
|
||||
import com.intellij.openapi.components.Service
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.ui.popup.Balloon
|
||||
import com.intellij.openapi.ui.popup.JBPopupFactory
|
||||
import com.intellij.ui.BalloonImpl
|
||||
import com.intellij.ui.ExperimentalUI
|
||||
import com.intellij.ui.JBColor
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.channels.BufferOverflow
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
import org.intellij.plugins.markdown.ui.preview.jcef.MarkdownJCEFHtmlPanel
|
||||
import org.intellij.plugins.markdown.util.MarkdownPluginScope
|
||||
import java.lang.ref.WeakReference
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
@Service(Service.Level.PROJECT)
|
||||
class PreviewZoomIndicatorManager(project: Project) {
|
||||
private val coroutineScope = MarkdownPluginScope.createChildScope(project)
|
||||
|
||||
private val cancelBalloonRequests = MutableSharedFlow<Unit>(replay = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST)
|
||||
|
||||
private var balloon: Balloon? = null
|
||||
private var preview: WeakReference<MarkdownJCEFHtmlPanel> = WeakReference(null)
|
||||
|
||||
init {
|
||||
project.messageBus.connect().subscribe(AnActionListener.TOPIC, object : AnActionListener {
|
||||
override fun afterActionPerformed(action: AnAction, event: AnActionEvent, result: AnActionResult) {
|
||||
if (event.place == ActionPlaces.POPUP && action is PreviewZoomIndicatorView.SettingsAction) {
|
||||
cancelCurrentPopup()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
coroutineScope.launch(context = Dispatchers.EDT) {
|
||||
cancelBalloonRequests.collectLatest {
|
||||
val b = balloon ?: return@collectLatest
|
||||
b.getView().isHovered().collectLatest { isHovered ->
|
||||
if (!isHovered) {
|
||||
delay(5.seconds)
|
||||
cancelCurrentPopup()
|
||||
} else {
|
||||
check(cancelBalloonRequests.tryEmit(Unit))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun createOrGetBalloon(preview: MarkdownJCEFHtmlPanel): Balloon? {
|
||||
val view = PreviewZoomIndicatorView(preview)
|
||||
val b = balloon
|
||||
if (this.preview.refersTo(preview) && (b as? BalloonImpl)?.isVisible == true) {
|
||||
b.getView().updateFontSize()
|
||||
return null
|
||||
}
|
||||
cancelCurrentPopup()
|
||||
val newUI = ExperimentalUI.isNewUI()
|
||||
val b2 = JBPopupFactory.getInstance().createBalloonBuilder(view)
|
||||
.setRequestFocus(false)
|
||||
.setShadow(true)
|
||||
.setFillColor(if (newUI) JBColor.namedColor("Toolbar.Floating.background", JBColor(0xEDEDED, 0x454A4D)) else view.background)
|
||||
.setBorderColor(if (newUI) JBColor.namedColor("Toolbar.Floating.borderColor", JBColor(0xEBECF0, 0x43454A)) else JBColor.border())
|
||||
.setShowCallout(false)
|
||||
.setFadeoutTime(0)
|
||||
.setHideOnKeyOutside(false)
|
||||
.createBalloon().apply { setAnimationEnabled(false) }
|
||||
balloon = b2
|
||||
check(cancelBalloonRequests.tryEmit(Unit))
|
||||
this.preview = WeakReference(preview)
|
||||
return b2
|
||||
}
|
||||
|
||||
fun cancelCurrentPopup() {
|
||||
balloon?.hide()
|
||||
balloon = null
|
||||
preview.clear()
|
||||
}
|
||||
|
||||
private fun Balloon.getView() = ((this as BalloonImpl).content as PreviewZoomIndicatorView)
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.intellij.plugins.markdown.ui.preview.jcef.zoomIndicator
|
||||
|
||||
import com.intellij.icons.AllIcons
|
||||
import com.intellij.ide.IdeBundle
|
||||
import com.intellij.ide.actions.ShowSettingsUtilImpl
|
||||
import com.intellij.openapi.actionSystem.*
|
||||
import com.intellij.openapi.actionSystem.ex.ActionUtil
|
||||
import com.intellij.openapi.actionSystem.impl.ActionButton
|
||||
import com.intellij.openapi.actionSystem.impl.SimpleDataContext
|
||||
import com.intellij.openapi.project.DumbAwareAction
|
||||
import com.intellij.ui.components.AnActionLink
|
||||
import com.intellij.util.ui.JBUI
|
||||
import kotlinx.coroutines.channels.BufferOverflow
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import net.miginfocom.swing.MigLayout
|
||||
import org.intellij.plugins.markdown.MarkdownBundle
|
||||
import org.intellij.plugins.markdown.ui.preview.MarkdownPreviewFileEditor.Companion.PREVIEW_JCEF_PANEL
|
||||
import org.intellij.plugins.markdown.ui.preview.jcef.MarkdownJCEFHtmlPanel
|
||||
import java.awt.event.MouseAdapter
|
||||
import java.awt.event.MouseEvent
|
||||
import java.lang.ref.WeakReference
|
||||
import javax.swing.JLabel
|
||||
import javax.swing.JPanel
|
||||
|
||||
class PreviewZoomIndicatorView(private val preview: MarkdownJCEFHtmlPanel) : JPanel(MigLayout("novisualpadding, ins 0")) {
|
||||
private val isHoveredFlow = MutableSharedFlow<Boolean>(replay = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST)
|
||||
|
||||
private val fontSizeLabel = JLabel(IdeBundle.message("action.reset.font.size.info", "000"))
|
||||
|
||||
private val settingsButton = SettingsButton(SettingsAction())
|
||||
|
||||
internal class SettingsAction: DumbAwareAction(IdeBundle.message("action.open.editor.settings.text"), "", AllIcons.General.Settings) {
|
||||
override fun actionPerformed(e: AnActionEvent) {
|
||||
val prj = e.project ?: return
|
||||
val searchName = MarkdownBundle.message("markdown.settings.preview.font.size")
|
||||
ShowSettingsUtilImpl.showSettingsDialog(prj, "Settings.Markdown", searchName)
|
||||
}
|
||||
}
|
||||
|
||||
internal class SettingsButton(settingsAction: SettingsAction) : ActionButton(settingsAction, settingsAction.templatePresentation.clone(), ActionPlaces.POPUP, JBUI.size(22, 22)) {
|
||||
override fun performAction(e: MouseEvent?) {
|
||||
val event = AnActionEvent.createFromInputEvent(e, myPlace, myPresentation, dataContext, false, true)
|
||||
ActionUtil.performDumbAwareWithCallbacks(myAction, event) { actionPerformed(event) }
|
||||
}
|
||||
override fun isShowing() = true
|
||||
}
|
||||
|
||||
private inner class PatchedActionLink(action: AnAction, event: AnActionEvent) : AnActionLink(action, ActionPlaces.POPUP) {
|
||||
init {
|
||||
text = event.presentation.text
|
||||
autoHideOnDisable = false
|
||||
isEnabled = event.presentation.isEnabled
|
||||
event.presentation.addPropertyChangeListener {
|
||||
if (it.propertyName == Presentation.PROP_ENABLED) {
|
||||
isEnabled = it.newValue as Boolean
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun uiDataSnapshot(sink: DataSink) {
|
||||
super.uiDataSnapshot(sink)
|
||||
sink[PREVIEW_JCEF_PANEL] = WeakReference(preview)
|
||||
}
|
||||
override fun isShowing() = true
|
||||
}
|
||||
|
||||
private val resetLink = ActionManager.getInstance().getAction("Markdown.Preview.ResetFontSize").run {
|
||||
val dataContext = SimpleDataContext.builder().add(PREVIEW_JCEF_PANEL, WeakReference(preview)).build()
|
||||
val event = AnActionEvent.createFromInputEvent(null, ActionPlaces.POPUP,
|
||||
null, dataContext,
|
||||
false, true)
|
||||
update(event)
|
||||
fontSizeLabel.addPropertyChangeListener {
|
||||
if (it.propertyName == "text") {
|
||||
update(event)
|
||||
}
|
||||
}
|
||||
|
||||
PatchedActionLink(this, event)
|
||||
}
|
||||
|
||||
init {
|
||||
check(isHoveredFlow.tryEmit(false))
|
||||
|
||||
val mouseListener = object : MouseAdapter() {
|
||||
override fun mouseEntered(e: MouseEvent?) { check(isHoveredFlow.tryEmit(true)) }
|
||||
override fun mouseExited(e: MouseEvent?) { check(isHoveredFlow.tryEmit(false)) }
|
||||
}
|
||||
addMouseListener(mouseListener)
|
||||
resetLink.addMouseListener(mouseListener)
|
||||
settingsButton.addMouseListener(mouseListener)
|
||||
|
||||
updateFontSize()
|
||||
|
||||
add(fontSizeLabel, "wmin 100, gapbottom 1, gapleft 3")
|
||||
add(resetLink, "gapbottom 1")
|
||||
add(settingsButton)
|
||||
}
|
||||
|
||||
fun updateFontSize() {
|
||||
fontSizeLabel.text = IdeBundle.message("action.reset.font.size.info", preview.getTemporaryFontSize())
|
||||
}
|
||||
|
||||
fun isHovered(): Flow<Boolean> {
|
||||
return isHoveredFlow
|
||||
}
|
||||
}
|
||||
@@ -35614,6 +35614,12 @@
|
||||
<option name="markdown" hit="Markdown" />
|
||||
<option name="uri" hit="URI:" />
|
||||
</configurable>
|
||||
<configurable id="Settings.Markdown" configurable_name="Markdown">
|
||||
<option name="" hit="" />
|
||||
<option name="preview" hit="Preview font size:" />
|
||||
<option name="font" hit="Preview font size:" />
|
||||
<option name="size" hit="Preview font size:" />
|
||||
</configurable>
|
||||
<configurable id="settings.nodejs" configurable_name="Node.js and NPM">
|
||||
<option name="" hit="" />
|
||||
<option name="assistance" hit="Coding Assistance" />
|
||||
|
||||
Reference in New Issue
Block a user