All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.swingdpi.UiScaling Maven / Gradle / Ivy

/*
 * Copyright 2016 the original author or authors.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see .
 *
 * This project is hosted at: https://github.com/lukeu/swing-dpi
 * Comments & collaboration are both welcome.
 */

package com.github.swingdpi;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

import javax.swing.BorderFactory;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

/**
 * Class storing an observable static/global UI scaling factor, and some utility methods to scale
 * various types and metrics by that value.
 */
public class UiScaling {
    private UiScaling() {}

    /**
     * Scaling in integer percentage points; so 100 results in the 'standard' setting of 96 DPI.
     */
    private static final AtomicInteger s_scalingPercentage = 
            new AtomicInteger(DpiUtils.getClosestStandardScaling());

    /**
     * Threading: all access must synchronize on this final member
     */
    private static final List s_changeListeners = new ArrayList();

    /**
     * @return the currently-set scaling as a factor (or is that multiplicand?) Anyway 2.5f == 250%
     */
    public static float getScalingFactor() {
        return getScaling() / 100f;
    }

    /**
     * @return the currently-set scaling in percentage points.
     */
    public static int getScaling() {
        return s_scalingPercentage.get();
    }

    public static void setScaling(int scalingInPercent) {
        assert SwingUtilities.isEventDispatchThread();

        int old = s_scalingPercentage.getAndSet(scalingInPercent);
        if (old != scalingInPercent) {
            notifyListeners();
        }
    }

    /**
     * Public to allow users to notify listeners of similar events (like L&F changes) without
     * needing a second listener & event to register on. (For better or worse.)
     */
    private static void notifyListeners() {
        List listeners;
        synchronized (s_changeListeners) {
            listeners = new ArrayList(s_changeListeners);
        }

        for (ChangeListener changeListener : listeners) {
            changeListener.stateChanged(new ChangeEvent(UiScaling.class));
        }
    }

    /**
     * Be notified when L&F or scaling-level has changed.
     * 

* As always when listening on static objects: take care to avoid memory leaks by removing * listeners again, as these may continue to hold references to otherwise shorter-lived objects. */ public static void addChangeListener(ChangeListener listener) { synchronized (s_changeListeners) { s_changeListeners.add(listener); } } /** * Threading note: it is possible that listeners will still be notified of events for a short * period after this method has exited, unless this method is called from the EDT. */ public static void removeChangeListener(ChangeListener listener) { synchronized (s_changeListeners) { s_changeListeners.remove(listener); } } public static Dimension newDimension(int width, int height) { return scale(new Dimension(width, height)); } public static int scale(int i) { return Math.round((i * getScaling()) / 100f); } public static float scale(float f) { return f * getScalingFactor(); } public static Dimension scale(Dimension dim) { return (getScaling() == 100) ? dim : new Dimension(scale(dim.width), scale(dim.height)); } public static Font scale(Font font) { return font.deriveFont(font.getSize2D() * getScalingFactor()); } public static Border createEmptyBorder(int top, int left, int bottom, int right) { return BorderFactory.createEmptyBorder( scale(top), scale(left), scale(bottom), scale(right)); } public static Border createLineBorder(Color color, int thickness) { return BorderFactory.createLineBorder(color, scale(thickness)); } public static Border createMatteBorder(int top, int left, int bottom, int right, Color color) { return BorderFactory.createMatteBorder( scale(top), scale(left), scale(bottom), scale(right), color); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy