From 4da0c342f8141214a53434576eebdbd29b0a4e77 Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Mon, 6 Apr 2020 15:42:58 +0200 Subject: [PATCH] Theme Editor: paint real colors and HSL values in overlay on right side of editor (instead of behind editor text; previous commit) --- .../themeeditor/FlatThemeEditorOverlay.java | 136 ++++++++++++++++++ .../themeeditor/FlatThemeEditorPane.java | 15 +- 2 files changed, 146 insertions(+), 5 deletions(-) create mode 100644 flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemeEditorOverlay.java diff --git a/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemeEditorOverlay.java b/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemeEditorOverlay.java new file mode 100644 index 00000000..9ec3f0eb --- /dev/null +++ b/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemeEditorOverlay.java @@ -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 +{ + 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)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; + } +} diff --git a/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemeEditorPane.java b/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemeEditorPane.java index 6f346a50..d5e80354 100644 --- a/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemeEditorPane.java +++ b/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemeEditorPane.java @@ -21,6 +21,7 @@ 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; @@ -55,7 +56,7 @@ class FlatThemeEditorPane textArea.setSyntaxEditingStyle( FLATLAF_STYLE ); textArea.setMarkOccurrences( true ); textArea.addParser( new FlatThemeParser() ); - textArea.setUseColorOfColorTokens( true ); +// textArea.setUseColorOfColorTokens( true ); // theme try { @@ -71,15 +72,19 @@ class FlatThemeEditorPane scheme.getStyle( FlatThemeTokenMaker.TOKEN_COLOR ).background = new Color( 0x0a000000, true ); scheme.getStyle( FlatThemeTokenMaker.TOKEN_VARIABLE ).background = new Color( 0x1800cc00, true ); + // create overlay layer + JLayer overlay = new JLayer<>( textArea, new FlatThemeEditorOverlay() ); + // create scroll pane - scrollPane = new RTextScrollPane( textArea ); + scrollPane = new RTextScrollPane( overlay ); scrollPane.setLineNumbersEnabled( true ); // scale fonts - if( UIScale.getUserScaleFactor() != 1 ) { + if( UIScale.getUserScaleFactor() != 1 ) textArea.setFont( scaleFont( textArea.getFont() ) ); - scrollPane.getGutter().setLineNumberFont( scaleFont( scrollPane.getGutter().getLineNumberFont() ) ); - } + + // use same font for line numbers as in editor + scrollPane.getGutter().setLineNumberFont( textArea.getFont() ); add( scrollPane, BorderLayout.CENTER ); }