Compare commits
155 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a253b6c0cf | ||
|
|
efcbc1fbdb | ||
|
|
ae28c595f9 | ||
|
|
1d08ddda60 | ||
|
|
578379fd00 | ||
|
|
7c9f550d4c | ||
|
|
84d4510d70 | ||
|
|
fa194ec258 | ||
|
|
fd56de403d | ||
|
|
85fde46504 | ||
|
|
b283178979 | ||
|
|
bddef38a7c | ||
|
|
b5f2f77944 | ||
|
|
fca0718ed0 | ||
|
|
0d44ade6ea | ||
|
|
6018f83a22 | ||
|
|
0b6247851b | ||
|
|
8640dee053 | ||
|
|
824db2e3bd | ||
|
|
c2c79c4676 | ||
|
|
4795fe5687 | ||
|
|
d508f339c1 | ||
|
|
c7054537e7 | ||
|
|
b98b904023 | ||
|
|
253df9325d | ||
|
|
78a9cc1d0c | ||
|
|
b25fcc3381 | ||
|
|
51d7bc2c37 | ||
|
|
09a18b2305 | ||
|
|
31f2feee2e | ||
|
|
218bb62bfd | ||
|
|
694c2ad767 | ||
|
|
97943fcd38 | ||
|
|
77f33467d2 | ||
|
|
651454170d | ||
|
|
7ca48bd136 | ||
|
|
968e508bb5 | ||
|
|
a6d318a197 | ||
|
|
cd20f4086b | ||
|
|
ebd5905947 | ||
|
|
817a3c62bb | ||
|
|
f8f58400fe | ||
|
|
ef06840649 | ||
|
|
b17c14d62e | ||
|
|
19dba94064 | ||
|
|
601e24f9e7 | ||
|
|
c7f323ee13 | ||
|
|
e4522f3af4 | ||
|
|
79af461a5b | ||
|
|
2e8e07faf6 | ||
|
|
ecdb000818 | ||
|
|
999fd0d4da | ||
|
|
705dd9558f | ||
|
|
97ca866ffa | ||
|
|
543b977db7 | ||
|
|
ebb8a6d025 | ||
|
|
506543281e | ||
|
|
60322be22a | ||
|
|
e1f30f24a8 | ||
|
|
1759f6b25c | ||
|
|
6578f25cc9 | ||
|
|
8c26e0323f | ||
|
|
a5575894ab | ||
|
|
357823a027 | ||
|
|
a6d3f6b3eb | ||
|
|
ae4c69e75c | ||
|
|
31cadc532b | ||
|
|
6e8443473b | ||
|
|
cca4ab3cd8 | ||
|
|
dab0ee3306 | ||
|
|
c6d1ed91a7 | ||
|
|
a613a244f4 | ||
|
|
268fe15004 | ||
|
|
7bc9be686f | ||
|
|
751919ec5a | ||
|
|
da913b426e | ||
|
|
d8ef99cd8f | ||
|
|
d08a6d7dd3 | ||
|
|
896e9bca8e | ||
|
|
1df9597bb1 | ||
|
|
eaf55f2099 | ||
|
|
5018a1f9eb | ||
|
|
71ba8f55a7 | ||
|
|
b65db707ed | ||
|
|
ed62266a43 | ||
|
|
49913b7dad | ||
|
|
3eeeb9e00b | ||
|
|
bfb1642284 | ||
|
|
0544a605c3 | ||
|
|
3f5acda132 | ||
|
|
02b1ba2926 | ||
|
|
7f7f9e3c7c | ||
|
|
6fcee03752 | ||
|
|
5782ceeb5d | ||
|
|
f752db5892 | ||
|
|
bce58bc97b | ||
|
|
d373687bc4 | ||
|
|
e5e510c825 | ||
|
|
29064ec72f | ||
|
|
953eee1dc8 | ||
|
|
75f76f4875 | ||
|
|
ecfbe68c33 | ||
|
|
7f02eb9cf0 | ||
|
|
4ab90065dc | ||
|
|
d3e39a1359 | ||
|
|
60e5861de4 | ||
|
|
ca7f5045ae | ||
|
|
b0997fb5d2 | ||
|
|
37dab9fb22 | ||
|
|
fb44c8fbe4 | ||
|
|
94375b7d36 | ||
|
|
8b585deb78 | ||
|
|
4d8b544aed | ||
|
|
548d651d29 | ||
|
|
0b342acec9 | ||
|
|
cc6d3c1b1a | ||
|
|
74a748d92e | ||
|
|
1de81d0af5 | ||
|
|
ff9ef21f67 | ||
|
|
266a546478 | ||
|
|
87407ca832 | ||
|
|
90282d4436 | ||
|
|
abbe6d6c1f | ||
|
|
a28f701e6f | ||
|
|
4cdc995a7f | ||
|
|
c708205593 | ||
|
|
a22c6c8013 | ||
|
|
b576f473e5 | ||
|
|
0b127caa83 | ||
|
|
4507ce359d | ||
|
|
3e14f28dc2 | ||
|
|
a9dcf09d13 | ||
|
|
c8998c2bcf | ||
|
|
10bf1295bc | ||
|
|
1e869973d4 | ||
|
|
731c8962c9 | ||
|
|
294b8bb789 | ||
|
|
4f9b819f48 | ||
|
|
5318d5fa8e | ||
|
|
98b156bdde | ||
|
|
511dd02107 | ||
|
|
f1f7a2e7b6 | ||
|
|
d557cf5427 | ||
|
|
39d2941099 | ||
|
|
2a732306a1 | ||
|
|
8a72b30cbc | ||
|
|
ed9cb0f918 | ||
|
|
7e0915cb9c | ||
|
|
a51294d570 | ||
|
|
d962f218a1 | ||
|
|
7b248427f0 | ||
|
|
b99fb8b11f | ||
|
|
26250e790f | ||
|
|
b26dbe81f4 | ||
|
|
903212345b |
8
.gitbugtraq
Normal file
@@ -0,0 +1,8 @@
|
||||
# links issue numbers in git commit messages to issue tracker
|
||||
# https://github.com/mstrap/bugtraq
|
||||
# for SmartGit - https://www.syntevo.com/smartgit/
|
||||
|
||||
[bugtraq]
|
||||
url = "https://github.com/JFormDesigner/FlatLaf/issues/%BUGID%"
|
||||
loglinkregex = "#[0-9]{1,5}"
|
||||
logregex = "[0-9]{1,5}"
|
||||
26
.github/workflows/ci.yml
vendored
@@ -97,11 +97,22 @@ jobs:
|
||||
restore-keys: ${{ runner.os }}-gradle
|
||||
|
||||
- name: Publish snapshot to oss.sonatype.org
|
||||
run: ./gradlew publish -Dorg.gradle.internal.publish.checksums.insecure=true
|
||||
run: ./gradlew publish :flatlaf-theme-editor:build -Dorg.gradle.internal.publish.checksums.insecure=true
|
||||
env:
|
||||
OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
|
||||
OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
|
||||
|
||||
- name: Upload theme editor
|
||||
uses: sebastianpopp/ftp-action@releases/v2
|
||||
with:
|
||||
host: ${{ secrets.FTP_SERVER }}
|
||||
user: ${{ secrets.FTP_USERNAME }}
|
||||
password: ${{ secrets.FTP_PASSWORD }}
|
||||
forceSsl: true
|
||||
localDir: "flatlaf-theme-editor/build/libs"
|
||||
remoteDir: "snapshots"
|
||||
options: "--only-newer --no-recursion --verbose=1"
|
||||
|
||||
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -133,7 +144,7 @@ jobs:
|
||||
restore-keys: ${{ runner.os }}-gradle
|
||||
|
||||
- name: Release a new stable version to Maven Central
|
||||
run: ./gradlew publish :flatlaf-demo:build -Drelease=true
|
||||
run: ./gradlew publish :flatlaf-demo:build :flatlaf-theme-editor:build -Drelease=true
|
||||
env:
|
||||
OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
|
||||
OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
|
||||
@@ -150,3 +161,14 @@ jobs:
|
||||
localDir: "flatlaf-demo/build/libs"
|
||||
remoteDir: "."
|
||||
options: "--only-newer --no-recursion --verbose=1"
|
||||
|
||||
- name: Upload theme editor
|
||||
uses: sebastianpopp/ftp-action@releases/v2
|
||||
with:
|
||||
host: ${{ secrets.FTP_SERVER }}
|
||||
user: ${{ secrets.FTP_USERNAME }}
|
||||
password: ${{ secrets.FTP_PASSWORD }}
|
||||
forceSsl: true
|
||||
localDir: "flatlaf-theme-editor/build/libs"
|
||||
remoteDir: "."
|
||||
options: "--only-newer --no-recursion --verbose=1"
|
||||
|
||||
137
CHANGELOG.md
@@ -1,6 +1,143 @@
|
||||
FlatLaf Change Log
|
||||
==================
|
||||
|
||||
## 1.6.1
|
||||
|
||||
#### Fixed bugs
|
||||
|
||||
- Native window decorations: Catch `UnsatisfiedLinkError` when trying to load
|
||||
`jawt.dll` to avoid an application crash (Java 8 on Windows 10 only).
|
||||
|
||||
|
||||
## 1.6
|
||||
|
||||
#### New features and improvements
|
||||
|
||||
- InternalFrame: Double-click on icon in internal frame title bar now closes the
|
||||
internal frame. (issue #374)
|
||||
- IntelliJ Themes: Removed deprecated `install()` methods.
|
||||
|
||||
#### Fixed bugs
|
||||
|
||||
- Menus: Fixed missing modifiers flags in `ActionEvent` (e.g. `Ctrl` key
|
||||
pressed) when running in Java 9+ on Linux, macOS. Occurs also on Windows in
|
||||
large popup menus that do not fit into the window. (issue #371; regression
|
||||
since FlatLaf 1.3)
|
||||
- OptionPane: Fixed `OptionPane.sameSizeButtons`, which did not work as expected
|
||||
when setting to `false`.
|
||||
- OptionPane: Fixed rendering of longer HTML text if it is passed as
|
||||
`StringBuilder`, `StringBuffer`, or any other object that returns HTML text in
|
||||
method `toString()`. (similar to issue #12)
|
||||
- ComboBox: Fixed popup border painting on HiDPI screens (e.g. at 150% scaling).
|
||||
- ComboBox: Fixed popup location if shown above of combo box (Java 8 only).
|
||||
- ComboBox (editable): Fixed wrong border of internal text field under special
|
||||
circumstances.
|
||||
- Spinner: Fixed painting of border corners on left side. (issue #382;
|
||||
regression since FlatLaf 1.4)
|
||||
- TableHeader: Do not show resize cursor for last column if resizing last column
|
||||
is not possible because auto resize mode of table is not off. (issue #332)
|
||||
- TableHeader: Fixed missing trailing vertical separator line if used in upper
|
||||
left corner of scroll pane. (issue #332)
|
||||
- TextField, FormattedTextField, PasswordField and ComboBox: Fixed alignment of
|
||||
placeholder text in right-to-left component orientation.
|
||||
- Slider: Fixed calculation of baseline, which was wrong under some
|
||||
circumstances.
|
||||
|
||||
|
||||
## 1.5
|
||||
|
||||
#### New features and improvements
|
||||
|
||||
- SwingX: Added search and clear icons to `JXSearchField`. (issue #359)
|
||||
|
||||
#### Fixed bugs
|
||||
|
||||
- Button and TextComponent: Do not apply minimum width/height if margins are
|
||||
set. (issue #364)
|
||||
- ComboBox and Spinner: Limit arrow button width if component has large
|
||||
preferred height. (issue #361)
|
||||
- FileChooser: Fixed missing (localized) texts when FlatLaf is loaded in special
|
||||
classloader (e.g. plugin system in Apache NetBeans).
|
||||
- InternalFrame: Limit internal frame bounds to parent bounds on resize. Also
|
||||
honor maximum size of internal frame. (issue #362)
|
||||
- Popup: Fixed incorrectly placed drop shadow for medium-weight popups in
|
||||
maximized windows. (issue #358)
|
||||
- Native window decorations (Windows 10 only):
|
||||
- Fixed occasional application crash in `flatlaf-windows.dll`. (issue #357)
|
||||
- When window is initially shown, fill background with window background color
|
||||
(instead of white), which avoids flickering in dark themes. (issue 339)
|
||||
- When resizing a window at the right/bottom edge, then first fill the new
|
||||
space with the window background color (instead of black) before the layout
|
||||
is updated.
|
||||
- When resizing a window at the left/top edge, then first fill the new space
|
||||
with the window background color (instead of garbage) before the layout is
|
||||
updated.
|
||||
|
||||
|
||||
## 1.4
|
||||
|
||||
#### New features and improvements
|
||||
|
||||
- TextField, FormattedTextField and PasswordField: Support adding extra padding.
|
||||
(set client property `JTextField.padding` to `Insets`).
|
||||
- PasswordField: UI delegate `FlatPasswordFieldUI` now extends `FlatTextFieldUI`
|
||||
(instead of `BasicPasswordFieldUI`) to avoid duplicate code and for easier
|
||||
extensibility.
|
||||
- Table and PopupFactory: Use `StackWalker` in Java 9+ for better performance.
|
||||
(issue #334)
|
||||
- ToolBar: Paint focus indicator for focused button in toolbar. (issue #346)
|
||||
- ToolBar: Support focusable buttons in toolbar (set UI value
|
||||
`ToolBar.focusableButtons` to `true`). (issue #346)
|
||||
|
||||
#### Fixed bugs
|
||||
|
||||
- ComboBox (editable) and Spinner: Increased size of internal text field to the
|
||||
component border so that it behaves like plain text field (mouse click to left
|
||||
of text now positions caret to first character instead of opening ComboBox
|
||||
popup; mouse cursor is now of type "text" within the whole component, except
|
||||
for arrow buttons). (issue #330)
|
||||
- ComboBox (not editable): Increased size of internal renderer pane to the
|
||||
component border so that it can paint within the whole component. Also
|
||||
increase combo box size if a custom renderer uses a border with insets that
|
||||
are larger than the default combo box padding (`2,6,2,6`).
|
||||
- Fixed component heights at `1.25x`, `1.75x` and `2.25x` scaling factors (Java
|
||||
8 only) so that Button, ComboBox, Spinner and TextField components (including
|
||||
subclasses) have same heights. This increases heights of Button and TextField
|
||||
components by:
|
||||
- `2px` at `1.75x` in **Light** and **Dark** themes
|
||||
- `2px` at `1.25x` and `2.25x` in **IntelliJ** and **Darcula** themes
|
||||
- OptionPane: Do not make child components, which are derived from `JPanel`,
|
||||
non-opaque. (issue #349)
|
||||
- OptionPane: Align wrapped lines to the right if component orientation is
|
||||
right-to-left. (issue #350)
|
||||
- PasswordField: Caps lock icon no longer painted over long text. (issue #172)
|
||||
- PasswordField: Paint caps lock icon on left side in right-to-left component
|
||||
orientation.
|
||||
- Window decorations: Window title bar width is no longer considered when
|
||||
calculating preferred/minimum width of window. (issue #351)
|
||||
|
||||
|
||||
## 1.3
|
||||
|
||||
#### New features and improvements
|
||||
|
||||
- TextComponents, ComboBox and Spinner: Support different background color when
|
||||
component is focused (use UI values `TextField.focusedBackground`,
|
||||
`PasswordField.focusedBackground`, `FormattedTextField.focusedBackground`,
|
||||
`TextArea.focusedBackground`, `TextPane.focusedBackground`,
|
||||
`EditorPane.focusedBackground`, `ComboBox.focusedBackground`,
|
||||
`ComboBox.buttonFocusedBackground`, `ComboBox.popupBackground` and
|
||||
`Spinner.focusedBackground`). (issue #335)
|
||||
|
||||
#### Fixed bugs
|
||||
|
||||
- Fixed white lines at bottom and right side of window (in dark themes on HiDPI
|
||||
screens with scaling enabled).
|
||||
- ScrollBar: Fixed left/top arrow icon location (if visible). (issue #329)
|
||||
- Spinner: Fixed up/down arrow icon location.
|
||||
- ToolTip: Fixed positioning of huge tooltips. (issue #333)
|
||||
|
||||
|
||||
## 1.2
|
||||
|
||||
#### New features and improvements
|
||||
|
||||
15
README.md
@@ -67,20 +67,23 @@ docs).
|
||||
Addons
|
||||
------
|
||||
|
||||
- [IntelliJ Themes Pack](flatlaf-intellij-themes)
|
||||
- [Extras](flatlaf-extras)
|
||||
- [SwingX](flatlaf-swingx)
|
||||
- [JIDE Common Layer](flatlaf-jide-oss)
|
||||
- [IntelliJ Themes Pack](flatlaf-intellij-themes) - bundles many popular
|
||||
open-source 3rd party themes
|
||||
- [Extras](flatlaf-extras) - SVG icon, tri-state check box, UI inspectors, and
|
||||
more
|
||||
- [SwingX](flatlaf-swingx) - support for SwingX components
|
||||
- [JIDE Common Layer](flatlaf-jide-oss) - support for JIDE Common Layer
|
||||
components
|
||||
|
||||
|
||||
Getting started
|
||||
---------------
|
||||
|
||||
To enable FlatLaf, add following code to your main method before you create any
|
||||
To use FlatLaf, add following code to your main method before you create any
|
||||
Swing component:
|
||||
|
||||
~~~java
|
||||
FlatLightLaf.install();
|
||||
FlatLightLaf.setup();
|
||||
|
||||
// create UI here...
|
||||
~~~
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
val releaseVersion = "1.2"
|
||||
val developmentVersion = "1.3-SNAPSHOT"
|
||||
val releaseVersion = "1.6.1"
|
||||
val developmentVersion = "2.0-SNAPSHOT"
|
||||
|
||||
version = if( java.lang.Boolean.getBoolean( "release" ) ) releaseVersion else developmentVersion
|
||||
|
||||
|
||||
@@ -21,6 +21,12 @@ plugins {
|
||||
`flatlaf-publish`
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testImplementation( "org.junit.jupiter:junit-jupiter-api:5.7.2" )
|
||||
testImplementation( "org.junit.jupiter:junit-jupiter-params" )
|
||||
testRuntimeOnly( "org.junit.jupiter:junit-jupiter-engine" )
|
||||
}
|
||||
|
||||
java {
|
||||
withSourcesJar()
|
||||
withJavadocJar()
|
||||
@@ -52,6 +58,11 @@ tasks {
|
||||
named<Jar>( "javadocJar" ) {
|
||||
archiveBaseName.set( "flatlaf" )
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
testLogging.exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
|
||||
}
|
||||
}
|
||||
|
||||
flatlafPublish {
|
||||
|
||||
@@ -733,6 +733,18 @@ public interface FlatClientProperties
|
||||
*/
|
||||
String PLACEHOLDER_TEXT = "JTextField.placeholderText";
|
||||
|
||||
/**
|
||||
* Specifies the padding of the text.
|
||||
* This changes the location and size of the text view within the component bounds,
|
||||
* but does not affect the size of the component.
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JTextField} (and subclasses)<br>
|
||||
* <strong>Value type</strong> {@link java.awt.Insets}
|
||||
*
|
||||
* @since 1.4
|
||||
*/
|
||||
String TEXT_FIELD_PADDING = "JTextField.padding";
|
||||
|
||||
//---- JToggleButton ------------------------------------------------------
|
||||
|
||||
/**
|
||||
|
||||
@@ -32,10 +32,14 @@ import java.beans.PropertyChangeListener;
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.Properties;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
@@ -63,9 +67,11 @@ import javax.swing.text.html.HTMLEditorKit;
|
||||
import com.formdev.flatlaf.ui.FlatNativeWindowBorder;
|
||||
import com.formdev.flatlaf.ui.FlatPopupFactory;
|
||||
import com.formdev.flatlaf.ui.FlatRootPaneUI;
|
||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
import com.formdev.flatlaf.util.GrayFilter;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
import com.formdev.flatlaf.util.MultiResolutionImageSupport;
|
||||
import com.formdev.flatlaf.util.StringUtils;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
@@ -92,6 +98,7 @@ public abstract class FlatLaf
|
||||
private MnemonicHandler mnemonicHandler;
|
||||
|
||||
private Consumer<UIDefaults> postInitialization;
|
||||
private List<Function<Object, Object>> uiDefaultsGetters;
|
||||
|
||||
/**
|
||||
* Sets the application look and feel to the given LaF
|
||||
@@ -350,14 +357,21 @@ public abstract class FlatLaf
|
||||
|
||||
@Override
|
||||
public UIDefaults getDefaults() {
|
||||
UIDefaults defaults = super.getDefaults();
|
||||
// use larger initial capacity to avoid resizing UI defaults hash table
|
||||
// (from 610 to 1221 to 2443 entries) and to save some memory
|
||||
UIDefaults defaults = new FlatUIDefaults( 1500, 0.75f );
|
||||
|
||||
// initialize basic defaults (see super.getDefaults())
|
||||
initClassDefaults( defaults );
|
||||
initSystemColorDefaults( defaults );
|
||||
initComponentDefaults( defaults );
|
||||
|
||||
// add flag that indicates whether the LaF is light or dark
|
||||
// (can be queried without using FlatLaf API)
|
||||
defaults.put( "laf.dark", isDark() );
|
||||
|
||||
// add resource bundle for localized texts
|
||||
defaults.addResourceBundle( "com.formdev.flatlaf.resources.Bundle" );
|
||||
// init resource bundle for localized texts
|
||||
initResourceBundle( defaults, "com.formdev.flatlaf.resources.Bundle" );
|
||||
|
||||
// initialize some defaults (for overriding) that are used in UI delegates,
|
||||
// but are not set in BasicLookAndFeel
|
||||
@@ -453,6 +467,45 @@ public abstract class FlatLaf
|
||||
return null;
|
||||
}
|
||||
|
||||
private void initResourceBundle( UIDefaults defaults, String bundleName ) {
|
||||
// add resource bundle for localized texts
|
||||
defaults.addResourceBundle( bundleName );
|
||||
|
||||
// Check whether Swing can not load the FlatLaf resource bundle,
|
||||
// which can happen in applications that use some plugin system
|
||||
// and load FlatLaf in a plugin that uses its own classloader.
|
||||
// (e.g. Apache NetBeans)
|
||||
if( defaults.get( "FileChooser.fileNameHeaderText" ) != null )
|
||||
return;
|
||||
|
||||
// load FlatLaf resource bundle and add content to defaults
|
||||
try {
|
||||
ResourceBundle bundle = ResourceBundle.getBundle( bundleName, defaults.getDefaultLocale() );
|
||||
|
||||
Enumeration<String> keys = bundle.getKeys();
|
||||
while( keys.hasMoreElements() ) {
|
||||
String key = keys.nextElement();
|
||||
String value = bundle.getString( key );
|
||||
|
||||
String baseKey = StringUtils.removeTrailing( key, ".textAndMnemonic" );
|
||||
if( baseKey != key ) {
|
||||
String text = value.replace( "&", "" );
|
||||
String mnemonic = null;
|
||||
int index = value.indexOf( '&' );
|
||||
if( index >= 0 )
|
||||
mnemonic = Integer.toString( Character.toUpperCase( value.charAt( index + 1 ) ) );
|
||||
|
||||
defaults.put( baseKey + "Text", text );
|
||||
if( mnemonic != null )
|
||||
defaults.put( baseKey + "Mnemonic", mnemonic );
|
||||
} else
|
||||
defaults.put( key, value );
|
||||
}
|
||||
} catch( MissingResourceException ex ) {
|
||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||
}
|
||||
}
|
||||
|
||||
private void initFonts( UIDefaults defaults ) {
|
||||
FontUIResource uiFont = null;
|
||||
|
||||
@@ -871,6 +924,139 @@ public abstract class FlatLaf
|
||||
return super.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a UI defaults getter function that is invoked before the standard getter.
|
||||
* This allows using different UI defaults for special purposes
|
||||
* (e.g. using multiple themes at the same time).
|
||||
* <p>
|
||||
* The key is passed as parameter to the function.
|
||||
* If the function returns {@code null}, then the next registered function is invoked.
|
||||
* If all registered functions return {@code null}, then the current look and feel is asked.
|
||||
* If the function returns {@link #NULL_VALUE}, then the UI value becomes {@code null}.
|
||||
*
|
||||
* @see #unregisterUIDefaultsGetter(Function)
|
||||
* @see #runWithUIDefaultsGetter(Function, Runnable)
|
||||
* @since 1.6
|
||||
*/
|
||||
public void registerUIDefaultsGetter( Function<Object, Object> uiDefaultsGetter ) {
|
||||
if( uiDefaultsGetters == null )
|
||||
uiDefaultsGetters = new ArrayList<>();
|
||||
|
||||
uiDefaultsGetters.remove( uiDefaultsGetter );
|
||||
uiDefaultsGetters.add( uiDefaultsGetter );
|
||||
|
||||
// disable shared UIs
|
||||
FlatUIUtils.setUseSharedUIs( false );
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters a UI defaults getter function that was invoked before the standard getter.
|
||||
*
|
||||
* @see #registerUIDefaultsGetter(Function)
|
||||
* @see #runWithUIDefaultsGetter(Function, Runnable)
|
||||
* @since 1.6
|
||||
*/
|
||||
public void unregisterUIDefaultsGetter( Function<Object, Object> uiDefaultsGetter ) {
|
||||
if( uiDefaultsGetters == null )
|
||||
return;
|
||||
|
||||
uiDefaultsGetters.remove( uiDefaultsGetter );
|
||||
|
||||
// enable shared UIs
|
||||
if( uiDefaultsGetters.isEmpty() )
|
||||
FlatUIUtils.setUseSharedUIs( true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a UI defaults getter function that is invoked before the standard getter,
|
||||
* runs the given runnable and unregisters the UI defaults getter function again.
|
||||
* This allows using different UI defaults for special purposes
|
||||
* (e.g. using multiple themes at the same time).
|
||||
* If the current look and feel is not FlatLaf, then the getter is ignored and
|
||||
* the given runnable invoked.
|
||||
* <p>
|
||||
* The key is passed as parameter to the function.
|
||||
* If the function returns {@code null}, then the next registered function is invoked.
|
||||
* If all registered functions return {@code null}, then the current look and feel is asked.
|
||||
* If the function returns {@link #NULL_VALUE}, then the UI value becomes {@code null}.
|
||||
* <p>
|
||||
* Example:
|
||||
* <pre>{@code
|
||||
* // create secondary theme
|
||||
* UIDefaults darkDefaults = new FlatDarkLaf().getDefaults();
|
||||
*
|
||||
* // create panel using secondary theme
|
||||
* FlatLaf.runWithUIDefaultsGetter( key -> {
|
||||
* Object value = darkDefaults.get( key );
|
||||
* return (value != null) ? value : FlatLaf.NULL_VALUE;
|
||||
* }, () -> {
|
||||
* // TODO create components that should use secondary theme here
|
||||
* } );
|
||||
* }</pre>
|
||||
*
|
||||
* @see #registerUIDefaultsGetter(Function)
|
||||
* @see #unregisterUIDefaultsGetter(Function)
|
||||
* @since 1.6
|
||||
*/
|
||||
public static void runWithUIDefaultsGetter( Function<Object, Object> uiDefaultsGetter, Runnable runnable ) {
|
||||
LookAndFeel laf = UIManager.getLookAndFeel();
|
||||
if( laf instanceof FlatLaf ) {
|
||||
((FlatLaf)laf).registerUIDefaultsGetter( uiDefaultsGetter );
|
||||
try {
|
||||
runnable.run();
|
||||
} finally {
|
||||
((FlatLaf)laf).unregisterUIDefaultsGetter( uiDefaultsGetter );
|
||||
}
|
||||
} else
|
||||
runnable.run();
|
||||
}
|
||||
|
||||
/**
|
||||
* Special value returned by functions used in {@link #runWithUIDefaultsGetter(Function, Runnable)}
|
||||
* or {@link #registerUIDefaultsGetter(Function)} to indicate that the UI value should
|
||||
* become {@code null}.
|
||||
*
|
||||
* @see #runWithUIDefaultsGetter(Function, Runnable)
|
||||
* @see #registerUIDefaultsGetter(Function)
|
||||
* @since 1.6
|
||||
*/
|
||||
public static final Object NULL_VALUE = new Object();
|
||||
|
||||
//---- class FlatUIDefaults -----------------------------------------------
|
||||
|
||||
private class FlatUIDefaults
|
||||
extends UIDefaults
|
||||
{
|
||||
FlatUIDefaults( int initialCapacity, float loadFactor ) {
|
||||
super( initialCapacity, loadFactor );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get( Object key ) {
|
||||
Object value = getValue( key );
|
||||
return (value != null) ? (value != NULL_VALUE ? value : null) : super.get( key );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get( Object key, Locale l ) {
|
||||
Object value = getValue( key );
|
||||
return (value != null) ? (value != NULL_VALUE ? value : null) : super.get( key, l );
|
||||
}
|
||||
|
||||
private Object getValue( Object key ) {
|
||||
if( uiDefaultsGetters == null )
|
||||
return null;
|
||||
|
||||
for( int i = uiDefaultsGetters.size() - 1; i >= 0; i-- ) {
|
||||
Object value = uiDefaultsGetters.get( i ).apply( key );
|
||||
if( value != null )
|
||||
return value;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
//---- class ActiveFont ---------------------------------------------------
|
||||
|
||||
private static class ActiveFont
|
||||
|
||||
@@ -128,7 +128,7 @@ class LinuxFontPolicy
|
||||
// find last word in family
|
||||
int index = family.lastIndexOf( ' ' );
|
||||
if( index < 0 )
|
||||
return createFont( "Dialog", style, size, dsize );;
|
||||
return createFont( "Dialog", style, size, dsize );
|
||||
|
||||
// check whether last work contains some font weight (e.g. Ultra-Bold or Heavy)
|
||||
String lastWord = family.substring( index + 1 ).toLowerCase();
|
||||
@@ -309,6 +309,9 @@ class LinuxFontPolicy
|
||||
* - running on JetBrains Runtime 11 or later and scaling is enabled in system Settings
|
||||
*/
|
||||
private static boolean isSystemScaling() {
|
||||
if( GraphicsEnvironment.isHeadless() )
|
||||
return true;
|
||||
|
||||
GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment()
|
||||
.getDefaultScreenDevice().getDefaultConfiguration();
|
||||
return UIScale.getSystemScaleFactor( gc ) > 1;
|
||||
|
||||
@@ -604,6 +604,13 @@ class UIDefaultsLoader
|
||||
case "fadeout": return parseColorHSLIncreaseDecrease( 3, false, params, resolver, reportError );
|
||||
case "fade": return parseColorFade( params, resolver, reportError );
|
||||
case "spin": return parseColorSpin( params, resolver, reportError );
|
||||
case "changeHue": return parseColorChange( 0, params, resolver, reportError );
|
||||
case "changeSaturation":return parseColorChange( 1, params, resolver, reportError );
|
||||
case "changeLightness": return parseColorChange( 2, params, resolver, reportError );
|
||||
case "changeAlpha": return parseColorChange( 3, params, resolver, reportError );
|
||||
case "mix": return parseColorMix( null, params, resolver, reportError );
|
||||
case "tint": return parseColorMix( "#fff", params, resolver, reportError );
|
||||
case "shade": return parseColorMix( "#000", params, resolver, reportError );
|
||||
}
|
||||
} finally {
|
||||
parseColorDepth--;
|
||||
@@ -753,6 +760,68 @@ class UIDefaultsLoader
|
||||
return parseFunctionBaseColor( colorStr, function, derived, resolver, reportError );
|
||||
}
|
||||
|
||||
/**
|
||||
* Syntax: changeHue(color,value[,options]) or
|
||||
* changeSaturation(color,value[,options]) or
|
||||
* changeLightness(color,value[,options]) or
|
||||
* changeAlpha(color,value[,options])
|
||||
* - color: a color (e.g. #f00) or a color function
|
||||
* - value: for hue: number of degrees; otherwise: percentage 0-100%
|
||||
* - options: [derived]
|
||||
*/
|
||||
private static Object parseColorChange( int hslIndex,
|
||||
List<String> params, Function<String, String> resolver, boolean reportError )
|
||||
{
|
||||
String colorStr = params.get( 0 );
|
||||
int value = (hslIndex == 0)
|
||||
? parseInteger( params.get( 1 ), true )
|
||||
: parsePercentage( params.get( 1 ) );
|
||||
boolean derived = false;
|
||||
|
||||
if( params.size() > 2 ) {
|
||||
String options = params.get( 2 );
|
||||
derived = options.contains( "derived" );
|
||||
}
|
||||
|
||||
// create function
|
||||
ColorFunction function = new ColorFunctions.HSLChange( hslIndex, value );
|
||||
|
||||
// parse base color, apply function and create derived color
|
||||
return parseFunctionBaseColor( colorStr, function, derived, resolver, reportError );
|
||||
}
|
||||
|
||||
/**
|
||||
* Syntax: mix(color1,color2[,weight]) or
|
||||
* tint(color[,weight]) or
|
||||
* shade(color[,weight])
|
||||
* - color1: a color (e.g. #f00) or a color function
|
||||
* - color2: a color (e.g. #f00) or a color function
|
||||
* - weight: the weight (in range 0-100%) to mix the two colors
|
||||
* larger weight uses more of first color, smaller weight more of second color
|
||||
*/
|
||||
private static Object parseColorMix( String color1Str, List<String> params, Function<String, String> resolver, boolean reportError ) {
|
||||
int i = 0;
|
||||
if( color1Str == null )
|
||||
color1Str = params.get( i++ );
|
||||
String color2Str = params.get( i++ );
|
||||
int weight = 50;
|
||||
|
||||
if( params.size() > i )
|
||||
weight = parsePercentage( params.get( i++ ) );
|
||||
|
||||
// parse second color
|
||||
String resolvedColor2Str = resolver.apply( color2Str );
|
||||
ColorUIResource color2 = (ColorUIResource) parseColorOrFunction( resolvedColor2Str, resolver, reportError );
|
||||
if( color2 == null )
|
||||
return null;
|
||||
|
||||
// create function
|
||||
ColorFunction function = new ColorFunctions.Mix( color2, weight );
|
||||
|
||||
// parse first color, apply function and create mixed color
|
||||
return parseFunctionBaseColor( color1Str, function, false, resolver, reportError );
|
||||
}
|
||||
|
||||
private static Object parseFunctionBaseColor( String colorStr, ColorFunction function,
|
||||
boolean derived, Function<String, String> resolver, boolean reportError )
|
||||
{
|
||||
|
||||
@@ -44,7 +44,7 @@ public class FlatCapsLockIcon
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<rect width="16" height="16" fill="#6E6E6E" rx="3"/>
|
||||
<rect width="6" height="2" x="5" y="12" fill="#FFF"/>
|
||||
<rect width="6" height="2" x="5" y="11.5" fill="#FFF"/>
|
||||
<path fill="#FFF" d="M2,8 L8,2 L14,8 L11,8 L11,10 L5,10 L5,8 L2,8 Z"/>
|
||||
</g>
|
||||
</svg>
|
||||
@@ -52,7 +52,7 @@ public class FlatCapsLockIcon
|
||||
|
||||
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
|
||||
path.append( new RoundRectangle2D.Float( 0, 0, 16, 16, 6, 6 ), false );
|
||||
path.append( new Rectangle2D.Float( 5, 12, 6, 2 ), false );
|
||||
path.append( new Rectangle2D.Float( 5, 11.5f, 6, 2 ), false );
|
||||
path.append( FlatUIUtils.createPath( 2,8, 8,2, 14,8, 11,8, 11,10, 5,10, 5,8 ), false );
|
||||
g.fill( path );
|
||||
}
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2021 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.icons;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.Ellipse2D;
|
||||
import java.awt.geom.Line2D;
|
||||
import java.awt.geom.Path2D;
|
||||
import javax.swing.AbstractButton;
|
||||
import javax.swing.ButtonModel;
|
||||
import javax.swing.UIManager;
|
||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
|
||||
/**
|
||||
* "clear" icon for search fields.
|
||||
*
|
||||
* @uiDefault SearchField.clearIconColor Color
|
||||
* @uiDefault SearchField.clearIconHoverColor Color
|
||||
* @uiDefault SearchField.clearIconPressedColor Color
|
||||
*
|
||||
* @author Karl Tauber
|
||||
* @since 1.5
|
||||
*/
|
||||
public class FlatClearIcon
|
||||
extends FlatAbstractIcon
|
||||
{
|
||||
protected Color clearIconColor = UIManager.getColor( "SearchField.clearIconColor" );
|
||||
protected Color clearIconHoverColor = UIManager.getColor( "SearchField.clearIconHoverColor" );
|
||||
protected Color clearIconPressedColor = UIManager.getColor( "SearchField.clearIconPressedColor" );
|
||||
|
||||
public FlatClearIcon() {
|
||||
super( 16, 16, null );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintIcon( Component c, Graphics2D g ) {
|
||||
if( c instanceof AbstractButton ) {
|
||||
ButtonModel model = ((AbstractButton)c).getModel();
|
||||
if( model.isPressed() || model.isRollover() ) {
|
||||
/*
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<path fill="#7F8B91" fill-opacity=".5" fill-rule="evenodd" d="M8,1.75 C11.4517797,1.75 14.25,4.54822031 14.25,8 C14.25,11.4517797 11.4517797,14.25 8,14.25 C4.54822031,14.25 1.75,11.4517797 1.75,8 C1.75,4.54822031 4.54822031,1.75 8,1.75 Z M10.5,4.5 L8,7 L5.5,4.5 L4.5,5.5 L7,8 L4.5,10.5 L5.5,11.5 L8,9 L10.5,11.5 L11.5,10.5 L9,8 L11.5,5.5 L10.5,4.5 Z"/>
|
||||
</svg>
|
||||
*/
|
||||
|
||||
// paint filled circle with cross
|
||||
g.setColor( model.isPressed() ? clearIconPressedColor : clearIconHoverColor );
|
||||
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
|
||||
path.append( new Ellipse2D.Float( 1.75f, 1.75f, 12.5f, 12.5f ), false );
|
||||
path.append( FlatUIUtils.createPath( 4.5,5.5, 5.5,4.5, 8,7, 10.5,4.5, 11.5,5.5, 9,8, 11.5,10.5, 10.5,11.5, 8,9, 5.5,11.5, 4.5,10.5, 7,8 ), false );
|
||||
g.fill( path );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<path fill="none" stroke="#7F8B91" stroke-linecap="square" stroke-opacity=".5" d="M5,5 L11,11 M5,11 L11,5"/>
|
||||
</svg>
|
||||
*/
|
||||
|
||||
// paint cross
|
||||
g.setColor( clearIconColor );
|
||||
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
|
||||
path.append( new Line2D.Float( 5,5, 11,11 ), false );
|
||||
path.append( new Line2D.Float( 5,11, 11,5 ), false );
|
||||
g.draw( path );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2021 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.icons;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.Area;
|
||||
import java.awt.geom.Ellipse2D;
|
||||
import javax.swing.UIManager;
|
||||
import com.formdev.flatlaf.ui.FlatButtonUI;
|
||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
|
||||
/**
|
||||
* "search" icon for search fields.
|
||||
*
|
||||
* @uiDefault SearchField.searchIconColor Color
|
||||
* @uiDefault SearchField.searchIconHoverColor Color
|
||||
* @uiDefault SearchField.searchIconPressedColor Color
|
||||
*
|
||||
* @author Karl Tauber
|
||||
* @since 1.5
|
||||
*/
|
||||
public class FlatSearchIcon
|
||||
extends FlatAbstractIcon
|
||||
{
|
||||
protected Color searchIconColor = UIManager.getColor( "SearchField.searchIconColor" );
|
||||
protected Color searchIconHoverColor = UIManager.getColor( "SearchField.searchIconHoverColor" );
|
||||
protected Color searchIconPressedColor = UIManager.getColor( "SearchField.searchIconPressedColor" );
|
||||
|
||||
public FlatSearchIcon() {
|
||||
super( 16, 16, null );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintIcon( Component c, Graphics2D g ) {
|
||||
/*
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<g fill="none" fill-opacity=".9" fill-rule="evenodd">
|
||||
<polygon fill="#7F8B91" points="10.813 9.75 14 12.938 12.938 14 9.75 10.813"/>
|
||||
<path fill="#7F8B91" d="M7,2 C9.76142375,2 12,4.23857625 12,7 C12,9.76142375 9.76142375,12 7,12 C4.23857625,12 2,9.76142375 2,7 C2,4.23857625 4.23857625,2 7,2 Z M7,3 C4.790861,3 3,4.790861 3,7 C3,9.209139 4.790861,11 7,11 C9.209139,11 11,9.209139 11,7 C11,4.790861 9.209139,3 7,3 Z"/>
|
||||
</g>
|
||||
</svg>
|
||||
*/
|
||||
|
||||
g.setColor( FlatButtonUI.buttonStateColor( c, searchIconColor, searchIconColor,
|
||||
null, searchIconHoverColor, searchIconPressedColor ) );
|
||||
|
||||
// paint magnifier
|
||||
Area area = new Area( new Ellipse2D.Float( 2, 2, 10, 10 ) );
|
||||
area.subtract( new Area( new Ellipse2D.Float( 3, 3, 8, 8 ) ) );
|
||||
area.add( new Area( FlatUIUtils.createPath( 10.813,9.75, 14,12.938, 12.938,14, 9.75,10.813 ) ) );
|
||||
g.fill( area );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2021 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.icons;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics2D;
|
||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
|
||||
/**
|
||||
* "search with history" icon for search fields.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
* @since 1.5
|
||||
*/
|
||||
public class FlatSearchWithHistoryIcon
|
||||
extends FlatSearchIcon
|
||||
{
|
||||
public FlatSearchWithHistoryIcon() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintIcon( Component c, Graphics2D g ) {
|
||||
/*
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<g fill="none" fill-opacity=".9" fill-rule="evenodd">
|
||||
<polygon fill="#7F8B91" points="8.813 9.75 12 12.938 10.938 14 7.75 10.813"/>
|
||||
<path fill="#7F8B91" d="M5,2 C7.76142375,2 10,4.23857625 10,7 C10,9.76142375 7.76142375,12 5,12 C2.23857625,12 0,9.76142375 0,7 C0,4.23857625 2.23857625,2 5,2 Z M5,3 C2.790861,3 1,4.790861 1,7 C1,9.209139 2.790861,11 5,11 C7.209139,11 9,9.209139 9,7 C9,4.790861 7.209139,3 5,3 Z"/>
|
||||
<polygon fill="#7F8B91" points="11 7 16 7 13.5 10"/>
|
||||
</g>
|
||||
</svg>
|
||||
*/
|
||||
|
||||
// paint magnifier
|
||||
g.translate( -2, 0 );
|
||||
super.paintIcon( c, g );
|
||||
g.translate( 2, 0 );
|
||||
|
||||
// paint history arrow
|
||||
g.fill( FlatUIUtils.createPath( 11,7, 16,7, 13.5,10 ) );
|
||||
}
|
||||
}
|
||||
@@ -48,8 +48,8 @@ public class FlatArrowButton
|
||||
protected final Color pressedBackground;
|
||||
|
||||
private int arrowWidth = DEFAULT_ARROW_WIDTH;
|
||||
private int xOffset = 0;
|
||||
private int yOffset = 0;
|
||||
private float xOffset = 0;
|
||||
private float yOffset = 0;
|
||||
|
||||
private boolean hover;
|
||||
private boolean pressed;
|
||||
@@ -117,19 +117,19 @@ public class FlatArrowButton
|
||||
return pressed;
|
||||
}
|
||||
|
||||
public int getXOffset() {
|
||||
public float getXOffset() {
|
||||
return xOffset;
|
||||
}
|
||||
|
||||
public void setXOffset( int xOffset ) {
|
||||
public void setXOffset( float xOffset ) {
|
||||
this.xOffset = xOffset;
|
||||
}
|
||||
|
||||
public int getYOffset() {
|
||||
public float getYOffset() {
|
||||
return yOffset;
|
||||
}
|
||||
|
||||
public void setYOffset( int yOffset ) {
|
||||
public void setYOffset( float yOffset ) {
|
||||
this.yOffset = yOffset;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,17 +22,12 @@ import java.awt.Component;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Insets;
|
||||
import java.awt.KeyboardFocusManager;
|
||||
import java.awt.Paint;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JSpinner;
|
||||
import javax.swing.JTable;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.JTree;
|
||||
import javax.swing.JViewport;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.basic.BasicBorders;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
@@ -50,6 +45,7 @@ import com.formdev.flatlaf.util.DerivedColor;
|
||||
*
|
||||
* @uiDefault Component.focusWidth int
|
||||
* @uiDefault Component.innerFocusWidth int or float
|
||||
* @uiDefault Component.innerOutlineWidth int or float
|
||||
* @uiDefault Component.focusColor Color
|
||||
* @uiDefault Component.borderColor Color
|
||||
* @uiDefault Component.disabledBorderColor Color
|
||||
@@ -164,37 +160,13 @@ public class FlatBorder
|
||||
}
|
||||
|
||||
protected boolean isFocused( Component c ) {
|
||||
if( c instanceof JScrollPane ) {
|
||||
JViewport viewport = ((JScrollPane)c).getViewport();
|
||||
Component view = (viewport != null) ? viewport.getView() : null;
|
||||
if( view != null ) {
|
||||
if( FlatUIUtils.isPermanentFocusOwner( view ) )
|
||||
return true;
|
||||
|
||||
if( (view instanceof JTable && ((JTable)view).isEditing()) ||
|
||||
(view instanceof JTree && ((JTree)view).isEditing()) )
|
||||
{
|
||||
Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
|
||||
if( focusOwner != null )
|
||||
return SwingUtilities.isDescendingFrom( focusOwner, view );
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} else if( c instanceof JComboBox && ((JComboBox<?>)c).isEditable() ) {
|
||||
Component editorComponent = ((JComboBox<?>)c).getEditor().getEditorComponent();
|
||||
return (editorComponent != null) ? FlatUIUtils.isPermanentFocusOwner( editorComponent ) : false;
|
||||
} else if( c instanceof JSpinner ) {
|
||||
if( FlatUIUtils.isPermanentFocusOwner( c ) )
|
||||
return true;
|
||||
|
||||
JComponent editor = ((JSpinner)c).getEditor();
|
||||
if( editor instanceof JSpinner.DefaultEditor ) {
|
||||
JTextField textField = ((JSpinner.DefaultEditor)editor).getTextField();
|
||||
if( textField != null )
|
||||
return FlatUIUtils.isPermanentFocusOwner( textField );
|
||||
}
|
||||
return false;
|
||||
} else
|
||||
if( c instanceof JScrollPane )
|
||||
return FlatScrollPaneUI.isPermanentFocusOwner( (JScrollPane) c );
|
||||
else if( c instanceof JComboBox )
|
||||
return FlatComboBoxUI.isPermanentFocusOwner( (JComboBox<?>) c );
|
||||
else if( c instanceof JSpinner )
|
||||
return FlatSpinnerUI.isPermanentFocusOwner( (JSpinner) c );
|
||||
else
|
||||
return FlatUIUtils.isPermanentFocusOwner( c );
|
||||
}
|
||||
|
||||
@@ -205,13 +177,14 @@ public class FlatBorder
|
||||
@Override
|
||||
public Insets getBorderInsets( Component c, Insets insets ) {
|
||||
float focusWidth = scale( (float) getFocusWidth( c ) );
|
||||
float ow = focusWidth + scale( (float) getLineWidth( c ) );
|
||||
int ow = Math.round( focusWidth + scale( (float) getLineWidth( c ) ) );
|
||||
|
||||
insets = super.getBorderInsets( c, insets );
|
||||
insets.top = Math.round( scale( (float) insets.top ) + ow );
|
||||
insets.left = Math.round( scale( (float) insets.left ) + ow );
|
||||
insets.bottom = Math.round( scale( (float) insets.bottom ) + ow );
|
||||
insets.right = Math.round( scale( (float) insets.right ) + ow );
|
||||
|
||||
insets.top = scale( insets.top ) + ow;
|
||||
insets.left = scale( insets.left ) + ow;
|
||||
insets.bottom = scale( insets.bottom ) + ow;
|
||||
insets.right = scale( insets.right ) + ow;
|
||||
|
||||
if( isCellEditor( c ) ) {
|
||||
// remove top and bottom insets if used as cell editor
|
||||
|
||||
@@ -20,6 +20,7 @@ import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.GradientPaint;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Paint;
|
||||
import javax.swing.AbstractButton;
|
||||
@@ -42,11 +43,13 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
* @uiDefault Button.default.hoverBorderColor Color optional
|
||||
* @uiDefault Button.default.focusedBorderColor Color
|
||||
* @uiDefault Button.default.focusColor Color
|
||||
* @uiDefault Button.toolbar.focusColor Color optional; defaults to Component.focusColor
|
||||
* @uiDefault Button.borderWidth int
|
||||
* @uiDefault Button.default.borderWidth int
|
||||
* @uiDefault Button.innerFocusWidth int or float optional; defaults to Component.innerFocusWidth
|
||||
* @uiDefault Button.toolbar.margin Insets
|
||||
* @uiDefault Button.toolbar.spacingInsets Insets
|
||||
* @uiDefault Button.toolbar.focusWidth int or float optional; default is 1
|
||||
* @uiDefault Button.arc int
|
||||
*
|
||||
* @author Karl Tauber
|
||||
@@ -64,11 +67,15 @@ public class FlatButtonBorder
|
||||
protected final Color defaultHoverBorderColor = UIManager.getColor( "Button.default.hoverBorderColor" );
|
||||
protected final Color defaultFocusedBorderColor = UIManager.getColor( "Button.default.focusedBorderColor" );
|
||||
protected final Color defaultFocusColor = UIManager.getColor( "Button.default.focusColor" );
|
||||
/** @since 1.4 */
|
||||
protected final Color toolbarFocusColor = UIManager.getColor( "Button.toolbar.focusColor" );
|
||||
protected final int borderWidth = UIManager.getInt( "Button.borderWidth" );
|
||||
protected final int defaultBorderWidth = UIManager.getInt( "Button.default.borderWidth" );
|
||||
protected final float buttonInnerFocusWidth = FlatUIUtils.getUIFloat( "Button.innerFocusWidth", innerFocusWidth );
|
||||
protected final Insets toolbarMargin = UIManager.getInsets( "Button.toolbar.margin" );
|
||||
protected final Insets toolbarSpacingInsets = UIManager.getInsets( "Button.toolbar.spacingInsets" );
|
||||
/** @since 1.4 */
|
||||
protected final float toolbarFocusWidth = FlatUIUtils.getUIFloat( "Button.toolbar.focusWidth", 1.5f );
|
||||
protected final int arc = UIManager.getInt( "Button.arc" );
|
||||
|
||||
@Override
|
||||
@@ -79,11 +86,41 @@ public class FlatButtonBorder
|
||||
!FlatButtonUI.isHelpButton( c ) &&
|
||||
!FlatToggleButtonUI.isTabButton( c ) )
|
||||
super.paintBorder( c, g, x, y, width, height );
|
||||
else if( FlatButtonUI.isToolBarButton( c ) && isFocused( c ) )
|
||||
paintToolBarFocus( c, g, x, y, width, height );
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.4
|
||||
*/
|
||||
protected void paintToolBarFocus( Component c, Graphics g, int x, int y, int width, int height ) {
|
||||
Graphics2D g2 = (Graphics2D) g.create();
|
||||
try {
|
||||
FlatUIUtils.setRenderingHints( g2 );
|
||||
|
||||
float focusWidth = UIScale.scale( toolbarFocusWidth );
|
||||
float arc = UIScale.scale( (float) getArc( c ) );
|
||||
Color outlineColor = getOutlineColor( c );
|
||||
|
||||
Insets spacing = UIScale.scale( toolbarSpacingInsets );
|
||||
x += spacing.left;
|
||||
y += spacing.top;
|
||||
width -= spacing.left + spacing.right;
|
||||
height -= spacing.top + spacing.bottom;
|
||||
|
||||
g2.setColor( (outlineColor != null) ? outlineColor : getFocusColor( c ) );
|
||||
// not using paintComponentOuterBorder() here because its round edges look too "thick"
|
||||
FlatUIUtils.paintComponentBorder( g2, x, y, width, height, 0, focusWidth, arc );
|
||||
} finally {
|
||||
g2.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Color getFocusColor( Component c ) {
|
||||
return FlatButtonUI.isDefaultButton( c ) ? defaultFocusColor : super.getFocusColor( c );
|
||||
return (toolbarFocusColor != null && FlatButtonUI.isToolBarButton( c ))
|
||||
? toolbarFocusColor
|
||||
: (FlatButtonUI.isDefaultButton( c ) ? defaultFocusColor : super.getFocusColor( c ));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -30,6 +30,7 @@ import java.awt.Insets;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.geom.RoundRectangle2D;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.util.Objects;
|
||||
import javax.swing.AbstractButton;
|
||||
import javax.swing.ButtonModel;
|
||||
import javax.swing.Icon;
|
||||
@@ -129,6 +130,7 @@ public class FlatButtonUI
|
||||
protected Color toolbarSelectedBackground;
|
||||
|
||||
private Icon helpButtonIcon;
|
||||
private Insets defaultMargin;
|
||||
|
||||
private boolean defaults_initialized = false;
|
||||
|
||||
@@ -184,6 +186,7 @@ public class FlatButtonUI
|
||||
toolbarSelectedBackground = UIManager.getColor( prefix + "toolbar.selectedBackground" );
|
||||
|
||||
helpButtonIcon = UIManager.getIcon( "HelpButton.icon" );
|
||||
defaultMargin = UIManager.getInsets( prefix + "margin" );
|
||||
|
||||
defaults_initialized = true;
|
||||
}
|
||||
@@ -499,16 +502,23 @@ public class FlatButtonUI
|
||||
} else if( isIconOnlyOrSingleCharacter && ((AbstractButton)c).getIcon() == null ) {
|
||||
// make single-character-no-icon button square (increase width)
|
||||
prefSize.width = Math.max( prefSize.width, prefSize.height );
|
||||
} else if( !isIconOnlyOrSingleCharacter && !isToolBarButton( c ) && c.getBorder() instanceof FlatButtonBorder ) {
|
||||
} else if( !isIconOnlyOrSingleCharacter && !isToolBarButton( c ) &&
|
||||
c.getBorder() instanceof FlatButtonBorder && hasDefaultMargins( c ) )
|
||||
{
|
||||
// apply minimum width/height
|
||||
float focusWidth = FlatUIUtils.getBorderFocusWidth( c );
|
||||
prefSize.width = Math.max( prefSize.width, scale( FlatUIUtils.minimumWidth( c, minimumWidth ) ) + Math.round( focusWidth * 2 ) );
|
||||
prefSize.height = Math.max( prefSize.height, scale( FlatUIUtils.minimumHeight( c, 0 ) ) + Math.round( focusWidth * 2 ) );
|
||||
int fw = Math.round( FlatUIUtils.getBorderFocusWidth( c ) * 2 );
|
||||
prefSize.width = Math.max( prefSize.width, scale( FlatUIUtils.minimumWidth( c, minimumWidth ) ) + fw );
|
||||
prefSize.height = Math.max( prefSize.height, scale( FlatUIUtils.minimumHeight( c, 0 ) ) + fw );
|
||||
}
|
||||
|
||||
return prefSize;
|
||||
}
|
||||
|
||||
private boolean hasDefaultMargins( JComponent c ) {
|
||||
Insets margin = ((AbstractButton)c).getMargin();
|
||||
return margin instanceof UIResource && Objects.equals( margin, defaultMargin );
|
||||
}
|
||||
|
||||
//---- class FlatButtonListener -------------------------------------------
|
||||
|
||||
protected class FlatButtonListener
|
||||
|
||||
@@ -18,10 +18,13 @@ package com.formdev.flatlaf.ui;
|
||||
|
||||
import static com.formdev.flatlaf.FlatClientProperties.*;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.MouseEvent;
|
||||
import javax.swing.JFormattedTextField;
|
||||
import javax.swing.plaf.UIResource;
|
||||
import javax.swing.text.BadLocationException;
|
||||
import javax.swing.text.DefaultCaret;
|
||||
import javax.swing.text.Document;
|
||||
import javax.swing.text.JTextComponent;
|
||||
@@ -61,6 +64,19 @@ public class FlatCaret
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void adjustVisibility( Rectangle nloc ) {
|
||||
JTextComponent c = getComponent();
|
||||
if( c != null && c.getUI() instanceof FlatTextFieldUI ) {
|
||||
Insets padding = ((FlatTextFieldUI)c.getUI()).getPadding();
|
||||
if( padding != null ) {
|
||||
nloc.x -= padding.left;
|
||||
nloc.y -= padding.top;
|
||||
}
|
||||
}
|
||||
super.adjustVisibility( nloc );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void focusGained( FocusEvent e ) {
|
||||
if( !wasTemporaryLost && (!isMousePressed || selectAllOnMouseClick) )
|
||||
@@ -127,4 +143,23 @@ public class FlatCaret
|
||||
moveDot( doc.getLength() );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.4
|
||||
*/
|
||||
public void scrollCaretToVisible() {
|
||||
JTextComponent c = getComponent();
|
||||
if( c == null || c.getUI() == null )
|
||||
return;
|
||||
|
||||
try {
|
||||
Rectangle loc = c.getUI().modelToView( c, getDot(), getDotBias() );
|
||||
if( loc != null ) {
|
||||
adjustVisibility( loc );
|
||||
damage( loc );
|
||||
}
|
||||
} catch( BadLocationException ex ) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,11 +17,13 @@
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import static com.formdev.flatlaf.util.UIScale.scale;
|
||||
import static com.formdev.flatlaf.util.UIScale.unscale;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.ComponentOrientation;
|
||||
import java.awt.Container;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.FontMetrics;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
@@ -39,11 +41,9 @@ import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.lang.ref.WeakReference;
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.CellRendererPane;
|
||||
import javax.swing.ComboBoxEditor;
|
||||
import javax.swing.DefaultListCellRenderer;
|
||||
import javax.swing.InputMap;
|
||||
import javax.swing.JButton;
|
||||
@@ -61,13 +61,13 @@ import javax.swing.UIManager;
|
||||
import javax.swing.border.AbstractBorder;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.UIResource;
|
||||
import javax.swing.plaf.basic.BasicComboBoxUI;
|
||||
import javax.swing.plaf.basic.BasicComboPopup;
|
||||
import javax.swing.plaf.basic.ComboPopup;
|
||||
import javax.swing.text.JTextComponent;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JComboBox}.
|
||||
@@ -92,14 +92,17 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
* @uiDefault Component.borderColor Color
|
||||
* @uiDefault Component.disabledBorderColor Color
|
||||
* @uiDefault ComboBox.editableBackground Color optional; defaults to ComboBox.background
|
||||
* @uiDefault ComboBox.focusedBackground Color optional
|
||||
* @uiDefault ComboBox.disabledBackground Color
|
||||
* @uiDefault ComboBox.disabledForeground Color
|
||||
* @uiDefault ComboBox.buttonBackground Color
|
||||
* @uiDefault ComboBox.buttonEditableBackground Color
|
||||
* @uiDefault ComboBox.buttonFocusedBackground Color optional; defaults to ComboBox.focusedBackground
|
||||
* @uiDefault ComboBox.buttonArrowColor Color
|
||||
* @uiDefault ComboBox.buttonDisabledArrowColor Color
|
||||
* @uiDefault ComboBox.buttonHoverArrowColor Color
|
||||
* @uiDefault ComboBox.buttonPressedArrowColor Color
|
||||
* @uiDefault ComboBox.popupBackground Color optional
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
@@ -115,21 +118,25 @@ public class FlatComboBoxUI
|
||||
protected Color disabledBorderColor;
|
||||
|
||||
protected Color editableBackground;
|
||||
protected Color focusedBackground;
|
||||
protected Color disabledBackground;
|
||||
protected Color disabledForeground;
|
||||
|
||||
protected Color buttonBackground;
|
||||
protected Color buttonEditableBackground;
|
||||
protected Color buttonFocusedBackground;
|
||||
protected Color buttonArrowColor;
|
||||
protected Color buttonDisabledArrowColor;
|
||||
protected Color buttonHoverArrowColor;
|
||||
protected Color buttonPressedArrowColor;
|
||||
|
||||
protected Color popupBackground;
|
||||
|
||||
private MouseListener hoverListener;
|
||||
protected boolean hover;
|
||||
protected boolean pressed;
|
||||
|
||||
private WeakReference<Component> lastRendererComponent;
|
||||
private CellPaddingBorder paddingBorder;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatComboBoxUI();
|
||||
@@ -195,23 +202,26 @@ public class FlatComboBoxUI
|
||||
disabledBorderColor = UIManager.getColor( "Component.disabledBorderColor" );
|
||||
|
||||
editableBackground = UIManager.getColor( "ComboBox.editableBackground" );
|
||||
focusedBackground = UIManager.getColor( "ComboBox.focusedBackground" );
|
||||
disabledBackground = UIManager.getColor( "ComboBox.disabledBackground" );
|
||||
disabledForeground = UIManager.getColor( "ComboBox.disabledForeground" );
|
||||
|
||||
buttonBackground = UIManager.getColor( "ComboBox.buttonBackground" );
|
||||
buttonFocusedBackground = UIManager.getColor( "ComboBox.buttonFocusedBackground" );
|
||||
buttonEditableBackground = UIManager.getColor( "ComboBox.buttonEditableBackground" );
|
||||
buttonArrowColor = UIManager.getColor( "ComboBox.buttonArrowColor" );
|
||||
buttonDisabledArrowColor = UIManager.getColor( "ComboBox.buttonDisabledArrowColor" );
|
||||
buttonHoverArrowColor = UIManager.getColor( "ComboBox.buttonHoverArrowColor" );
|
||||
buttonPressedArrowColor = UIManager.getColor( "ComboBox.buttonPressedArrowColor" );
|
||||
|
||||
popupBackground = UIManager.getColor( "ComboBox.popupBackground" );
|
||||
|
||||
// set maximumRowCount
|
||||
int maximumRowCount = UIManager.getInt( "ComboBox.maximumRowCount" );
|
||||
if( maximumRowCount > 0 && maximumRowCount != 8 && comboBox.getMaximumRowCount() == 8 )
|
||||
comboBox.setMaximumRowCount( maximumRowCount );
|
||||
|
||||
// scale
|
||||
padding = UIScale.scale( padding );
|
||||
paddingBorder = new CellPaddingBorder( padding );
|
||||
|
||||
MigLayoutVisualPadding.install( comboBox );
|
||||
}
|
||||
@@ -224,16 +234,22 @@ public class FlatComboBoxUI
|
||||
disabledBorderColor = null;
|
||||
|
||||
editableBackground = null;
|
||||
focusedBackground = null;
|
||||
disabledBackground = null;
|
||||
disabledForeground = null;
|
||||
|
||||
buttonBackground = null;
|
||||
buttonEditableBackground = null;
|
||||
buttonFocusedBackground = null;
|
||||
buttonArrowColor = null;
|
||||
buttonDisabledArrowColor = null;
|
||||
buttonHoverArrowColor = null;
|
||||
buttonPressedArrowColor = null;
|
||||
|
||||
popupBackground = null;
|
||||
|
||||
paddingBorder.uninstall();
|
||||
|
||||
MigLayoutVisualPadding.uninstall( comboBox );
|
||||
}
|
||||
|
||||
@@ -245,8 +261,12 @@ public class FlatComboBoxUI
|
||||
super.layoutContainer( parent );
|
||||
|
||||
if( arrowButton != null ) {
|
||||
// limit button width to height of a raw combobox (without insets)
|
||||
FontMetrics fm = comboBox.getFontMetrics( comboBox.getFont() );
|
||||
int maxButtonWidth = fm.getHeight() + scale( padding.top ) + scale( padding.bottom );
|
||||
|
||||
Insets insets = getInsets();
|
||||
int buttonWidth = parent.getPreferredSize().height - insets.top - insets.bottom;
|
||||
int buttonWidth = Math.min( parent.getPreferredSize().height - insets.top - insets.bottom, maxButtonWidth );
|
||||
if( buttonWidth != arrowButton.getWidth() ) {
|
||||
// set width of arrow button to preferred height of combobox
|
||||
int xOffset = comboBox.getComponentOrientation().isLeftToRight()
|
||||
@@ -260,11 +280,6 @@ public class FlatComboBoxUI
|
||||
editor.setBounds( rectangleForCurrentValue() );
|
||||
}
|
||||
}
|
||||
|
||||
if( editor != null && padding != null ) {
|
||||
// fix editor bounds by subtracting padding
|
||||
editor.setBounds( FlatUIUtils.subtractInsets( editor.getBounds(), padding ) );
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -322,14 +337,16 @@ public class FlatComboBoxUI
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ComboBoxEditor createEditor() {
|
||||
ComboBoxEditor comboBoxEditor = super.createEditor();
|
||||
protected void configureEditor() {
|
||||
super.configureEditor();
|
||||
|
||||
Component editor = comboBoxEditor.getEditorComponent();
|
||||
if( editor instanceof JTextField ) {
|
||||
JTextField textField = (JTextField) editor;
|
||||
textField.setColumns( editorColumns );
|
||||
|
||||
// remove default text field border from editor
|
||||
Border border = textField.getBorder();
|
||||
if( border == null || border instanceof UIResource ) {
|
||||
// assign a non-null and non-javax.swing.plaf.UIResource border to the text field,
|
||||
// otherwise it is replaced with default text field border when switching LaF
|
||||
// because javax.swing.plaf.basic.BasicComboBoxEditor.BorderlessTextField.setBorder()
|
||||
@@ -337,24 +354,15 @@ public class FlatComboBoxUI
|
||||
// instead of "border instanceof javax.swing.plaf.UIResource"
|
||||
textField.setBorder( BorderFactory.createEmptyBorder() );
|
||||
}
|
||||
|
||||
return comboBoxEditor;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureEditor() {
|
||||
super.configureEditor();
|
||||
|
||||
// remove default text field border from editor
|
||||
if( editor instanceof JTextField && ((JTextField)editor).getBorder() instanceof FlatTextBorder )
|
||||
((JTextField)editor).setBorder( BorderFactory.createEmptyBorder() );
|
||||
|
||||
// explicitly make non-opaque
|
||||
if( editor instanceof JComponent )
|
||||
((JComponent)editor).setOpaque( false );
|
||||
|
||||
editor.applyComponentOrientation( comboBox.getComponentOrientation() );
|
||||
|
||||
updateEditorPadding();
|
||||
updateEditorColors();
|
||||
|
||||
// macOS
|
||||
@@ -371,6 +379,25 @@ public class FlatComboBoxUI
|
||||
}
|
||||
}
|
||||
|
||||
private void updateEditorPadding() {
|
||||
if( !(editor instanceof JTextField) )
|
||||
return;
|
||||
|
||||
JTextField textField = (JTextField) editor;
|
||||
Insets insets = textField.getInsets();
|
||||
Insets pad = padding;
|
||||
if( insets.top != 0 || insets.left != 0 || insets.bottom != 0 || insets.right != 0 ) {
|
||||
// if text field has custom border, subtract text field insets from padding
|
||||
pad = new Insets(
|
||||
unscale( Math.max( scale( padding.top ) - insets.top, 0 ) ),
|
||||
unscale( Math.max( scale( padding.left ) - insets.left, 0 ) ),
|
||||
unscale( Math.max( scale( padding.bottom ) - insets.bottom, 0 ) ),
|
||||
unscale( Math.max( scale( padding.right ) - insets.right, 0 ) )
|
||||
);
|
||||
}
|
||||
textField.putClientProperty( FlatClientProperties.TEXT_FIELD_PADDING, pad );
|
||||
}
|
||||
|
||||
private void updateEditorColors() {
|
||||
// use non-UIResource colors because when SwingUtilities.updateComponentTreeUI()
|
||||
// is used, then the editor is updated after the combobox and the
|
||||
@@ -423,7 +450,11 @@ public class FlatComboBoxUI
|
||||
|
||||
// paint arrow button background
|
||||
if( enabled && !isCellRenderer ) {
|
||||
g2.setColor( paintButton ? buttonEditableBackground : buttonBackground );
|
||||
g2.setColor( paintButton
|
||||
? buttonEditableBackground
|
||||
: (buttonFocusedBackground != null || focusedBackground != null) && isPermanentFocusOwner( comboBox )
|
||||
? (buttonFocusedBackground != null ? buttonFocusedBackground : focusedBackground)
|
||||
: buttonBackground );
|
||||
Shape oldClip = g2.getClip();
|
||||
if( isLeftToRight )
|
||||
g2.clipRect( arrowX, 0, width - arrowX, height );
|
||||
@@ -451,30 +482,24 @@ public class FlatComboBoxUI
|
||||
@Override
|
||||
@SuppressWarnings( "unchecked" )
|
||||
public void paintCurrentValue( Graphics g, Rectangle bounds, boolean hasFocus ) {
|
||||
paddingBorder.uninstall();
|
||||
|
||||
ListCellRenderer<Object> renderer = comboBox.getRenderer();
|
||||
uninstallCellPaddingBorder( renderer );
|
||||
if( renderer == null )
|
||||
renderer = new DefaultListCellRenderer();
|
||||
Component c = renderer.getListCellRendererComponent( listBox, comboBox.getSelectedItem(), -1, false, false );
|
||||
c.setFont( comboBox.getFont() );
|
||||
c.applyComponentOrientation( comboBox.getComponentOrientation() );
|
||||
uninstallCellPaddingBorder( c );
|
||||
|
||||
boolean enabled = comboBox.isEnabled();
|
||||
c.setBackground( getBackground( enabled ) );
|
||||
c.setForeground( getForeground( enabled ) );
|
||||
|
||||
boolean shouldValidate = (c instanceof JPanel);
|
||||
if( padding != null )
|
||||
bounds = FlatUIUtils.subtractInsets( bounds, padding );
|
||||
|
||||
// increase the size of the rendering area to make sure that the text
|
||||
// is vertically aligned with other component types (e.g. JTextField)
|
||||
Insets rendererInsets = getRendererComponentInsets( c );
|
||||
if( rendererInsets != null )
|
||||
bounds = FlatUIUtils.addInsets( bounds, rendererInsets );
|
||||
|
||||
paddingBorder.install( c );
|
||||
currentValuePane.paintComponent( g, c, comboBox, bounds.x, bounds.y, bounds.width, bounds.height, shouldValidate );
|
||||
paddingBorder.uninstall();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -483,9 +508,20 @@ public class FlatComboBoxUI
|
||||
}
|
||||
|
||||
protected Color getBackground( boolean enabled ) {
|
||||
return enabled
|
||||
? (editableBackground != null && comboBox.isEditable() ? editableBackground : comboBox.getBackground())
|
||||
: (isIntelliJTheme ? FlatUIUtils.getParentBackground( comboBox ) : disabledBackground);
|
||||
if( enabled ) {
|
||||
Color background = comboBox.getBackground();
|
||||
|
||||
// always use explicitly set color
|
||||
if( !(background instanceof UIResource) )
|
||||
return background;
|
||||
|
||||
// focused
|
||||
if( focusedBackground != null && isPermanentFocusOwner( comboBox ) )
|
||||
return focusedBackground;
|
||||
|
||||
return (editableBackground != null && comboBox.isEditable()) ? editableBackground : background;
|
||||
} else
|
||||
return isIntelliJTheme ? FlatUIUtils.getParentBackground( comboBox ) : disabledBackground;
|
||||
}
|
||||
|
||||
protected Color getForeground( boolean enabled ) {
|
||||
@@ -495,77 +531,49 @@ public class FlatComboBoxUI
|
||||
@Override
|
||||
public Dimension getMinimumSize( JComponent c ) {
|
||||
Dimension minimumSize = super.getMinimumSize( c );
|
||||
minimumSize.width = Math.max( minimumSize.width, scale( FlatUIUtils.minimumWidth( c, minimumWidth ) ) );
|
||||
int fw = Math.round( FlatUIUtils.getBorderFocusWidth( c ) * 2 );
|
||||
minimumSize.width = Math.max( minimumSize.width, scale( FlatUIUtils.minimumWidth( c, minimumWidth ) ) + fw );
|
||||
return minimumSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Dimension getDefaultSize() {
|
||||
@SuppressWarnings( "unchecked" )
|
||||
ListCellRenderer<Object> renderer = comboBox.getRenderer();
|
||||
uninstallCellPaddingBorder( renderer );
|
||||
|
||||
paddingBorder.uninstall();
|
||||
Dimension size = super.getDefaultSize();
|
||||
|
||||
uninstallCellPaddingBorder( renderer );
|
||||
paddingBorder.uninstall();
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Dimension getDisplaySize() {
|
||||
@SuppressWarnings( "unchecked" )
|
||||
ListCellRenderer<Object> renderer = comboBox.getRenderer();
|
||||
uninstallCellPaddingBorder( renderer );
|
||||
|
||||
paddingBorder.uninstall();
|
||||
Dimension displaySize = super.getDisplaySize();
|
||||
paddingBorder.uninstall();
|
||||
|
||||
// remove padding added in super.getDisplaySize()
|
||||
int displayWidth = displaySize.width - padding.left - padding.right;
|
||||
int displayHeight = displaySize.height - padding.top - padding.bottom;
|
||||
|
||||
// recalculate width without hardcoded 100 under special conditions
|
||||
if( displaySize.width == 100 + padding.left + padding.right &&
|
||||
if( displayWidth == 100 &&
|
||||
comboBox.isEditable() &&
|
||||
comboBox.getItemCount() == 0 &&
|
||||
comboBox.getPrototypeDisplayValue() == null )
|
||||
{
|
||||
int width = getDefaultSize().width;
|
||||
width = Math.max( width, editor.getPreferredSize().width );
|
||||
width += padding.left + padding.right;
|
||||
displaySize = new Dimension( width, displaySize.height );
|
||||
displayWidth = Math.max( getDefaultSize().width, editor.getPreferredSize().width );
|
||||
}
|
||||
|
||||
uninstallCellPaddingBorder( renderer );
|
||||
return displaySize;
|
||||
return new Dimension( displayWidth, displayHeight );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Dimension getSizeForComponent( Component comp ) {
|
||||
paddingBorder.install( comp );
|
||||
Dimension size = super.getSizeForComponent( comp );
|
||||
|
||||
// remove the renderer border top/bottom insets from the size to make sure that
|
||||
// the combobox gets the same height as other component types (e.g. JTextField)
|
||||
Insets rendererInsets = getRendererComponentInsets( comp );
|
||||
if( rendererInsets != null )
|
||||
size = new Dimension( size.width, size.height - rendererInsets.top - rendererInsets.bottom );
|
||||
|
||||
paddingBorder.uninstall();
|
||||
return size;
|
||||
}
|
||||
|
||||
private Insets getRendererComponentInsets( Component rendererComponent ) {
|
||||
if( rendererComponent instanceof JComponent ) {
|
||||
Border rendererBorder = ((JComponent)rendererComponent).getBorder();
|
||||
if( rendererBorder != null )
|
||||
return rendererBorder.getBorderInsets( rendererComponent );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void uninstallCellPaddingBorder( Object o ) {
|
||||
CellPaddingBorder.uninstall( o );
|
||||
if( lastRendererComponent != null ) {
|
||||
CellPaddingBorder.uninstall( lastRendererComponent );
|
||||
lastRendererComponent = null;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isCellRenderer() {
|
||||
return comboBox.getParent() instanceof CellRendererPane;
|
||||
}
|
||||
@@ -576,6 +584,17 @@ public class FlatComboBoxUI
|
||||
return parentParent != null && !comboBox.getBackground().equals( parentParent.getBackground() );
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.3
|
||||
*/
|
||||
public static boolean isPermanentFocusOwner( JComboBox<?> comboBox ) {
|
||||
if( comboBox.isEditable() ) {
|
||||
Component editorComponent = comboBox.getEditor().getEditorComponent();
|
||||
return (editorComponent != null) ? FlatUIUtils.isPermanentFocusOwner( editorComponent ) : false;
|
||||
} else
|
||||
return FlatUIUtils.isPermanentFocusOwner( comboBox );
|
||||
}
|
||||
|
||||
//---- class FlatComboBoxButton -------------------------------------------
|
||||
|
||||
protected class FlatComboBoxButton
|
||||
@@ -618,13 +637,11 @@ public class FlatComboBoxUI
|
||||
protected class FlatComboPopup
|
||||
extends BasicComboPopup
|
||||
{
|
||||
private CellPaddingBorder paddingBorder;
|
||||
|
||||
protected FlatComboPopup( JComboBox combo ) {
|
||||
super( combo );
|
||||
|
||||
// BasicComboPopup listens to JComboBox.componentOrientation and updates
|
||||
// the component orientation of the list, scroller and popup, but when
|
||||
// the component orientation of the list, scroll pane and popup, but when
|
||||
// switching the LaF and a new combo popup is created, the component
|
||||
// orientation is not applied.
|
||||
ComponentOrientation o = comboBox.getComponentOrientation();
|
||||
@@ -678,6 +695,9 @@ public class FlatComboBoxUI
|
||||
protected void configurePopup() {
|
||||
super.configurePopup();
|
||||
|
||||
// make opaque to avoid that background shines thru border (e.g. at 150% scaling)
|
||||
setOpaque( true );
|
||||
|
||||
Border border = UIManager.getBorder( "PopupMenu.border" );
|
||||
if( border != null )
|
||||
setBorder( border );
|
||||
@@ -688,6 +708,8 @@ public class FlatComboBoxUI
|
||||
super.configureList();
|
||||
|
||||
list.setCellRenderer( new PopupListCellRenderer() );
|
||||
if( popupBackground != null )
|
||||
list.setBackground( popupBackground );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -701,6 +723,34 @@ public class FlatComboBoxUI
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getPopupHeightForRowCount( int maxRowCount ) {
|
||||
int height = super.getPopupHeightForRowCount( maxRowCount );
|
||||
paddingBorder.uninstall();
|
||||
return height;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show( Component invoker, int x, int y ) {
|
||||
// Java 8: fix y coordinate if popup is shown above the combobox
|
||||
// (already fixed in Java 9+ https://bugs.openjdk.java.net/browse/JDK-7072653)
|
||||
if( y < 0 && !SystemInfo.isJava_9_orLater ) {
|
||||
Border popupBorder = getBorder();
|
||||
if( popupBorder != null ) {
|
||||
Insets insets = popupBorder.getBorderInsets( this );
|
||||
y -= insets.top + insets.bottom;
|
||||
}
|
||||
}
|
||||
|
||||
super.show( invoker, x, y );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintChildren( Graphics g ) {
|
||||
super.paintChildren( g );
|
||||
paddingBorder.uninstall();
|
||||
}
|
||||
|
||||
//---- class PopupListCellRenderer -----
|
||||
|
||||
private class PopupListCellRenderer
|
||||
@@ -710,22 +760,15 @@ public class FlatComboBoxUI
|
||||
public Component getListCellRendererComponent( JList list, Object value,
|
||||
int index, boolean isSelected, boolean cellHasFocus )
|
||||
{
|
||||
ListCellRenderer renderer = comboBox.getRenderer();
|
||||
CellPaddingBorder.uninstall( renderer );
|
||||
CellPaddingBorder.uninstall( lastRendererComponent );
|
||||
paddingBorder.uninstall();
|
||||
|
||||
ListCellRenderer renderer = comboBox.getRenderer();
|
||||
if( renderer == null )
|
||||
renderer = new DefaultListCellRenderer();
|
||||
Component c = renderer.getListCellRendererComponent( list, value, index, isSelected, cellHasFocus );
|
||||
c.applyComponentOrientation( comboBox.getComponentOrientation() );
|
||||
|
||||
if( c instanceof JComponent ) {
|
||||
if( paddingBorder == null )
|
||||
paddingBorder = new CellPaddingBorder( padding );
|
||||
paddingBorder.install( (JComponent) c );
|
||||
}
|
||||
|
||||
lastRendererComponent = (c != renderer) ? new WeakReference<>( c ) : null;
|
||||
paddingBorder.install( c );
|
||||
|
||||
return c;
|
||||
}
|
||||
@@ -735,49 +778,69 @@ public class FlatComboBoxUI
|
||||
//---- class CellPaddingBorder --------------------------------------------
|
||||
|
||||
/**
|
||||
* Cell padding border used only in popup list.
|
||||
*
|
||||
* Cell padding border used in popup list and for current value if not editable.
|
||||
* <p>
|
||||
* The insets are the union of the cell padding and the renderer border insets,
|
||||
* which vertically aligns text in popup list with text in combobox.
|
||||
*
|
||||
* The renderer border is painted on the outside of this border.
|
||||
* <p>
|
||||
* The renderer border is painted on the outer side of this border.
|
||||
*/
|
||||
private static class CellPaddingBorder
|
||||
extends AbstractBorder
|
||||
{
|
||||
private final Insets padding;
|
||||
private JComponent rendererComponent;
|
||||
private Border rendererBorder;
|
||||
|
||||
CellPaddingBorder( Insets padding ) {
|
||||
this.padding = padding;
|
||||
}
|
||||
|
||||
void install( JComponent rendererComponent ) {
|
||||
Border oldBorder = rendererComponent.getBorder();
|
||||
if( !(oldBorder instanceof CellPaddingBorder) ) {
|
||||
rendererBorder = oldBorder;
|
||||
rendererComponent.setBorder( this );
|
||||
}
|
||||
}
|
||||
|
||||
static void uninstall( Object o ) {
|
||||
if( o instanceof WeakReference )
|
||||
o = ((WeakReference<?>)o).get();
|
||||
|
||||
if( !(o instanceof JComponent) )
|
||||
void install( Component c ) {
|
||||
if( !(c instanceof JComponent) )
|
||||
return;
|
||||
|
||||
JComponent rendererComponent = (JComponent) o;
|
||||
Border border = rendererComponent.getBorder();
|
||||
if( border instanceof CellPaddingBorder ) {
|
||||
CellPaddingBorder paddingBorder = (CellPaddingBorder) border;
|
||||
rendererComponent.setBorder( paddingBorder.rendererBorder );
|
||||
paddingBorder.rendererBorder = null;
|
||||
JComponent jc = (JComponent) c;
|
||||
Border oldBorder = jc.getBorder();
|
||||
if( oldBorder == this )
|
||||
return; // already installed
|
||||
|
||||
// component already has a padding border --> uninstall it
|
||||
// (may happen if single renderer instance is used in multiple comboboxes)
|
||||
if( oldBorder instanceof CellPaddingBorder )
|
||||
((CellPaddingBorder)oldBorder).uninstall();
|
||||
|
||||
// this border can be installed only at one component
|
||||
// (may happen if a renderer returns varying components)
|
||||
uninstall();
|
||||
|
||||
// remember component where this border was installed for uninstall
|
||||
rendererComponent = jc;
|
||||
|
||||
// remember old border and replace it
|
||||
rendererBorder = jc.getBorder();
|
||||
rendererComponent.setBorder( this );
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninstall border from previously installed component.
|
||||
* Because this border is installed in PopupListCellRenderer.getListCellRendererComponent(),
|
||||
* there is no single place to uninstall it.
|
||||
* This is the reason why this method is called from various places.
|
||||
*/
|
||||
void uninstall() {
|
||||
if( rendererComponent == null )
|
||||
return;
|
||||
|
||||
if( rendererComponent.getBorder() == this )
|
||||
rendererComponent.setBorder( rendererBorder );
|
||||
rendererComponent = null;
|
||||
rendererBorder = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Insets getBorderInsets( Component c, Insets insets ) {
|
||||
Insets padding = scale( this.padding );
|
||||
if( rendererBorder != null ) {
|
||||
Insets insideInsets = rendererBorder.getBorderInsets( c );
|
||||
insets.top = Math.max( padding.top, insideInsets.top );
|
||||
|
||||
@@ -17,15 +17,17 @@
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import static com.formdev.flatlaf.util.UIScale.scale;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Insets;
|
||||
import java.awt.event.FocusListener;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JEditorPane;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.UIResource;
|
||||
import javax.swing.plaf.basic.BasicEditorPaneUI;
|
||||
import javax.swing.text.JTextComponent;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
@@ -53,6 +55,7 @@ import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
*
|
||||
* @uiDefault Component.minimumWidth int
|
||||
* @uiDefault Component.isIntelliJTheme boolean
|
||||
* @uiDefault EditorPane.focusedBackground Color optional
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
@@ -61,8 +64,12 @@ public class FlatEditorPaneUI
|
||||
{
|
||||
protected int minimumWidth;
|
||||
protected boolean isIntelliJTheme;
|
||||
protected Color focusedBackground;
|
||||
|
||||
private Insets defaultMargin;
|
||||
|
||||
private Object oldHonorDisplayProperties;
|
||||
private FocusListener focusListener;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatEditorPaneUI();
|
||||
@@ -72,8 +79,12 @@ public class FlatEditorPaneUI
|
||||
protected void installDefaults() {
|
||||
super.installDefaults();
|
||||
|
||||
String prefix = getPropertyPrefix();
|
||||
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
|
||||
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
|
||||
focusedBackground = UIManager.getColor( prefix + ".focusedBackground" );
|
||||
|
||||
defaultMargin = UIManager.getInsets( prefix + ".margin" );
|
||||
|
||||
// use component font and foreground for HTML text
|
||||
oldHonorDisplayProperties = getComponent().getClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES );
|
||||
@@ -84,9 +95,28 @@ public class FlatEditorPaneUI
|
||||
protected void uninstallDefaults() {
|
||||
super.uninstallDefaults();
|
||||
|
||||
focusedBackground = null;
|
||||
|
||||
getComponent().putClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES, oldHonorDisplayProperties );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installListeners() {
|
||||
super.installListeners();
|
||||
|
||||
// necessary to update focus background
|
||||
focusListener = new FlatUIUtils.RepaintFocusListener( getComponent(), c -> focusedBackground != null );
|
||||
getComponent().addFocusListener( focusListener );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void uninstallListeners() {
|
||||
super.uninstallListeners();
|
||||
|
||||
getComponent().removeFocusListener( focusListener );
|
||||
focusListener = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void propertyChange( PropertyChangeEvent e ) {
|
||||
super.propertyChange( e );
|
||||
@@ -103,15 +133,19 @@ public class FlatEditorPaneUI
|
||||
|
||||
@Override
|
||||
public Dimension getPreferredSize( JComponent c ) {
|
||||
return applyMinimumWidth( c, super.getPreferredSize( c ), minimumWidth );
|
||||
return applyMinimumWidth( c, super.getPreferredSize( c ), minimumWidth, defaultMargin );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getMinimumSize( JComponent c ) {
|
||||
return applyMinimumWidth( c, super.getMinimumSize( c ), minimumWidth );
|
||||
return applyMinimumWidth( c, super.getMinimumSize( c ), minimumWidth, defaultMargin );
|
||||
}
|
||||
|
||||
static Dimension applyMinimumWidth( JComponent c, Dimension size, int minimumWidth ) {
|
||||
static Dimension applyMinimumWidth( JComponent c, Dimension size, int minimumWidth, Insets defaultMargin ) {
|
||||
// do not apply minimum width if JTextComponent.margin is set
|
||||
if( !FlatTextFieldUI.hasDefaultMargins( c, defaultMargin ) )
|
||||
return size;
|
||||
|
||||
// Assume that text area is in a scroll pane (that displays the border)
|
||||
// and subtract 1px border line width.
|
||||
// Using "(scale( 1 ) * 2)" instead of "scale( 2 )" to deal with rounding
|
||||
@@ -128,14 +162,11 @@ public class FlatEditorPaneUI
|
||||
|
||||
@Override
|
||||
protected void paintBackground( Graphics g ) {
|
||||
JTextComponent c = getComponent();
|
||||
|
||||
// for compatibility with IntelliJ themes
|
||||
if( isIntelliJTheme && (!c.isEnabled() || !c.isEditable()) && (c.getBackground() instanceof UIResource) ) {
|
||||
FlatUIUtils.paintParentBackground( g, c );
|
||||
return;
|
||||
paintBackground( g, getComponent(), isIntelliJTheme, focusedBackground );
|
||||
}
|
||||
|
||||
super.paintBackground( g );
|
||||
static void paintBackground( Graphics g, JTextComponent c, boolean isIntelliJTheme, Color focusedBackground ) {
|
||||
g.setColor( FlatTextFieldUI.getBackground( c, isIntelliJTheme, focusedBackground ) );
|
||||
g.fillRect( 0, 0, c.getWidth(), c.getHeight() );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,11 +39,10 @@ import javax.swing.plaf.ComponentUI;
|
||||
*
|
||||
* <!-- FlatTextFieldUI -->
|
||||
*
|
||||
* @uiDefault TextComponent.arc int
|
||||
* @uiDefault Component.focusWidth int
|
||||
* @uiDefault Component.minimumWidth int
|
||||
* @uiDefault Component.isIntelliJTheme boolean
|
||||
* @uiDefault FormattedTextField.placeholderForeground Color
|
||||
* @uiDefault FormattedTextField.focusedBackground Color optional
|
||||
* @uiDefault TextComponent.selectAllOnFocusPolicy String never, once (default) or always
|
||||
* @uiDefault TextComponent.selectAllOnMouseClick boolean
|
||||
*
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.LayoutManager;
|
||||
import java.awt.Rectangle;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import javax.swing.BorderFactory;
|
||||
@@ -146,6 +147,19 @@ public class FlatInternalFrameTitlePane
|
||||
closeButton.setVisible( frame.isClosable() );
|
||||
}
|
||||
|
||||
Rectangle getFrameIconBounds() {
|
||||
Icon icon = titleLabel.getIcon();
|
||||
if( icon == null )
|
||||
return null;
|
||||
|
||||
int iconWidth = icon.getIconWidth();
|
||||
int iconHeight = icon.getIconHeight();
|
||||
boolean leftToRight = titleLabel.getComponentOrientation().isLeftToRight();
|
||||
int x = titleLabel.getX() + (leftToRight ? 0 : (titleLabel.getWidth() - iconWidth));
|
||||
int y = titleLabel.getY() + ((titleLabel.getHeight() - iconHeight) / 2);
|
||||
return new Rectangle( x, y, iconWidth, iconHeight );
|
||||
}
|
||||
|
||||
/**
|
||||
* Does nothing because FlatLaf internal frames do not have system menus.
|
||||
*/
|
||||
|
||||
@@ -22,10 +22,13 @@ import java.awt.Component;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.event.MouseEvent;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JInternalFrame;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.event.MouseInputAdapter;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicInternalFrameUI;
|
||||
|
||||
@@ -122,6 +125,11 @@ public class FlatInternalFrameUI
|
||||
return new FlatWindowResizer.InternalFrameResizer( frame, this::getDesktopManager );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MouseInputAdapter createBorderListener( JInternalFrame w ) {
|
||||
return new FlatBorderListener();
|
||||
}
|
||||
|
||||
//---- class FlatInternalFrameBorder --------------------------------------
|
||||
|
||||
public static class FlatInternalFrameBorder
|
||||
@@ -195,4 +203,29 @@ public class FlatInternalFrameUI
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---- class FlatBorderListener -------------------------------------------
|
||||
|
||||
/**
|
||||
* @since 1.6
|
||||
*/
|
||||
protected class FlatBorderListener
|
||||
extends BorderListener
|
||||
{
|
||||
@Override
|
||||
public void mouseClicked( MouseEvent e ) {
|
||||
if( e.getClickCount() == 2 && !frame.isIcon() &&
|
||||
e.getSource() instanceof FlatInternalFrameTitlePane )
|
||||
{
|
||||
Rectangle iconBounds = ((FlatInternalFrameTitlePane)e.getSource()).getFrameIconBounds();
|
||||
if( iconBounds != null && iconBounds.contains( e.getX(), e.getY() ) ) {
|
||||
if( frame.isClosable() )
|
||||
frame.doDefaultCloseAction();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
super.mouseClicked( e );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,10 +20,12 @@ import java.awt.Color;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.FocusListener;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicListUI;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JList}.
|
||||
@@ -95,6 +97,17 @@ public class FlatListUI
|
||||
selectionInactiveForeground = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PropertyChangeListener createPropertyChangeListener() {
|
||||
PropertyChangeListener superListener = super.createPropertyChangeListener();
|
||||
return e -> {
|
||||
superListener.propertyChange( e );
|
||||
|
||||
if( FlatClientProperties.COMPONENT_FOCUS_OWNER.equals( e.getPropertyName() ) )
|
||||
toggleSelectionColors();
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FocusListener createFocusListener() {
|
||||
return new BasicListUI.FocusHandler() {
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Container;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Window;
|
||||
import java.beans.PropertyChangeListener;
|
||||
@@ -24,7 +25,6 @@ import java.util.List;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JRootPane;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.event.ChangeListener;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
@@ -76,6 +76,11 @@ public class FlatNativeWindowBorder
|
||||
if( !isSupported() )
|
||||
return null;
|
||||
|
||||
// do nothing if root pane has a parent that is not a window (e.g. a JInternalFrame)
|
||||
Container parent = rootPane.getParent();
|
||||
if( parent != null && !(parent instanceof Window) )
|
||||
return null;
|
||||
|
||||
// Check whether root pane already has a window, which is the case when
|
||||
// switching from another LaF to FlatLaf.
|
||||
// Also check whether the window is displayable, which is required to install
|
||||
@@ -83,9 +88,8 @@ public class FlatNativeWindowBorder
|
||||
// If the window is not displayable, then it was probably closed/disposed but not yet removed
|
||||
// from the list of windows that AWT maintains and returns with Window.getWindows().
|
||||
// It could be also be a window that is currently hidden, but may be shown later.
|
||||
Window window = SwingUtilities.windowForComponent( rootPane );
|
||||
if( window != null && window.isDisplayable() )
|
||||
install( window );
|
||||
if( parent instanceof Window && parent.isDisplayable() )
|
||||
install( (Window) parent );
|
||||
|
||||
// Install FlatLaf native window border, which must be done late,
|
||||
// when the native window is already created, because it needs access to the window.
|
||||
@@ -174,9 +178,9 @@ public class FlatNativeWindowBorder
|
||||
return;
|
||||
|
||||
// uninstall native window border
|
||||
Window window = SwingUtilities.windowForComponent( rootPane );
|
||||
if( window != null )
|
||||
uninstall( window );
|
||||
Container parent = rootPane.getParent();
|
||||
if( parent instanceof Window )
|
||||
uninstall( (Window) parent );
|
||||
}
|
||||
|
||||
private static void uninstall( Window window ) {
|
||||
|
||||
@@ -22,7 +22,11 @@ import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.Insets;
|
||||
import javax.swing.Box;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.border.Border;
|
||||
@@ -88,6 +92,7 @@ public class FlatOptionPaneUI
|
||||
protected int messagePadding;
|
||||
protected int maxCharactersPerLine;
|
||||
private int focusWidth;
|
||||
private boolean sameSizeButtons;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatOptionPaneUI();
|
||||
@@ -101,6 +106,7 @@ public class FlatOptionPaneUI
|
||||
messagePadding = UIManager.getInt( "OptionPane.messagePadding" );
|
||||
maxCharactersPerLine = UIManager.getInt( "OptionPane.maxCharactersPerLine" );
|
||||
focusWidth = UIManager.getInt( "Component.focusWidth" );
|
||||
sameSizeButtons = FlatUIUtils.getUIBoolean( "OptionPane.sameSizeButtons", true );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -157,15 +163,40 @@ public class FlatOptionPaneUI
|
||||
cons.insets.bottom = UIScale.scale( messagePadding );
|
||||
|
||||
// disable line wrapping for HTML
|
||||
if( msg instanceof String && BasicHTML.isHTMLString( (String) msg ) )
|
||||
if( msg != null &&
|
||||
!(msg instanceof Component) &&
|
||||
!(msg instanceof Object[]) &&
|
||||
!(msg instanceof Icon) )
|
||||
{
|
||||
msg = msg.toString();
|
||||
if( BasicHTML.isHTMLString( (String) msg ) )
|
||||
maxll = Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
// fix right-to-left alignment if super.addMessageComponents() breaks longer lines
|
||||
// into multiple labels and puts them into a box that aligns them to the left
|
||||
if( msg instanceof Box ) {
|
||||
Box box = (Box) msg;
|
||||
if( "OptionPane.verticalBox".equals( box.getName() ) &&
|
||||
box.getLayout() instanceof BoxLayout &&
|
||||
((BoxLayout)box.getLayout()).getAxis() == BoxLayout.Y_AXIS )
|
||||
{
|
||||
box.addPropertyChangeListener( "componentOrientation", e -> {
|
||||
float alignX = box.getComponentOrientation().isLeftToRight() ? 0 : 1;
|
||||
for( Component c : box.getComponents() ) {
|
||||
if( c instanceof JLabel && "OptionPane.label".equals( c.getName() ) )
|
||||
((JLabel)c).setAlignmentX( alignX );
|
||||
}
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
super.addMessageComponents( container, cons, msg, maxll, internallyCreated );
|
||||
}
|
||||
|
||||
private void updateChildPanels( Container c ) {
|
||||
for( Component child : c.getComponents() ) {
|
||||
if( child instanceof JPanel ) {
|
||||
if( child.getClass() == JPanel.class ) {
|
||||
JPanel panel = (JPanel)child;
|
||||
|
||||
// make sub-panel non-opaque for OptionPane.background
|
||||
@@ -177,11 +208,10 @@ public class FlatOptionPaneUI
|
||||
panel.setBorder( new NonUIResourceBorder( border ) );
|
||||
}
|
||||
|
||||
if( child instanceof Container ) {
|
||||
if( child instanceof Container )
|
||||
updateChildPanels( (Container) child );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Component findByName( Container c, String name ) {
|
||||
for( Component child : c.getComponents() ) {
|
||||
@@ -197,6 +227,11 @@ public class FlatOptionPaneUI
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean getSizeButtonsToSameWidth() {
|
||||
return sameSizeButtons;
|
||||
}
|
||||
|
||||
//---- class NonUIResourceBorder ------------------------------------------
|
||||
|
||||
private static class NonUIResourceBorder
|
||||
|
||||
@@ -16,30 +16,31 @@
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Shape;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.event.FocusListener;
|
||||
import java.awt.event.KeyAdapter;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.KeyListener;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import javax.swing.Action;
|
||||
import javax.swing.ActionMap;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicPasswordFieldUI;
|
||||
import javax.swing.text.Caret;
|
||||
import javax.swing.text.DefaultEditorKit;
|
||||
import javax.swing.text.Element;
|
||||
import javax.swing.text.JTextComponent;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
import javax.swing.text.PasswordView;
|
||||
import javax.swing.text.View;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JPasswordField}.
|
||||
*
|
||||
* <!-- BasicPasswordFieldUI -->
|
||||
* <!-- BasicTextFieldUI -->
|
||||
*
|
||||
* @uiDefault PasswordField.font Font
|
||||
* @uiDefault PasswordField.background Color
|
||||
@@ -52,68 +53,67 @@ import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
* @uiDefault PasswordField.inactiveForeground Color used if not enabled (yes, this is confusing; this should be named disabledForeground)
|
||||
* @uiDefault PasswordField.border Border
|
||||
* @uiDefault PasswordField.margin Insets
|
||||
* @uiDefault PasswordField.echoChar character
|
||||
* @uiDefault PasswordField.caretBlinkRate int default is 500 milliseconds
|
||||
*
|
||||
* <!-- FlatPasswordFieldUI -->
|
||||
* <!-- FlatTextFieldUI -->
|
||||
*
|
||||
* @uiDefault Component.minimumWidth int
|
||||
* @uiDefault Component.isIntelliJTheme boolean
|
||||
* @uiDefault PasswordField.placeholderForeground Color
|
||||
* @uiDefault PasswordField.showCapsLock boolean
|
||||
* @uiDefault PasswordField.capsLockIcon Icon
|
||||
* @uiDefault PasswordField.focusedBackground Color optional
|
||||
* @uiDefault TextComponent.selectAllOnFocusPolicy String never, once (default) or always
|
||||
* @uiDefault TextComponent.selectAllOnMouseClick boolean
|
||||
*
|
||||
* <!-- FlatPasswordFieldUI -->
|
||||
*
|
||||
* @uiDefault PasswordField.echoChar character
|
||||
* @uiDefault PasswordField.showCapsLock boolean
|
||||
* @uiDefault PasswordField.capsLockIcon Icon
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatPasswordFieldUI
|
||||
extends BasicPasswordFieldUI
|
||||
extends FlatTextFieldUI
|
||||
{
|
||||
protected int minimumWidth;
|
||||
protected boolean isIntelliJTheme;
|
||||
protected Color placeholderForeground;
|
||||
protected boolean showCapsLock;
|
||||
protected Icon capsLockIcon;
|
||||
|
||||
private FocusListener focusListener;
|
||||
private KeyListener capsLockListener;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatPasswordFieldUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getPropertyPrefix() {
|
||||
return "PasswordField";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installDefaults() {
|
||||
super.installDefaults();
|
||||
|
||||
String prefix = getPropertyPrefix();
|
||||
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
|
||||
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
|
||||
placeholderForeground = UIManager.getColor( prefix + ".placeholderForeground" );
|
||||
Character echoChar = (Character) UIManager.get( prefix + ".echoChar" );
|
||||
if( echoChar != null )
|
||||
LookAndFeel.installProperty( getComponent(), "echoChar", echoChar );
|
||||
|
||||
showCapsLock = UIManager.getBoolean( "PasswordField.showCapsLock" );
|
||||
capsLockIcon = UIManager.getIcon( "PasswordField.capsLockIcon" );
|
||||
|
||||
LookAndFeel.installProperty( getComponent(), "opaque", false );
|
||||
|
||||
MigLayoutVisualPadding.install( getComponent() );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void uninstallDefaults() {
|
||||
super.uninstallDefaults();
|
||||
|
||||
placeholderForeground = null;
|
||||
capsLockIcon = null;
|
||||
|
||||
MigLayoutVisualPadding.uninstall( getComponent() );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installListeners() {
|
||||
super.installListeners();
|
||||
|
||||
focusListener = new FlatUIUtils.RepaintFocusListener( getComponent() );
|
||||
// update caps lock indicator
|
||||
capsLockListener = new KeyAdapter() {
|
||||
@Override
|
||||
public void keyPressed( KeyEvent e ) {
|
||||
@@ -124,12 +124,13 @@ public class FlatPasswordFieldUI
|
||||
repaint( e );
|
||||
}
|
||||
private void repaint( KeyEvent e ) {
|
||||
if( e.getKeyCode() == KeyEvent.VK_CAPS_LOCK )
|
||||
if( e.getKeyCode() == KeyEvent.VK_CAPS_LOCK ) {
|
||||
e.getComponent().repaint();
|
||||
scrollCaretToVisible();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
getComponent().addFocusListener( focusListener );
|
||||
getComponent().addKeyListener( capsLockListener );
|
||||
}
|
||||
|
||||
@@ -137,59 +138,74 @@ public class FlatPasswordFieldUI
|
||||
protected void uninstallListeners() {
|
||||
super.uninstallListeners();
|
||||
|
||||
getComponent().removeFocusListener( focusListener );
|
||||
getComponent().removeKeyListener( capsLockListener );
|
||||
focusListener = null;
|
||||
capsLockListener = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Caret createCaret() {
|
||||
return new FlatCaret( UIManager.getString( "TextComponent.selectAllOnFocusPolicy" ),
|
||||
UIManager.getBoolean( "TextComponent.selectAllOnMouseClick" ) );
|
||||
protected void installKeyboardActions() {
|
||||
super.installKeyboardActions();
|
||||
|
||||
// map "select-word" action (double-click) to "select-line" action
|
||||
ActionMap map = SwingUtilities.getUIActionMap( getComponent() );
|
||||
if( map != null && map.get( DefaultEditorKit.selectWordAction ) != null ) {
|
||||
Action selectLineAction = map.get( DefaultEditorKit.selectLineAction );
|
||||
if( selectLineAction != null )
|
||||
map.put( DefaultEditorKit.selectWordAction, selectLineAction );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void propertyChange( PropertyChangeEvent e ) {
|
||||
super.propertyChange( e );
|
||||
FlatTextFieldUI.propertyChange( getComponent(), e );
|
||||
public View create( Element elem ) {
|
||||
return new PasswordView( elem );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintSafely( Graphics g ) {
|
||||
FlatTextFieldUI.paintBackground( g, getComponent(), isIntelliJTheme );
|
||||
FlatTextFieldUI.paintPlaceholder( g, getComponent(), placeholderForeground );
|
||||
paintCapsLock( g );
|
||||
// safe and restore clipping area because super.paintSafely() modifies it
|
||||
// and the caps lock icon would be truncated
|
||||
Shape oldClip = g.getClip();
|
||||
super.paintSafely( g );
|
||||
g.setClip( oldClip );
|
||||
|
||||
super.paintSafely( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ) );
|
||||
paintCapsLock( g );
|
||||
}
|
||||
|
||||
protected void paintCapsLock( Graphics g ) {
|
||||
if( !showCapsLock )
|
||||
if( !isCapsLockVisible() )
|
||||
return;
|
||||
|
||||
JTextComponent c = getComponent();
|
||||
if( !FlatUIUtils.isPermanentFocusOwner( c ) ||
|
||||
!Toolkit.getDefaultToolkit().getLockingKeyState( KeyEvent.VK_CAPS_LOCK ) )
|
||||
return;
|
||||
|
||||
int y = (c.getHeight() - capsLockIcon.getIconHeight()) / 2;
|
||||
int x = c.getWidth() - capsLockIcon.getIconWidth() - y;
|
||||
int x = c.getComponentOrientation().isLeftToRight()
|
||||
? c.getWidth() - capsLockIcon.getIconWidth() - y
|
||||
: y;
|
||||
capsLockIcon.paintIcon( c, g, x, y );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintBackground( Graphics g ) {
|
||||
// background is painted elsewhere
|
||||
/**
|
||||
* @since 1.4
|
||||
*/
|
||||
protected boolean isCapsLockVisible() {
|
||||
if( !showCapsLock )
|
||||
return false;
|
||||
|
||||
JTextComponent c = getComponent();
|
||||
return FlatUIUtils.isPermanentFocusOwner( c ) &&
|
||||
Toolkit.getDefaultToolkit().getLockingKeyState( KeyEvent.VK_CAPS_LOCK );
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.4
|
||||
*/
|
||||
@Override
|
||||
public Dimension getPreferredSize( JComponent c ) {
|
||||
return FlatTextFieldUI.applyMinimumWidth( c, super.getPreferredSize( c ), minimumWidth );
|
||||
}
|
||||
protected Insets getPadding() {
|
||||
Insets padding = super.getPadding();
|
||||
if( !isCapsLockVisible() )
|
||||
return padding;
|
||||
|
||||
@Override
|
||||
public Dimension getMinimumSize( JComponent c ) {
|
||||
return FlatTextFieldUI.applyMinimumWidth( c, super.getMinimumSize( c ), minimumWidth );
|
||||
boolean ltr = getComponent().getComponentOrientation().isLeftToRight();
|
||||
int iconWidth = capsLockIcon.getIconWidth();
|
||||
return FlatUIUtils.addInsets( padding, new Insets( 0, ltr ? 0 : iconWidth, 0, ltr ? iconWidth : 0 ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,12 +20,16 @@ import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.GraphicsDevice;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.Insets;
|
||||
import java.awt.MouseInfo;
|
||||
import java.awt.Panel;
|
||||
import java.awt.Point;
|
||||
import java.awt.PointerInfo;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.Window;
|
||||
import java.awt.event.ComponentEvent;
|
||||
import java.awt.event.ComponentListener;
|
||||
@@ -40,6 +44,7 @@ import javax.swing.Popup;
|
||||
import javax.swing.PopupFactory;
|
||||
import javax.swing.RootPaneContainer;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.ToolTipManager;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.border.Border;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
@@ -63,7 +68,7 @@ public class FlatPopupFactory
|
||||
public Popup getPopup( Component owner, Component contents, int x, int y )
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
Point pt = fixToolTipLocation( contents, x, y );
|
||||
Point pt = fixToolTipLocation( owner, contents, x, y );
|
||||
if( pt != null ) {
|
||||
x = pt.x;
|
||||
y = pt.y;
|
||||
@@ -207,13 +212,13 @@ public class FlatPopupFactory
|
||||
/**
|
||||
* Usually ToolTipManager places a tooltip at (mouseLocation.x, mouseLocation.y + 20).
|
||||
* In case that the tooltip would be partly outside of the screen,
|
||||
* ToolTipManagerthe changes the location so that the entire tooltip fits on screen.
|
||||
* the ToolTipManager changes the location so that the entire tooltip fits on screen.
|
||||
* But this can place the tooltip under the mouse location and hide the owner component.
|
||||
* <p>
|
||||
* This method checks whether the current mouse location is within tooltip bounds
|
||||
* and corrects the y-location so that the tooltip is placed above the mouse location.
|
||||
*/
|
||||
private Point fixToolTipLocation( Component contents, int x, int y ) {
|
||||
private Point fixToolTipLocation( Component owner, Component contents, int x, int y ) {
|
||||
if( !(contents instanceof JToolTip) || !wasInvokedFromToolTipManager() )
|
||||
return null;
|
||||
|
||||
@@ -229,18 +234,34 @@ public class FlatPopupFactory
|
||||
if( !tipBounds.contains( mouseLocation ) )
|
||||
return null;
|
||||
|
||||
// place tooltip above mouse location
|
||||
return new Point( x, mouseLocation.y - tipSize.height - UIScale.scale( 20 ) );
|
||||
// find GraphicsConfiguration at mouse location (similar to ToolTipManager.getDrawingGC())
|
||||
GraphicsConfiguration gc = null;
|
||||
for( GraphicsDevice device : GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices() ) {
|
||||
GraphicsConfiguration dgc = device.getDefaultConfiguration();
|
||||
if( dgc.getBounds().contains( mouseLocation ) ) {
|
||||
gc = dgc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( gc == null )
|
||||
gc = owner.getGraphicsConfiguration();
|
||||
if( gc == null )
|
||||
return null;
|
||||
|
||||
Rectangle screenBounds = gc.getBounds();
|
||||
Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets( gc );
|
||||
int screenTop = screenBounds.y + screenInsets.top;
|
||||
|
||||
// place tooltip above mouse location if there is enough space
|
||||
int newY = mouseLocation.y - tipSize.height - UIScale.scale( 20 );
|
||||
if( newY < screenTop )
|
||||
return null;
|
||||
|
||||
return new Point( x, newY );
|
||||
}
|
||||
|
||||
private boolean wasInvokedFromToolTipManager() {
|
||||
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
|
||||
for( StackTraceElement stackTraceElement : stackTrace ) {
|
||||
if( "javax.swing.ToolTipManager".equals( stackTraceElement.getClassName() ) &&
|
||||
"showTipWindow".equals( stackTraceElement.getMethodName() ) )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return StackUtils.wasInvokedFrom( ToolTipManager.class.getName(), "showTipWindow", 8 );
|
||||
}
|
||||
|
||||
//---- class NonFlashingPopup ---------------------------------------------
|
||||
@@ -468,6 +489,9 @@ public class FlatPopupFactory
|
||||
JLayeredPane layeredPane = ((RootPaneContainer)window).getLayeredPane();
|
||||
layeredPane.add( dropShadowPanel, JLayeredPane.POPUP_LAYER, 0 );
|
||||
|
||||
moveMediumWeightDropShadow();
|
||||
resizeMediumWeightDropShadow();
|
||||
|
||||
mediumPanelListener = new ComponentListener() {
|
||||
@Override
|
||||
public void componentShown( ComponentEvent e ) {
|
||||
@@ -483,17 +507,12 @@ public class FlatPopupFactory
|
||||
|
||||
@Override
|
||||
public void componentMoved( ComponentEvent e ) {
|
||||
if( dropShadowPanel != null && mediumWeightPanel != null ) {
|
||||
Point location = mediumWeightPanel.getLocation();
|
||||
Insets insets = dropShadowPanel.getInsets();
|
||||
dropShadowPanel.setLocation( location.x - insets.left, location.y - insets.top );
|
||||
}
|
||||
moveMediumWeightDropShadow();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentResized( ComponentEvent e ) {
|
||||
if( dropShadowPanel != null )
|
||||
dropShadowPanel.setSize( FlatUIUtils.addInsets( mediumWeightPanel.getSize(), dropShadowPanel.getInsets() ) );
|
||||
resizeMediumWeightDropShadow();
|
||||
}
|
||||
};
|
||||
mediumWeightPanel.addComponentListener( mediumPanelListener );
|
||||
@@ -509,5 +528,18 @@ public class FlatPopupFactory
|
||||
parent.repaint( bounds.x, bounds.y, bounds.width, bounds.height );
|
||||
}
|
||||
}
|
||||
|
||||
private void moveMediumWeightDropShadow() {
|
||||
if( dropShadowPanel != null && mediumWeightPanel != null ) {
|
||||
Point location = mediumWeightPanel.getLocation();
|
||||
Insets insets = dropShadowPanel.getInsets();
|
||||
dropShadowPanel.setLocation( location.x - insets.left, location.y - insets.top );
|
||||
}
|
||||
}
|
||||
|
||||
private void resizeMediumWeightDropShadow() {
|
||||
if( dropShadowPanel != null && mediumWeightPanel != null )
|
||||
dropShadowPanel.setSize( FlatUIUtils.addInsets( mediumWeightPanel.getSize(), dropShadowPanel.getInsets() ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,8 +24,8 @@ import javax.swing.plaf.ComponentUI;
|
||||
*
|
||||
* <!-- BasicSeparatorUI -->
|
||||
*
|
||||
* @uiDefault PopupMenuSeparator.background Color unused
|
||||
* @uiDefault PopupMenuSeparator.foreground Color
|
||||
* @uiDefault Separator.background Color unused
|
||||
* @uiDefault Separator.foreground Color
|
||||
*
|
||||
* <!-- FlatSeparatorUI -->
|
||||
*
|
||||
|
||||
@@ -27,7 +27,11 @@ import java.awt.Insets;
|
||||
import java.awt.LayoutManager;
|
||||
import java.awt.LayoutManager2;
|
||||
import java.awt.Window;
|
||||
import java.awt.event.ComponentAdapter;
|
||||
import java.awt.event.ComponentEvent;
|
||||
import java.awt.event.ComponentListener;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.function.Function;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JDialog;
|
||||
@@ -36,6 +40,7 @@ import javax.swing.JLayeredPane;
|
||||
import javax.swing.JMenuBar;
|
||||
import javax.swing.JRootPane;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.plaf.BorderUIResource;
|
||||
@@ -79,6 +84,8 @@ public class FlatRootPaneUI
|
||||
|
||||
private Object nativeWindowBorderData;
|
||||
private LayoutManager oldLayout;
|
||||
private PropertyChangeListener ancestorListener;
|
||||
private ComponentListener componentListener;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatRootPaneUI();
|
||||
@@ -136,6 +143,61 @@ public class FlatRootPaneUI
|
||||
c.putClientProperty( "jetbrains.awt.windowDarkAppearance", FlatLaf.isLafDark() );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installListeners( JRootPane root ) {
|
||||
super.installListeners( root );
|
||||
|
||||
if( SystemInfo.isJava_9_orLater ) {
|
||||
// On HiDPI screens, where scaling is used, there may be white lines at the
|
||||
// bottom and at the right side of the window when it is initially shown.
|
||||
// This is very disturbing in dark themes, but hard to notice in light themes.
|
||||
// Seems to be a rounding issue when Swing adds dirty region of window
|
||||
// using RepaintManager.nativeAddDirtyRegion().
|
||||
//
|
||||
// Note: Not using a HierarchyListener here, which would be much easier,
|
||||
// because this causes problems with mouse clicks in heavy-weight popups.
|
||||
// Instead, add a listener to the root pane that waits until it is added
|
||||
// to a window, then add a component listener to the window.
|
||||
// See: https://github.com/JFormDesigner/FlatLaf/issues/371
|
||||
ancestorListener = e -> {
|
||||
Object oldValue = e.getOldValue();
|
||||
Object newValue = e.getNewValue();
|
||||
if( newValue instanceof Window ) {
|
||||
if( componentListener == null ) {
|
||||
componentListener = new ComponentAdapter() {
|
||||
@Override
|
||||
public void componentShown( ComponentEvent e ) {
|
||||
// add whole root pane to dirty regions when window is initially shown
|
||||
root.getParent().repaint( root.getX(), root.getY(), root.getWidth(), root.getHeight() );
|
||||
}
|
||||
};
|
||||
}
|
||||
((Window)newValue).addComponentListener( componentListener );
|
||||
} else if( newValue == null && oldValue instanceof Window ) {
|
||||
if( componentListener != null )
|
||||
((Window)oldValue).removeComponentListener( componentListener );
|
||||
}
|
||||
};
|
||||
root.addPropertyChangeListener( "ancestor", ancestorListener );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void uninstallListeners( JRootPane root ) {
|
||||
super.uninstallListeners( root );
|
||||
|
||||
if( SystemInfo.isJava_9_orLater ) {
|
||||
if( componentListener != null ) {
|
||||
Window window = SwingUtilities.windowForComponent( root );
|
||||
if( window != null )
|
||||
window.removeComponentListener( componentListener );
|
||||
componentListener = null;
|
||||
}
|
||||
root.removePropertyChangeListener( "ancestor", ancestorListener );
|
||||
ancestorListener = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.1.2
|
||||
*/
|
||||
@@ -306,7 +368,7 @@ public class FlatRootPaneUI
|
||||
? getSizeFunc.apply( rootPane.getContentPane() )
|
||||
: rootPane.getSize();
|
||||
|
||||
int width = Math.max( titlePaneSize.width, contentSize.width );
|
||||
int width = contentSize.width; // title pane width is not considered here
|
||||
int height = titlePaneSize.height + contentSize.height;
|
||||
if( titlePane == null || !titlePane.isMenuBarEmbedded() ) {
|
||||
JMenuBar menuBar = rootPane.getJMenuBar();
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.formdev.flatlaf.ui;
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Insets;
|
||||
import java.awt.KeyboardFocusManager;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.event.ContainerEvent;
|
||||
import java.awt.event.ContainerListener;
|
||||
@@ -34,11 +35,13 @@ import javax.swing.JComponent;
|
||||
import javax.swing.JScrollBar;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTable;
|
||||
import javax.swing.JTree;
|
||||
import javax.swing.JViewport;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.ScrollPaneConstants;
|
||||
import javax.swing.Scrollable;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicScrollPaneUI;
|
||||
@@ -329,6 +332,31 @@ public class FlatScrollPaneUI
|
||||
paint( g, c );
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.3
|
||||
*/
|
||||
public static boolean isPermanentFocusOwner( JScrollPane scrollPane ) {
|
||||
JViewport viewport = scrollPane.getViewport();
|
||||
Component view = (viewport != null) ? viewport.getView() : null;
|
||||
if( view == null )
|
||||
return false;
|
||||
|
||||
// check whether view is focus owner
|
||||
if( FlatUIUtils.isPermanentFocusOwner( view ) )
|
||||
return true;
|
||||
|
||||
// check whether editor component in JTable or JTree is focus owner
|
||||
if( (view instanceof JTable && ((JTable)view).isEditing()) ||
|
||||
(view instanceof JTree && ((JTree)view).isEditing()) )
|
||||
{
|
||||
Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
|
||||
if( focusOwner != null )
|
||||
return SwingUtilities.isDescendingFrom( focusOwner, view );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//---- class Handler ------------------------------------------------------
|
||||
|
||||
/**
|
||||
@@ -350,11 +378,13 @@ public class FlatScrollPaneUI
|
||||
|
||||
@Override
|
||||
public void focusGained( FocusEvent e ) {
|
||||
// necessary to update focus border
|
||||
scrollpane.repaint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void focusLost( FocusEvent e ) {
|
||||
// necessary to update focus border
|
||||
scrollpane.repaint();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,9 +18,11 @@ package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.FontMetrics;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Shape;
|
||||
import java.awt.event.MouseEvent;
|
||||
@@ -176,9 +178,27 @@ public class FlatSliderUI
|
||||
if( slider.getOrientation() == JSlider.VERTICAL )
|
||||
return -1;
|
||||
|
||||
// use default font (instead of slider font) because the slider font size
|
||||
// may be different to label font size, but we want align the track/thumb with labels
|
||||
Font font = UIManager.getFont( "defaultFont" );
|
||||
if( font == null )
|
||||
font = slider.getFont();
|
||||
FontMetrics fm = slider.getFontMetrics( font );
|
||||
|
||||
// calculate track y coordinate and height
|
||||
// (not using field trackRect here because slider size may be [0,0]
|
||||
// and field trackRect may have invalid values in this case)
|
||||
Insets insets = slider.getInsets();
|
||||
int thumbHeight = getThumbSize().height;
|
||||
int contentHeight = height - insets.top - insets.bottom - focusInsets.top - focusInsets.bottom;
|
||||
int centerSpacing = thumbHeight
|
||||
+ (slider.getPaintTicks() ? getTickLength() : 0)
|
||||
+ (slider.getPaintLabels() ? getHeightOfTallestLabel() : 0);
|
||||
int trackY = insets.top + focusInsets.top + (contentHeight - centerSpacing - 1) / 2;
|
||||
int trackHeight = thumbHeight;
|
||||
|
||||
// compute a baseline so that the track is vertically centered
|
||||
FontMetrics fm = slider.getFontMetrics( slider.getFont() );
|
||||
return trackRect.y + Math.round( (trackRect.height - fm.getHeight()) / 2f ) + fm.getAscent() - 1;
|
||||
return trackY + Math.round( (trackHeight - fm.getHeight()) / 2f ) + fm.getAscent() - 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.FontMetrics;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Insets;
|
||||
@@ -39,6 +40,7 @@ import javax.swing.LookAndFeel;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.UIResource;
|
||||
import javax.swing.plaf.basic.BasicSpinnerUI;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
|
||||
@@ -65,6 +67,7 @@ import com.formdev.flatlaf.FlatClientProperties;
|
||||
* @uiDefault Component.disabledBorderColor Color
|
||||
* @uiDefault Spinner.disabledBackground Color
|
||||
* @uiDefault Spinner.disabledForeground Color
|
||||
* @uiDefault Spinner.focusedBackground Color optional
|
||||
* @uiDefault Spinner.buttonBackground Color
|
||||
* @uiDefault Spinner.buttonArrowColor Color
|
||||
* @uiDefault Spinner.buttonDisabledArrowColor Color
|
||||
@@ -87,6 +90,7 @@ public class FlatSpinnerUI
|
||||
protected Color disabledBorderColor;
|
||||
protected Color disabledBackground;
|
||||
protected Color disabledForeground;
|
||||
protected Color focusedBackground;
|
||||
protected Color buttonBackground;
|
||||
protected Color buttonArrowColor;
|
||||
protected Color buttonDisabledArrowColor;
|
||||
@@ -112,6 +116,7 @@ public class FlatSpinnerUI
|
||||
disabledBorderColor = UIManager.getColor( "Component.disabledBorderColor" );
|
||||
disabledBackground = UIManager.getColor( "Spinner.disabledBackground" );
|
||||
disabledForeground = UIManager.getColor( "Spinner.disabledForeground" );
|
||||
focusedBackground = UIManager.getColor( "Spinner.focusedBackground" );
|
||||
buttonBackground = UIManager.getColor( "Spinner.buttonBackground" );
|
||||
buttonArrowColor = UIManager.getColor( "Spinner.buttonArrowColor" );
|
||||
buttonDisabledArrowColor = UIManager.getColor( "Spinner.buttonDisabledArrowColor" );
|
||||
@@ -119,9 +124,6 @@ public class FlatSpinnerUI
|
||||
buttonPressedArrowColor = UIManager.getColor( "Spinner.buttonPressedArrowColor" );
|
||||
padding = UIManager.getInsets( "Spinner.padding" );
|
||||
|
||||
// scale
|
||||
padding = scale( padding );
|
||||
|
||||
MigLayoutVisualPadding.install( spinner );
|
||||
}
|
||||
|
||||
@@ -133,6 +135,7 @@ public class FlatSpinnerUI
|
||||
disabledBorderColor = null;
|
||||
disabledBackground = null;
|
||||
disabledForeground = null;
|
||||
focusedBackground = null;
|
||||
buttonBackground = null;
|
||||
buttonArrowColor = null;
|
||||
buttonDisabledArrowColor = null;
|
||||
@@ -172,14 +175,7 @@ public class FlatSpinnerUI
|
||||
@Override
|
||||
protected JComponent createEditor() {
|
||||
JComponent editor = super.createEditor();
|
||||
|
||||
// explicitly make non-opaque
|
||||
editor.setOpaque( false );
|
||||
JTextField textField = getEditorTextField( editor );
|
||||
if( textField != null )
|
||||
textField.setOpaque( false );
|
||||
|
||||
updateEditorColors();
|
||||
configureEditor( editor );
|
||||
return editor;
|
||||
}
|
||||
|
||||
@@ -187,8 +183,21 @@ public class FlatSpinnerUI
|
||||
protected void replaceEditor( JComponent oldEditor, JComponent newEditor ) {
|
||||
super.replaceEditor( oldEditor, newEditor );
|
||||
|
||||
configureEditor( newEditor );
|
||||
|
||||
removeEditorFocusListener( oldEditor );
|
||||
addEditorFocusListener( newEditor );
|
||||
}
|
||||
|
||||
/** @since 1.6 */
|
||||
protected void configureEditor( JComponent editor ) {
|
||||
// explicitly make non-opaque
|
||||
editor.setOpaque( false );
|
||||
JTextField textField = getEditorTextField( editor );
|
||||
if( textField != null )
|
||||
textField.setOpaque( false );
|
||||
|
||||
updateEditorPadding();
|
||||
updateEditorColors();
|
||||
}
|
||||
|
||||
@@ -204,6 +213,12 @@ public class FlatSpinnerUI
|
||||
textField.removeFocusListener( getHandler() );
|
||||
}
|
||||
|
||||
private void updateEditorPadding() {
|
||||
JTextField textField = getEditorTextField( spinner.getEditor() );
|
||||
if( textField != null )
|
||||
textField.putClientProperty( FlatClientProperties.TEXT_FIELD_PADDING, padding );
|
||||
}
|
||||
|
||||
private void updateEditorColors() {
|
||||
JTextField textField = getEditorTextField( spinner.getEditor() );
|
||||
if( textField != null ) {
|
||||
@@ -221,10 +236,34 @@ public class FlatSpinnerUI
|
||||
: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.3
|
||||
*/
|
||||
public static boolean isPermanentFocusOwner( JSpinner spinner ) {
|
||||
if( FlatUIUtils.isPermanentFocusOwner( spinner ) )
|
||||
return true;
|
||||
|
||||
JTextField textField = getEditorTextField( spinner.getEditor() );
|
||||
return (textField != null)
|
||||
? FlatUIUtils.isPermanentFocusOwner( textField )
|
||||
: false;
|
||||
}
|
||||
|
||||
protected Color getBackground( boolean enabled ) {
|
||||
return enabled
|
||||
? spinner.getBackground()
|
||||
: (isIntelliJTheme ? FlatUIUtils.getParentBackground( spinner ) : disabledBackground);
|
||||
if( enabled ) {
|
||||
Color background = spinner.getBackground();
|
||||
|
||||
// always use explicitly set color
|
||||
if( !(background instanceof UIResource) )
|
||||
return background;
|
||||
|
||||
// focused
|
||||
if( focusedBackground != null && isPermanentFocusOwner( spinner ) )
|
||||
return focusedBackground;
|
||||
|
||||
return background;
|
||||
} else
|
||||
return isIntelliJTheme ? FlatUIUtils.getParentBackground( spinner ) : disabledBackground;
|
||||
}
|
||||
|
||||
protected Color getForeground( boolean enabled ) {
|
||||
@@ -250,7 +289,7 @@ public class FlatSpinnerUI
|
||||
FlatArrowButton button = new FlatArrowButton( direction, arrowType, buttonArrowColor,
|
||||
buttonDisabledArrowColor, buttonHoverArrowColor, null, buttonPressedArrowColor, null );
|
||||
button.setName( name );
|
||||
button.setYOffset( (direction == SwingConstants.NORTH) ? 1 : -1 );
|
||||
button.setYOffset( (direction == SwingConstants.NORTH) ? 1.25f : -1.25f );
|
||||
if( direction == SwingConstants.NORTH )
|
||||
installNextButtonListeners( button );
|
||||
else
|
||||
@@ -344,6 +383,7 @@ public class FlatSpinnerUI
|
||||
@Override
|
||||
public Dimension preferredLayoutSize( Container parent ) {
|
||||
Insets insets = parent.getInsets();
|
||||
Insets padding = scale( FlatSpinnerUI.this.padding );
|
||||
Dimension editorSize = (editor != null) ? editor.getPreferredSize() : new Dimension( 0, 0 );
|
||||
|
||||
// the arrows width is the same as the inner height so that the arrows area is square
|
||||
@@ -368,15 +408,19 @@ public class FlatSpinnerUI
|
||||
|
||||
if( nextButton == null && previousButton == null ) {
|
||||
if( editor != null )
|
||||
editor.setBounds( FlatUIUtils.subtractInsets( r, padding ) );
|
||||
editor.setBounds( r );
|
||||
return;
|
||||
}
|
||||
|
||||
Rectangle editorRect = new Rectangle( r );
|
||||
Rectangle buttonsRect = new Rectangle( r );
|
||||
|
||||
// limit buttons width to height of a raw spinner (without insets)
|
||||
FontMetrics fm = spinner.getFontMetrics( spinner.getFont() );
|
||||
int maxButtonWidth = fm.getHeight() + scale( padding.top ) + scale( padding.bottom );
|
||||
|
||||
// make button area square (if spinner has preferred height)
|
||||
int buttonsWidth = parent.getPreferredSize().height - insets.top - insets.bottom;
|
||||
int buttonsWidth = Math.min( parent.getPreferredSize().height - insets.top - insets.bottom, maxButtonWidth );
|
||||
buttonsRect.width = buttonsWidth;
|
||||
|
||||
if( parent.getComponentOrientation().isLeftToRight() ) {
|
||||
@@ -388,7 +432,7 @@ public class FlatSpinnerUI
|
||||
}
|
||||
|
||||
if( editor != null )
|
||||
editor.setBounds( FlatUIUtils.subtractInsets( editorRect, padding ) );
|
||||
editor.setBounds( editorRect );
|
||||
|
||||
int nextHeight = (buttonsRect.height / 2) + (buttonsRect.height % 2); // round up
|
||||
if( nextButton != null )
|
||||
@@ -405,6 +449,7 @@ public class FlatSpinnerUI
|
||||
|
||||
@Override
|
||||
public void focusGained( FocusEvent e ) {
|
||||
// necessary to update focus border
|
||||
spinner.repaint();
|
||||
|
||||
// if spinner gained focus, transfer it to the editor text field
|
||||
@@ -417,6 +462,7 @@ public class FlatSpinnerUI
|
||||
|
||||
@Override
|
||||
public void focusLost( FocusEvent e ) {
|
||||
// necessary to update focus border
|
||||
spinner.repaint();
|
||||
}
|
||||
|
||||
|
||||
@@ -842,6 +842,17 @@ public class FlatTabbedPaneUI
|
||||
paintTabArea( g, tabPlacement, selectedIndex );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintTabArea( Graphics g, int tabPlacement, int selectedIndex ) {
|
||||
// need to set rendering hints here too because this method is also invoked
|
||||
// from BasicTabbedPaneUI.ScrollableTabPanel.paintComponent()
|
||||
Object[] oldHints = FlatUIUtils.setRenderingHints( g );
|
||||
|
||||
super.paintTabArea( g, tabPlacement, selectedIndex );
|
||||
|
||||
FlatUIUtils.resetRenderingHints( g, oldHints );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintTab( Graphics g, int tabPlacement, Rectangle[] rects,
|
||||
int tabIndex, Rectangle iconRect, Rectangle textRect )
|
||||
|
||||
@@ -24,6 +24,7 @@ import java.awt.Graphics2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import javax.swing.JScrollBar;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JViewport;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.table.JTableHeader;
|
||||
@@ -44,6 +45,7 @@ public class FlatTableHeaderBorder
|
||||
{
|
||||
protected Color separatorColor = UIManager.getColor( "TableHeader.separatorColor" );
|
||||
protected Color bottomSeparatorColor = UIManager.getColor( "TableHeader.bottomSeparatorColor" );
|
||||
/** @since 1.6 */ protected boolean showTrailingVerticalLine = UIManager.getBoolean( "TableHeader.showTrailingVerticalLine" );
|
||||
|
||||
public FlatTableHeaderBorder() {
|
||||
super( UIManager.getInsets( "TableHeader.cellMargins" ) );
|
||||
@@ -108,12 +110,23 @@ public class FlatTableHeaderBorder
|
||||
}
|
||||
|
||||
protected boolean hideTrailingVerticalLine( JTableHeader header ) {
|
||||
if( showTrailingVerticalLine )
|
||||
return false;
|
||||
|
||||
// do not hide if table header is not a child of a scroll pane
|
||||
Container viewport = header.getParent();
|
||||
Container viewportParent = (viewport != null) ? viewport.getParent() : null;
|
||||
if( !(viewportParent instanceof JScrollPane) )
|
||||
return true;
|
||||
return false;
|
||||
|
||||
JScrollBar vsb = ((JScrollPane)viewportParent).getVerticalScrollBar();
|
||||
// do not hide if table header is not the column header of the scroll pane
|
||||
JScrollPane scrollPane = (JScrollPane) viewportParent;
|
||||
JViewport columnHeader = scrollPane.getColumnHeader();
|
||||
if( viewport != columnHeader )
|
||||
return false;
|
||||
|
||||
// hide if vertical scroll bar is not shown
|
||||
JScrollBar vsb = scrollPane.getVerticalScrollBar();
|
||||
if( vsb == null || !vsb.isVisible() )
|
||||
return true;
|
||||
|
||||
|
||||
@@ -18,10 +18,13 @@ package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Cursor;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.util.Objects;
|
||||
import javax.swing.Icon;
|
||||
@@ -31,6 +34,7 @@ import javax.swing.JTable;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.event.MouseInputListener;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.UIResource;
|
||||
import javax.swing.plaf.basic.BasicTableHeaderUI;
|
||||
@@ -58,6 +62,7 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
* @uiDefault TableHeader.cellMargins Insets
|
||||
* @uiDefault TableHeader.separatorColor Color
|
||||
* @uiDefault TableHeader.bottomSeparatorColor Color
|
||||
* @uiDefault TableHeader.showTrailingVerticalLine boolean
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
@@ -94,6 +99,17 @@ public class FlatTableHeaderUI
|
||||
bottomSeparatorColor = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MouseInputListener createMouseInputListener() {
|
||||
return new FlatMouseInputHandler();
|
||||
}
|
||||
|
||||
// overridden and made public to allow usage in custom renderers
|
||||
@Override
|
||||
public int getRolloverColumn() {
|
||||
return super.getRolloverColumn();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paint( Graphics g, JComponent c ) {
|
||||
TableColumnModel columnModel = header.getColumnModel();
|
||||
@@ -246,4 +262,54 @@ public class FlatTableHeaderUI
|
||||
return (origBorder != null) ? origBorder.isBorderOpaque() : false;
|
||||
}
|
||||
}
|
||||
|
||||
//---- class FlatMouseInputHandler ----------------------------------------
|
||||
|
||||
/**
|
||||
* @since 1.6
|
||||
*/
|
||||
protected class FlatMouseInputHandler
|
||||
extends MouseInputHandler
|
||||
{
|
||||
Cursor oldCursor;
|
||||
|
||||
@Override
|
||||
public void mouseMoved( MouseEvent e ) {
|
||||
// restore old cursor, which is necessary because super.mouseMoved() swaps cursors
|
||||
if( oldCursor != null ) {
|
||||
header.setCursor( oldCursor );
|
||||
oldCursor = null;
|
||||
}
|
||||
|
||||
super.mouseMoved( e );
|
||||
|
||||
// if resizing last column is not possible, then Swing still shows a resize cursor,
|
||||
// which can be confusing for the user --> change cursor to standard cursor
|
||||
JTable table;
|
||||
int column;
|
||||
if( header.isEnabled() &&
|
||||
(table = header.getTable()) != null &&
|
||||
table.getAutoResizeMode() != JTable.AUTO_RESIZE_OFF &&
|
||||
header.getCursor() == Cursor.getPredefinedCursor( Cursor.E_RESIZE_CURSOR ) &&
|
||||
(column = header.columnAtPoint( e.getPoint() )) >= 0 &&
|
||||
column == header.getColumnModel().getColumnCount() - 1 )
|
||||
{
|
||||
// mouse is in last column
|
||||
Rectangle r = header.getHeaderRect( column );
|
||||
r.grow( -3, 0 );
|
||||
if( !r.contains( e.getX(), e.getY() ) ) {
|
||||
// mouse is in left or right resize area of last column
|
||||
boolean isResizeLastColumn = (e.getX() >= r.x + (r.width / 2));
|
||||
if( !header.getComponentOrientation().isLeftToRight() )
|
||||
isResizeLastColumn = !isResizeLastColumn;
|
||||
|
||||
if( isResizeLastColumn ) {
|
||||
// resize is not possible --> change cursor to standard cursor
|
||||
oldCursor = header.getCursor();
|
||||
header.setCursor( Cursor.getDefaultCursor() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import java.awt.Graphics2D;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.FocusListener;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JViewport;
|
||||
@@ -34,6 +35,7 @@ import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicTableUI;
|
||||
import javax.swing.table.JTableHeader;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.util.Graphics2DProxy;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
@@ -69,6 +71,7 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
* @uiDefault Table.rowHeight int
|
||||
* @uiDefault Table.showHorizontalLines boolean
|
||||
* @uiDefault Table.showVerticalLines boolean
|
||||
* @uiDefault Table.showTrailingVerticalLine boolean
|
||||
* @uiDefault Table.intercellSpacing Dimension
|
||||
* @uiDefault Table.selectionInactiveBackground Color
|
||||
* @uiDefault Table.selectionInactiveForeground Color
|
||||
@@ -90,6 +93,7 @@ public class FlatTableUI
|
||||
{
|
||||
protected boolean showHorizontalLines;
|
||||
protected boolean showVerticalLines;
|
||||
/** @since 1.6 */ protected boolean showTrailingVerticalLine;
|
||||
protected Dimension intercellSpacing;
|
||||
|
||||
protected Color selectionBackground;
|
||||
@@ -101,6 +105,8 @@ public class FlatTableUI
|
||||
private boolean oldShowVerticalLines;
|
||||
private Dimension oldIntercellSpacing;
|
||||
|
||||
private PropertyChangeListener propertyChangeListener;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatTableUI();
|
||||
}
|
||||
@@ -111,6 +117,7 @@ public class FlatTableUI
|
||||
|
||||
showHorizontalLines = UIManager.getBoolean( "Table.showHorizontalLines" );
|
||||
showVerticalLines = UIManager.getBoolean( "Table.showVerticalLines" );
|
||||
showTrailingVerticalLine = UIManager.getBoolean( "Table.showTrailingVerticalLine" );
|
||||
intercellSpacing = UIManager.getDimension( "Table.intercellSpacing" );
|
||||
|
||||
selectionBackground = UIManager.getColor( "Table.selectionBackground" );
|
||||
@@ -159,6 +166,25 @@ public class FlatTableUI
|
||||
table.setIntercellSpacing( oldIntercellSpacing );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installListeners() {
|
||||
super.installListeners();
|
||||
|
||||
propertyChangeListener = e -> {
|
||||
if( FlatClientProperties.COMPONENT_FOCUS_OWNER.equals( e.getPropertyName() ) )
|
||||
toggleSelectionColors();
|
||||
};
|
||||
table.addPropertyChangeListener( propertyChangeListener );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void uninstallListeners() {
|
||||
super.uninstallListeners();
|
||||
|
||||
table.removePropertyChangeListener( propertyChangeListener );
|
||||
propertyChangeListener = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FocusListener createFocusListener() {
|
||||
return new BasicTableUI.FocusHandler() {
|
||||
@@ -240,7 +266,7 @@ public class FlatTableUI
|
||||
if( isDragging &&
|
||||
SystemInfo.isJava_9_orLater &&
|
||||
((horizontalLines && y1 == y2) || (verticalLines && x1 == x2)) &&
|
||||
wasInvokedFromPaintDraggedArea() )
|
||||
wasInvokedFromMethod( "paintDraggedArea" ) )
|
||||
{
|
||||
if( y1 == y2 ) {
|
||||
// horizontal grid line
|
||||
@@ -282,22 +308,8 @@ public class FlatTableUI
|
||||
return wasInvokedFromMethod( "paintGrid" );
|
||||
}
|
||||
|
||||
private boolean wasInvokedFromPaintDraggedArea() {
|
||||
return wasInvokedFromMethod( "paintDraggedArea" );
|
||||
}
|
||||
|
||||
private boolean wasInvokedFromMethod( String methodName ) {
|
||||
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
|
||||
for( int i = 0; i < 10 || i < stackTrace.length; i++ ) {
|
||||
if( "javax.swing.plaf.basic.BasicTableUI".equals( stackTrace[i].getClassName() ) ) {
|
||||
String methodName2 = stackTrace[i].getMethodName();
|
||||
if( "paintCell".equals( methodName2 ) )
|
||||
return false;
|
||||
if( methodName.equals( methodName2 ) )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return StackUtils.wasInvokedFrom( BasicTableUI.class.getName(), methodName, 8 );
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -306,6 +318,10 @@ public class FlatTableUI
|
||||
}
|
||||
|
||||
protected boolean hideLastVerticalLine() {
|
||||
if( showTrailingVerticalLine )
|
||||
return false;
|
||||
|
||||
// do not hide if table is not a child of a scroll pane
|
||||
Container viewport = SwingUtilities.getUnwrappedParent( table );
|
||||
Container viewportParent = (viewport != null) ? viewport.getParent() : null;
|
||||
if( !(viewportParent instanceof JScrollPane) )
|
||||
|
||||
@@ -20,6 +20,8 @@ import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Insets;
|
||||
import java.awt.event.FocusListener;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JTextArea;
|
||||
@@ -52,6 +54,7 @@ import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
* @uiDefault Component.isIntelliJTheme boolean
|
||||
* @uiDefault TextArea.disabledBackground Color used if not enabled
|
||||
* @uiDefault TextArea.inactiveBackground Color used if not editable
|
||||
* @uiDefault TextArea.focusedBackground Color optional
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
@@ -63,6 +66,11 @@ public class FlatTextAreaUI
|
||||
protected Color background;
|
||||
protected Color disabledBackground;
|
||||
protected Color inactiveBackground;
|
||||
protected Color focusedBackground;
|
||||
|
||||
private Insets defaultMargin;
|
||||
|
||||
private FocusListener focusListener;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatTextAreaUI();
|
||||
@@ -84,6 +92,9 @@ public class FlatTextAreaUI
|
||||
background = UIManager.getColor( "TextArea.background" );
|
||||
disabledBackground = UIManager.getColor( "TextArea.disabledBackground" );
|
||||
inactiveBackground = UIManager.getColor( "TextArea.inactiveBackground" );
|
||||
focusedBackground = UIManager.getColor( "TextArea.focusedBackground" );
|
||||
|
||||
defaultMargin = UIManager.getInsets( "TextArea.margin" );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -93,6 +104,24 @@ public class FlatTextAreaUI
|
||||
background = null;
|
||||
disabledBackground = null;
|
||||
inactiveBackground = null;
|
||||
focusedBackground = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installListeners() {
|
||||
super.installListeners();
|
||||
|
||||
// necessary to update focus background
|
||||
focusListener = new FlatUIUtils.RepaintFocusListener( getComponent(), c -> focusedBackground != null );
|
||||
getComponent().addFocusListener( focusListener );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void uninstallListeners() {
|
||||
super.uninstallListeners();
|
||||
|
||||
getComponent().removeFocusListener( focusListener );
|
||||
focusListener = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -146,7 +175,7 @@ public class FlatTextAreaUI
|
||||
if( c instanceof JTextArea && ((JTextArea)c).getColumns() > 0 )
|
||||
return size;
|
||||
|
||||
return FlatEditorPaneUI.applyMinimumWidth( c, size, minimumWidth );
|
||||
return FlatEditorPaneUI.applyMinimumWidth( c, size, minimumWidth, defaultMargin );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -156,14 +185,6 @@ public class FlatTextAreaUI
|
||||
|
||||
@Override
|
||||
protected void paintBackground( Graphics g ) {
|
||||
JTextComponent c = getComponent();
|
||||
|
||||
// for compatibility with IntelliJ themes
|
||||
if( isIntelliJTheme && (!c.isEnabled() || !c.isEditable()) && (c.getBackground() instanceof UIResource) ) {
|
||||
FlatUIUtils.paintParentBackground( g, c );
|
||||
return;
|
||||
}
|
||||
|
||||
super.paintBackground( g );
|
||||
FlatEditorPaneUI.paintBackground( g, getComponent(), isIntelliJTheme, focusedBackground );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,8 +24,10 @@ import java.awt.FontMetrics;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.event.FocusListener;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.util.Objects;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JSpinner;
|
||||
@@ -40,6 +42,7 @@ import javax.swing.text.JTextComponent;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
import com.formdev.flatlaf.util.JavaCompatibility;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JTextField}.
|
||||
@@ -64,6 +67,7 @@ import com.formdev.flatlaf.util.JavaCompatibility;
|
||||
* @uiDefault Component.minimumWidth int
|
||||
* @uiDefault Component.isIntelliJTheme boolean
|
||||
* @uiDefault TextField.placeholderForeground Color
|
||||
* @uiDefault TextField.focusedBackground Color optional
|
||||
* @uiDefault TextComponent.selectAllOnFocusPolicy String never, once (default) or always
|
||||
* @uiDefault TextComponent.selectAllOnMouseClick boolean
|
||||
*
|
||||
@@ -75,6 +79,9 @@ public class FlatTextFieldUI
|
||||
protected int minimumWidth;
|
||||
protected boolean isIntelliJTheme;
|
||||
protected Color placeholderForeground;
|
||||
protected Color focusedBackground;
|
||||
|
||||
private Insets defaultMargin;
|
||||
|
||||
private FocusListener focusListener;
|
||||
|
||||
@@ -90,6 +97,9 @@ public class FlatTextFieldUI
|
||||
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
|
||||
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
|
||||
placeholderForeground = UIManager.getColor( prefix + ".placeholderForeground" );
|
||||
focusedBackground = UIManager.getColor( prefix + ".focusedBackground" );
|
||||
|
||||
defaultMargin = UIManager.getInsets( prefix + ".margin" );
|
||||
|
||||
LookAndFeel.installProperty( getComponent(), "opaque", false );
|
||||
|
||||
@@ -101,6 +111,7 @@ public class FlatTextFieldUI
|
||||
super.uninstallDefaults();
|
||||
|
||||
placeholderForeground = null;
|
||||
focusedBackground = null;
|
||||
|
||||
MigLayoutVisualPadding.uninstall( getComponent() );
|
||||
}
|
||||
@@ -109,7 +120,8 @@ public class FlatTextFieldUI
|
||||
protected void installListeners() {
|
||||
super.installListeners();
|
||||
|
||||
focusListener = new FlatUIUtils.RepaintFocusListener( getComponent() );
|
||||
// necessary to update focus border and background
|
||||
focusListener = new FlatUIUtils.RepaintFocusListener( getComponent(), null );
|
||||
getComponent().addFocusListener( focusListener );
|
||||
}
|
||||
|
||||
@@ -137,6 +149,7 @@ public class FlatTextFieldUI
|
||||
switch( e.getPropertyName() ) {
|
||||
case FlatClientProperties.PLACEHOLDER_TEXT:
|
||||
case FlatClientProperties.COMPONENT_ROUND_RECT:
|
||||
case FlatClientProperties.TEXT_FIELD_PADDING:
|
||||
c.repaint();
|
||||
break;
|
||||
|
||||
@@ -148,8 +161,8 @@ public class FlatTextFieldUI
|
||||
|
||||
@Override
|
||||
protected void paintSafely( Graphics g ) {
|
||||
paintBackground( g, getComponent(), isIntelliJTheme );
|
||||
paintPlaceholder( g, getComponent(), placeholderForeground );
|
||||
paintBackground( g, getComponent(), isIntelliJTheme, focusedBackground );
|
||||
paintPlaceholder( g );
|
||||
|
||||
super.paintSafely( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ) );
|
||||
}
|
||||
@@ -159,7 +172,7 @@ public class FlatTextFieldUI
|
||||
// background is painted elsewhere
|
||||
}
|
||||
|
||||
static void paintBackground( Graphics g, JTextComponent c, boolean isIntelliJTheme ) {
|
||||
static void paintBackground( Graphics g, JTextComponent c, boolean isIntelliJTheme, Color focusedBackground ) {
|
||||
// do not paint background if:
|
||||
// - not opaque and
|
||||
// - border is not a flat border and
|
||||
@@ -180,19 +193,34 @@ public class FlatTextFieldUI
|
||||
try {
|
||||
FlatUIUtils.setRenderingHints( g2 );
|
||||
|
||||
Color background = c.getBackground();
|
||||
g2.setColor( !(background instanceof UIResource)
|
||||
? background
|
||||
: (isIntelliJTheme && (!c.isEnabled() || !c.isEditable())
|
||||
? FlatUIUtils.getParentBackground( c )
|
||||
: background) );
|
||||
g2.setColor( getBackground( c, isIntelliJTheme, focusedBackground ) );
|
||||
FlatUIUtils.paintComponentBackground( g2, 0, 0, c.getWidth(), c.getHeight(), focusWidth, arc );
|
||||
} finally {
|
||||
g2.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
static void paintPlaceholder( Graphics g, JTextComponent c, Color placeholderForeground ) {
|
||||
static Color getBackground( JTextComponent c, boolean isIntelliJTheme, Color focusedBackground ) {
|
||||
Color background = c.getBackground();
|
||||
|
||||
// always use explicitly set color
|
||||
if( !(background instanceof UIResource) )
|
||||
return background;
|
||||
|
||||
// focused
|
||||
if( focusedBackground != null && FlatUIUtils.isPermanentFocusOwner( c ) )
|
||||
return focusedBackground;
|
||||
|
||||
// for compatibility with IntelliJ themes
|
||||
if( isIntelliJTheme && (!c.isEnabled() || !c.isEditable()) )
|
||||
return FlatUIUtils.getParentBackground( c );
|
||||
|
||||
return background;
|
||||
}
|
||||
|
||||
protected void paintPlaceholder( Graphics g ) {
|
||||
JTextComponent c = getComponent();
|
||||
|
||||
// check whether text component is empty
|
||||
if( c.getDocument().getLength() > 0 )
|
||||
return;
|
||||
@@ -207,15 +235,14 @@ public class FlatTextFieldUI
|
||||
return;
|
||||
|
||||
// compute placeholder location
|
||||
Insets insets = c.getInsets();
|
||||
Rectangle r = getVisibleEditorRect();
|
||||
FontMetrics fm = c.getFontMetrics( c.getFont() );
|
||||
int x = insets.left;
|
||||
int y = insets.top + fm.getAscent() + ((c.getHeight() - insets.top - insets.bottom - fm.getHeight()) / 2);
|
||||
String clippedPlaceholder = JavaCompatibility.getClippedString( c, fm, (String) placeholder, r.width );
|
||||
int x = r.x + (c.getComponentOrientation().isLeftToRight() ? 0 : r.width - fm.stringWidth( clippedPlaceholder ));
|
||||
int y = r.y + fm.getAscent() + ((r.height - fm.getHeight()) / 2);
|
||||
|
||||
// paint placeholder
|
||||
g.setColor( placeholderForeground );
|
||||
String clippedPlaceholder = JavaCompatibility.getClippedString( jc, fm,
|
||||
(String) placeholder, c.getWidth() - insets.left - insets.right );
|
||||
FlatUIUtils.drawString( c, g, clippedPlaceholder, x, y );
|
||||
}
|
||||
|
||||
@@ -229,11 +256,15 @@ public class FlatTextFieldUI
|
||||
return applyMinimumWidth( c, super.getMinimumSize( c ), minimumWidth );
|
||||
}
|
||||
|
||||
static Dimension applyMinimumWidth( JComponent c, Dimension size, int minimumWidth ) {
|
||||
private Dimension applyMinimumWidth( JComponent c, Dimension size, int minimumWidth ) {
|
||||
// do not apply minimum width if JTextField.columns is set
|
||||
if( c instanceof JTextField && ((JTextField)c).getColumns() > 0 )
|
||||
return size;
|
||||
|
||||
// do not apply minimum width if JTextComponent.margin is set
|
||||
if( !hasDefaultMargins( c, defaultMargin ) )
|
||||
return size;
|
||||
|
||||
// do not apply minimum width if used in combobox or spinner
|
||||
Container parent = c.getParent();
|
||||
if( parent instanceof JComboBox ||
|
||||
@@ -246,4 +277,41 @@ public class FlatTextFieldUI
|
||||
size.width = Math.max( size.width, scale( minimumWidth ) + Math.round( focusWidth * 2 ) );
|
||||
return size;
|
||||
}
|
||||
|
||||
static boolean hasDefaultMargins( JComponent c, Insets defaultMargin ) {
|
||||
Insets margin = ((JTextComponent)c).getMargin();
|
||||
return margin instanceof UIResource && Objects.equals( margin, defaultMargin );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Rectangle getVisibleEditorRect() {
|
||||
Rectangle r = super.getVisibleEditorRect();
|
||||
if( r != null ) {
|
||||
// remove padding
|
||||
Insets padding = getPadding();
|
||||
if( padding != null ) {
|
||||
r = FlatUIUtils.subtractInsets( r, padding );
|
||||
r.width = Math.max( r.width, 0 );
|
||||
r.height = Math.max( r.height, 0 );
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.4
|
||||
*/
|
||||
protected Insets getPadding() {
|
||||
Object padding = getComponent().getClientProperty( FlatClientProperties.TEXT_FIELD_PADDING );
|
||||
return (padding instanceof Insets) ? UIScale.scale( (Insets) padding ) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.4
|
||||
*/
|
||||
protected void scrollCaretToVisible() {
|
||||
Caret caret = getComponent().getCaret();
|
||||
if( caret instanceof FlatCaret )
|
||||
((FlatCaret)caret).scrollCaretToVisible();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,17 +16,18 @@
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Insets;
|
||||
import java.awt.event.FocusListener;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JEditorPane;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.UIResource;
|
||||
import javax.swing.plaf.basic.BasicTextPaneUI;
|
||||
import javax.swing.text.JTextComponent;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
|
||||
/**
|
||||
@@ -51,6 +52,7 @@ import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
*
|
||||
* @uiDefault Component.minimumWidth int
|
||||
* @uiDefault Component.isIntelliJTheme boolean
|
||||
* @uiDefault TextPane.focusedBackground Color optional
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
@@ -59,8 +61,12 @@ public class FlatTextPaneUI
|
||||
{
|
||||
protected int minimumWidth;
|
||||
protected boolean isIntelliJTheme;
|
||||
protected Color focusedBackground;
|
||||
|
||||
private Insets defaultMargin;
|
||||
|
||||
private Object oldHonorDisplayProperties;
|
||||
private FocusListener focusListener;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatTextPaneUI();
|
||||
@@ -70,8 +76,12 @@ public class FlatTextPaneUI
|
||||
protected void installDefaults() {
|
||||
super.installDefaults();
|
||||
|
||||
String prefix = getPropertyPrefix();
|
||||
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
|
||||
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
|
||||
focusedBackground = UIManager.getColor( prefix + ".focusedBackground" );
|
||||
|
||||
defaultMargin = UIManager.getInsets( prefix + ".margin" );
|
||||
|
||||
// use component font and foreground for HTML text
|
||||
oldHonorDisplayProperties = getComponent().getClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES );
|
||||
@@ -82,9 +92,28 @@ public class FlatTextPaneUI
|
||||
protected void uninstallDefaults() {
|
||||
super.uninstallDefaults();
|
||||
|
||||
focusedBackground = null;
|
||||
|
||||
getComponent().putClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES, oldHonorDisplayProperties );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installListeners() {
|
||||
super.installListeners();
|
||||
|
||||
// necessary to update focus background
|
||||
focusListener = new FlatUIUtils.RepaintFocusListener( getComponent(), c -> focusedBackground != null );
|
||||
getComponent().addFocusListener( focusListener );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void uninstallListeners() {
|
||||
super.uninstallListeners();
|
||||
|
||||
getComponent().removeFocusListener( focusListener );
|
||||
focusListener = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void propertyChange( PropertyChangeEvent e ) {
|
||||
super.propertyChange( e );
|
||||
@@ -93,12 +122,12 @@ public class FlatTextPaneUI
|
||||
|
||||
@Override
|
||||
public Dimension getPreferredSize( JComponent c ) {
|
||||
return FlatEditorPaneUI.applyMinimumWidth( c, super.getPreferredSize( c ), minimumWidth );
|
||||
return FlatEditorPaneUI.applyMinimumWidth( c, super.getPreferredSize( c ), minimumWidth, defaultMargin );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getMinimumSize( JComponent c ) {
|
||||
return FlatEditorPaneUI.applyMinimumWidth( c, super.getMinimumSize( c ), minimumWidth );
|
||||
return FlatEditorPaneUI.applyMinimumWidth( c, super.getMinimumSize( c ), minimumWidth, defaultMargin );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -108,14 +137,6 @@ public class FlatTextPaneUI
|
||||
|
||||
@Override
|
||||
protected void paintBackground( Graphics g ) {
|
||||
JTextComponent c = getComponent();
|
||||
|
||||
// for compatibility with IntelliJ themes
|
||||
if( isIntelliJTheme && (!c.isEnabled() || !c.isEditable()) && (c.getBackground() instanceof UIResource) ) {
|
||||
FlatUIUtils.paintParentBackground( g, c );
|
||||
return;
|
||||
}
|
||||
|
||||
super.paintBackground( g );
|
||||
FlatEditorPaneUI.paintBackground( g, getComponent(), isIntelliJTheme, focusedBackground );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.awt.event.ContainerEvent;
|
||||
import java.awt.event.ContainerListener;
|
||||
import javax.swing.AbstractButton;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicToolBarUI;
|
||||
@@ -41,15 +42,47 @@ import javax.swing.plaf.basic.BasicToolBarUI;
|
||||
* @uiDefault ToolBar.floatingForeground Color
|
||||
* @uiDefault ToolBar.isRollover boolean
|
||||
*
|
||||
* <!-- FlatToolBarUI -->
|
||||
*
|
||||
* @uiDefault ToolBar.focusableButtons boolean
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatToolBarUI
|
||||
extends BasicToolBarUI
|
||||
{
|
||||
/** @since 1.4 */
|
||||
protected boolean focusableButtons;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatToolBarUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void installUI( JComponent c ) {
|
||||
super.installUI( c );
|
||||
|
||||
// disable focusable state of buttons (when switching from another Laf)
|
||||
if( !focusableButtons )
|
||||
setButtonsFocusable( false );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uninstallUI( JComponent c ) {
|
||||
super.uninstallUI( c );
|
||||
|
||||
// re-enable focusable state of buttons (when switching to another Laf)
|
||||
if( !focusableButtons )
|
||||
setButtonsFocusable( true );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installDefaults() {
|
||||
super.installDefaults();
|
||||
|
||||
focusableButtons = UIManager.getBoolean( "ToolBar.focusableButtons" );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ContainerListener createToolBarContListener() {
|
||||
return new ToolBarContListener() {
|
||||
@@ -57,22 +90,36 @@ public class FlatToolBarUI
|
||||
public void componentAdded( ContainerEvent e ) {
|
||||
super.componentAdded( e );
|
||||
|
||||
if( !focusableButtons ) {
|
||||
Component c = e.getChild();
|
||||
if( c instanceof AbstractButton )
|
||||
c.setFocusable( false );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentRemoved( ContainerEvent e ) {
|
||||
super.componentRemoved( e );
|
||||
|
||||
if( !focusableButtons ) {
|
||||
Component c = e.getChild();
|
||||
if( c instanceof AbstractButton )
|
||||
c.setFocusable( true );
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.4
|
||||
*/
|
||||
protected void setButtonsFocusable( boolean focusable ) {
|
||||
for( Component c : toolBar.getComponents() ) {
|
||||
if( c instanceof AbstractButton )
|
||||
c.setFocusable( focusable );
|
||||
}
|
||||
}
|
||||
|
||||
// disable rollover border
|
||||
@Override protected void setBorderToRollover( Component c ) {}
|
||||
@Override protected void setBorderToNonRollover( Component c ) {}
|
||||
|
||||
@@ -230,6 +230,26 @@ public class FlatTreeUI
|
||||
tree.repaint( 0, r.y, tree.getWidth(), r.height );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rectangle getPathBounds( JTree tree, TreePath path ) {
|
||||
Rectangle bounds = super.getPathBounds( tree, path );
|
||||
|
||||
// If this method was invoked from JTree.getPathForLocation(int x, int y) to check whether
|
||||
// the location is within tree node bounds, then return the bounds of a wide node.
|
||||
// This changes the behavior of JTree.getPathForLocation(int x, int y) and
|
||||
// JTree.getRowForLocation(int x, int y), which now return the path/row even
|
||||
// if [x,y] is in the wide row area outside of the actual tree node.
|
||||
if( bounds != null &&
|
||||
isWideSelection() &&
|
||||
UIManager.getBoolean( "FlatLaf.experimental.tree.widePathForLocation" ) &&
|
||||
StackUtils.wasInvokedFrom( JTree.class.getName(), "getPathForLocation", 5 ) )
|
||||
{
|
||||
bounds.x = 0;
|
||||
bounds.width = tree.getWidth();
|
||||
}
|
||||
return bounds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as super.paintRow(), but supports wide selection and uses
|
||||
* inactive selection background/foreground if tree is not focused.
|
||||
|
||||
@@ -69,6 +69,7 @@ public class FlatUIUtils
|
||||
{
|
||||
public static final boolean MAC_USE_QUARTZ = Boolean.getBoolean( "apple.awt.graphics.UseQuartz" );
|
||||
|
||||
private static boolean useSharedUIs = true;
|
||||
private static WeakHashMap<LookAndFeel, IdentityHashMap<Object, ComponentUI>> sharedUIinstances = new WeakHashMap<>();
|
||||
|
||||
public static Rectangle addInsets( Rectangle r, Insets insets ) {
|
||||
@@ -94,6 +95,11 @@ public class FlatUIUtils
|
||||
}
|
||||
|
||||
public static Insets addInsets( Insets insets1, Insets insets2 ) {
|
||||
if( insets1 == null )
|
||||
return insets2;
|
||||
if( insets2 == null )
|
||||
return insets1;
|
||||
|
||||
return new Insets(
|
||||
insets1.top + insets2.top,
|
||||
insets1.left + insets2.left,
|
||||
@@ -660,7 +666,7 @@ public class FlatUIUtils
|
||||
* @since 1.1
|
||||
*/
|
||||
public static void paintArrow( Graphics2D g, int x, int y, int width, int height,
|
||||
int direction, boolean chevron, int arrowSize, int xOffset, int yOffset )
|
||||
int direction, boolean chevron, int arrowSize, float xOffset, float yOffset )
|
||||
{
|
||||
// compute arrow width/height
|
||||
int aw = UIScale.scale( arrowSize + (chevron ? 0 : 1) );
|
||||
@@ -679,8 +685,10 @@ public class FlatUIUtils
|
||||
int extra = chevron ? 1 : 0;
|
||||
|
||||
// compute arrow location
|
||||
int ax = x + Math.round( ((width - (aw + extra)) / 2f) + UIScale.scale( (float) xOffset ) );
|
||||
int ay = y + Math.round( ((height - (ah + extra)) / 2f) + UIScale.scale( (float) yOffset ) );
|
||||
float ox = ((width - (aw + extra)) / 2f) + UIScale.scale( xOffset );
|
||||
float oy = ((height - (ah + extra)) / 2f) + UIScale.scale( yOffset );
|
||||
int ax = x + ((direction == SwingConstants.WEST) ? -Math.round( -ox ) : Math.round( ox ));
|
||||
int ay = y + ((direction == SwingConstants.NORTH) ? -Math.round( -oy ) : Math.round( oy ));
|
||||
|
||||
// paint arrow
|
||||
g.translate( ax, ay );
|
||||
@@ -818,6 +826,27 @@ debug*/
|
||||
return explicitlySet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether shared UI delegates are used.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
public static boolean isUseSharedUIs() {
|
||||
return useSharedUIs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies whether shared UI delegates are used.
|
||||
* This does not change already existing UI delegates.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
public static boolean setUseSharedUIs( boolean useSharedUIs ) {
|
||||
boolean old = FlatUIUtils.useSharedUIs;
|
||||
FlatUIUtils.useSharedUIs = useSharedUIs;
|
||||
return old;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a shared component UI for the given key and the current Laf.
|
||||
* Each Laf instance has its own shared component UI instance.
|
||||
@@ -826,6 +855,9 @@ debug*/
|
||||
* may use multiple Laf instances at the same time.
|
||||
*/
|
||||
public static ComponentUI createSharedUI( Object key, Supplier<ComponentUI> newInstanceSupplier ) {
|
||||
if( !useSharedUIs )
|
||||
return newInstanceSupplier.get();
|
||||
|
||||
return sharedUIinstances
|
||||
.computeIfAbsent( UIManager.getLookAndFeel(), k -> new IdentityHashMap<>() )
|
||||
.computeIfAbsent( key, k -> newInstanceSupplier.get() );
|
||||
@@ -837,18 +869,22 @@ debug*/
|
||||
implements FocusListener
|
||||
{
|
||||
private final Component repaintComponent;
|
||||
private final Predicate<Component> repaintCondition;
|
||||
|
||||
public RepaintFocusListener( Component repaintComponent ) {
|
||||
public RepaintFocusListener( Component repaintComponent, Predicate<Component> repaintCondition ) {
|
||||
this.repaintComponent = repaintComponent;
|
||||
this.repaintCondition = repaintCondition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void focusGained( FocusEvent e ) {
|
||||
if( repaintCondition == null || repaintCondition.test( repaintComponent ) )
|
||||
repaintComponent.repaint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void focusLost( FocusEvent e ) {
|
||||
if( repaintCondition == null || repaintCondition.test( repaintComponent ) )
|
||||
repaintComponent.repaint();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,8 +181,12 @@ public abstract class FlatWindowResizer
|
||||
protected abstract boolean isWindowResizable();
|
||||
protected abstract Rectangle getWindowBounds();
|
||||
protected abstract void setWindowBounds( Rectangle r );
|
||||
protected abstract boolean limitToParentBounds();
|
||||
protected abstract Rectangle getParentBounds();
|
||||
protected abstract boolean honorMinimumSizeOnResize();
|
||||
protected abstract boolean honorMaximumSizeOnResize();
|
||||
protected abstract Dimension getWindowMinimumSize();
|
||||
protected abstract Dimension getWindowMaximumSize();
|
||||
|
||||
protected void beginResizing( int direction ) {}
|
||||
protected void endResizing() {}
|
||||
@@ -283,6 +287,16 @@ public abstract class FlatWindowResizer
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean limitToParentBounds() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Rectangle getParentBounds() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean honorMinimumSizeOnResize() {
|
||||
return
|
||||
@@ -290,11 +304,21 @@ public abstract class FlatWindowResizer
|
||||
(honorDialogMinimumSizeOnResize && window instanceof Dialog);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean honorMaximumSizeOnResize() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Dimension getWindowMinimumSize() {
|
||||
return window.getMinimumSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Dimension getWindowMaximumSize() {
|
||||
return window.getMaximumSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isDialog() {
|
||||
return window instanceof Dialog;
|
||||
@@ -354,16 +378,36 @@ public abstract class FlatWindowResizer
|
||||
desktopManager.get().resizeFrame( getFrame(), r.x, r.y, r.width, r.height );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean limitToParentBounds() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Rectangle getParentBounds() {
|
||||
return getFrame().getParent().getBounds();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean honorMinimumSizeOnResize() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean honorMaximumSizeOnResize() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Dimension getWindowMinimumSize() {
|
||||
return getFrame().getMinimumSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Dimension getWindowMaximumSize() {
|
||||
return getFrame().getMaximumSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void beginResizing( int direction ) {
|
||||
desktopManager.get().beginResizingFrame( getFrame(), direction );
|
||||
@@ -521,7 +565,7 @@ debug*/
|
||||
int xOnScreen = e.getXOnScreen();
|
||||
int yOnScreen = e.getYOnScreen();
|
||||
|
||||
// Get current window bounds and compute new bounds based them.
|
||||
// Get current window bounds and compute new bounds based on them.
|
||||
// This is necessary because window manager may alter window bounds while resizing.
|
||||
// E.g. when having two monitors with different scale factors and resizing
|
||||
// a window on first screen to the second screen, then the window manager may
|
||||
@@ -535,41 +579,72 @@ debug*/
|
||||
// top
|
||||
if( resizeDir == N_RESIZE_CURSOR || resizeDir == NW_RESIZE_CURSOR || resizeDir == NE_RESIZE_CURSOR ) {
|
||||
newBounds.y = yOnScreen - dragTopOffset;
|
||||
if( limitToParentBounds() && newBounds.y < 0 )
|
||||
newBounds.y = 0;
|
||||
newBounds.height += (oldBounds.y - newBounds.y);
|
||||
}
|
||||
|
||||
// bottom
|
||||
if( resizeDir == S_RESIZE_CURSOR || resizeDir == SW_RESIZE_CURSOR || resizeDir == SE_RESIZE_CURSOR )
|
||||
if( resizeDir == S_RESIZE_CURSOR || resizeDir == SW_RESIZE_CURSOR || resizeDir == SE_RESIZE_CURSOR ) {
|
||||
newBounds.height = (yOnScreen + dragBottomOffset) - newBounds.y;
|
||||
if( limitToParentBounds() ) {
|
||||
int parentHeight = getParentBounds().height;
|
||||
if( newBounds.y + newBounds.height > parentHeight )
|
||||
newBounds.height = parentHeight - newBounds.y;
|
||||
}
|
||||
}
|
||||
|
||||
// left
|
||||
if( resizeDir == W_RESIZE_CURSOR || resizeDir == NW_RESIZE_CURSOR || resizeDir == SW_RESIZE_CURSOR ) {
|
||||
newBounds.x = xOnScreen - dragLeftOffset;
|
||||
if( limitToParentBounds() && newBounds.x < 0 )
|
||||
newBounds.x = 0;
|
||||
newBounds.width += (oldBounds.x - newBounds.x);
|
||||
}
|
||||
|
||||
// right
|
||||
if( resizeDir == E_RESIZE_CURSOR || resizeDir == NE_RESIZE_CURSOR || resizeDir == SE_RESIZE_CURSOR )
|
||||
if( resizeDir == E_RESIZE_CURSOR || resizeDir == NE_RESIZE_CURSOR || resizeDir == SE_RESIZE_CURSOR ) {
|
||||
newBounds.width = (xOnScreen + dragRightOffset) - newBounds.x;
|
||||
if( limitToParentBounds() ) {
|
||||
int parentWidth = getParentBounds().width;
|
||||
if( newBounds.x + newBounds.width > parentWidth )
|
||||
newBounds.width = parentWidth - newBounds.x;
|
||||
}
|
||||
}
|
||||
|
||||
// apply minimum window size
|
||||
Dimension minimumSize = honorMinimumSizeOnResize() ? getWindowMinimumSize() : null;
|
||||
if( minimumSize == null )
|
||||
minimumSize = UIScale.scale( new Dimension( 150, 50 ) );
|
||||
if( newBounds.width < minimumSize.width ) {
|
||||
if( newBounds.x != oldBounds.x )
|
||||
newBounds.x -= (minimumSize.width - newBounds.width);
|
||||
newBounds.width = minimumSize.width;
|
||||
}
|
||||
if( newBounds.height < minimumSize.height ) {
|
||||
if( newBounds.y != oldBounds.y )
|
||||
newBounds.y -= (minimumSize.height - newBounds.height);
|
||||
newBounds.height = minimumSize.height;
|
||||
if( newBounds.width < minimumSize.width )
|
||||
changeWidth( oldBounds, newBounds, minimumSize.width );
|
||||
if( newBounds.height < minimumSize.height )
|
||||
changeHeight( oldBounds, newBounds, minimumSize.height );
|
||||
|
||||
// apply maximum window size
|
||||
if( honorMaximumSizeOnResize() ) {
|
||||
Dimension maximumSize = getWindowMaximumSize();
|
||||
if( newBounds.width > maximumSize.width )
|
||||
changeWidth( oldBounds, newBounds, maximumSize.width );
|
||||
if( newBounds.height > maximumSize.height )
|
||||
changeHeight( oldBounds, newBounds, maximumSize.height );
|
||||
}
|
||||
|
||||
// set window bounds
|
||||
if( !newBounds.equals( oldBounds ) )
|
||||
setWindowBounds( newBounds );
|
||||
}
|
||||
|
||||
private void changeWidth( Rectangle oldBounds, Rectangle newBounds, int width ) {
|
||||
if( newBounds.x != oldBounds.x )
|
||||
newBounds.x -= (width - newBounds.width);
|
||||
newBounds.width = width;
|
||||
}
|
||||
|
||||
private void changeHeight( Rectangle oldBounds, Rectangle newBounds, int height ) {
|
||||
if( newBounds.y != oldBounds.y )
|
||||
newBounds.y -= (height - newBounds.height);
|
||||
newBounds.height = height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@ import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Window;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.Collections;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.List;
|
||||
@@ -94,6 +96,11 @@ class FlatWindowsNativeWindowBorder
|
||||
// Java 9 and later does not have this problem.
|
||||
try {
|
||||
System.loadLibrary( "jawt" );
|
||||
} catch( UnsatisfiedLinkError ex ) {
|
||||
// log error only if native library jawt.dll not already loaded
|
||||
String message = ex.getMessage();
|
||||
if( message == null || !message.contains( "already loaded in another classloader" ) )
|
||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||
} catch( Exception ex ) {
|
||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||
}
|
||||
@@ -289,6 +296,7 @@ class FlatWindowsNativeWindowBorder
|
||||
//---- class WndProc ------------------------------------------------------
|
||||
|
||||
private class WndProc
|
||||
implements PropertyChangeListener
|
||||
{
|
||||
// WM_NCHITTEST mouse position codes
|
||||
private static final int
|
||||
@@ -313,18 +321,36 @@ class FlatWindowsNativeWindowBorder
|
||||
|
||||
// remove the OS window title bar
|
||||
updateFrame( hwnd, (window instanceof JFrame) ? ((JFrame)window).getExtendedState() : 0 );
|
||||
|
||||
// set window background (used when resizing window)
|
||||
updateWindowBackground();
|
||||
window.addPropertyChangeListener( "background", this );
|
||||
}
|
||||
|
||||
void uninstall() {
|
||||
window.removePropertyChangeListener( "background", this );
|
||||
|
||||
uninstallImpl( hwnd );
|
||||
|
||||
// cleanup
|
||||
window = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void propertyChange( PropertyChangeEvent e ) {
|
||||
updateWindowBackground();
|
||||
}
|
||||
|
||||
private void updateWindowBackground() {
|
||||
Color bg = window.getBackground();
|
||||
if( bg != null )
|
||||
setWindowBackground( hwnd, bg.getRed(), bg.getGreen(), bg.getBlue() );
|
||||
}
|
||||
|
||||
private native long installImpl( Window window );
|
||||
private native void uninstallImpl( long hwnd );
|
||||
private native void updateFrame( long hwnd, int state );
|
||||
private native void setWindowBackground( long hwnd, int r, int g, int b );
|
||||
private native void showWindow( long hwnd, int cmd );
|
||||
|
||||
// invoked from native code
|
||||
|
||||
@@ -70,9 +70,10 @@ public class JBRCustomDecorations
|
||||
return null;
|
||||
|
||||
// check whether root pane already has a parent, which is the case when switching LaF
|
||||
Window window = SwingUtilities.windowForComponent( rootPane );
|
||||
if( window != null ) {
|
||||
FlatNativeWindowBorder.install( window );
|
||||
Container parent = rootPane.getParent();
|
||||
if( parent != null ) {
|
||||
if( parent instanceof Window )
|
||||
FlatNativeWindowBorder.install( (Window) parent );
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -110,9 +111,9 @@ public class JBRCustomDecorations
|
||||
// since it is actually not possible to uninstall JBR decorations,
|
||||
// simply reduce titleBarHeight so that it is still possible to resize window
|
||||
// and remove hitTestSpots
|
||||
Window window = SwingUtilities.windowForComponent( rootPane );
|
||||
if( window != null )
|
||||
setHasCustomDecoration( window, false );
|
||||
Container parent = rootPane.getParent();
|
||||
if( parent instanceof Window )
|
||||
setHasCustomDecoration( (Window) parent, false );
|
||||
}
|
||||
|
||||
static boolean hasCustomDecoration( Window window ) {
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2021 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.ui;
|
||||
|
||||
import java.util.function.BiPredicate;
|
||||
|
||||
/**
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
class StackUtils
|
||||
{
|
||||
private static final StackUtils INSTANCE = new StackUtilsImpl();
|
||||
|
||||
// hide from javadoc
|
||||
StackUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether current method was invoked from the given class and method.
|
||||
*/
|
||||
public static boolean wasInvokedFrom( String className, String methodName, int limit ) {
|
||||
return wasInvokedFrom( (c,m) -> c.equals( className ) && m.equals( methodName ), limit );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether current method was invoked from a class and method using the given predicate,
|
||||
* which gets the class name of the stack frame as first parameter and the method name as second parameter.
|
||||
*/
|
||||
public static boolean wasInvokedFrom( BiPredicate<String, String> predicate, int limit ) {
|
||||
return INSTANCE.wasInvokedFromImpl( predicate, limit );
|
||||
}
|
||||
|
||||
boolean wasInvokedFromImpl( BiPredicate<String, String> predicate, int limit ) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2021 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.ui;
|
||||
|
||||
import java.util.function.BiPredicate;
|
||||
|
||||
/**
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
class StackUtilsImpl
|
||||
extends StackUtils
|
||||
{
|
||||
@Override
|
||||
boolean wasInvokedFromImpl( BiPredicate<String, String> predicate, int limit ) {
|
||||
int count = -2;
|
||||
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
|
||||
for( StackTraceElement stackTraceElement : stackTrace ) {
|
||||
if( predicate.test( stackTraceElement.getClassName(), stackTraceElement.getMethodName() ) )
|
||||
return true;
|
||||
|
||||
count++;
|
||||
if( limit > 0 && count > limit )
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -26,13 +26,16 @@ import java.awt.Color;
|
||||
public class ColorFunctions
|
||||
{
|
||||
public static Color applyFunctions( Color color, ColorFunction... functions ) {
|
||||
// convert RGB to HSL
|
||||
float[] hsl = HSLColor.fromRGB( color );
|
||||
float alpha = color.getAlpha() / 255f;
|
||||
float[] hsla = { hsl[0], hsl[1], hsl[2], alpha * 100 };
|
||||
|
||||
// apply color functions
|
||||
for( ColorFunction function : functions )
|
||||
function.apply( hsla );
|
||||
|
||||
// convert HSL to RGB
|
||||
return HSLColor.toRGB( hsla[0], hsla[1], hsla[2], hsla[3] / 100 );
|
||||
}
|
||||
|
||||
@@ -145,7 +148,46 @@ public class ColorFunctions
|
||||
}
|
||||
}
|
||||
|
||||
//---- class HSLIncreaseDecrease ------------------------------------------
|
||||
//---- class HSLChange ----------------------------------------------------
|
||||
|
||||
/**
|
||||
* Set the hue, saturation, luminance or alpha of a color.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
public static class HSLChange
|
||||
implements ColorFunction
|
||||
{
|
||||
public final int hslIndex;
|
||||
public final float value;
|
||||
|
||||
public HSLChange( int hslIndex, float value ) {
|
||||
this.hslIndex = hslIndex;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply( float[] hsla ) {
|
||||
hsla[hslIndex] = (hslIndex == 0)
|
||||
? value % 360
|
||||
: clamp( value );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String name;
|
||||
switch( hslIndex ) {
|
||||
case 0: name = "changeHue"; break;
|
||||
case 1: name = "changeSaturation"; break;
|
||||
case 2: name = "changeLightness"; break;
|
||||
case 3: name = "changeAlpha"; break;
|
||||
default: throw new IllegalArgumentException();
|
||||
}
|
||||
return String.format( "%s(%.0f%s)", name, value, (hslIndex == 0 ? "" : "%") );
|
||||
}
|
||||
}
|
||||
|
||||
//---- class Fade ---------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Set the alpha of a color.
|
||||
@@ -169,4 +211,42 @@ public class ColorFunctions
|
||||
return String.format( "fade(%.0f%%)", amount );
|
||||
}
|
||||
}
|
||||
|
||||
//---- class Mix ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Mix two colors.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
public static class Mix
|
||||
implements ColorFunction
|
||||
{
|
||||
public final Color color2;
|
||||
public final float weight;
|
||||
|
||||
public Mix( Color color2, float weight ) {
|
||||
this.color2 = color2;
|
||||
this.weight = weight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply( float[] hsla ) {
|
||||
// convert from HSL to RGB because color mixing is done on RGB values
|
||||
Color color1 = HSLColor.toRGB( hsla[0], hsla[1], hsla[2], hsla[3] / 100 );
|
||||
|
||||
// mix
|
||||
Color color = mix( color1, color2, weight / 100 );
|
||||
|
||||
// convert RGB to HSL
|
||||
float[] hsl = HSLColor.fromRGB( color );
|
||||
System.arraycopy( hsl, 0, hsla, 0, hsl.length );
|
||||
hsla[3] = (color.getAlpha() / 255f) * 100;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format( "mix(#%08x,%.0f%%)", color2.getRGB(), weight );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2021 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.ui;
|
||||
|
||||
import java.util.function.BiPredicate;
|
||||
|
||||
/**
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
class StackUtilsImpl
|
||||
extends StackUtils
|
||||
{
|
||||
@Override
|
||||
boolean wasInvokedFromImpl( BiPredicate<String, String> predicate, int limit ) {
|
||||
return StackWalker.getInstance().walk( stream -> {
|
||||
if( limit > 0 )
|
||||
stream = stream.limit( limit + 2 );
|
||||
return stream.anyMatch( f -> {
|
||||
return predicate.test( f.getClassName(), f.getMethodName() );
|
||||
} );
|
||||
} );
|
||||
}
|
||||
}
|
||||
@@ -514,6 +514,17 @@ ScrollPane.fillUpperCorner = true
|
||||
ScrollPane.smoothScrolling = true
|
||||
|
||||
|
||||
#---- SearchField ----
|
||||
|
||||
SearchField.searchIconColor = fadeout(Actions.GreyInline,10%,lazy)
|
||||
SearchField.searchIconHoverColor = fadeout(Actions.GreyInline,30%,lazy)
|
||||
SearchField.searchIconPressedColor = fadeout(Actions.GreyInline,50%,lazy)
|
||||
|
||||
SearchField.clearIconColor = fadeout(Actions.GreyInline,50%,lazy)
|
||||
SearchField.clearIconHoverColor = $SearchField.clearIconColor
|
||||
SearchField.clearIconPressedColor = fadeout(Actions.GreyInline,20%,lazy)
|
||||
|
||||
|
||||
#---- Separator ----
|
||||
|
||||
Separator.height = 3
|
||||
@@ -617,6 +628,7 @@ TabbedPane.closeCrossLineWidth = {float}1
|
||||
Table.rowHeight = 20
|
||||
Table.showHorizontalLines = false
|
||||
Table.showVerticalLines = false
|
||||
Table.showTrailingVerticalLine = false
|
||||
Table.consistentHomeEndKeyBehavior = true
|
||||
Table.intercellSpacing = {dimension}0,0
|
||||
Table.scrollPaneBorder = com.formdev.flatlaf.ui.FlatBorder
|
||||
@@ -646,7 +658,7 @@ TableHeader.cellBorder = com.formdev.flatlaf.ui.FlatTableHeaderBorder
|
||||
TableHeader.cellMargins = 2,3,2,3
|
||||
TableHeader.focusCellBackground = $TableHeader.background
|
||||
TableHeader.background = @textComponentBackground
|
||||
|
||||
TableHeader.showTrailingVerticalLine = false
|
||||
|
||||
#---- TextArea ----
|
||||
|
||||
@@ -752,6 +764,7 @@ ToolBar.separatorWidth = 7
|
||||
ToolBar.separatorColor = $Separator.foreground
|
||||
|
||||
ToolBar.spacingBorder = $Button.toolbar.spacingInsets
|
||||
ToolBar.focusableButtons = false
|
||||
|
||||
|
||||
#---- ToolTipManager ----
|
||||
|
||||
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
* Copyright 2021 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.ui;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Insets;
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.border.LineBorder;
|
||||
import javax.swing.plaf.basic.BasicComboBoxEditor;
|
||||
import javax.swing.plaf.basic.BasicComboBoxRenderer;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class TestFlatComponentSizes
|
||||
{
|
||||
@BeforeAll
|
||||
static void setup() {
|
||||
TestUtils.setup( false );
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void cleanup() {
|
||||
TestUtils.cleanup();
|
||||
}
|
||||
|
||||
static float[] factors() {
|
||||
return TestUtils.FACTORS;
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource( "factors" )
|
||||
void sizes( float factor ) {
|
||||
TestUtils.scaleFont( factor );
|
||||
|
||||
|
||||
// should have same default size (minimumWidth is 64)
|
||||
JTextField textField = new JTextField();
|
||||
JFormattedTextField formattedTextField = new JFormattedTextField();
|
||||
JPasswordField passwordField = new JPasswordField();
|
||||
JSpinner spinner = new JSpinner();
|
||||
|
||||
Dimension textFieldSize = textField.getPreferredSize();
|
||||
assertEquals( textFieldSize, formattedTextField.getPreferredSize() );
|
||||
assertEquals( textFieldSize, passwordField.getPreferredSize() );
|
||||
assertEquals( textFieldSize, spinner.getPreferredSize() );
|
||||
|
||||
|
||||
// should have same default size (minimumWidth is 72)
|
||||
JButton button = new JButton( "text" );
|
||||
JComboBox<String> comboBox = new JComboBox<>();
|
||||
JComboBox<String> comboBoxEditable = new JComboBox<>();
|
||||
comboBoxEditable.setEditable( true );
|
||||
|
||||
Dimension buttonSize = button.getPreferredSize();
|
||||
assertEquals( buttonSize, comboBox.getPreferredSize() );
|
||||
assertEquals( buttonSize, comboBoxEditable.getPreferredSize() );
|
||||
|
||||
|
||||
// should have same height
|
||||
JToggleButton toggleButton = new JToggleButton( "text" );
|
||||
|
||||
assertEquals( textFieldSize.height, button.getPreferredSize().height );
|
||||
assertEquals( textFieldSize.height, toggleButton.getPreferredSize().height );
|
||||
|
||||
|
||||
// should have same size
|
||||
JCheckBox checkBox = new JCheckBox( "text" );
|
||||
JRadioButton radioButton = new JRadioButton( "text" );
|
||||
assertEquals( checkBox.getPreferredSize(), radioButton.getPreferredSize() );
|
||||
|
||||
|
||||
// should have same size
|
||||
JMenu menu = new JMenu( "text" );
|
||||
JMenuItem menuItem = new JMenuItem( "text" );
|
||||
JCheckBoxMenuItem checkBoxMenuItem = new JCheckBoxMenuItem( "text" );
|
||||
JRadioButtonMenuItem radioButtonMenuItem = new JRadioButtonMenuItem( "text" );
|
||||
|
||||
Dimension menuSize = menu.getPreferredSize();
|
||||
assertEquals( menuSize, menuItem.getPreferredSize() );
|
||||
assertEquals( menuSize, checkBoxMenuItem.getPreferredSize() );
|
||||
assertEquals( menuSize, radioButtonMenuItem.getPreferredSize() );
|
||||
|
||||
|
||||
TestUtils.resetFont();
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource( "factors" )
|
||||
void comboBox( float factor ) {
|
||||
TestUtils.scaleFont( factor );
|
||||
|
||||
String[] items = { "t" };
|
||||
JComboBox<String> comboBox = new JComboBox<>( items );
|
||||
JComboBox<String> comboBox2 = new JComboBox<>( items );
|
||||
JComboBox<String> comboBox3 = new JComboBox<>( items );
|
||||
JComboBox<String> comboBox4 = new JComboBox<>( items );
|
||||
|
||||
applyCustomComboBoxRendererBorder( comboBox2, new LineBorder( Color.orange, UIScale.scale( 6 ) ) );
|
||||
applyCustomComboBoxRendererBorder( comboBox3, new BorderWithIcon() );
|
||||
applyCustomComboBoxRendererBorder( comboBox4, null );
|
||||
|
||||
Dimension size = comboBox.getPreferredSize();
|
||||
assertEquals( size.width, comboBox2.getPreferredSize().width );
|
||||
assertEquals( size.height - (2 * UIScale.scale( 2 )) + (2 * UIScale.scale( 6 )), comboBox2.getPreferredSize().height );
|
||||
assertEquals( size, comboBox3.getPreferredSize() );
|
||||
assertEquals( size, comboBox4.getPreferredSize() );
|
||||
|
||||
TestUtils.resetFont();
|
||||
}
|
||||
|
||||
@SuppressWarnings( "unchecked" )
|
||||
private void applyCustomComboBoxRendererBorder( JComboBox<String> comboBox, Border border ) {
|
||||
BasicComboBoxRenderer customRenderer = new BasicComboBoxRenderer();
|
||||
customRenderer.setBorder( border );
|
||||
comboBox.setRenderer( customRenderer );
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource( "factors" )
|
||||
void comboBoxEditable( float factor ) {
|
||||
TestUtils.scaleFont( factor );
|
||||
|
||||
String[] items = { "t" };
|
||||
JComboBox<String> comboBox = new JComboBox<>( items );
|
||||
JComboBox<String> comboBox2 = new JComboBox<>( items );
|
||||
JComboBox<String> comboBox3 = new JComboBox<>( items );
|
||||
JComboBox<String> comboBox4 = new JComboBox<>( items );
|
||||
|
||||
comboBox.setEditable( true );
|
||||
comboBox2.setEditable( true );
|
||||
comboBox3.setEditable( true );
|
||||
comboBox4.setEditable( true );
|
||||
|
||||
applyCustomComboBoxEditorBorder( comboBox2, new LineBorder( Color.orange, UIScale.scale( 6 ) ) );
|
||||
applyCustomComboBoxEditorBorder( comboBox3, new BorderWithIcon() );
|
||||
applyCustomComboBoxEditorBorder( comboBox4, null );
|
||||
|
||||
Dimension size = comboBox.getPreferredSize();
|
||||
assertEquals( size.width, comboBox2.getPreferredSize().width );
|
||||
assertEquals( size.height - (2 * UIScale.scale( 2 )) + (2 * UIScale.scale( 6 )), comboBox2.getPreferredSize().height );
|
||||
assertEquals( size, comboBox3.getPreferredSize() );
|
||||
assertEquals( size, comboBox4.getPreferredSize() );
|
||||
|
||||
TestUtils.resetFont();
|
||||
}
|
||||
|
||||
private void applyCustomComboBoxEditorBorder( JComboBox<String> comboBox, Border border ) {
|
||||
JTextField customTextField = new JTextField();
|
||||
if( border != null )
|
||||
customTextField.setBorder( border );
|
||||
comboBox.setEditor( new BasicComboBoxEditor() {
|
||||
@Override
|
||||
protected JTextField createEditorComponent() {
|
||||
return customTextField;
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
//---- class BorderWithIcon -----------------------------------------------
|
||||
|
||||
private static class BorderWithIcon
|
||||
implements Border
|
||||
{
|
||||
@Override
|
||||
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBorderOpaque() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Insets getBorderInsets( Component c ) {
|
||||
return new Insets( 0, 0, 0, UIScale.scale( 16 ) + 4 );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2021 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.ui;
|
||||
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
|
||||
/**
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class TestFlatComponentSizesWithFocus
|
||||
extends TestFlatComponentSizes
|
||||
{
|
||||
@BeforeAll
|
||||
static void setup() {
|
||||
TestUtils.setup( true );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2021 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.ui;
|
||||
|
||||
import java.awt.Font;
|
||||
import javax.swing.UIManager;
|
||||
import com.formdev.flatlaf.FlatIntelliJLaf;
|
||||
import com.formdev.flatlaf.FlatLightLaf;
|
||||
import com.formdev.flatlaf.FlatSystemProperties;
|
||||
|
||||
/**
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class TestUtils
|
||||
{
|
||||
public static final float[] FACTORS = new float[] { 1f, 1.25f, 1.5f, 1.75f, 2f, 2.25f, 2.5f, 2.75f, 3f, 3.25f, 3.5f, 3.75f, 4f, 5f, 6f };
|
||||
|
||||
public static void setup( boolean withFocus ) {
|
||||
System.setProperty( FlatSystemProperties.UI_SCALE, "1x" );
|
||||
if( withFocus )
|
||||
FlatIntelliJLaf.setup();
|
||||
else
|
||||
FlatLightLaf.setup();
|
||||
System.clearProperty( FlatSystemProperties.UI_SCALE );
|
||||
}
|
||||
|
||||
public static void cleanup() {
|
||||
UIManager.put( "defaultFont", null );
|
||||
}
|
||||
|
||||
public static void scaleFont( float factor ) {
|
||||
Font defaultFont = UIManager.getLookAndFeelDefaults().getFont( "defaultFont" );
|
||||
UIManager.put( "defaultFont", defaultFont.deriveFont( (float) Math.round( defaultFont.getSize() * factor ) ) );
|
||||
}
|
||||
|
||||
public static void resetFont() {
|
||||
UIManager.put( "defaultFont", null );
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<rect width="16" height="16" fill="#6E6E6E" rx="3"/>
|
||||
<rect width="6" height="2" x="5" y="12" fill="#FFF"/>
|
||||
<rect width="6" height="2" x="5" y="11.5" fill="#FFF"/>
|
||||
<path fill="#FFF" d="M2,8 L8,2 L14,8 L11,8 L11,10 L5,10 L5,8 L2,8 Z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 326 B After Width: | Height: | Size: 328 B |
3
flatlaf-core/svg/ClearHoveredIcon.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<path fill="#7F8B91" fill-opacity=".5" fill-rule="evenodd" d="M8,1.75 C11.4517797,1.75 14.25,4.54822031 14.25,8 C14.25,11.4517797 11.4517797,14.25 8,14.25 C4.54822031,14.25 1.75,11.4517797 1.75,8 C1.75,4.54822031 4.54822031,1.75 8,1.75 Z M10.5,4.5 L8,7 L5.5,4.5 L4.5,5.5 L7,8 L4.5,10.5 L5.5,11.5 L8,9 L10.5,11.5 L11.5,10.5 L9,8 L11.5,5.5 L10.5,4.5 Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 446 B |
3
flatlaf-core/svg/ClearIcon.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<path fill="none" stroke="#7F8B91" stroke-linecap="square" stroke-opacity=".5" d="M5,5 L11,11 M5,11 L11,5"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 202 B |
6
flatlaf-core/svg/SearchIcon.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<g fill="none" fill-opacity=".9" fill-rule="evenodd">
|
||||
<polygon fill="#7F8B91" points="10.813 9.75 14 12.938 12.938 14 9.75 10.813"/>
|
||||
<path fill="#7F8B91" d="M7,2 C9.76142375,2 12,4.23857625 12,7 C12,9.76142375 9.76142375,12 7,12 C4.23857625,12 2,9.76142375 2,7 C2,4.23857625 4.23857625,2 7,2 Z M7,3 C4.790861,3 3,4.790861 3,7 C3,9.209139 4.790861,11 7,11 C9.209139,11 11,9.209139 11,7 C11,4.790861 9.209139,3 7,3 Z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 526 B |
7
flatlaf-core/svg/SearchWithHistoryIcon.svg
Normal file
@@ -0,0 +1,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<g fill="none" fill-opacity=".9" fill-rule="evenodd">
|
||||
<polygon fill="#7F8B91" points="8.813 9.75 12 12.938 10.938 14 7.75 10.813"/>
|
||||
<path fill="#7F8B91" d="M5,2 C7.76142375,2 10,4.23857625 10,7 C10,9.76142375 7.76142375,12 5,12 C2.23857625,12 0,9.76142375 0,7 C0,4.23857625 2.23857625,2 5,2 Z M5,3 C2.790861,3 1,4.790861 1,7 C1,9.209139 2.790861,11 5,11 C7.209139,11 9,9.209139 9,7 C9,4.790861 7.209139,3 5,3 Z"/>
|
||||
<polygon fill="#7F8B91" points="11 7 16 7 13.5 10"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 579 B |
@@ -28,6 +28,7 @@ import javax.swing.plaf.metal.MetalLookAndFeel;
|
||||
import javax.swing.plaf.nimbus.NimbusLookAndFeel;
|
||||
import com.formdev.flatlaf.*;
|
||||
import com.formdev.flatlaf.extras.FlatAnimatedLafChange;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
import net.miginfocom.layout.ConstraintParser;
|
||||
@@ -240,7 +241,7 @@ class ControlBar
|
||||
frame.setSize( Math.max( prefSize.width, width ), Math.max( prefSize.height, height ) );
|
||||
|
||||
} catch( Exception ex ) {
|
||||
ex.printStackTrace();
|
||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
@@ -18,6 +18,10 @@ package com.formdev.flatlaf.demo;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.time.Year;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.prefs.Preferences;
|
||||
@@ -34,8 +38,10 @@ import com.formdev.flatlaf.extras.FlatUIDefaultsInspector;
|
||||
import com.formdev.flatlaf.extras.components.FlatButton;
|
||||
import com.formdev.flatlaf.extras.components.FlatButton.ButtonType;
|
||||
import com.formdev.flatlaf.extras.FlatSVGUtils;
|
||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
import com.formdev.flatlaf.ui.JBRCustomDecorations;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
import net.miginfocom.layout.ConstraintParser;
|
||||
import net.miginfocom.layout.LC;
|
||||
import net.miginfocom.layout.UnitValue;
|
||||
@@ -127,7 +133,36 @@ class DemoFrame
|
||||
}
|
||||
|
||||
private void aboutActionPerformed() {
|
||||
JOptionPane.showMessageDialog( this, "FlatLaf Demo", "About", JOptionPane.PLAIN_MESSAGE );
|
||||
JLabel titleLabel = new JLabel( "FlatLaf Demo" );
|
||||
Font titleFont = titleLabel.getFont();
|
||||
titleLabel.setFont( titleFont.deriveFont( (float) titleFont.getSize() + UIScale.scale( 6 ) ) );
|
||||
|
||||
String link = "https://www.formdev.com/flatlaf/";
|
||||
JLabel linkLabel = new JLabel( "<html><a href=\"#\">" + link + "</a></html>" );
|
||||
linkLabel.setCursor( Cursor.getPredefinedCursor( Cursor.HAND_CURSOR ) );
|
||||
linkLabel.addMouseListener( new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseClicked( MouseEvent e ) {
|
||||
try {
|
||||
Desktop.getDesktop().browse( new URI( link ) );
|
||||
} catch( IOException | URISyntaxException ex ) {
|
||||
JOptionPane.showMessageDialog( linkLabel,
|
||||
"Failed to open '" + link + "' in browser.",
|
||||
"About", JOptionPane.PLAIN_MESSAGE );
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
|
||||
JOptionPane.showMessageDialog( this,
|
||||
new Object[] {
|
||||
titleLabel,
|
||||
"Demonstrates FlatLaf Swing look and feel",
|
||||
" ",
|
||||
"Copyright 2019-" + Year.now() + " FormDev Software GmbH",
|
||||
linkLabel,
|
||||
},
|
||||
"About", JOptionPane.PLAIN_MESSAGE );
|
||||
}
|
||||
|
||||
private void selectedTabChanged() {
|
||||
@@ -185,6 +220,8 @@ class DemoFrame
|
||||
|
||||
Font font = UIManager.getFont( "defaultFont" );
|
||||
Font newFont = StyleContext.getDefaultStyleContext().getFont( fontFamily, font.getStyle(), font.getSize() );
|
||||
// StyleContext.getFont() may return a UIResource, which would cause loosing user scale factor on Windows
|
||||
newFont = FlatUIUtils.nonUIResource( newFont );
|
||||
UIManager.put( "defaultFont", newFont );
|
||||
|
||||
FlatLaf.updateUI();
|
||||
|
||||
@@ -25,6 +25,7 @@ import com.formdev.flatlaf.FlatLightLaf;
|
||||
import com.formdev.flatlaf.FlatPropertiesLaf;
|
||||
import com.formdev.flatlaf.IntelliJTheme;
|
||||
import com.formdev.flatlaf.demo.intellijthemes.IJThemesPanel;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
import com.formdev.flatlaf.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -83,7 +84,7 @@ public class DemoPrefs
|
||||
UIManager.setLookAndFeel( lafClassName );
|
||||
}
|
||||
} catch( Throwable ex ) {
|
||||
ex.printStackTrace();
|
||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||
|
||||
// fallback
|
||||
FlatLightLaf.setup();
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
|
||||
/**
|
||||
* This tool creates look and feel classes for all themes listed in themes.json.
|
||||
@@ -120,7 +121,7 @@ public class IJThemesClassGenerator
|
||||
Files.write( out, content.getBytes( StandardCharsets.ISO_8859_1 ),
|
||||
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING );
|
||||
} catch( IOException ex ) {
|
||||
ex.printStackTrace();
|
||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,14 +169,6 @@ public class IJThemesClassGenerator
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" /**\n" +
|
||||
" * @deprecated use {@link #setup()} instead; this method will be removed in a future version\n" +
|
||||
" */\n" +
|
||||
" @Deprecated\n" +
|
||||
" public static boolean install() {\n" +
|
||||
" return setup();\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" public static void installLafInfo() {\n" +
|
||||
" installLafInfo( NAME, ${themeClass}.class );\n" +
|
||||
" }\n" +
|
||||
|
||||
@@ -26,6 +26,7 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import com.formdev.flatlaf.json.Json;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
import com.formdev.flatlaf.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -46,7 +47,7 @@ class IJThemesManager
|
||||
try( Reader reader = new InputStreamReader( getClass().getResourceAsStream( "themes.json" ), StandardCharsets.UTF_8 ) ) {
|
||||
json = (Map<String, Object>) Json.parse( reader );
|
||||
} catch( IOException ex ) {
|
||||
ex.printStackTrace();
|
||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -52,6 +52,7 @@ import com.formdev.flatlaf.IntelliJTheme;
|
||||
import com.formdev.flatlaf.demo.DemoPrefs;
|
||||
import com.formdev.flatlaf.extras.FlatAnimatedLafChange;
|
||||
import com.formdev.flatlaf.extras.FlatSVGIcon;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
import com.formdev.flatlaf.util.StringUtils;
|
||||
import net.miginfocom.swing.*;
|
||||
|
||||
@@ -259,7 +260,7 @@ public class IJThemesPanel
|
||||
try {
|
||||
UIManager.setLookAndFeel( themeInfo.lafClassName );
|
||||
} catch( Exception ex ) {
|
||||
ex.printStackTrace();
|
||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||
showInformationDialog( "Failed to create '" + themeInfo.lafClassName + "'.", ex );
|
||||
}
|
||||
} else if( themeInfo.themeFile != null ) {
|
||||
@@ -273,7 +274,7 @@ public class IJThemesPanel
|
||||
|
||||
DemoPrefs.getState().put( DemoPrefs.KEY_LAF_THEME, DemoPrefs.FILE_PREFIX + themeInfo.themeFile );
|
||||
} catch( Exception ex ) {
|
||||
ex.printStackTrace();
|
||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||
showInformationDialog( "Failed to load '" + themeInfo.themeFile + "'.", ex );
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -23,6 +23,7 @@ import java.net.URLConnection;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
|
||||
/**
|
||||
* This tool updates all IntelliJ themes listed in themes.json by downloading
|
||||
@@ -61,7 +62,7 @@ public class IJThemesUpdater
|
||||
URLConnection con = url.openConnection();
|
||||
Files.copy( con.getInputStream(), out, StandardCopyOption.REPLACE_EXISTING );
|
||||
} catch( IOException ex ) {
|
||||
ex.printStackTrace();
|
||||
LoggingFacade.INSTANCE.logSevere( null, ex );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<g fill="none" fill-rule="evenodd" transform="translate(2 2)">
|
||||
<rect width="5.5" height="5.5" fill="#59A869"/>
|
||||
|
||||
|
Before Width: | Height: | Size: 403 B After Width: | Height: | Size: 550 B |
@@ -1,3 +1,4 @@
|
||||
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<path fill="#6E6E6E" d="M11,3 L4,3 L4,11 L2,11 L2,1 L11,1 L11,3 Z"/>
|
||||
|
||||
|
Before Width: | Height: | Size: 363 B After Width: | Height: | Size: 510 B |
@@ -1,3 +1,4 @@
|
||||
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<polygon fill="#59A869" fill-rule="evenodd" points="4 2 14 8 4 14"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 162 B After Width: | Height: | Size: 309 B |
@@ -1,3 +1,4 @@
|
||||
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<rect width="6" height="1" x="5" y="12" fill="#6E6E6E"/>
|
||||
|
||||
|
Before Width: | Height: | Size: 493 B After Width: | Height: | Size: 640 B |
@@ -1,3 +1,4 @@
|
||||
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<rect width="6" height="1" x="5" y="12" fill="#6E6E6E"/>
|
||||
|
||||
|
Before Width: | Height: | Size: 493 B After Width: | Height: | Size: 640 B |
@@ -1,3 +1,4 @@
|
||||
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<rect width="10" height="10" x="3" y="3" fill="#DB5860" fill-rule="evenodd"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 171 B After Width: | Height: | Size: 318 B |
@@ -1,3 +1,4 @@
|
||||
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
|
||||
<path fill="#DB5860" fill-rule="evenodd" d="M16,30 C8.2680135,30 2,23.7319865 2,16 C2,8.2680135 8.2680135,2 16,2 C23.7319865,2 30,8.2680135 30,16 C30,23.7319865 23.7319865,30 16,30 Z M14,7 L14,18 L18,18 L18,7 L14,7 Z M14,21 L14,25 L18,25 L18,21 L14,21 Z"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 350 B After Width: | Height: | Size: 497 B |
@@ -1,3 +1,4 @@
|
||||
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
|
||||
<path fill="#389FD6" fill-rule="evenodd" d="M16,30 C8.2680135,30 2,23.7319865 2,16 C2,8.2680135 8.2680135,2 16,2 C23.7319865,2 30,8.2680135 30,16 C30,23.7319865 23.7319865,30 16,30 Z M14,7 L14,18 L18,18 L18,7 L14,7 Z M14,21 L14,25 L18,25 L18,21 L14,21 Z" transform="rotate(180 16 16)"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 380 B After Width: | Height: | Size: 527 B |
@@ -1,3 +1,4 @@
|
||||
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16" viewBox="0 0 16 16">
|
||||
<defs>
|
||||
<rect id="abstractclass-a" width="8" height="14"/>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.5 KiB |
@@ -1,3 +1,4 @@
|
||||
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16" viewBox="0 0 16 16">
|
||||
<defs>
|
||||
<rect id="abstractmethod-a" width="8" height="14"/>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.7 KiB |
@@ -1,3 +1,4 @@
|
||||
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<path fill="#62B543" fill-opacity=".6" d="M15,8 C15,11.866 11.866,15 8,15 C4.134,15 1,11.866 1,8 C1,4.134 4.134,1 8,1 C11.866,1 15,4.134 15,8"/>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.8 KiB |
@@ -1,10 +1,17 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<polygon fill="#9AA7B0" fill-opacity=".8" points="7 1 3 5 7 5"/>
|
||||
<polygon fill="#9AA7B0" fill-opacity=".8" points="8 1 8 6 3 6 3 8 13 8 13 1"/>
|
||||
<polygon fill="#40B6E0" fill-opacity=".7" points="1 16 16 16 16 9 1 9"/>
|
||||
<path fill="#231F20" fill-opacity=".7" d="M0,2.501 C0,1 0.931,2.02832126e-16 2.256,0 C3.20239258,0 3.55,0.311 3.969,0.753 L3.42669678,1.42712402 C3.07669678,1.06812402 2.75,1 2.25,1 C1.418,1 1,1.73791504 1,2.487 C1,3.23608496 1.412,4 2.25,4 C2.787,4 3.05169678,3.89340869 3.42669678,3.50640869 L4,4.144 C3.544,4.669 3.19732666,5 2.225,5 C0.949,5 7.35277938e-17,4.002 0,2.501 Z" transform="translate(2 10)"/>
|
||||
<path fill="#231F20" fill-opacity=".7" d="M0.972767969,1.50152588 C0.972767969,1.13305664 1.284,1 1.845,1 C1.85033333,1 2.23533333,1 3,1 L3,0 C2.26266667,0 1.88266667,0 1.86,0 C0.778,0 0,0.45916748 0,1.45 C0,2.31452637 0.419555664,2.69049072 1.47125244,2.91607666 C2.24158869,3.08131157 2.496155,3.22862939 2.496155,3.548 C2.496155,3.86737061 2.13842773,4 1.47125244,4 C1.46058577,4 1.07016829,4 0.3,4 L0.3,5 C1.07550163,5 1.46591911,5 1.47125244,5 C3.5,5 3.5,4 3.5,3.548 C3.5,2.91607666 3.02026367,2.42071533 2.15869141,2.14685059 C1.29711914,1.87298584 0.972767969,1.86999512 0.972767969,1.50152588 Z" transform="translate(7 10)"/>
|
||||
<path fill="#231F20" fill-opacity=".7" d="M0.972767969,1.50152588 C0.972767969,1.13305664 1.284,1 1.845,1 C1.85033333,1 2.23533333,1 3,1 L3,0 C2.26266667,0 1.88266667,0 1.86,0 C0.778,0 0,0.45916748 0,1.45 C0,2.31452637 0.419555664,2.69049072 1.47125244,2.91607666 C2.24158869,3.08131157 2.496155,3.22862939 2.496155,3.548 C2.496155,3.86737061 2.13842773,4 1.47125244,4 C1.46058577,4 1.07016829,4 0.3,4 L0.3,5 C1.07550163,5 1.46591911,5 1.47125244,5 C3.5,5 3.5,4 3.5,3.548 C3.5,2.91607666 3.02026367,2.42071533 2.15869141,2.14685059 C1.29711914,1.87298584 0.972767969,1.86999512 0.972767969,1.50152588 Z" transform="translate(11 10)"/>
|
||||
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="css">
|
||||
<path id="Fill 1" fill-rule="evenodd" clip-rule="evenodd" d="M7 1L3 5H7V1Z" fill="#9AA7B0" fill-opacity="0.8"/>
|
||||
<path id="Fill 3" fill-rule="evenodd" clip-rule="evenodd" d="M8 1V6H3V8H13V1H8Z" fill="#9AA7B0" fill-opacity="0.8"/>
|
||||
<path id="Fill 5" fill-rule="evenodd" clip-rule="evenodd" d="M1 16H16V9H1V16Z" fill="#F98B9E" fill-opacity="0.6"/>
|
||||
<g id="⌘/alphabet/C">
|
||||
<path id="⌘/alphabet/C_2" fill-rule="evenodd" clip-rule="evenodd" d="M2 12.501C2 11 2.931 10 4.256 10C5.20239 10 5.55 10.311 5.969 10.753L5.4267 11.4271C5.0767 11.0681 4.75 11 4.25 11C3.418 11 3 11.7379 3 12.487C3 13.2361 3.412 14 4.25 14C4.787 14 5.0517 13.8934 5.4267 13.5064L6 14.144C5.544 14.669 5.19733 15 4.225 15C2.949 15 2 14.002 2 12.501Z" fill="#231F20" fill-opacity="0.7"/>
|
||||
</g>
|
||||
<g id="⌘/alphabet/S">
|
||||
<path id="⌘/alphabet/S_2" fill-rule="evenodd" clip-rule="evenodd" d="M7.97277 11.5015C7.97277 11.1331 8.284 11 8.845 11C8.853 11 10 11 10 11V10C10 10 8.894 10 8.86 10C7.778 10 7 10.4592 7 11.45C7 12.3145 7.41956 12.6905 8.47125 12.9161C9.24159 13.0813 9.49616 13.2286 9.49616 13.548C9.49616 13.8674 9.13843 14 8.47125 14C8.45525 14 7.3 14 7.3 14V15C7.3 15 8.46325 15 8.47125 15C10.5 15 10.5 14 10.5 13.548C10.5 12.9161 10.0203 12.4207 9.15869 12.1469C8.29712 11.873 7.97277 11.87 7.97277 11.5015Z" fill="#231F20" fill-opacity="0.7"/>
|
||||
</g>
|
||||
<g id="⌘/alphabet/S_3">
|
||||
<path id="⌘/alphabet/S_4" fill-rule="evenodd" clip-rule="evenodd" d="M11.9728 11.5015C11.9728 11.1331 12.284 11 12.845 11C12.853 11 14 11 14 11V10C14 10 12.894 10 12.86 10C11.778 10 11 10.4592 11 11.45C11 12.3145 11.4196 12.6905 12.4713 12.9161C13.2416 13.0813 13.4962 13.2286 13.4962 13.548C13.4962 13.8674 13.1384 14 12.4713 14C12.4553 14 11.3 14 11.3 14V15C11.3 15 12.4633 15 12.4713 15C14.5 15 14.5 14 14.5 13.548C14.5 12.9161 14.0203 12.4207 13.1587 12.1469C12.2971 11.873 11.9728 11.87 11.9728 11.5015Z" fill="#231F20" fill-opacity="0.7"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.2 KiB |
@@ -1,3 +1,4 @@
|
||||
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<polygon fill="#F4AF3D" fill-opacity=".7" points="1 16 16 16 16 9 1 9"/>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.4 KiB |
@@ -1,3 +1,4 @@
|
||||
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<polygon fill="#F26522" fill-opacity=".7" points="1 16 16 16 16 9 1 9"/>
|
||||
|
||||
|
Before Width: | Height: | Size: 498 B After Width: | Height: | Size: 645 B |
@@ -1,3 +1,4 @@
|
||||
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
|
||||
<path fill="#EDA200" fill-rule="evenodd" d="M16,2 L31,28 L1,28 L16,2 Z M18,25 L18,21 L14,21 L14,25 L18,25 Z M18,18 L18,10 L14,10 L14,18 L18,18 Z"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 241 B After Width: | Height: | Size: 388 B |
@@ -1,3 +1,4 @@
|
||||
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10 0C8.02219 0 6.08879 0.58649 4.4443 1.6853C2.79981 2.78412 1.51809 4.3459 0.761209 6.17317C0.00433284 8.00043 -0.193701 10.0111 0.192152 11.9509C0.578004 13.8907 1.53041 15.6725 2.92894 17.0711C4.32746 18.4696 6.10929 19.422 8.0491 19.8079C9.98891 20.1937 11.9996 19.9957 13.8268 19.2388C15.6541 18.4819 17.2159 17.2002 18.3147 15.5557C19.4135 13.9112 20 11.9778 20 10C20 7.34784 18.9464 4.8043 17.0711 2.92893C15.1957 1.05357 12.6522 0 10 0ZM10 18.2C8.3782 18.2 6.79281 17.7191 5.44433 16.8181C4.09585 15.917 3.04483 14.6364 2.42419 13.138C1.80355 11.6397 1.64117 9.9909 1.95757 8.40026C2.27396 6.80961 3.05494 5.34852 4.20173 4.20172C5.34852 3.05493 6.80962 2.27396 8.40026 1.95756C9.99091 1.64116 11.6397 1.80355 13.138 2.42419C14.6364 3.04483 15.917 4.09584 16.8181 5.44432C17.7191 6.79281 18.2 8.37819 18.2 10C18.1974 12.174 17.3326 14.2581 15.7954 15.7954C14.2581 17.3326 12.174 18.1974 10 18.2ZM10.9 9.43L14.46 11.09L13.7 12.72L9.10001 10.57V4H10.9V9.43Z" fill="#9AA7B0" fill-opacity="0.8"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.2 KiB |
@@ -1,3 +1,4 @@
|
||||
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<g fill="#6E6E6E" fill-rule="evenodd" transform="translate(1 3)">
|
||||
<rect width="12" height="2" x="1" y="4"/>
|
||||
|
||||
|
Before Width: | Height: | Size: 442 B After Width: | Height: | Size: 589 B |
@@ -1,3 +1,4 @@
|
||||
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<path fill="#389FD6" fill-rule="evenodd" d="M14.0431479,8.44999981 L14.3048222,13.4430431 L12.574725,11.885269 C11.4741571,13.1817306 9.83248424,14.0044386 7.99865879,14.0044386 C5.03921121,14.0044386 2.58020312,11.8617896 2.08827651,9.04314243 L3.94798986,9.10858763 C4.43427312,10.8903005 6.0642585,12.2000519 8.00015362,12.2000519 C9.30169687,12.2000519 10.4649641,11.6080237 11.2353504,10.6785714 L9.05000019,8.71167959 L14.0431479,8.44999981 Z M7.99865879,2.00443857 C10.9184669,2.00443857 13.3511517,4.09007371 13.888219,6.85284133 L12.0226275,6.7880427 C11.5024638,5.05933714 9.89836709,3.8000774 8.00015362,3.8000774 C6.69883692,3.8000774 5.53574811,4.39189956 4.76535914,5.32107268 L6.95482203,7.29304326 L1.96167436,7.55472304 L1.70000005,2.56167973 L3.42768119,4.11762166 C4.52821742,2.82461451 6.1676575,2.00443857 7.99865879,2.00443857 Z" transform="rotate(3 8.002 8.004)"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 981 B After Width: | Height: | Size: 1.1 KiB |
@@ -1,3 +1,4 @@
|
||||
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<polygon fill="#59A869" points="13.789 2.09 15.535 3.837 6.292 13.08 1.95 8.738 3.698 6.99 6.293 9.585"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 199 B After Width: | Height: | Size: 346 B |
@@ -1,3 +1,4 @@
|
||||
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<path fill="#6E6E6E" d="M11,3 L4,3 L4,11 L2,11 L2,1 L11,1 L11,3 Z"/>
|
||||
|
||||
|
Before Width: | Height: | Size: 363 B After Width: | Height: | Size: 510 B |
@@ -1,3 +1,4 @@
|
||||
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<g fill="#389FD6" fill-rule="evenodd" transform="translate(1)">
|
||||
<path d="M10.9000003,4.89999992 L14.0999999,4.89999992 L9.9000001,9.09999973 L5.70000029,4.89999992 L8.90000027,4.89999992 L8.90000027,0.899999917 L10.9000003,0.899999917 L10.9000003,4.89999992 Z" transform="rotate(90 9.9 5)"/>
|
||||
|
||||
|
Before Width: | Height: | Size: 630 B After Width: | Height: | Size: 777 B |
@@ -1,3 +1,4 @@
|
||||
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<polygon fill="#6E6E6E" points="9 7 12 7 8 11 4 7 7 7 7 2 9 2" transform="matrix(-1 0 0 1 16 0)"/>
|
||||
|
||||
|
Before Width: | Height: | Size: 301 B After Width: | Height: | Size: 448 B |
@@ -1,3 +1,4 @@
|
||||
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<polygon fill="#F4AF3D" fill-rule="evenodd" points="7.998 11.522 3.673 14.311 4.989 9.336 1 6.084 6.138 5.798 7.998 1 9.858 5.798 14.996 6.084 11.007 9.336 12.323 14.311"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 266 B After Width: | Height: | Size: 413 B |
@@ -1,3 +1,4 @@
|
||||
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<rect width="11" height="2" x="2" y="7" fill="#6E6E6E" transform="matrix(-1 0 0 1 15 0)"/>
|
||||
|
||||
|
Before Width: | Height: | Size: 484 B After Width: | Height: | Size: 631 B |
@@ -1,3 +1,4 @@
|
||||
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<path fill="#161514" fill-rule="evenodd" d="M7.99707713,1 C4.13339149,1 1,4.1329619 1,7.9979363 C1,11.0896581 3.00487223,13.7122732 5.78557461,14.6375989 C6.13568621,14.7020366 6.2632729,14.4859554 6.2632729,14.3003748 C6.2632729,14.1345551 6.25725871,13.6942307 6.25382203,13.1104249 C4.30737333,13.5331364 3.89669027,12.1722117 3.89669027,12.1722117 C3.57836793,11.3637332 3.11957137,11.1485112 3.11957137,11.1485112 C2.48421546,10.7146305 3.16768487,10.7232222 3.16768487,10.7232222 C3.87005601,10.7726245 4.23949893,11.4444951 4.23949893,11.4444951 C4.86368564,12.5137317 5.87750575,12.2048602 6.27616044,12.0257233 C6.33973899,11.5738001 6.52059419,11.2653582 6.72035112,11.0905172 C5.16654292,10.9139579 3.53283195,10.3133983 3.53283195,7.63193005 C3.53283195,6.86812829 3.80561829,6.24308241 4.25324565,5.75421492 C4.1810754,5.57722598 3.9409375,4.86540398 4.32197921,3.90227487 C4.32197921,3.90227487 4.90922163,3.71411673 6.24608951,4.61968148 C6.80412015,4.46417178 7.40296136,4.38684652 7.9979363,4.38383942 C8.59248165,4.38684652 9.19089327,4.46417178 9.74978309,4.61968148 C11.0857918,3.71411673 11.672175,3.90227487 11.672175,3.90227487 C12.0540759,4.86540398 11.813938,5.57722598 11.7421974,5.75421492 C12.1906839,6.24308241 12.4613223,6.86812829 12.4613223,7.63193005 C12.4613223,10.3202717 10.8250338,10.91181 9.26650019,11.0849326 C9.51737771,11.3010138 9.74119139,11.7280211 9.74119139,12.38099 C9.74119139,13.316196 9.7325997,14.0709765 9.7325997,14.3003748 C9.7325997,14.4876738 9.85889763,14.7054733 10.2137347,14.6371693 C12.9922891,13.7096957 14.995443,11.0887989 14.995443,7.9979363 C14.995443,4.1329619 11.8620515,1 7.99707713,1"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.9 KiB |
@@ -1,3 +1,4 @@
|
||||
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<path fill="#FFFFFE" fill-rule="evenodd" d="M7.99707713,1 C4.13339149,1 1,4.1329619 1,7.9979363 C1,11.0896581 3.00487223,13.7122732 5.78557461,14.6375989 C6.13568621,14.7020366 6.2632729,14.4859554 6.2632729,14.3003748 C6.2632729,14.1341255 6.25725871,13.6942307 6.25382203,13.1104249 C4.30737333,13.5331364 3.89669027,12.1722117 3.89669027,12.1722117 C3.57836793,11.3637332 3.11957137,11.1485112 3.11957137,11.1485112 C2.48421546,10.7146305 3.16768487,10.7232222 3.16768487,10.7232222 C3.87005601,10.7726245 4.23949893,11.4444951 4.23949893,11.4444951 C4.86368564,12.5137317 5.87750575,12.2048602 6.27616044,12.0257233 C6.33973899,11.5738001 6.52059419,11.2653582 6.72035112,11.0905172 C5.16654292,10.9139579 3.53283195,10.3133983 3.53283195,7.63193005 C3.53283195,6.86812829 3.80561829,6.24308241 4.25324565,5.75421492 C4.1810754,5.57722598 3.9409375,4.86540398 4.32197921,3.90227487 C4.32197921,3.90227487 4.90922163,3.71411673 6.24608951,4.61968148 C6.80412015,4.46417178 7.40296136,4.38684652 7.9979363,4.38383942 C8.59248165,4.38684652 9.19089327,4.46417178 9.74978309,4.61968148 C11.0857918,3.71411673 11.672175,3.90227487 11.672175,3.90227487 C12.0540759,4.86540398 11.813938,5.57722598 11.7421974,5.75421492 C12.1906839,6.24308241 12.4613223,6.86812829 12.4613223,7.63193005 C12.4613223,10.3202717 10.8250338,10.91181 9.26650019,11.0849326 C9.51737771,11.3010138 9.74119139,11.7280211 9.74119139,12.3805604 C9.74119139,13.316196 9.7325997,14.0709765 9.7325997,14.3003748 C9.7325997,14.4876738 9.85889763,14.7054733 10.2137347,14.6371693 C12.9922891,13.7096957 14.995443,11.0887989 14.995443,7.9979363 C14.995443,4.1329619 11.8620515,1 7.99707713,1"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.9 KiB |
@@ -1,3 +1,4 @@
|
||||
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<rect width="12" height="2" x="2" y="3" fill="#6E6E6E"/>
|
||||
|
||||
|
Before Width: | Height: | Size: 320 B After Width: | Height: | Size: 467 B |
@@ -1,3 +1,4 @@
|
||||
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<path fill="#6E6E6E" d="M6.53206047,5.10906 C6.68535547,4.77581 6.77200047,4.40923501 6.77200047,4.01600001 C6.77200047,2.54303502 5.57896548,1.35000002 4.10600049,1.35000002 C2.63303549,1.35000002 1.4400005,2.54303502 1.4400005,4.01600001 C1.4400005,5.488965 2.63303549,6.68199999 4.10600049,6.68199999 C4.49923548,6.68199999 4.86581048,6.59535499 5.19906048,6.44205999 L6.77200047,8.01499999 L5.19906048,9.58793998 C4.86581048,9.43464498 4.49923548,9.34799998 4.10600049,9.34799998 C2.63303549,9.34799998 1.4400005,10.541035 1.4400005,12.014 C1.4400005,13.486965 2.63303549,14.6799999 4.10600049,14.6799999 C5.57896548,14.6799999 6.77200047,13.486965 6.77200047,12.014 C6.77200047,11.620765 6.68535547,11.25419 6.53206047,10.92094 L8.10500046,9.34799998 L12.7705004,14 L14.7700004,14 L14.7700004,13.347 L6.53206047,5.10906 Z M4.1053342,5.33702364 C3.37236745,5.33702364 2.77266738,4.74383861 2.77266738,4.00402356 C2.77266738,3.26420851 3.37236745,2.67102348 4.1053342,2.67102348 C4.83830096,2.67102348 5.43800103,3.26420851 5.43800103,4.00402356 C5.43800103,4.74383861 4.83830096,5.33702364 4.1053342,5.33702364 Z M4.1053342,13.3350241 C3.37236745,13.3350241 2.77266738,12.7418391 2.77266738,12.0020241 C2.77266738,11.262209 3.37236745,10.669024 4.1053342,10.669024 C4.83830096,10.669024 5.43800103,11.262209 5.43800103,12.0020241 C5.43800103,12.7418391 4.83830096,13.3350241 4.1053342,13.3350241 Z M8.10333468,8.33627383 C7.91676132,8.33627383 7.77016797,8.18964382 7.77016797,8.00302381 C7.77016797,7.8164038 7.91676132,7.66977379 8.10333468,7.66977379 C8.28990803,7.66977379 8.43650138,7.8164038 8.43650138,8.00302381 C8.43650138,8.18964382 8.28990803,8.33627383 8.10333468,8.33627383 Z M12.7710002,2.00452344 L8.77299971,6.00352368 L10.1056665,7.33652377 L14.7700004,2.67102348 L14.7700004,2.00452344 L12.7710002,2.00452344 Z"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 2.0 KiB |
@@ -1,3 +1,8 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<path fill="#6E6E6E" fill-rule="evenodd" d="M3,1 L3,0 L7,0 L7,1 L10,1 L10,13 L0,13 L0,1 L3,1 Z M4,1 L4,2 L6,2 L6,1 L4,1 Z M2,4 L2,11 L8,11 L8,4 L2,4 Z" transform="translate(3 1)"/>
|
||||
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="menu-paste">
|
||||
<g id="paste">
|
||||
<path id="Shape" fill-rule="evenodd" clip-rule="evenodd" d="M6 2V1H10V2H13V14H3V2H6ZM7 2V3H9V2H7ZM5 5V12H11V5H5Z" fill="#6E6E6E"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 274 B After Width: | Height: | Size: 426 B |
@@ -1,3 +1,4 @@
|
||||
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<path fill="#9AA7B0" fill-opacity=".8" d="M1,1 L15,1 L15,14 L1,14 L1,1 Z M2,4 L2,13 L14,13 L14,4 L2,4 Z"/>
|
||||
|
||||
|
Before Width: | Height: | Size: 326 B After Width: | Height: | Size: 473 B |