Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question: How to show vertical lines in CodeArea for indentations? #1214

Open
PavelTurk opened this issue Nov 13, 2023 · 18 comments
Open

Question: How to show vertical lines in CodeArea for indentations? #1214

PavelTurk opened this issue Nov 13, 2023 · 18 comments

Comments

@PavelTurk
Copy link
Contributor

Many editors shows grey vertical lines for indentations. For example like this:
Screenshot from 2023-11-14 00-01-00
Could anyone say how to do it fox XML with CodeArea?

@PavelTurk
Copy link
Contributor Author

Can anyone help me? Or this is very difficult or RichTextFX doesn't support such things?

@Jugen
Copy link
Collaborator

Jugen commented Nov 20, 2023

Sorry, can't help with this one - it seems quite difficult.

@PavelTurk
Copy link
Contributor Author

@Jugen That's very sad. But thank you for your answer.

@PavelTurk
Copy link
Contributor Author

@Jugen Maybe then it is necessary to make this issue as a feature request? How do you think?

@PavelTurk
Copy link
Contributor Author

@Jugen Any ideas? Or there is no chance that it will be implemented?

@Jugen
Copy link
Collaborator

Jugen commented Nov 30, 2023

Sorry to say @PavelTurk but I don't think it will be implemented as there are hardly any PR by the community lately.

@PavelTurk
Copy link
Contributor Author

@Jugen Could you say if it is possible to make vertical lines that will be ignored by selection, cursor etc. By other words these lines must be only visible, but not be the part of the text. I need to do something like table columns but in RichTextFX.

I wouldn’t like to use StackPane with RichTextFX and SomeLinePane because it would complicate things

@Jugen
Copy link
Collaborator

Jugen commented Sep 30, 2024

I think the only way to do that would be make the vertical lines part of the styling. Can Text nodes be styled with either a left or right side border?

@PavelTurk
Copy link
Contributor Author

@Jugen Thank you for your reply.

I will try to make it with border. But the problem is that these lines must be visible even if there is no text at all. Maybe it is necessary to add to RichTexfFX something like grid? Because we have lines (horizontal lines) and characters (vertical line). Of course with possibility to control every side of every cell. However, grid won't be linked to text - it will be displayed even if there is no text at all.

What do you think?

@PavelTurk
Copy link
Contributor Author

PavelTurk commented Oct 3, 2024

@Jugen Any ideas? Or you think it is a bad idea?

@Jugen
Copy link
Collaborator

Jugen commented Oct 4, 2024

I think doing tables will be hard. In a way each cell is it's own little editor who's dimensions are linked to its neighbors. So maybe the way to go is to embed a GridPane with each cell being a RichTextFX editor ? Not sure if this will scale well for very large tables but for small ones it could maybe work ?

@PavelTurk
Copy link
Contributor Author

@Jugen I suggested grid because anyway it is necessary to add a general solution for vertical (and maybe horizontal) lines. For example, even if we consider a simple editor we can need vertical lines for indentation or one line to show the end of the line (for example at position 80).

So, I think RichTextFX must support such things. For example, we can start with assumption that monospace font is used and font size is the same for all text. The reason of this assumption is that otherwise it is impossible to make any vertical (horizontal) grid.

So, with such assumption we will add one more layer above text. I mean all existing text layer remains at it is. We are only adding a new layer with lines exactly along the edges of the cells. For example, right margin in NetBeans:

Screenshot from 2024-10-04 10-01-48

Yes, suggested solution has its limitation, but it is easy to implement and gives many opportunities.

What do you think?

@Jugen
Copy link
Collaborator

Jugen commented Oct 7, 2024

Yes, I think that could work. Do you have suggested API ?

@PavelTurk
Copy link
Contributor Author

I would suggest the following:

  1. it is necessary to add BooleanProperty gridEnabledProperty. If true then
  2. ObjecProperty<GridCellFactory> gridCellFactoryProperty is used. Maybe something like this
public interface GridCellFactory {
   /**    -fx-border-width: 1px 1px 2px 2px; 
          -fx-border-style: solid dashed none dotted;
          -fx-border-color: red blue green yellow;
          -fx-view-order: 1 -1 1 -1  /* 1 is above text, -1 is under text */
   */ 
    String bodersStyle(in paragraphIndex, int columnPosition);
}

We have a virtual flow, that's why grid will be build only for visible cells. Besides, GridCell border styles will be created dynamically - so we could control every paragraph and column.

@Jugen
Copy link
Collaborator

Jugen commented Oct 9, 2024

Mmm, maybe that can work - not sure how it would be implemented though ?

An idea from my side is to sort of copy how selection works. So we have addVerticalLine( Range, col, styleClass ) and addVerticalLine( startParagraph, endParagraph, col, styleClass ) .

Actually I'm wondering if a transparent selection with only one or more visible edges couldn't work as is now ?

@PavelTurk
Copy link
Contributor Author

@Jugen Unfortunately, I can't give any advice here because I don't know how RichTextFX works internally. It's still a black box for me.

@Jugen
Copy link
Collaborator

Jugen commented Oct 10, 2024

Here's a VerticalLine solution that I hope will work for you. (Its one drawback is that it doesn't show where there are no lines.)

    VerticalLine.builder( area, 25 )
//      .lineColor( Color.RED )
//      .startParagraph( 4 )
//      .endParagraph( 16 )
//      .lineWidth( 2 )
        .create();
import org.fxmisc.richtext.GenericStyledArea;
import org.fxmisc.richtext.SelectionImpl;

import javafx.collections.ListChangeListener.Change;
import javafx.scene.paint.Color;
import javafx.scene.shape.LineTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.PathElement;
import javafx.scene.shape.VLineTo;
import javafx.scene.text.Font;
import javafx.scene.text.Text;

public class VerticalLine<PS,SEG,S> extends SelectionImpl<PS,SEG,S>
{
    private VerticalLine( GenericStyledArea<PS,SEG,S> area, String lineStyle, double x )
    {
        super( "vertical-line", area, path ->
        {
            path.setStyle( lineStyle );

            path.getElements().addListener( (Change<? extends PathElement> chg) ->
            {
                if ( chg.next() && (chg.wasAdded() || chg.wasReplaced()) && path.getParent() != null )
                {
                    if ( path.getElements().size() > 2 )
                    {
                        var yStats = path.getElements().stream()
                            .filter( ele -> ele instanceof LineTo )
                            .mapToDouble( ele -> ((LineTo) ele).getY() )
                            .summaryStatistics();

                        var moveTo = new MoveTo( x, yStats.getMin()  );
                        var lineTo = new VLineTo( yStats.getMax() );
                        path.getElements().setAll( moveTo, lineTo );
                    }
                }
            } );
        } );
    }


    public static <PS,SEG,S> Builder<PS,SEG,S> builder( GenericStyledArea<PS,SEG,S> area, int column )
    {
        return new Builder<>( area, column );
    }

    public static class Builder<PS,SEG,S>
    {
        private GenericStyledArea<PS,SEG,S> area;
        private int startParagraph, endParagraph, column;
        private String lineWidth = "-fx-stroke-width: 1;";
        private String lineColor = "-fx-stroke: pink;";
        private double fontWidth;

        private Builder( GenericStyledArea<PS,SEG,S> area, int column )
        {
            this.column = column;
            this.area = area;
        }

        public Builder<PS,SEG,S> startParagraph( int start )
        {
            startParagraph = start;
            return this;
        }

        public Builder<PS,SEG,S> endParagraph( int end )
        {
            endParagraph = end;
            return this;
        }

        public Builder<PS,SEG,S> lineColor( Color c )
        {
            lineColor = "-fx-stroke: #"+ c.toString().replace( "0x", "" ) +";";
            return this;
        }

        public Builder<PS,SEG,S> lineWidth( int width )
        {
            lineWidth = "-fx-stroke-width: "+ width +";";
            return this;
        }

        public Builder<PS,SEG,S> font( Font font )
        {
            fontWidth = fontWidth( font );
            return this;
        }

        /** The fixed width font that the text area is using. The default is Monospace. */
        private double fontWidth( Font font )
        {
            var text = new Text( "F" );  text.setFont(font);
            return text.getLayoutBounds().getWidth();
        }

        public VerticalLine<PS,SEG,S> create()
        {
            String lineStyle = lineColor + lineWidth;
            if ( fontWidth == 0 ) fontWidth = fontWidth( Font.font( "Monospace" ) );

            var vl = new VerticalLine<>( area, lineStyle, column * fontWidth );

            if ( endParagraph == 0 ) endParagraph = area.getParagraphs().size();
            vl.selectRange( startParagraph, 0, endParagraph, 0 );

            area.addSelection( vl );

            return vl;
        }
    }
}

@PavelTurk
Copy link
Contributor Author

@Jugen Thank you very much for the proposed solution. Please, give me several days to test it. I am now struggling with virtual flow :) and after that I will be back to a text editor.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants