Skip to content

Commit

Permalink
macOS light and dark themes (issue #497)
Browse files Browse the repository at this point in the history
  • Loading branch information
DevCharly committed May 10, 2022
1 parent 37c375e commit 3ca15ad
Show file tree
Hide file tree
Showing 20 changed files with 4,041 additions and 45 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Expand Up @@ -9,5 +9,7 @@ out/
*.iml
*.ipr
*.iws
*.xcuserstate
*.xcworkspacedata
.vs/
.vscode/
2 changes: 1 addition & 1 deletion flatlaf-core/build.gradle.kts
Expand Up @@ -83,7 +83,7 @@ tasks {
"action" to "generate",
"fileName" to "${project.name}-sigtest.txt",
"classpath" to jar.get().outputs.files.asPath,
"packages" to "com.formdev.flatlaf,com.formdev.flatlaf.util",
"packages" to "com.formdev.flatlaf,com.formdev.flatlaf.themes,com.formdev.flatlaf.util",
"version" to version,
"release" to "1.8", // Java version
"failonerror" to "true" )
Expand Down
@@ -0,0 +1,68 @@
/*
* Copyright 2022 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.themes;

import javax.swing.UIManager;
import com.formdev.flatlaf.FlatDarkLaf;

/**
* A Flat LaF that imitates macOS dark look.
* <p>
* The UI defaults are loaded from {@code FlatMacDarkLaf.properties},
* {@code FlatDarkLaf.properties} and {@code FlatLaf.properties}.
*
* @author Karl Tauber
* @since 3
*/
public class FlatMacDarkLaf
extends FlatDarkLaf
{
public static final String NAME = "FlatLaf macOS Dark";

/**
* Sets the application look and feel to this LaF
* using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}.
*/
public static boolean setup() {
return setup( new FlatMacDarkLaf() );
}

/**
* Adds this look and feel to the set of available look and feels.
* <p>
* Useful if your application uses {@link UIManager#getInstalledLookAndFeels()}
* to query available LaFs and display them to the user in a combobox.
*/
public static void installLafInfo() {
installLafInfo( NAME, FlatMacDarkLaf.class );
}

@Override
public String getName() {
return NAME;
}

@Override
public String getDescription() {
return "FlatLaf macOS Dark Look and Feel";
}

@Override
public boolean isDark() {
return true;
}
}
@@ -0,0 +1,68 @@
/*
* Copyright 2022 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.themes;

import javax.swing.UIManager;
import com.formdev.flatlaf.FlatLightLaf;

/**
* A Flat LaF that imitates macOS light look.
* <p>
* The UI defaults are loaded from {@code FlatMacLightLaf.properties},
* {@code FlatLightLaf.properties} and {@code FlatLaf.properties}.
*
* @author Karl Tauber
* @since 3
*/
public class FlatMacLightLaf
extends FlatLightLaf
{
public static final String NAME = "FlatLaf macOS Light";

/**
* Sets the application look and feel to this LaF
* using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}.
*/
public static boolean setup() {
return setup( new FlatMacLightLaf() );
}

/**
* Adds this look and feel to the set of available look and feels.
* <p>
* Useful if your application uses {@link UIManager#getInstalledLookAndFeels()}
* to query available LaFs and display them to the user in a combobox.
*/
public static void installLafInfo() {
installLafInfo( NAME, FlatMacLightLaf.class );
}

@Override
public String getName() {
return NAME;
}

@Override
public String getDescription() {
return "FlatLaf macOS Light Look and Feel";
}

@Override
public boolean isDark() {
return false;
}
}
Expand Up @@ -48,8 +48,10 @@ public class FlatArrowButton
protected Color pressedBackground;

private int arrowWidth = DEFAULT_ARROW_WIDTH;
private float arrowThickness = 1;
private float xOffset = 0;
private float yOffset = 0;
private boolean roundBorderAutoXOffset = true;

private boolean hover;
private boolean pressed;
Expand Down Expand Up @@ -116,6 +118,16 @@ public void setArrowWidth( int arrowWidth ) {
this.arrowWidth = arrowWidth;
}

/** @since 3 */
public float getArrowThickness() {
return arrowThickness;
}

/** @since 3 */
public void setArrowThickness( float arrowThickness ) {
this.arrowThickness = arrowThickness;
}

protected boolean isHover() {
return hover;
}
Expand All @@ -140,6 +152,16 @@ public void setYOffset( float yOffset ) {
this.yOffset = yOffset;
}

/** @since 3 */
public boolean isRoundBorderAutoXOffset() {
return roundBorderAutoXOffset;
}

/** @since 3 */
public void setRoundBorderAutoXOffset( boolean roundBorderAutoXOffset ) {
this.roundBorderAutoXOffset = roundBorderAutoXOffset;
}

protected Color deriveBackground( Color background ) {
return background;
}
Expand Down Expand Up @@ -203,14 +225,17 @@ protected void paintBackground( Graphics2D g ) {
}

protected void paintArrow( Graphics2D g ) {
boolean vert = (direction == NORTH || direction == SOUTH);
int x = 0;

// move arrow for round borders
Container parent = getParent();
if( vert && parent instanceof JComponent && FlatUIUtils.hasRoundBorder( (JComponent) parent ) )
x -= scale( parent.getComponentOrientation().isLeftToRight() ? 1 : -1 );
if( isRoundBorderAutoXOffset() ) {
Container parent = getParent();
boolean vert = (direction == NORTH || direction == SOUTH);
if( vert && parent instanceof JComponent && FlatUIUtils.hasRoundBorder( (JComponent) parent ) )
x -= scale( parent.getComponentOrientation().isLeftToRight() ? 1 : -1 );
}

FlatUIUtils.paintArrow( g, x, 0, getWidth(), getHeight(), getDirection(), chevron, getArrowWidth(), getXOffset(), getYOffset() );
FlatUIUtils.paintArrow( g, x, 0, getWidth(), getHeight(), getDirection(), chevron,
getArrowWidth(), getArrowThickness(), getXOffset(), getYOffset() );
}
}
Expand Up @@ -96,7 +96,7 @@
* @uiDefault ComboBox.minimumWidth int
* @uiDefault ComboBox.editorColumns int
* @uiDefault ComboBox.maximumRowCount int
* @uiDefault ComboBox.buttonStyle String auto (default), button or none
* @uiDefault ComboBox.buttonStyle String auto (default), button, mac or none
* @uiDefault Component.arrowType String chevron (default) or triangle
* @uiDefault Component.isIntelliJTheme boolean
* @uiDefault ComboBox.editableBackground Color optional; defaults to ComboBox.background
Expand Down Expand Up @@ -538,7 +538,9 @@ public void update( Graphics g, JComponent c ) {
int height = c.getHeight();
int arrowX = arrowButton.getX();
int arrowWidth = arrowButton.getWidth();
boolean paintButton = (comboBox.isEditable() || "button".equals( buttonStyle )) && !"none".equals( buttonStyle );
boolean paintButton = (comboBox.isEditable() || "button".equals( buttonStyle )) &&
!"none".equals( buttonStyle ) &&
!isMacStyle();
boolean enabled = comboBox.isEnabled();
boolean isLeftToRight = comboBox.getComponentOrientation().isLeftToRight();

Expand All @@ -556,13 +558,21 @@ public void update( Graphics g, JComponent c ) {
: buttonBackground;
if( buttonColor != null ) {
g2.setColor( buttonColor );
Shape oldClip = g2.getClip();
if( isLeftToRight )
g2.clipRect( arrowX, 0, width - arrowX, height );
else
g2.clipRect( 0, 0, arrowX + arrowWidth, height );
FlatUIUtils.paintComponentBackground( g2, 0, 0, width, height, focusWidth, arc );
g2.setClip( oldClip );
if( isMacStyle() ) {
Insets insets = comboBox.getInsets();
int gap = scale( 2 );
FlatUIUtils.paintComponentBackground( g2, arrowX + gap, insets.top + gap,
arrowWidth - (gap * 2), height - insets.top - insets.bottom - (gap * 2),
0, arc - focusWidth );
} else {
Shape oldClip = g2.getClip();
if( isLeftToRight )
g2.clipRect( arrowX, 0, width - arrowX, height );
else
g2.clipRect( 0, 0, arrowX + arrowWidth, height );
FlatUIUtils.paintComponentBackground( g2, 0, 0, width, height, focusWidth, arc );
g2.setClip( oldClip );
}
}
}

Expand Down Expand Up @@ -698,6 +708,10 @@ private boolean isCellRendererBackgroundChanged() {
return parentParent != null && !comboBox.getBackground().equals( parentParent.getBackground() );
}

private boolean isMacStyle() {
return "mac".equals( buttonStyle );
}

/** @since 1.3 */
public static boolean isPermanentFocusOwner( JComboBox<?> comboBox ) {
if( comboBox.isEditable() ) {
Expand All @@ -718,6 +732,12 @@ protected class FlatComboBoxButton
protected FlatComboBoxButton() {
this( SwingConstants.SOUTH, arrowType, buttonArrowColor, buttonDisabledArrowColor,
buttonHoverArrowColor, null, buttonPressedArrowColor, null );

if( isMacStyle() ) {
setArrowWidth( 7 );
setArrowThickness( 1.5f );
setRoundBorderAutoXOffset( false );
}
}

protected FlatComboBoxButton( int direction, String type, Color foreground, Color disabledForeground,
Expand Down Expand Up @@ -749,6 +769,20 @@ protected Color getArrowColor() {

return super.getArrowColor();
}

@Override
protected void paintArrow( Graphics2D g ) {
if( isMacStyle() && !comboBox.isEditable() ) {
// for style "mac", paint up and down arrows if combobox is not editable
int height = getHeight();
int h = Math.round( height / 2f );
FlatUIUtils.paintArrow( g, 0, 0, getWidth(), h, SwingConstants.NORTH, chevron,
getArrowWidth(), getArrowThickness(), getXOffset(), getYOffset() + 1.25f );
FlatUIUtils.paintArrow( g, 0, height - h, getWidth(), h, SwingConstants.SOUTH, chevron,
getArrowWidth(), getArrowThickness(), getXOffset(), getYOffset() - 1.25f );
} else
super.paintArrow( g );
}
}

//---- class FlatComboPopup -----------------------------------------------
Expand Down

0 comments on commit 3ca15ad

Please sign in to comment.