Is it possible to do this in Vision (Java Swing Examples)

I found this on the internet and wondered if it’s possible to do/use this in Vision…?

I’m not very (not at all :woozy_face:) good in java, so maybe the java gurus here,
in the community, can help…

MajorTickOnTrack

Summary
// -*- mode:java; encoding:utf-8 -*-
// vim:set fileencoding=utf-8:
// https://ateraimemo.com/Swing/MajorTickOnTrack.html

package example;

import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.font.TextLayout;
import java.awt.geom.AffineTransform;
import java.util.Objects;
import javax.swing.*;

public final class MainPanel extends JPanel {
  private MainPanel() {
    super(new BorderLayout());
    JSlider slider = new JSlider();
    slider.setSnapToTicks(true);
    slider.setMajorTickSpacing(10);
    slider.addMouseMotionListener(new MouseAdapter() {
      @Override public void mouseDragged(MouseEvent e) {
        super.mouseDragged(e);
        e.getComponent().repaint();
      }
    });

    UIDefaults d = new UIDefaults();
    d.put("Slider.thumbWidth", 24);
    d.put("Slider.thumbHeight", 24);
    Painter<JSlider> thumbPainter = (g, c, w, h) -> {
      g.setPaint(new Color(0x21_98_F6));
      g.fillOval(0, 0, 24, 24);
      NumberIcon icon = new NumberIcon(slider.getValue());
      icon.paintIcon(c, g, 2, 2);
    };
    d.put("Slider:SliderThumb[Disabled].backgroundPainter", thumbPainter);
    d.put("Slider:SliderThumb[Enabled].backgroundPainter", thumbPainter);
    d.put("Slider:SliderThumb[Focused+MouseOver].backgroundPainter", thumbPainter);
    d.put("Slider:SliderThumb[Focused+Pressed].backgroundPainter", thumbPainter);
    d.put("Slider:SliderThumb[Focused].backgroundPainter", thumbPainter);
    d.put("Slider:SliderThumb[MouseOver].backgroundPainter", thumbPainter);
    d.put("Slider:SliderThumb[Pressed].backgroundPainter", thumbPainter);

    d.put("Slider:SliderTrack[Enabled].backgroundPainter", new Painter<JSlider>() {
      @Override public void paint(Graphics2D g, JSlider c, int w, int h) {
        int arc = 10;
        int thumbSize = 24;
        int trackHeight = 8;
        int tickSize = 4;
        int trackWidth = w - thumbSize;
        int fillTop = (thumbSize - trackHeight) / 2;
        int fillLeft = thumbSize / 2;

        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g.setColor(new Color(0xC6_E4_FC));
        g.fillRoundRect(fillLeft, fillTop + 2, trackWidth, trackHeight - 4, arc, arc);

        int fillBottom = fillTop + trackHeight;
        Rectangle r = new Rectangle(fillLeft, fillTop, trackWidth, fillBottom - fillTop);
        int fillRight = getXPositionForValue(c, r, c.getValue());
        g.setColor(new Color(0x21_98_F6));
        g.fillRoundRect(fillLeft, fillTop, fillRight - fillLeft, fillBottom - fillTop, arc, arc);

        // Paints the major tick on the track
        int value = c.getMinimum();
        while (value <= c.getMaximum()) {
          int xpt = getXPositionForValue(c, r, value);
          g.fillOval(xpt, (int) r.getCenterY() - tickSize / 2, tickSize, tickSize);
          // Overflow checking
          if (Integer.MAX_VALUE - c.getMajorTickSpacing() < value) {
            break;
          }
          value += c.getMajorTickSpacing();
        }
      }

      // @see javax/swing/plaf/basic/BasicSliderUI#xPositionForValue(int value)
      private int getXPositionForValue(JSlider slider, Rectangle trackRect, float value) {
        float min = slider.getMinimum();
        float max = slider.getMaximum();
        float pixelsPerValue = trackRect.width / (max - min);
        int trackLeft = trackRect.x;
        int trackRight = trackRect.x + trackRect.width - 1;
        int pos = trackLeft + Math.round(pixelsPerValue * (value - min));
        return Math.max(trackLeft, Math.min(trackRight, pos));
      }
    });
    slider.putClientProperty("Nimbus.Overrides", d);

    Box box = Box.createVerticalBox();
    box.add(Box.createVerticalStrut(5));
    box.add(makeTitledPanel("Default", new JSlider()));
    box.add(Box.createVerticalStrut(5));
    box.add(makeTitledPanel("Nimbus JSlider.isFilled", slider));
    box.add(Box.createVerticalGlue());
    add(box);
    setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
    setPreferredSize(new Dimension(320, 240));
  }

  private static Component makeTitledPanel(String title, Component c) {
    JPanel p = new JPanel(new BorderLayout());
    p.setBorder(BorderFactory.createTitledBorder(title));
    p.add(c);
    return p;
  }

  public static void main(String[] args) {
    EventQueue.invokeLater(MainPanel::createAndShowGui);
  }

  private static void createAndShowGui() {
    try {
      UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
      // UIManager.put("JSlider.isFilled", Boolean.TRUE);
      // UIManager.put("Slider.paintValue", Boolean.TRUE);
    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
      ex.printStackTrace();
      Toolkit.getDefaultToolkit().beep();
    }
    JFrame frame = new JFrame("MajorTickOnTrack");
    frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    frame.getContentPane().add(new MainPanel());
    frame.pack();
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
  }
}

class NumberIcon implements Icon {
  private final int value;

  protected NumberIcon(int value) {
    this.value = value;
  }

  protected Shape getTextShape(Graphics2D g2) {
    // Java 12:
    // NumberFormat fmt = NumberFormat.getCompactNumberInstance(
    //    Locale.US, NumberFormat.Style.SHORT);
    // String txt = fmt.format(value);
    String txt = value > 999 ? "1K" : Objects.toString(value);
    AffineTransform at = txt.length() < 3 ? null : AffineTransform.getScaleInstance(.66, 1d);
    return new TextLayout(txt, g2.getFont(), g2.getFontRenderContext()).getOutline(at);
  }

  @Override public void paintIcon(Component c, Graphics g, int x, int y) {
    Graphics2D g2 = (Graphics2D) g.create();
    g2.translate(x, y);

    Shape shape = getTextShape(g2);
    Rectangle b = shape.getBounds();
    double tx = getIconWidth() / 2d - b.getCenterX();
    double ty = getIconHeight() / 2d - b.getCenterY();
    AffineTransform toCenterAtf = AffineTransform.getTranslateInstance(tx, ty);
    g2.setPaint(Color.WHITE);
    g2.fill(toCenterAtf.createTransformedShape(shape));
    g2.dispose();
  }

  @Override public int getIconWidth() {
    return 20;
  }

  @Override public int getIconHeight() {
    return 20;
  }
}

Java Swing Tips

Maybe. It seems to be dependent on the default Swing UI layer. The techniques might work in Vision, but neither v7.9 nor v8.x use the default Swing UI.

It would likely need to be a new component in a module.