11package org .overengineer .inlineproblems ;
22
3+ import com .intellij .codeInsight .hints .presentation .InputHandler ;
4+ import com .intellij .codeInsight .intention .impl .ShowIntentionActionsHandler ;
35import com .intellij .ide .ui .AntialiasingType ;
46import com .intellij .ide .ui .UISettings ;
7+ import com .intellij .openapi .actionSystem .AnAction ;
8+ import com .intellij .openapi .actionSystem .IdeActions ;
9+ import com .intellij .openapi .actionSystem .ex .ActionUtil ;
510import com .intellij .openapi .editor .Editor ;
611import com .intellij .openapi .editor .EditorCustomElementRenderer ;
712import com .intellij .openapi .editor .Inlay ;
13+ import com .intellij .openapi .editor .ScrollType ;
814import com .intellij .openapi .editor .impl .FontInfo ;
915import com .intellij .openapi .editor .markup .GutterIconRenderer ;
1016import com .intellij .openapi .editor .markup .TextAttributes ;
17+ import com .intellij .openapi .project .Project ;
18+ import com .intellij .psi .PsiFile ;
19+ import com .intellij .psi .util .PsiUtilBase ;
20+ import com .intellij .ui .paint .EffectPainter ;
1121import lombok .Getter ;
1222import lombok .Setter ;
23+ import org .jdesktop .swingx .action .ActionManager ;
1324import org .jetbrains .annotations .NotNull ;
1425import org .jetbrains .annotations .Nullable ;
1526import org .overengineer .inlineproblems .entities .InlineProblem ;
1627import org .overengineer .inlineproblems .settings .SettingsState ;
1728import org .overengineer .inlineproblems .utils .FontUtil ;
1829
1930import java .awt .*;
31+ import java .awt .event .MouseEvent ;
2032import java .awt .font .FontRenderContext ;
2133
2234
2335@ Getter
24- public class InlineProblemLabel implements EditorCustomElementRenderer {
25-
36+ public class InlineProblemLabel implements EditorCustomElementRenderer , InputHandler {
2637 private final String text ;
2738 private final Color textColor ;
2839 private final Color backgroundColor ;
40+ private final Color hoverColor ;
2941 private final boolean isDrawBox ;
3042 private final boolean isRoundedCorners ;
3143 private final boolean isFillBackground ;
44+ private boolean hovered ;
45+ private final boolean clickableContext ;
46+ private Inlay <?> inlay ;
47+ private final int actualStartOffset ;
3248
3349 @ Setter
3450 private boolean isBlockElement ;
@@ -47,10 +63,12 @@ public InlineProblemLabel(
4763 final InlineProblem problem ,
4864 final Color textColor ,
4965 final Color backgroundColor ,
66+ final Color hoverColor ,
5067 final SettingsState settings
5168 ) {
5269 this .textColor = textColor ;
5370 this .backgroundColor = backgroundColor ;
71+ this .hoverColor = hoverColor ;
5472 this .isDrawBox = settings .isDrawBoxesAroundErrorLabels ();
5573 this .isRoundedCorners = settings .isRoundedCornerBoxes ();
5674 this .text = problem .getText ();
@@ -59,6 +77,9 @@ public InlineProblemLabel(
5977
6078 this .isUseEditorFont = settings .isUseEditorFont ();
6179 this .inlayFontSizeDelta = settings .getInlayFontSizeDelta ();
80+ this .hovered = false ;
81+ this .actualStartOffset = problem .getActualStartffset ();
82+ this .clickableContext = settings .isClickableContext ();
6283 }
6384
6485 @ Override
@@ -80,7 +101,7 @@ public int calcWidthInPixels(@NotNull Editor editor) {
80101 @ Override
81102 public void paint (@ NotNull Inlay inlay , @ NotNull Graphics graphics , @ NotNull Rectangle targetRegion , @ NotNull TextAttributes textAttributes ) {
82103 Editor editor = inlay .getEditor ();
83-
104+ this . inlay = inlay ;
84105 // These offsets are applied here and not in the calc functions itself because we use it to shrink the drawn stuff a little bit
85106 int width = calcWidthInPixels (inlay ) + DRAW_BOX_WIDTH_OFFSET ;
86107 int height = calcHeightInPixels (inlay ) + DRAW_BOX_HEIGHT_OFFSET ;
@@ -92,7 +113,7 @@ public void paint(@NotNull Inlay inlay, @NotNull Graphics graphics, @NotNull Rec
92113 // Apply delta on the boxes
93114 if (inlayFontSizeDelta != 0 && editorFontSize > inlayFontSizeDelta ) {
94115 height -= inlayFontSizeDelta ;
95- targetRegionY += (int )(inlayFontSizeDelta / 1.5 );
116+ targetRegionY += (int ) (inlayFontSizeDelta / 1.5 );
96117 }
97118
98119 if (isDrawBox ) {
@@ -118,14 +139,13 @@ public void paint(@NotNull Inlay inlay, @NotNull Graphics graphics, @NotNull Rec
118139 5
119140 );
120141 }
121- }
122- else {
123- graphics .drawRect (
124- targetRegion .x ,
125- targetRegionY ,
126- width ,
127- height
128- );
142+ } else {
143+ graphics .drawRect (
144+ targetRegion .x ,
145+ targetRegionY ,
146+ width ,
147+ height
148+ );
129149
130150 if (isFillBackground ) {
131151 graphics .fillRect (
@@ -138,7 +158,7 @@ public void paint(@NotNull Inlay inlay, @NotNull Graphics graphics, @NotNull Rec
138158 }
139159 }
140160
141- graphics .setColor (textColor );
161+ graphics .setColor (hovered ? hoverColor : textColor );
142162
143163 graphics .setFont (FontUtil .getActiveFont (editor ));
144164
@@ -147,10 +167,63 @@ public void paint(@NotNull Inlay inlay, @NotNull Graphics graphics, @NotNull Rec
147167 targetRegion .x + DRAW_STRING_LINE_PLACEMENT_OFFSET_X ,
148168 targetRegion .y + DRAW_STRING_LINE_PLACEMENT_OFFSET_Y + editor .getAscent ()
149169 );
170+ if (hovered )
171+ EffectPainter .LINE_UNDERSCORE .paint (
172+ (Graphics2D ) graphics ,
173+ targetRegion .x - DRAW_BOX_WIDTH_OFFSET ,
174+ targetRegion .y + editor .getAscent () ,
175+ width + (DRAW_BOX_WIDTH_OFFSET * 2 ),
176+ editor .getAscent (),
177+ FontUtil .getActiveFont (editor ));
178+ }
179+
180+ private void setHovered (boolean hovered ) {
181+ if (!this .clickableContext || this .hovered == hovered ) {
182+ return ;
183+ }
184+ this .hovered = hovered ;
185+ if (inlay != null )
186+ inlay .repaint ();
150187 }
151188
152189 @ Override
153190 public @ Nullable GutterIconRenderer calcGutterIconRenderer (@ NotNull Inlay inlay ) {
154191 return EditorCustomElementRenderer .super .calcGutterIconRenderer (inlay );
155192 }
193+
194+ @ Override
195+ public void mouseClicked (@ NotNull MouseEvent mouseEvent , @ NotNull Point point ) {
196+ if (!clickableContext ) {
197+ return ;
198+ }
199+ if (mouseEvent .getButton () == MouseEvent .BUTTON1 ) {
200+ mouseEvent .consume ();
201+
202+ var editor = inlay .getEditor ();
203+ editor .getCaretModel ().moveToOffset (actualStartOffset );
204+ editor .getScrollingModel ().scrollToCaret (ScrollType .CENTER );
205+
206+ var action = ActionManager .getInstance ().getAction (IdeActions .ACTION_SHOW_INTENTION_ACTIONS );
207+ if (action == null ) {
208+ Project project = editor .getProject ();
209+ if (project == null ) return ;
210+ PsiFile psiFileInEditor = PsiUtilBase .getPsiFileInEditor (editor , project );
211+ if (psiFileInEditor == null ) return ;
212+ new ShowIntentionActionsHandler ().invoke (project , editor , psiFileInEditor , false );
213+ } else {
214+ ActionUtil .invokeAction ((AnAction ) action , editor .getComponent (), "EditorInlay" , null , null );
215+ }
216+ }
217+ }
218+
219+ @ Override
220+ public void mouseMoved (@ NotNull MouseEvent mouseEvent , @ NotNull Point point ) {
221+ setHovered (true );
222+ }
223+
224+ @ Override
225+ public void mouseExited () {
226+ setHovered (false );
227+ }
228+
156229}
0 commit comments