mirror of
https://github.com/JFormDesigner/FlatLaf.git
synced 2025-12-07 06:20:53 +03:00
Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d134c33499 | ||
|
|
a2b615d4a7 | ||
|
|
2e1acb7871 | ||
|
|
97a1bf90a4 | ||
|
|
7d3ffbc45a | ||
|
|
93ac6fa88a | ||
|
|
09d19a13b7 | ||
|
|
9eaee8d2c4 | ||
|
|
4da0c342f8 | ||
|
|
70fed22737 | ||
|
|
acb62e347a | ||
|
|
78d06d82d6 | ||
|
|
4777bdd250 | ||
|
|
266e9d92d5 | ||
|
|
54c14d0dc8 | ||
|
|
d59d353c2e | ||
|
|
204da2175b |
15
CHANGELOG.md
15
CHANGELOG.md
@@ -1,6 +1,21 @@
|
|||||||
FlatLaf Change Log
|
FlatLaf Change Log
|
||||||
==================
|
==================
|
||||||
|
|
||||||
|
## 0.31
|
||||||
|
|
||||||
|
- Focus indication border (or background) no longer hidden when temporary
|
||||||
|
loosing focus (e.g. showing a popup menu).
|
||||||
|
- List, Table and Tree: Item selection color of focused components no longer
|
||||||
|
change from blue to gray when temporary loosing focus (e.g. showing a popup
|
||||||
|
menu).
|
||||||
|
|
||||||
|
|
||||||
|
## 0.30
|
||||||
|
|
||||||
|
- Windows: Fixed rendering of Unicode characters. Previously not all Unicode
|
||||||
|
characters were rendered on Windows. (issue #81)
|
||||||
|
|
||||||
|
|
||||||
## 0.29
|
## 0.29
|
||||||
|
|
||||||
- Linux: Fixed scaling if `GDK_SCALE` environment variable is set or if running
|
- Linux: Fixed scaling if `GDK_SCALE` environment variable is set or if running
|
||||||
|
|||||||
@@ -79,7 +79,13 @@ Projects using FlatLaf
|
|||||||
- [jclasslib bytecode viewer](https://github.com/ingokegel/jclasslib) 5.5
|
- [jclasslib bytecode viewer](https://github.com/ingokegel/jclasslib) 5.5
|
||||||
- [KeyStore Explorer](https://keystore-explorer.org/) 5.4.3
|
- [KeyStore Explorer](https://keystore-explorer.org/) 5.4.3
|
||||||
- [OWASP Zed Attack Proxy (ZAP)](https://www.zaproxy.org/) (in weekly releases)
|
- [OWASP Zed Attack Proxy (ZAP)](https://www.zaproxy.org/) (in weekly releases)
|
||||||
|
- [XMLmind XML Editor](https://www.xmlmind.com/xmleditor/) 9.3 (commercial)
|
||||||
|
- [Total Validator](https://www.totalvalidator.com/) 15 (commercial)
|
||||||
- [j-lawyer](https://github.com/jlawyerorg/j-lawyer-org)
|
- [j-lawyer](https://github.com/jlawyerorg/j-lawyer-org)
|
||||||
|
- [MegaMek](https://github.com/MegaMek/megamek) v0.47.4 and
|
||||||
|
[MekHQ](https://github.com/MegaMek/mekhq) v0.47.5
|
||||||
|
- [GUIslice Builder](https://github.com/ImpulseAdventure/GUIslice-Builder)
|
||||||
|
0.13.b024
|
||||||
- [Rest Suite](https://github.com/supanadit/restsuite)
|
- [Rest Suite](https://github.com/supanadit/restsuite)
|
||||||
- [ControllerBuddy](https://github.com/bwRavencl/ControllerBuddy)
|
- [ControllerBuddy](https://github.com/bwRavencl/ControllerBuddy)
|
||||||
- [SpringRemote](https://github.com/HaleyWang/SpringRemote)
|
- [SpringRemote](https://github.com/HaleyWang/SpringRemote)
|
||||||
@@ -89,6 +95,8 @@ Projects using FlatLaf
|
|||||||
[mendelson AS2](https://mendelson-e-c.com/as2/),
|
[mendelson AS2](https://mendelson-e-c.com/as2/),
|
||||||
[AS4](https://mendelson-e-c.com/as4/) and
|
[AS4](https://mendelson-e-c.com/as4/) and
|
||||||
[OFTP2](https://mendelson-e-c.com/oftp2) (commercial)
|
[OFTP2](https://mendelson-e-c.com/oftp2) (commercial)
|
||||||
|
- [MeteoInfo](https://github.com/meteoinfo/MeteoInfo) 2.1.6
|
||||||
|
- [lsfusion platform](https://github.com/lsfusion/platform)
|
||||||
- and more...
|
- and more...
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -14,8 +14,8 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
val releaseVersion = "0.29"
|
val releaseVersion = "0.31"
|
||||||
val developmentVersion = "0.30-SNAPSHOT"
|
val developmentVersion = "0.32-SNAPSHOT"
|
||||||
|
|
||||||
version = if( java.lang.Boolean.getBoolean( "release" ) ) releaseVersion else developmentVersion
|
version = if( java.lang.Boolean.getBoolean( "release" ) ) releaseVersion else developmentVersion
|
||||||
|
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ import javax.swing.plaf.ColorUIResource;
|
|||||||
import javax.swing.plaf.FontUIResource;
|
import javax.swing.plaf.FontUIResource;
|
||||||
import javax.swing.plaf.UIResource;
|
import javax.swing.plaf.UIResource;
|
||||||
import javax.swing.plaf.basic.BasicLookAndFeel;
|
import javax.swing.plaf.basic.BasicLookAndFeel;
|
||||||
|
import javax.swing.text.StyleContext;
|
||||||
import javax.swing.text.html.HTMLEditorKit;
|
import javax.swing.text.html.HTMLEditorKit;
|
||||||
import com.formdev.flatlaf.util.SystemInfo;
|
import com.formdev.flatlaf.util.SystemInfo;
|
||||||
import com.formdev.flatlaf.util.UIScale;
|
import com.formdev.flatlaf.util.UIScale;
|
||||||
@@ -324,7 +325,7 @@ public abstract class FlatLaf
|
|||||||
if( SystemInfo.IS_WINDOWS ) {
|
if( SystemInfo.IS_WINDOWS ) {
|
||||||
Font winFont = (Font) Toolkit.getDefaultToolkit().getDesktopProperty( "win.messagebox.font" );
|
Font winFont = (Font) Toolkit.getDefaultToolkit().getDesktopProperty( "win.messagebox.font" );
|
||||||
if( winFont != null )
|
if( winFont != null )
|
||||||
uiFont = new FontUIResource( winFont );
|
uiFont = createCompositeFont( winFont.getFamily(), winFont.getStyle(), winFont.getSize() );
|
||||||
|
|
||||||
} else if( SystemInfo.IS_MAC ) {
|
} else if( SystemInfo.IS_MAC ) {
|
||||||
String fontName;
|
String fontName;
|
||||||
@@ -335,7 +336,8 @@ public abstract class FlatLaf
|
|||||||
// default font on older systems (see com.apple.laf.AquaFonts)
|
// default font on older systems (see com.apple.laf.AquaFonts)
|
||||||
fontName = "Lucida Grande";
|
fontName = "Lucida Grande";
|
||||||
}
|
}
|
||||||
uiFont = new FontUIResource( fontName, Font.PLAIN, 13 );
|
|
||||||
|
uiFont = createCompositeFont( fontName, Font.PLAIN, 13 );
|
||||||
|
|
||||||
} else if( SystemInfo.IS_LINUX ) {
|
} else if( SystemInfo.IS_LINUX ) {
|
||||||
Font font = LinuxFontPolicy.getFont();
|
Font font = LinuxFontPolicy.getFont();
|
||||||
@@ -343,7 +345,7 @@ public abstract class FlatLaf
|
|||||||
}
|
}
|
||||||
|
|
||||||
if( uiFont == null )
|
if( uiFont == null )
|
||||||
return;
|
uiFont = createCompositeFont( Font.SANS_SERIF, Font.PLAIN, 12 );
|
||||||
|
|
||||||
uiFont = UIScale.applyCustomScaleFactor( uiFont );
|
uiFont = UIScale.applyCustomScaleFactor( uiFont );
|
||||||
|
|
||||||
@@ -365,6 +367,14 @@ public abstract class FlatLaf
|
|||||||
defaults.put( "defaultFont", uiFont );
|
defaults.put( "defaultFont", uiFont );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static FontUIResource createCompositeFont( String family, int style, int size ) {
|
||||||
|
// using StyleContext.getFont() here because it uses
|
||||||
|
// sun.font.FontUtilities.getCompositeFontUIResource()
|
||||||
|
// and creates a composite font that is able to display all Unicode characters
|
||||||
|
Font font = new StyleContext().getFont( family, style, size );
|
||||||
|
return (font instanceof FontUIResource) ? (FontUIResource) font : new FontUIResource( font );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the default color palette for action icons and object icons to the given UIDefaults.
|
* Adds the default color palette for action icons and object icons to the given UIDefaults.
|
||||||
* <p>
|
* <p>
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ import java.util.Collections;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import javax.swing.text.StyleContext;
|
|
||||||
import com.formdev.flatlaf.util.StringUtils;
|
import com.formdev.flatlaf.util.StringUtils;
|
||||||
import com.formdev.flatlaf.util.SystemInfo;
|
import com.formdev.flatlaf.util.SystemInfo;
|
||||||
import com.formdev.flatlaf.util.UIScale;
|
import com.formdev.flatlaf.util.UIScale;
|
||||||
@@ -90,9 +89,7 @@ class LinuxFontPolicy
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static Font createFont( String family, int style, int size, double dsize ) {
|
private static Font createFont( String family, int style, int size, double dsize ) {
|
||||||
// using StyleContext.getFont() here because it uses
|
Font font = FlatLaf.createCompositeFont( family, style, size );
|
||||||
// sun.font.FontUtilities.getCompositeFontUIResource()
|
|
||||||
Font font = new StyleContext().getFont( family, style, size );
|
|
||||||
|
|
||||||
// set font size in floating points
|
// set font size in floating points
|
||||||
font = font.deriveFont( style, (float) dsize );
|
font = font.deriveFont( style, (float) dsize );
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ public class FlatCheckBoxIcon
|
|||||||
boolean selected = indeterminate || (c instanceof AbstractButton && ((AbstractButton)c).isSelected());
|
boolean selected = indeterminate || (c instanceof AbstractButton && ((AbstractButton)c).isSelected());
|
||||||
|
|
||||||
// paint focused border
|
// paint focused border
|
||||||
if( c.hasFocus() && focusWidth > 0 ) {
|
if( FlatUIUtils.isPermanentFocusOwner( c ) && focusWidth > 0 ) {
|
||||||
g2.setColor( focusColor );
|
g2.setColor( focusColor );
|
||||||
paintFocusBorder( g2 );
|
paintFocusBorder( g2 );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ public class FlatHelpButtonIcon
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
boolean enabled = c.isEnabled();
|
boolean enabled = c.isEnabled();
|
||||||
boolean focused = c.hasFocus();
|
boolean focused = FlatUIUtils.isPermanentFocusOwner( c );
|
||||||
|
|
||||||
// paint focused border
|
// paint focused border
|
||||||
if( focused ) {
|
if( focused ) {
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ public class FlatBorder
|
|||||||
JViewport viewport = ((JScrollPane)c).getViewport();
|
JViewport viewport = ((JScrollPane)c).getViewport();
|
||||||
Component view = (viewport != null) ? viewport.getView() : null;
|
Component view = (viewport != null) ? viewport.getView() : null;
|
||||||
if( view != null ) {
|
if( view != null ) {
|
||||||
if( view.hasFocus() )
|
if( FlatUIUtils.isPermanentFocusOwner( view ) )
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if( (view instanceof JTable && ((JTable)view).isEditing()) ||
|
if( (view instanceof JTable && ((JTable)view).isEditing()) ||
|
||||||
@@ -133,17 +133,17 @@ public class FlatBorder
|
|||||||
return false;
|
return false;
|
||||||
} else if( c instanceof JComboBox && ((JComboBox<?>)c).isEditable() ) {
|
} else if( c instanceof JComboBox && ((JComboBox<?>)c).isEditable() ) {
|
||||||
Component editorComponent = ((JComboBox<?>)c).getEditor().getEditorComponent();
|
Component editorComponent = ((JComboBox<?>)c).getEditor().getEditorComponent();
|
||||||
return (editorComponent != null) ? editorComponent.hasFocus() : false;
|
return (editorComponent != null) ? FlatUIUtils.isPermanentFocusOwner( editorComponent ) : false;
|
||||||
} else if( c instanceof JSpinner ) {
|
} else if( c instanceof JSpinner ) {
|
||||||
JComponent editor = ((JSpinner)c).getEditor();
|
JComponent editor = ((JSpinner)c).getEditor();
|
||||||
if( editor instanceof JSpinner.DefaultEditor ) {
|
if( editor instanceof JSpinner.DefaultEditor ) {
|
||||||
JTextField textField = ((JSpinner.DefaultEditor)editor).getTextField();
|
JTextField textField = ((JSpinner.DefaultEditor)editor).getTextField();
|
||||||
if( textField != null )
|
if( textField != null )
|
||||||
return textField.hasFocus();
|
return FlatUIUtils.isPermanentFocusOwner( textField );
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
} else
|
} else
|
||||||
return c.hasFocus();
|
return FlatUIUtils.isPermanentFocusOwner( c );
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean isTableCellEditor( Component c ) {
|
protected boolean isTableCellEditor( Component c ) {
|
||||||
|
|||||||
@@ -294,7 +294,9 @@ public class FlatButtonUI
|
|||||||
|
|
||||||
// paint shadow
|
// paint shadow
|
||||||
Color shadowColor = def ? defaultShadowColor : this.shadowColor;
|
Color shadowColor = def ? defaultShadowColor : this.shadowColor;
|
||||||
if( !isToolBarButton && shadowColor != null && shadowWidth > 0 && focusWidth > 0 && !c.hasFocus() && c.isEnabled() ) {
|
if( !isToolBarButton && shadowColor != null && shadowWidth > 0 && focusWidth > 0 &&
|
||||||
|
!FlatUIUtils.isPermanentFocusOwner( c ) && c.isEnabled() )
|
||||||
|
{
|
||||||
g2.setColor( shadowColor );
|
g2.setColor( shadowColor );
|
||||||
g2.fill( new RoundRectangle2D.Float( focusWidth, focusWidth + UIScale.scale( (float) shadowWidth ),
|
g2.fill( new RoundRectangle2D.Float( focusWidth, focusWidth + UIScale.scale( (float) shadowWidth ),
|
||||||
width - focusWidth * 2, height - focusWidth * 2, arc, arc ) );
|
width - focusWidth * 2, height - focusWidth * 2, arc, arc ) );
|
||||||
@@ -382,7 +384,7 @@ public class FlatButtonUI
|
|||||||
if( hoverColor != null && b != null && b.getModel().isRollover() )
|
if( hoverColor != null && b != null && b.getModel().isRollover() )
|
||||||
return hoverColor;
|
return hoverColor;
|
||||||
|
|
||||||
if( focusedColor != null && c.hasFocus() )
|
if( focusedColor != null && FlatUIUtils.isPermanentFocusOwner( c ) )
|
||||||
return focusedColor;
|
return focusedColor;
|
||||||
|
|
||||||
return enabledColor;
|
return enabledColor;
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ public class FlatListUI
|
|||||||
selectionInactiveBackground = UIManager.getColor( "List.selectionInactiveBackground" );
|
selectionInactiveBackground = UIManager.getColor( "List.selectionInactiveBackground" );
|
||||||
selectionInactiveForeground = UIManager.getColor( "List.selectionInactiveForeground" );
|
selectionInactiveForeground = UIManager.getColor( "List.selectionInactiveForeground" );
|
||||||
|
|
||||||
toggleSelectionColors( list.hasFocus() );
|
toggleSelectionColors();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -100,13 +100,13 @@ public class FlatListUI
|
|||||||
@Override
|
@Override
|
||||||
public void focusGained( FocusEvent e ) {
|
public void focusGained( FocusEvent e ) {
|
||||||
super.focusGained( e );
|
super.focusGained( e );
|
||||||
toggleSelectionColors( true );
|
toggleSelectionColors();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void focusLost( FocusEvent e ) {
|
public void focusLost( FocusEvent e ) {
|
||||||
super.focusLost( e );
|
super.focusLost( e );
|
||||||
toggleSelectionColors( false );
|
toggleSelectionColors();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -120,8 +120,8 @@ public class FlatListUI
|
|||||||
* already used in applications. Then either the inactive colors are not used,
|
* already used in applications. Then either the inactive colors are not used,
|
||||||
* or the application has to be changed to extend a FlatLaf renderer.
|
* or the application has to be changed to extend a FlatLaf renderer.
|
||||||
*/
|
*/
|
||||||
private void toggleSelectionColors( boolean focused ) {
|
private void toggleSelectionColors() {
|
||||||
if( focused ) {
|
if( FlatUIUtils.isPermanentFocusOwner( list ) ) {
|
||||||
if( list.getSelectionBackground() == selectionInactiveBackground )
|
if( list.getSelectionBackground() == selectionInactiveBackground )
|
||||||
list.setSelectionBackground( selectionBackground );
|
list.setSelectionBackground( selectionBackground );
|
||||||
if( list.getSelectionForeground() == selectionInactiveForeground )
|
if( list.getSelectionForeground() == selectionInactiveForeground )
|
||||||
|
|||||||
@@ -168,7 +168,7 @@ public class FlatPasswordFieldUI
|
|||||||
|
|
||||||
protected void paintCapsLock( Graphics g ) {
|
protected void paintCapsLock( Graphics g ) {
|
||||||
JTextComponent c = getComponent();
|
JTextComponent c = getComponent();
|
||||||
if( !c.isFocusOwner() ||
|
if( !FlatUIUtils.isPermanentFocusOwner( c ) ||
|
||||||
!Toolkit.getDefaultToolkit().getLockingKeyState( KeyEvent.VK_CAPS_LOCK ) )
|
!Toolkit.getDefaultToolkit().getLockingKeyState( KeyEvent.VK_CAPS_LOCK ) )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|||||||
@@ -201,7 +201,7 @@ public class FlatSliderUI
|
|||||||
}
|
}
|
||||||
|
|
||||||
if( coloredTrack != null ) {
|
if( coloredTrack != null ) {
|
||||||
FlatUIUtils.setColor( g, slider.hasFocus() ? focusColor : (hover ? hoverColor : thumbColor), thumbColor );
|
FlatUIUtils.setColor( g, FlatUIUtils.isPermanentFocusOwner( slider ) ? focusColor : (hover ? hoverColor : thumbColor), thumbColor );
|
||||||
((Graphics2D)g).fill( coloredTrack );
|
((Graphics2D)g).fill( coloredTrack );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,7 +212,7 @@ public class FlatSliderUI
|
|||||||
@Override
|
@Override
|
||||||
public void paintThumb( Graphics g ) {
|
public void paintThumb( Graphics g ) {
|
||||||
FlatUIUtils.setColor( g, slider.isEnabled()
|
FlatUIUtils.setColor( g, slider.isEnabled()
|
||||||
? (slider.hasFocus() ? focusColor : (hover ? hoverColor : thumbColor))
|
? (FlatUIUtils.isPermanentFocusOwner( slider ) ? focusColor : (hover ? hoverColor : thumbColor))
|
||||||
: disabledForeground,
|
: disabledForeground,
|
||||||
thumbColor );
|
thumbColor );
|
||||||
|
|
||||||
|
|||||||
@@ -318,7 +318,7 @@ public class FlatTabbedPaneUI
|
|||||||
boolean enabled = tabPane.isEnabled();
|
boolean enabled = tabPane.isEnabled();
|
||||||
g.setColor( enabled && tabPane.isEnabledAt( tabIndex ) && getRolloverTab() == tabIndex
|
g.setColor( enabled && tabPane.isEnabledAt( tabIndex ) && getRolloverTab() == tabIndex
|
||||||
? hoverColor
|
? hoverColor
|
||||||
: (enabled && isSelected && tabPane.hasFocus()
|
: (enabled && isSelected && FlatUIUtils.isPermanentFocusOwner( tabPane )
|
||||||
? focusColor
|
? focusColor
|
||||||
: (selectedBackground != null && enabled && isSelected
|
: (selectedBackground != null && enabled && isSelected
|
||||||
? selectedBackground
|
? selectedBackground
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ public class FlatTableUI
|
|||||||
selectionInactiveBackground = UIManager.getColor( "Table.selectionInactiveBackground" );
|
selectionInactiveBackground = UIManager.getColor( "Table.selectionInactiveBackground" );
|
||||||
selectionInactiveForeground = UIManager.getColor( "Table.selectionInactiveForeground" );
|
selectionInactiveForeground = UIManager.getColor( "Table.selectionInactiveForeground" );
|
||||||
|
|
||||||
toggleSelectionColors( table.hasFocus() );
|
toggleSelectionColors();
|
||||||
|
|
||||||
int rowHeight = FlatUIUtils.getUIInt( "Table.rowHeight", 16 );
|
int rowHeight = FlatUIUtils.getUIInt( "Table.rowHeight", 16 );
|
||||||
if( rowHeight > 0 )
|
if( rowHeight > 0 )
|
||||||
@@ -160,13 +160,13 @@ public class FlatTableUI
|
|||||||
@Override
|
@Override
|
||||||
public void focusGained( FocusEvent e ) {
|
public void focusGained( FocusEvent e ) {
|
||||||
super.focusGained( e );
|
super.focusGained( e );
|
||||||
toggleSelectionColors( true );
|
toggleSelectionColors();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void focusLost( FocusEvent e ) {
|
public void focusLost( FocusEvent e ) {
|
||||||
super.focusLost( e );
|
super.focusLost( e );
|
||||||
toggleSelectionColors( false );
|
toggleSelectionColors();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -180,8 +180,8 @@ public class FlatTableUI
|
|||||||
* already used in applications. Then either the inactive colors are not used,
|
* already used in applications. Then either the inactive colors are not used,
|
||||||
* or the application has to be changed to extend a FlatLaf renderer.
|
* or the application has to be changed to extend a FlatLaf renderer.
|
||||||
*/
|
*/
|
||||||
private void toggleSelectionColors( boolean focused ) {
|
private void toggleSelectionColors() {
|
||||||
if( focused ) {
|
if( FlatUIUtils.isPermanentFocusOwner( table ) ) {
|
||||||
if( table.getSelectionBackground() == selectionInactiveBackground )
|
if( table.getSelectionBackground() == selectionInactiveBackground )
|
||||||
table.setSelectionBackground( selectionBackground );
|
table.setSelectionBackground( selectionBackground );
|
||||||
if( table.getSelectionForeground() == selectionInactiveForeground )
|
if( table.getSelectionForeground() == selectionInactiveForeground )
|
||||||
|
|||||||
@@ -221,7 +221,7 @@ public class FlatTreeUI
|
|||||||
TreePath path, int row, boolean isExpanded, boolean hasBeenExpanded, boolean isLeaf )
|
TreePath path, int row, boolean isExpanded, boolean hasBeenExpanded, boolean isLeaf )
|
||||||
{
|
{
|
||||||
boolean isEditing = (editingComponent != null && editingRow == row);
|
boolean isEditing = (editingComponent != null && editingRow == row);
|
||||||
boolean hasFocus = tree.hasFocus();
|
boolean hasFocus = FlatUIUtils.isPermanentFocusOwner( tree );
|
||||||
boolean cellHasFocus = hasFocus && (row == getLeadSelectionRow());
|
boolean cellHasFocus = hasFocus && (row == getLeadSelectionRow());
|
||||||
boolean isSelected = tree.isRowSelected( row );
|
boolean isSelected = tree.isRowSelected( row );
|
||||||
boolean isDropRow = isDropRow( row );
|
boolean isDropRow = isDropRow( row );
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import java.awt.Font;
|
|||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
import java.awt.Insets;
|
import java.awt.Insets;
|
||||||
|
import java.awt.KeyboardFocusManager;
|
||||||
import java.awt.Rectangle;
|
import java.awt.Rectangle;
|
||||||
import java.awt.RenderingHints;
|
import java.awt.RenderingHints;
|
||||||
import java.awt.Shape;
|
import java.awt.Shape;
|
||||||
@@ -136,6 +137,10 @@ public class FlatUIUtils
|
|||||||
return c instanceof JComponent && Boolean.TRUE.equals( ((JComponent)c).getClientProperty( "JComboBox.isTableCellEditor" ) );
|
return c instanceof JComponent && Boolean.TRUE.equals( ((JComponent)c).getClientProperty( "JComboBox.isTableCellEditor" ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isPermanentFocusOwner( Component c ) {
|
||||||
|
return (KeyboardFocusManager.getCurrentKeyboardFocusManager().getPermanentFocusOwner() == c);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets rendering hints used for painting.
|
* Sets rendering hints used for painting.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -81,6 +81,11 @@ class DataComponentsPanel
|
|||||||
JScrollPane scrollPane5 = new JScrollPane();
|
JScrollPane scrollPane5 = new JScrollPane();
|
||||||
table1 = new JTable();
|
table1 = new JTable();
|
||||||
dndCheckBox = new JCheckBox();
|
dndCheckBox = new JCheckBox();
|
||||||
|
JPopupMenu popupMenu2 = new JPopupMenu();
|
||||||
|
JMenuItem menuItem3 = new JMenuItem();
|
||||||
|
JMenuItem menuItem4 = new JMenuItem();
|
||||||
|
JMenuItem menuItem5 = new JMenuItem();
|
||||||
|
JMenuItem menuItem6 = new JMenuItem();
|
||||||
|
|
||||||
//======== this ========
|
//======== this ========
|
||||||
setLayout(new MigLayout(
|
setLayout(new MigLayout(
|
||||||
@@ -126,6 +131,7 @@ class DataComponentsPanel
|
|||||||
@Override
|
@Override
|
||||||
public String getElementAt(int i) { return values[i]; }
|
public String getElementAt(int i) { return values[i]; }
|
||||||
});
|
});
|
||||||
|
list1.setComponentPopupMenu(popupMenu2);
|
||||||
scrollPane1.setViewportView(list1);
|
scrollPane1.setViewportView(list1);
|
||||||
}
|
}
|
||||||
add(scrollPane1, "cell 1 0,growx");
|
add(scrollPane1, "cell 1 0,growx");
|
||||||
@@ -198,6 +204,7 @@ class DataComponentsPanel
|
|||||||
add(node1);
|
add(node1);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
tree1.setComponentPopupMenu(popupMenu2);
|
||||||
scrollPane3.setViewportView(tree1);
|
scrollPane3.setViewportView(tree1);
|
||||||
}
|
}
|
||||||
add(scrollPane3, "cell 1 1,growx");
|
add(scrollPane3, "cell 1 1,growx");
|
||||||
@@ -287,6 +294,7 @@ class DataComponentsPanel
|
|||||||
}))));
|
}))));
|
||||||
}
|
}
|
||||||
table1.setAutoCreateRowSorter(true);
|
table1.setAutoCreateRowSorter(true);
|
||||||
|
table1.setComponentPopupMenu(popupMenu2);
|
||||||
scrollPane5.setViewportView(table1);
|
scrollPane5.setViewportView(table1);
|
||||||
}
|
}
|
||||||
add(scrollPane5, "cell 1 2 2 1,growx,width 300");
|
add(scrollPane5, "cell 1 2 2 1,growx,width 300");
|
||||||
@@ -296,6 +304,27 @@ class DataComponentsPanel
|
|||||||
dndCheckBox.setMnemonic('D');
|
dndCheckBox.setMnemonic('D');
|
||||||
dndCheckBox.addActionListener(e -> dndChanged());
|
dndCheckBox.addActionListener(e -> dndChanged());
|
||||||
add(dndCheckBox, "cell 0 3 3 1");
|
add(dndCheckBox, "cell 0 3 3 1");
|
||||||
|
|
||||||
|
//======== popupMenu2 ========
|
||||||
|
{
|
||||||
|
|
||||||
|
//---- menuItem3 ----
|
||||||
|
menuItem3.setText("Some Action");
|
||||||
|
popupMenu2.add(menuItem3);
|
||||||
|
|
||||||
|
//---- menuItem4 ----
|
||||||
|
menuItem4.setText("More Action");
|
||||||
|
popupMenu2.add(menuItem4);
|
||||||
|
popupMenu2.addSeparator();
|
||||||
|
|
||||||
|
//---- menuItem5 ----
|
||||||
|
menuItem5.setText("No Action");
|
||||||
|
popupMenu2.add(menuItem5);
|
||||||
|
|
||||||
|
//---- menuItem6 ----
|
||||||
|
menuItem6.setText("Noop Action");
|
||||||
|
popupMenu2.add(menuItem6);
|
||||||
|
}
|
||||||
// JFormDesigner - End of component initialization //GEN-END:initComponents
|
// JFormDesigner - End of component initialization //GEN-END:initComponents
|
||||||
|
|
||||||
((JComboBox)((DefaultCellEditor)table1.getColumnModel().getColumn( 3 ).getCellEditor()).getComponent()).setEditable( true );
|
((JComboBox)((DefaultCellEditor)table1.getColumnModel().getColumn( 3 ).getCellEditor()).getComponent()).setEditable( true );
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
JFDML JFormDesigner: "7.0.0.0.194" Java: "13.0.1" encoding: "UTF-8"
|
JFDML JFormDesigner: "7.0.1.0.272" Java: "13.0.2" encoding: "UTF-8"
|
||||||
|
|
||||||
new FormModel {
|
new FormModel {
|
||||||
contentType: "form/swing"
|
contentType: "form/swing"
|
||||||
@@ -39,6 +39,7 @@ new FormModel {
|
|||||||
addElement( "item 14" )
|
addElement( "item 14" )
|
||||||
addElement( "item 15" )
|
addElement( "item 15" )
|
||||||
}
|
}
|
||||||
|
"componentPopupMenu": new FormReference( "popupMenu2" )
|
||||||
auxiliary() {
|
auxiliary() {
|
||||||
"JavaCodeGenerator.typeParameters": "String"
|
"JavaCodeGenerator.typeParameters": "String"
|
||||||
"JavaCodeGenerator.variableLocal": false
|
"JavaCodeGenerator.variableLocal": false
|
||||||
@@ -143,6 +144,7 @@ new FormModel {
|
|||||||
} )
|
} )
|
||||||
} )
|
} )
|
||||||
} )
|
} )
|
||||||
|
"componentPopupMenu": new FormReference( "popupMenu2" )
|
||||||
auxiliary() {
|
auxiliary() {
|
||||||
"JavaCodeGenerator.variableLocal": false
|
"JavaCodeGenerator.variableLocal": false
|
||||||
}
|
}
|
||||||
@@ -299,6 +301,7 @@ new FormModel {
|
|||||||
add( null )
|
add( null )
|
||||||
} )
|
} )
|
||||||
"autoCreateRowSorter": true
|
"autoCreateRowSorter": true
|
||||||
|
"componentPopupMenu": new FormReference( "popupMenu2" )
|
||||||
auxiliary() {
|
auxiliary() {
|
||||||
"JavaCodeGenerator.variableLocal": false
|
"JavaCodeGenerator.variableLocal": false
|
||||||
}
|
}
|
||||||
@@ -321,5 +324,29 @@ new FormModel {
|
|||||||
"location": new java.awt.Point( 0, 0 )
|
"location": new java.awt.Point( 0, 0 )
|
||||||
"size": new java.awt.Dimension( 790, 715 )
|
"size": new java.awt.Dimension( 790, 715 )
|
||||||
} )
|
} )
|
||||||
|
add( new FormContainer( "javax.swing.JPopupMenu", new FormLayoutManager( class javax.swing.JPopupMenu ) ) {
|
||||||
|
name: "popupMenu2"
|
||||||
|
add( new FormComponent( "javax.swing.JMenuItem" ) {
|
||||||
|
name: "menuItem3"
|
||||||
|
"text": "Some Action"
|
||||||
|
} )
|
||||||
|
add( new FormComponent( "javax.swing.JMenuItem" ) {
|
||||||
|
name: "menuItem4"
|
||||||
|
"text": "More Action"
|
||||||
|
} )
|
||||||
|
add( new FormComponent( "javax.swing.JPopupMenu$Separator" ) {
|
||||||
|
name: "separator1"
|
||||||
|
} )
|
||||||
|
add( new FormComponent( "javax.swing.JMenuItem" ) {
|
||||||
|
name: "menuItem5"
|
||||||
|
"text": "No Action"
|
||||||
|
} )
|
||||||
|
add( new FormComponent( "javax.swing.JMenuItem" ) {
|
||||||
|
name: "menuItem6"
|
||||||
|
"text": "Noop Action"
|
||||||
|
} )
|
||||||
|
}, new FormLayoutConstraints( null ) {
|
||||||
|
"location": new java.awt.Point( 0, 740 )
|
||||||
|
} )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -216,7 +216,7 @@ public class FlatJideTabbedPaneUI
|
|||||||
g.setColor( enabled && _tabPane.isEnabledAt( tabIndex ) &&
|
g.setColor( enabled && _tabPane.isEnabledAt( tabIndex ) &&
|
||||||
(_indexMouseOver == tabIndex || (_closeButtons != null && ((JideTabbedPane.NoFocusButton)_closeButtons[tabIndex]).isMouseOver()))
|
(_indexMouseOver == tabIndex || (_closeButtons != null && ((JideTabbedPane.NoFocusButton)_closeButtons[tabIndex]).isMouseOver()))
|
||||||
? hoverColor
|
? hoverColor
|
||||||
: (enabled && isSelected && _tabPane.hasFocus()
|
: (enabled && isSelected && FlatUIUtils.isPermanentFocusOwner( _tabPane )
|
||||||
? focusColor
|
? focusColor
|
||||||
: _tabPane.getBackgroundAt( tabIndex )) );
|
: _tabPane.getBackgroundAt( tabIndex )) );
|
||||||
g.fillRect( x, y, w, h );
|
g.fillRect( x, y, w, h );
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import java.awt.Component;
|
|||||||
import javax.swing.JTable;
|
import javax.swing.JTable;
|
||||||
import org.jdesktop.swingx.JXDatePicker;
|
import org.jdesktop.swingx.JXDatePicker;
|
||||||
import com.formdev.flatlaf.ui.FlatRoundBorder;
|
import com.formdev.flatlaf.ui.FlatRoundBorder;
|
||||||
|
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Border for {@link org.jdesktop.swingx.JXDatePicker}.
|
* Border for {@link org.jdesktop.swingx.JXDatePicker}.
|
||||||
@@ -32,7 +33,7 @@ public class FlatDatePickerBorder
|
|||||||
@Override
|
@Override
|
||||||
protected boolean isFocused( Component c ) {
|
protected boolean isFocused( Component c ) {
|
||||||
if( c instanceof JXDatePicker )
|
if( c instanceof JXDatePicker )
|
||||||
return ((JXDatePicker)c).getEditor().hasFocus();
|
return FlatUIUtils.isPermanentFocusOwner( ((JXDatePicker)c).getEditor() );
|
||||||
|
|
||||||
return super.isFocused( c );
|
return super.isFocused( c );
|
||||||
}
|
}
|
||||||
|
|||||||
25
flatlaf-theme-editor/build.gradle.kts
Normal file
25
flatlaf-theme-editor/build.gradle.kts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 FormDev Software GmbH
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
`java-library`
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation( project( ":flatlaf-core" ) )
|
||||||
|
|
||||||
|
implementation( "com.fifesoft:rsyntaxtextarea:3.1.0" )
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 FormDev Software GmbH
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.formdev.flatlaf;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable accessing package private methods of {@link UIDefaultsLoader}.
|
||||||
|
*
|
||||||
|
* @author Karl Tauber
|
||||||
|
*/
|
||||||
|
public class UIDefaultsLoaderAccessor
|
||||||
|
{
|
||||||
|
public static int parseColorRGBA( String value ) {
|
||||||
|
return UIDefaultsLoader.parseColorRGBA( value );
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 FormDev Software GmbH
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.formdev.flatlaf.themeeditor;
|
||||||
|
|
||||||
|
import org.fife.ui.rsyntaxtextarea.OccurrenceMarker;
|
||||||
|
import org.fife.ui.rsyntaxtextarea.RSyntaxDocument;
|
||||||
|
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
|
||||||
|
import org.fife.ui.rsyntaxtextarea.RSyntaxTextAreaHighlighter;
|
||||||
|
import org.fife.ui.rsyntaxtextarea.Token;
|
||||||
|
import org.fife.ui.rsyntaxtextarea.TokenImpl;
|
||||||
|
import org.fife.ui.rtextarea.SmartHighlightPainter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delegating occurrence marker that does not mark token at caret if it does
|
||||||
|
* not occur elsewhere.
|
||||||
|
*
|
||||||
|
* @author Karl Tauber
|
||||||
|
*/
|
||||||
|
class FlatOccurrenceMarker
|
||||||
|
implements OccurrenceMarker
|
||||||
|
{
|
||||||
|
private final OccurrenceMarker delegate;
|
||||||
|
|
||||||
|
FlatOccurrenceMarker( OccurrenceMarker delegate ) {
|
||||||
|
this.delegate = delegate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Token getTokenToMark( RSyntaxTextArea textArea ) {
|
||||||
|
return delegate.getTokenToMark( textArea );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValidType( RSyntaxTextArea textArea, Token t ) {
|
||||||
|
return delegate.isValidType( textArea, t );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void markOccurrences( RSyntaxDocument doc, Token t, RSyntaxTextAreaHighlighter h, SmartHighlightPainter p ) {
|
||||||
|
char[] lexeme = t.getLexeme().toCharArray();
|
||||||
|
int type = t.getType();
|
||||||
|
int lineCount = doc.getDefaultRootElement().getElementCount();
|
||||||
|
|
||||||
|
// make a copy of the token because it is overwritten in getTokenListForLine()
|
||||||
|
Token t2 = new TokenImpl( t );
|
||||||
|
|
||||||
|
// check whether token occurres more than once
|
||||||
|
boolean mark = false;
|
||||||
|
for( int i = 0; i < lineCount && !mark; i++ ) {
|
||||||
|
Token temp = doc.getTokenListForLine( i );
|
||||||
|
while( temp != null && temp.isPaintable() ) {
|
||||||
|
if( temp.is( type, lexeme ) && temp.getOffset() != t2.getOffset() ) {
|
||||||
|
mark = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
temp = temp.getNextToken();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( mark )
|
||||||
|
delegate.markOccurrences( doc, t2, h, p );
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 FormDev Software GmbH
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.formdev.flatlaf.themeeditor;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import javax.swing.text.BadLocationException;
|
||||||
|
import org.fife.ui.rsyntaxtextarea.TextEditorPane;
|
||||||
|
import org.fife.ui.rsyntaxtextarea.Token;
|
||||||
|
import com.formdev.flatlaf.UIDefaultsLoaderAccessor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A text area that supports editing FlatLaf themes.
|
||||||
|
*
|
||||||
|
* @author Karl Tauber
|
||||||
|
*/
|
||||||
|
class FlatSyntaxTextArea
|
||||||
|
extends TextEditorPane
|
||||||
|
{
|
||||||
|
private boolean useColorOfColorTokens;
|
||||||
|
|
||||||
|
private final Map<String, Color> parsedColorsMap = new HashMap<>();
|
||||||
|
|
||||||
|
FlatSyntaxTextArea() {
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isUseColorOfColorTokens() {
|
||||||
|
return useColorOfColorTokens;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setUseColorOfColorTokens( boolean useColorOfColorTokens ) {
|
||||||
|
this.useColorOfColorTokens = useColorOfColorTokens;
|
||||||
|
setHighlightCurrentLine( !useColorOfColorTokens );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Color getBackgroundForToken( Token t ) {
|
||||||
|
if( useColorOfColorTokens && t.getType() == FlatThemeTokenMaker.TOKEN_COLOR ) {
|
||||||
|
Color color = parseColor( t );
|
||||||
|
if( color != null )
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.getBackgroundForToken( t );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Color getForegroundForToken( Token t ) {
|
||||||
|
if( useColorOfColorTokens && t.getType() == FlatThemeTokenMaker.TOKEN_COLOR && !isCurrentLineHighlighted( t.getOffset() )) {
|
||||||
|
Color color = parseColor( t );
|
||||||
|
if( color != null ) {
|
||||||
|
return (colorLuminance( color ) > 164 || color.getAlpha() < 96)
|
||||||
|
? Color.black
|
||||||
|
: Color.white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.getForegroundForToken( t );
|
||||||
|
}
|
||||||
|
|
||||||
|
private Color parseColor( Token token ) {
|
||||||
|
return parsedColorsMap.computeIfAbsent( token.getLexeme(), s -> {
|
||||||
|
try {
|
||||||
|
return new Color( UIDefaultsLoaderAccessor.parseColorRGBA( s ), true );
|
||||||
|
} catch( IllegalArgumentException ex ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private int colorLuminance( Color c ) {
|
||||||
|
int red = c.getRed();
|
||||||
|
int green = c.getGreen();
|
||||||
|
int blue = c.getBlue();
|
||||||
|
|
||||||
|
int min = Math.min( red, Math.min( green, blue ) );
|
||||||
|
int max = Math.max( red, Math.max( green, blue ) );
|
||||||
|
|
||||||
|
return (max + min) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isCurrentLineHighlighted( int offset ) {
|
||||||
|
try {
|
||||||
|
return getHighlightCurrentLine() &&
|
||||||
|
getSelectionStart() == getSelectionEnd() &&
|
||||||
|
getLineOfOffset( offset ) == getLineOfOffset( getSelectionStart() );
|
||||||
|
} catch( BadLocationException ex ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 FormDev Software GmbH
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.formdev.flatlaf.themeeditor;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.awt.Font;
|
||||||
|
import java.awt.FontMetrics;
|
||||||
|
import java.awt.Graphics;
|
||||||
|
import java.awt.Point;
|
||||||
|
import java.awt.Rectangle;
|
||||||
|
import javax.swing.JComponent;
|
||||||
|
import javax.swing.JLayer;
|
||||||
|
import javax.swing.plaf.LayerUI;
|
||||||
|
import javax.swing.text.BadLocationException;
|
||||||
|
import org.fife.ui.rsyntaxtextarea.Token;
|
||||||
|
import com.formdev.flatlaf.UIDefaultsLoaderAccessor;
|
||||||
|
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||||
|
import com.formdev.flatlaf.util.HSLColor;
|
||||||
|
import com.formdev.flatlaf.util.UIScale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An overlay layer that paints additional information about line content on the right side.
|
||||||
|
*
|
||||||
|
* @author Karl Tauber
|
||||||
|
*/
|
||||||
|
class FlatThemeEditorOverlay
|
||||||
|
extends LayerUI<FlatSyntaxTextArea>
|
||||||
|
{
|
||||||
|
private static final int COLOR_PREVIEW_WIDTH = 100;
|
||||||
|
|
||||||
|
private Font font;
|
||||||
|
private Font baseFont;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void paint( Graphics g, JComponent c ) {
|
||||||
|
// paint the syntax text area
|
||||||
|
super.paint( g, c );
|
||||||
|
|
||||||
|
@SuppressWarnings( "unchecked" )
|
||||||
|
FlatSyntaxTextArea textArea = ((JLayer<FlatSyntaxTextArea>)c).getView();
|
||||||
|
Rectangle clipBounds = g.getClipBounds();
|
||||||
|
|
||||||
|
// determine first and last visible lines
|
||||||
|
int firstVisibleLine;
|
||||||
|
int lastVisibleLine;
|
||||||
|
try {
|
||||||
|
int startOffset = textArea.viewToModel( new Point( 0, clipBounds.y ) );
|
||||||
|
int endOffset = textArea.viewToModel( new Point( 0, clipBounds.y + clipBounds.height ) );
|
||||||
|
firstVisibleLine = textArea.getLineOfOffset( startOffset );
|
||||||
|
lastVisibleLine = textArea.getLineOfOffset( endOffset );
|
||||||
|
} catch( BadLocationException ex ) {
|
||||||
|
// ignore
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// compute font (and cache it)
|
||||||
|
if( baseFont != textArea.getFont() ) {
|
||||||
|
baseFont = textArea.getFont();
|
||||||
|
int fontSize = Math.max( (int) Math.round( baseFont.getSize() * 0.8 ), 8 );
|
||||||
|
font = baseFont.deriveFont( (float) fontSize );
|
||||||
|
}
|
||||||
|
|
||||||
|
FontMetrics fm = c.getFontMetrics( font );
|
||||||
|
int maxTextWidth = fm.stringWidth( "HSL 360 100 100" );
|
||||||
|
int textHeight = fm.getAscent() - fm.getLeading();
|
||||||
|
|
||||||
|
int width = c.getWidth();
|
||||||
|
int previewWidth = UIScale.scale( COLOR_PREVIEW_WIDTH );
|
||||||
|
int gap = UIScale.scale( 4 );
|
||||||
|
|
||||||
|
// check whether preview is outside of clip bounds
|
||||||
|
if( clipBounds.x + clipBounds.width < width - previewWidth - maxTextWidth - gap )
|
||||||
|
return;
|
||||||
|
|
||||||
|
g.setFont( font );
|
||||||
|
|
||||||
|
// paint additional information
|
||||||
|
for( int line = firstVisibleLine; line <= lastVisibleLine; line++ ) {
|
||||||
|
Color color = getColorInLine( textArea, line );
|
||||||
|
if( color == null )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// paint color preview
|
||||||
|
int lineEndOffset = textArea.getLineEndOffset( line );
|
||||||
|
Rectangle r = textArea.modelToView( lineEndOffset - 1 );
|
||||||
|
int pw = Math.min( width - r.x - gap, previewWidth );
|
||||||
|
int px = width - pw;
|
||||||
|
g.setColor( color );
|
||||||
|
g.fillRect( px, r.y, pw, r.height );
|
||||||
|
|
||||||
|
// paint text
|
||||||
|
int textX = px - maxTextWidth;
|
||||||
|
if( textX > r.x + gap) {
|
||||||
|
float[] hsl = HSLColor.fromRGB( color );
|
||||||
|
String hslStr = String.format( "HSL %d %d %d",
|
||||||
|
Math.round( hsl[0] ), Math.round( hsl[1] ), Math.round( hsl[2] ) );
|
||||||
|
g.setColor( textArea.getForeground() );
|
||||||
|
FlatUIUtils.drawString( textArea, g, hslStr, textX,
|
||||||
|
r.y + ((r.height - textHeight) / 2) + textHeight );
|
||||||
|
}
|
||||||
|
} catch( BadLocationException ex ) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Color getColorInLine( FlatSyntaxTextArea textArea, int line ) {
|
||||||
|
Token token = textArea.getTokenListForLine( line );
|
||||||
|
for( Token t = token; t != null && t.isPaintable(); t = t.getNextToken() ) {
|
||||||
|
if( t.getType() == FlatThemeTokenMaker.TOKEN_COLOR ) {
|
||||||
|
try {
|
||||||
|
return new Color( UIDefaultsLoaderAccessor.parseColorRGBA( t.getLexeme() ), true );
|
||||||
|
} catch( IllegalArgumentException ex ) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 FormDev Software GmbH
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.formdev.flatlaf.themeeditor;
|
||||||
|
|
||||||
|
import java.awt.BorderLayout;
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.awt.Font;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import javax.swing.JLayer;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import org.fife.ui.rsyntaxtextarea.AbstractTokenMakerFactory;
|
||||||
|
import org.fife.ui.rsyntaxtextarea.FileLocation;
|
||||||
|
import org.fife.ui.rsyntaxtextarea.SyntaxScheme;
|
||||||
|
import org.fife.ui.rsyntaxtextarea.Theme;
|
||||||
|
import org.fife.ui.rsyntaxtextarea.TokenMakerFactory;
|
||||||
|
import org.fife.ui.rtextarea.RTextScrollPane;
|
||||||
|
import com.formdev.flatlaf.util.UIScale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A pane that supports editing FlatLaf themes.
|
||||||
|
*
|
||||||
|
* @author Karl Tauber
|
||||||
|
*/
|
||||||
|
class FlatThemeEditorPane
|
||||||
|
extends JPanel
|
||||||
|
{
|
||||||
|
private static final String FLATLAF_STYLE = "text/flatlaf";
|
||||||
|
|
||||||
|
private final RTextScrollPane scrollPane;
|
||||||
|
private final FlatSyntaxTextArea textArea;
|
||||||
|
|
||||||
|
FlatThemeEditorPane() {
|
||||||
|
super( new BorderLayout() );
|
||||||
|
|
||||||
|
// register FlatLaf token maker
|
||||||
|
AbstractTokenMakerFactory tmf = (AbstractTokenMakerFactory) TokenMakerFactory.getDefaultInstance();
|
||||||
|
tmf.putMapping( FLATLAF_STYLE, FlatThemeTokenMaker.class.getName() );
|
||||||
|
|
||||||
|
// create text area
|
||||||
|
textArea = new FlatSyntaxTextArea();
|
||||||
|
textArea.setSyntaxEditingStyle( FLATLAF_STYLE );
|
||||||
|
textArea.setMarkOccurrences( true );
|
||||||
|
textArea.addParser( new FlatThemeParser() );
|
||||||
|
// textArea.setUseColorOfColorTokens( true );
|
||||||
|
|
||||||
|
// theme
|
||||||
|
try {
|
||||||
|
Theme theme = Theme.load( getClass().getResourceAsStream( "light.xml" ) );
|
||||||
|
theme.apply( textArea );
|
||||||
|
} catch( IOException ex ) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
// use semitransparent token background because token background
|
||||||
|
// is painted over mark occurrences background
|
||||||
|
SyntaxScheme scheme = textArea.getSyntaxScheme();
|
||||||
|
scheme.getStyle( FlatThemeTokenMaker.TOKEN_COLOR ).background = new Color( 0x0a000000, true );
|
||||||
|
scheme.getStyle( FlatThemeTokenMaker.TOKEN_VARIABLE ).background = new Color( 0x1800cc00, true );
|
||||||
|
|
||||||
|
// create overlay layer
|
||||||
|
JLayer<FlatSyntaxTextArea> overlay = new JLayer<>( textArea, new FlatThemeEditorOverlay() );
|
||||||
|
|
||||||
|
// create scroll pane
|
||||||
|
scrollPane = new RTextScrollPane( overlay );
|
||||||
|
scrollPane.setLineNumbersEnabled( true );
|
||||||
|
|
||||||
|
// scale fonts
|
||||||
|
if( UIScale.getUserScaleFactor() != 1 )
|
||||||
|
textArea.setFont( scaleFont( textArea.getFont() ) );
|
||||||
|
|
||||||
|
// use same font for line numbers as in editor
|
||||||
|
scrollPane.getGutter().setLineNumberFont( textArea.getFont() );
|
||||||
|
|
||||||
|
add( scrollPane, BorderLayout.CENTER );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Font scaleFont( Font font ) {
|
||||||
|
int newFontSize = UIScale.scale( font.getSize() );
|
||||||
|
return font.deriveFont( (float) newFontSize );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void load( FileLocation loc ) throws IOException {
|
||||||
|
textArea.load( loc, StandardCharsets.ISO_8859_1 );
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 FormDev Software GmbH
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.formdev.flatlaf.themeeditor;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import javax.swing.*;
|
||||||
|
import org.fife.ui.rsyntaxtextarea.FileLocation;
|
||||||
|
import com.formdev.flatlaf.FlatLightLaf;
|
||||||
|
import com.formdev.flatlaf.util.UIScale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO
|
||||||
|
*
|
||||||
|
* @author Karl Tauber
|
||||||
|
*/
|
||||||
|
public class FlatThemeFileEditor
|
||||||
|
extends JFrame
|
||||||
|
{
|
||||||
|
public static void main( String[] args ) {
|
||||||
|
File file = new File( args.length > 0
|
||||||
|
? args[0]
|
||||||
|
: "theme-editor-test.properties" ); // TODO
|
||||||
|
|
||||||
|
SwingUtilities.invokeLater( () -> {
|
||||||
|
FlatLightLaf.install();
|
||||||
|
|
||||||
|
FlatThemeFileEditor frame = new FlatThemeFileEditor();
|
||||||
|
|
||||||
|
try {
|
||||||
|
frame.themeEditorArea.load( FileLocation.create( file ) );
|
||||||
|
} catch( IOException ex ) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
|
||||||
|
frame.setSize( Math.min( UIScale.scale( 800 ), screenSize.width ),
|
||||||
|
screenSize.height - UIScale.scale( 100 ) );
|
||||||
|
frame.setLocationRelativeTo( null );
|
||||||
|
frame.setVisible( true );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
public FlatThemeFileEditor() {
|
||||||
|
initComponents();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initComponents() {
|
||||||
|
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
|
||||||
|
dialogPane = new JPanel();
|
||||||
|
themeEditorArea = new FlatThemeEditorPane();
|
||||||
|
|
||||||
|
//======== this ========
|
||||||
|
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
|
||||||
|
setTitle("FlatLaf Theme Editor");
|
||||||
|
Container contentPane = getContentPane();
|
||||||
|
contentPane.setLayout(new BorderLayout());
|
||||||
|
|
||||||
|
//======== dialogPane ========
|
||||||
|
{
|
||||||
|
dialogPane.setLayout(new BorderLayout());
|
||||||
|
dialogPane.add(themeEditorArea, BorderLayout.CENTER);
|
||||||
|
}
|
||||||
|
contentPane.add(dialogPane, BorderLayout.CENTER);
|
||||||
|
// JFormDesigner - End of component initialization //GEN-END:initComponents
|
||||||
|
}
|
||||||
|
|
||||||
|
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables
|
||||||
|
private JPanel dialogPane;
|
||||||
|
private FlatThemeEditorPane themeEditorArea;
|
||||||
|
// JFormDesigner - End of variables declaration //GEN-END:variables
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
JFDML JFormDesigner: "7.0.1.0.272" Java: "13.0.1" encoding: "UTF-8"
|
||||||
|
|
||||||
|
new FormModel {
|
||||||
|
contentType: "form/swing"
|
||||||
|
root: new FormRoot {
|
||||||
|
add( new FormWindow( "javax.swing.JFrame", new FormLayoutManager( class java.awt.BorderLayout ) ) {
|
||||||
|
name: "this"
|
||||||
|
"$locationPolicy": 2
|
||||||
|
"$sizePolicy": 2
|
||||||
|
"defaultCloseOperation": 2
|
||||||
|
"title": "FlatLaf Theme Editor"
|
||||||
|
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class java.awt.BorderLayout ) ) {
|
||||||
|
name: "dialogPane"
|
||||||
|
add( new FormComponent( "com.formdev.flatlaf.themeeditor.FlatThemeEditorPane" ) {
|
||||||
|
name: "themeEditorArea"
|
||||||
|
}, new FormLayoutConstraints( class java.lang.String ) {
|
||||||
|
"value": "Center"
|
||||||
|
} )
|
||||||
|
}, new FormLayoutConstraints( class java.lang.String ) {
|
||||||
|
"value": "Center"
|
||||||
|
} )
|
||||||
|
}, new FormLayoutConstraints( null ) {
|
||||||
|
"location": new java.awt.Point( 0, 0 )
|
||||||
|
"size": new java.awt.Dimension( 535, 300 )
|
||||||
|
} )
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 FormDev Software GmbH
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.formdev.flatlaf.themeeditor;
|
||||||
|
|
||||||
|
import javax.swing.text.Element;
|
||||||
|
import org.fife.ui.rsyntaxtextarea.RSyntaxDocument;
|
||||||
|
import org.fife.ui.rsyntaxtextarea.Token;
|
||||||
|
import org.fife.ui.rsyntaxtextarea.parser.AbstractParser;
|
||||||
|
import org.fife.ui.rsyntaxtextarea.parser.DefaultParseResult;
|
||||||
|
import org.fife.ui.rsyntaxtextarea.parser.DefaultParserNotice;
|
||||||
|
import org.fife.ui.rsyntaxtextarea.parser.ParseResult;
|
||||||
|
import com.formdev.flatlaf.UIDefaultsLoaderAccessor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parser for FlatLaf properties files that checks for invalid values.
|
||||||
|
*
|
||||||
|
* @author Karl Tauber
|
||||||
|
*/
|
||||||
|
class FlatThemeParser
|
||||||
|
extends AbstractParser
|
||||||
|
{
|
||||||
|
private final DefaultParseResult result;
|
||||||
|
|
||||||
|
FlatThemeParser() {
|
||||||
|
result = new DefaultParseResult( this );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ParseResult parse( RSyntaxDocument doc, String style ) {
|
||||||
|
Element root = doc.getDefaultRootElement();
|
||||||
|
|
||||||
|
result.clearNotices();
|
||||||
|
result.setParsedLines( 0, root.getElementCount() - 1 );
|
||||||
|
|
||||||
|
for( Token token : doc ) {
|
||||||
|
if( token.getType() == FlatThemeTokenMaker.TOKEN_COLOR ) {
|
||||||
|
try {
|
||||||
|
UIDefaultsLoaderAccessor.parseColorRGBA( token.getLexeme() );
|
||||||
|
} catch( IllegalArgumentException ex ) {
|
||||||
|
result.addNotice( new DefaultParserNotice( this,
|
||||||
|
"Invalid color.\n\nUse #RRGGBB, #RRGGBBAA, #RGB or #RGBA",
|
||||||
|
root.getElementIndex( token.getOffset() ),
|
||||||
|
token.getOffset(), token.length() ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,228 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 FormDev Software GmbH
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.formdev.flatlaf.themeeditor;
|
||||||
|
|
||||||
|
import org.fife.ui.rsyntaxtextarea.OccurrenceMarker;
|
||||||
|
import org.fife.ui.rsyntaxtextarea.RSyntaxUtilities;
|
||||||
|
import org.fife.ui.rsyntaxtextarea.Token;
|
||||||
|
import org.fife.ui.rsyntaxtextarea.TokenMap;
|
||||||
|
import org.fife.ui.rsyntaxtextarea.TokenTypes;
|
||||||
|
import org.fife.ui.rsyntaxtextarea.modes.PropertiesFileTokenMaker;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Token maker for FlatLaf properties files.
|
||||||
|
* <p>
|
||||||
|
* Lets the super class parse the properties file and modify the added tokens.
|
||||||
|
* The super class uses {@link TokenTypes#RESERVED_WORD} for property keys and
|
||||||
|
* {@link TokenTypes#LITERAL_STRING_DOUBLE_QUOTE} for property values.
|
||||||
|
*
|
||||||
|
* @author Karl Tauber
|
||||||
|
*/
|
||||||
|
public class FlatThemeTokenMaker
|
||||||
|
extends PropertiesFileTokenMaker
|
||||||
|
{
|
||||||
|
static final int TOKEN_PROPERTY = Token.IDENTIFIER;
|
||||||
|
static final int TOKEN_VARIABLE = Token.VARIABLE;
|
||||||
|
static final int TOKEN_NUMBER = Token.LITERAL_NUMBER_DECIMAL_INT;
|
||||||
|
static final int TOKEN_COLOR = Token.LITERAL_NUMBER_HEXADECIMAL;
|
||||||
|
static final int TOKEN_STRING = Token.LITERAL_STRING_DOUBLE_QUOTE;
|
||||||
|
static final int TOKEN_FUNCTION = Token.FUNCTION;
|
||||||
|
static final int TOKEN_TYPE = Token.DATA_TYPE;
|
||||||
|
|
||||||
|
private final TokenMap tokenMap = new TokenMap();
|
||||||
|
|
||||||
|
public FlatThemeTokenMaker() {
|
||||||
|
// null, false, true
|
||||||
|
tokenMap.put( "null", Token.RESERVED_WORD );
|
||||||
|
tokenMap.put( "false", Token.LITERAL_BOOLEAN );
|
||||||
|
tokenMap.put( "true", Token.LITERAL_BOOLEAN );
|
||||||
|
|
||||||
|
// functions
|
||||||
|
tokenMap.put( "rgb", TOKEN_FUNCTION );
|
||||||
|
tokenMap.put( "rgba", TOKEN_FUNCTION );
|
||||||
|
tokenMap.put( "hsl", TOKEN_FUNCTION );
|
||||||
|
tokenMap.put( "hsla", TOKEN_FUNCTION );
|
||||||
|
tokenMap.put( "lighten", TOKEN_FUNCTION );
|
||||||
|
tokenMap.put( "darken", TOKEN_FUNCTION );
|
||||||
|
tokenMap.put( "lazy", TOKEN_FUNCTION );
|
||||||
|
|
||||||
|
// function options
|
||||||
|
tokenMap.put( "relative", Token.RESERVED_WORD );
|
||||||
|
tokenMap.put( "autoInverse", Token.RESERVED_WORD );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is only invoked from the super class.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void addToken( char[] array, int start, int end, int tokenType, int startOffset, boolean hyperlink ) {
|
||||||
|
// debugInputToken( array, start, end, tokenType, startOffset, hyperlink );
|
||||||
|
|
||||||
|
// ignore invalid token
|
||||||
|
if( end < start )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if( tokenType == Token.RESERVED_WORD ) {
|
||||||
|
// key
|
||||||
|
int newTokenType = (array[start] == '@') ? TOKEN_VARIABLE : TOKEN_PROPERTY;
|
||||||
|
super.addToken( array, start, end, newTokenType, startOffset, hyperlink );
|
||||||
|
} else if( tokenType == Token.LITERAL_STRING_DOUBLE_QUOTE ) {
|
||||||
|
// value
|
||||||
|
tokenizeValue( array, start, end, startOffset );
|
||||||
|
} else if( tokenType == Token.VARIABLE ) {
|
||||||
|
// '{variable}'
|
||||||
|
super.addToken( array, start, end, TOKEN_TYPE, startOffset, hyperlink );
|
||||||
|
} else {
|
||||||
|
// comments or operators
|
||||||
|
super.addToken( array, start, end, tokenType, startOffset, hyperlink );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void tokenizeValue( char[] array, int start, int end, int startOffset ) {
|
||||||
|
int newStartOffset = startOffset - start;
|
||||||
|
|
||||||
|
int currentTokenStart = start;
|
||||||
|
int currentTokenType = Token.NULL;
|
||||||
|
int parenthesisLevel = 0;
|
||||||
|
|
||||||
|
for( int i = start; i <= end; i++ ) {
|
||||||
|
int newTokenType;
|
||||||
|
char ch = array[i];
|
||||||
|
if( ch <= ' ' )
|
||||||
|
newTokenType = Token.WHITESPACE;
|
||||||
|
else if( ch == '#' || (currentTokenType == TOKEN_COLOR && RSyntaxUtilities.isHexCharacter( ch )) )
|
||||||
|
newTokenType = TOKEN_COLOR;
|
||||||
|
else if( ch == '$' || (currentTokenType == TOKEN_PROPERTY && isPropertyChar( ch )) )
|
||||||
|
newTokenType = TOKEN_PROPERTY;
|
||||||
|
else if( ch == '@' || (currentTokenType == TOKEN_VARIABLE && isPropertyChar( ch )) )
|
||||||
|
newTokenType = TOKEN_VARIABLE;
|
||||||
|
else if( currentTokenType != TOKEN_STRING && (RSyntaxUtilities.isDigit( ch ) || (currentTokenType == TOKEN_NUMBER && ch == '.')) )
|
||||||
|
newTokenType = TOKEN_NUMBER;
|
||||||
|
else if( ch == ',' || ch == '(' || ch == ')' || ch == '"' || ch == '%' )
|
||||||
|
newTokenType = TokenTypes.OPERATOR;
|
||||||
|
else
|
||||||
|
newTokenType = TOKEN_STRING;
|
||||||
|
|
||||||
|
if( currentTokenType == Token.NULL )
|
||||||
|
currentTokenType = newTokenType;
|
||||||
|
else if( newTokenType != currentTokenType ) {
|
||||||
|
addTokenImpl( array, currentTokenStart, i - 1, currentTokenType, newStartOffset + currentTokenStart, parenthesisLevel );
|
||||||
|
currentTokenType = newTokenType;
|
||||||
|
currentTokenStart = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ch == '(' )
|
||||||
|
parenthesisLevel++;
|
||||||
|
else if( ch == ')' )
|
||||||
|
parenthesisLevel--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( currentTokenType != Token.NULL )
|
||||||
|
addTokenImpl( array, currentTokenStart, end, currentTokenType, newStartOffset + currentTokenStart, parenthesisLevel );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addTokenImpl( char[] array, int start, int end, int tokenType, int startOffset, int parenthesisLevel ) {
|
||||||
|
if( tokenType == TOKEN_PROPERTY && array[start] == '$' ) {
|
||||||
|
// separate '$' from property token for mark occurrences to work
|
||||||
|
super.addToken( array, start, start, TokenTypes.OPERATOR, startOffset, false );
|
||||||
|
start++;
|
||||||
|
startOffset++;
|
||||||
|
} else if( tokenType == TOKEN_STRING ) {
|
||||||
|
// check for reserved words, functions, etc
|
||||||
|
int type = tokenMap.get( array, start, end );
|
||||||
|
if( type != -1 )
|
||||||
|
tokenType = type;
|
||||||
|
else if( parenthesisLevel > 0 ) {
|
||||||
|
// assume property reference if in function parameters
|
||||||
|
tokenType = TOKEN_PROPERTY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// debugOutputToken( array, start, end, tokenType );
|
||||||
|
super.addToken( array, start, end, tokenType, startOffset, false );
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isPropertyChar( char ch ) {
|
||||||
|
return RSyntaxUtilities.isLetterOrDigit( ch ) || ch == '.' || ch == '_' || ch == '-';
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected OccurrenceMarker createOccurrenceMarker() {
|
||||||
|
return new FlatOccurrenceMarker( super.createOccurrenceMarker() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getMarkOccurrencesOfTokenType( int type ) {
|
||||||
|
switch( type ) {
|
||||||
|
case TOKEN_PROPERTY:
|
||||||
|
case TOKEN_VARIABLE:
|
||||||
|
case TOKEN_COLOR:
|
||||||
|
case TOKEN_FUNCTION:
|
||||||
|
case TOKEN_TYPE:
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*debug
|
||||||
|
private java.util.HashMap<Integer, String> tokenTypeStrMap;
|
||||||
|
|
||||||
|
private void debugInputToken( char[] array, int start, int end, int tokenType, int startOffset, boolean hyperlink ) {
|
||||||
|
if( tokenTypeStrMap == null ) {
|
||||||
|
tokenTypeStrMap = new java.util.HashMap<>();
|
||||||
|
for( java.lang.reflect.Field f : TokenTypes.class.getFields() ) {
|
||||||
|
try {
|
||||||
|
tokenTypeStrMap.put( (Integer) f.get( null ), f.getName() );
|
||||||
|
} catch( IllegalArgumentException | IllegalAccessException ex ) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String tokenTypeStr = tokenTypeStrMap.computeIfAbsent( tokenType, t -> {
|
||||||
|
return "(unknown " + t + ")";
|
||||||
|
} );
|
||||||
|
|
||||||
|
System.out.printf( "%d-%d (%d) %-30s '%s'\n",
|
||||||
|
start, end, end - start, tokenTypeStr, new String( array, start, end - start + 1 ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void debugOutputToken( char[] array, int start, int end, int tokenType ) {
|
||||||
|
String tokenTypeStr = null;
|
||||||
|
switch( tokenType ) {
|
||||||
|
case TOKEN_PROPERTY: tokenTypeStr = "PROPERTY"; break;
|
||||||
|
case TOKEN_VARIABLE: tokenTypeStr = "VARIABLE"; break;
|
||||||
|
case TOKEN_NUMBER: tokenTypeStr = "NUMBER"; break;
|
||||||
|
case TOKEN_COLOR: tokenTypeStr = "COLOR"; break;
|
||||||
|
case TOKEN_STRING: tokenTypeStr = "STRING"; break;
|
||||||
|
case TOKEN_FUNCTION: tokenTypeStr = "FUNCTION"; break;
|
||||||
|
case TOKEN_TYPE: tokenTypeStr = "TYPE"; break;
|
||||||
|
case TokenTypes.OPERATOR: tokenTypeStr = "OPERATOR"; break;
|
||||||
|
case TokenTypes.WHITESPACE: tokenTypeStr = "WHITESPACE"; break;
|
||||||
|
case TokenTypes.LITERAL_BOOLEAN: tokenTypeStr = "BOOLEAN"; break;
|
||||||
|
case TokenTypes.RESERVED_WORD: tokenTypeStr = "RESERVED_WORD"; break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException( String.valueOf( tokenType ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.printf( " %d-%d (%d) %-15s '%s'\n",
|
||||||
|
start, end, end - start, tokenTypeStr, new String( array, start, end - start + 1 ) );
|
||||||
|
}
|
||||||
|
debug*/
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<!DOCTYPE RSyntaxTheme SYSTEM "theme.dtd">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
FlatLaf Light theme.
|
||||||
|
See theme.dtd and org.fife.ui.rsyntaxtextarea.Theme for more information.
|
||||||
|
-->
|
||||||
|
<RSyntaxTheme version="1.0">
|
||||||
|
|
||||||
|
<!-- Omitting baseFont will use a system-appropriate monospaced. -->
|
||||||
|
<baseFont size="12"/>
|
||||||
|
|
||||||
|
<!-- General editor colors. -->
|
||||||
|
<background color="ffffff"/>
|
||||||
|
<caret color="000000"/>
|
||||||
|
<selection fg="default" useFG="false" bg="A6D2FF"/>
|
||||||
|
<currentLineHighlight color="FCFAED" fade="false"/>
|
||||||
|
<marginLine fg="b0b4b9"/>
|
||||||
|
<markAllHighlight color="ffc800"/>
|
||||||
|
<markOccurrencesHighlight color="d4d4d4" border="false"/>
|
||||||
|
<matchedBracket fg="000080" bg="eaeaff" highlightBoth="false" animate="true"/>
|
||||||
|
<hyperlinks fg="0000ff"/>
|
||||||
|
<secondaryLanguages>
|
||||||
|
<language index="1" bg="fff0cc"/>
|
||||||
|
<language index="2" bg="dafeda"/>
|
||||||
|
<language index="3" bg="ffe0f0"/>
|
||||||
|
</secondaryLanguages>
|
||||||
|
|
||||||
|
<!-- Gutter styling. -->
|
||||||
|
<gutterBorder color="dddddd"/>
|
||||||
|
<lineNumbers fg="787878"/>
|
||||||
|
<foldIndicator fg="808080" iconBg="ffffff"/>
|
||||||
|
<iconRowHeader activeLineRange="3399ff"/>
|
||||||
|
|
||||||
|
<!-- Syntax tokens. -->
|
||||||
|
<tokenStyles>
|
||||||
|
<style token="IDENTIFIER" fg="000000"/>
|
||||||
|
<style token="RESERVED_WORD" fg="871094"/>
|
||||||
|
<style token="RESERVED_WORD_2" fg="0000ff"/>
|
||||||
|
<style token="ANNOTATION" fg="808080"/>
|
||||||
|
<style token="COMMENT_DOCUMENTATION" fg="a40000" italic="true"/>
|
||||||
|
<style token="COMMENT_EOL" fg="8C8C8C" italic="true"/>
|
||||||
|
<style token="COMMENT_MULTILINE" fg="8C8C8C" italic="true"/>
|
||||||
|
<style token="COMMENT_KEYWORD" fg="ff9900"/>
|
||||||
|
<style token="COMMENT_MARKUP" fg="808080"/>
|
||||||
|
<style token="DATA_TYPE" fg="8C8C8C"/>
|
||||||
|
<style token="FUNCTION" fg="871094"/>
|
||||||
|
<style token="LITERAL_BOOLEAN" fg="871094"/>
|
||||||
|
<style token="LITERAL_NUMBER_DECIMAL_INT" fg="1750EB"/>
|
||||||
|
<style token="LITERAL_NUMBER_FLOAT" fg="1750EB"/>
|
||||||
|
<style token="LITERAL_NUMBER_HEXADECIMAL" fg="1750EB"/>
|
||||||
|
<style token="LITERAL_STRING_DOUBLE_QUOTE" fg="008000"/>
|
||||||
|
<style token="LITERAL_CHAR" fg="DC009C"/>
|
||||||
|
<style token="LITERAL_BACKQUOTE" fg="DC009C"/>
|
||||||
|
<style token="MARKUP_TAG_DELIMITER" fg="ff0000"/>
|
||||||
|
<style token="MARKUP_TAG_NAME" fg="0000ff"/>
|
||||||
|
<style token="MARKUP_TAG_ATTRIBUTE" fg="3f7f7f"/>
|
||||||
|
<style token="MARKUP_TAG_ATTRIBUTE_VALUE" fg="DC009C"/>
|
||||||
|
<style token="MARKUP_COMMENT" fg="006000" italic="true"/>
|
||||||
|
<style token="MARKUP_DTD" fg="ad8000"/>
|
||||||
|
<style token="MARKUP_PROCESSING_INSTRUCTION" fg="808080"/>
|
||||||
|
<style token="MARKUP_CDATA" fg="cc6600"/>
|
||||||
|
<style token="MARKUP_CDATA_DELIMITER" fg="008080"/>
|
||||||
|
<style token="MARKUP_ENTITY_REFERENCE" fg="008000"/>
|
||||||
|
<style token="OPERATOR" fg="000000"/>
|
||||||
|
<style token="PREPROCESSOR" fg="808080"/>
|
||||||
|
<style token="REGEX" fg="008040"/>
|
||||||
|
<style token="SEPARATOR" fg="ff0000"/>
|
||||||
|
<style token="VARIABLE" fg="000000"/>
|
||||||
|
<style token="WHITESPACE" fg="000000"/>
|
||||||
|
|
||||||
|
<style token="ERROR_IDENTIFIER" fg="000000" bg="ffcccc"/>
|
||||||
|
<style token="ERROR_NUMBER_FORMAT" fg="000000" bg="ffcccc"/>
|
||||||
|
<style token="ERROR_STRING_DOUBLE" fg="000000" bg="ffcccc"/>
|
||||||
|
<style token="ERROR_CHAR" fg="000000" bg="ffcccc"/>
|
||||||
|
</tokenStyles>
|
||||||
|
|
||||||
|
</RSyntaxTheme>
|
||||||
42
flatlaf-theme-editor/theme-editor-test.properties
Normal file
42
flatlaf-theme-editor/theme-editor-test.properties
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
#
|
||||||
|
# some comment
|
||||||
|
#
|
||||||
|
|
||||||
|
ButtonUI=com.formdev.flatlaf.ui.FlatButtonUI
|
||||||
|
CheckBoxUI = com.formdev.flatlaf.ui.FlatCheckBoxUI
|
||||||
|
|
||||||
|
Prop.string=some string
|
||||||
|
Prop.string2="some string 123 #f80"
|
||||||
|
Prop.char1=x
|
||||||
|
Prop.char2=\u2022
|
||||||
|
Prop.integer=123
|
||||||
|
Prop.float=456.123
|
||||||
|
Prop.color1=#f80
|
||||||
|
Prop.color2=#ff8800
|
||||||
|
Prop.color3=#f804
|
||||||
|
Prop.color4=#ff880044
|
||||||
|
Prop.color5=#12
|
||||||
|
Prop.color6=#12345
|
||||||
|
Prop.border=1,2,3,4
|
||||||
|
|
||||||
|
Prop.scaledInteger={scaledInteger}123
|
||||||
|
|
||||||
|
Prop.null=null
|
||||||
|
Prop.false=false
|
||||||
|
Prop.true=true
|
||||||
|
|
||||||
|
@var1=123
|
||||||
|
Prop.var=@var1
|
||||||
|
Prop.ref=$Prop.string
|
||||||
|
|
||||||
|
Prop.lazy=lazy(Prop.string)
|
||||||
|
|
||||||
|
Prop.colorFunc1=rgb(12,34,56)
|
||||||
|
Prop.colorFunc2=rgba(12,34,56,78)
|
||||||
|
Prop.colorFunc3=hsl(12,34,56)
|
||||||
|
Prop.colorFunc4=hsla(12,34,56,78)
|
||||||
|
|
||||||
|
Prop.colorFunc5=lighten(#fe1289,20%)
|
||||||
|
Prop.colorFunc6=darken(#fe1289,20%)
|
||||||
|
Prop.colorFunc7=lighten($Prop.colorFunc4,20%,relative autoInverse)
|
||||||
|
Prop.colorFunc8=lighten(Prop.colorFunc4,20%,lazy)
|
||||||
@@ -22,6 +22,7 @@ include( "flatlaf-swingx" )
|
|||||||
include( "flatlaf-jide-oss" )
|
include( "flatlaf-jide-oss" )
|
||||||
include( "flatlaf-demo" )
|
include( "flatlaf-demo" )
|
||||||
include( "flatlaf-testing" )
|
include( "flatlaf-testing" )
|
||||||
|
include( "flatlaf-theme-editor" )
|
||||||
|
|
||||||
pluginManagement {
|
pluginManagement {
|
||||||
plugins {
|
plugins {
|
||||||
|
|||||||
Reference in New Issue
Block a user