@ -10,13 +10,18 @@ import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicToolTipUI ;
import javax.swing.text.View ;
import java.awt.* ;
import java.awt.event.HierarchyEvent ;
import java.awt.event.HierarchyListener ;
import java.awt.event.MouseAdapter ;
import java.awt.event.MouseEvent ;
import java.awt.event.MouseListener ;
import java.beans.PropertyChangeEvent ;
import java.beans.PropertyChangeListener ;
/ * *
* @author Jannis Weis
* /
public class DarkTooltipUI extends BasicToolTipUI implements PropertyChangeListener {
public class DarkTooltipUI extends BasicToolTipUI implements PropertyChangeListener , HierarchyListener {
@NotNull
@Contract ( "_ -> new" )
@ -28,8 +33,69 @@ public class DarkTooltipUI extends BasicToolTipUI implements PropertyChangeListe
}
}
protected JToolTip toolTip ;
protected MouseListener mouseListener = new MouseAdapter ( ) {
@Override
public void mouseEntered ( @NotNull final MouseEvent e ) {
if ( e . getButton ( ) = = MouseEvent . BUTTON1 ) return ;
/ *
* We redispatch the event to the ToolTipManager with a corrected location .
* Because the ToolTipManager check for outside using > = width / height instead of > width / height and due to
* the nature of mouseEntered events most of the times having width / height as their coordinated ToolTips would
* not show up when the component is entered through the bottom / right side of the component .
* /
var p = e . getPoint ( ) ;
var c = toolTip . getComponent ( ) ;
if ( p . x = = c . getWidth ( ) ) p . x - - ;
if ( p . y = = c . getHeight ( ) ) p . y - - ;
p . x = Math . max ( p . x , 0 ) ;
p . y = Math . max ( p . y , 0 ) ;
ToolTipManager . sharedInstance ( )
. mouseEntered ( new MouseEvent ( c , e . getID ( ) , e . getWhen ( ) , e . getModifiersEx ( ) , p . x , p . y ,
e . getClickCount ( ) , e . isPopupTrigger ( ) , e . getButton ( ) ) ) ;
}
@Override
public void mouseExited ( @NotNull final MouseEvent e ) {
boolean inside = isInside ( e ) ;
if ( ! inside ) {
ToolTipManager . sharedInstance ( ) . mouseExited (
new MouseEvent ( toolTip . getComponent ( ) , e . getID ( ) , e . getWhen ( ) , e . getModifiersEx ( ) ,
Integer . MIN_VALUE , Integer . MIN_VALUE , e . getClickCount ( ) , e . isPopupTrigger ( ) ,
e . getButton ( ) ) ) ;
}
}
} ;
protected MouseListener exitListener = new MouseAdapter ( ) {
@Override
public void mouseExited ( @NotNull final MouseEvent e ) {
ToolTipManager . sharedInstance ( ) . mouseExited (
new MouseEvent ( toolTip . getComponent ( ) , e . getID ( ) , e . getWhen ( ) , e . getModifiersEx ( ) ,
Integer . MIN_VALUE , Integer . MIN_VALUE , e . getClickCount ( ) , e . isPopupTrigger ( ) ,
e . getButton ( ) ) ) ;
}
} ;
protected boolean isInside ( @NotNull final MouseEvent e ) {
var p = SwingUtilities . convertPoint ( e . getComponent ( ) , e . getPoint ( ) , toolTip ) ;
return contains ( toolTip , p . x , p . y ) ;
}
@Override
public boolean contains ( @NotNull final JComponent c , final int x , final int y ) {
var b = c . getBorder ( ) ;
if ( b instanceof DarkTooltipBorder ) {
var insideArea = ( ( DarkTooltipBorder ) b ) . getBackgroundArea ( toolTip ,
toolTip . getWidth ( ) , toolTip . getHeight ( ) ) ;
return insideArea . contains ( x , y ) ;
} else {
return super . contains ( c , x , y ) ;
}
}
@Override
public void installUI ( final JComponent c ) {
toolTip = ( JToolTip ) c ;
super . installUI ( c ) ;
}
@ -43,16 +109,33 @@ public class DarkTooltipUI extends BasicToolTipUI implements PropertyChangeListe
}
}
@Override
public void uninstallUI ( final JComponent c ) {
super . uninstallUI ( c ) ;
toolTip = null ;
}
@Override
protected void installListeners ( final JComponent c ) {
super . installListeners ( c ) ;
c . addHierarchyListener ( e - > {
var w = SwingUtilities . getWindowAncestor ( c ) ;
if ( w ! = null & & ! c . isLightweight ( ) & & ! isDecorated ( w ) ) {
w . setBackground ( DarkUIUtil . TRANSPARENT_COLOR ) ;
}
} ) ;
c . addHierarchyListener ( this ) ;
c . addPropertyChangeListener ( this ) ;
toolTip . addMouseListener ( exitListener ) ;
var comp = toolTip . getComponent ( ) ;
if ( comp ! = null ) {
comp . addMouseListener ( mouseListener ) ;
}
}
@Override
protected void uninstallListeners ( final JComponent c ) {
super . uninstallListeners ( c ) ;
c . removePropertyChangeListener ( this ) ;
toolTip . removeMouseListener ( exitListener ) ;
var comp = toolTip . getComponent ( ) ;
if ( comp ! = null ) {
comp . removeMouseListener ( mouseListener ) ;
}
}
@Override
@ -98,6 +181,14 @@ public class DarkTooltipUI extends BasicToolTipUI implements PropertyChangeListe
return false ;
}
@Override
public void hierarchyChanged ( final HierarchyEvent e ) {
var w = SwingUtilities . getWindowAncestor ( toolTip ) ;
if ( w ! = null & & ! toolTip . isLightweight ( ) & & ! isDecorated ( w ) ) {
w . setBackground ( DarkUIUtil . TRANSPARENT_COLOR ) ;
}
}
@Override
public void propertyChange ( @NotNull final PropertyChangeEvent evt ) {
var key = evt . getPropertyName ( ) ;
@ -123,8 +214,20 @@ public class DarkTooltipUI extends BasicToolTipUI implements PropertyChangeListe
border . setPointerWidth ( ( Integer ) newVal ) ;
}
tooltip . setComponent ( tooltip . getComponent ( ) ) ;
} else if ( "JToolTip.insets" . equals ( key ) ) {
tooltip . setComponent ( tooltip . getComponent ( ) ) ;
} else if ( "component" . equals ( key ) ) {
var oldComp = evt . getOldValue ( ) ;
if ( oldComp instanceof Component ) {
( ( Component ) oldComp ) . removeMouseListener ( mouseListener ) ;
}
var newComp = evt . getNewValue ( ) ;
if ( newComp instanceof Component ) {
( ( Component ) newComp ) . addMouseListener ( mouseListener ) ;
}
}
}
}
}
}