Refactor JBValue

This commit is contained in:
Anton Tarasov
2018-04-16 15:11:46 +03:00
parent bd74388650
commit 27d2ec6ff2
3 changed files with 73 additions and 186 deletions
@@ -2,6 +2,8 @@
package com.intellij.util.ui;
import com.intellij.ui.RestoreScaleRule;
import com.intellij.ui.paint.PaintUtil.RoundingMode;
import com.intellij.util.ui.JBValue.JBValueGroup;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.rules.ExternalResource;
@@ -20,41 +22,30 @@ public class JBValueTest {
public static final ExternalResource manageState = new RestoreScaleRule();
@Test
public void testInt() {
public void testSeparateValue() {
JBUI.setUserScaleFactor(1);
JBValue value1 = JBUI.intValue(2);
JBValue.SelfCachedInteger value2 = new JBValue.SelfCachedInteger(2);
JBValue value1 = JBUI.value(2);
JBValue value2 = JBUI.value(2.6f);
JBValue value3 = JBUI.value(2.9f);
JBUI.setUserScaleFactor(2);
assertEquals(JBUI.scale(2), value1.get());
assertEquals(JBUI.scale(2), value2.get());
}
@Test
public void testFloat() {
JBUI.setUserScaleFactor(1);
JBValue.Float value1 = JBUI.floatValue(2.6f);
JBValue.SelfCachedFloat value2 = new JBValue.SelfCachedFloat(2.6f);
JBUI.setUserScaleFactor(2);
assertEquals(Math.round(JBUI.scale(2.6f)), value1.get());
assertEquals(Math.round(JBUI.scale(2.6f)), value2.get());
assertEquals(JBUI.scale(2.6f), value1.getFloat());
assertEquals(JBUI.scale(2.6f), value2.getFloat());
assertEquals((int)Math.ceil(JBUI.scale(2.6f)), value2.get(RoundingMode.CEIL));
assertEquals((int)Math.floor(JBUI.scale(2.6f)), value3.get(RoundingMode.FLOOR));
}
@Test
public void testUpdateTracker() {
public void testGroup() {
JBUI.setUserScaleFactor(1);
JBValue.UpdateTracker tracker = new JBValue.UpdateTracker();
JBValue value1 = JBUI.intValue(1, tracker);
JBValue value2 = JBUI.intValue(2, tracker);
JBValue.Float value3 = JBUI.floatValue(3.6f, tracker);
JBValueGroup values = new JBValueGroup();
JBValue value1 = values.add(1);
JBValue value2 = values.add(2);
JBValue value3 = values.add(3.6f);
JBUI.setUserScaleFactor(2);
@@ -63,38 +54,35 @@ public class JBValueTest {
assertEquals(Math.round(JBUI.scale(3.6f)), value3.get());
assertEquals(JBUI.scale(3.6f), value3.getFloat());
tracker.forget((JBValue.Cacheable)value3);
values.dispose();
int scale = JBUI.scale(1);
JBUI.setUserScaleFactor(3);
assertEquals(Math.round(scale * 3.6f), value3.get());
assertEquals(scale * 3.6f, value3.getFloat());
tracker.dispose();
scale = JBUI.scale(1);
JBUI.setUserScaleFactor(1);
assertEquals(scale, value1.get());
assertEquals(scale * 2, value2.get());
assertEquals(Math.round(scale * 3.6f), value3.get());
assertEquals(scale * 3.6f, value3.getFloat());
}
@Test
public void testUIDefaultsInteger() {
public void testUIInteger() {
JBUI.setUserScaleFactor(1);
String key = "JBValue.int";
String absentKey = "JBValue.absent";
UIManager.put(key, 2);
JBValue.UIDefaultsInteger value = new JBValue.UIDefaultsInteger(key);
JBValue value1 = JBUI.uiIntValue(key, 1);
JBValue value2 = JBUI.uiIntValue(absentKey, 1);
JBUI.setUserScaleFactor(2);
assertEquals(JBUI.scale(2), value.get());
assertEquals(JBUI.scale(2), value1.get());
assertEquals(JBUI.scale(1), value2.get());
UIManager.put(key, 3);
assertEquals(JBUI.scale(3), value.get());
assertEquals(JBUI.scale(3), value1.get());
UIManager.put(key, null);
}
@@ -483,20 +483,13 @@ public class JBUI {
}
@NotNull
public static JBValue.Integer intValue(int value) {
return new JBValue.Integer(value);
}
public static JBValue.Integer intValue(int value, JBValue.UpdateTracker tracker) {
return new JBValue.CachedInteger(value, tracker);
}
public static JBValue.Float floatValue(float value) {
public static JBValue value(float value) {
return new JBValue.Float(value);
}
public static JBValue.Float floatValue(float value, JBValue.UpdateTracker tracker) {
return new JBValue.CachedFloat(value, tracker);
@NotNull
public static JBValue uiIntValue(@NotNull String key, int defValue) {
return new JBValue.UIInteger(key, defValue);
}
public static JBDimension size(int width, int height) {
@@ -16,21 +16,15 @@ import static com.intellij.ui.paint.PaintUtil.RoundingMode.ROUND;
/**
* A wrapper over an unscaled numeric value, auto-scaled via {@link JBUI#scale}.
* <p>
* Use {@link Integer} or {@link Float} classes for on-demand value scaling.
* {@code JBValue} can be used separately or in a group, see {@link JBValueGroup}.
* <p>
* If the same JBValue object is used multiple times in a code block, then in order to save scaling ops,
* a {@link CachedInteger} or {@link CachedFloat} classes can be used instead. Either with a separate
* {@link UpdateTracker} (better to use for many JBValue objects), or with a dedicated one (for a single
* JBValue object) as in the {@link SelfCachedInteger} or {@link SelfCachedFloat} classes.
* <p>
* Also, the {@link UIDefaultsInteger} class can be used for auto-scaling an integer value stored in
* {@link UIDefaults}.
* Also, a {@link UIInteger} value can be used as a wrapper over an integer value stored in {@link UIDefaults}.
*
* @see JBUI#value(float)
* @see JBValueGroup#add(float)
* @see JBUI#uiIntValue(String, int)
*
* @author tav
* @see JBUI#intValue(int)
* @see JBUI#intValue(int,UpdateTracker)
* @see JBUI#floatValue(float)
* @see JBUI#floatValue(float,UpdateTracker)
*/
public abstract class JBValue {
protected JBValue() {}
@@ -39,8 +33,14 @@ public abstract class JBValue {
* Returns scaled rounded to int value.
*/
public int get() {
// for backward compatibility rely on the rounding mode applied in JBUI.scale(int)
return JBUI.scale((int)getUnscaled());
return ROUND.round(JBUI.scale(getUnscaled()));
}
/**
* Returns scaled float value.
*/
public float getFloat() {
return JBUI.scale(getUnscaled());
}
/**
@@ -55,143 +55,53 @@ public abstract class JBValue {
*/
protected abstract float getUnscaled();
public interface Cacheable {
/**
* Scales and caches the value.
*/
void cache();
}
/**
* JBValue wrapper over an integer value in {@link UIDefaults}.
*
* @see JBUI#uiIntValue(String,int)
*/
public static class UIDefaultsInteger extends JBValue {
public static class UIInteger extends JBValue {
private final @NotNull String key;
private final int defValue;
public UIDefaultsInteger(@NotNull String key) {
public UIInteger(@NotNull String key, int defValue) {
this.key = key;
this.defValue = defValue;
}
@Override
protected float getUnscaled() {
return UIManager.getInt(key);
}
}
/**
* JBValue wrapper over an integer.
*/
public static class Integer extends JBValue {
private final int value;
/**
* @param value unscaled value
* @see JBUI#intValue(int)
*/
public Integer(int value) {
this.value = value;
}
@Override
protected float getUnscaled() {
return value;
return JBUI.getInt(key, defValue);
}
}
/**
* JBValue wrapper over a float.
*
* @see JBUI#value(float)
*/
public static class Float extends JBValue {
private final float value;
/**
* @param value unscaled value
* @see JBUI#floatValue(float)
*/
public Float(float value) {
this.value = value;
}
@Override
public int get() {
return ROUND.round(JBUI.scale(value));
}
/**
* Scales the value and returns.
*/
public float getFloat() {
return JBUI.scale(value);
}
@Override
protected float getUnscaled() {
return value;
}
}
/**
* Integer JBValue which caches its scaled value on JBUI.scale change.
*/
public static class CachedInteger extends Integer implements Cacheable {
private int cachedScaledValue;
protected CachedInteger(int value) {
super(value);
}
/**
* @param value unscaled value
* @param tracker updates the value
* @see JBUI#intValue(int, UpdateTracker)
*/
public CachedInteger(int value, @NotNull UpdateTracker tracker) {
super(value);
cachedScaledValue = JBUI.scale(value);
tracker.track(this);
}
@Override
public int get() {
return cachedScaledValue;
}
public void cache() {
cachedScaledValue = JBUI.scale((int)getUnscaled());
}
}
/**
* CachedInteger with a dedicated UpdateTracker.
*/
public static class SelfCachedInteger extends CachedInteger {
private final @NotNull UpdateTracker tracker = new UpdateTracker();
public SelfCachedInteger(int value) {
super(value);
this.tracker.track(this);
}
}
/**
* Float JBValue which caches its scaled value on JBUI.scale change.
*/
public static class CachedFloat extends Float implements Cacheable {
private static class CachedFloat extends Float {
private float cachedScaledValue;
protected CachedFloat(float value) {
super(value);
}
/**
* @param value unscaled value
* @param tracker updates the value
* @see JBUI#floatValue(float, UpdateTracker)
*/
public CachedFloat(float value, UpdateTracker tracker) {
super(value);
cachedScaledValue = JBUI.scale(value);
tracker.track(this);
scaleAndCache();
}
@Override
@@ -204,50 +114,46 @@ public abstract class JBValue {
return cachedScaledValue;
}
public void cache() {
@Override
public int get(@NotNull RoundingMode rm) {
return rm.round(cachedScaledValue);
}
public void scaleAndCache() {
cachedScaledValue = JBUI.scale(getUnscaled());
}
}
/**
* CachedFloat with a dedicated UpdateTracker.
* A group of values, utilizing caching strategy per value. The group listens to the global user scale factor change and updates
* all of the values. The {@link JBValue#get()} method of a value returns a cached scaled value, saving recalculation.
* This can be a better choice when values are used multiple times in a code block.
*/
public static class SelfCachedFloat extends CachedFloat {
private final @NotNull UpdateTracker tracker = new UpdateTracker();
public SelfCachedFloat(float value) {
super(value);
this.tracker.track(this);
}
}
/**
* Tracks for a list of {@link Cacheable} values and auto-updates them on {@link JBUI#USER_SCALE_FACTOR_PROPERTY}} change.
*/
public static class UpdateTracker {
private final List<Cacheable> list = new LinkedList<Cacheable>();
public static class JBValueGroup {
private final List<CachedFloat> group = new LinkedList<CachedFloat>();
private final PropertyChangeListener listener = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
for (Cacheable value : list) value.cache();
for (CachedFloat value : group) value.scaleAndCache();
}
};
public UpdateTracker() {
public JBValueGroup() {
JBUI.addPropertyChangeListener(JBUI.USER_SCALE_FACTOR_PROPERTY, listener);
}
public void track(Cacheable value) {
list.add(value);
}
public void forget(Cacheable value) {
list.remove(value);
/**
* Creates {@link JBValue} and adds it to this group.
*/
public JBValue add(float value) {
CachedFloat v = new CachedFloat(value);
group.add(v);
return v;
}
public void dispose() {
JBUI.removePropertyChangeListener(JBUI.USER_SCALE_FACTOR_PROPERTY, listener);
list.clear();
group.clear();
}
}
}