StylableComponent.java
package swingtree.style;
import javax.swing.JComponent;
import javax.swing.plaf.ComponentUI;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.util.function.Consumer;
/**
* Implementations of this interface are SwingTree native components
* which enjoy the full support of the style API.
* Regular Swing components can be styled on most layers
* but not all. The {@link swingtree.UI.Layer#BACKGROUND} and
* {@link swingtree.UI.Layer#FOREGROUND} layers are not supported
* for some components for which SwingTree tries to install a
* custom UI delegate. <br>
* This however is prone to side effects and can cause issues
* with third party look and feels. <br>
* For full support of the style API for your custom components
* you should implement this interface.
*/
public interface StylableComponent
{
/**
* Certain style configurations require SwingTree to install a
* custom UI delegate. This method is used to set the UI delegate
* for the component but without triggering side effects like
* the former UI being uninstalled (which itself can cause
* a lot of undesired side effects).
* <p>
* <b>This method is not intended to be called by client code!
* It exists for internal use only and unfortunately cannot be
* protected or private due to the nature of the Swing API.</b>
* <p>
* The implementation of this method is expected to look like this:
* <pre>
* {@literal @}Override
* public void setUISilently(ComponentUI ui){
* this.ui = ui; // no side effects
* }
* </pre>
* @param ui the UI delegate to set for the component
* without triggering side effects.
*/
void setUISilently( ComponentUI ui );
/**
* This method is expected to be implemented as follows
* within a component extension which ought to be made compatible
* with SwingTree.
* <pre>
* {@literal @}Override
* public void paint(Graphics g){
* paintBackground(g, ()->super.paint(g));
* }
* </pre>
* @param g the graphics context to paint on,
* obtained from the component's {@link JComponent#paint(Graphics)} method.
*/
void paint( Graphics g );
/**
* This method is expected to be implemented as follows:
* <pre>
* {@literal @}Override
* public void paintChildren(Graphics g){
* paintForeground(g, ()->super.paintChildren(g));
* }
* </pre>
* @param g the graphics context to paint on,
* obtained from the component's {@code JComponent::paintChildren(Graphics)} method.
*/
void paintChildren( Graphics g );
/**
* <b>
* This default method is not intended to be overridden by client code!
* It delegates the painting to the library internal {@link ComponentExtension}.
* </b>
*
* @param g The graphics context to paint on.
* @param superPaint The super.paint() method to call.
*/
/*final*/ default void paintBackground( Graphics g, Consumer<Graphics> superPaint ) {
if ( this instanceof JComponent ) {
ComponentExtension.from((JComponent) this).paintBackgroundIfNeeded( g, superPaint );
}
else
throw new UnsupportedOperationException( "This interface is only intended for JComponent implementations" );
}
/**
* <b>
* This default method is not intended to be overridden by client code!
* It delegates the painting to the library internal {@link ComponentExtension}.
* </b>
*
* @param g The graphics context to paint on.
* @param superPaint The super.paintChildren() method to call.
*/
/*final*/ default void paintForeground( Graphics g, Consumer<Graphics> superPaint ) {
if ( this instanceof JComponent ) {
ComponentExtension.from((JComponent) this).paintForeground( (Graphics2D) g, superPaint );
}
else
throw new UnsupportedOperationException( "This interface is only intended for JComponent implementations" );
}
}