StylableComponent.java

  1. package swingtree.style;

  2. import javax.swing.JComponent;
  3. import javax.swing.plaf.ComponentUI;
  4. import java.awt.Graphics;
  5. import java.awt.Graphics2D;
  6. import java.util.function.Consumer;

  7. /**
  8.  *  Implementations of this interface are SwingTree native components
  9.  *  which enjoy the full support of the style API.
  10.  *  Regular Swing components can be styled on most layers
  11.  *  but not all. The {@link swingtree.UI.Layer#BACKGROUND} and
  12.  *  {@link swingtree.UI.Layer#FOREGROUND} layers are not supported
  13.  *  for some components for which SwingTree tries to install a
  14.  *  custom UI delegate. <br>
  15.  *  This however is prone to side effects and can cause issues
  16.  *  with third party look and feels. <br>
  17.  *  For full support of the style API for your custom components
  18.  *  you should implement this interface.
  19.  */
  20. public interface StylableComponent
  21. {
  22.     /**
  23.      *  Certain style configurations require SwingTree to install a
  24.      *  custom UI delegate. This method is used to set the UI delegate
  25.      *  for the component but without triggering side effects like
  26.      *  the former UI being uninstalled (which itself can cause
  27.      *  a lot of undesired side effects).
  28.      *  <p>
  29.      *  <b>This method is not intended to be called by client code!
  30.      *  It exists for internal use only and unfortunately cannot be
  31.      *  protected or private due to the nature of the Swing API.</b>
  32.      *  <p>
  33.      *  The implementation of this method is expected to look like this:
  34.      *  <pre>
  35.      *  {@literal @}Override
  36.      *  public void setUISilently(ComponentUI ui){
  37.      *      this.ui = ui; // no side effects
  38.      *  }
  39.      *  </pre>
  40.      * @param ui the UI delegate to set for the component
  41.      *           without triggering side effects.
  42.      */
  43.     void setUISilently( ComponentUI ui );

  44.     /**
  45.      *  This method is expected to be implemented as follows
  46.      *  within a component extension which ought to be made compatible
  47.      *  with SwingTree.
  48.      *  <pre>
  49.      *      {@literal @}Override
  50.      *      public void paint(Graphics g){
  51.      *          paintBackground(g, ()-&gt;super.paint(g));
  52.      *      }
  53.      *  </pre>
  54.      * @param g the graphics context to paint on,
  55.      *          obtained from the component's {@link JComponent#paint(Graphics)} method.
  56.      */
  57.     void paint( Graphics g );

  58.     /**
  59.      *  This method is expected to be implemented as follows:
  60.      *  <pre>
  61.      *      {@literal @}Override
  62.      *      public void paintChildren(Graphics g){
  63.      *          paintForeground(g, ()-&gt;super.paintChildren(g));
  64.      *      }
  65.      *  </pre>
  66.      * @param g the graphics context to paint on,
  67.      *          obtained from the component's {@code JComponent::paintChildren(Graphics)} method.
  68.      */
  69.     void paintChildren( Graphics g );

  70.     /**
  71.      *  <b>
  72.      *      This default method is not intended to be overridden by client code!
  73.      *      It delegates the painting to the library internal {@link ComponentExtension}.
  74.      *  </b>
  75.      *
  76.      * @param g The graphics context to paint on.
  77.      * @param superPaint The super.paint() method to call.
  78.      */
  79.     /*final*/ default void paintBackground( Graphics g, Consumer<Graphics> superPaint ) {
  80.         if ( this instanceof JComponent ) {
  81.             ComponentExtension.from((JComponent) this).paintBackgroundIfNeeded( g, superPaint );
  82.         }
  83.         else
  84.             throw new UnsupportedOperationException( "This interface is only intended for JComponent implementations" );
  85.     }

  86.     /**
  87.      *  <b>
  88.      *      This default method is not intended to be overridden by client code!
  89.      *      It delegates the painting to the library internal {@link ComponentExtension}.
  90.      *  </b>
  91.      *
  92.      * @param g The graphics context to paint on.
  93.      * @param superPaint The super.paintChildren() method to call.
  94.      */
  95.     /*final*/ default void paintForeground( Graphics g, Consumer<Graphics> superPaint ) {
  96.         if ( this instanceof JComponent ) {
  97.             ComponentExtension.from((JComponent) this).paintForeground( (Graphics2D) g, superPaint );
  98.         }
  99.         else
  100.             throw new UnsupportedOperationException( "This interface is only intended for JComponent implementations" );
  101.     }

  102. }