package com.pump.swing.popup;

import java.awt.Point;
import java.awt.Rectangle;
import java.lang.reflect.Field;
import java.util.Objects;

import javax.swing.JSlider;
import javax.swing.SwingUtilities;
import javax.swing.plaf.basic.BasicSliderUI;

/**
 * This PopupTarget points to the thumb of a JSlider.
 */
public class SliderThumbPopupTarget implements PopupTarget {
	JSlider slider;

	public SliderThumbPopupTarget(JSlider slider) {
		Objects.requireNonNull(slider);
		this.slider = slider;
		getLocalThumbScreenRect();
	}

	/**
	 * Return the bounds of the slider thumb relative to the JSliders coordinate
	 * system.
	 */
	protected Rectangle getLocalThumbScreenRect() {
		BasicSliderUI sliderUI = slider.getUI() instanceof BasicSliderUI ? (BasicSliderUI) slider
				.getUI() : null;
		if (sliderUI == null)
			throw new UnsupportedOperationException("This UI is unsupported "
					+ slider.getUI().getClass().getName());

		try {
			Field f = BasicSliderUI.class.getDeclaredField("thumbRect");
			f.setAccessible(true);
			Rectangle thumbRect = (Rectangle) f.get(sliderUI);
			if (thumbRect == null)
				throw new NullPointerException();
			if (thumbRect.isEmpty())
				throw new IllegalArgumentException();

			thumbRect = new Rectangle(thumbRect);
			return thumbRect;
		} catch (NoSuchFieldException | SecurityException
				| IllegalAccessException e) {
			throw new UnsupportedOperationException(e);
		}

		// this... kinda worked. It derives the thumb location.
		// But it was still a little imprecise, and just
		// grabbing the thumbRect is simplest.

		// int value = slider.getValue();
		// if (slider.getOrientation() == JSlider.HORIZONTAL) {
		// float bestX = slider.getWidth() / 2;
		// int span = 0;
		// int bestDiff = Integer.MAX_VALUE;
		// for (int x = 0; x < slider.getWidth(); x++) {
		// int v = sliderUI.valueForXPosition(x);
		// int diff = (Math.abs(value - v));
		// if (diff < bestDiff) {
		// bestX = x;
		// span = 1;
		// bestDiff = diff;
		// } else if (diff == bestDiff) {
		// bestX = (bestX * span + x) / (++span);
		// }
		// }
		// return new Point((int) Math.round(bestX), slider.getHeight());
		// } else if (slider.getOrientation() == JSlider.VERTICAL) {
		// float bestY = slider.getHeight() / 2;
		// int span = 0;
		// int bestDiff = Integer.MAX_VALUE;
		// for (int y = 0; y < slider.getHeight(); y++) {
		// int v = ui.valueForYPosition(y);
		// int diff = (Math.abs(value - v));
		// if (diff < bestDiff) {
		// bestY = y;
		// span = 1;
		// bestDiff = diff;
		// } else if (diff == bestDiff) {
		// bestY = (bestY * span + y) / (++span);
		// }
		// }
		// return new Point(slider.getWidth(), (int) Math.round(bestY));
		// }
		// throw new RuntimeException("Unexpected orientation: "
		// + slider.getOrientation());

	}

	/**
	 * Return the bounds of the slider thumb relative to the screen.
	 */
	@Override
	public Rectangle getScreenBounds() {
		Rectangle rect = getLocalThumbScreenRect();
		Point p = new Point(0, 0);
		SwingUtilities.convertPointToScreen(p, slider);
		rect.x += p.x;
		rect.y += p.y;
		return rect;
	}
}

@@ -24,16 +24,44 @@
 popup;%0A%0A
+import java.awt.Graphics2D;%0A
 import j
@@ -106,40 +106,8 @@
 le;%0A
-import java.lang.reflect.Field;%0A
 impo
@@ -238,16 +238,62 @@
 derUI;%0A%0A
+import com.pump.graphics.vector.VectorImage;%0A%0A
 /**%0A * T
@@ -341,16 +341,84 @@
 JSlider.
+ Currently this only%0A * supports a slider that uses a BasicSliderUI.
 %0A */%0Apub
@@ -475,16 +475,17 @@
 arget %7B%0A
+%0A
 %09JSlider
@@ -849,17 +849,21 @@
 SliderUI
- 
+%0A%09%09%09%09
 ? (Basic
@@ -882,21 +882,16 @@
 ider
-%0A%09%09%09%09
 .getUI()
  : n
@@ -886,17 +886,21 @@
 .getUI()
- 
+%0A%09%09%09%09
 : null;%0A
@@ -1044,1846 +1044,161 @@
 %0A%0A%09%09
-try %7B%0A%09%09%09Field f = BasicSliderUI.class.getDeclaredField(%22thumbRect%22);%0A%09%09%09f.setAccessible(true);%0A%09%09%09Rectangle thumbRect = (Rectangle) f.get(sliderUI);%0A%09%09%09if (thumbRect == null)%0A%09%09%09%09throw new NullPointerException();%0A%09%09%09if (thumbRect.isEmpty())%0A%09%09%09%09throw new IllegalArgumentException();%0A%0A%09%09%09thumbRect = new Rectangle(thumbRect);%0A%09%09%09return thumbRect;%0A%09%09%7D catch (NoSuchFieldException %7C SecurityException%0A%09%09%09%09%7C IllegalAccessException e) %7B%0A%09%09%09throw new UnsupportedOperationException(e);%0A%09%09%7D%0A%0A%09%09// this... kinda worked. It derives the thumb location.%0A%09%09// But it was still a little imprecise, and just%0A%09%09// grabbing the thumbRect is simplest.%0A%0A%09%09// int value = slider.getValue();%0A%09%09// if (slider.getOrientation() == JSlider.HORIZONTAL) %7B%0A%09%09// float bestX = slider.getWidth() / 2;%0A%09%09// int span = 0;%0A%09%09// int bestDiff = Integer.MAX_VALUE;%0A%09%09// for (int x = 0; x %3C slider.getWidth(); x++) %7B%0A%09%09// int v = sliderUI.valueForXPosition(x);%0A%09%09// int diff = (Math.abs(value - v));%0A%09%09// if (diff %3C bestDiff) %7B%0A%09%09// bestX = x;%0A%09%09// span = 1;%0A%09%09// bestDiff = diff;%0A%09%09// %7D else if (diff == bestDiff) %7B%0A%09%09// bestX = (bestX * span + x) / (++span);%0A%09%09// %7D%0A%09%09// %7D%0A%09%09// return new Point((int) Math.round(bestX), slider.getHeight());%0A%09%09// %7D else if (slider.getOrientation() == JSlider.VERTICAL) %7B%0A%09%09// float bestY = slider.getHeight() / 2;%0A%09%09// int span = 0;%0A%09%09// int bestDiff = Integer.MAX_VALUE;%0A%09%09// for (int y = 0; y %3C slider.getHeight(); y++) %7B%0A%09%09// int v = ui.valueForYPosition(y);%0A%09%09// int diff = (Math.abs(value - v));%0A%09%09// if (diff %3C bestDiff) %7B%0A%09%09// bestY = y;%0A%09%09// span = 1;%0A%09%09// bestDiff = diff;%0A%09%09// %7D else if (diff == bestDiff) %7B%0A%09%09// bestY = (bestY * span + y) / (++span);%0A%09%09// %7D%0A%09%09// %7D%0A%09%09// return new Point(slider.getWidth(), (int) Math.round(bestY));%0A%09%09// %7D%0A%09%09// throw new RuntimeException(%22Unexpected orientation: %22%0A%09%09// + slider.getOrientation()
+VectorImage img = new VectorImage();%0A%09%09Graphics2D g = img.createGraphics();%0A%09%09sliderUI.paintThumb(g);%0A%09%09g.dispose();%0A%0A%09%09return img.getBounds().getBounds(
 );%0A%0A

Refactor SliderThumbPopupTarget to use VectorImage