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

Wide selection in trees paints over lines #598

Closed
rkeen-siemens opened this issue Oct 4, 2022 · 2 comments
Closed

Wide selection in trees paints over lines #598

rkeen-siemens opened this issue Oct 4, 2022 · 2 comments
Milestone

Comments

@rkeen-siemens
Copy link

When painting tree lines with wide selection enabled, the selection is painted over the lines. The lines should be painted over the selection background like the disclosure control on the "sports" node in the image below.

Missing Tree Lines

This is a screenshot from the FlatLaf Demo app using the following theme customizations:

# This is the only line really required, but the other lines make the issue more obvious

Tree.paintLines = true


@accentBaseColor = #cde6eb

Tree.hash = #000
Component.arrowType = triangle
@aterai
Copy link

aterai commented Oct 22, 2022

The implementation of the SynthTreeUI#paint(SynthContext context, Graphics g) method might be helpful for painting JTree lines after painting the background of the row selection.

WideSelectionLinesTest

// javac -cp flatlaf-2.6.jar WideSelectionLinesTest.java
// java -cp ".;flatlaf-2.6.jar" WideSelectionLinesTest
import com.formdev.flatlaf.*;
import com.formdev.flatlaf.ui.FlatTreeUI;

import java.awt.*;
import java.util.Enumeration;
import javax.swing.*;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;

public final class WideSelectionLinesTest {
  private Component makeUI() {
    UIManager.put("Tree.paintLines", Boolean.TRUE);
    UIManager.put("Tree.repaintWholeRow", Boolean.TRUE);
    UIManager.put("Tree.hash", new Color(0x0));

    JTree tree = new JTree();
    tree.setUI(new FlatTreeUI() {
      @Override
      public void paint(Graphics g, JComponent c) {
        // @see javax/swing/plaf/synth/SynthTreeUI#paint(SynthContext context, Graphics g)
        if (tree != c) {
          throw new InternalError("incorrect component");
        }

        // Should never happen if installed for a UI
        if(treeState == null) {
          return;
        }

        // paintContext = context;
        // updateLeadSelectionRow();
        Rectangle paintBounds = g.getClipBounds();
        Insets insets = tree.getInsets();
        TreePath initialPath = getClosestPathForLocation(tree, 0, paintBounds.y);
        Enumeration<?> paintingEnumerator = treeState.getVisiblePathsFrom(initialPath);
        int row = treeState.getRowForPath(initialPath);
        int endY = paintBounds.y + paintBounds.height;
        TreeModel treeModel = tree.getModel();
        // SynthContext cellContext = getContext(tree, Region.TREE_CELL);

        drawingCache.clear();
        // setHashColor(context.getStyle().getColor(context, ColorType.FOREGROUND));

        if(initialPath != null && paintingEnumerator != null) {
          // First pass, draw the rows

          boolean done = false;
          boolean isExpanded;
          boolean hasBeenExpanded;
          boolean isLeaf;
          // Rectangle rowBounds = new Rectangle(0, 0, tree.getWidth(),0);
          Rectangle bounds;
          TreePath path;
          // TreeCellRenderer renderer = tree.getCellRenderer();
          // DefaultTreeCellRenderer dtcr = null;
          // if (renderer instanceof DefaultTreeCellRenderer) {
          //   dtcr = (DefaultTreeCellRenderer) renderer;
          // }

          // configureRenderer(cellContext);
          while (!done && paintingEnumerator.hasMoreElements()) {
            path = (TreePath) paintingEnumerator.nextElement();
            bounds = getPathBounds(tree, path);
            if (path != null && bounds != null) {
              isLeaf = treeModel.isLeaf(path.getLastPathComponent());
              if (isLeaf) {
                isExpanded = hasBeenExpanded = false;
              } else {
                isExpanded = treeState.getExpandedState(path);
                hasBeenExpanded = tree.hasBeenExpanded(path);
              }
              // rowBounds.y = bounds.y;
              // rowBounds.height = bounds.height;
              // paintRow(renderer, dtcr, context, cellContext, g,
              //          paintBounds, insets, bounds, rowBounds, path,
              //          row, isExpanded, hasBeenExpanded, isLeaf);
              paintRow(
                g, paintBounds, insets, bounds, path, row, isExpanded, hasBeenExpanded, isLeaf);
              if (bounds.y + bounds.height >= endY) {
                done = true;
              }
            } else {
              done = true;
            }
            row++;
          }

          // Draw the connecting lines and controls.
          // Find each parent and have them draw a line to their last child
          // boolean rootVisible = tree.isRootVisible();
          TreePath  parentPath = initialPath;
          parentPath = parentPath.getParentPath();
          while (parentPath != null) {
            paintVerticalPartOfLeg(g, paintBounds, insets, parentPath);
            drawingCache.put(parentPath, Boolean.TRUE);
            parentPath = parentPath.getParentPath();
          }
          done = false;
          paintingEnumerator = treeState.getVisiblePathsFrom(initialPath);
          while (!done && paintingEnumerator.hasMoreElements()) {
            path = (TreePath) paintingEnumerator.nextElement();
            bounds = getPathBounds(tree, path);
            if (path != null && bounds != null) {
              isLeaf = treeModel.isLeaf(path.getLastPathComponent());
              if (isLeaf) {
                isExpanded = hasBeenExpanded = false;
              } else {
                isExpanded = treeState.getExpandedState(path);
                hasBeenExpanded = tree.hasBeenExpanded(path);
              }
              // See if the vertical line to the parent has been drawn.
              parentPath = path.getParentPath();
              if (parentPath != null) {
                if (drawingCache.get(parentPath) == null) {
                  paintVerticalPartOfLeg(g, paintBounds, insets, parentPath);
                  drawingCache.put(parentPath, Boolean.TRUE);
                }
                paintHorizontalPartOfLeg(
                  g, paintBounds, insets, bounds, path, row, isExpanded, hasBeenExpanded, isLeaf);
              } else if (tree.isRootVisible() && row == 0) {
                paintHorizontalPartOfLeg(
                  g, paintBounds, insets, bounds, path, row, isExpanded, hasBeenExpanded, isLeaf);
              }
              if (shouldPaintExpandControl(path, row, isExpanded, hasBeenExpanded, isLeaf)) {
                paintExpandControl(
                  g, paintBounds, insets, bounds, path, row, isExpanded, hasBeenExpanded, isLeaf);
              }
              if (bounds.y + bounds.height >= endY) {
                done = true;
              }
            } else {
              done = true;
            }
            row++;
          }
        }

        paintDropLine(g);

        // Empty out the renderer pane, allowing renderers to be gc'ed.
        rendererPane.removeAll();

        drawingCache.clear();
      }
    });

    JPanel p = new JPanel(new GridLayout(1, 0));
    p.add(new JScrollPane(new JTree()));
    p.add(new JScrollPane(tree));
    return p;
  }

  public static void main(String[] args) {
    EventQueue.invokeLater(() -> {
      FlatLightLaf.setup();
      JFrame frame = new JFrame();
      frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
      frame.getContentPane().add(new WideSelectionLinesTest().makeUI());
      frame.setSize(320, 240);
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
    });
  }
}

DevCharly added a commit that referenced this issue Nov 1, 2022
- Fixed missing tree lines (if enabled) for wide-selected rows. (issue #598)
- Fixed scaling of tree lines and fixed alignment to expand/collapse arrows.
- Removed support for dashed tree lines. `Tree.lineTypeDashed` is now ignored.
@DevCharly
Copy link
Collaborator

Thanks for reporting.

Fixed in main branch.
Also fixed scaling and position of lines if scaled.

Removed support for dashed tree lines because this does not scale well and it looks outdated.
And using a light color for tree lines has nearly the same visual appearance (to the user) as using darker line color and dashed lines.
Tree.lineTypeDashed is now ignored.

@DevCharly DevCharly added this to the 3.0 milestone Nov 1, 2022
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

3 participants