Skip to content

Commit

Permalink
#459: Make the 'expanded folds hide' option run on a timer rather tha…
Browse files Browse the repository at this point in the history
…n be immediate
  • Loading branch information
bobbylight committed Sep 25, 2022
1 parent 05bed39 commit 0547761
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 16 deletions.
101 changes: 91 additions & 10 deletions RSyntaxTextArea/src/main/java/org/fife/ui/rtextarea/FoldIndicator.java
Expand Up @@ -10,6 +10,8 @@
package org.fife.ui.rtextarea;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
Expand Down Expand Up @@ -121,11 +123,30 @@ public class FoldIndicator extends AbstractGutterComponent {
*/
public static final Color DEFAULT_FOLD_BACKGROUND = Color.WHITE;

/**
* The alpha used for "collapsed" fold icons.
*/
private float collapsedFoldIconAlpha;

/**
* Used to update the collapsed fold icons' alpha value on a timer.
*/
private AlphaRunnable alphaRunnable;

/**
* The timer used to update collapsed fold icons' alpha.
*/
private Timer timer;

/**
* Listens for events in this component.
*/
private Listener listener;

private static final int COLLAPSED_FOLD_ALPHA_DELAY_MILLIS = 16;

private static final float ALPHA_DELTA = 0.1f;


public FoldIndicator(RTextArea textArea) {
super(textArea);
Expand Down Expand Up @@ -236,7 +257,7 @@ public Color getFoldIconBackground() {
* @return Whether to paint expanded folds.
*/
private boolean getPaintExpandedFolds() {
return expandedFoldRenderStrategy == ExpandedFoldRenderStrategy.ALWAYS || getGutter().isArmed();
return expandedFoldRenderStrategy == ExpandedFoldRenderStrategy.ALWAYS || collapsedFoldIconAlpha > 0;
}


Expand Down Expand Up @@ -357,6 +378,19 @@ public String getToolTipText(MouseEvent e) {
}


void gutterArmedUpdate(boolean armed) {
if (expandedFoldRenderStrategy == ExpandedFoldRenderStrategy.ON_HOVER) {
alphaRunnable.delta = armed ? ALPHA_DELTA : -ALPHA_DELTA;
timer.restart();
}
else {
collapsedFoldIconAlpha = 1;
timer.stop();
repaint();
}
}


@Override
void handleDocumentEvent(DocumentEvent e) {
int newLineCount = textArea.getLineCount();
Expand All @@ -372,11 +406,13 @@ protected void init() {
super.init();
setForeground(DEFAULT_FOREGROUND);
setFoldIconBackground(DEFAULT_FOLD_BACKGROUND);
setStyle(FoldIndicatorStyle.CLASSIC);
setStyle(FoldIndicatorStyle.MODERN);
listener = new Listener(this);
visibleRect = new Rectangle();
setShowCollapsedRegionToolTips(true);
setExpandedFoldRenderStrategy(ExpandedFoldRenderStrategy.ALWAYS);
alphaRunnable = new AlphaRunnable();
timer = new Timer(COLLAPSED_FOLD_ALPHA_DELAY_MILLIS, alphaRunnable);
timer.setRepeats(true);
}


Expand Down Expand Up @@ -476,7 +512,7 @@ protected void paintComponent(Graphics g) {
}
if (fold.isCollapsed()) {
int x = (width - collapsedFoldIcon.getIconWidth()) / 2;
paintIcon(collapsedFoldIcon, g, x, y);
paintIcon(collapsedFoldIcon, g, x, y, true);
// Skip to next line to paint, taking extra care for lines with
// block ends and begins together, e.g. "} else {"
do {
Expand All @@ -493,7 +529,7 @@ protected void paintComponent(Graphics g) {
}
else if (getPaintExpandedFolds()) {
int x = (width - expandedFoldIcon.getIconWidth()) / 2;
paintIcon(expandedFoldIcon, g, x, y);
paintIcon(expandedFoldIcon, g, x, y, false);
}
paintFoldArmed = false;
}
Expand Down Expand Up @@ -606,15 +642,15 @@ private void paintComponentWrapped(Graphics g) {
}
if (fold.isCollapsed()) {
int x = (width - collapsedFoldIcon.getIconWidth()) / 2;
paintIcon(collapsedFoldIcon, g, x, y);
paintIcon(collapsedFoldIcon, g, x, y, true);
y += LineNumberList.getChildViewBounds(v, line,
visibleEditorRect).height;
line += fold.getLineCount() + 1;
}
else {
if (getPaintExpandedFolds()) {
int x = (width - expandedFoldIcon.getIconWidth()) / 2;
paintIcon(expandedFoldIcon, g, x, y);
paintIcon(expandedFoldIcon, g, x, y, false);
}
y += curLineH;
line++;
Expand All @@ -630,9 +666,26 @@ private void paintComponentWrapped(Graphics g) {
}


private void paintIcon(FoldIndicatorIcon icon, Graphics g, int x, int y) {
icon.setArmed(paintFoldArmed);
icon.paintIcon(this, g, x, y);
private void paintIcon(FoldIndicatorIcon icon, Graphics g, int x, int y, boolean collapsed) {

Graphics2D g2d = (Graphics2D)g;
Composite orig = g2d.getComposite();

if (!collapsed) {
if (collapsedFoldIconAlpha == 0) {
return;
}
AlphaComposite ac = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, collapsedFoldIconAlpha);
g2d.setComposite(ac);
}
try {
icon.setArmed(paintFoldArmed);
icon.paintIcon(this, g, x, y);
} finally {
if (!collapsed) {
g2d.setComposite(orig);
}
}
}


Expand Down Expand Up @@ -674,6 +727,15 @@ public void setAdditionalLeftMargin(int leftMargin) {
}


private void setCollapsedFoldIconAlpha(float collapsedFoldIconAlpha) {
collapsedFoldIconAlpha = Math.max(0, Math.min(collapsedFoldIconAlpha, 1));
if (collapsedFoldIconAlpha != this.collapsedFoldIconAlpha) {
this.collapsedFoldIconAlpha = collapsedFoldIconAlpha;
repaint();
}
}


/**
* Sets the strategy to use for rendering expanded folds.
*
Expand All @@ -685,6 +747,7 @@ public void setExpandedFoldRenderStrategy(ExpandedFoldRenderStrategy strategy) {
throw new NullPointerException("strategy cannot be null");
}
expandedFoldRenderStrategy = strategy;
collapsedFoldIconAlpha = strategy == ExpandedFoldRenderStrategy.ALWAYS ? 1 : 0;
}


Expand Down Expand Up @@ -814,6 +877,24 @@ public void setTextArea(RTextArea textArea) {
}


/**
* Updates the alpha used for this component's "collapsed" fold icons, if
* necessary.
*/
private class AlphaRunnable implements ActionListener {

private float delta;

@Override
public void actionPerformed(ActionEvent e) {
setCollapsedFoldIconAlpha(collapsedFoldIconAlpha + delta);
if (collapsedFoldIconAlpha == 0 || collapsedFoldIconAlpha == 1) {
timer.stop();
}
}
}


/**
* Listens for events in this component.
*/
Expand Down
Expand Up @@ -600,7 +600,7 @@ void setArmed(boolean armed) {
if (armed != this.armed) {
this.armed = armed;
if (foldIndicator != null) {
foldIndicator.repaint();
foldIndicator.gutterArmedUpdate(armed);
}
}
}
Expand Down
Expand Up @@ -95,9 +95,9 @@ void testGetSetAdditionalLeftMargin_error_negativeValue() {
void testGetSetExpandedFoldRenderStrategy() {
RSyntaxTextArea textArea = createTextArea();
FoldIndicator fi = new FoldIndicator(textArea);
Assertions.assertEquals(ExpandedFoldRenderStrategy.ALWAYS, fi.getExpandedFoldRenderStrategy());
fi.setExpandedFoldRenderStrategy(ExpandedFoldRenderStrategy.ON_HOVER);
Assertions.assertEquals(ExpandedFoldRenderStrategy.ON_HOVER, fi.getExpandedFoldRenderStrategy());
fi.setExpandedFoldRenderStrategy(ExpandedFoldRenderStrategy.ALWAYS);
Assertions.assertEquals(ExpandedFoldRenderStrategy.ALWAYS, fi.getExpandedFoldRenderStrategy());
}


Expand Down
Expand Up @@ -287,9 +287,9 @@ void testGetSetCurrentLineNumberColor() {
void testGetSetExpandedFoldRenderStrategy() {
RTextArea textArea = new RTextArea(PLAIN_TEXT);
Gutter gutter = new Gutter(textArea);
Assertions.assertEquals(ExpandedFoldRenderStrategy.ALWAYS, gutter.getExpandedFoldRenderStrategy());
gutter.setExpandedFoldRenderStrategy(ExpandedFoldRenderStrategy.ON_HOVER);
Assertions.assertEquals(ExpandedFoldRenderStrategy.ON_HOVER, gutter.getExpandedFoldRenderStrategy());
gutter.setExpandedFoldRenderStrategy(ExpandedFoldRenderStrategy.ALWAYS);
Assertions.assertEquals(ExpandedFoldRenderStrategy.ALWAYS, gutter.getExpandedFoldRenderStrategy());
}


Expand Down
Expand Up @@ -131,8 +131,8 @@ private JMenuBar createMenuBar() {
JMenu foldStyleSubMenu = new JMenu("Fold Region Style");
JRadioButtonMenuItem classicStyleItem = new JRadioButtonMenuItem(
new FoldStyleAction(FoldIndicatorStyle.CLASSIC));
classicStyleItem.setSelected(true);
JRadioButtonMenuItem modernStyleItem = new JRadioButtonMenuItem(new FoldStyleAction(FoldIndicatorStyle.MODERN));
modernStyleItem.setSelected(true);
bg = new ButtonGroup();
bg.add(classicStyleItem);
bg.add(modernStyleItem);
Expand Down

0 comments on commit 0547761

Please sign in to comment.