Browse Source

Pull request #14611: 无jira newui合fbp

Merge in DESIGN/design from ~LEVY.XIE/design:fbp-1.0 to fbp-1.0

* commit '5eba8a469ebf793ab74ce316627fea723f5e54d6': (299 commits)
  无jira 解决合并分支冲突
  REPORT-130921 & REPORT-130922 & REPORT-130807 【NewUI】测试验收问题修复
  REPORT-130921 & REPORT-130922 & REPORT-130807 【NewUI】测试验收问题修复
  边框问题
  边框问题
  REPORT-113994 【NewUI】视觉&测试验收问题修复
  气泡弹窗
  REPORT-127437 fix:数据筛选缩放问题
  REPORT-130919 & REPORT-130916 & REPORT-130911 &REPORT-130847 & REPORT-130831 & REPORT-130830 & REPORT-130756 & REPORT-130707 & REPORT-130263 fix:【NewUI】问题修复
  边框问题
  边框问题
  REPORT-127437 fix:数据字典增加类型问题修复
  修改width
  REPORT-127437 fix: 新建 poly sheet 按钮缩放问题
  单元格元素-数据列-过滤普通未换行
  模板主题配置;单元格元素缩放,新增图标
  REPORT-127437 fix: 图表条件属性翻新,视觉问题调整
  REPORT-113994 【NewUI】视觉&测试验收问题修复
  REPORT-113994 【NewUI】视觉&测试验收问题修复
  vcs问题待产品确认再修改
  ...
fbp-1.0
Levy.Xie-解安森 3 months ago
parent
commit
85ad118765
  1. 9
      build.gradle
  2. 12
      designer-base/build.base.gradle
  3. 68
      designer-base/src/main/java/com/fine/theme/icon/AbstractIconSet.java
  4. 109
      designer-base/src/main/java/com/fine/theme/icon/AbstractIconSource.java
  5. 23
      designer-base/src/main/java/com/fine/theme/icon/DisabledIcon.java
  6. 59
      designer-base/src/main/java/com/fine/theme/icon/GraphicsFilter.java
  7. 29
      designer-base/src/main/java/com/fine/theme/icon/IconException.java
  8. 179
      designer-base/src/main/java/com/fine/theme/icon/IconManager.java
  9. 23
      designer-base/src/main/java/com/fine/theme/icon/IconResource.java
  10. 50
      designer-base/src/main/java/com/fine/theme/icon/IconSet.java
  11. 37
      designer-base/src/main/java/com/fine/theme/icon/IconSource.java
  12. 24
      designer-base/src/main/java/com/fine/theme/icon/IconType.java
  13. 12
      designer-base/src/main/java/com/fine/theme/icon/Identifiable.java
  14. 125
      designer-base/src/main/java/com/fine/theme/icon/JsonIconSet.java
  15. 120
      designer-base/src/main/java/com/fine/theme/icon/LazyIcon.java
  16. 53
      designer-base/src/main/java/com/fine/theme/icon/UrlIconResource.java
  17. 22
      designer-base/src/main/java/com/fine/theme/icon/WhiteIcon.java
  18. 75
      designer-base/src/main/java/com/fine/theme/icon/icons/AnimatedRadioButtonIcon.java
  19. 58
      designer-base/src/main/java/com/fine/theme/icon/img/ImageIconSource.java
  20. 207
      designer-base/src/main/java/com/fine/theme/icon/svg/SvgIcon.java
  21. 43
      designer-base/src/main/java/com/fine/theme/icon/svg/SvgIconSource.java
  22. 50
      designer-base/src/main/java/com/fine/theme/icon/svg/WhiteParser.java
  23. 160
      designer-base/src/main/java/com/fine/theme/icon/svg/batik/BatikSvgIcon.java
  24. 90
      designer-base/src/main/java/com/fine/theme/icon/svg/batik/SvgTranscoder.java
  25. 73
      designer-base/src/main/java/com/fine/theme/light/ui/CollapsibleScrollBarLayerUI.java
  26. 42
      designer-base/src/main/java/com/fine/theme/light/ui/FineButtonBorder.java
  27. 30
      designer-base/src/main/java/com/fine/theme/light/ui/FineButtonGroupUI.java
  28. 114
      designer-base/src/main/java/com/fine/theme/light/ui/FineButtonUI.java
  29. 37
      designer-base/src/main/java/com/fine/theme/light/ui/FineCheckBoxUI.java
  30. 66
      designer-base/src/main/java/com/fine/theme/light/ui/FineColorButtonUI.java
  31. 90
      designer-base/src/main/java/com/fine/theme/light/ui/FineCombinationButtonUI.java
  32. 67
      designer-base/src/main/java/com/fine/theme/light/ui/FineComboBoxUI.java
  33. 309
      designer-base/src/main/java/com/fine/theme/light/ui/FineGradientBarUI.java
  34. 74
      designer-base/src/main/java/com/fine/theme/light/ui/FineHeadGroupUI.java
  35. 112
      designer-base/src/main/java/com/fine/theme/light/ui/FineHeaderPaneUI.java
  36. 68
      designer-base/src/main/java/com/fine/theme/light/ui/FineInputUI.java
  37. 17
      designer-base/src/main/java/com/fine/theme/light/ui/FineLightIconSet.java
  38. 80
      designer-base/src/main/java/com/fine/theme/light/ui/FineMenuItemUI.java
  39. 38
      designer-base/src/main/java/com/fine/theme/light/ui/FineOptionPaneUI.java
  40. 55
      designer-base/src/main/java/com/fine/theme/light/ui/FinePanelUI.java
  41. 19
      designer-base/src/main/java/com/fine/theme/light/ui/FinePopupMenuBorder.java
  42. 70
      designer-base/src/main/java/com/fine/theme/light/ui/FinePopupMenuSeparatorUI.java
  43. 58
      designer-base/src/main/java/com/fine/theme/light/ui/FinePopupMenuUI.java
  44. 28
      designer-base/src/main/java/com/fine/theme/light/ui/FineReportComponentBorder.java
  45. 40
      designer-base/src/main/java/com/fine/theme/light/ui/FineReportComponentCompositeUI.java
  46. 63
      designer-base/src/main/java/com/fine/theme/light/ui/FineRoundBorder.java
  47. 49
      designer-base/src/main/java/com/fine/theme/light/ui/FineSelectBoxUI.java
  48. 344
      designer-base/src/main/java/com/fine/theme/light/ui/FineSliderUI.java
  49. 108
      designer-base/src/main/java/com/fine/theme/light/ui/FineTableHeaderUI.java
  50. 53
      designer-base/src/main/java/com/fine/theme/light/ui/FineTableScrollBarPaneUI.java
  51. 52
      designer-base/src/main/java/com/fine/theme/light/ui/FineTemplateListMenuItemUI.java
  52. 396
      designer-base/src/main/java/com/fine/theme/light/ui/FineTemplateTabPaneUI.java
  53. 218
      designer-base/src/main/java/com/fine/theme/light/ui/FineToggleButtonUI.java
  54. 102
      designer-base/src/main/java/com/fine/theme/light/ui/FineTooltipUI.java
  55. 64
      designer-base/src/main/java/com/fine/theme/light/ui/RectangleButtonUI.java
  56. 92
      designer-base/src/main/java/com/fine/theme/light/ui/ReportScrollBarUI.java
  57. 32
      designer-base/src/main/java/com/fine/theme/light/ui/UIFlatTreeUI.java
  58. 52
      designer-base/src/main/java/com/fine/theme/light/ui/laf/FineDarkLaf.java
  59. 56
      designer-base/src/main/java/com/fine/theme/light/ui/laf/FineLaf.java
  60. 52
      designer-base/src/main/java/com/fine/theme/light/ui/laf/FineLightLaf.java
  61. 131
      designer-base/src/main/java/com/fine/theme/utils/AnimatedPainter.java
  62. 174
      designer-base/src/main/java/com/fine/theme/utils/AnimatedPainterSupport.java
  63. 43
      designer-base/src/main/java/com/fine/theme/utils/FineClientProperties.java
  64. 65
      designer-base/src/main/java/com/fine/theme/utils/FineComponentsFactory.java
  65. 189
      designer-base/src/main/java/com/fine/theme/utils/FineLayoutBuilder.java
  66. 25
      designer-base/src/main/java/com/fine/theme/utils/FineUIConstants.java
  67. 86
      designer-base/src/main/java/com/fine/theme/utils/FineUIScale.java
  68. 121
      designer-base/src/main/java/com/fine/theme/utils/FineUIStyle.java
  69. 438
      designer-base/src/main/java/com/fine/theme/utils/FineUIUtils.java
  70. 12
      designer-base/src/main/java/com/fr/design/actions/AllowAuthorityEditAction.java
  71. 14
      designer-base/src/main/java/com/fr/design/actions/TableDataSourceAction.java
  72. 20
      designer-base/src/main/java/com/fr/design/actions/UpdateAction.java
  73. 3
      designer-base/src/main/java/com/fr/design/actions/community/BBSAction.java
  74. 3
      designer-base/src/main/java/com/fr/design/actions/community/BugAction.java
  75. 6
      designer-base/src/main/java/com/fr/design/actions/community/BugNeedAction.java
  76. 3
      designer-base/src/main/java/com/fr/design/actions/community/CenterAction.java
  77. 3
      designer-base/src/main/java/com/fr/design/actions/community/NeedAction.java
  78. 3
      designer-base/src/main/java/com/fr/design/actions/community/QuestionAction.java
  79. 3
      designer-base/src/main/java/com/fr/design/actions/community/SignAction.java
  80. 3
      designer-base/src/main/java/com/fr/design/actions/community/StudyPlanAction.java
  81. 3
      designer-base/src/main/java/com/fr/design/actions/community/TechSolutionAction.java
  82. 4
      designer-base/src/main/java/com/fr/design/actions/community/TemplateStoreAction.java
  83. 5
      designer-base/src/main/java/com/fr/design/actions/community/VideoAction.java
  84. 3
      designer-base/src/main/java/com/fr/design/actions/community/WorkOrderCenterAction.java
  85. 22
      designer-base/src/main/java/com/fr/design/actions/core/ActionFactory.java
  86. 3
      designer-base/src/main/java/com/fr/design/actions/edit/CopyAction.java
  87. 4
      designer-base/src/main/java/com/fr/design/actions/edit/CutAction.java
  88. 3
      designer-base/src/main/java/com/fr/design/actions/edit/PasteAction.java
  89. 7
      designer-base/src/main/java/com/fr/design/actions/edit/RedoAction.java
  90. 7
      designer-base/src/main/java/com/fr/design/actions/edit/UndoAction.java
  91. 2
      designer-base/src/main/java/com/fr/design/actions/file/CloseCurrentTemplateAction.java
  92. 3
      designer-base/src/main/java/com/fr/design/actions/file/DelFileAction.java
  93. 2
      designer-base/src/main/java/com/fr/design/actions/file/EditEnvAction.java
  94. 2
      designer-base/src/main/java/com/fr/design/actions/file/ExitDesignerAction.java
  95. 3
      designer-base/src/main/java/com/fr/design/actions/file/LocateAction.java
  96. 4
      designer-base/src/main/java/com/fr/design/actions/file/OpenRecentReportMenuDef.java
  97. 8
      designer-base/src/main/java/com/fr/design/actions/file/OpenTemplateAction.java
  98. 2
      designer-base/src/main/java/com/fr/design/actions/file/PreferenceAction.java
  99. 545
      designer-base/src/main/java/com/fr/design/actions/file/PreferencePane.java
  100. 23
      designer-base/src/main/java/com/fr/design/actions/file/RenameAction.java
  101. Some files were not shown because too many files have changed in this diff Show More

9
build.gradle

@ -114,8 +114,8 @@ allprojects {
implementation 'org.swingexplorer:swexpl:2.0.1'
implementation 'org.swingexplorer:swag:1.0'
implementation 'net.java.dev.jna:jna:5.4.0'
implementation 'org.apache.tomcat:tomcat-catalina:8.5.72'
implementation 'org.apache.tomcat:tomcat-websocket:8.5.72'
implementation 'org.apache.tomcat:tomcat-catalina:8.5.93'
implementation 'org.apache.tomcat:tomcat-websocket:8.5.93'
implementation 'io.socket:socket.io-client:0.7.0'
implementation('com.fr.third:fine-third:' + frVersion) { exclude group: "com.fr.cbb", module: "fine-cbb" }
implementation 'com.fr.core:fine-core:' + frDevVersion
@ -128,7 +128,11 @@ allprojects {
implementation 'com.fr.report:engine-chart:' + frDevVersion
implementation 'com.fr.report:engine-i18n:' + frDevVersion
implementation 'com.fr.design:design-i18n:' + frDevVersion
implementation 'com.github.weisj:jsvg:1.2.0'
implementation 'com.formdev:flatlaf:3.4'
implementation 'com.formdev:flatlaf-extras:3.4'
implementation 'com.fine.swing.ui:layout:1.0-SNAPSHOT'
implementation 'com.fanruan.vito:gui-inspector:1.0.2'
testImplementation 'org.easymock:easymock:3.5.1'
testImplementation 'org.powermock:powermock-module-junit4:1.7.1'
testImplementation 'org.powermock:powermock-api-easymock:1.7.1'
@ -140,6 +144,7 @@ allprojects {
if (OperatingSystem.current().isMacOsX() && "aarch64".equals(System.getProperty("os.arch"))) {
dependencies {
// jxbrowser 6.23M16.23jar还是需要留着
implementation 'com.fr.third:jxbrowser-mac:6.23'
implementation "com.fr.third:jxbrowser-mac-arm-v7:${jxBrowserVersion}"
}
} else if (OperatingSystem.current().isMacOsX()) {

12
designer-base/build.base.gradle

@ -59,12 +59,12 @@ def branchName=buildDir.substring(buildDir.lastIndexOf ('\\')+1)
//
dependencies{
compile fileTree(dir:"../${baseDir}/lib-other",include:'**/*.jar')
compile fileTree(dir:"../${baseDir}/lib-core",include:'**/*.jar')
compile fileTree(dir:"../${baseDir}/lib-design",include:'**/*.jar')
compile fileTree(dir:"../${baseDir}",include:"**/build/libs/*.jar",exclude:"bi/**/*.jar")
compile group: 'io.socket', name: 'socket.io-client', version: '0.7.0'
testCompile 'junit:junit:4.12'
api fileTree(dir:"../${baseDir}/lib-other",include:'**/*.jar')
api fileTree(dir:"../${baseDir}/lib-core",include:'**/*.jar')
api fileTree(dir:"../${baseDir}/lib-design",include:'**/*.jar')
api fileTree(dir:"../${baseDir}",include:"**/build/libs/*.jar",exclude:"bi/**/*.jar")
api group: 'io.socket', name: 'socket.io-client', version: '0.7.0'
testImplementation 'junit:junit:4.12'
}
//

68
designer-base/src/main/java/com/fine/theme/icon/AbstractIconSet.java

@ -0,0 +1,68 @@
package com.fine.theme.icon;
import com.fr.essential.errorprone.annotations.Immutable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.Icon;
import java.awt.Dimension;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 抽象图标集
*
* @author vito
* @since 11.0
* Created on 2023/11/15
*/
@Immutable
public abstract class AbstractIconSet implements IconSet {
protected String name;
protected boolean dark;
private final Map<String, IconSource<? extends Icon>> iconSourceMap = new ConcurrentHashMap<>(64);
private final Map<String, Icon> iconCache = new ConcurrentHashMap<>(64);
public AbstractIconSet() {
}
@Override
public @NotNull String getId() {
return name;
}
@Override
public @NotNull Collection<String> getIds() {
return iconSourceMap.keySet();
}
@Override
public void addIcon(@NotNull IconSource<? extends Icon> icon) {
iconSourceMap.put(icon.getId(), icon);
}
@SafeVarargs
@Override
public final void addIcon(@NotNull IconSource<? extends Icon>... icons) {
for (IconSource<? extends Icon> icon : icons) {
iconSourceMap.put(icon.getId(), icon);
}
}
@Override
public @Nullable Icon findIcon(@NotNull String id, @NotNull Dimension dimension, IconType type) {
String cacheKey = IconManager.genCacheKey(id, dimension, type);
Icon icon = iconCache.get(cacheKey);
if (icon == null) {
IconSource<? extends Icon> iconSource = iconSourceMap.get(id);
if (iconSource != null) {
icon = iconSource.loadIcon(dimension, type);
iconCache.put(cacheKey, icon);
}
}
return icon;
}
}

109
designer-base/src/main/java/com/fine/theme/icon/AbstractIconSource.java

@ -0,0 +1,109 @@
package com.fine.theme.icon;
import com.fr.third.errorprone.annotations.Immutable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.Icon;
import java.awt.Dimension;
/**
* 抽象图标源
* <p>
* 1. 记录图标来源的所有信息
* 2. 如果使用来源提供灰化和反白图标source负责提供图标的不同来源
* 3. 默认查找命名如图标名称为 path/pic.svg,根据以下规则自动查询灰化和反白图标
* 1). 灰化图 path/pic_disable.svg
* 2). 反白图 path/pic_white.svg
*
* @author vito
* @since 11.0
* Created on 2023/11/14
*/
@Immutable
public abstract class AbstractIconSource<I extends Icon> implements IconSource<I> {
protected String id;
protected final IconResource resource;
@Nullable
protected IconResource grayResource;
@Nullable
protected IconResource whiteResource;
public AbstractIconSource(@NotNull final String id, @NotNull final IconResource resource) {
this.id = id;
this.resource = resource;
}
public AbstractIconSource(@NotNull final String id,
@NotNull final IconResource resource,
@Nullable final IconResource grayResource,
@Nullable final IconResource whiteResource) {
this.id = id;
this.resource = resource;
this.grayResource = grayResource;
this.whiteResource = whiteResource;
}
@NotNull
@Override
public String getId() {
return id;
}
@NotNull
@Override
public IconResource getResource() {
return resource;
}
@NotNull
@Override
public I loadIcon(Dimension dimension, IconType type) {
try {
switch (type) {
case disable:
return loadDisabledIcon(dimension);
case white:
return white(dimension);
default:
return loadIcon(resource, dimension, type);
}
} catch (final Exception e) {
throw new IconException("Unable to load Icon: " + getId(), e);
}
}
@NotNull
protected abstract I loadIcon(@NotNull IconResource resource, Dimension dimension, IconType type);
/**
* 先找提供明确URL的灰化图
* 再找指定自动寻找路径的灰化图
* 最后再由具体图标提供默认灰化图
*
* @return 灰化图
*/
private @NotNull I loadDisabledIcon(Dimension dimension) {
if (grayResource != null) {
return loadIcon(grayResource, dimension, IconType.normal);
}
return loadIcon(resource, dimension, IconType.disable);
}
private @NotNull I white(Dimension dimension) {
if (whiteResource != null) {
return loadIcon(whiteResource, dimension, IconType.normal);
}
return loadIcon(resource, dimension, IconType.white);
}
}

23
designer-base/src/main/java/com/fine/theme/icon/DisabledIcon.java

@ -0,0 +1,23 @@
package com.fine.theme.icon;
import org.jetbrains.annotations.NotNull;
import javax.swing.Icon;
/**
* 创建一个灰化 Icon
*
* @author vito
* @since 11.0
* Created on 2023/11/16
*/
public interface DisabledIcon {
/**
* 创建一份灰化图标
*
* @return 灰化图标
*/
@NotNull
Icon disabled();
}

59
designer-base/src/main/java/com/fine/theme/icon/GraphicsFilter.java

@ -0,0 +1,59 @@
package com.fine.theme.icon;
import com.formdev.flatlaf.util.Graphics2DProxy;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.image.RGBImageFilter;
/**
* 颜色过滤器画板
*
* @author vito
* @since 11.0
* Created on 2023/11/21
*/
public class GraphicsFilter
extends Graphics2DProxy {
private final RGBImageFilter grayFilter;
public GraphicsFilter(Graphics2D delegate, RGBImageFilter grayFilter) {
super(delegate);
this.grayFilter = grayFilter;
}
@Override
public Graphics create() {
return new GraphicsFilter((Graphics2D) super.create(), grayFilter);
}
@Override
public Graphics create(int x, int y, int width, int height) {
return new GraphicsFilter((Graphics2D) super.create(x, y, width, height), grayFilter);
}
@Override
public void setColor(Color c) {
super.setColor(filterColor(c));
}
@Override
public void setPaint(Paint paint) {
if (paint instanceof Color) {
paint = filterColor((Color) paint);
}
super.setPaint(paint);
}
private Color filterColor(Color color) {
if (grayFilter != null) {
int oldRGB = color.getRGB();
int newRGB = grayFilter.filterRGB(0, 0, oldRGB);
color = (newRGB != oldRGB) ? new Color(newRGB, true) : color;
}
return color;
}
}

29
designer-base/src/main/java/com/fine/theme/icon/IconException.java

@ -0,0 +1,29 @@
package com.fine.theme.icon;
/**
* 图标异常
*
* @author vito
* @since 11.0
* Created on 2023/11/6
*/
public class IconException extends RuntimeException {
public IconException() {
}
public IconException(String message) {
super(message);
}
public IconException(String message, Throwable cause) {
super(message, cause);
}
public IconException(Throwable cause) {
super(cause);
}
public IconException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}

179
designer-base/src/main/java/com/fine/theme/icon/IconManager.java

@ -0,0 +1,179 @@
package com.fine.theme.icon;
import com.fr.base.extension.FileExtension;
import com.fr.general.IOUtils;
import com.fr.log.FineLoggerFactory;
import com.fr.third.errorprone.annotations.Immutable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.Icon;
import java.awt.Dimension;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
/**
* 图标管理器
* 1. 提供注册管理图标集方便整体替换
* 2. 提供图标缓存
* 3. 查找图标
* 4. 配合 {@link LazyIcon} 实现图标懒加载
*
* @author vito
* @since 11.0
* Created on 2023/9/12
*/
@Immutable
public class IconManager {
public static final String ICON_DISABLE_SUFFIX = "_disable";
public static final Dimension DEFAULT_DIMENSION = new Dimension(16, 16);
private static final ArrayList<IconSet> ICON_SETS = new ArrayList<>(2);
private static final HashMap<String, WeakReference<Icon>> CACHE = new HashMap<>(64);
/**
* 获取图标集
*
* @param id 图标集ID
* @return 图标集
*/
public static IconSet getSet(String id) {
for (IconSet set : ICON_SETS) {
if (set.getId().equals(id)) {
return set;
}
}
throw new IconException("[IconManager] Can not find icon set by id: " + id);
}
/**
* 添加图标集
*
* @param set 图标集
*/
public static void addSet(@NotNull IconSet set) {
ICON_SETS.remove(set);
ICON_SETS.add(set);
clearCache();
}
/**
* 根据图标ID获取图标
* <p>
* 查找路径
* 1查找图集图标
* 2路径为图片图标从路径再查找
* 3提供默认svg图标
*
* @param id 图标ID
* @param <I> 图标类型
* @return 图标
*/
@NotNull
public static <I extends Icon> I getIcon(@NotNull final String id, @NotNull Dimension dimension, @NotNull IconType type) {
Icon icon = findIcon(id, dimension, type);
if (icon == null) {
// 只有找不到再进行其他fallback,提升效率
if (IconManager.isImageIcon(id)) {
return (I) fallbackLegacyIcon(id);
} else {
FineLoggerFactory.getLogger().warn("[IconManager] Can not find icon by id: " + id);
return (I) new LazyIcon("default");
}
}
return (I) icon;
}
private static Icon fallbackLegacyIcon(String id) {
return IOUtils.readIcon(id);
}
@Nullable
private static <I extends Icon> I findIcon(String id, Dimension dimension, IconType type) {
String cacheKey = genCacheKey(id, dimension, type);
final WeakReference<Icon> reference = CACHE.get(cacheKey);
I icon = reference != null ? (I) reference.get() : null;
if (icon == null) {
for (IconSet set : ICON_SETS) {
Icon f = set.findIcon(id, dimension, type);
if (f != null) {
icon = (I) f;
CACHE.put(cacheKey, new WeakReference<>(icon));
}
}
}
return icon;
}
/**
* 生成缓存key
*
* @param id id
* @param dimension 尺寸
* @param type 图标类型
* @return 缓存key
*/
public static @NotNull String genCacheKey(String id, Dimension dimension, IconType type) {
if (DEFAULT_DIMENSION.equals(dimension)) {
return id + "_" + type;
}
return id + "_" + dimension.width + "_" + dimension.height + "_" + type;
}
/**
* 是否SVG图标格式
*
* @param path 路径
* @return 是否SVG图标格式
*/
public static boolean isSvgIcon(String path) {
return FileExtension.SVG.matchExtension(path);
}
/**
* 是否支持的图片图标格式目前只支持png和jpg
*
* @param path 路径
* @return 是否支持的图片图标格式
*/
public static boolean isImageIcon(String path) {
return FileExtension.PNG.matchExtension(path)
|| FileExtension.JPG.matchExtension(path);
}
/**
* 判断是否存在指定id的icon非io读取行为而是从已注册的sourceMap中遍历判断
*
* @param id id
* @return 是否存在
*/
public static boolean existIcon(String id) {
for (IconSet set : ICON_SETS) {
if (set.getIds().contains(id)) {
return true;
}
}
return false;
}
/**
* 清理所有缓存
*/
public static void clearCache() {
CACHE.clear();
}
/**
* 查找灰化图标
*
* @param path 原始路径
* @return 灰化路径
*/
public static String findDisablePath(String path) {
int i = path.lastIndexOf('.');
return path.substring(0, i) + ICON_DISABLE_SUFFIX + path.substring(i);
}
}

23
designer-base/src/main/java/com/fine/theme/icon/IconResource.java

@ -0,0 +1,23 @@
package com.fine.theme.icon;
import org.jetbrains.annotations.NotNull;
import java.io.InputStream;
/**
* 资源接口
*
* @author vito
* @since 11.0
* Created on 2023/11/6
*/
public interface IconResource {
/**
* 获取输入资源流
*
* @return 资源流
*/
@NotNull
InputStream getInputStream();
}

50
designer-base/src/main/java/com/fine/theme/icon/IconSet.java

@ -0,0 +1,50 @@
package com.fine.theme.icon;
import com.fr.third.errorprone.annotations.Immutable;
import org.jetbrains.annotations.NotNull;
import javax.swing.Icon;
import java.awt.Dimension;
import java.util.Collection;
/**
* 图标集
*
* @author vito
* @since 11.0
* Created on 2023/11/6
*/
@Immutable
public interface IconSet extends Identifiable {
/**
* 返回集合中所有 Icons id
*
* @return 集合中所有 Icons id
*/
@NotNull
Collection<String> getIds();
/**
* 将指定 IconSource 引用的新 Icon 添加到集合中
*
* @param icon icon
*/
void addIcon(@NotNull IconSource<? extends Icon> icon);
/**
* 将指定 IconSource 引用的新 Icon 添加到集合中
*
* @param icon icon
*/
void addIcon(@NotNull IconSource<? extends Icon>... icon);
/**
* 返回指定 id Icon
*
* @param id id
* @return Icon
*/
Icon findIcon(@NotNull String id, @NotNull Dimension dimension, IconType type);
}

37
designer-base/src/main/java/com/fine/theme/icon/IconSource.java

@ -0,0 +1,37 @@
package com.fine.theme.icon;
import com.fr.third.errorprone.annotations.Immutable;
import org.jetbrains.annotations.NotNull;
import javax.swing.Icon;
import java.awt.Dimension;
import java.io.Serializable;
/**
* 图标源在进行图标管理的时候代替真实图标对象
* 使用时加载节省内存
*
* @author vito
* @since 11.0
* Created on 2023/11/6
*/
@Immutable
public interface IconSource<I extends Icon> extends Identifiable, Cloneable, Serializable {
/**
* 获取图标资源
*
* @return 图标资源
*/
@NotNull
IconResource getResource();
/**
* 加载图标
*
* @return 图标
*/
@NotNull
I loadIcon(Dimension dimension, IconType type);
}

24
designer-base/src/main/java/com/fine/theme/icon/IconType.java

@ -0,0 +1,24 @@
package com.fine.theme.icon;
/**
* 图标类型
*
* @author vito
* @since 11.0
* Created on 2024/01/09
*/
public enum IconType {
/**
* 灰化图
*/
disable,
/**
* 白化图用于反白场景
*/
white,
/**
* 原始图
*/
normal
}

12
designer-base/src/main/java/com/fine/theme/icon/Identifiable.java

@ -0,0 +1,12 @@
package com.fine.theme.icon;
/**
* id 接口
*
* @author vito
* @since 11.0
* Created on 2023/11/6
*/
public interface Identifiable {
String getId();
}

125
designer-base/src/main/java/com/fine/theme/icon/JsonIconSet.java

@ -0,0 +1,125 @@
package com.fine.theme.icon;
import com.fine.theme.icon.img.ImageIconSource;
import com.fine.theme.icon.svg.SvgIconSource;
import com.formdev.flatlaf.json.Json;
import com.formdev.flatlaf.json.ParseException;
import com.fr.stable.StringUtils;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.Objects;
/**
* json 格式图标集
*
* @author vito
* @since 11.0
* Created on 2023/11/17
*/
public class JsonIconSet extends AbstractIconSet {
private String base;
public JsonIconSet(UrlIconResource resource) {
addIcon(new SvgIconSource("default", "com/fine/theme/icon/default.svg"));
Map<String, Object> json;
try (InputStream in = resource.getInputStream()) {
try (Reader reader = new InputStreamReader(in, StandardCharsets.UTF_8)) {
json = (Map<String, Object>) Json.parse(reader);
}
} catch (ParseException | IOException ex) {
throw new RuntimeException(ex.getMessage(), ex);
}
name = (String) json.get("name");
dark = Boolean.parseBoolean((String) json.get("dark"));
base = (String) json.get("base");
if (base == null) {
base = StringUtils.EMPTY;
}
Map<String, Object> icons = (Map<String, Object>) json.get("icons");
for (Map.Entry<String, Object> icon : icons.entrySet()) {
applyIcon(icon.getKey(), icon.getValue());
}
}
/**
* 从配置文件中添加icon只处理认识的格式和结构
*/
private void applyIcon(String key, Object value) {
if (value instanceof String) {
dealWithIconString(key, (String) value);
} else if (value instanceof Map) {
dealWithIconMap(key, (Map<String, Object>) value);
}
}
/**
* 处理字符串格式的icon配置
*/
private void dealWithIconString(String key, String value) {
if (IconManager.isSvgIcon(value)) {
// 默认字符串提供正常图和灰化图
addIcon(new SvgIconSource(key,
base + value,
IconManager.findDisablePath(base + value),
null
));
} else if (IconManager.isImageIcon(value)) {
addIcon(new ImageIconSource(key, base + value));
}
// 其他无法识别格式不处理
}
/**
* 处理object形式的icon配置
*/
private void dealWithIconMap(String key, Map<String, Object> value) {
String normalPath = (String) value.get(IconType.normal.name());
String disablePath = (String) value.get(IconType.disable.name());
String whitePath = (String) value.get(IconType.white.name());
// 暂不支持混合格式,每个id的格式需要保持一致
if (IconManager.isSvgIcon(normalPath)) {
addIcon(new SvgIconSource(key,
base + normalPath,
StringUtils.isNotBlank(disablePath) ? base + disablePath : null,
StringUtils.isNotBlank(whitePath) ? base + whitePath : null
));
} else if (IconManager.isImageIcon(normalPath)) {
addIcon(new ImageIconSource(key,
base + normalPath,
StringUtils.isNotBlank(disablePath) ? base + disablePath : null,
StringUtils.isNotBlank(whitePath) ? base + whitePath : null
));
}
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
JsonIconSet that = (JsonIconSet) o;
return Objects.equals(name, that.name);
}
@Override
public int hashCode() {
return Objects.hashCode(name);
}
}

120
designer-base/src/main/java/com/fine/theme/icon/LazyIcon.java

@ -0,0 +1,120 @@
package com.fine.theme.icon;
import com.fr.third.errorprone.annotations.Immutable;
import org.jetbrains.annotations.NotNull;
import javax.swing.Icon;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.util.StringJoiner;
import static com.fine.theme.utils.FineUIScale.scale;
/**
* 懒加载图标
* 非常懒宽高都不想算
*
* @author vito
* @since 11.0
* Created on 2023/11/6
*/
@Immutable
public class LazyIcon implements Identifiable, DisabledIcon, WhiteIcon, Icon {
@NotNull
private final String id;
private final Dimension dimension;
private final IconType type;
public LazyIcon(@NotNull final String id) {
this.id = id;
this.dimension = IconManager.DEFAULT_DIMENSION;
this.type = IconType.normal;
}
public LazyIcon(@NotNull final String id, int side) {
this.id = id;
this.dimension = new Dimension(side, side);
this.type = IconType.normal;
}
public LazyIcon(@NotNull final String id, @NotNull Dimension dimension) {
this.id = id;
this.dimension = dimension;
this.type = IconType.normal;
}
private LazyIcon(@NotNull final String id, @NotNull IconType type) {
this.id = id;
this.dimension = IconManager.DEFAULT_DIMENSION;
this.type = type;
}
public LazyIcon(@NotNull final String id, @NotNull Dimension dimension, @NotNull IconType type) {
this.id = id;
this.dimension = dimension;
this.type = type;
}
@NotNull
@Override
public String getId() {
return id;
}
@Override
public void paintIcon(@NotNull final Component c, @NotNull final Graphics g, final int x, final int y) {
getIcon().paintIcon(c, g, x, y);
}
@Override
public int getIconWidth() {
return scale(dimension.width);
}
@Override
public int getIconHeight() {
return scale(dimension.height);
}
@NotNull
public <I extends Icon> I getIcon() {
return IconManager.getIcon(getId(), dimension, type);
}
/**
* 创建一份灰化图标
*
* @return 灰化图标
*/
@NotNull
@Override
public Icon disabled() {
return new LazyIcon(getId(), dimension, IconType.disable);
}
/**
* 创建一份白化图标
*
* @return 白化图标
*/
@NotNull
@Override
public Icon white() {
return new LazyIcon(getId(), dimension, IconType.white);
}
@Override
public String toString() {
return new StringJoiner(", ", LazyIcon.class.getSimpleName() + "[", "]")
.add("id='" + id + "'")
.add("size=" + "[w=" + scale(dimension.width) + ",h=" + scale(dimension.height) + "]")
.add("type=" + type)
.toString();
}
}

53
designer-base/src/main/java/com/fine/theme/icon/UrlIconResource.java

@ -0,0 +1,53 @@
package com.fine.theme.icon;
import com.fr.general.IOUtils;
import com.fr.io.utils.ResourceIOUtils;
import com.fr.third.errorprone.annotations.Immutable;
import org.jetbrains.annotations.NotNull;
import java.io.InputStream;
import java.util.StringJoiner;
/**
* url图标资源
*
* @author vito
* @since 11.0
* Created on 2023/11/15
*/
@Immutable
public class UrlIconResource implements IconResource {
private final String path;
public UrlIconResource(String path) {
this.path = path;
}
public String getPath() {
return path;
}
@Override
@NotNull
public InputStream getInputStream() {
InputStream inputStream = getInputStream(path);
if (inputStream == null) {
throw new IconException("Icon load failed: " + path);
}
return inputStream;
}
private InputStream getInputStream(String path) {
InputStream inputStream = IOUtils.getInputStream(path);
return inputStream != null ? inputStream : ResourceIOUtils.read(path);
}
@Override
public String toString() {
return new StringJoiner(", ", UrlIconResource.class.getSimpleName() + "[", "]")
.add("path='" + path + "'")
.toString();
}
}

22
designer-base/src/main/java/com/fine/theme/icon/WhiteIcon.java

@ -0,0 +1,22 @@
package com.fine.theme.icon;
import org.jetbrains.annotations.NotNull;
import javax.swing.Icon;
/**
* 白化图像
*
* @author vito
* @since 11.0
* Created on 2024/1/8
*/
public interface WhiteIcon {
/**
* 创建一份白化图标
*
* @return 灰化图标
*/
@NotNull
Icon white();
}

75
designer-base/src/main/java/com/fine/theme/icon/icons/AnimatedRadioButtonIcon.java

@ -0,0 +1,75 @@
package com.fine.theme.icon.icons;
import com.formdev.flatlaf.icons.FlatAnimatedIcon;
import com.formdev.flatlaf.util.ColorFunctions;
import org.jetbrains.annotations.Nullable;
import javax.swing.AbstractButton;
import javax.swing.ButtonModel;
import javax.swing.JRadioButton;
import javax.swing.UIManager;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
/**
* RadioButton 图标带动画
*
* @author vito
* @since 11.0
* Created on 2023/11/22
*/
public class AnimatedRadioButtonIcon
extends FlatAnimatedIcon {
private static final int SIZE = 16;
private static final int BORDER_SIZE = 2;
private static final int ON_SIZE = 8;
private final Color offColor = UIManager.getColor("CheckBox.icon.borderColor");
private final Color onColor = UIManager.getColor("CheckBox.icon.checkmarkColor");
public AnimatedRadioButtonIcon() {
super(SIZE, SIZE, null);
}
@Override
public void paintIconAnimated(Component c, Graphics g, int x, int y, float animatedValue) {
Color color = ColorFunctions.mix(onColor, offColor, animatedValue);
// border
g.setColor(getBorderColor(c, color, onColor));
g.fillOval(0, 0, SIZE, SIZE);
// background
g.setColor(c.getBackground());
float onDiameter = SIZE - (BORDER_SIZE + (ON_SIZE - BORDER_SIZE) * (animatedValue));
float xy = (SIZE - onDiameter) / 2f;
((Graphics2D) g).fill(new Ellipse2D.Float(xy, xy, onDiameter, onDiameter));
}
@Nullable
private Color getBorderColor(Component c, Color enableColor, Color hoverColor) {
if (c instanceof AbstractButton) {
ButtonModel model = ((AbstractButton) c).getModel();
if (model.isRollover()) {
return hoverColor;
}
}
return enableColor;
}
@Override
public float getValue(Component c) {
return ((JRadioButton) c).isSelected() ? 1 : 0;
}
@Override
public int getAnimationDuration() {
return 200;
}
}

58
designer-base/src/main/java/com/fine/theme/icon/img/ImageIconSource.java

@ -0,0 +1,58 @@
package com.fine.theme.icon.img;
import com.fine.theme.icon.AbstractIconSource;
import com.fine.theme.icon.IconResource;
import com.fine.theme.icon.IconType;
import com.fine.theme.icon.UrlIconResource;
import com.fr.clone.cloning.Immutable;
import com.fr.general.FRLogger;
import com.fr.general.IOUtils;
import com.fr.stable.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.ImageIcon;
import java.awt.Dimension;
import java.awt.image.BufferedImage;
/**
* 图片图标源
*
* @author vito
* @since 11.0
* Created on 2024/05/09
*/
@Immutable
public class ImageIconSource extends AbstractIconSource<ImageIcon> {
public ImageIconSource(@NotNull String id, @NotNull String resource) {
super(id, new UrlIconResource(resource));
}
public ImageIconSource(@NotNull String id,
@NotNull String resource,
@Nullable String grayResource,
@Nullable String whiteResource) {
super(id, new UrlIconResource(resource),
StringUtils.isEmpty(grayResource) ? null : new UrlIconResource(grayResource),
StringUtils.isEmpty(whiteResource) ? null : new UrlIconResource(whiteResource));
}
@NotNull
@Override
protected ImageIcon loadIcon(@NotNull IconResource resource, Dimension dimension, IconType type) {
byte[] bytes = IOUtils.inputStream2Bytes(resource.getInputStream());
if (bytes == null && resource instanceof UrlIconResource) {
// 换readImageWithCache尝试读取
UrlIconResource iconResource = (UrlIconResource) resource;
BufferedImage icon = IOUtils.readImageWithCache(iconResource.getPath());
if (icon == null) {
FRLogger.getLogger().error(iconResource.getPath());
return new ImageIcon();
}
return new ImageIcon(icon);
}
return new ImageIcon(bytes);
}
}

207
designer-base/src/main/java/com/fine/theme/icon/svg/SvgIcon.java

@ -0,0 +1,207 @@
package com.fine.theme.icon.svg;
import com.fine.theme.icon.DisabledIcon;
import com.fine.theme.icon.GraphicsFilter;
import com.fine.theme.icon.IconManager;
import com.fine.theme.icon.IconResource;
import com.fine.theme.icon.IconType;
import com.fine.theme.icon.UrlIconResource;
import com.fine.theme.icon.WhiteIcon;
import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.ui.FlatUIUtils;
import com.formdev.flatlaf.util.GrayFilter;
import com.fr.clone.cloning.Immutable;
import com.fr.log.FineLoggerFactory;
import com.fr.value.NullableLazyValue;
import com.github.weisj.jsvg.SVGDocument;
import com.github.weisj.jsvg.attributes.ViewBox;
import com.github.weisj.jsvg.parser.SVGLoader;
import org.jetbrains.annotations.NotNull;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.UIManager;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.RGBImageFilter;
import java.util.StringJoiner;
import static com.fine.theme.utils.FineUIScale.scale;
/**
* svg图标
* 1.绘制长度会跟随DPI比率变化
* 1跟2的缩放原因不同因此不能混淆宽高测量等依旧
* 使用DPI缩放进行只有绘制内容时使用Retina绘制如果有
* Retina绘制不影响最终尺寸注意区分
*
* @author vito
* @since 11.0
* Created on 2023/11/15
*/
@Immutable
public class SvgIcon implements DisabledIcon, WhiteIcon, Icon {
private final Dimension size;
private final Dimension scaleSize;
private final IconResource resource;
private final IconType type;
private final static NullableLazyValue<SVGDocument> DEFAULT_ICON_DOC =
NullableLazyValue.createValue(SvgIcon::loadDefault);
private final NullableLazyValue<SVGDocument> svgDocument =
NullableLazyValue.createValue(() -> load(IconType.normal));
private final NullableLazyValue<SVGDocument> whiteSvgDocument =
NullableLazyValue.createValue(() -> load(IconType.white));
public SvgIcon(IconResource resource, Dimension size, IconType type) {
this.resource = resource;
this.size = size;
// 根据dpi进行缩放
this.scaleSize = scale(size);
this.type = type;
}
/**
* 如果支持绘制Retina绘制则进行Retina绘制
* 绘制结束不影响任何外部尺寸
*/
@Override
public void paintIcon(Component c, Graphics g, int x, int y) {
if (type == IconType.disable) {
g = grayGraphics(g);
}
Object[] oldRenderingHints = FlatUIUtils.setRenderingHints(g);
try {
render(c, g, x, y, this::fallbackRender);
} finally {
FlatUIUtils.resetRenderingHints(g, oldRenderingHints);
}
}
/**
* 用于fallback渲染disable图像这段代码来自异常分支使用率要保持较低水平
*/
private boolean fallbackRender(Component c, Graphics g, int x, int y) {
if (resource instanceof UrlIconResource) {
String path = ((UrlIconResource) resource).getPath();
int index = path.lastIndexOf(IconManager.ICON_DISABLE_SUFFIX);
if (path.contains(IconManager.ICON_DISABLE_SUFFIX) && index > 0) {
SVGLoader loader = new SVGLoader();
SVGDocument document = loader.load(
new UrlIconResource(path.substring(0, index) +
path.substring(index + IconManager.ICON_DISABLE_SUFFIX.length()))
.getInputStream());
if (document != null) {
document.render((JComponent) c, grayGraphics(g),
new ViewBox(x, y, scaleSize.width, scaleSize.height));
return true;
}
}
}
return false;
}
private Graphics2D grayGraphics(Graphics g) {
Object grayFilterObj = UIManager.get("Component.grayFilter");
RGBImageFilter grayFilter = (grayFilterObj instanceof RGBImageFilter)
? (RGBImageFilter) grayFilterObj
: GrayFilter.createDisabledIconFilter(FlatLaf.isLafDark());
return new GraphicsFilter((Graphics2D) g.create(), grayFilter);
}
@Override
public int getIconWidth() {
return scaleSize.width;
}
@Override
public int getIconHeight() {
return scaleSize.height;
}
private void render(Component c, Graphics g, int x, int y, FallbackRender fallbackRender) {
SVGDocument document;
try {
if (type == IconType.white) {
document = whiteSvgDocument.getValue();
} else {
document = svgDocument.getValue();
}
// 由于 weisj 库中加载svg描述出现问题,则返回一个Null,这里补充一个默认图标
if (document == null) {
document = DEFAULT_ICON_DOC.getValue();
}
document.render((JComponent) c, (Graphics2D) g, new ViewBox(x, y, scaleSize.width, scaleSize.height));
} catch (Exception e) {
boolean rendered = fallbackRender.render(c, g, x, y);
if (rendered) {
FineLoggerFactory.getLogger().warn("SvgIcon from url: " + resource + " paint with fallbackRender");
} else {
FineLoggerFactory.getLogger().error("SvgIcon from url: " + resource + "can not paint.", e);
}
}
}
private static SVGDocument loadDefault() {
SVGLoader loader = new SVGLoader();
UrlIconResource iconResource = new UrlIconResource("com/fine/theme/icon/default.svg");
return loader.load(iconResource.getInputStream());
}
private SVGDocument load(IconType type) {
SVGLoader loader = new SVGLoader();
return type == IconType.white
? loader.load(resource.getInputStream(), new WhiteParser())
: loader.load(resource.getInputStream());
}
@Override
public String toString() {
return new StringJoiner(", ", SvgIcon.class.getSimpleName() + "[", "]")
.add("resource=" + resource)
.add("type=" + type)
.add("size=" + size)
.add("scaleSize=" + scaleSize)
.toString();
}
/**
* 默认提供一个简单的灰化处理
*/
@Override
public @NotNull SvgIcon white() {
return new SvgIcon(resource, size, IconType.white);
}
/**
* 默认提供一个简单的灰化处理
*/
@Override
public @NotNull SvgIcon disabled() {
return new SvgIcon(resource, size, IconType.disable);
}
/**
* 用于回退渲染的回调类
*/
@FunctionalInterface
interface FallbackRender {
/**
* 渲染图标
*
* @param c 待绘制组件
* @param g 抽象画板
* @param x 起点横坐标
* @param y 起点纵坐标
* @return 是否使用了回退渲染
*/
boolean render(Component c, Graphics g, int x, int y);
}
}

43
designer-base/src/main/java/com/fine/theme/icon/svg/SvgIconSource.java

@ -0,0 +1,43 @@
package com.fine.theme.icon.svg;
import com.fine.theme.icon.AbstractIconSource;
import com.fine.theme.icon.IconResource;
import com.fine.theme.icon.IconType;
import com.fine.theme.icon.UrlIconResource;
import com.fr.clone.cloning.Immutable;
import com.fr.stable.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.awt.Dimension;
/**
* svg图标源
*
* @author vito
* @since 11.0
* Created on 2023/11/14
*/
@Immutable
public class SvgIconSource extends AbstractIconSource<SvgIcon> {
public SvgIconSource(@NotNull String id, @NotNull String resource) {
super(id, new UrlIconResource(resource));
}
public SvgIconSource(@NotNull String id,
@NotNull String resource,
@Nullable String grayResource,
@Nullable String whiteResource) {
super(id, new UrlIconResource(resource),
StringUtils.isEmpty(grayResource) ? null : new UrlIconResource(grayResource),
StringUtils.isEmpty(whiteResource) ? null : new UrlIconResource(whiteResource));
}
@NotNull
@Override
protected SvgIcon loadIcon(@NotNull IconResource resource, Dimension dimension, IconType type) {
return new SvgIcon(resource, dimension, type);
}
}

50
designer-base/src/main/java/com/fine/theme/icon/svg/WhiteParser.java

@ -0,0 +1,50 @@
package com.fine.theme.icon.svg;
import com.github.weisj.jsvg.attributes.paint.AwtSVGPaint;
import com.github.weisj.jsvg.attributes.paint.PaintParser;
import com.github.weisj.jsvg.attributes.paint.SVGPaint;
import com.github.weisj.jsvg.parser.AttributeNode;
import com.github.weisj.jsvg.parser.DefaultParserProvider;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.awt.Color;
/**
* svg绘制白化转化器
*
* @author vito
* @since 11.0
* Created on 2024/1/8
*/
public class WhiteParser extends DefaultParserProvider {
@Override
public @NotNull PaintParser createPaintParser() {
return new WhitePaintParser(super.createPaintParser());
}
static class WhitePaintParser implements PaintParser {
private final PaintParser delegate;
WhitePaintParser(PaintParser delegate) {
this.delegate = delegate;
}
@Override
public @Nullable Color parseColor(@NotNull String value, @NotNull AttributeNode attributeNode) {
return delegate.parseColor(value, attributeNode);
}
@Override
public @Nullable SVGPaint parsePaint(@Nullable String value, @NotNull AttributeNode attributeNode) {
SVGPaint paint = delegate.parsePaint(value, attributeNode);
if (!(paint instanceof AwtSVGPaint)) {
return paint;
}
return new AwtSVGPaint(Color.WHITE);
}
}
}

160
designer-base/src/main/java/com/fine/theme/icon/svg/batik/BatikSvgIcon.java

@ -0,0 +1,160 @@
package com.fine.theme.icon.svg.batik;
import com.fine.theme.icon.DisabledIcon;
import com.fine.theme.icon.GraphicsFilter;
import com.fine.theme.icon.IconResource;
import com.fine.theme.icon.IconType;
import com.fine.theme.icon.WhiteIcon;
import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.util.GrayFilter;
import com.fr.clone.cloning.Immutable;
import com.fr.log.FineLoggerFactory;
import org.apache.batik.transcoder.TranscoderException;
import org.apache.batik.transcoder.TranscoderInput;
import org.jetbrains.annotations.NotNull;
import javax.swing.Icon;
import javax.swing.UIManager;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.image.RGBImageFilter;
import java.util.StringJoiner;
import static com.fine.theme.utils.FineUIScale.scale;
import static com.fine.theme.utils.FineUIUtils.RETINA_SCALE_FACTOR;
import static com.fine.theme.utils.FineUIUtils.getRetina;
/**
* svg图标
* 1.绘制长度会跟随DPI比率变化
* 1跟2的缩放原因不同因此不能混淆宽高测量等依旧
* 使用DPI缩放进行只有绘制内容时使用Retina绘制如果有
* Retina绘制不影响最终尺寸注意区分
*
* @author vito
* @since 11.0
* Created on 2023/11/15
*/
@Immutable
public class BatikSvgIcon implements DisabledIcon, WhiteIcon, Icon {
private final Dimension size;
private final Dimension scaleSize;
private final IconResource resource;
private final IconType type;
public BatikSvgIcon(IconResource resource, Dimension size) {
this(resource, size, IconType.normal);
}
public BatikSvgIcon(IconResource resource, Dimension size, IconType type) {
this.resource = resource;
this.size = size;
// 根据dpi进行缩放
this.scaleSize = scale(size);
this.type = type;
}
public BatikSvgIcon(IconResource resource, int side) {
this(resource, new Dimension(side, side), IconType.normal);
}
/**
* 如果支持绘制Retina绘制则进行Retina绘制
* 绘制结束不影响任何外部尺寸
*/
@Override
public void paintIcon(Component c, Graphics g, int x, int y) {
if (getRetina()) {
BufferedImage image = toImage(scaleRetina(size));
// 高清绘制的原理:scale(1/2,1/2)的原理是坐标减半,底层是矩阵进行坐标变换,意思是坐标减半进行绘制,
// 这样就可以将两倍图绘制到一倍的大小,如果这时候设备支持Retina绘制(四个像素模拟一个像素),
// 正好就可以将4个像素利用起来,每个像素点都有不同的颜色,而不像之前只能是四个共用一个颜色。因此图像
// 可以更加细腻当然,绘图之后,需要将这个坐标变换给恢复。
((Graphics2D) g).scale(1.0 / RETINA_SCALE_FACTOR, 1.0 / RETINA_SCALE_FACTOR);
g.drawImage(image, x * RETINA_SCALE_FACTOR, y * RETINA_SCALE_FACTOR, null);
((Graphics2D) g).scale(RETINA_SCALE_FACTOR, RETINA_SCALE_FACTOR);
} else {
BufferedImage image = toImage(size);
g.drawImage(image, x, y, null);
}
}
private static Dimension scaleRetina(Dimension dimension) {
return getRetina()
? new Dimension(dimension.width * RETINA_SCALE_FACTOR, dimension.height * RETINA_SCALE_FACTOR)
: dimension;
}
/**
* 根据指定尺寸绘制图片这里尺寸为结算后的尺寸
* 因此不必进行缩放
*
* @param size 图像尺寸
* @return 图像
*/
private BufferedImage toImage(Dimension size) {
SvgTranscoder transcoder = new SvgTranscoder(size);
TranscoderInput transcoderInput = new TranscoderInput(resource.getInputStream());
try {
transcoder.transcode(transcoderInput, null);
return transcoder.getImage();
} catch (TranscoderException e) {
FineLoggerFactory.getLogger().error("SvgIcon from url: " + resource + "can not paint.", e);
}
return transcoder.getImage();
}
private Graphics2D grayGraphics(Graphics g) {
Object grayFilterObj = UIManager.get("Component.grayFilter");
RGBImageFilter grayFilter = (grayFilterObj instanceof RGBImageFilter)
? (RGBImageFilter) grayFilterObj
: GrayFilter.createDisabledIconFilter(FlatLaf.isLafDark());
return new GraphicsFilter((Graphics2D) g.create(), grayFilter);
}
@Override
public int getIconWidth() {
return scaleSize.width;
}
@Override
public int getIconHeight() {
return scaleSize.height;
}
@Override
public String toString() {
return new StringJoiner(", ", BatikSvgIcon.class.getSimpleName() + "[", "]")
.add("resource=" + resource)
.add("type=" + type)
.add("size=" + size)
.add("scaleSize=" + scaleSize)
.toString();
}
/**
* 默认提供一个简单的灰化处理
*/
@Override
public @NotNull BatikSvgIcon white() {
return new BatikSvgIcon(resource, size, IconType.white);
}
/**
* 默认提供一个简单的灰化处理
*/
@Override
public @NotNull BatikSvgIcon disabled() {
return new BatikSvgIcon(resource, size, IconType.disable);
}
}

90
designer-base/src/main/java/com/fine/theme/icon/svg/batik/SvgTranscoder.java

@ -0,0 +1,90 @@
package com.fine.theme.icon.svg.batik;
import org.apache.batik.transcoder.SVGAbstractTranscoder;
import org.apache.batik.transcoder.TranscoderException;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.image.ImageTranscoder;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
import java.awt.image.IndexColorModel;
import java.awt.image.Raster;
/**
* Svg图标转码器
*
* @author vito
* @since 11.0
* Created on 2023/11/15
*/
public class SvgTranscoder extends ImageTranscoder {
public enum Type {
gray, white, origin
}
private BufferedImage bufferedImage;
private Type type = Type.origin;
public SvgTranscoder(Dimension size) {
addTranscodingHint(SVGAbstractTranscoder.KEY_WIDTH, (float) size.getWidth());
addTranscodingHint(SVGAbstractTranscoder.KEY_HEIGHT, (float) size.getHeight());
}
public SvgTranscoder(Dimension size, Color background, Type type) {
this.type = type;
addTranscodingHint(SVGAbstractTranscoder.KEY_WIDTH, (float) size.getWidth());
addTranscodingHint(SVGAbstractTranscoder.KEY_HEIGHT, (float) size.getHeight());
addTranscodingHint(ImageTranscoder.KEY_BACKGROUND_COLOR, background);
}
public SvgTranscoder(float width, float height) {
addTranscodingHint(SVGAbstractTranscoder.KEY_WIDTH, width);
addTranscodingHint(SVGAbstractTranscoder.KEY_HEIGHT, height);
}
@Override
public BufferedImage createImage(int width, int height) {
switch (type) {
case gray:
return createGrayImage(width, height);
case white:
return createWhiteImage(width, height);
default:
return new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
}
}
/**
* 灰化底图
*/
private BufferedImage createGrayImage(int width, int height) {
return new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
}
/**
* 灰化底图
*/
private BufferedImage createWhiteImage(int width, int height) {
byte[] arr = {(byte) 0xff, (byte) 0,};
return new BufferedImage(
new IndexColorModel(1, 2, arr, arr, arr),
Raster.createPackedRaster(DataBuffer.TYPE_BYTE, width, height, 1, 1, null),
false,
null);
}
@Override
public void writeImage(BufferedImage bufferedImage, TranscoderOutput transcoderOutput) throws TranscoderException {
this.bufferedImage = bufferedImage;
}
public BufferedImage getImage() {
return bufferedImage;
}
}

73
designer-base/src/main/java/com/fine/theme/light/ui/CollapsibleScrollBarLayerUI.java

@ -0,0 +1,73 @@
package com.fine.theme.light.ui;
import com.fr.design.gui.icontainer.UIScrollPane;
import javax.swing.JComponent;
import javax.swing.JLayer;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;
import javax.swing.plaf.LayerUI;
import java.awt.AWTEvent;
import java.awt.Component;
import java.awt.event.MouseEvent;
/**
* 滚动面板的装饰层UI支持滚动条仅当悬浮时显示
* 使用见工具类: {@link com.fine.theme.utils.FineUIUtils#createCollapsibleScrollBarLayer(Component)}
*
* @author Levy.Xie
* @since 11.0
* Created on 2024/01/25
*/
public class CollapsibleScrollBarLayerUI extends LayerUI<UIScrollPane> {
private final int verticalPolicy;
private final int horizontalPolicy;
public CollapsibleScrollBarLayerUI() {
this(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
}
public CollapsibleScrollBarLayerUI(int verticalPolicy, int horizontalPolicy) {
this.verticalPolicy = verticalPolicy;
this.horizontalPolicy = horizontalPolicy;
}
@Override
public void installUI(JComponent c) {
super.installUI(c);
if (c instanceof JLayer) {
((JLayer<?>) c).setLayerEventMask(AWTEvent.MOUSE_EVENT_MASK);
}
}
@Override
public void uninstallUI(JComponent c) {
if (c instanceof JLayer) {
((JLayer<?>) c).setLayerEventMask(0);
}
super.uninstallUI(c);
}
@Override
protected void processMouseEvent(MouseEvent e, JLayer<? extends UIScrollPane> l) {
JScrollPane view = l.getView();
switch (e.getID()) {
case MouseEvent.MOUSE_ENTERED:
// 在鼠标进入时恢复滚动条显示策略
if (view != null) {
view.setVerticalScrollBarPolicy(verticalPolicy);
view.setHorizontalScrollBarPolicy(horizontalPolicy);
}
break;
case MouseEvent.MOUSE_EXITED:
// 在鼠标退出时隐藏滚动条
if (view != null) {
view.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
view.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
}
break;
default:
break;
}
}
}

42
designer-base/src/main/java/com/fine/theme/light/ui/FineButtonBorder.java

@ -0,0 +1,42 @@
package com.fine.theme.light.ui;
import com.fine.theme.utils.FineUIUtils;
import com.formdev.flatlaf.ui.FlatButtonBorder;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Paint;
import static com.fine.theme.light.ui.FineButtonUI.isPartRoundButton;
/**
* 按钮边框
*
* @author vito
* @since 11.0
* Created on 2023/12/20
*/
public class FineButtonBorder extends FlatButtonBorder {
public FineButtonBorder() {
}
@Override
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
if (isPartRoundButton(c)) {
Graphics2D g2 = (Graphics2D) g.create();
Paint borderPaint = getBorderColor(c);
if (borderPaint == null) {
return;
}
g2.setPaint(borderPaint);
FineUIUtils.paintPartRoundButtonBorder(c, g2, x, y, width, height, borderWidth, (float) getArc(c));
} else {
super.paintBorder(c, g, x, y, width, height);
}
}
}

30
designer-base/src/main/java/com/fine/theme/light/ui/FineButtonGroupUI.java

@ -0,0 +1,30 @@
package com.fine.theme.light.ui;
import javax.swing.JComponent;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.PanelUI;
/**
* 按钮组UI应用于 {@link com.fr.design.gui.ibutton.UIButtonGroup}
*
* @author Levy.Xie
* @since 11.0
* Created on 2023/12/15
*/
public class FineButtonGroupUI extends PanelUI {
/**
* 创建UI
*
* @param c 组件
* @return ComponentUI
*/
public static ComponentUI createUI(JComponent c) {
return new FineButtonGroupUI();
}
@Override
public void uninstallUI(JComponent c) {
super.uninstallUI(c);
}
}

114
designer-base/src/main/java/com/fine/theme/light/ui/FineButtonUI.java

@ -0,0 +1,114 @@
package com.fine.theme.light.ui;
import com.fine.theme.utils.FineClientProperties;
import com.fine.theme.utils.FineUIUtils;
import com.formdev.flatlaf.ui.FlatButtonUI;
import com.formdev.flatlaf.ui.FlatUIUtils;
import javax.swing.AbstractButton;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.plaf.ComponentUI;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Path2D;
import static com.fine.theme.utils.FineClientProperties.BUTTON_BORDER;
/**
* 按钮UI
*
* @author vito
* @since 11.0
* Created on 2023/12/20
*/
public class FineButtonUI extends FlatButtonUI {
/**
* @param shared
* @since 2
*/
protected FineButtonUI(boolean shared) {
super(shared);
}
/**
* 是否左圆角矩形
*
* @param c 组件
* @return 是否左圆角矩形
*/
public static boolean isLeftRoundButton(Component c) {
return c instanceof JButton
&& FineClientProperties.BUTTON_BORDER_LEFT_ROUND_RECT.equals(getButtonBorderTypeStr((JButton) c));
}
/**
* 是否右圆角矩形
*
* @param c 组件
* @return 是否右圆角矩形
*/
public static boolean isRightRoundButton(Component c) {
return c instanceof JButton
&& FineClientProperties.BUTTON_BORDER_RIGHT_ROUND_RECT.equals(getButtonBorderTypeStr((JButton) c));
}
/**
* 是否部分圆角矩形
*
* @param c 组件
* @return 是否部分圆角矩形
*/
public static boolean isPartRoundButton(Component c) {
return isLeftRoundButton(c) || isRightRoundButton(c);
}
protected void paintBackground(Graphics g, JComponent c) {
if (isPartRoundButton(c)) {
Color background = getBackground(c);
if (background == null) {
return;
}
Graphics2D g2 = (Graphics2D) g.create();
try {
FlatUIUtils.setRenderingHints(g2);
float arc = FlatUIUtils.getBorderArc(c);
int width = c.getWidth();
int height = c.getHeight();
g2.setColor(FlatUIUtils.deriveColor(background, getBackgroundBase(c, false)));
Path2D path2DLeft;
if (isLeftRoundButton(c)) {
path2DLeft = FineUIUtils.createLeftRoundRectangle(0, 0, width, height, arc);
} else {
path2DLeft = FineUIUtils.createRightRoundRectangle(0, 0, width, height, arc);
}
g2.fill(path2DLeft);
} finally {
g2.dispose();
}
} else {
super.paintBackground(g, c);
}
}
/**
* 创建UI
*/
public static ComponentUI createUI(JComponent c) {
return new FineButtonUI(false);
}
static String getButtonBorderTypeStr(AbstractButton c) {
Object value = c.getClientProperty(BUTTON_BORDER);
if (value instanceof String) {
return (String) value;
}
return null;
}
}

37
designer-base/src/main/java/com/fine/theme/light/ui/FineCheckBoxUI.java

@ -0,0 +1,37 @@
package com.fine.theme.light.ui;
import com.fine.theme.icon.LazyIcon;
import com.formdev.flatlaf.ui.FlatCheckBoxUI;
import javax.swing.AbstractButton;
import javax.swing.JComponent;
import javax.swing.plaf.ComponentUI;
/**
* 提供 {@link javax.swing.JCheckBox} 的UI类
*
* @author Levy.Xie
* @since 11.0
* Created on 2023/12/14
*/
public class FineCheckBoxUI extends FlatCheckBoxUI {
public static ComponentUI createUI(JComponent c) {
return new FineCheckBoxUI(false);
}
protected FineCheckBoxUI(boolean shared) {
super(shared);
}
@Override
public void installDefaults(AbstractButton b) {
super.installDefaults(b);
b.setIcon(new LazyIcon("checkbox_unchecked"));
b.setSelectedIcon(new LazyIcon("checkbox_checked"));
b.setRolloverIcon(new LazyIcon("checkbox_hovered"));
b.setDisabledIcon(new LazyIcon("checkbox_unchecked").disabled());
b.setDisabledSelectedIcon(new LazyIcon("checkbox_checked").disabled());
}
}

66
designer-base/src/main/java/com/fine/theme/light/ui/FineColorButtonUI.java

@ -0,0 +1,66 @@
package com.fine.theme.light.ui;
import com.formdev.flatlaf.ui.FlatUIUtils;
import com.fr.base.Utils;
import com.fr.design.gui.ibutton.UIColorButton;
import javax.swing.ButtonModel;
import javax.swing.JComponent;
import javax.swing.plaf.ComponentUI;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.geom.RoundRectangle2D;
import static com.fine.theme.utils.FineUIScale.scale;
/**
* 颜色按钮
*
* @author vito
* @since 11.0
* Created on 2024/1/3
*/
public class FineColorButtonUI extends FineButtonUI {
public static final float HEIGHT = 2.5f;
public static final float WIDTH = 14;
public static final float Y = 13.5f;
/**
* @param shared
* @since 2
*/
protected FineColorButtonUI(boolean shared) {
super(shared);
}
/**
* 创建UI
*/
public static ComponentUI createUI(JComponent c) {
return new FineColorButtonUI(false);
}
@Override
protected void paintIcon(Graphics g, JComponent c, Rectangle iconRect) {
super.paintIcon(g, c, iconRect);
UIColorButton b = (UIColorButton) c;
ButtonModel model = b.getModel();
if (model.isEnabled()) {
g.setColor(b.getColor());
} else {
g.setColor(new Color(Utils.filterRGB(b.getColor().getRGB(), 50)));
}
FlatUIUtils.setRenderingHints(g);
Graphics2D g2d = (Graphics2D) g;
float height = scale(HEIGHT);
float width = scale(WIDTH);
// 计算实际大小与icon区域大小的偏移,用于居中调整
float offsetX = (iconRect.width - width) / 2.0f;
RoundRectangle2D.Float colorRect = new RoundRectangle2D.Float(
iconRect.x + offsetX, iconRect.y + scale(Y), width, height, height, height);
g2d.fill(colorRect);
}
}

90
designer-base/src/main/java/com/fine/theme/light/ui/FineCombinationButtonUI.java

@ -0,0 +1,90 @@
package com.fine.theme.light.ui;
import com.fine.theme.utils.FineClientProperties;
import com.fine.theme.utils.FineUIStyle;
import com.fine.theme.utils.FineUIUtils;
import com.formdev.flatlaf.ui.FlatPanelUI;
import com.formdev.flatlaf.ui.FlatUIUtils;
import com.fr.design.gui.ibutton.UICombinationButton;
import javax.swing.JComponent;
import javax.swing.plaf.ComponentUI;
import java.awt.Color;
import java.awt.Graphics;
import java.beans.PropertyChangeEvent;
import static com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
/**
* 双组件按钮UI
*
* @author vito
* @since 11.0
* Created on 2023/12/21
*/
public class FineCombinationButtonUI extends FlatPanelUI {
@Styleable(dot = true)
protected Color background;
@Styleable(dot = true)
protected int arc;
/**
* @param shared
* @since 2
*/
protected FineCombinationButtonUI(boolean shared) {
super(shared);
}
/**
* 创建UI
*
* @param c 组件
* @return ComponentUI
*/
public static ComponentUI createUI(JComponent c) {
return new FineCombinationButtonUI(false);
}
@Override
public void installUI(JComponent c) {
super.installUI(c);
background = FineUIUtils.getUIColor("CombinationButton.background", "desktop");
arc = FineUIUtils.getUIInt("CombinationButton.arc", "Component.arc");
}
@Override
public void uninstallUI(JComponent c) {
super.uninstallUI(c);
}
@Override
public void paint(Graphics g, JComponent c) {
paintBackground(g, c);
super.paint(g, c);
}
protected void paintBackground(Graphics g, JComponent c) {
FlatUIUtils.setRenderingHints(g);
g.setColor(background);
g.fillRoundRect(0, 0, c.getWidth(), c.getHeight(), arc, arc);
}
@Override
public void propertyChange(PropertyChangeEvent e) {
super.propertyChange(e);
switch (e.getPropertyName()) {
case FineClientProperties.STYLE_CLASS:
UICombinationButton b = (UICombinationButton) e.getSource();
if (FineUIStyle.STYLE_PRIMARY.equals(e.getNewValue())) {
b.setPrimary();
}
b.repaint();
break;
default:
break;
}
}
}

67
designer-base/src/main/java/com/fine/theme/light/ui/FineComboBoxUI.java

@ -0,0 +1,67 @@
package com.fine.theme.light.ui;
import com.fine.theme.utils.FineClientProperties;
import com.fine.theme.utils.FineUIScale;
import com.formdev.flatlaf.ui.FlatComboBoxUI;
import com.formdev.flatlaf.ui.FlatUIUtils;
import org.jetbrains.annotations.Nullable;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.SwingConstants;
import javax.swing.plaf.ComponentUI;
import java.awt.Dimension;
import java.awt.Graphics2D;
/**
* 提供 {@link javax.swing.JComboBox} 的UI类
*
* @author Levy.Xie
* @since 11.0
* Created on 2023/12/07
*/
public class FineComboBoxUI extends FlatComboBoxUI {
public static ComponentUI createUI(JComponent c) {
return new FineComboBoxUI();
}
@Override
protected JButton createArrowButton() {
return new FineComboBoxButton();
}
protected class FineComboBoxButton extends FlatComboBoxButton {
@Override
protected void paintArrow(Graphics2D g) {
if (isPopupVisible(comboBox)) {
setDirection(SwingConstants.NORTH);
} else {
setDirection(SwingConstants.SOUTH);
}
super.paintArrow(g);
}
}
@Override
public Dimension getMinimumSize(JComponent c) {
// ComboBox基于子组件计算适配尺寸性能一般,仅考虑部分ComboBox进行适配计算,其他采用默认值
if (FineClientProperties.ADAPTIVE_COMBO_BOX.equals(getComboBoxTypeStr(c))) {
return super.getMinimumSize(c);
}
return FineUIScale.scale(new Dimension(
FlatUIUtils.getUIInt("ComboBox.minimumWidth", 72),
FlatUIUtils.getUIInt("ComboBox.comboHeight", 24)
));
}
@Nullable
static String getComboBoxTypeStr(JComponent c) {
Object value = c.getClientProperty(FineClientProperties.COMBO_BOX_TYPE);
if (value instanceof String) {
return (String) value;
}
return null;
}
}

309
designer-base/src/main/java/com/fine/theme/light/ui/FineGradientBarUI.java

@ -0,0 +1,309 @@
package com.fine.theme.light.ui;
import com.fine.theme.utils.FineUIUtils;
import com.formdev.flatlaf.ui.FlatPanelUI;
import com.fr.design.style.background.gradient.GradientBar;
import com.fr.design.style.background.gradient.SelectColorPointBtn;
import com.fr.stable.AssistUtils;
import com.fr.stable.os.OperatingSystem;
import javax.swing.JComponent;
import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.LinearGradientPaint;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionAdapter;
import java.awt.geom.Path2D;
import java.awt.geom.Point2D;
import java.util.Collections;
import java.util.List;
/**
* 渐变色滑块 UI类
*
* @author Leo.Qin
* @since 11.0
* Created on 2023/12/19
*/
public class FineGradientBarUI extends FlatPanelUI {
private int directionalShapeSize;
private int recHeight;
private int width;
private int height;
private int borderWidth;
private Color borderColor;
private Color thumbBorderColor;
private Color hoverThumbColor;
private Color pressedThumbColor;
private MouseMotionAdapter mouseMotionListener;
GradientBar gradientBar;
private List<SelectColorPointBtn> list;
private SelectColorPointBtn p1;
private SelectColorPointBtn p2;
private MouseListener mouseListener;
private double offset = 0.0001;
boolean[] hoverStatus;
protected FineGradientBarUI(boolean shared) {
super(shared);
}
/**
* 创建UI
*
* @param c 组件
* @return UI
*/
public static ComponentUI createUI(JComponent c) {
return new FineGradientBarUI(false);
}
@Override
public void installUI(JComponent c) {
super.installUI(c);
installDefaults(c);
gradientBar = (GradientBar) c;
mouseMotionListener = new TrackMotionListener();
mouseListener = new TrackMouseListener();
gradientBar.addMouseMotionListener(mouseMotionListener);
gradientBar.addMouseListener(mouseListener);
}
private void installDefaults(JComponent c) {
directionalShapeSize = FineUIUtils.getAndScaleInt("GradientBar.thumbWidth", 12);
recHeight = FineUIUtils.getAndScaleInt("GradientBar.recHeight", 30);
width = FineUIUtils.getAndScaleInt("GradientBar.recWidth", 160);
height = recHeight + directionalShapeSize;
borderWidth = FineUIUtils.getAndScaleInt("GradientBar.borderWidth", 1);
borderColor = UIManager.getColor("GradientBar.borderColor");
thumbBorderColor = UIManager.getColor("GradientBar.thumbBorderColor");
hoverThumbColor = UIManager.getColor("GradientBar.hoverThumbColor");
pressedThumbColor = UIManager.getColor("GradientBar.pressedThumbColor");
}
private class TrackMouseListener extends MouseAdapter {
@Override
public void mouseExited(MouseEvent e) {
for (int i = 0; i < list.size(); i++) {
SelectColorPointBtn selectColorPointBtn = list.get(i);
selectColorPointBtn.setHover(false);
hoverStatus[i] = false;
}
gradientBar.repaint();
}
@Override
public void mouseEntered(MouseEvent e) {
checkHoverStatus(e);
}
@Override
public void mousePressed(MouseEvent e) {
for (SelectColorPointBtn btn : list) {
boolean hover = isOverBtn(e, btn);
btn.setPressed(hover);
}
gradientBar.repaint();
}
@Override
public void mouseReleased(MouseEvent e) {
for (SelectColorPointBtn btn : list) {
btn.setPressed(false);
}
gradientBar.repaint();
}
}
private class TrackMotionListener extends MouseMotionAdapter {
int index;
@Override
public void mouseDragged(MouseEvent e) {
if (!gradientBar.isDraggable()) {
return;
}
index = getSelectedIndex(e, index);
int halfSize = directionalShapeSize / 2;
boolean x = e.getX() <= gradientBar.getWidth() - halfSize && e.getX() >= halfSize;
if (x) {
list.get(index).setStartPosition((double) (e.getX() - halfSize) / (gradientBar.getWidth() - directionalShapeSize));
gradientBar.repaint();
}
}
private int getSelectedIndex(MouseEvent e, int index) {
int oldIndex = index;
for (int i = 0; i < list.size(); i++) {
if (list.get(i).contains(e.getX(), e.getY())) {
index = i;
break;
}
}
if (OperatingSystem.isLinux() && AssistUtils.equals(oldIndex, index)) {
if (Math.abs(p1.getX() - e.getX()) > Math.abs(p2.getX() - e.getX())) {
index = 1;
} else {
index = 0;
}
}
return index;
}
@Override
public void mouseMoved(MouseEvent e) {
checkHoverStatus(e);
}
}
private void checkHoverStatus(MouseEvent e) {
boolean repaint = false;
for (int i = 0; i < list.size(); i++) {
SelectColorPointBtn btn = list.get(i);
boolean hover = isOverBtn(e, btn);
if (hoverStatus[i] != hover) {
repaint = true;
hoverStatus[i] = hover;
btn.setHover(hover);
}
}
if (repaint) {
gradientBar.repaint();
}
}
private boolean isOverBtn(MouseEvent e, SelectColorPointBtn btn) {
return btn.contains(e.getX(), e.getY());
}
@Override
public void paint(Graphics g, JComponent c) {
Graphics2D g2 = (Graphics2D) g;
gradientBar = (GradientBar) c;
list = gradientBar.getList();
p1 = gradientBar.getSelectColorPointBtnP1();
p2 = gradientBar.getSelectColorPointBtnP2();
if (hoverStatus == null) {
hoverStatus = new boolean[list.size()];
}
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_NORMALIZE);
GradientBar component = (GradientBar) c;
List<SelectColorPointBtn> btnList = component.getList();
Collections.sort(btnList);
paintBorder(g2, component);
paintContent(g2, component);
paintButton(g2, btnList);
}
/**
* 实际绘制区域x范围directionalShapeSize / 2, width - directionalShapeSize)
*/
private void paintContent(Graphics2D g2d, GradientBar c) {
List<SelectColorPointBtn> btnList = c.getList();
int halfSize = directionalShapeSize / 2;
Point2D start = new Point2D.Float(halfSize, 0);
Point2D end = new Point2D.Float(c.getWidth() - halfSize, 0);
Collections.sort(btnList);
Color[] colors = new Color[btnList.size()];
for (int i = 0; i < btnList.size(); i++) {
colors[i] = btnList.get(i).getColorInner();
}
float[] dist = getColorFloats(c, btnList);
LinearGradientPaint paint = new LinearGradientPaint(start, end, dist, colors);
g2d.setPaint(paint);
g2d.fillRect(halfSize + borderWidth, borderWidth, c.getWidth() - directionalShapeSize - borderWidth * 2, recHeight - borderWidth * 2);
}
private float[] getColorFloats(GradientBar c, List<SelectColorPointBtn> btnList) {
float[] dist = new float[btnList.size()];
for (int i = 0; i < btnList.size(); i++) {
if (btnList.get(i).getStartPosition() < 0) {
dist[i] = 0;
} else if (btnList.get(i).getStartPosition() > 1) {
dist[i] = 1;
} else {
dist[i] = (float) btnList.get(i).getStartPosition();
}
btnList.get(i).setX(dist[i] * (c.getWidth() - directionalShapeSize) + (double) directionalShapeSize / 2);
btnList.get(i).setY(recHeight);
}
float dist1 = dist[btnList.size() - 1];
float dist2 = dist[btnList.size() - 2];
if (AssistUtils.equals(dist1, dist2)) {
dist[btnList.size() - 1] = (float) (dist2 + offset);
}
return dist;
}
private void paintBorder(Graphics2D g2d, GradientBar c) {
int halfSize = directionalShapeSize / 2;
if (borderColor == null) {
return;
}
g2d.setColor(borderColor);
g2d.fillRect(halfSize, 0, c.getWidth() - directionalShapeSize, recHeight);
}
private void paintButton(Graphics2D g2d, List<SelectColorPointBtn> list) {
for (SelectColorPointBtn selectColorPointBtn : list) {
Path2D directionalThumbShape = FineSliderUI.createDirectionalThumbShape((float) selectColorPointBtn.getX() - (float) directionalShapeSize / 2, (float) selectColorPointBtn.getY(), directionalShapeSize, directionalShapeSize, 0);
if (selectColorPointBtn.isHover() && hoverThumbColor != null) {
g2d.setColor(hoverThumbColor);
g2d.fill(directionalThumbShape);
} else if (selectColorPointBtn.isPressed() && pressedThumbColor != null) {
g2d.setColor(pressedThumbColor);
g2d.fill(directionalThumbShape);
} else if (thumbBorderColor != null) {
g2d.setColor(thumbBorderColor);
g2d.fill(directionalThumbShape);
}
selectColorPointBtn.updatePath(directionalThumbShape);
Path2D innerThumbShape = FineSliderUI.createDirectionalThumbShape((float) selectColorPointBtn.getX() - (float) directionalShapeSize / 2 + borderWidth, (float) selectColorPointBtn.getY() + borderWidth, directionalShapeSize - borderWidth * 2, directionalShapeSize - borderWidth * 2, 0);
g2d.setColor(selectColorPointBtn.getColorInner());
g2d.fill(innerThumbShape);
}
}
@Override
public Dimension getPreferredSize(JComponent c) {
return new Dimension(width, height);
}
}

74
designer-base/src/main/java/com/fine/theme/light/ui/FineHeadGroupUI.java

@ -0,0 +1,74 @@
package com.fine.theme.light.ui;
import com.fine.theme.utils.FineUIUtils;
import com.formdev.flatlaf.ui.FlatUIUtils;
import javax.swing.JComponent;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.PanelUI;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import static com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
/**
* HeadGroup 的UI类
*
* @author vito
* @since 11.0
* Created on 2023/12/15
*/
public class FineHeadGroupUI extends PanelUI {
@Styleable(dot = true)
protected Color background;
@Styleable(dot = true)
protected int arc;
/**
* 创建UI
*
* @param c 组件
* @return ComponentUI
*/
public static ComponentUI createUI(JComponent c) {
return new FineHeadGroupUI();
}
@Override
public void installUI(JComponent c) {
super.installUI(c);
background = FineUIUtils.getUIColor("HeadGroup.background", "desktop");
arc = FineUIUtils.getUIInt("HeadGroup.arc", "Component.arc");
}
@Override
public void uninstallUI(JComponent c) {
super.uninstallUI(c);
}
@Override
public Dimension getMinimumSize(JComponent component) {
return new Dimension(0, 0);
}
@Override
public Dimension getMaximumSize(JComponent component) {
return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
}
@Override
public void update(Graphics g, JComponent c) {
paintBackground(g, c);
paint(g, c);
}
protected void paintBackground(Graphics g, JComponent c) {
FlatUIUtils.setRenderingHints(g);
g.setColor(background);
g.fillRoundRect(0, 0, c.getWidth(), c.getHeight(), arc, arc);
}
}

112
designer-base/src/main/java/com/fine/theme/light/ui/FineHeaderPaneUI.java

@ -0,0 +1,112 @@
package com.fine.theme.light.ui;
import com.fine.theme.icon.LazyIcon;
import com.fine.theme.utils.AnimatedPainter;
import com.fine.theme.utils.FineUIScale;
import com.formdev.flatlaf.ui.FlatUIUtils;
import com.fr.design.foldablepane.HeaderPane;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.PanelUI;
import java.awt.AlphaComposite;
import java.awt.Component;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.geom.AffineTransform;
/**
* 标题组件UI
*
* @author vito
* @since 11.0
* Created on 2024/1/29
*/
public class FineHeaderPaneUI extends PanelUI implements AnimatedPainter {
private Icon triangleRight;
private static final int ICON_FIX = -2;
/**
* 创建UI
*
* @param c 组件
* @return ComponentUI
*/
public static ComponentUI createUI(JComponent c) {
return new FineHeaderPaneUI();
}
@Override
public void installUI(JComponent c) {
super.installUI(c);
triangleRight = new LazyIcon("triangle_right");
}
@Override
public void uninstallUI(JComponent c) {
super.uninstallUI(c);
}
@Override
public void paint(Graphics g, JComponent c) {
paintWithAnimation(c, g, c.getX(), c.getY(), c.getWidth(), c.getHeight());
}
@Override
public void paintAnimated(Component c, Graphics2D g, int x, int y, int width, int height, float[] animatedValues) {
Graphics2D g2d = (Graphics2D) g.create();
HeaderPane headerPane = (HeaderPane) c;
g2d.setColor(c.getBackground());
if (headerPane.isPressed()) {
g2d.setColor(UIManager.getColor("Button.pressedBackground"));
}
Insets insets = headerPane.getInsets();
g2d.fillRect(0, insets.top / 2,
headerPane.getWidth(), headerPane.getHeight() - (insets.top + insets.bottom) / 2);
int iconY = (headerPane.getHeight() - triangleRight.getIconHeight()) / 2;
// 动起来,旋转角度(弧度),动画帧绘制开始
double rotationAngle = Math.toRadians(90 * animatedValues[0]);
// 设置旋转中心
AffineTransform oldTransform = g2d.getTransform();
// 折叠面板需要icon显示左边缘对齐,fix一下
g2d.rotate(rotationAngle, FineUIScale.scale(ICON_FIX) + triangleRight.getIconWidth() / 2.0,
iconY + triangleRight.getIconHeight() / 2.0);
// 绘制旋转后的正方形
triangleRight.paintIcon(c, g2d, FineUIScale.scale(ICON_FIX), iconY);
// 恢复原始的变换
g2d.setTransform(oldTransform);
// ----- 动画帧绘制结束 -----
g2d.setFont(c.getFont().deriveFont(Font.BOLD));
g2d.setPaint(c.getForeground());
g2d.setComposite(AlphaComposite.SrcOver.derive(c.getForeground().getAlpha() / 255f));
FontMetrics metrics = g2d.getFontMetrics();
int ascent = metrics.getAscent();
int descent = metrics.getDescent();
float titleX = triangleRight.getIconWidth() + FineUIScale.scale(ICON_FIX)
+ FineUIScale.scale(UIManager.getInt("ExpandablePane.HeaderPane.hGap"));
float titleY = (headerPane.getHeight() - (ascent + descent)) / 2.0f + ascent;
FlatUIUtils.setRenderingHints(g2d);
g2d.drawString(headerPane.getTitle(), titleX, titleY);
g2d.dispose();
}
@Override
public float[] getValues(Component c) {
HeaderPane headerPane = (HeaderPane) c;
return new float[]{headerPane.isShow() ? 1 : 0};
}
}

68
designer-base/src/main/java/com/fine/theme/light/ui/FineInputUI.java

@ -0,0 +1,68 @@
package com.fine.theme.light.ui;
import com.fine.theme.utils.FineUIUtils;
import com.formdev.flatlaf.ui.FlatPanelUI;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI;
import java.beans.PropertyChangeEvent;
/**
* Input输入框类组件 UI类
*
* @author Leo.Qin
* @since 11.0
* Created on 2023/12/11
*/
public class FineInputUI extends FlatPanelUI {
private static final String ENABLED = "enabled";
private static final String EDITABLE = "editable";
private final int defaultArc = 5;
public FineInputUI(boolean shared) {
super(shared);
}
/**
* 创建UI
*/
public static ComponentUI createUI(JComponent c) {
return new FineInputUI(false);
}
@Override
public void installUI(JComponent c) {
super.installUI(c);
c.setBackground(UIManager.getColor("Input.background"));
c.setBorder(UIManager.getBorder("Input.border"));
}
@Override
protected void installDefaults(JPanel p) {
super.installDefaults(p);
arc = FineUIUtils.getAndScaleInt("Input.arc", defaultArc);
}
@Override
public void propertyChange(PropertyChangeEvent e) {
String propertyName = e.getPropertyName();
if (EDITABLE.equals(propertyName) || ENABLED.equals(propertyName)) {
updateBackground(e);
} else {
super.propertyChange(e);
}
}
private void updateBackground(PropertyChangeEvent e) {
JPanel source = (JPanel) e.getSource();
if (e.getNewValue() == Boolean.FALSE) {
source.setBackground(UIManager.getColor("Input.disabledBackground"));
} else {
source.setBackground(UIManager.getColor("Input.background"));
}
}
}

17
designer-base/src/main/java/com/fine/theme/light/ui/FineLightIconSet.java

@ -0,0 +1,17 @@
package com.fine.theme.light.ui;
import com.fine.theme.icon.JsonIconSet;
import com.fine.theme.icon.UrlIconResource;
/**
* Fine 亮主题图标集
*
* @author vito
* @since 11.0
* Created on 2024/5/7
*/
public class FineLightIconSet extends JsonIconSet {
public FineLightIconSet() {
super(new UrlIconResource("com/fine/theme/light/ui/fine_light.icon.json"));
}
}

80
designer-base/src/main/java/com/fine/theme/light/ui/FineMenuItemUI.java

@ -0,0 +1,80 @@
package com.fine.theme.light.ui;
import com.fine.theme.icon.LazyIcon;
import com.fine.theme.utils.FineClientProperties;
import com.formdev.flatlaf.ui.FlatMenuItemRenderer;
import com.formdev.flatlaf.ui.FlatMenuItemUI;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.JMenuItem;
import javax.swing.plaf.ComponentUI;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Rectangle;
/**
* menuItem UI类
*
* @author Leo.Qin
* @since 11.0
* Created on 2024/1/8
*/
public class FineMenuItemUI extends FlatMenuItemUI {
int iconSize = 16;
int rightMargin = 10;
/**
* 创建UI
*
* @param c
* @return
*/
public static ComponentUI createUI(JComponent c) {
return new FineMenuItemUI();
}
@Override
protected FlatMenuItemRenderer createRenderer() {
return new FineMenuItemRenderer(menuItem, checkIcon, arrowIcon, acceleratorFont, acceleratorDelimiter);
}
@Override
public void paint(Graphics g, JComponent c) {
super.paint(g, c);
Object itemType = c.getClientProperty(FineClientProperties.MENU_ITEM_TYPE);
if (FineClientProperties.MENU_ITEM_TYPE_LOCK.equals(itemType)) {
LazyIcon icon = new LazyIcon("locked");
icon.paintIcon(c, g, c.getWidth() - rightMargin - iconSize, (c.getHeight() - iconSize) / 2);
}
}
static class FineMenuItemRenderer extends FlatMenuItemRenderer {
protected FineMenuItemRenderer(JMenuItem menuItem, Icon checkIcon, Icon arrowIcon,
Font acceleratorFont, String acceleratorDelimiter )
{
super(menuItem, checkIcon, arrowIcon, acceleratorFont, acceleratorDelimiter);
}
@Override
protected void paintText( Graphics g, Rectangle textRect, String text, Color selectionForeground, Color disabledForeground ) {
if (!isTopLevelMenu(menuItem) && menuItem.getIcon() == null) {
textRect.x -= minimumIconSize.width;
}
super.paintText(g, textRect, text, selectionForeground, disabledForeground);
}
@Override
protected void paintIcon(Graphics g, Rectangle iconRect, Icon icon, Color checkBackground, Color selectionBackground) {
if (menuItem.getIcon() != null) {
super.paintIcon(g, iconRect, icon, checkBackground, selectionBackground);
}
}
}
}

38
designer-base/src/main/java/com/fine/theme/light/ui/FineOptionPaneUI.java

@ -0,0 +1,38 @@
package com.fine.theme.light.ui;
import com.fine.theme.utils.FineUIStyle;
import com.formdev.flatlaf.ui.FlatOptionPaneUI;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI;
import java.awt.Component;
import java.awt.Container;
/**
* @author Renekton
* @since 2024/08/15
* Created on 2024/08/15
*/
public class FineOptionPaneUI extends FlatOptionPaneUI {
/**
* 注册当前类的UI对象
*/
public static ComponentUI createUI(JComponent c ) {
return new FineOptionPaneUI();
}
@Override
protected void addButtonComponents(Container container, Object[] buttons,
int initialIndex) {
super.addButtonComponents(container, buttons, initialIndex);
Component[] components = container.getComponents();
for (Component component: components) {
if (UIManager.getString("OptionPane.okButtonText", optionPane.getLocale()).equals(((JButton) component).getText())) {
FineUIStyle.setStyle((JButton) component, FineUIStyle.STYLE_PRIMARY);
}
}
}
}

55
designer-base/src/main/java/com/fine/theme/light/ui/FinePanelUI.java

@ -0,0 +1,55 @@
package com.fine.theme.light.ui;
import com.fine.theme.utils.FineUIUtils;
import com.formdev.flatlaf.ui.FlatPanelUI;
import org.jetbrains.annotations.Nullable;
import javax.swing.JComponent;
import javax.swing.plaf.ComponentUI;
import java.awt.Graphics;
import static com.fine.theme.utils.FineClientProperties.PANEL_TYPE;
import static com.fine.theme.utils.FineClientProperties.ROUNDED_PANEL;
/**
* Panel 面板UI
*
* @author Levy.Xie
* @since 11.0
* Created on 2024/08/02
*/
public class FinePanelUI extends FlatPanelUI {
/**
* @param shared
* @since 2
*/
protected FinePanelUI(boolean shared) {
super(shared);
}
/**
* 创建UI
*/
public static ComponentUI createUI(JComponent c) {
return new FinePanelUI(false);
}
@Override
public void update(Graphics g, JComponent c) {
if (ROUNDED_PANEL.equals(getPanelTypeStr(c))) {
this.arc = FineUIUtils.getUIInt("Panel.arc", "Component.arc");
}
super.update(g, c);
}
@Nullable
static String getPanelTypeStr(JComponent p) {
Object value = p.getClientProperty(PANEL_TYPE);
if (value instanceof String) {
return (String) value;
}
return null;
}
}

19
designer-base/src/main/java/com/fine/theme/light/ui/FinePopupMenuBorder.java

@ -0,0 +1,19 @@
package com.fine.theme.light.ui;
import com.fine.theme.utils.FineUIUtils;
import com.formdev.flatlaf.ui.FlatPopupMenuBorder;
/**
* PopupMenu Border类
*
* @author Leo.Qin
* @since 11.0
* Created on 2023/12/25
*/
public class FinePopupMenuBorder extends FlatPopupMenuBorder {
@Override
public int getArc() {
return FineUIUtils.getAndScaleInt("PopupMenu.arc", 5);
}
}

70
designer-base/src/main/java/com/fine/theme/light/ui/FinePopupMenuSeparatorUI.java

@ -0,0 +1,70 @@
package com.fine.theme.light.ui;
import com.fine.theme.utils.FineUIUtils;
import com.formdev.flatlaf.ui.FlatPopupMenuSeparatorUI;
import com.formdev.flatlaf.ui.FlatUIUtils;
import javax.swing.JComponent;
import javax.swing.JSeparator;
import javax.swing.plaf.ComponentUI;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.geom.Rectangle2D;
import static com.formdev.flatlaf.util.UIScale.scale;
/**
* popup弹窗分割线UI
*
* @author Leo.Qin
* @since 11.0
* Created on 2024/1/8
*/
public class FinePopupMenuSeparatorUI extends FlatPopupMenuSeparatorUI {
protected Insets insets;
/**
* @param shared
* @since 2
*/
protected FinePopupMenuSeparatorUI(boolean shared) {
super(shared);
}
/**
* 创建UI类
*
* @param c
* @return
*/
public static ComponentUI createUI(JComponent c) {
return new FinePopupMenuSeparatorUI(false);
}
@Override
protected void installDefaults(JSeparator s) {
super.installDefaults(s);
insets = FineUIUtils.getAndScaleUIInsets("PopupMenuSeparator.Insets", new Insets(0, 10, 0, 10));
}
@Override
public void paint(Graphics g, JComponent c) {
Graphics2D g2 = (Graphics2D) g.create();
try {
FlatUIUtils.setRenderingHints(g2);
g2.setColor(c.getForeground());
float width = scale((float) stripeWidth);
float indent = scale((float) stripeIndent);
if (((JSeparator) c).getOrientation() == JSeparator.VERTICAL) {
g2.fill(new Rectangle2D.Float(indent, insets.left, width - (insets.left + insets.right), c.getHeight()));
} else {
g2.fill(new Rectangle2D.Float(insets.left, indent, c.getWidth() - (insets.left + insets.right), width));
}
} finally {
g2.dispose();
}
}
}

58
designer-base/src/main/java/com/fine/theme/light/ui/FinePopupMenuUI.java

@ -0,0 +1,58 @@
package com.fine.theme.light.ui;
import com.fine.theme.utils.FineUIUtils;
import com.formdev.flatlaf.ui.FlatPopupMenuUI;
import javax.swing.JComponent;
import javax.swing.plaf.ComponentUI;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.RoundRectangle2D;
/**
* PopupMenu UI类
*
* @author Leo.Qin
* @since 11.0
* Created on 2023/12/25
*/
public class FinePopupMenuUI extends FlatPopupMenuUI {
private int arc;
private final int DEFAULT_ARC = 10;
/**
* 创建UI
*
* @param c 组件
* @return UI
*/
public static ComponentUI createUI(JComponent c) {
return new FinePopupMenuUI();
}
@Override
public void installDefaults() {
super.installDefaults();
arc = FineUIUtils.getAndScaleInt("PopupMenu.arc", DEFAULT_ARC);
}
@Override
public void paint(Graphics g, JComponent c) {
// 绘制圆角矩形作为弹窗背景
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
RoundRectangle2D roundRect = new RoundRectangle2D.Double(0, 0, c.getWidth(), c.getHeight(), arc, arc);
g2d.setColor(c.getBackground());
g2d.fill(roundRect);
// 绘制组件内容
super.paint(g, c);
}
@Override
public void update(Graphics g, JComponent c) {
paint(g, c);
}
}

28
designer-base/src/main/java/com/fine/theme/light/ui/FineReportComponentBorder.java

@ -0,0 +1,28 @@
package com.fine.theme.light.ui;
import com.fine.theme.utils.FineUIUtils;
import com.formdev.flatlaf.ui.FlatRoundBorder;
import javax.swing.UIManager;
import java.awt.Color;
import java.awt.Component;
/**
* 报表编辑区域边框
*
* @author Leo.Qin
* @since 11.0
* Created on 2024/1/2
*/
public class FineReportComponentBorder extends FlatRoundBorder {
@Override
protected int getArc(Component c) {
return FineUIUtils.getAndScaleInt("Center.arc", 10);
}
@Override
protected Color getBorderColor(Component c) {
return UIManager.getColor("Center.ZoneBorderColor");
}
}

40
designer-base/src/main/java/com/fine/theme/light/ui/FineReportComponentCompositeUI.java

@ -0,0 +1,40 @@
package com.fine.theme.light.ui;
import com.fine.theme.utils.FineUIUtils;
import com.formdev.flatlaf.ui.FlatPanelUI;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.plaf.ComponentUI;
/**
* 报表编辑区域UI
*
* @author Leo.Qin
* @since 11.0
* Created on 2024/1/2
*/
public class FineReportComponentCompositeUI extends FlatPanelUI {
/**
* @param shared
* @since 2
*/
protected FineReportComponentCompositeUI(boolean shared) {
super(shared);
}
/**
* 创建UI
*/
public static ComponentUI createUI(JComponent c) {
return new FineReportComponentCompositeUI(false);
}
@Override
protected void installDefaults(JPanel p) {
super.installDefaults(p);
this.arc = FineUIUtils.getAndScaleInt("Center.arc", 10);
}
}

63
designer-base/src/main/java/com/fine/theme/light/ui/FineRoundBorder.java

@ -0,0 +1,63 @@
package com.fine.theme.light.ui;
import com.fine.theme.utils.FineUIUtils;
import com.formdev.flatlaf.ui.FlatRoundBorder;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.fr.design.event.HoverAware;
import java.awt.Color;
import java.awt.Component;
import java.awt.Paint;
import java.util.StringJoiner;
/**
* 通用的Border类具备hoverclick禁用等多种状态
*
* @author Levy.Xie
* @since 11.0
* Created on 2023/12/06
*/
public class FineRoundBorder extends FlatRoundBorder {
@Styleable(dot = true)
protected Color borderColor = FineUIUtils.getUIColor("defaultBorderColor", "Component.borderColor");
@Styleable(dot = true)
protected Color disabledBorderColor = FineUIUtils.getUIColor("defaultBorderColor", "Component.disabledBorderColor");
@Styleable(dot = true)
protected Color highlightBorderColor = FineUIUtils.getUIColor("defaultHighlightBorderColor", "Component.focusedBorderColor");
@Styleable(dot = true)
protected Color focusColor = FineUIUtils.getUIColor("defaultBorderFocusShadow", "Component.focusedBorderColor");
@Override
protected Paint getBorderColor(Component c) {
if (isEnabled(c)) {
if (c instanceof HoverAware && ((HoverAware) c).isHovered()) {
return getHoverBorderColor();
} else {
return isFocused(c) ? focusedBorderColor : borderColor;
}
}
return disabledBorderColor;
}
@Override
protected Color getFocusColor(Component c) {
return focusColor;
}
protected Color getHoverBorderColor() {
return highlightBorderColor;
}
@Override
public String toString() {
return new StringJoiner(", ", FineRoundBorder.class.getSimpleName() + "[", "]")
.add("borderColor=" + borderColor)
.add("arc=" + arc)
.add("roundRect=" + roundRect)
.add("borderWidth=" + borderWidth)
.toString();
}
}

49
designer-base/src/main/java/com/fine/theme/light/ui/FineSelectBoxUI.java

@ -0,0 +1,49 @@
package com.fine.theme.light.ui;
import com.fine.theme.utils.FineUIUtils;
import javax.swing.JComponent;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.PanelUI;
import java.awt.Dimension;
/**
* 选择框面板UI应用于 {@link com.fr.design.style.AbstractSelectBox}
*
* @author Levy.Xie
* @since 11.0
* Created on 2023/12/15
*/
public class FineSelectBoxUI extends PanelUI {
private static final int DEFAULT_BOX_HEIGHT = 24;
protected int boxHeight;
/**
* 创建UI
*
* @param c 组件
* @return ComponentUI
*/
public static ComponentUI createUI(JComponent c) {
return new FineSelectBoxUI();
}
@Override
public void installUI(JComponent c) {
super.installUI(c);
boxHeight = FineUIUtils.getAndScaleInt("ComboBox.comboHeight", DEFAULT_BOX_HEIGHT);
c.setBorder(new FineRoundBorder());
}
@Override
public void uninstallUI(JComponent c) {
super.uninstallUI(c);
}
@Override
public Dimension getPreferredSize(JComponent c) {
return new Dimension(c.getWidth(), boxHeight);
}
}

344
designer-base/src/main/java/com/fine/theme/light/ui/FineSliderUI.java

@ -0,0 +1,344 @@
package com.fine.theme.light.ui;
import com.fine.theme.utils.FineUIUtils;
import com.formdev.flatlaf.ui.FlatSliderUI;
import com.formdev.flatlaf.ui.FlatUIUtils;
import com.formdev.flatlaf.util.HiDPIUtils;
import com.formdev.flatlaf.util.UIScale;
import com.fr.stable.AssistUtils;
import javax.swing.JComponent;
import javax.swing.JSlider;
import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Path2D;
import java.awt.geom.RoundRectangle2D;
import java.util.Dictionary;
import java.util.Enumeration;
/**
* 滑块slider UI类
*
* @author Leo.Qin
* @since 11.0
* Created on 2023/12/15
*/
public class FineSliderUI extends FlatSliderUI {
private final int DEFAULT_LABEL_HEIGHT = 13;
private Color defaultForeground;
private int defaultLabelHeight;
/**
* 创建UI
*/
public static ComponentUI createUI(JComponent c) {
return new FineSliderUI();
}
@Override
protected void installDefaults(JSlider slider) {
super.installDefaults(slider);
defaultForeground = UIManager.getColor("Slider.foreground");
defaultLabelHeight = FineUIUtils.getAndScaleInt("Slider.labelHeight", DEFAULT_LABEL_HEIGHT);
}
@Override
protected void calculateLabelRect() {
if (slider.getPaintLabels()) {
calLabelRectWhenPaint();
} else {
calLabelRectWhenNotPaint();
}
}
private void calLabelRectWhenPaint() {
labelRect.y = 0;
if (slider.getOrientation() == JSlider.HORIZONTAL) {
labelRect.x = tickRect.x - trackBuffer;
labelRect.width = tickRect.width + (trackBuffer * 2);
labelRect.height = getHeightOfTallestLabel();
} else {
if (isLeftToRight(slider)) {
labelRect.x = tickRect.x + tickRect.width;
labelRect.width = getWidthOfWidestLabel();
} else {
labelRect.width = getWidthOfWidestLabel();
labelRect.x = tickRect.x - labelRect.width;
}
labelRect.height = tickRect.height + (trackBuffer * 2);
}
}
private void calLabelRectWhenNotPaint() {
labelRect.y = 0;
if (slider.getOrientation() == JSlider.HORIZONTAL) {
labelRect.x = tickRect.x;
labelRect.width = tickRect.width;
labelRect.height = 0;
} else {
if (isLeftToRight(slider)) {
labelRect.x = tickRect.x + tickRect.width;
} else {
labelRect.x = tickRect.x;
}
labelRect.width = 0;
labelRect.height = tickRect.height;
}
}
@Override
protected void calculateTrackRect() {
if (slider.getOrientation() == JSlider.HORIZONTAL) {
calHorizontalTrackRect();
} else {
calVerticalTrackRect();
}
}
private void calVerticalTrackRect() {
int centerSpacing;
centerSpacing = thumbRect.width;
if (isLeftToRight(slider)) {
if (slider.getPaintTicks()) {
centerSpacing += getTickLength();
}
if (slider.getPaintLabels()) {
centerSpacing += getWidthOfWidestLabel();
}
} else {
if (slider.getPaintTicks()) {
centerSpacing -= getTickLength();
}
if (slider.getPaintLabels()) {
centerSpacing -= getWidthOfWidestLabel();
}
}
trackRect.x = contentRect.x + getWidthOfWidestLabel() + (contentRect.width - centerSpacing - 1) / 2;
trackRect.y = contentRect.y + trackBuffer;
trackRect.width = thumbRect.width;
trackRect.height = contentRect.height - (trackBuffer * 2);
}
private void calHorizontalTrackRect() {
int centerSpacing;
centerSpacing = thumbRect.height;
if (slider.getPaintTicks()) {
centerSpacing += getTickLength();
}
if (slider.getPaintLabels()) {
centerSpacing += getHeightOfTallestLabel();
}
trackRect.x = contentRect.x + trackBuffer;
trackRect.y = contentRect.y + getHeightOfTallestLabel() + (contentRect.height - centerSpacing - 1) / 2;
trackRect.width = contentRect.width - (trackBuffer * 2);
trackRect.height = thumbRect.height;
}
@Override
protected int getHeightOfTallestLabel() {
Dictionary dictionary = slider.getLabelTable();
int tallest = 0;
if (dictionary != null) {
Enumeration keys = dictionary.keys();
while (keys.hasMoreElements()) {
JComponent label = (JComponent) dictionary.get(keys.nextElement());
tallest = Math.max(label.getPreferredSize().height, tallest);
}
}
return Math.min(tallest, defaultLabelHeight);
}
@Override
protected int getWidthOfWidestLabel() {
Dictionary dictionary = slider.getLabelTable();
int widest = 0;
if (dictionary != null) {
Enumeration keys = dictionary.keys();
while (keys.hasMoreElements()) {
JComponent label = (JComponent) dictionary.get(keys.nextElement());
widest = Math.max(label.getPreferredSize().width, widest);
}
}
return Math.min(widest, defaultLabelHeight);
}
/**
* Convenience function for determining ComponentOrientation. Helps us
* avoid having Munge directives throughout the code.
*/
static boolean isLeftToRight(Component c) {
return c.getComponentOrientation().isLeftToRight();
}
@Override
public void paintThumb(Graphics g) {
Color thumbColor = getThumbColor();
Color color = stateColor(slider, thumbHover, thumbPressed, thumbColor, disabledThumbColor, null, hoverThumbColor, pressedThumbColor);
color = FlatUIUtils.deriveColor(color, thumbColor);
Color foreground = slider.getForeground();
Color borderColor = (thumbBorderColor != null && foreground == defaultForeground) ? stateColor(slider, false, false, thumbBorderColor, disabledThumbBorderColor, focusedThumbBorderColor, null, null) : null;
Color focusedColor = FlatUIUtils.deriveColor(this.focusedColor, (foreground != defaultForeground) ? foreground : focusBaseColor);
paintThumb(g, slider, thumbRect, isRoundThumb(), color, borderColor, focusedColor, thumbBorderWidth, focusWidth);
}
/**
* Paints the thumb.
*
* @param g the graphics context
* @param slider the slider
* @param thumbRect the thumb rectangle
* @param roundThumb whether the thumb should be round
* @param thumbColor the thumb color
* @param thumbBorderColor the thumb border color
* @param focusedColor the focused color
* @param thumbBorderWidth the thumb border width
* @param focusWidth the focus width
*/
public static void paintThumb(Graphics g, JSlider slider, Rectangle thumbRect, boolean roundThumb, Color thumbColor, Color thumbBorderColor, Color focusedColor, float thumbBorderWidth, int focusWidth) {
double systemScaleFactor = UIScale.getSystemScaleFactor((Graphics2D) g);
int scaleFactor2 = 2;
if (systemScaleFactor != 1 && systemScaleFactor != scaleFactor2) {
// paint at scale 1x to avoid clipping on right and bottom edges at 125%, 150% or 175%
HiDPIUtils.paintAtScale1x((Graphics2D) g, thumbRect.x, thumbRect.y, thumbRect.width, thumbRect.height, (g2d, x2, y2, width2, height2, scaleFactor) -> {
paintThumbImpl(g, slider, x2, y2, width2, height2, roundThumb, thumbColor, thumbBorderColor, focusedColor, (float) (thumbBorderWidth * scaleFactor), (float) (focusWidth * scaleFactor));
});
return;
}
paintThumbImpl(g, slider, thumbRect.x, thumbRect.y, thumbRect.width, thumbRect.height, roundThumb, thumbColor, thumbBorderColor, focusedColor, thumbBorderWidth, focusWidth);
}
private static void paintThumbImpl(Graphics g, JSlider slider, int x, int y, int width, int height, boolean roundThumb, Color thumbColor, Color thumbBorderColor, Color focusedColor, float thumbBorderWidth, float focusWidth) {
int fw = Math.round(UIScale.scale(focusWidth));
int tx = x + fw;
int ty = y + fw;
int tw = width - fw - fw;
int th = height - fw - fw;
boolean focused = FlatUIUtils.isPermanentFocusOwner(slider);
if (roundThumb) {
paintRoundThumb(g, x, y, width, height, thumbColor, thumbBorderColor, focusedColor, thumbBorderWidth, focused, tx, ty, tw, th);
} else {
paintDirectionalThumb(g, slider, x, y, width, height, thumbColor, thumbBorderColor, focusedColor, thumbBorderWidth, tw, th, focused, fw);
}
}
private static void paintDirectionalThumb(Graphics g, JSlider slider, int x, int y, int width, int height, Color thumbColor, Color thumbBorderColor, Color focusedColor, float thumbBorderWidth, int tw, int th, boolean focused, int fw) {
Graphics2D g2 = (Graphics2D) g.create();
try {
g2.translate(x, y);
if (slider.getOrientation() == JSlider.VERTICAL) {
if (slider.getComponentOrientation().isLeftToRight()) {
g2.translate(0, height);
g2.rotate(Math.toRadians(270));
} else {
g2.translate(width, 0);
g2.rotate(Math.toRadians(90));
}
// rotate thumb width/height
int temp = tw;
tw = th;
th = temp;
}
paintDirectionalThumbImpl(thumbColor, thumbBorderColor, focusedColor, thumbBorderWidth, tw, th, focused, fw, g2);
} finally {
g2.dispose();
}
}
private static void paintDirectionalThumbImpl(Color thumbColor, Color thumbBorderColor, Color focusedColor, float thumbBorderWidth, int tw, int th, boolean focused, int fw, Graphics2D g2) {
// paint thumb focus border
if (focused) {
g2.setColor(focusedColor);
g2.fill(createDirectionalThumbShape(0, 0, tw + fw + fw, th + fw + fw, fw));
}
if (thumbBorderColor != null) {
// paint thumb border
g2.setColor(thumbBorderColor);
g2.fill(createDirectionalThumbShape(fw, fw, tw, th, 0));
// paint thumb background
float lw = UIScale.scale(thumbBorderWidth);
g2.setColor(thumbColor);
g2.fill(createDirectionalThumbShape(fw + lw, fw + lw, tw - lw - lw, th - lw - lw, 0));
} else {
// paint thumb background
g2.setColor(thumbColor);
g2.fill(createDirectionalThumbShape(fw, fw, tw, th, 0));
}
}
private static void paintRoundThumb(Graphics g, int x, int y, int width, int height, Color thumbColor, Color thumbBorderColor, Color focusedColor, float thumbBorderWidth, boolean focused, int tx, int ty, int tw, int th) {
// paint thumb focus border
if (focused) {
g.setColor(focusedColor);
((Graphics2D) g).fill(createRoundThumbShape(x, y, width, height));
}
if (thumbBorderColor != null) {
// paint thumb border
g.setColor(thumbBorderColor);
((Graphics2D) g).fill(createRoundThumbShape(tx, ty, tw, th));
// paint thumb background
float lw = UIScale.scale(thumbBorderWidth);
g.setColor(thumbColor);
((Graphics2D) g).fill(createRoundThumbShape(tx + lw, ty + lw, tw - lw - lw, th - lw - lw));
} else {
// paint thumb background
g.setColor(thumbColor);
((Graphics2D) g).fill(createRoundThumbShape(tx, ty, tw, th));
}
}
/**
* 无标签下创建圆形Thumb形状
*/
public static Shape createRoundThumbShape(float x, float y, float w, float h) {
if (AssistUtils.equals(w, h)) {
return new Ellipse2D.Float(x, y, w, h);
} else {
float arc = Math.min(w, h);
return new RoundRectangle2D.Float(x, y, w, h, arc, arc);
}
}
/**
* 有标签下创建Thumb形状
*/
public static Path2D createDirectionalThumbShape(float x, float y, float w, float h, float arc) {
float wh = w / 2;
Path2D path = new Path2D.Float(Path2D.WIND_NON_ZERO, 9);
path.moveTo(x + wh, y); // 移到反转后的位置
path.lineTo(x, y + wh); // 线到反转后的位置
path.lineTo(x, y + h - arc); // 线到反转后的位置
path.quadTo(x, y + h, x + arc, y + h); // 贝塞尔曲线到反转后的位置
path.lineTo(x + (w - arc), y + h); // 线到反转后的位置
path.quadTo(x + w, y + h, x + w, y + h - arc); // 贝塞尔曲线到反转后的位置
path.lineTo(x + w, y + wh); // 线到反转后的位置
path.closePath(); // 关闭路径
return path;
}
}

108
designer-base/src/main/java/com/fine/theme/light/ui/FineTableHeaderUI.java

@ -0,0 +1,108 @@
package com.fine.theme.light.ui;
import com.fine.theme.utils.FineUIStyle;
import com.formdev.flatlaf.ui.FlatTableHeaderUI;
import com.fr.stable.StringUtils;
import sun.swing.DefaultLookup;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JTable;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.JTableHeader;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
/**
* 应用于 JTable 的UI
*
* @author lemon
* @since
* Created on
*/
public class FineTableHeaderUI extends FlatTableHeaderUI {
protected static Color selectionBackground = UIManager.getColor("Table.background");
@Override
public void installUI(JComponent c) {
super.installUI(c);
JTableHeader header = (JTableHeader) c;
header.setDefaultRenderer(new TableHeaderRenderer());
JTable table = header.getTable();
if (table != null) {
table.setDefaultRenderer(Object.class, new TableRenderer());
}
}
@Override
public void paint(Graphics g, JComponent c) {
FineUIStyle.setStyle(((JTableHeader) c).getTable(), FineUIStyle.DEFAULT_TABLE);
super.paint(g, c);
}
/**
* 表头 render
*/
public static class TableHeaderRenderer extends DefaultTableCellRenderer implements UIResource {
public TableHeaderRenderer() {
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
Border border = DefaultLookup.getBorder(this, this.ui, "TableHeader.cellBorder");
this.setText(value == null ? "" : value.toString());
this.setHorizontalAlignment(SwingConstants.LEFT);
this.setBorder(border);
return this;
}
}
/**
* UI
* @param c
* @return
*/
public static ComponentUI createUI(JComponent c) {
return new FineTableHeaderUI();
}
/**
* 表身 render
*/
public static class TableRenderer extends DefaultTableCellRenderer {
public TableRenderer() {
setHorizontalAlignment(SwingConstants.LEFT);
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
Class<?> columnClass = table.getColumnClass(0);
Border border;
if (column == table.getColumnCount() - 1) {
border = BorderFactory.createCompoundBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, UIManager.getColor("defaultBorderColor")),
UIManager.getBorder("Table.cellNoFocusBorder"));
} else {
border = BorderFactory.createCompoundBorder(BorderFactory.createMatteBorder(0, 0, 1, 1, UIManager.getColor("defaultBorderColor")),
UIManager.getBorder("Table.cellNoFocusBorder"));
}
if (isSelected && columnClass != Boolean.class) {
selectionBackground = UIManager.getColor( "Table.selectionBackground");
} else {
selectionBackground = UIManager.getColor("Table.background");
}
setBackground(selectionBackground);
setText(value == null ? StringUtils.BLANK : String.valueOf(value));
setBorder(border);
return this;
}
}
}

53
designer-base/src/main/java/com/fine/theme/light/ui/FineTableScrollBarPaneUI.java

@ -0,0 +1,53 @@
package com.fine.theme.light.ui;
import com.formdev.flatlaf.ui.FlatScrollBarUI;
import com.fr.design.gui.iscrollbar.UIVerticalScrollBar;
import javax.swing.JComponent;
import javax.swing.JTable;
import javax.swing.plaf.ComponentUI;
import java.awt.Graphics;
import java.awt.Rectangle;
/**
* 应用于 JTable 的垂直滚动条UI
*
* @author lemon
* @since
* Created on 2024/08/11
*/
public class FineTableScrollBarPaneUI extends FlatScrollBarUI {
public FineTableScrollBarPaneUI() {
}
/**
* 创建UI
*
* @param c 组件
* @return ComponentUI
*/
public static ComponentUI createUI(JComponent c) {
return new FineTableScrollBarPaneUI();
}
@Override
protected void paintTrack(Graphics g, JComponent c, Rectangle trackBounds) {
super.paintTrack(g, c, trackBounds);
}
@Override
protected void paintThumb(Graphics g, JComponent c, Rectangle thumbBounds) {
if (c instanceof UIVerticalScrollBar) {
// 确保滚动条滑块不会超过表头区域
JTable table = ((UIVerticalScrollBar) c).getTable();
Rectangle headerRect = table.getTableHeader().getBounds();
int headerHeight = headerRect.height;
thumbBounds.y = Math.max(thumbBounds.y, headerHeight);
}
super.paintThumb(g, c, thumbBounds);
}
}

52
designer-base/src/main/java/com/fine/theme/light/ui/FineTemplateListMenuItemUI.java

@ -0,0 +1,52 @@
package com.fine.theme.light.ui;
import com.formdev.flatlaf.ui.FlatUIUtils;
import javax.swing.JComponent;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.PanelUI;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.geom.RoundRectangle2D;
/**
* 模版列表菜单ui
*
* @author vito
* @since 11.0
* Created on 2024/1/11
*/
public class FineTemplateListMenuItemUI extends PanelUI {
/**
* 创建UI
*
* @param c 组件
* @return ComponentUI
*/
public static ComponentUI createUI(JComponent c) {
return new FineTemplateListMenuItemUI();
}
@Override
public void update(Graphics g, JComponent c) {
Color color = g.getColor();
g.setColor(c.getBackground());
Insets insets = c.getInsets();
Object[] old = FlatUIUtils.setRenderingHints(g);
((Graphics2D) g).fill(new RoundRectangle2D.Float(
insets.left, insets.top,
(float) c.getWidth() - insets.left - insets.right,
(float) c.getHeight() - insets.top - insets.bottom,
3, 3));
g.setColor(color);
FlatUIUtils.resetRenderingHints(g, old);
super.paint(g, c);
}
@Override
public void uninstallUI(JComponent c) {
super.uninstallUI(c);
}
}

396
designer-base/src/main/java/com/fine/theme/light/ui/FineTemplateTabPaneUI.java

@ -0,0 +1,396 @@
package com.fine.theme.light.ui;
import com.fine.theme.icon.LazyIcon;
import com.fine.theme.utils.FineUIUtils;
import com.formdev.flatlaf.ui.FlatUIUtils;
import com.fr.base.GraphHelper;
import com.fr.base.vcs.DesignerMode;
import com.fr.design.file.MultiTemplateTabPane;
import com.fr.stable.collections.combination.Pair;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.PanelUI;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.geom.Path2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import static com.fine.theme.utils.FineUIScale.scale;
import static com.fine.theme.utils.FineUIUtils.paintRoundTabBorder;
import static com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import static com.fr.design.file.MultiTemplateTabPane.leadingWidth;
import static com.fr.design.file.MultiTemplateTabPane.TRAILING_WIDTH;
/**
* 文件Tab栏UI
*
* @author vito
* @since 11.0
* Created on 2023/12/27
*/
public class FineTemplateTabPaneUI extends PanelUI {
private MultiTemplateTabPane tabPane;
private static final String ELLIPSIS = "...";
private static final int ICON_TEXT_GAP = 4;
@Styleable(dot = true)
protected Color background;
@Styleable(dot = true)
protected Color selectedBackground;
@Styleable(dot = true)
protected Color hoverColor;
@Styleable(dot = true)
protected Color closeIconHoverBackground;
@Styleable(dot = true)
protected Color closeHoverBackground;
@Styleable(dot = true)
protected Color borderColor;
@Styleable(dot = true)
protected int tabHeight;
@Styleable(dot = true)
protected int separatorHeight;
@Styleable(dot = true)
protected int borderWidth;
@Styleable(dot = true)
protected int tabArc;
@Styleable(dot = true)
protected Insets tabInsets;
protected Icon fileIcon;
protected Icon moreAction;
protected Icon addAction;
protected Icon moreHoverAction;
private Icon closeIcon;
private Icon closeHoverIcon;
private int trailingWidth;
protected FineTemplateTabPaneUI() {
}
/**
* 创建UI
*
* @param c 组件
* @return ComponentUI
*/
public static ComponentUI createUI(JComponent c) {
return new FineTemplateTabPaneUI();
}
@Override
public void installUI(JComponent c) {
super.installUI(c);
this.tabPane = (MultiTemplateTabPane) c;
closeIcon = new LazyIcon("clear");
closeHoverIcon = new LazyIcon("clear_hover");
addAction = new LazyIcon("add_worksheet");
moreAction = new LazyIcon("tool_more");
moreHoverAction = new LazyIcon("tool_more_hover");
fileIcon = new LazyIcon("cpt_icon");
trailingWidth = scale(TRAILING_WIDTH);
borderWidth = FineUIUtils.getUIInt("TemplateTabPane.borderWidth", "TemplateTabPane.borderWidth");
tabArc = FineUIUtils.getUIInt("TemplateTabPane.tabArc", "TemplateTabPane.tabArc");
background = FineUIUtils.getUIColor("TemplateTabPane.background", "TabbedPane.background");
selectedBackground = FineUIUtils.getUIColor("TemplateTabPane.selectedBackground", "TemplateTabPane.selectedBackground");
closeHoverBackground = FineUIUtils.getUIColor("TemplateTabPane.closeHoverBackground", "TemplateTabPane.closeHoverBackground");
borderColor = FineUIUtils.getUIColor("TemplateTabPane.borderColor", "TabbedPane.tabSeparatorColor");
hoverColor = FineUIUtils.getUIColor("TemplateTabPane.hoverColor", "TemplateTabPane.hoverColor");
closeIconHoverBackground = FineUIUtils.getUIColor("TemplateTabPane.icon.hoverBackground ", "TemplateTabPane.icon.hoverBackground ");
// ---- scaled ----
tabInsets = FineUIUtils.getAndScaleUIInsets("TemplateTabPane.tabInsets", new Insets(4, 6, 4, 6));
tabHeight = FineUIUtils.getAndScaleInt("TemplateTabPane.tabHeight", "TabbedPane.tabHeight");
separatorHeight = FineUIUtils.getAndScaleInt("TemplateTabPane.separatorHeight", "TemplateTabPane.separatorHeight");
}
@Override
public void uninstallUI(JComponent c) {
super.uninstallUI(c);
}
@Override
public void update(Graphics g, JComponent c) {
super.update(g, c);
double maxWidth = c.getWidth() - scale(leadingWidth) - trailingWidth;
Graphics2D g2d = (Graphics2D) g;
paintDefaultBackground(g2d);
paintPaneUnderLine(c.getWidth(), g2d);
paintTabs(g2d, maxWidth);
}
private void paintDefaultBackground(Graphics2D g2d) {
//画默认背景
g2d.setPaint(new GradientPaint(0, 0, tabPane.getBackground(), 1, (float) (tabHeight), tabPane.getBackground()));
g2d.fillRect(0, 0, tabPane.getWidth(), tabHeight);
}
private void paintPaneUnderLine(float w, Graphics2D g2d) {
g2d.setPaint(borderColor);
float h = (float) tabHeight;
int t = scale(borderWidth);
Path2D border = new Path2D.Float(Path2D.WIND_EVEN_ODD);
border.append(FlatUIUtils.createComponentRectangle(0, 0, w, h, 0), false);
border.append(FlatUIUtils.createComponentRectangle(0, 0, w, h - t, 0), false);
g2d.fill(border);
}
private void paintTabs(Graphics2D g2d, double maxWidth) {
int maxStringlength = calculateStringMaxLength();
if (tabPane.getSelectedIndex() >= tabPane.getTabCount()) {
tabPane.setSelectedIndex(tabPane.getTabCount() - 1);
}
if (tabPane.getSelectedIndex() < 0) {
tabPane.setSelectedIndex(0);
}
double templateStartX = scale(leadingWidth);
//从可以开始展示在tab面板上的tab开始画
Pair<Integer, Integer> viewRange = tabPane.getViewRange();
for (int i = viewRange.getFirst(); i <= viewRange.getSecond(); i++) {
Icon icon = tabPane.getTemplateIconByIndex(i);
String name = tabPane.getTemplateShowNameByIndex(i);
//如果tab名字的长度大于最大能显示的英文字符长度,则进行省略号处理
if (getStringWidth(name) > maxStringlength) {
name = getEllipsisName(name, maxStringlength);
}
Icon tabcloseIcon = tabPane.isCloseCurrent(i) ? closeHoverIcon : closeIcon;
if (i == tabPane.getSelectedIndex()) {
paintSelectedTab(g2d, icon, templateStartX, name, tabcloseIcon);
} else {
paintUnSelectedTab(g2d, icon, templateStartX, name, tabcloseIcon,
tabPane.getHoverIndex(), i);
}
templateStartX += tabPane.getTabWidth();
}
paintSeparators(g2d);
if (!DesignerMode.isVcsMode()) {
paintTrailingAction(g2d, maxWidth);
}
}
private void paintSeparators(Graphics2D g2d) {
g2d.setPaint(borderColor);
float x = scale(leadingWidth);
Pair<Integer, Integer> viewRange = tabPane.getViewRange();
for (int i = viewRange.getFirst(); i <= viewRange.getSecond(); i++) {
if (i != tabPane.getSelectedIndex()
&& i + 1 != tabPane.getSelectedIndex()) {
paintSeparator(g2d, x);
}
x += tabPane.getTabWidth();
}
}
private void paintTrailingAction(Graphics2D g2d, double tabPaneWidth) {
int x = scale(leadingWidth) + (int) tabPaneWidth + (trailingWidth - moreAction.getIconWidth()) / 2;
int y = (tabHeight - moreAction.getIconHeight()) / 2;
if (tabPane.isHoverMoreAction()) {
moreHoverAction.paintIcon(tabPane, g2d, x, y);
} else {
moreAction.paintIcon(tabPane, g2d, x, y);
}
}
/**
* 判断tab文字的长度大于能装下的最大文字长度要用省略号
*
* @param name
* @param maxStringlength
* @return
*/
private String getEllipsisName(String name, int maxStringlength) {
int ellipsisWidth = getStringWidth(ELLIPSIS);
int leftkeyPoint = 0;
int rightKeyPoint = name.length() - 1;
int leftStrWidth = 0;
int rightStrWidth = 0;
while (leftStrWidth + rightStrWidth + ellipsisWidth < maxStringlength) {
if (leftStrWidth <= rightStrWidth) {
leftkeyPoint++;
} else {
rightKeyPoint--;
}
leftStrWidth = getStringWidth(name.substring(0, leftkeyPoint));
rightStrWidth = getStringWidth(name.substring(rightKeyPoint));
if (leftStrWidth + rightStrWidth + ellipsisWidth > maxStringlength) {
if (leftStrWidth <= rightStrWidth) {
rightKeyPoint++;
} else {
leftkeyPoint--;
}
break;
}
}
return name.substring(0, leftkeyPoint) + ELLIPSIS + name.substring(rightKeyPoint);
}
/**
* 计算过长度之后的每个tab的能接受的文字的英文字符数
*
* @return
*/
private int calculateStringMaxLength() {
return tabPane.getTabWidth()
- tabInsets.left - tabInsets.right
- ICON_TEXT_GAP * 2
- fileIcon.getIconWidth() - closeIcon.getIconWidth();
}
private int getStringWidth(String str) {
FontMetrics fm = GraphHelper.getFontMetrics(tabPane.getFont());
int size = 0;
for (int i = 0; i < str.length(); i++) {
size += fm.charWidth(str.codePointAt(i));
}
return size;
}
/**
* 画选中的tab
*
* @param g2d
* @param sheeticon
* @param templateStartX
* @param sheetName
* @param closeIcon
* @return
*/
private void paintSelectedTab(Graphics2D g2d, Icon sheeticon, double templateStartX, String sheetName, Icon closeIcon) {
Object[] oriRenderingHints = FlatUIUtils.setRenderingHints(g2d);
// 绘制选中背景
g2d.setPaint(selectedBackground);
Path2D tabShape = FineUIUtils.createTopRoundRectangle(templateStartX, 0,
tabPane.getTabWidth(), tabHeight, tabArc);
g2d.fill(tabShape);
// 绘制选中边框
g2d.setPaint(borderColor);
paintRoundTabBorder(g2d, templateStartX, 0,
tabPane.getTabWidth(), tabHeight, borderWidth, (float) tabArc);
// 绘制字符
g2d.setPaint(tabPane.getForeground());
Point2D.Double textPoint = calTextPoint(templateStartX, sheeticon.getIconWidth());
g2d.drawString(sheetName, (int) textPoint.x, (int) textPoint.y);
FlatUIUtils.resetRenderingHints(g2d, oriRenderingHints);
// 绘制图标
int sheetIconY = (tabHeight - sheeticon.getIconHeight()) / 2;
sheeticon.paintIcon(tabPane, g2d, (int) templateStartX + tabInsets.left, sheetIconY);
int closePosition = (int) templateStartX + tabPane.getTabWidth()
- this.closeIcon.getIconWidth() - tabInsets.right;
int closeY = (tabHeight - closeIcon.getIconHeight()) / 2;
if (!DesignerMode.isVcsMode()) {
closeIcon.paintIcon(tabPane, g2d, closePosition, closeY);
}
}
private Point2D.Double calTextPoint(double x, int iconWidth) {
FontMetrics fm = tabPane.getFontMetrics(tabPane.getFont());
int ascent = fm.getAscent();
int gap = (tabHeight - tabInsets.top - tabInsets.bottom - ascent) / 2;
double y = tabInsets.top + ascent + gap;
return new Point2D.Double(x + iconWidth + tabInsets.left + ICON_TEXT_GAP, y);
}
/**
* 画没有选中的tab
*
* @param g2d
* @param sheeticon
* @param templateStartX
* @param sheetName
* @param closeIcon
*/
private void paintUnSelectedTab(Graphics2D g2d, Icon sheeticon, double templateStartX, String sheetName, Icon closeIcon, int mouseOveredIndex, int selfIndex) {
if (selfIndex == mouseOveredIndex) {
g2d.setPaint(hoverColor);
} else {
g2d.setPaint(background);
}
Object[] oriRenderingHints = FlatUIUtils.setRenderingHints(g2d);
Path2D tabShape = FineUIUtils.createTopRoundRectangle(templateStartX, 0,
tabPane.getTabWidth(), tabHeight - scale(borderWidth), tabArc);
g2d.fill(tabShape);
// 画字符
g2d.setPaint(tabPane.getForeground());
Point2D.Double textPoint = calTextPoint(templateStartX, sheeticon.getIconWidth());
g2d.drawString(sheetName, (int) textPoint.x, (int) textPoint.y);
FlatUIUtils.resetRenderingHints(g2d, oriRenderingHints);
// 画图标
int sheetIconY = (tabHeight - sheeticon.getIconHeight()) / 2;
sheeticon.paintIcon(tabPane, g2d, (int) templateStartX + tabInsets.left, sheetIconY);
int closeY = (tabHeight - closeIcon.getIconHeight()) / 2;
int closePosition = (int) templateStartX + tabPane.getTabWidth()
- this.closeIcon.getIconWidth() - tabInsets.right;
if (!DesignerMode.isVcsMode()) {
closeIcon.paintIcon(tabPane, g2d, closePosition, closeY);
}
}
private void paintSeparator(Graphics2D g2d, float templateStartX) {
float x = templateStartX + tabPane.getTabWidth();
float gap = (tabHeight - separatorHeight) / 2.0f;
g2d.fill(new Rectangle2D.Float(x, gap, scale(borderWidth), tabHeight - gap * 2));
}
@Override
public Dimension getPreferredSize(JComponent c) {
return new Dimension(c.getWidth(), tabHeight);
}
@Override
public Dimension getMinimumSize(JComponent c) {
return new Dimension(0, tabHeight);
}
@Override
public Dimension getMaximumSize(JComponent c) {
return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
}
}

218
designer-base/src/main/java/com/fine/theme/light/ui/FineToggleButtonUI.java

@ -0,0 +1,218 @@
package com.fine.theme.light.ui;
import com.fine.theme.utils.FineUIUtils;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatToggleButtonUI;
import com.formdev.flatlaf.ui.FlatUIUtils;
import com.fr.design.gui.ibutton.UIButton;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.AbstractButton;
import javax.swing.JComponent;
import javax.swing.JToggleButton;
import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.Rectangle;
import static com.fine.theme.utils.FineClientProperties.BUTTON_TYPE_GROUP;
import static com.fine.theme.utils.FineClientProperties.BUTTON_TYPE;
import static com.fine.theme.utils.FineClientProperties.BUTTON_TYPE_TAB;
import static com.fine.theme.utils.FineClientProperties.BUTTON_GROUP_POSITION;
import static com.fine.theme.utils.FineClientProperties.GROUP_BUTTON_POSITION_INNER;
import static com.fine.theme.utils.FineClientProperties.GROUP_BUTTON_POSITION_LEFT;
import static com.fine.theme.utils.FineClientProperties.GROUP_BUTTON_POSITION_LEFT_BOTTOM;
import static com.fine.theme.utils.FineClientProperties.GROUP_BUTTON_POSITION_LEFT_TOP;
import static com.fine.theme.utils.FineClientProperties.GROUP_BUTTON_POSITION_RIGHT;
import static com.fine.theme.utils.FineClientProperties.GROUP_BUTTON_POSITION_RIGHT_BOTTOM;
import static com.fine.theme.utils.FineClientProperties.GROUP_BUTTON_POSITION_RIGHT_TOP;
import static com.fine.theme.utils.FineClientProperties.TAB_BUTTON_SELECTED_BACKGROUND;
import static com.formdev.flatlaf.FlatClientProperties.clientPropertyColor;
import static com.formdev.flatlaf.FlatClientProperties.clientPropertyInt;
/**
* 提供 {@link javax.swing.JToggleButton} 的UI类
* <p>
*
* @author vito
* @uiDefault ToggleButton.tab.arc int
* @since 11.0
* Created on 2023/11/3
*/
public class FineToggleButtonUI extends FlatToggleButtonUI {
@Styleable(dot = true)
protected int tabArc;
@Styleable(dot = true)
protected Color groupBackground;
@Styleable(dot = true)
protected Color groupSelectedBackground;
@Styleable(dot = true)
protected Color groupSelectedForeground;
public static ComponentUI createUI(JComponent c) {
return FlatUIUtils.canUseSharedUI(c)
? FlatUIUtils.createSharedUI(FlatToggleButtonUI.class, () -> new FineToggleButtonUI(true))
: new FineToggleButtonUI(false);
}
protected FineToggleButtonUI(boolean shared) {
super(shared);
}
@Override
protected void installDefaults(AbstractButton b) {
super.installDefaults(b);
tabArc = UIManager.getInt("ToggleButton.tab.arc");
groupBackground = FineUIUtils.getUIColor("ToggleButton.group.background", "ToggleButton.background");
groupSelectedBackground = FineUIUtils.getUIColor("ToggleButton.group.selectedBackground", "ToggleButton.selectedBackground");
groupSelectedForeground = FineUIUtils.getUIColor("ToggleButton.group.selectedForeground", "ToggleButton.selectedForeground");
}
@Nullable
static String getButtonTypeStr(AbstractButton c) {
Object value = c.getClientProperty(BUTTON_TYPE);
if (value instanceof String)
return (String) value;
return null;
}
static int getGroupButtonPosition(AbstractButton c) {
return clientPropertyInt(c, BUTTON_GROUP_POSITION, GROUP_BUTTON_POSITION_INNER);
}
static boolean isTabButton(Component c) {
return c instanceof JToggleButton && BUTTON_TYPE_TAB.equals(getButtonTypeStr((JToggleButton) c));
}
static boolean isGroupButton(Component c) {
return c instanceof UIButton && BUTTON_TYPE_GROUP.equals(getButtonTypeStr((UIButton) c));
}
@Override
public void paint(Graphics g, JComponent c) {
if (isGroupButton(c) || isTabButton(c)) {
((AbstractButton)c).setMargin(FineUIUtils.getUIInsets("ToggleButton.compact.margin", "ToggleButton.margin"));
}
super.paint(g, c);
}
@Override
protected void paintBackground(Graphics g, JComponent c) {
if (isTabButton(c)) {
paintTabButton(g, c);
} else if (isGroupButton(c)) {
paintGroupButton(g, c);
} else {
super.paintBackground(g, c);
}
}
protected void paintTabButton(Graphics g, JComponent c) {
int height = c.getHeight();
int width = c.getWidth();
boolean selected = ((AbstractButton) c).isSelected();
// paint background
Color background;
if(c.isEnabled() && selected) {
background = tabSelectedBackground;
} else {
Color enabledColor = selected ? clientPropertyColor(c, TAB_BUTTON_SELECTED_BACKGROUND, tabSelectedBackground) : null;
// use component background if explicitly set
if (enabledColor == null) {
Color bg = c.getBackground();
if (isCustomBackground(bg)) {
enabledColor = bg;
}
}
background = buttonStateColor(c, enabledColor,
null, tabFocusBackground, tabHoverBackground, null);
}
if (background != null) {
g.setColor(background);
g.fillRoundRect(0, 0, width, height, tabArc, tabArc);
}
}
protected void paintGroupButton(Graphics g, JComponent c) {
Color background = getBackground(c);
if (background == null) {
return;
}
Graphics2D g2 = (Graphics2D) g.create();
try {
FlatUIUtils.setRenderingHints(g2);
g2.setColor(FlatUIUtils.deriveColor(background, getBackgroundBase(c, true)));
int position = getGroupButtonPosition((AbstractButton) c);
if (position == GROUP_BUTTON_POSITION_INNER) {
float focusWidth = FlatUIUtils.getBorderFocusWidth(c);
FlatUIUtils.paintComponentBackground(g2, 0, 0, c.getWidth(), c.getHeight(), focusWidth, 0);
} else {
float arc = FlatUIUtils.getBorderArc( c ) / 2;
Shape path2D = getGroupButtonPath2D(c, position, arc);
g2.fill(path2D);
}
} finally {
g2.dispose();
}
}
@NotNull
private static Shape getGroupButtonPath2D(JComponent c, int position, float arc) {
Shape path2D;
switch (position) {
case GROUP_BUTTON_POSITION_LEFT:
path2D = FineUIUtils.createLeftRoundRectangle(0, 0, c.getWidth(), c.getHeight(), arc);
break;
case GROUP_BUTTON_POSITION_RIGHT:
path2D = FineUIUtils.createRightRoundRectangle(0, 0, c.getWidth(), c.getHeight(), arc);
break;
case GROUP_BUTTON_POSITION_LEFT_TOP:
path2D = FineUIUtils.createTopLeftRoundRectangle(0, 0, c.getWidth(), c.getHeight(), arc);
break;
case GROUP_BUTTON_POSITION_LEFT_BOTTOM:
path2D = FineUIUtils.createBottomLeftRoundRectangle(0, 0, c.getWidth(), c.getHeight(), arc);
break;
case GROUP_BUTTON_POSITION_RIGHT_TOP:
path2D = FineUIUtils.createTopRightRoundRectangle(0, 0, c.getWidth(), c.getHeight(), arc);
break;
case GROUP_BUTTON_POSITION_RIGHT_BOTTOM:
path2D = FineUIUtils.createBottomRightRoundRectangle(0, 0, c.getWidth(), c.getHeight(), arc);
break;
default:
path2D = new Rectangle();
}
return path2D;
}
@Override
protected Color getForeground(JComponent c) {
if (isGroupButton(c) && ((AbstractButton)c).isSelected()) {
return groupSelectedForeground;
}
return super.getForeground(c);
}
@Override
protected Color getBackground(JComponent c) {
if (isGroupButton(c)) {
return ((AbstractButton)c).isSelected() ? groupSelectedBackground : groupBackground;
}
return super.getBackground(c);
}
}

102
designer-base/src/main/java/com/fine/theme/light/ui/FineTooltipUI.java

@ -0,0 +1,102 @@
package com.fine.theme.light.ui;
import com.fine.theme.utils.FineUIScale;
import com.fine.theme.utils.FineUIUtils;
import com.formdev.flatlaf.ui.FlatToolTipUI;
import com.formdev.flatlaf.ui.FlatUIUtils;
import com.fr.base.BaseUtils;
import com.fr.stable.Constants;
import javax.swing.JComponent;
import javax.swing.JToolTip;
import javax.swing.SwingUtilities;
import javax.swing.plaf.ComponentUI;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.RenderingHints;
import java.util.List;
/**
* ToolTip UI类
*
* @author Leo.Qin
* @since 11.0
* Created on 2023/12/8
*/
public class FineTooltipUI extends FlatToolTipUI {
private final int defaultMaxWidth = 392;
private final int defaultArc = 5;
private int maxWidth;
private int arc;
private List<String> lines;
/**
* 创建UI
*/
public static ComponentUI createUI(JComponent c) {
return FlatUIUtils.createSharedUI(FineTooltipUI.class, FineTooltipUI::new);
}
@Override
public void paint(Graphics g, JComponent c) {
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(c.getBackground());
g2d.fillRoundRect(0, 0, c.getWidth(), c.getHeight(), arc, arc);
String text = ((JToolTip) c).getTipText();
if (text == null || text.isEmpty()) {
return;
}
Insets insets = c.getInsets();
FontMetrics fm = g2d.getFontMetrics();
int x = insets.left;
int y = insets.top + fm.getAscent();
g2d.setColor(c.getForeground());
for (String line : lines) {
g2d.drawString(line, x, y);
y += fm.getHeight();
}
}
@Override
protected void installDefaults(JComponent c) {
super.installDefaults(c);
c.setOpaque(false);
arc = FineUIScale.scale(FineUIUtils.getAndScaleInt("ToolTip.arc", defaultArc));
maxWidth = FineUIUtils.getAndScaleInt("ToolTip.maxWidth", defaultMaxWidth);
}
@Override
public Dimension getPreferredSize(JComponent c) {
String text = ((JToolTip) c).getTipText();
if (text == null || text.isEmpty()) {
return new Dimension();
}
Insets insets = c.getInsets();
int fontWidth = this.maxWidth - insets.left - insets.right;
lines = BaseUtils.getLineTextList(text, null, null, fontWidth, Constants.FR_PAINT_RESOLUTION);
FontMetrics fm = c.getFontMetrics(c.getFont());
int width = 0;
int height = fm.getHeight() * Math.max(lines.size(), 1);
for (String line : lines) {
width = Math.max(width, SwingUtilities.computeStringWidth(fm, line));
}
return new Dimension(insets.left + width + insets.right, insets.top + height + insets.bottom);
}
}

64
designer-base/src/main/java/com/fine/theme/light/ui/RectangleButtonUI.java

@ -0,0 +1,64 @@
package com.fine.theme.light.ui;
import com.fine.theme.utils.FineUIUtils;
import com.formdev.flatlaf.ui.FlatButtonUI;
import com.formdev.flatlaf.ui.FlatUIUtils;
import javax.swing.AbstractButton;
import javax.swing.JComponent;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
/**
* 矩形按钮UI忽略圆角属性
*
* @author Levy.Xie
* @since 11.0
* Created on 2023/11/30
*/
public class RectangleButtonUI extends FlatButtonUI {
public RectangleButtonUI(boolean shared) {
super(shared);
}
@Override
protected void installDefaults(AbstractButton b) {
super.installDefaults(b);
selectedBackground = FineUIUtils.getUIColor( "East.TabSelectedColor", "fill.deep");
}
@Override
protected void paintBackground(Graphics g, JComponent c) {
Color background = getBackground(c);
if (background == null) {
return;
}
Graphics2D g2 = (Graphics2D) g.create();
try {
FlatUIUtils.setRenderingHints(g2);
g2.setColor(FlatUIUtils.deriveColor(background, getBackgroundBase(c, true)));
float focusWidth = FlatUIUtils.getBorderFocusWidth(c);
FlatUIUtils.paintComponentBackground(g2, 0, 0, c.getWidth(), c.getHeight(), focusWidth, 0);
} finally {
g2.dispose();
}
}
@Override
protected Color getBackground(JComponent c) {
if( ((AbstractButton)c).isSelected() ) {
return selectedBackground;
}
return buttonStateColor( c,
getBackgroundBase( c, false ),
disabledBackground,
isCustomBackground( c.getBackground() ) ? null : focusedBackground,
hoverBackground,
pressedBackground );
}
}

92
designer-base/src/main/java/com/fine/theme/light/ui/ReportScrollBarUI.java

@ -0,0 +1,92 @@
package com.fine.theme.light.ui;
import com.formdev.flatlaf.ui.FlatScrollBarUI;
import com.formdev.flatlaf.ui.FlatUIUtils;
import javax.swing.JComponent;
import javax.swing.JButton;
import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
/**
* 应用于主面板报表工作区的滚动条UI提供给 {@link com.fr.design.cell.bar.DynamicScrollBar} 的UI类
*
* @author Levy.Xie
* @since 11.0`
* Created on 2023/12/08
*/
public class ReportScrollBarUI extends FlatScrollBarUI {
/**
* 创建UI类
*
* @param c 组件
* @return ReportScrollBarUI
*/
public static ComponentUI createUI(JComponent c) {
return new ReportScrollBarUI();
}
@Override
public void installUI(JComponent c) {
super.installUI(c);
scrollBarWidth = UIManager.getInt("ScrollBar.largeBar.width");
thumbInsets = UIManager.getInsets("ScrollBar.largeBar.thumbInsets");
showButtons = UIManager.getBoolean("ScrollBar.largeBar.showButtons");
trackColor = UIManager.getColor("ScrollBar.largeBar.track");
}
@Override
public void uninstallUI(JComponent c) {
super.uninstallUI(c);
}
@Override
protected JButton createDecreaseButton(int orientation) {
return new ReportScrollBarButton(orientation);
}
@Override
protected JButton createIncreaseButton(int orientation) {
return new ReportScrollBarButton(orientation);
}
protected class ReportScrollBarButton extends FlatScrollBarButton {
protected final Color defaultButtonBackground = UIManager.getColor("ScrollBar.largeBar.buttonBackground");
protected ReportScrollBarButton(int direction) {
super(direction);
}
@Override
public void paint(Graphics g) {
Object[] oldRenderingHints = FlatUIUtils.setRenderingHints(g);
// paint hover or pressed background
if (isEnabled()) {
Color background = (pressedBackground != null && isPressed())
? pressedBackground
: (hoverBackground != null && isHover()
? hoverBackground
: null);
if (background == null) {
background = defaultButtonBackground;
}
g.setColor(deriveBackground(background));
paintBackground((Graphics2D) g);
}
// paint arrow
g.setColor(deriveForeground(getArrowColor()));
paintArrow((Graphics2D) g);
FlatUIUtils.resetRenderingHints(g, oldRenderingHints);
}
}
}

32
designer-base/src/main/java/com/fine/theme/light/ui/UIFlatTreeUI.java

@ -0,0 +1,32 @@
package com.fine.theme.light.ui;
import com.fine.theme.icon.LazyIcon;
import com.formdev.flatlaf.ui.FlatTreeUI;
import javax.swing.JComponent;
import javax.swing.plaf.ComponentUI;
/**
* 主题化的TreeUI继承自FlatTreeUI
*
* @author Levy.Xie
* @since 11.0
* Created on 2023/11/29
*/
public class UIFlatTreeUI extends FlatTreeUI {
/**
* 创建组件UI
* @param x 组件
* @return 返回组件UI
*/
public static ComponentUI createUI(JComponent x) {
return new UIFlatTreeUI();
}
protected void installDefaults() {
super.installDefaults();
setExpandedIcon(new LazyIcon("minus"));
setCollapsedIcon(new LazyIcon("plus"));
}
}

52
designer-base/src/main/java/com/fine/theme/light/ui/laf/FineDarkLaf.java

@ -0,0 +1,52 @@
package com.fine.theme.light.ui.laf;
import com.fine.swing.ui.layout.Layouts;
import com.fine.theme.icon.IconManager;
import com.fine.theme.light.ui.FineLightIconSet;
import com.formdev.flatlaf.util.UIScale;
import com.fr.stable.StringUtils;
/**
* Fine 暗色主题
*
* @author vito
* @since 11.0
* Created on 2023/9/12
*/
public class FineDarkLaf extends FineLaf {
private static final String USER_SCALE_FACTOR = "userScaleFactor";
private static final String NAME = "FineLaf Dark";
/**
* 安装外观
*
* @return 是否安装成功
*/
public static boolean setup() {
IconManager.addSet(new FineLightIconSet());
Layouts.setScaleFactor(UIScale.getUserScaleFactor());
UIScale.addPropertyChangeListener(evt -> {
if (StringUtils.equals(evt.getPropertyName(), USER_SCALE_FACTOR)) {
Layouts.setScaleFactor((float) evt.getNewValue());
}
});
return setup(new FineDarkLaf());
}
@Override
public String getName() {
return NAME;
}
@Override
public String getDescription() {
return "Fine New Dark Look and Feel";
}
@Override
public boolean isDark() {
return true;
}
}

56
designer-base/src/main/java/com/fine/theme/light/ui/laf/FineLaf.java

@ -0,0 +1,56 @@
package com.fine.theme.light.ui.laf;
import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.util.SystemInfo;
import javax.swing.PopupFactory;
/**
* Fine designer new look and feel
* FineLaf.properties 定义公共属性如UI等
* 其他主题继承该主题进行自定义防止出现UI不存在等问题
*
* @author vito
* @since 11.0
* Created on 2023/12/18
*/
public abstract class FineLaf extends FlatLaf {
private static final String NAME = "FineLaf";
@Override
public String getName() {
return NAME;
}
@Override
public String getDescription() {
return "Fine New Look and Feel";
}
@Override
public void initialize() {
super.initialize();
resetWindowDecorations();
// flat默认使用系统弹窗,3.4版本mac及win11上支持圆角边框和阴影效果
// popup弹窗不使用flat提供的工具,使用swing原生自带的
if (shouldUseNativePopupFactory()) {
PopupFactory.setSharedInstance(new PopupFactory());
}
}
private static boolean shouldUseNativePopupFactory() {
return !SystemInfo.isMacOS && !SystemInfo.isWindows_11_orLater;
}
/**
* 在win10和win11下重置窗口装饰恢复系统原生
*/
private static void resetWindowDecorations() {
if (SystemInfo.isWindows_10_orLater) {
System.setProperty("flatlaf.useWindowDecorations", "false");
System.setProperty("flatlaf.menuBarEmbedded", "false");
}
}
}

52
designer-base/src/main/java/com/fine/theme/light/ui/laf/FineLightLaf.java

@ -0,0 +1,52 @@
package com.fine.theme.light.ui.laf;
import com.fine.swing.ui.layout.Layouts;
import com.fine.theme.icon.IconManager;
import com.fine.theme.light.ui.FineLightIconSet;
import com.formdev.flatlaf.util.UIScale;
import com.fr.stable.StringUtils;
/**
* Fine 亮色主题
*
* @author vito
* @since 11.0
* Created on 2023/9/12
*/
public class FineLightLaf extends FineLaf {
public static final String USER_SCALE_FACTOR = "userScaleFactor";
private static final String NAME = "FineLaf Light";
/**
* 安装外观
*
* @return 是否安装成功
*/
public static boolean setup() {
IconManager.addSet(new FineLightIconSet());
Layouts.setScaleFactor(UIScale.getUserScaleFactor());
UIScale.addPropertyChangeListener(evt -> {
if (StringUtils.equals(evt.getPropertyName(), USER_SCALE_FACTOR)) {
Layouts.setScaleFactor((float) evt.getNewValue());
}
});
return setup(new FineLightLaf());
}
@Override
public String getName() {
return NAME;
}
@Override
public String getDescription() {
return "Fine New Light Look and Feel";
}
@Override
public boolean isDark() {
return false;
}
}

131
designer-base/src/main/java/com/fine/theme/utils/AnimatedPainter.java

@ -0,0 +1,131 @@
package com.fine.theme.utils;
import com.formdev.flatlaf.util.Animator.Interpolator;
import com.formdev.flatlaf.util.CubicBezierEasing;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
/**
* Painter 可在组件值更改时自动对绘画进行动画处理
* getValues(Component) 返回组件的值如果值已更改 paintAnimated(Component, Graphics2D, int, int, int, int, float[])
* 使用动画值从旧值到新值多次调用如果 getValues(Component) 返回多个值则每个值都有自己独立的动画
* 仅当传递给 paintWithAnimation(Component, Graphics, int, int, int, int) 的组件是 JComponent实例时动画才有效
* 在组件上设置客户端属性以存储动画状态
*
* @author vito
* @since 11.0
* Created on 2024/1/29
*/
public interface AnimatedPainter {
/**
* 开始绘画调用 paintAnimated(Component, Graphics2D, int, int, int, int, float[]) 一次来绘制当前值
* 或者如果值与上次绘制相比发生了变化则它会启动动画并使用动画值从旧值到新值多次调用
* paintAnimated(Component, Graphics2D, int, int, int, int, float[])
*
* @param c 动画所属组件
* @param g 绘制上下文
* @param x x
* @param y y
* @param width 区域宽度
* @param height 区域高度
*/
default void paintWithAnimation(Component c, Graphics g, int x, int y, int width, int height) {
AnimatedPainterSupport.paint(this, c, g, x, y, width, height);
}
/**
* 绘制给定的动画
* paintWithAnimation(Component, Graphics, int, int, int, int)调用
*
* @param c 动画所属组件
* @param g 绘制上下文
* @param x x
* @param y y
* @param width 区域宽度
* @param height 区域高度
* @param animatedValues 动画值介于先前的值 getValues(Component) 和返回的最新值 getValues(Component) 之间
*/
void paintAnimated(Component c, Graphics2D g, int x, int y, int width, int height, float[] animatedValues);
/**
* animator 调用以重新绘制区域
* 用于限制重绘区域例如如果希望只有底部边框有动画如果对多个边框进行动画处理例如底部和右侧那么单独的重绘是没有意义的
* 因为 Swing 重绘管理器会合并区域并重绘整个组件默认实现会重新绘制整个给定区域
*/
default void repaintDuringAnimation(Component c, int x, int y, int width, int height) {
c.repaint(x, y, width, height);
}
/**
* 获取组件的值
* 如果值发生更改则此类将从旧值动画到新值如果返回多个值则每个值都有自己独立的动画
* 对于切换按钮0 表示关闭和 1 表示打开
*/
float[] getValues(Component c);
/**
* 动画是否启用
*/
default boolean isAnimationEnabled() {
return true;
}
/**
* 返回动画的持续时间以毫秒为单位默认值为 150
*/
default int getAnimationDuration() {
return 150;
}
/**
* 返回动画的分辨率以毫秒为单位默认值为 10分辨率是计时事件之间的时间量
*/
default int getAnimationResolution() {
return 10;
}
/**
* 返回动画的插值器默认值为 {@link CubicBezierEasing#STANDARD_EASING}.
*/
default Interpolator getAnimationInterpolator() {
return CubicBezierEasing.STANDARD_EASING;
}
/**
* 返回给定值索引和值的动画持续时间以毫秒为单位默认值为 150
*/
default int getAnimationDuration(int valueIndex, float value) {
return getAnimationDuration();
}
/**
* 返回给定值索引和值的动画分辨率以毫秒为单位默认值为 10分辨率是计时事件之间的时间量
*/
default int getAnimationResolution(int valueIndex, float value) {
return getAnimationResolution();
}
/**
* 返回给定值索引和值的动画插值器默认值为 {@link CubicBezierEasing#STANDARD_EASING}.
*/
default Interpolator getAnimationInterpolator(int valueIndex, float value) {
return getAnimationInterpolator();
}
/**
* 返回用于存储动画支持的客户端属性键
*/
default Object getClientPropertyKey() {
return getClass();
}
/**
* 保存位置提供给 repaintDuringAnimation(Component, int, int, int, int)使用重新绘制动画区域
* 仅当传递到的 paintWithAnimation(Component, Graphics, int, int, int, int) 图形上下文使用转换的位置时才需要
*/
static void saveRepaintLocation(AnimatedPainter painter, Component c, int x, int y) {
AnimatedPainterSupport.saveRepaintLocation(painter, c, x, y);
}
}

174
designer-base/src/main/java/com/fine/theme/utils/AnimatedPainterSupport.java

@ -0,0 +1,174 @@
package com.fine.theme.utils;
import com.formdev.flatlaf.util.Animator;
import javax.swing.JComponent;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
/**
* 动画支持类用于存储动画状态并实现动画
* 逻辑保持与AnimatedIcon逻辑一致
*
* @author vito
* @since 12.0
* Created on 2024/1/29
*/
class AnimatedPainterSupport {
private int valueIndex;
private float startValue;
private float targetValue;
private float animatedValue;
private float fraction;
private Animator animator;
// last bounds of the paint area needed to repaint while animating
private int x;
private int y;
private int width;
private int height;
/**
* 用于包内绘制保持与AnimatedIcon逻辑一致
* 后期整合逻辑之后在整理代码质量
*/
static void paint(AnimatedPainter painter, Component c, Graphics g,
int x, int y, int width, int height) {
if (!isAnimationEnabled(painter, c)) {
// paint without animation if animation is disabled or
// component is not a JComponent and therefore does not support
// client properties, which are required to keep animation state
painter.paintAnimated(c, (Graphics2D) g, x, y, width, height, painter.getValues(c));
return;
}
// get component values
float[] values = painter.getValues(c);
JComponent jc = (JComponent) c;
Object key = painter.getClientPropertyKey();
AnimatedPainterSupport[] ass = (AnimatedPainterSupport[]) jc.getClientProperty(key);
// check whether length of values array has changed
if (ass != null && ass.length != values.length) {
// cancel all running animations
for (AnimatedPainterSupport as : ass) {
if (as.animator != null) {
as.animator.cancel();
}
}
ass = null;
}
if (ass == null) {
ass = new AnimatedPainterSupport[values.length];
jc.putClientProperty(key, ass);
}
for (int i = 0; i < ass.length; i++) {
AnimatedPainterSupport as = ass[i];
float value = values[i];
if (as == null) {
// painted first time --> do not animate, but remember current component value
as = new AnimatedPainterSupport();
as.valueIndex = i;
as.startValue = as.targetValue = as.animatedValue = value;
ass[i] = as;
} else if (value != as.targetValue) {
// value changed --> (re)start animation
int animationDuration = painter.getAnimationDuration(as.valueIndex, value);
// do not animate if animation duration (for current value) is zero
if (animationDuration <= 0) {
if (as.animator != null) {
as.animator.cancel();
as.animator = null;
}
as.startValue = as.targetValue = as.animatedValue = value;
as.fraction = 0;
continue;
}
if (as.animator == null) {
// create animator
AnimatedPainterSupport as2 = as;
as.animator = new Animator(1, fraction -> {
// check whether component was removed while animation is running
if (!c.isDisplayable()) {
as2.animator.stop();
return;
}
// compute animated value
as2.animatedValue = as2.startValue + ((as2.targetValue - as2.startValue) * fraction);
as2.fraction = fraction;
// repaint
painter.repaintDuringAnimation(c, as2.x, as2.y, as2.width, as2.height);
}, () -> {
as2.startValue = as2.animatedValue = as2.targetValue;
as2.animator = null;
});
}
if (as.animator.isRunning()) {
// if animation is still running, restart it from the current
// animated value to the new target value with reduced duration
as.animator.cancel();
int duration2 = (int) (animationDuration * as.fraction);
if (duration2 > 0) {
as.animator.setDuration(duration2);
}
as.startValue = as.animatedValue;
} else {
// new animation
as.animator.setDuration(animationDuration);
as.animatedValue = as.startValue;
}
// update animator for new value
as.animator.setResolution(painter.getAnimationResolution(as.valueIndex, value));
as.animator.setInterpolator(painter.getAnimationInterpolator(as.valueIndex, value));
// start animation
as.targetValue = value;
as.animator.start();
}
as.x = x;
as.y = y;
as.width = width;
as.height = height;
}
float[] animatedValues = new float[ass.length];
for (int i = 0; i < ass.length; i++) {
animatedValues[i] = ass[i].animatedValue;
}
painter.paintAnimated(c, (Graphics2D) g, x, y, width, height, animatedValues);
}
private static boolean isAnimationEnabled(AnimatedPainter painter, Component c) {
return Animator.useAnimation() && painter.isAnimationEnabled() && c instanceof JComponent;
}
static void saveRepaintLocation(AnimatedPainter painter, Component c, int x, int y) {
if (!isAnimationEnabled(painter, c)) {
return;
}
AnimatedPainterSupport[] ass = (AnimatedPainterSupport[]) ((JComponent) c).getClientProperty(painter.getClientPropertyKey());
if (ass != null) {
for (AnimatedPainterSupport as : ass) {
as.x = x;
as.y = y;
}
}
}
}

43
designer-base/src/main/java/com/fine/theme/utils/FineClientProperties.java

@ -0,0 +1,43 @@
package com.fine.theme.utils;
import com.formdev.flatlaf.FlatClientProperties;
/**
* FR-UI中使用的各类属性
*
* @author Levy.Xie
* @since 11.0
* Created on 2023/12/15
*/
public interface FineClientProperties extends FlatClientProperties {
//--------------------------- ButtonGroup -----------------------
String BUTTON_TYPE_GROUP = "group";
String BUTTON_BORDER = "buttonBorder";
String BUTTON_BORDER_LEFT_ROUND_RECT = "leftRoundRect";
String BUTTON_BORDER_RIGHT_ROUND_RECT = "rightRoundRect";
//--------------------------- PopupMenu -----------------------
String MENU_ITEM_TYPE = "MenuItemType";
String MENU_ITEM_TYPE_LOCK = "lock";
String BUTTON_GROUP_POSITION = "group_position";
//--------------------------- Panel ----------------------------
String PANEL_TYPE = "panelType";
String ROUNDED_PANEL = "roundedPanel";
//--------------------------- ComboBox ----------------------------
String COMBO_BOX_TYPE = "comboBoxType";
String ADAPTIVE_COMBO_BOX = "adaptiveComboBox";
int GROUP_BUTTON_POSITION_INNER = 0;
int GROUP_BUTTON_POSITION_LEFT = 1;
int GROUP_BUTTON_POSITION_RIGHT = 2;
int GROUP_BUTTON_POSITION_LEFT_TOP = 3;
int GROUP_BUTTON_POSITION_LEFT_BOTTOM = 4;
int GROUP_BUTTON_POSITION_RIGHT_TOP = 5;
int GROUP_BUTTON_POSITION_RIGHT_BOTTOM = 6;
}

65
designer-base/src/main/java/com/fine/theme/utils/FineComponentsFactory.java

@ -0,0 +1,65 @@
package com.fine.theme.utils;
import com.fine.theme.icon.LazyIcon;
import com.fr.design.gui.ibutton.UIButtonGroup;
import com.fr.stable.Constants;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JPanel;
import static com.fine.swing.ui.layout.Layouts.cell;
import static com.fine.swing.ui.layout.Layouts.flex;
import static com.fine.swing.ui.layout.Layouts.row;
import static com.fine.theme.utils.FineUIStyle.STYLE_PRIMARY;
import static com.fine.theme.utils.FineUIStyle.setStyle;
/**
* 设计器典型组件组合工厂
*
* @author Levy.Xie
* @since 11.0
* Created on 2024/07/26
*/
public class FineComponentsFactory {
/**
* 创建水平对齐按钮组
*
* @return 组件
*/
public static UIButtonGroup<Integer> createHorizontalAlignmentButtonGroup() {
Icon[][] alignmentIconArray = {{new LazyIcon("h_left"), new LazyIcon("h_left").white()},
{new LazyIcon("h_center"), new LazyIcon("h_center").white()},
{new LazyIcon("h_right"), new LazyIcon("h_right").white()}};
Integer[] alignment = new Integer[]{Constants.LEFT, Constants.CENTER, Constants.RIGHT};
return new UIButtonGroup<>(alignmentIconArray, alignment);
}
/**
* 创建垂直对齐按钮组
*
* @return 组件
*/
public static UIButtonGroup<Integer> createVerticalAlignmentButtonGroup() {
Icon[][] alignmentIconArray = {{new LazyIcon("v_top"), new LazyIcon("v_top").white()},
{new LazyIcon("v_center"), new LazyIcon("v_center").white()},
{new LazyIcon("v_bottom"), new LazyIcon("v_bottom").white()}};
Integer[] alignment = new Integer[]{Constants.TOP, Constants.CENTER, Constants.BOTTOM};
return new UIButtonGroup<>(alignmentIconArray, alignment);
}
/**
* 创建确认&取消按钮组间距为8右对齐
*
* @param confirmButton 确认按钮
* @param cancelButton 取消按钮
* @return 确认&取消按钮组面板
*/
public static JPanel createConfirmCancelButtonPane(JButton confirmButton, JButton cancelButton) {
setStyle(confirmButton, STYLE_PRIMARY);
return row(8,
flex(), cell(confirmButton), cell(cancelButton)).getComponent();
}
}

189
designer-base/src/main/java/com/fine/theme/utils/FineLayoutBuilder.java

@ -0,0 +1,189 @@
package com.fine.theme.utils;
import com.fine.swing.ui.layout.Column;
import com.fine.swing.ui.layout.Layouts;
import com.fine.swing.ui.layout.Row;
import com.fine.swing.ui.layout.Spacer;
import com.fr.design.foldablepane.UIExpandablePane;
import com.fr.design.gui.ilable.UILabel;
import com.fr.log.FineLoggerFactory;
import com.fr.stable.collections.combination.Pair;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import java.awt.Component;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import static com.fine.swing.ui.layout.Layouts.cell;
/**
* 设计器典型布局构建器
*
* @author Levy.Xie
* @since 11.0
* Created on 2024/05/08
*/
public class FineLayoutBuilder {
/**
* 创建标准行列表格布局行内元素均匀分布
*
* @param elePerRow 每行元素数
* @param rowSpacing 行内间距
* @param colSpacing 列内间距
* @param componentList 组件
* @return 表格面板
*/
public static Column createCommonTableLayout(int elePerRow, int rowSpacing, int colSpacing, List<? extends Component> componentList) {
int rowNum = componentList.size() / elePerRow + 1;
Iterator<? extends Component> iterator = componentList.iterator();
Column column = new Column();
column.setSpacing(colSpacing);
Row currentRow;
for (int i = 0; i < rowNum; i++) {
currentRow = new Row();
currentRow.setSpacing(rowSpacing);
for (int j = 0; j < elePerRow; j++) {
Layouts.populate(currentRow, cell(
iterator.hasNext() ? iterator.next() : new Spacer(1)
).weight(1));
}
column.add(currentRow);
}
return column;
}
/**
* 兼容TableLayout配置项生成网格布局面板
*
* @param colSpacing 间距
* @param components 组件二维数组内部每个一维数组均为行内组件一维数组元素需与weight严格对应
* @param weight 行内权重列表形如[0.4,0.6] 即首个元素占比0.4第二个元素占比0.6
* @return 面板
*/
public static JPanel compatibleTableLayout(int colSpacing, Component[][] components, double[] weight) {
Column column = new Column();
column.setSpacing(colSpacing);
try {
for (Component[] componentArray : components) {
Row row = new Row();
List<Component> visibleComponents = Arrays.stream(componentArray)
.filter(com -> com != null && com.isVisible()).collect(Collectors.toList());
if (visibleComponents.size() >= 1) {
// 仅当存在可见组件时处理布局
dealWithVisibleComponents(weight, column, componentArray, row, visibleComponents);
}
}
return asBorderLayoutWrapped(column);
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e, "[Designer] create layout failed.");
}
return new JPanel();
}
private static void dealWithVisibleComponents(double[] weight, Column column, Component[] value, Row row, List<Component> components) {
if (components.size() == 1 && value[0] != null) {
// 仅存在首个元素,则该元素自适应占满整行
Layouts.populate(row, cell(components.get(0)).weight(1));
} else {
// 其他场景,按权重分配布局,以适配原TableLayout形式
for (int j = 0; j < value.length; j++) {
Component component = value[j];
if (component == null) {
component = new Spacer(1);
}
Layouts.populate(row, cell(component).weight(weight[j]));
}
}
column.add(row);
}
/**
* 创建竖向排列的扩展面板列表
*
* @param spacing 间距
* @param elements 面板元素含标题面板
* @return 竖向排列面板
*/
@SafeVarargs
public static Column createVerticalExpandPaneLayout(int spacing, Pair<String, JPanel>... elements) {
UIExpandablePane[] panes = IntStream.range(0, elements.length)
.mapToObj(i -> {
Pair<String, JPanel> pair = elements[i];
if (i != elements.length - 1) {
return new UIExpandablePane(pair.getFirst(), pair.getSecond(), true);
}
return new UIExpandablePane(pair.getFirst(), pair.getSecond());
})
.toArray(UIExpandablePane[]::new);
return createVerticalLayout(spacing, panes);
}
/**
* 创建垂直布局面板
*
* @param spacing 间距
* @param elements 面板元素
* @return 面板
*/
public static Column createVerticalLayout(int spacing, Component... elements) {
Column column = new Column();
column.setSpacing(spacing);
for (Component element : elements) {
column.add(element);
}
return column;
}
/**
* 创建水平布局面板
*
* @param spacing 间距
* @param elements 面板元素
* @return 面板
*/
public static Row createHorizontalLayout(int spacing, double[] weight, Component... elements) {
Row row = new Row();
row.setSpacing(spacing);
for (int i = 0; i < elements.length; i++) {
Layouts.populate(row, cell(elements[i]).weight(weight[i]));
}
return row;
}
/**
* 创建水平布局面板
*
* @param spacing 间距
* @param elements 面板元素
* @return 面板
*/
public static Row createHorizontalLayout(int spacing, Component... elements) {
Row row = new Row();
row.setSpacing(spacing);
for (Component element : elements) {
Layouts.populate(row, cell(element));
}
return row;
}
/**
* 组件包装于BorderLayout中
*
* @param component 组件
* @return 包装后的面板
*/
public static JPanel asBorderLayoutWrapped(Component component) {
JPanel panel = new JPanel(new BorderLayout());
panel.add(component);
return panel;
}
}

25
designer-base/src/main/java/com/fine/theme/utils/FineUIConstants.java

@ -0,0 +1,25 @@
package com.fine.theme.utils;
import java.awt.Dimension;
/**
* 主题UI常量
*
* @author Levy.Xie
* @since 11.0
* Created on 2024/08/05
*/
public class FineUIConstants {
public static final int SCALE_FONT_SIZE_12 = FineUIScale.scale(12);
public static final int SCALE_FONT_SIZE_13 = FineUIScale.scale(13);
/**
* 对话框常量
*/
public static class Dialog {
public static final Dimension POP_DIALOG_MEDIUM = FineUIScale.scale(new Dimension(360, 400));
}
}

86
designer-base/src/main/java/com/fine/theme/utils/FineUIScale.java

@ -0,0 +1,86 @@
package com.fine.theme.utils;
import com.formdev.flatlaf.util.UIScale;
import javax.swing.plaf.DimensionUIResource;
import javax.swing.plaf.InsetsUIResource;
import javax.swing.plaf.UIResource;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Insets;
/**
* UI缩放工具
*
* @author vito
* @since 11.0
* Created on 2023/11/15
*/
public class FineUIScale {
/**
* Multiplies the given value by the user scale factor.
*/
public static float scale(float value) {
return UIScale.scale(value);
}
/**
* Multiplies the given value by the user scale factor and rounds the result.
*/
public static int scale(int value) {
return UIScale.scale(value);
}
/**
* Similar as {@link #scale(int)} but always "rounds down".
* <p>
* For use in special cases. {@link #scale(int)} is the preferred method.
*/
public static int scale2(int value) {
return UIScale.scale2(value);
}
/**
* Divides the given value by the user scale factor.
*/
public static float unscale(float value) {
return UIScale.unscale(value);
}
/**
* Divides the given value by the user scale factor and rounds the result.
*/
public static int unscale(int value) {
return UIScale.unscale(value);
}
/**
* If user scale factor is not 1, scale the given graphics context by invoking
* {@link Graphics2D#scale(double, double)} with user scale factor.
*/
public static void scaleGraphics(Graphics2D g) {
UIScale.scaleGraphics(g);
}
/**
* Scales the given dimension with the user scale factor.
* <p>
* If user scale factor is 1, then the given dimension is simply returned.
* Otherwise, a new instance of {@link Dimension} or {@link DimensionUIResource}
* is returned, depending on whether the passed dimension implements {@link UIResource}.
*/
public static Dimension scale(Dimension dimension) {
return UIScale.scale(dimension);
}
/**
* Scales the given insets with the user scale factor.
* <p>
* If user scale factor is 1, then the given insets is simply returned.
* Otherwise, a new instance of {@link Insets} or {@link InsetsUIResource}
* is returned, depending on whether the passed dimension implements {@link UIResource}.
*/
public static Insets scale(Insets insets) {
return UIScale.scale(insets);
}
}

121
designer-base/src/main/java/com/fine/theme/utils/FineUIStyle.java

@ -0,0 +1,121 @@
package com.fine.theme.utils;
import com.finebi.cbb.utils.StringUtils;
import javax.swing.JComponent;
/**
* UI样式工具
*
* @author vito
* @since 11.0
* Created on 2024/1/4
*/
public interface FineUIStyle {
String IN_TOOLBAR_GROUP = "inToolbarGroup";
String STYLE_PRIMARY = "primary";
String STYLE_SECONDARY = "secondary";
String STYLE_TEXT = "text";
String STYLE_SIZE_MEDIUM = "mediumSize";
String STYLE_SIZE_SMALL = "smallSize";
String MENU_BAR = "menuBar";
String LIGHT_GREY = "lightGrey";
String IN_TOOLBAR_LEFT = "inToolbarLeft";
String IN_TOOLBAR_RIGHT = "inToolbarRight";
String NORMAL_COLOR = "normalColor";
String TOP_TOOLS = "topTools";
String BRAND_COLOR_LABEL = "brandColorLabel";
String BUTTON_TAB_ACTION = "tabAction";
String LABEL_BOLD = "boldLabel";
String LABEL_SECONDARY = "secondaryLabel";
String LABEL_TIP = "tipLabel";
String LABEL_WARNING_TIP = "warningTipLabel";
String LABEL_UILIST = "uiListLabel";
String PLAIN_BUTTON = "plainButton";
String TOGGLE_GROUP = "inToggleGroup";
String COMPACT_BUTTON = "compactButton";
String MENU_TOOL_BAR = "menuToolBar";
String MENU_ITEM_TOOL_BAR = "menuItemToolBar";
String POPUP_MENU_TOOL_BAR = "popupMenuToolBar";
String POPUP_MENU_DROPDOWN = "dropdownPopupMenu";
String TRANSPARENT_TEXT_FIELD = "transparentTextField";
String TRANSPARENT_BACKGROUND = "transparentBackground";
String PURE_LIST = "pureList";
String NO_BORDER_LIST = "noBorderList";
String PURE_TREE = "pureTree";
String PASTEL_BUTTON = "pastelButton";
String BREADCRUMB_BUTTON = "breadcrumbButton";
String DEFAULT_TABLE = "defaultTable";
String WHITE_BUTTON = "whiteButton";
String ORIGINAL_BUTTON = "originalButton";
String DETAIL_LABEL = "detailLabel";
/**
* 添加组件的样式类类似css该方法会接在原样式后方
* <code>
* FineClientProperties.appendStyle("primary small")
* </code>
*
* @param it 组件
* @param styleClass 样式字符串支持连续添加类用空格
*/
static void appendStyle(JComponent it, String styleClass) {
Object oriProperty = it.getClientProperty(FineClientProperties.STYLE_CLASS);
if (oriProperty instanceof String && StringUtils.isNotBlank((String) oriProperty)) {
styleClass = oriProperty + " " + styleClass;
}
it.putClientProperty(FineClientProperties.STYLE_CLASS, styleClass);
}
/**
* 设置组件的样式类类似css该方法会替换原样式
* <code>
* FineClientProperties.setStyle("primary small")
* </code>
*
* @param jComponent 组件
* @param styleClass 样式字符串支持连续添加类用空格
*/
static void setStyle(JComponent jComponent, String styleClass) {
jComponent.putClientProperty(FineClientProperties.STYLE_CLASS, styleClass);
}
/**
* 样式组合
*
* @param styleClasses 所有样式
* @return 样式列表
*/
static String joinStyle(String... styleClasses) {
final StringBuilder sb = new StringBuilder();
for (final String style : styleClasses) {
if (style == null) {
continue;
}
if (sb.length() > 0) {
sb.append(" ");
}
sb.append(style);
}
return sb.toString();
}
/**
* 包含样式
*
* @param jComponent 组件
* @param styleClass 样式
* @return 是否包含指定的样式
*/
static boolean hasStyle(JComponent jComponent, String styleClass) {
Object style = jComponent.getClientProperty(FineClientProperties.STYLE_CLASS);
if (style instanceof String && StringUtils.isNotBlank((String) style)) {
return ((String) style).contains(styleClass);
}
return false;
}
}

438
designer-base/src/main/java/com/fine/theme/utils/FineUIUtils.java

@ -0,0 +1,438 @@
package com.fine.theme.utils;
import com.fine.theme.light.ui.CollapsibleScrollBarLayerUI;
import com.formdev.flatlaf.ui.FlatUIUtils;
import com.fr.design.border.FineBorderFactory;
import com.fr.design.constants.LayoutConstants;
import com.fr.design.gui.icontainer.UIScrollPane;
import com.fr.design.gui.ilable.UILabel;
import com.fr.stable.os.OperatingSystem;
import com.fr.value.AtomicClearableLazyValue;
import javax.swing.JLabel;
import javax.swing.JLayer;
import javax.swing.ScrollPaneConstants;
import javax.swing.UIManager;
import java.awt.Color;
import java.awt.Component;
import java.awt.Composite;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Insets;
import java.awt.geom.Path2D;
import java.awt.geom.RoundRectangle2D;
import java.lang.reflect.Field;
import static com.fine.swing.ui.layout.Layouts.cell;
import static com.fine.swing.ui.layout.Layouts.column;
import static com.fine.theme.light.ui.FineButtonUI.isLeftRoundButton;
import static com.formdev.flatlaf.util.UIScale.scale;
/**
* UI绘制的一些常用方法
*
* @author vito
* @since 11.0
* Created on 2023/11/3
*/
public class FineUIUtils {
public static final int RETINA_SCALE_FACTOR = 2;
/**
* 判断是否支持retina制作一些特殊效果如HIDPI图片绘制
* retina 是一种特殊的效果使用4个像素点模拟一个像素点
* 因此在其他操作系统上即使是高分屏也不具备retina的效果
* 甚至还有劣化的效果以及更差的性能
*
* @since 2023.11.16
*/
private static final AtomicClearableLazyValue<Boolean> RETINA = AtomicClearableLazyValue.create(() -> {
// 经过测试win11,ubuntu等,没有retina效果
if (!OperatingSystem.isMacos()) {
return false;
}
GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice device = env.getDefaultScreenDevice();
try {
Field field = device.getClass().getDeclaredField("scale");
field.setAccessible(true);
Object scale = field.get(device);
if (scale instanceof Integer && (Integer) scale == RETINA_SCALE_FACTOR) {
return true;
}
} catch (Exception ignored) {
}
return false;
});
/**
* 是否支持 retina
*
* @return 是否支持 retina
*/
public static boolean getRetina() {
return RETINA.getValue();
}
/**
* 放弃 retina 判断结果用于清理或者切换环境
*/
public static void clearRetina() {
RETINA.drop();
}
/**
* 通过key获取UI的颜色如果没有则使用后备key获取
*
* @param key 颜色key
* @param defaultKey 颜色后备key
* @return 颜色
*/
public static Color getUIColor(String key, String defaultKey) {
Color color = UIManager.getColor(key);
return (color != null) ? color : UIManager.getColor(defaultKey);
}
/**
* 获取key指定的int值如果没有则使用后备key获取
*
* @param key int所在的key
* @param defaultKey 后备key
* @return 长度
*/
public static int getUIInt(String key, String defaultKey) {
Object value = UIManager.get(key);
return (value instanceof Integer) ? (Integer) value : UIManager.getInt(defaultKey);
}
/**
* 获取key指定的int值并根据dpi进行缩放
*
* @param key int所在的key
* @param defaultKey 后备key
* @return 长度
*/
public static int getAndScaleInt(String key, String defaultKey) {
int intNum = getUIInt(key, defaultKey);
return FineUIScale.scale(intNum);
}
/**
* 获取key指定的int值并根据dpi进行缩放
*
* @param key int所在的key
* @param defaultInt 默认值
* @return 长度
*/
public static int getAndScaleInt(String key, int defaultInt) {
int intNum = FlatUIUtils.getUIInt(key, defaultInt);
return FineUIScale.scale(intNum);
}
/**
* 通过key获取UI的边距如果没有则使用后备key获取
*
* @param key 边距key
* @param defaultKey 边距后备key
* @return 边距
*/
public static Insets getUIInsets(String key, String defaultKey) {
Insets margin = UIManager.getInsets(key);
return (margin != null) ? margin : UIManager.getInsets(defaultKey);
}
/**
* 通过key获取UI的边距如果没有则使用后备边距
*
* @param key 边距key
* @param defaultInsets 后备边距
* @return 边距
*/
public static Insets getUIInsets(String key, Insets defaultInsets) {
Insets margin = UIManager.getInsets(key);
return (margin != null) ? margin : defaultInsets;
}
/**
* 通过key获取UI的边距如果没有则使用后备边距并根据dpi进行缩放
*
* @param key 边距key
* @param defaultInsets 后备边距
* @return 根据dpi缩放后的边距
*/
public static Insets getAndScaleUIInsets(String key, Insets defaultInsets) {
Insets margin = UIManager.getInsets(key);
Insets insets = (margin != null) ? margin : defaultInsets;
return FineUIScale.scale(insets);
}
/**
* 绘制混合图像含圆角背景色设置
*
* @param g 图像
* @param composite 混合图像
* @param background 背景色
* @param width 宽度
* @param height 高度
* @param radius 圆角
*/
public static void paintWithComposite(Graphics g, Composite composite, Color background,
int width, int height, int radius) {
Graphics2D g2d = (Graphics2D) g;
FlatUIUtils.setRenderingHints(g2d);
Composite oldComposite = g2d.getComposite();
g2d.setComposite(composite);
g2d.setColor(background);
g2d.fill(new RoundRectangle2D.Float(0, 0, width, height, radius, radius));
g2d.setComposite(oldComposite);
}
/**
* 绘制部分圆角矩形边框
*
* @param g2 Graphics2D
* @param x x坐标
* @param y y坐标
* @param width 宽度
* @param height 高度
* @param borderWidth 边框宽度
* @param arc 圆角
*/
public static void paintPartRoundButtonBorder(Component c, Graphics2D g2, int x, int y, int width, int height,
float borderWidth, float arc) {
FlatUIUtils.setRenderingHints(g2);
arc = scale(arc);
float t = scale(borderWidth);
float t2x = t * 2;
Path2D path2D = new Path2D.Float(Path2D.WIND_EVEN_ODD);
if (isLeftRoundButton(c)) {
path2D.append(createLeftRoundRectangle(x, y, width, height, arc), false);
path2D.append(createLeftRoundRectangle(x + t, y + t, width - t, height - t2x, arc - t), false);
} else {
path2D.append(createRightRoundRectangle(x, y, width, height, arc), false);
path2D.append(createRightRoundRectangle(x, y + t, width - t, height - t2x, arc - t), false);
}
g2.fill(path2D);
}
/**
* 绘制圆角tab边框
*
* @param g2 Graphics2D
* @param x x坐标
* @param y y坐标
* @param width 宽度
* @param height 高度
* @param borderWidth 边框宽度
* @param arc 圆角
*/
public static void paintRoundTabBorder(Graphics2D g2, double x, double y, double width, double height,
float borderWidth, float arc) {
FlatUIUtils.setRenderingHints(g2);
arc = scale(arc);
float t = scale(borderWidth);
float t2x = t * 2;
Path2D path2D = new Path2D.Float(Path2D.WIND_EVEN_ODD);
path2D.append(createTopRoundRectangle(x, y, width, height, arc), false);
path2D.append(createTopRoundRectangle(x + t, y + t, width - t2x, height - t, arc - t), false);
g2.fill(path2D);
}
/**
* 创建一个部分圆角的矩形路径
*
* @param x x坐标
* @param y y坐标
* @param width 矩形宽度
* @param height 矩形高度
* @param arcTopLeft 左上圆角弧度
* @param arcTopRight 右上圆角弧度
* @param arcBottomRight 右下圆角弧度
* @param arcBottomLeft 左下圆角弧度
* @return 路径
*/
public static Path2D createPartRoundRectangle(double x, double y, double width, double height,
double arcTopLeft, double arcTopRight, double arcBottomRight, double arcBottomLeft) {
Path2D path = new Path2D.Double(Path2D.WIND_EVEN_ODD, 7);
path.moveTo(x + arcTopLeft, y);
path.lineTo(x + width - arcTopRight, y);
path.quadTo(x + width, y, x + width, y + arcTopRight);
path.lineTo(x + width, y + height - arcBottomRight);
path.quadTo(x + width, y + height, x + width - arcBottomRight, y + height);
path.lineTo(x + arcBottomLeft, y + height);
path.quadTo(x, y + height, x, y + height - arcBottomLeft);
path.lineTo(x, y + arcTopLeft);
path.quadTo(x, y, x + arcTopLeft, y);
path.closePath();
return path;
}
/**
* 创建一个左圆角矩形路径
*
* @param x x坐标
* @param y y坐标
* @param width 矩形宽度
* @param height 矩形高度
* @param arc 圆角弧度
* @return 路径
*/
public static Path2D createLeftRoundRectangle(float x, float y, float width, float height, float arc) {
return createPartRoundRectangle(x, y, width, height, arc, 0, 0, arc);
}
/**
* 创建一个右圆角矩形路径
*
* @param x x坐标
* @param y y坐标
* @param width 矩形宽度
* @param height 矩形高度
* @param arc 圆角弧度
* @return 路径
*/
public static Path2D createRightRoundRectangle(float x, float y, float width, float height, float arc) {
return createPartRoundRectangle(x, y, width, height, 0, arc, arc, 0);
}
/**
* 创建一个顶圆角矩形路径
*
* @param x x坐标
* @param y y坐标
* @param width 矩形宽度
* @param height 矩形高度
* @param arc 圆角弧度
* @return 路径
*/
public static Path2D createTopRoundRectangle(double x, double y, double width, double height, double arc) {
return createPartRoundRectangle(x, y, width, height, arc, arc, 0, 0);
}
/**
* 创建一个左上圆角的矩形路径
*
* @param x x坐标
* @param y y坐标
* @param width 矩形宽度
* @param height 矩形高度
* @param arc 圆角弧度
* @return 路径
*/
public static Path2D createTopLeftRoundRectangle(float x, float y, float width, float height, float arc) {
return createPartRoundRectangle(x, y, width, height, arc, 0, 0, 0);
}
/**
* 创建一个左下圆角的矩形路径
*
* @param x x坐标
* @param y y坐标
* @param width 矩形宽度
* @param height 矩形高度
* @param arc 圆角弧度
* @return 路径
*/
public static Path2D createBottomLeftRoundRectangle(float x, float y, float width, float height, float arc) {
return createPartRoundRectangle(x, y, width, height, 0, 0, 0, arc);
}
/**
* 创建一个右上圆角的矩形路径
*
* @param x x坐标
* @param y y坐标
* @param width 矩形宽度
* @param height 矩形高度
* @param arc 圆角弧度
* @return 路径
*/
public static Path2D createTopRightRoundRectangle(float x, float y, float width, float height, float arc) {
return createPartRoundRectangle(x, y, width, height, 0, arc, 0, 0);
}
/**
* 创建一个右下圆角的矩形路径
*
* @param x x坐标
* @param y y坐标
* @param width 矩形宽度
* @param height 矩形高度
* @param arc 圆角弧度
* @return 路径
*/
public static Path2D createBottomRightRoundRectangle(float x, float y, float width, float height, float arc) {
return createPartRoundRectangle(x, y, width, height, 0, 0, arc, 0);
}
/**
* 标签加粗显示并设置下划线适用于小标题
*
* @param label 标签
*/
public static void wrapBoldLabelWithUnderline(JLabel label) {
label.setBorder(FineBorderFactory.createDefaultUnderlineBorder());
FineUIStyle.setStyle(label, FineUIStyle.LABEL_BOLD);
}
/**
* 面板元素头部添加小标题
*
* @param component 面板元素
* @param title 标题文本
* @return 包装面板
*/
public static Component wrapComponentWithTitle(Component component, String title) {
UILabel label = new UILabel(title);
wrapBoldLabelWithUnderline(label);
return column(LayoutConstants.VERTICAL_GAP,
cell(label), cell(component).weight(1.0)
).getComponent();
}
/**
* 基于组件创建一个UIScrollPane的装饰层内部的ScrollPane仅当悬浮时显示滚动条
*
* @param c 组件
* @return UIScrollPane的装饰层
*/
public static JLayer<UIScrollPane> createCollapsibleScrollBarLayer(Component c) {
return new JLayer<>(new UIScrollPane(c, ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER),
new CollapsibleScrollBarLayerUI());
}
/**
* 基于组件创建一个UIScrollPane的装饰层内部的ScrollPane仅当悬浮时显示滚动条
*
* @param c 组件
* @param verticalPolicy 滚动条垂直显示策略
* @param horizontalPolicy 滚动条水平显示策略
* @return UIScrollPane的装饰层
*/
public static JLayer<UIScrollPane> createCollapsibleScrollBarLayer(Component c, int verticalPolicy, int horizontalPolicy) {
return new JLayer<>(new UIScrollPane(c, ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER),
new CollapsibleScrollBarLayerUI(verticalPolicy, horizontalPolicy));
}
/**
* 设置组件字体大小已适配字体缩放
*
* @param c 组件
* @param size 字体大小
*/
public static void setFontSize(Component c, int size) {
Font font = c.getFont();
Font newSizeFont = font.deriveFont(font.getStyle(), scale(size));
c.setFont(newSizeFont);
}
}

12
designer-base/src/main/java/com/fr/design/actions/AllowAuthorityEditAction.java

@ -1,14 +1,18 @@
package com.fr.design.actions;
import com.fine.theme.icon.LazyIcon;
import com.fr.base.vcs.DesignerMode;
import com.fr.design.constants.UIConstants;
import com.fr.design.designer.TargetComponent;
import com.fr.design.file.HistoryTemplateListPane;
import com.fr.design.mainframe.DesignerContext;
import com.fr.design.mainframe.EastRegionContainerPane;
import com.fr.design.mainframe.JTemplate;
import com.fr.design.mainframe.WestRegionContainerPane;
import com.fr.design.menu.KeySetUtils;
import com.fr.design.module.DesignModuleFactory;
import com.fr.design.roleAuthority.ReportAndFSManagePane;
import com.fr.design.roleAuthority.RolesAlreadyEditedPane;
import com.fr.design.designer.TargetComponent;
import com.fr.design.file.HistoryTemplateListPane;
import com.fr.design.mainframe.*;
/**
* Author : daisy
@ -22,7 +26,7 @@ public class AllowAuthorityEditAction extends TemplateComponentAction {
this.setMenuKeySet(KeySetUtils.ALLOW_AUTHORITY_EDIT);
this.setName(getMenuKeySet().getMenuName());
this.setMnemonic(getMenuKeySet().getMnemonic());
this.setSmallIcon("/com/fr/design/images/m_report/allow_authority_edit");
this.setSmallIcon(new LazyIcon("allowAuthorityEdit"));
}
/**

14
designer-base/src/main/java/com/fr/design/actions/TableDataSourceAction.java

@ -1,18 +1,18 @@
package com.fr.design.actions;
import javax.swing.SwingUtilities;
import com.fr.base.svg.IconUtils;
import com.fr.design.data.DesignTableDataManager;
import com.fine.theme.icon.LazyIcon;
import com.fr.data.TableDataSource;
import com.fr.design.DesignModelAdapter;
import com.fr.design.data.DesignTableDataManager;
import com.fr.design.data.datapane.ReportTableDataPane;
import com.fr.design.data.datapane.TableDataTreePane;
import com.fr.design.data.tabledata.ResponseDataSourceChange;
import com.fr.design.DesignModelAdapter;
import com.fr.design.mainframe.JTemplate;
import com.fr.design.menu.KeySetUtils;
import com.fr.design.dialog.BasicDialog;
import com.fr.design.dialog.DialogActionAdapter;
import com.fr.design.mainframe.JTemplate;
import com.fr.design.menu.KeySetUtils;
import javax.swing.SwingUtilities;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
@ -26,7 +26,7 @@ public class TableDataSourceAction extends TemplateComponentAction<JTemplate<?,
this.setMenuKeySet(KeySetUtils.TEMPLATE_TABLE_DATA_SOURCE);
this.setName(getMenuKeySet().getMenuKeySetName() + "...");
this.setMnemonic(getMenuKeySet().getMnemonic());
this.setSmallIcon("/com/fr/design/images/m_web/datasource");
this.setSmallIcon(new LazyIcon("datasource"));
}
/**

20
designer-base/src/main/java/com/fr/design/actions/UpdateAction.java

@ -3,6 +3,7 @@
*/
package com.fr.design.actions;
import com.fine.theme.icon.LazyIcon;
import com.fr.base.NameStyle;
import com.fr.base.ScreenResolution;
import com.fr.base.Style;
@ -90,16 +91,6 @@ public abstract class UpdateAction extends ShortCut implements Action {
*/
public static final String DISABLED_ICON = "disabledIcon";
/**
* Constructor
*/
public UpdateAction() {
//设置默认的small icon,必须有一个默认的图片,这样菜单整体美观.
this.putValue(Action.SMALL_ICON, UIConstants.BLACK_ICON);
}
/**
* Returns true if the action is enabled.
*
@ -126,6 +117,7 @@ public abstract class UpdateAction extends ShortCut implements Action {
this.enabled = newValue;
//循环遍历所有的Enable属性.
if (this.componentMap != null) {
Iterator<Object> valueIt = this.componentMap.values().iterator();
while (valueIt.hasNext()) {
Object valueObject = valueIt.next();
@ -135,6 +127,7 @@ public abstract class UpdateAction extends ShortCut implements Action {
}
}
}
}
/**
@ -171,6 +164,11 @@ public abstract class UpdateAction extends ShortCut implements Action {
* @param smallIcon The small icon for the action.
*/
public void setSmallIcon(Icon smallIcon) {
if(smallIcon instanceof LazyIcon){
this.putValue(Action.SMALL_ICON, smallIcon);
this.putValue(UpdateAction.DISABLED_ICON,((LazyIcon) smallIcon).disabled());
return;
}
this.putValue(Action.SMALL_ICON, smallIcon);
}
@ -677,7 +675,7 @@ public abstract class UpdateAction extends ShortCut implements Action {
protected void setDisabledIcon4Button(AbstractButton button) {
Icon disabledIcon = (Icon) this.getValue(UpdateAction.DISABLED_ICON);
if (disabledIcon != null && disabledIcon instanceof SVGIcon) {
if (disabledIcon != null) {
button.setDisabledIcon(disabledIcon);
}
}

3
designer-base/src/main/java/com/fr/design/actions/community/BBSAction.java

@ -1,5 +1,6 @@
package com.fr.design.actions.community;
import com.fine.theme.icon.LazyIcon;
import com.fr.design.i18n.LocaleLinkProvider;
import com.fr.design.login.AbstractDesignerSSO;
import com.fr.design.menu.MenuKeySet;
@ -22,7 +23,7 @@ public class BBSAction extends AbstractDesignerSSO {
this.setMenuKeySet(BBS);
this.setName(getMenuKeySet().getMenuName());
this.setMnemonic(getMenuKeySet().getMnemonic());
this.setSmallIcon("/com/fr/design/images/bbs/bbs");
this.setSmallIcon(new LazyIcon("bbs"));
}

3
designer-base/src/main/java/com/fr/design/actions/community/BugAction.java

@ -1,5 +1,6 @@
package com.fr.design.actions.community;
import com.fine.theme.icon.LazyIcon;
import com.fr.design.i18n.LocaleLinkProvider;
import com.fr.design.login.AbstractDesignerSSO;
import com.fr.design.menu.MenuKeySet;
@ -22,7 +23,7 @@ public class BugAction extends AbstractDesignerSSO {
this.setMenuKeySet(BUG);
this.setName(getMenuKeySet().getMenuName());
this.setMnemonic(getMenuKeySet().getMnemonic());
this.setSmallIcon("/com/fr/design/images/bbs/bug");
this.setSmallIcon(new LazyIcon("bug"));
}
@Override

6
designer-base/src/main/java/com/fr/design/actions/community/BugNeedAction.java

@ -1,6 +1,6 @@
package com.fr.design.actions.community;
import com.fr.base.svg.IconUtils;
import com.fine.theme.icon.LazyIcon;
import com.fr.design.actions.UpdateAction;
import com.fr.design.locale.impl.BugNeedMark;
import com.fr.design.menu.MenuKeySet;
@ -8,7 +8,7 @@ import com.fr.design.utils.BrowseUtils;
import com.fr.general.locale.LocaleCenter;
import com.fr.general.locale.LocaleMark;
import javax.swing.*;
import javax.swing.KeyStroke;
import java.awt.event.ActionEvent;
/**
@ -20,7 +20,7 @@ public class BugNeedAction extends UpdateAction {
this.setMenuKeySet(BugAndNeed);
this.setName(getMenuKeySet().getMenuName());
this.setMnemonic(getMenuKeySet().getMnemonic());
this.setSmallIcon("/com/fr/design/images/bbs/need");
this.setSmallIcon(new LazyIcon("need"));
}
@Override

3
designer-base/src/main/java/com/fr/design/actions/community/CenterAction.java

@ -1,5 +1,6 @@
package com.fr.design.actions.community;
import com.fine.theme.icon.LazyIcon;
import com.fr.design.i18n.LocaleLinkProvider;
import com.fr.design.menu.MenuKeySet;
@ -24,7 +25,7 @@ public class CenterAction extends UpAction {
this.setMenuKeySet(CENTER);
this.setName(getMenuKeySet().getMenuName());
this.setMnemonic(getMenuKeySet().getMnemonic());
this.setSmallIcon("/com/fr/design/images/bbs/center");
this.setSmallIcon(new LazyIcon("actCenter"));
}
@Override

3
designer-base/src/main/java/com/fr/design/actions/community/NeedAction.java

@ -1,5 +1,6 @@
package com.fr.design.actions.community;
import com.fine.theme.icon.LazyIcon;
import com.fr.design.i18n.LocaleLinkProvider;
import com.fr.design.login.AbstractDesignerSSO;
import com.fr.design.menu.MenuKeySet;
@ -22,7 +23,7 @@ public class NeedAction extends AbstractDesignerSSO {
this.setMenuKeySet(NEED);
this.setName(getMenuKeySet().getMenuName());
this.setMnemonic(getMenuKeySet().getMnemonic());
this.setSmallIcon("/com/fr/design/images/bbs/need");
this.setSmallIcon(new LazyIcon("need"));
}

3
designer-base/src/main/java/com/fr/design/actions/community/QuestionAction.java

@ -1,5 +1,6 @@
package com.fr.design.actions.community;
import com.fine.theme.icon.LazyIcon;
import com.fr.design.i18n.LocaleLinkProvider;
import com.fr.design.login.AbstractDesignerSSO;
import com.fr.design.menu.MenuKeySet;
@ -22,7 +23,7 @@ public class QuestionAction extends AbstractDesignerSSO {
this.setMenuKeySet(QUESTIONS);
this.setName(getMenuKeySet().getMenuName());
this.setMnemonic(getMenuKeySet().getMnemonic());
this.setSmallIcon("/com/fr/design/images/bbs/question");
this.setSmallIcon(new LazyIcon("question"));
}

3
designer-base/src/main/java/com/fr/design/actions/community/SignAction.java

@ -1,5 +1,6 @@
package com.fr.design.actions.community;
import com.fine.theme.icon.LazyIcon;
import com.fr.design.i18n.LocaleLinkProvider;
import com.fr.design.login.AbstractDesignerSSO;
import com.fr.design.menu.MenuKeySet;
@ -22,7 +23,7 @@ public class SignAction extends AbstractDesignerSSO {
this.setMenuKeySet(SIGN);
this.setName(getMenuKeySet().getMenuName());
this.setMnemonic(getMenuKeySet().getMnemonic());
this.setSmallIcon("/com/fr/design/images/bbs/sign");
this.setSmallIcon(new LazyIcon("sign"));
}
@Override

3
designer-base/src/main/java/com/fr/design/actions/community/StudyPlanAction.java

@ -1,5 +1,6 @@
package com.fr.design.actions.community;
import com.fine.theme.icon.LazyIcon;
import com.fr.design.i18n.LocaleLinkProvider;
import com.fr.design.i18n.Toolkit;
import com.fr.design.login.AbstractDesignerSSO;
@ -18,7 +19,7 @@ public class StudyPlanAction extends AbstractDesignerSSO {
public StudyPlanAction() {
this.setName(Toolkit.i18nText("Fine-Design_Study_Plan"));
this.setSmallIcon("/com/fr/design/images/bbs/studyPlan");
this.setSmallIcon(new LazyIcon("studyPlan"));
}
@Override

3
designer-base/src/main/java/com/fr/design/actions/community/TechSolutionAction.java

@ -1,5 +1,6 @@
package com.fr.design.actions.community;
import com.fine.theme.icon.LazyIcon;
import com.fr.design.i18n.LocaleLinkProvider;
import com.fr.design.login.AbstractDesignerSSO;
import com.fr.design.menu.MenuKeySet;
@ -25,7 +26,7 @@ public class TechSolutionAction extends AbstractDesignerSSO {
this.setMenuKeySet(TSO);
this.setName(getMenuKeySet().getMenuName());
this.setMnemonic(getMenuKeySet().getMnemonic());
this.setSmallIcon("/com/fr/design/images/bbs/solution");
this.setSmallIcon(new LazyIcon("solution"));
}

4
designer-base/src/main/java/com/fr/design/actions/community/TemplateStoreAction.java

@ -1,6 +1,6 @@
package com.fr.design.actions.community;
import com.fr.base.BaseUtils;
import com.fine.theme.icon.LazyIcon;
import com.fr.design.i18n.LocaleLinkProvider;
import com.fr.design.login.AbstractDesignerSSO;
import com.fr.design.mainframe.share.collect.ComponentCollector;
@ -28,7 +28,7 @@ public class TemplateStoreAction extends AbstractDesignerSSO {
this.setMenuKeySet(TEMPLATE);
this.setName(getMenuKeySet().getMenuName());
this.setMnemonic(getMenuKeySet().getMnemonic());
this.setSmallIcon(BaseUtils.readIcon("/com/fr/base/images/share/template_store.png"));
this.setSmallIcon(new LazyIcon("templateStore"));
}
public static final MenuKeySet TEMPLATE = new MenuKeySet() {

5
designer-base/src/main/java/com/fr/design/actions/community/VideoAction.java

@ -1,12 +1,13 @@
package com.fr.design.actions.community;
import com.fine.theme.icon.LazyIcon;
import com.fr.design.locale.impl.VideoMark;
import com.fr.design.login.AbstractDesignerSSO;
import com.fr.design.menu.MenuKeySet;
import com.fr.general.locale.LocaleCenter;
import com.fr.general.locale.LocaleMark;
import javax.swing.*;
import javax.swing.KeyStroke;
public class VideoAction extends AbstractDesignerSSO {
@ -14,7 +15,7 @@ public class VideoAction extends AbstractDesignerSSO {
this.setMenuKeySet(VIDEO);
this.setName(getMenuKeySet().getMenuName());
this.setMnemonic(getMenuKeySet().getMnemonic());
this.setSmallIcon("/com/fr/design/images/bbs/video");
this.setSmallIcon(new LazyIcon("video"));
}
@Override

3
designer-base/src/main/java/com/fr/design/actions/community/WorkOrderCenterAction.java

@ -1,5 +1,6 @@
package com.fr.design.actions.community;
import com.fine.theme.icon.LazyIcon;
import com.fr.design.i18n.LocaleLinkProvider;
import com.fr.design.i18n.Toolkit;
@ -21,7 +22,7 @@ public class WorkOrderCenterAction extends UpAction {
private static final String PROPS_LINK_KEY_DEFAULT = "Fine-Design-CloudCenter_Work_Order_Center_Default";
public WorkOrderCenterAction() {
this.setSmallIcon("/com/fr/design/images/bbs/workOrderCenter");
this.setSmallIcon(new LazyIcon("workOrderCenter"));
this.setName(Toolkit.i18nText("Fine-Design_Basic_Commuinity_Work_Order_Center"));
}

22
designer-base/src/main/java/com/fr/design/actions/core/ActionFactory.java

@ -30,8 +30,8 @@ import java.util.concurrent.CopyOnWriteArraySet;
* @version 2017年11月17日14点39分
*/
public class ActionFactory {
private static Set<Class<?>> actionClasses = new CopyOnWriteArraySet<>();
private static Set<Class<?>> floatActionClasses = new CopyOnWriteArraySet<>();
private static final Set<Class<? extends UpdateAction>> actionClasses = new CopyOnWriteArraySet<>();
private static final Set<Class<? extends UpdateAction>> floatActionClasses = new CopyOnWriteArraySet<>();
private static Class chartCollectionClass = null;
/**
@ -287,13 +287,13 @@ public class ActionFactory {
*
* @param cls 类型数组
*/
public static void registerCellInsertActionClass(Class<?>[] cls) {
public static void registerCellInsertActionClass(Class<? extends UpdateAction>[] cls) {
if (cls != null) {
actionClasses.addAll(Arrays.asList(cls));
}
}
public static void referCellInsertActionClass(Class<?>[] cls) {
public static void referCellInsertActionClass(Class<? extends UpdateAction>[] cls) {
if (cls != null) {
actionClasses.clear();
actionClasses.addAll(Arrays.asList(cls));
@ -331,13 +331,13 @@ public class ActionFactory {
public static MenuKeySet[] createCellInsertActionName() {
List<MenuKeySet> actionNames = new ArrayList<>();
JTemplate jTemplate = HistoryTemplateListPane.getInstance().getCurrentEditingTemplate();
for (Class<?> clazz : actionClasses) {
for (Class<? extends UpdateAction> clazz : actionClasses) {
if (clazz == null) {
continue;
}
if (jTemplate.acceptToolbarItem(clazz)) {
try {
Constructor<? extends UpdateAction> c = (Constructor<? extends UpdateAction>) clazz.getConstructor();
Constructor<? extends UpdateAction> c = clazz.getConstructor();
actionNames.add(c.newInstance().getMenuKeySet());
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
@ -352,13 +352,13 @@ public class ActionFactory {
*
* @param cls 插入类型数组
*/
public static void registerFloatInsertActionClass(Class<?>[] cls) {
public static void registerFloatInsertActionClass(Class<? extends UpdateAction>[] cls) {
if (cls != null) {
floatActionClasses.addAll(Arrays.asList(cls));
}
}
public static void referFloatInsertActionClass(Class<?>[] cls) {
public static void referFloatInsertActionClass(Class<? extends UpdateAction>[] cls) {
if (cls != null) {
floatActionClasses.clear();
floatActionClasses.addAll(Arrays.asList(cls));
@ -374,18 +374,18 @@ public class ActionFactory {
*/
public static UpdateAction[] createFloatInsertAction(Class cls, Object obj) {
List<UpdateAction> actions = new ArrayList<>();
for (Class<?> clazz : floatActionClasses) {
for (Class<? extends UpdateAction> clazz : floatActionClasses) {
if (clazz == null) {
continue;
}
try {
Constructor<? extends UpdateAction> c = (Constructor<? extends UpdateAction>) clazz.getConstructor(cls);
Constructor<? extends UpdateAction> c = clazz.getConstructor(cls);
actions.add(c.newInstance(obj));
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
}
return actions.toArray(new UpdateAction[actions.size()]);
return actions.toArray(new UpdateAction[0]);
}
private static QuickEditor createEditor(Class clazz, Map<Class, QuickEditor> editorMap, Map<Class, Class<? extends QuickEditor>> editorClassMap) {

3
designer-base/src/main/java/com/fr/design/actions/edit/CopyAction.java

@ -3,6 +3,7 @@
*/
package com.fr.design.actions.edit;
import com.fine.theme.icon.LazyIcon;
import com.fr.design.actions.TemplateComponentAction;
import com.fr.design.base.mode.DesignModeContext;
import com.fr.design.designer.TargetComponent;
@ -21,7 +22,7 @@ public class CopyAction extends TemplateComponentAction {
this.setName(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_M_Edit_Copy"));
this.setMnemonic('C');
this.setSmallIcon("/com/fr/design/standard/copy/copy");
this.setSmallIcon(new LazyIcon("copy"));
this.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, DEFAULT_MODIFIER));
this.setEnabled(!DesignModeContext.isBanCopyAndCut());
}

4
designer-base/src/main/java/com/fr/design/actions/edit/CutAction.java

@ -3,10 +3,10 @@
*/
package com.fr.design.actions.edit;
import com.fine.theme.icon.LazyIcon;
import com.fr.design.actions.TemplateComponentAction;
import com.fr.design.base.mode.DesignModeContext;
import com.fr.design.designer.TargetComponent;
import com.fr.general.IOUtils;
import javax.swing.KeyStroke;
import java.awt.event.KeyEvent;
@ -25,7 +25,7 @@ public class CutAction extends TemplateComponentAction {
this.setName(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_M_Edit_Cut"));
this.setMnemonic('T');
this.setSmallIcon("/com/fr/design/standard/cut/cut");
this.setSmallIcon(new LazyIcon("cut"));
this.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, DEFAULT_MODIFIER));
this.setEnabled(!DesignModeContext.isBanCopyAndCut());
}

3
designer-base/src/main/java/com/fr/design/actions/edit/PasteAction.java

@ -3,6 +3,7 @@
*/
package com.fr.design.actions.edit;
import com.fine.theme.icon.LazyIcon;
import com.fr.design.actions.TemplateComponentAction;
import com.fr.design.base.mode.DesignModeContext;
import com.fr.design.designer.TargetComponent;
@ -24,7 +25,7 @@ public class PasteAction extends TemplateComponentAction {
this.setName(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_M_Edit_Paste"));
this.setMnemonic('P');
this.setSmallIcon("/com/fr/design/standard/paste/paste");
this.setSmallIcon(new LazyIcon("paste"));
this.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, DEFAULT_MODIFIER));
}

7
designer-base/src/main/java/com/fr/design/actions/edit/RedoAction.java

@ -3,14 +3,15 @@
*/
package com.fr.design.actions.edit;
import java.awt.event.ActionEvent;
import com.fine.theme.icon.LazyIcon;
import com.fr.design.DesignerEnvManager;
import com.fr.design.actions.TemplateComponentActionInterface;
import com.fr.design.actions.UpdateAction;
import com.fr.design.mainframe.JTemplate;
import com.fr.design.menu.KeySetUtils;
import java.awt.event.ActionEvent;
/**
* Redo.
*/
@ -22,7 +23,7 @@ public class RedoAction extends UpdateAction implements TemplateComponentActionI
this.setMenuKeySet(KeySetUtils.REDO);
this.setName(getMenuKeySet().getMenuKeySetName());
this.setMnemonic(getMenuKeySet().getMnemonic());
this.setSmallIcon("com/fr/design/images/m_edit/redo");
this.setSmallIcon(new LazyIcon("monochrome_redo"));
this.setAccelerator(getMenuKeySet().getKeyStroke());
}

7
designer-base/src/main/java/com/fr/design/actions/edit/UndoAction.java

@ -3,14 +3,15 @@
*/
package com.fr.design.actions.edit;
import java.awt.event.ActionEvent;
import com.fine.theme.icon.LazyIcon;
import com.fr.design.DesignerEnvManager;
import com.fr.design.actions.TemplateComponentActionInterface;
import com.fr.design.actions.UpdateAction;
import com.fr.design.mainframe.JTemplate;
import com.fr.design.menu.KeySetUtils;
import java.awt.event.ActionEvent;
/**
* Undo.
*/
@ -22,7 +23,7 @@ public class UndoAction extends UpdateAction implements TemplateComponentActionI
this.setMenuKeySet(KeySetUtils.UNDO);
this.setName(getMenuKeySet().getMenuKeySetName());
this.setMnemonic(getMenuKeySet().getMnemonic());
this.setSmallIcon("/com/fr/design/images/m_edit/undo");
this.setSmallIcon(new LazyIcon("monochrome_undo"));
this.setAccelerator(getMenuKeySet().getKeyStroke());
}

2
designer-base/src/main/java/com/fr/design/actions/file/CloseCurrentTemplateAction.java

@ -7,6 +7,7 @@ import com.fr.design.file.MultiTemplateTabPane;
import com.fr.design.mainframe.JTemplate;
import com.fr.design.menu.KeySetUtils;
import com.fr.general.IOUtils;
import java.awt.event.ActionEvent;
/**
@ -21,6 +22,7 @@ public class CloseCurrentTemplateAction extends UpdateAction {
this.setName(getMenuKeySet().getMenuKeySetName());
this.setMnemonic(getMenuKeySet().getMnemonic());
this.setAccelerator(getMenuKeySet().getKeyStroke());
this.setSmallIcon(IOUtils.readIcon("/com/fr/base/images/cell/blank.gif"));
}
/**

3
designer-base/src/main/java/com/fr/design/actions/file/DelFileAction.java

@ -1,5 +1,6 @@
package com.fr.design.actions.file;
import com.fine.theme.icon.LazyIcon;
import com.fr.design.actions.UpdateAction;
import com.fr.design.dialog.FineJOptionPane;
import com.fr.design.file.FileOperations;
@ -22,7 +23,7 @@ public class DelFileAction extends UpdateAction {
public DelFileAction() {
this.setName(Toolkit.i18nText("Fine-Design_Basic_Remove"));
this.setSmallIcon("/com/fr/design/standard/remove/remove");
this.setSmallIcon(new LazyIcon("remove"));
}
@Override

2
designer-base/src/main/java/com/fr/design/actions/file/EditEnvAction.java

@ -5,6 +5,7 @@ import com.fr.design.actions.UpdateAction;
import com.fr.design.file.HistoryTemplateListCache;
import com.fr.design.mainframe.JTemplate;
import com.fr.general.IOUtils;
import java.awt.event.ActionEvent;
@ -13,6 +14,7 @@ public class EditEnvAction extends UpdateAction {
public EditEnvAction() {
this.setName(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_M_Others") + "...");
this.setSmallIcon(IOUtils.readIcon("/com/fr/base/images/cell/blank.gif"));
}
@Override

2
designer-base/src/main/java/com/fr/design/actions/file/ExitDesignerAction.java

@ -5,6 +5,7 @@ package com.fr.design.actions.file;
import com.fr.design.file.SaveSomeTemplatePane;
import com.fr.design.mainframe.TemplateSavingChecker;
import com.fr.general.IOUtils;
import java.awt.event.ActionEvent;
import com.fr.design.actions.UpdateAction;
@ -22,6 +23,7 @@ public class ExitDesignerAction extends UpdateAction {
this.setMenuKeySet(KeySetUtils.EXIT_DESIGNER);
this.setName(getMenuKeySet().getMenuKeySetName());
this.setMnemonic(getMenuKeySet().getMnemonic());
this.setSmallIcon(IOUtils.readIcon("/com/fr/base/images/cell/blank.gif"));
}
/**

3
designer-base/src/main/java/com/fr/design/actions/file/LocateAction.java

@ -1,5 +1,6 @@
package com.fr.design.actions.file;
import com.fine.theme.icon.LazyIcon;
import com.fr.design.actions.UpdateAction;
import com.fr.design.file.HistoryTemplateListCache;
import com.fr.design.file.TemplateTreePane;
@ -28,7 +29,7 @@ public class LocateAction extends UpdateAction {
public LocateAction() {
this.setName(Toolkit.i18nText("Fine-Design_Basic_Locate"));
this.setSmallIcon("/com/fr/design/standard/locate/locate");
this.setSmallIcon(new LazyIcon("locate"));
}
@Override

4
designer-base/src/main/java/com/fr/design/actions/file/OpenRecentReportMenuDef.java

@ -1,10 +1,10 @@
package com.fr.design.actions.file;
import com.fine.theme.icon.LazyIcon;
import java.awt.event.ActionEvent;
import java.io.File;
import java.util.List;
import com.fr.base.BaseUtils;
import com.fr.design.DesignerEnvManager;
import com.fr.design.actions.UpdateAction;
import com.fr.design.gui.imenu.UIMenu;
@ -62,7 +62,7 @@ public class OpenRecentReportMenuDef extends MenuDef {
public OpenRecentReportAction(String cptName) {
this.setName(cptName);
this.setSmallIcon(BaseUtils.readIcon("/com/fr/base/images/oem/logo.png"));
this.setSmallIcon(new LazyIcon("logo"));
}
/**

8
designer-base/src/main/java/com/fr/design/actions/file/OpenTemplateAction.java

@ -3,15 +3,15 @@
*/
package com.fr.design.actions.file;
import java.awt.event.ActionEvent;
import com.fr.base.svg.IconUtils;
import com.fine.theme.icon.LazyIcon;
import com.fr.design.actions.UpdateAction;
import com.fr.design.mainframe.DesignerContext;
import com.fr.design.menu.KeySetUtils;
import com.fr.file.FILE;
import com.fr.file.FILEChooserPane;
import java.awt.event.ActionEvent;
/**
* Open Template.
@ -22,7 +22,7 @@ public class OpenTemplateAction extends UpdateAction {
this.setMenuKeySet(KeySetUtils.OPEN_TEMPLATE);
this.setName(getMenuKeySet().getMenuKeySetName());
this.setMnemonic(getMenuKeySet().getMnemonic());
this.setSmallIcon("/com/fr/design/images/buttonicon/open");
this.setSmallIcon(new LazyIcon("openTemplate"));
this.setAccelerator(getMenuKeySet().getKeyStroke());
}

2
designer-base/src/main/java/com/fr/design/actions/file/PreferenceAction.java

@ -11,6 +11,7 @@ import com.fr.design.mainframe.DesignerFrameFileDealerPane;
import com.fr.design.mainframe.JTemplate;
import com.fr.design.menu.KeySetUtils;
import com.fr.general.IOUtils;
import java.awt.event.ActionEvent;
@ -20,6 +21,7 @@ public class PreferenceAction extends UpdateAction {
this.setName(getMenuKeySet().getMenuKeySetName() + "...");
this.setMnemonic(getMenuKeySet().getMnemonic());
this.generateAndSetSearchText(PreferencePane.class.getName());
this.setSmallIcon(IOUtils.readIcon("/com/fr/base/images/cell/blank.gif"));
}
/**

545
designer-base/src/main/java/com/fr/design/actions/file/PreferencePane.java

@ -1,5 +1,10 @@
package com.fr.design.actions.file;
import com.fine.swing.ui.layout.Row;
import com.fine.theme.utils.FineLayoutBuilder;
import com.fine.theme.utils.FineUIScale;
import com.fine.theme.utils.FineUIStyle;
import com.fine.theme.utils.FineUIUtils;
import com.fr.config.Configuration;
import com.fr.config.ServerPreferenceConfig;
import com.fr.design.DesignerEnvManager;
@ -10,7 +15,7 @@ import com.fr.design.dialog.DialogActionAdapter;
import com.fr.design.dialog.DialogActionListener;
import com.fr.design.editor.editor.IntegerEditor;
import com.fr.design.file.SaveSomeTemplatePane;
import com.fr.design.gui.frpane.UITabbedPane;
import com.fr.design.gui.frpane.FineTabbedPane;
import com.fr.design.gui.ibutton.UIButton;
import com.fr.design.gui.ibutton.UIColorButton;
import com.fr.design.gui.ibutton.UINoThemeColorButton;
@ -31,8 +36,6 @@ import com.fr.design.gui.itextfield.UITextField;
import com.fr.design.i18n.Toolkit;
import com.fr.design.jdk.JdkVersion;
import com.fr.design.layout.FRGUIPaneFactory;
import com.fr.design.layout.TableLayout;
import com.fr.design.layout.TableLayoutHelper;
import com.fr.design.layout.VerticalFlowLayout;
import com.fr.design.mainframe.vcs.VcsConfigManager;
import com.fr.design.mainframe.vcs.common.VcsHelper;
@ -44,7 +47,6 @@ import com.fr.design.utils.gui.GUICoreUtils;
import com.fr.design.widget.FRWidgetFactory;
import com.fr.general.ComparatorUtils;
import com.fr.general.FRFont;
import com.fr.general.GeneralContext;
import com.fr.general.IOUtils;
import com.fr.general.Inter;
import com.fr.general.log.Log4jConfig;
@ -52,7 +54,6 @@ import com.fr.io.attr.ImageExportAttr;
import com.fr.locale.InterProviderFactory;
import com.fr.log.FineLoggerFactory;
import com.fr.report.ReportConfigManager;
import com.fr.scheduler.tool.FineScheduler;
import com.fr.stable.Constants;
import com.fr.stable.os.OperatingSystem;
import com.fr.third.apache.logging.log4j.Level;
@ -70,13 +71,10 @@ import com.fr.workspace.server.vcs.v2.scheduler.VcsAutoCleanSchedule;
import com.fr.workspace.server.vcs.v2.scheduler.VcsAutoCleanService;
import org.jetbrains.annotations.NotNull;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
@ -86,10 +84,17 @@ import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.*;
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
@ -105,6 +110,13 @@ import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import static com.fine.swing.ui.layout.Layouts.cell;
import static com.fine.swing.ui.layout.Layouts.column;
import static com.fine.swing.ui.layout.Layouts.fix;
import static com.fine.swing.ui.layout.Layouts.row;
import static com.fine.theme.utils.FineClientProperties.COMBO_BOX_TYPE;
import static com.fine.theme.utils.FineClientProperties.ADAPTIVE_COMBO_BOX;
import static com.fine.theme.utils.FineUIConstants.SCALE_FONT_SIZE_12;
import static com.fr.design.i18n.Toolkit.i18nText;
/**
@ -127,6 +139,7 @@ public class PreferencePane extends BasicPane {
private static final int MEMORY_TIP_LABEL_MAX_WIDTH = 230;
private static final int PREFERENCE_LABEL_MAX_WIDTH = 460;
private static final int OFFSET_HEIGHT = 60;
private static final int SETTING_V_GAP = 15;
private static final int VCS_FILL_TOTAL = 5;
private static final String TYPE = "pressed";
@ -275,109 +288,120 @@ public class PreferencePane extends BasicPane {
protected void initComponents() {
JPanel contentPane = this;
contentPane.setLayout(FRGUIPaneFactory.createBorderLayout());
// 常用面板
JPanel generalPane = column(SETTING_V_GAP,
// 功能设置
cell(createFunctionPane()),
// 编辑器设置
cell(createEditPane()),
// 颜色设置
cell(createColorSettingPane()),
// 语言选择
cell(createLanPane()),
// 启动页配置
cell(createStartupPagePane())
).weight(1).getComponent();
JPanel generalScrollPane = patchScroll(FineLayoutBuilder.asBorderLayoutWrapped(generalPane));
// 高级面板
JPanel advancePane = column(SETTING_V_GAP,
// log导出配置
cell(createLogPane()),
// 标尺单位设置
cell(createLengthPane()),
// 服务器设置
cell(createServerPane()),
// 插件管理设置
cell(createUpmSelectorPane()).with(it -> it.setVisible(!OperatingSystem.isLinux() && JdkVersion.LE_8.support())),
// 登录选项
cell(createLoginSelectorPane()).with(it -> it.setVisible(SupportOSImpl.DESIGNER_LOGIN.support())),
// Oracle设置
cell(createOraclePane()),
// 内存设置
cell(createMemoryPane()),
// 产品改良
cell(createImprovePane()),
// 内置服务器
/// 暂时不支持跟随启动
// cell(createEmbeddedServerPane()),
// 模板预览性能
cell(createTplPreviewPane()),
// 设计器启动选项
cell(createDesignerStartupPane())
).weight(1).getComponent();
useUniverseDBMCheckbox = new UICheckBox(i18nText("Fine-Design_Basic_Use_Universe_Database_Manager"));
JPanel adviceScrollPane = patchScroll(advancePane);
UITabbedPane jtabPane = new UITabbedPane();
JPanel generalPane = FRGUIPaneFactory.createY_AXISBoxInnerContainer_L_Pane();
UIScrollPane generalScrollPane = patchScroll(generalPane);
jtabPane.addTab(i18nText("Fine-Design_Basic_General"), generalScrollPane);
JPanel advancePane = FRGUIPaneFactory.createY_AXISBoxInnerContainer_L_Pane();
UIScrollPane adviceScrollPane = patchScroll(advancePane);
jtabPane.addTab(i18nText("Fine-Design_Basic_Advanced"), adviceScrollPane);
// 版本管理面板
//初始化vcs总面板
JPanel vcsParentPane = new JPanel();
CardLayout cardLayout = new CardLayout();
vcsParentPane.setLayout(cardLayout);
//vcs配置面板
JPanel vcsPane = new JPanel(new BorderLayout());
JPanel vcsPane = new JPanel(new BorderLayout(0, SETTING_V_GAP));
// vcsPane
createVcsSettingPane(vcsPane, vcsParentPane, cardLayout);
//添加滚动条
UIScrollPane vcsScrollPane = patchScroll(vcsPane);
JPanel vcsScrollPane = patchScroll(vcsPane);
//配置面板作为vcs总面板的一张卡片
vcsParentPane.add(vcsScrollPane, VcsMovePanel.SETTING);
jtabPane.addTab(i18nText("Fine-Design_Vcs_Title"), vcsParentPane);
contentPane.add(jtabPane, BorderLayout.NORTH);
createFunctionPane(generalPane);
createEditPane(generalPane);
createColorSettingPane(generalPane);
// vcsPane
createVcsSettingPane(vcsPane, vcsParentPane, cardLayout);
// ConfPane
JPanel confLocationPane = FRGUIPaneFactory.createX_AXISBoxInnerContainer_S_Pane();
advancePane.add(confLocationPane);
createLogPane(advancePane);
FineTabbedPane tabbedPane = FineTabbedPane.builder()
.addTab(i18nText("Fine-Design_Basic_General"), generalScrollPane)
.addTab(i18nText("Fine-Design_Basic_Advanced"), adviceScrollPane)
.addTab(i18nText("Fine-Design_Vcs_Title"), vcsParentPane)
.build();
contentPane.add(tabbedPane, BorderLayout.CENTER);
createLanPane(generalPane);
createStartupPagePane(generalPane);
createLengthPane(advancePane);
createServerPane(advancePane);
JPanel oraclePane = FRGUIPaneFactory.createTitledBorderPane("Oracle" + i18nText("Fine-Design_Basic_Oracle_All_Tables"));
oracleSpace = new UICheckBox(i18nText("Fine-Design_Basic_Show_All_Oracle_Tables"));
oraclePane.add(oracleSpace);
}
if (!OperatingSystem.isLinux() && JdkVersion.LE_8.support()) {
JPanel upmSelectorPane = FRGUIPaneFactory.createTitledBorderPane(i18nText("Fine-Design_Basic_Update_Plugin_Manager"));
useOptimizedUPMCheckbox = new UICheckBox(i18nText("Fine-Design_Basic_Use_New_Update_Plugin_Manager"));
upmSelectorPane.add(useOptimizedUPMCheckbox);
advancePane.add(upmSelectorPane);
private Component createDesignerStartupPane() {
cloudAnalyticsDelayCheckBox = new UICheckBox(i18nText("Fine-Design_Cloud_Analytics_Delay"));
return FineUIUtils.wrapComponentWithTitle(column(10, cell(cloudAnalyticsDelayCheckBox)).getComponent(),
i18nText("Fine-Design_Startup_Option"));
}
if (SupportOSImpl.DESIGNER_LOGIN.support()) {
JPanel loginSelectorPane = FRGUIPaneFactory.createTitledBorderPane(i18nText("Fine-Design_Basic_Login_Manager"));
useNewVersionLoginCheckbox = new UICheckBox(i18nText("Fine-Design_Basic_Use_New_Login_Manager"));
loginSelectorPane.add(useNewVersionLoginCheckbox);
advancePane.add(loginSelectorPane);
private Component createTplPreviewPane() {
imageCompressPanelCheckBox = new UICheckBox(i18nText("Fine-Design_Image_Compress"));
return FineUIUtils.wrapComponentWithTitle(column(10,
cell(imageCompressPanelCheckBox),
cell(createImageExportSettingPane())
).getComponent(),
i18nText("Fine-Design_Template_Preview_Performance"));
}
JPanel dbmSelectorPane = FRGUIPaneFactory.createTitledBorderPane(i18nText("Fine-Design_Basic_Database_Manager"));
useUniverseDBMCheckbox = new UICheckBox(i18nText("Fine-Design_Basic_Use_Universe_Database_Manager"));
//dbmSelectorPane.add(useUniverseDBMCheckbox);
//advancePane.add(dbmSelectorPane);
private Component createEmbeddedServerPane() {
embedServerLazyStartupCheckBox = new UICheckBox(i18nText("Fine-Design_Startup_When_Needed"));
return FineUIUtils.wrapComponentWithTitle(column(10, cell(embedServerLazyStartupCheckBox)).getComponent(),
i18nText("Fine-Design_Embed_Server"));
}
JPanel improvePane = FRGUIPaneFactory.createVerticalTitledBorderPane(i18nText("Fine-Design_Basic_Product_Improve"));
private Component createImprovePane() {
joinProductImproveCheckBox = new UICheckBox(i18nText("Fine-Design_Basic_Join_Product_Improve"));
improvePane.add(joinProductImproveCheckBox);
if (SupportOSImpl.AUTOPUSHUPDATE.support()) {
autoPushUpdateCheckBox = new UICheckBox(i18nText("Fine-Design_Automatic_Push_Update"));
improvePane.add(autoPushUpdateCheckBox);
JPanel improvePane = column(10,
cell(joinProductImproveCheckBox),
cell(autoPushUpdateCheckBox).with(it -> it.setVisible(SupportOSImpl.AUTOPUSHUPDATE.support()))
).getComponent();
return FineUIUtils.wrapComponentWithTitle(improvePane, i18nText("Fine-Design_Basic_Product_Improve"));
}
/*
if (DesignerPushUpdateManager.getInstance().isAutoPushUpdateSupported()) {
autoPushUpdateCheckBox = new UICheckBox(i18nText("Fine-Design_Automatic_Push_Update"));
improvePane.add(autoPushUpdateCheckBox);
}*/
JPanel spaceUpPane = FRGUIPaneFactory.createBorderLayout_S_Pane();
spaceUpPane.add(oraclePane, BorderLayout.NORTH);
spaceUpPane.add(createMemoryPane(), BorderLayout.CENTER);
spaceUpPane.add(improvePane, BorderLayout.SOUTH);
advancePane.add(spaceUpPane);
JPanel embedServerPanel = FRGUIPaneFactory.createVerticalTitledBorderPane(i18nText("Fine-Design_Embed_Server"));
embedServerLazyStartupCheckBox = new UICheckBox(i18nText("Fine-Design_Startup_When_Needed"));
embedServerPanel.add(embedServerLazyStartupCheckBox);
/// 暂时不支持跟随启动
//advancePane.add(embedServerPanel);
private Component createOraclePane() {
oracleSpace = new UICheckBox(i18nText("Fine-Design_Basic_Show_All_Oracle_Tables"));
return FineUIUtils.wrapComponentWithTitle(column(10, cell(oracleSpace)).getComponent(),
i18nText("Fine-Design_Basic_Oracle_All_Tables"));
}
JPanel imageCompressPanel = FRGUIPaneFactory.createVerticalTitledBorderPane(i18nText("Fine-Design_Template_Preview_Performance"));
imageCompressPanelCheckBox = new UICheckBox(i18nText("Fine-Design_Image_Compress"));
imageCompressPanel.add(imageCompressPanelCheckBox);
imageCompressPanel.add(createImageExportSettingPane());
advancePane.add(imageCompressPanel);
private Component createLoginSelectorPane() {
useNewVersionLoginCheckbox = new UICheckBox(i18nText("Fine-Design_Basic_Use_New_Login_Manager"));
return FineUIUtils.wrapComponentWithTitle(column(10, cell(useNewVersionLoginCheckbox)).getComponent(),
i18nText("Fine-Design_Basic_Login_Manager"));
}
JPanel designerStartupOption = FRGUIPaneFactory.createTitledBorderPane(i18nText("Fine-Design_Startup_Option"));
cloudAnalyticsDelayCheckBox = new UICheckBox(i18nText("Fine-Design_Cloud_Analytics_Delay"));
designerStartupOption.add(cloudAnalyticsDelayCheckBox);
advancePane.add(designerStartupOption);
private Component createUpmSelectorPane() {
useOptimizedUPMCheckbox = new UICheckBox(i18nText("Fine-Design_Basic_Use_New_Update_Plugin_Manager"));
return FineUIUtils.wrapComponentWithTitle(column(10, cell(useOptimizedUPMCheckbox)).getComponent(),
i18nText("Fine-Design_Basic_Update_Plugin_Manager"));
}
private JPanel createImageExportSettingPane() {
@ -392,42 +416,31 @@ public class PreferencePane extends BasicPane {
ButtonGroup previewRenderGroup = new ButtonGroup();
previewRenderGroup.add(previewRenderQuality);
previewRenderGroup.add(previewRenderSpeed);
JPanel imageExportSettingPane = FRGUIPaneFactory.createBorderLayout_S_Pane();
JComponent[][] templateComps = {
{new UILabel(Toolkit.i18nText("Fine-Design_Report_Engine_Enlarge_Or_Reduce") + ":"), this.previewResolutionBtnS, this.previewResolutionBtnM},
{new UILabel(Toolkit.i18nText("Fine-Design_Image_Export_Rendering_Quality") + ":"), this.previewRenderQuality, this.previewRenderSpeed},
};
imageExportSettingPane.add(
TableLayoutHelper.createGapTableLayoutPane(
templateComps,
new double[]{TableLayout.FILL, TableLayout.FILL},
new double[]{TableLayout.FILL, TableLayout.FILL, TableLayout.FILL},
20, 0),
BorderLayout.CENTER);
imageExportSettingPane.setBorder(BorderFactory.createEmptyBorder(0, 3, 0, 0));
return imageExportSettingPane;
return column(10,
row(
cell(new UILabel(Toolkit.i18nText("Fine-Design_Report_Engine_Enlarge_Or_Reduce") + ":")).weight(1),
cell(this.previewResolutionBtnS).weight(1),
cell(this.previewResolutionBtnM).weight(1)
),
row(
cell(new UILabel(Toolkit.i18nText("Fine-Design_Image_Export_Rendering_Quality") + ":")).weight(1),
cell(this.previewRenderQuality).weight(1),
cell(this.previewRenderSpeed).weight(1)
)
).getComponent();
}
@NotNull
private UIScrollPane patchScroll(JPanel generalPane) {
UIScrollPane generalPanelWithScroll = new UIScrollPane(generalPane, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
generalPanelWithScroll.setBorder(new EmptyBorder(0, 0, 0, 0));
generalPanelWithScroll.setPreferredSize(new Dimension(generalPane.getWidth(), 600));
return generalPanelWithScroll;
private JPanel patchScroll(JPanel generalPane) {
UIScrollPane uiScrollPane = new UIScrollPane(FineLayoutBuilder.asBorderLayoutWrapped(generalPane),
ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
return FineLayoutBuilder.asBorderLayoutWrapped(uiScrollPane);
}
private void createVcsSettingPane(JPanel generalPane,JPanel parentPane, CardLayout cardLayout) {
private void createVcsSettingPane(JPanel generalPane, JPanel parentPane, CardLayout cardLayout) {
//迁移面板
movePanel = createMovePane(cardLayout, parentPane);
generalPane.add(movePanel, BorderLayout.NORTH);
JPanel savePane = FRGUIPaneFactory.createTopVerticalTitledBorderPane(i18nText("Fine-Design_Vcs_Save_Setting"));
JPanel vcsPane = FRGUIPaneFactory.createTopVerticalTitledBorderPane(i18nText("Fine-Design_Vcs_Clean_Setting"));
JPanel containPane = FRGUIPaneFactory.createY_AXISBoxInnerContainer_L_Pane();
containPane.add(savePane);
containPane.add(vcsPane);
//填充一下面板
fillPane(containPane, VCS_FILL_TOTAL);
generalPane.add(containPane, BorderLayout.CENTER);
remindVcsLabel = new UILabel(i18nText("Fine-Design_Vcs_Remind"));
remindVcsLabel.setVisible(!VcsHelper.getInstance().needInit());
vcsEnableCheckBox = new UICheckBox(i18nText("Fine-Design_Vcs_SaveAuto"));
@ -436,26 +449,19 @@ public class PreferencePane extends BasicPane {
saveCommitCheckBox = new UICheckBox(i18nText("Fine-Design_Vcs_No_Delete"));
saveIntervalEditor = new UIPositiveIntEditor(60);
useIntervalCheckBox = new UICheckBox();
savePane.add(vcsEnableCheckBox);
savePane.add(saveIntervalPane);
//gc面板
gcControlPane = createGcControlPane();
JPanel enableVcsPanel = new JPanel(FRGUIPaneFactory.createLeftZeroLayout());
enableVcsPanel.add(remindVcsLabel);
JPanel intervalPanel = new JPanel(FRGUIPaneFactory.createLeftZeroLayout());
final UILabel everyLabel = new UILabel(i18nText("Fine-Design_Vcs_Every"));
final UILabel delayLabel = new UILabel(i18nText("Fine-Design_Vcs_Delay"));
intervalPanel.add(useIntervalCheckBox);
intervalPanel.add(everyLabel);
intervalPanel.add(saveIntervalEditor);
intervalPanel.add(delayLabel);
JPanel intervalPanel = row(4,
cell(useIntervalCheckBox),
cell(everyLabel),
cell(saveIntervalEditor),
cell(delayLabel)
).getComponent();
autoCleanPane = createAutoCleanPane();
checkAutoScheduleStartAndUpdateStatus();
vcsEnableCheckBox.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
vcsEnableCheckBox.addChangeListener(e -> {
boolean selected = vcsEnableCheckBox.isSelected();
if (selected && vcsEnableCheckBox.isEnabled()) {
saveCommitCheckBox.setEnabled(true);
@ -470,21 +476,32 @@ public class PreferencePane extends BasicPane {
everyLabel.setEnabled(false);
delayLabel.setEnabled(false);
}
}
});
vcsPane.add(enableVcsPanel);
vcsPane.add(intervalPanel);
if (VcsHelper.getInstance().isLegacyMode()) {
vcsPane.add(saveCommitCheckBox);
}
vcsPane.add(autoCleanPane);
boolean support = VcsHelper.getInstance().checkV2FunctionSupport();
saveIntervalPane.setVisible(support);
autoCleanPane.setVisible(support);
if (VcsHelper.getInstance().isLegacyMode()) {
// 老版本时才显示gc选项
vcsPane.add(gcControlPane);
}
//gc面板
gcControlPane = createGcControlPane();
boolean supportV2 = VcsHelper.getInstance().checkV2FunctionSupport();
boolean legacyMode = VcsHelper.getInstance().isLegacyMode();
Component savePane = FineUIUtils.wrapComponentWithTitle(column(10,
cell(vcsEnableCheckBox),
cell(saveIntervalPane).with(it -> it.setVisible(supportV2))
).getComponent(), i18nText("Fine-Design_Vcs_Save_Setting"));
Component vcsPane = FineUIUtils.wrapComponentWithTitle(column(10,
cell(remindVcsLabel),
cell(intervalPanel),
cell(saveCommitCheckBox).with(it -> it.setVisible(legacyMode)),
cell(autoCleanPane).with(it -> it.setVisible(supportV2)),
cell(gcControlPane).with(it -> it.setVisible(legacyMode))
).getComponent(), i18nText("Fine-Design_Vcs_Clean_Setting"));
JPanel containPane = column(SETTING_V_GAP,
cell(savePane),
cell(vcsPane)
).getComponent();
//填充一下面板
fillPane(containPane, VCS_FILL_TOTAL);
generalPane.add(containPane, BorderLayout.CENTER);
}
private void fillPane(JPanel containPane, int total) {
@ -510,12 +527,15 @@ public class PreferencePane extends BasicPane {
};
private JPanel createAutoCleanPane() {
JPanel autoCleanPane = new JPanel(FRGUIPaneFactory.createLeftZeroLayout());
Row autoCleanPane = new Row();
autoCleanPane.setSpacing(2);
useVcsAutoCleanScheduleCheckBox = new UICheckBox();
autoCleanIntervalComboBox = new UIComboBox(INTERVAL);
autoCleanIntervalComboBox.setSelectedIndex(DEFAULT_INDEX);
autoCleanRetainIntervalComboBox = new UIComboBox(INTERVAL);
autoCleanRetainIntervalComboBox.setSelectedIndex(DEFAULT_INDEX);
autoCleanIntervalComboBox.putClientProperty(COMBO_BOX_TYPE, ADAPTIVE_COMBO_BOX);
autoCleanRetainIntervalComboBox.putClientProperty(COMBO_BOX_TYPE, ADAPTIVE_COMBO_BOX);
autoCleanPane.add(useVcsAutoCleanScheduleCheckBox);
autoCleanPane.add(new UILabel(i18nText("Fine-Design_Vcs_Auto_Clean_Every")));
autoCleanPane.add(autoCleanIntervalComboBox);
@ -561,20 +581,16 @@ public class PreferencePane extends BasicPane {
}
private JPanel createSaveIntervalPane() {
JPanel saveIntervalPane = new JPanel(FRGUIPaneFactory.createLeftZeroLayout());
useVcsAutoSaveScheduleCheckBox = new UICheckBox();
autoSaveIntervalEditor = new UIPositiveIntEditor(60);
saveIntervalPane.add(useVcsAutoSaveScheduleCheckBox);
saveIntervalPane.add(new UILabel(i18nText("Fine-Design_Vcs_Every")));
saveIntervalPane.add(autoSaveIntervalEditor);
saveIntervalPane.add(new UILabel(i18nText("Fine-Design_Vcs_Save_Delay")));
useVcsAutoSaveScheduleCheckBox.setEnabled(!VcsHelper.getInstance().isLegacyMode());
saveIntervalPane.setVisible(false);
return saveIntervalPane;
return row(4,
cell(useVcsAutoSaveScheduleCheckBox).with(it -> it.setEnabled(!VcsHelper.getInstance().isLegacyMode())),
cell(new UILabel(i18nText("Fine-Design_Vcs_Every"))),
cell(autoSaveIntervalEditor),
cell(new UILabel(i18nText("Fine-Design_Vcs_Save_Delay")))
).with(it -> it.setVisible(false)).getComponent();
}
/**
* 模创建板版本gc 配置操作面板
*
@ -604,22 +620,14 @@ public class PreferencePane extends BasicPane {
return gcControlPane;
}
private void createFunctionPane(JPanel generalPane) {
JPanel topVerticalTitledBorderPane = FRGUIPaneFactory.createTopVerticalTitledBorderPane(i18nText("Fine-Design_Basic_Preference_Function"));
JPanel supportUndoPanel = new JPanel(FRGUIPaneFactory.createLeftZeroVgapNormalHgapLayout());
topVerticalTitledBorderPane.add(supportUndoPanel);
generalPane.add(topVerticalTitledBorderPane);
private Component createFunctionPane() {
//添加supportUndo选择项
supportUndoCheckBox = new UICheckBox(i18nText("Fine-Design_Basic_Preference_Support_Undo"));
supportUndoPanel.add(supportUndoCheckBox);
//添加maxUndoLimit
//String[] undoTimes = {"最大撤销次数","5次","10次","15次","20次","50次"};
String[] undoTimes = {i18nText("Fine-Design_Basic_Max_Undo_Limit"), MAX_UNDO_LIMIT_5 + i18nText("Fine-Design_Basic_Time(s)"), MAX_UNDO_LIMIT_10 + i18nText("Fine-Design_Basic_Time(s)")
, MAX_UNDO_LIMIT_15 + i18nText("Fine-Design_Basic_Time(s)"), MAX_UNDO_LIMIT_20 + i18nText("Fine-Design_Basic_Time(s)"), MAX_UNDO_LIMIT_50 + i18nText("Fine-Design_Basic_Time(s)")};
maxUndoLimit = new UIComboBox(undoTimes);
supportUndoPanel.add(maxUndoLimit);
maxUndoLimit.putClientProperty(COMBO_BOX_TYPE, ADAPTIVE_COMBO_BOX);
//不支持撤销则不能选择撤销可缓存,也不能设置最大撤销次数
supportUndoCheckBox.addActionListener(new ActionListener() {
@ -629,32 +637,31 @@ public class PreferencePane extends BasicPane {
}
});
//添加supportDefaultParentCalculate选择项
supportDefaultParentCalculateCheckBox = new UICheckBox(
i18nText("Fine-Design_Basic_Preference_Support_Default_Parent_Calculate"));
topVerticalTitledBorderPane.add(supportDefaultParentCalculateCheckBox);
//添加是否展示打开模板提示缺少插件选择项
showTemplateMissingPlugin = new UICheckBox(
i18nText("Fine-Design_Basic_Preference_Show-Template-Missing-Plugin"));
topVerticalTitledBorderPane.add(showTemplateMissingPlugin);
startWithEmptyFile = new UICheckBox(i18nText("Fine-Design_Basic_Preference_Start_Empty_File"));
topVerticalTitledBorderPane.add(startWithEmptyFile);
JPanel functionPanel = column(10,
row(10,
cell(supportUndoCheckBox), cell(maxUndoLimit)
),
cell(supportDefaultParentCalculateCheckBox),
cell(showTemplateMissingPlugin),
cell(startWithEmptyFile)
).getComponent();
return FineUIUtils.wrapComponentWithTitle(functionPanel, i18nText("Fine-Design_Basic_Preference_Function"));
}
private void createEditPane(JPanel generalPane) {
private Component createEditPane() {
//samuel:编辑器设置
JPanel editPane = FRGUIPaneFactory.createTopVerticalTitledBorderPane(i18nText("Fine-Design_Basic_Editor_Preference"));
generalPane.add(editPane);
//设置是否支持将字符串编辑为公式
supportStringToFormulaBox = new UICheckBox(i18nText("Fine-Design_Report_Support_String_To_Formula"));
editPane.add(supportStringToFormulaBox);
//是否默认转化
defaultStringToFormulaBox = new UICheckBox(i18nText("Fine-Design_Basic_Always"));
//不支持转化则不能默认执行
supportStringToFormulaBox.addActionListener(new ActionListener() {
@Override
@ -662,16 +669,8 @@ public class PreferencePane extends BasicPane {
defaultStringToFormulaBox.setEnabled(supportStringToFormulaBox.isSelected());
}
});
JPanel keyStrokePane = new JPanel(new BorderLayout());
keyStrokePane.add(new UILabel(i18nText("Fine-Design_Basic_Support_Auto_Complete_Shortcut") + ":"), BorderLayout.WEST);
UILabel shortCutInfoLabel = new UILabel(i18nText("Fine-Design_Basic_Support_Auto_Complete_Shortcut") + ":");
shortCutLabel = new UILabel();
keyStrokePane.add(shortCutLabel, BorderLayout.CENTER);
keyStrokePane.setBorder(new EmptyBorder(0, 10,0,0));
JPanel defaultExecutePane = new JPanel(FRGUIPaneFactory.createLeftZeroVgapNormalHgapLayout());
defaultExecutePane.add(defaultStringToFormulaBox);
defaultExecutePane.add(keyStrokePane);
editPane.add(defaultExecutePane);
shortCutLabel.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
@ -687,6 +686,16 @@ public class PreferencePane extends BasicPane {
}
}
});
JPanel editPanel = column(10,
cell(supportStringToFormulaBox),
row(
cell(defaultStringToFormulaBox),
fix(10),
cell(shortCutInfoLabel),
cell(shortCutLabel)
)
).getComponent();
return FineUIUtils.wrapComponentWithTitle(editPanel, i18nText("Fine-Design_Basic_Editor_Preference"));
}
private class KeyStrokePane extends BasicPane {
@ -730,39 +739,28 @@ public class PreferencePane extends BasicPane {
}
private void createColorSettingPane(JPanel generalPane) {
private Component createColorSettingPane() {
// Color Setting Pane
JPanel colorSettingPane = FRGUIPaneFactory.createTitledBorderPane(i18nText("Fine-Design_Basic_Preference_Setting_Colors"));
generalPane.add(colorSettingPane);
gridLineColorTBButton = new UINoThemeColorButton(IOUtils.readIcon("/com/fr/design/images/gui/color/foreground.png"));
gridLineColorTBButton.setEnabled(this.isEnabled());
paginationLineColorTBButton = new UINoThemeColorButton(IOUtils.readIcon("/com/fr/design/images/gui/color/foreground.png"));
paginationLineColorTBButton.setEnabled(this.isEnabled());
JPanel leftPane = FRGUIPaneFactory.createNormalFlowInnerContainer_S_Pane();
leftPane.add(new UILabel(i18nText("Fine-Design_Basic_Preference_Grid_Line_Color") + ":"));
leftPane.add(gridLineColorTBButton);
JPanel rightPane = FRGUIPaneFactory.createNormalFlowInnerContainer_S_Pane();
rightPane.add(new UILabel(i18nText("Fine-Design_Basic_Preference_Pagination_Line_Color") + ":"));
rightPane.add(paginationLineColorTBButton);
colorSettingPane.add(leftPane);
colorSettingPane.add(rightPane);
JPanel colorPanel = row(10,
cell(new UILabel(i18nText("Fine-Design_Basic_Preference_Grid_Line_Color") + ":")),
cell(gridLineColorTBButton),
cell(new UILabel(i18nText("Fine-Design_Basic_Preference_Pagination_Line_Color") + ":")),
cell(paginationLineColorTBButton)
).getComponent();
return FineUIUtils.wrapComponentWithTitle(colorPanel, i18nText("Fine-Design_Basic_Preference_Setting_Colors"));
}
private void createLogPane(JPanel advancePane) {
private Component createLogPane() {
//richer:选择导出log文件的目录.
JPanel logPane = FRGUIPaneFactory.createX_AXISBoxInnerContainer_S_Pane();
advancePane.add(logPane);
JPanel logExportPane = FRGUIPaneFactory.createTitledBorderPane("log" + i18nText("Fine-Design_Basic_Export_Setting"));
logPane.add(logExportPane);
UILabel logLabel = new UILabel(i18nText("Fine-Design_Basic_Select_Export_Log_Directory") + ":");
logExportPane.add(logLabel, BorderLayout.WEST);
logExportDirectoryField = new UITextField(24);
logExportPane.add(logExportDirectoryField, BorderLayout.CENTER);
UIButton chooseDirBtn = new UIButton("...");
logExportPane.add(chooseDirBtn, BorderLayout.EAST);
chooseDirBtn.setPreferredSize(new Dimension(25, 25));
chooseDirBtn.addActionListener(new ActionListener() {
@Override
@ -777,27 +775,24 @@ public class PreferencePane extends BasicPane {
}
}
});
JPanel logLevelPane = FRGUIPaneFactory.createTitledBorderPane("log" + i18nText("Fine-Design_Basic_Level_Setting"));
logPane.add(logLevelPane);
UILabel logLevelLabel = new UILabel("Log" + i18nText("Fine-Design_Basic_Level_Setting"));
logLevelComboBox = new UIComboBox(LOG);
logLevelComboBox.setEnabled(WorkContext.getCurrent().isLocal());
logLevelPane.add(logLevelComboBox);
JPanel logPanel = row(10,
cell(logLabel),
cell(logExportDirectoryField),
cell(chooseDirBtn),
cell(logLevelLabel),
cell(logLevelComboBox).with(it -> it.putClientProperty(COMBO_BOX_TYPE, ADAPTIVE_COMBO_BOX))
).getComponent();
return FineUIUtils.wrapComponentWithTitle(logPanel, "Log" + i18nText("Fine-Design_Basic_Export_Setting"));
}
private void createLanPane(JPanel generalPane) {
private Component createLanPane() {
// ben:选择版本语言;
JPanel languageAndDashBoard_pane = FRGUIPaneFactory.createX_AXISBoxInnerContainer_S_Pane();
JPanel LanguagePane = FRGUIPaneFactory.createTitledBorderPane(i18nText("Fine-Design_Basic_Choose_Language"));
generalPane.add(languageAndDashBoard_pane);
languageAndDashBoard_pane.add(LanguagePane);
languageComboBox = createLanguageComboBox();
ActionLabel languageLabel = new ActionLabel(i18nText("Fine-Design_Basic_Designer_Language"));
languageLabel.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
languageLabel.addActionListener(e -> {
final LocalePane localePane = new LocalePane();
BasicDialog dlg = localePane.showLargeWindow(SwingUtilities.getWindowAncestor(PreferencePane.this), new DialogActionAdapter() {
@Override
@ -806,17 +801,14 @@ public class PreferencePane extends BasicPane {
}
});
dlg.setVisible(true);
}
});
UILabel noticeLabel = new UILabel(i18nText("Fine-Design_Basic_Work_After_Restart_Designer"));//sail:提示重启后生效
double p = TableLayout.PREFERRED;
double[] rowSize = {p};
double[] columnSize = {p, p, p};
Component[][] components = {
{languageLabel, languageComboBox, noticeLabel},
};
JPanel choosePane = TableLayoutHelper.createTableLayoutPane(components, rowSize, columnSize);
LanguagePane.add(choosePane);
JPanel langPanel = row(10,
cell(languageLabel),
cell(languageComboBox),
cell(noticeLabel)
).getComponent();
return FineUIUtils.wrapComponentWithTitle(langPanel, i18nText("Fine-Design_Basic_Choose_Language"));
}
private UIDictionaryComboBox<Locale> createLanguageComboBox() {
@ -832,23 +824,20 @@ public class PreferencePane extends BasicPane {
i++;
}
UIDictionaryComboBox<Locale> languageComboBox = new UIDictionaryComboBox<>(keys, values);
languageComboBox.setFont(FRFont.getInstance("Dialog", Font.PLAIN, 12));//为了在中文系统中显示韩文
languageComboBox.putClientProperty(COMBO_BOX_TYPE, ADAPTIVE_COMBO_BOX);
languageComboBox.setFont(FRFont.getInstance("Dialog", Font.PLAIN, SCALE_FONT_SIZE_12));//为了在中文系统中显示韩文
return languageComboBox;
}
private void createStartupPagePane(JPanel generalPane) {
// ben:选择版本语言;
JPanel startupPagePaneWrapper = FRGUIPaneFactory.createX_AXISBoxInnerContainer_S_Pane();
JPanel startupPane = FRGUIPaneFactory.createTopVerticalTitledBorderPane(Toolkit.i18nText("Fine-Design_Startup_Page_Config"));
generalPane.add(startupPagePaneWrapper);
startupPagePaneWrapper.add(startupPane);
private Component createStartupPagePane() {
startupPageEnabledCheckBox = new UICheckBox(Toolkit.i18nText("Fine-Design_Startup_Page_Config_Check_Text"));
startupPane.add(startupPageEnabledCheckBox);
UILabel descLabel = FRWidgetFactory.createLineWrapLabel(Toolkit.i18nText("Fine-Design_Startup_Page_Config_Desc"), PREFERENCE_LABEL_MAX_WIDTH);
descLabel.setForeground(new Color(51, 51, 52, (int)Math.round(0.5 * 255)));
startupPane.add(descLabel);
FineUIStyle.setStyle(descLabel, FineUIStyle.LABEL_TIP);
JPanel startPanel = column(10,
cell(startupPageEnabledCheckBox),
cell(descLabel)
).getComponent();
return FineUIUtils.wrapComponentWithTitle(startPanel, i18nText("Fine-Design_Startup_Page_Config"));
}
private String getDisplayShortCut(String shotrCut) {
@ -864,60 +853,44 @@ public class PreferencePane extends BasicPane {
}
private void createLengthPane(JPanel advancePane) {
double p = TableLayout.PREFERRED;
double[] rowSize = {p};
private Component createLengthPane() {
// 长度单位选择
JPanel lengthPane = FRGUIPaneFactory.createTitledBorderPane(i18nText("Fine-Design_Basic_Setting_Ruler_Units"));
advancePane.add(lengthPane);
pageLengthComboBox = new UIComboBox(new String[]{i18nText("Fine-Design_Basic_Page_Setup_MM"), i18nText("Fine-Design_Report_Unit_CM"), i18nText("Fine-Design_Report_Unit_INCH")});
pageLengthComboBox.setPreferredSize(new Dimension(80, 20));
pageLengthComboBox.setMinimumSize(new Dimension(80, 20));
reportLengthComboBox = new UIComboBox(UnitConvertUtil.getUnitItems());
reportLengthComboBox.setPreferredSize(new Dimension(80, 20));
reportLengthComboBox.setMinimumSize(new Dimension(80, 20));
UILabel pagelengthLabel = new UILabel(i18nText("Fine-Design_Basic_Page_Setup_Scale_Units") + ":");
UILabel pageLengthLabel = new UILabel(i18nText("Fine-Design_Basic_Page_Setup_Scale_Units") + ":");
UILabel reportLengthLabel = new UILabel(i18nText("Fine-Design_Basic_Report_Design_Ruler_Units") + ":");
Component[][] lengthComponents = {
{pagelengthLabel, pageLengthComboBox, reportLengthLabel, reportLengthComboBox},
};
JPanel chooseLengthPane = TableLayoutHelper.createTableLayoutPane(lengthComponents, rowSize, new double[]{p, p, p, p});
lengthPane.add(chooseLengthPane);
JPanel lengthPane = row(10,
cell(pageLengthLabel),
cell(pageLengthComboBox),
cell(reportLengthLabel),
cell(reportLengthComboBox)
).getComponent();
return FineUIUtils.wrapComponentWithTitle(lengthPane, i18nText("Fine-Design_Basic_Setting_Ruler_Units"));
}
private void createServerPane(JPanel advancePane) {
double p = TableLayout.PREFERRED;
double[] rowSize = {p};
double[] columnSize = {p, p, p};
JPanel serverPortPane = FRGUIPaneFactory.createTitledBorderPane(i18nText("Fine-Design_Basic_Web_Preview_Port_Setting"));
advancePane.add(serverPortPane);
private Component createServerPane() {
portEditor = new IntegerEditor();
portEditor.setPreferredSize(new Dimension(80, 20));
portEditor.setMinimumSize(new Dimension(80, 20));
UILabel notiJlabel = new UILabel(i18nText("Fine-Design_Basic_Work_After_Restart_Designer"));
UILabel serverPortLabel = new UILabel(i18nText("Fine-Design_Basic_Web_Preview_Port") + ":");
Component[][] portComponents = {
{serverPortLabel, portEditor, notiJlabel},
};
JPanel choosePortPane = TableLayoutHelper.createTableLayoutPane(portComponents, rowSize, columnSize);
serverPortPane.add(choosePortPane, BorderLayout.CENTER);
JPanel serverPane = row(10,
cell(serverPortLabel),
cell(portEditor),
cell(notiJlabel)
).getComponent();
return FineUIUtils.wrapComponentWithTitle(serverPane, i18nText("Fine-Design_Basic_Web_Preview_Port_Setting"));
}
private JPanel createMemoryPane() {
JPanel memoryPane = FRGUIPaneFactory.createTitledBorderPane(i18nText("Fine-Design_Basic_Preference_Caching_Template"));
private Component createMemoryPane() {
UILabel memoryLabel = new UILabel(i18nText("Fine-Design_Basic_Preference_Max_Caching_Template"));
UILabel memoryTipLabel = FRWidgetFactory.createLineWrapLabel(
i18nText("Fine-Design_Basic_Preference_Caching_Template_Tip"), MEMORY_TIP_LABEL_MAX_WIDTH);
memoryTipLabel.setBorder(BorderFactory.createEmptyBorder(0, CACHING_GAP, 0, 0));
cachingTemplateSpinner = new UISpinner(0, CACHING_MAX, 1, CACHING_DEFAULT);
JPanel memorySpace = new JPanel(FRGUIPaneFactory.createLeftZeroLayout());
memorySpace.add(memoryLabel);
memorySpace.add(cachingTemplateSpinner);
memorySpace.add(memoryTipLabel);
memoryPane.add(memorySpace);
return memoryPane;
JPanel memoryPane = row(5,
cell(memoryLabel),
cell(cachingTemplateSpinner),
cell(memoryTipLabel)
).getComponent();
return FineUIUtils.wrapComponentWithTitle(memoryPane, i18nText("Fine-Design_Basic_Preference_Caching_Template"));
}
@Override
@ -1021,7 +994,7 @@ public class PreferencePane extends BasicPane {
this.autoPushUpdateCheckBox.setSelected(designerEnvManager.isAutoPushUpdateEnabled());
}
this.embedServerLazyStartupCheckBox.setSelected(designerEnvManager.isEmbedServerLazyStartup());
// this.embedServerLazyStartupCheckBox.setSelected(designerEnvManager.isEmbedServerLazyStartup());
this.startWithEmptyFile.setSelected(designerEnvManager.isStartWithEmptyFile());
this.imageCompressPanelCheckBox.setSelected(designerEnvManager.isImageCompress());
@ -1290,7 +1263,7 @@ public class PreferencePane extends BasicPane {
@Override
public BasicDialog showWindow(Window window, DialogActionListener l) {
return showWindowWithCustomSize(window, l, new Dimension(BasicDialog.DEFAULT.width, this.getPreferredSize().height + OFFSET_HEIGHT));
return showWindowWithCustomSize(window, l, new Dimension(BasicDialog.DEFAULT.width, BasicDialog.DEFAULT.height + OFFSET_HEIGHT));
}
private void tryGc() {
@ -1486,7 +1459,7 @@ public class PreferencePane extends BasicPane {
*/
private UIButton initGcButton() {
UIButton gcButton = new UIButton(i18nText("Fine-Design_Vcs_Clean"));
gcButton.setPreferredSize(new Dimension(100, 15));
gcButton.setPreferredSize(FineUIScale.scale(new Dimension(100, 15)));
gcButton.setRoundBorder(true, Constants.LEFT);
return gcButton;
}

23
designer-base/src/main/java/com/fr/design/actions/file/RenameAction.java

@ -1,5 +1,9 @@
package com.fr.design.actions.file;
import com.fine.theme.icon.LazyIcon;
import com.fine.theme.utils.FineUIScale;
import com.fine.theme.utils.FineUIStyle;
import com.formdev.flatlaf.util.ScaledEmptyBorder;
import com.fr.base.BaseUtils;
import com.fr.chartx.TwoTuple;
import com.fr.design.DesignerEnvManager;
@ -62,7 +66,7 @@ public class RenameAction extends UpdateAction {
public RenameAction() {
this.setName(Toolkit.i18nText("Fine-Design_Basic_Rename"));
this.setSmallIcon("/com/fr/design/standard/rename/rename");
this.setSmallIcon(new LazyIcon("rename"));
}
@Override
@ -145,7 +149,7 @@ public class RenameAction extends UpdateAction {
"Fine-Design_Basic_Enter_New_Folder_Name" : "Fine-Design_Basic_Enter_New_File_Name")
);
newNameLabel.setHorizontalAlignment(SwingConstants.RIGHT);
newNameLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 10));
newNameLabel.setBorder(new ScaledEmptyBorder(0, 0, 0, 10));
//newNameLabel.setPreferredSize(new Dimension(118, 15));
// 重命名输入框
@ -168,10 +172,10 @@ public class RenameAction extends UpdateAction {
}
});
nameField.selectAll();
nameField.setPreferredSize(new Dimension(170, 20));
nameField.setPreferredSize(FineUIScale.scale(new Dimension(170, 20)));
JPanel topPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 5));
topPanel.setBorder(BorderFactory.createEmptyBorder(15, 15, 0, 15));
topPanel.setBorder(new ScaledEmptyBorder(15, 15, 0, 15));
topPanel.add(newNameLabel);
topPanel.add(nameField);
@ -179,18 +183,19 @@ public class RenameAction extends UpdateAction {
nameField.addKeyListener(keyListener);
// 重名提示
warnLabel = new UILabel();
warnLabel.setPreferredSize(new Dimension(300, 50));
warnLabel.setPreferredSize(FineUIScale.scale(new Dimension(300, 50)));
warnLabel.setHorizontalAlignment(SwingConstants.LEFT);
warnLabel.setVerticalAlignment(SwingConstants.TOP);
warnLabel.setForeground(Color.RED);
warnLabel.setVisible(false);
JPanel midPanel = new JPanel(new BorderLayout());
midPanel.setBorder(BorderFactory.createEmptyBorder(0, 15, 0, 15));
midPanel.setBorder(new ScaledEmptyBorder(0, 15, 0, 15));
midPanel.add(warnLabel, BorderLayout.WEST);
// 确认按钮
confirmButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Confirm"));
FineUIStyle.setStyle(confirmButton, FineUIStyle.STYLE_PRIMARY);
confirmButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
@ -210,8 +215,8 @@ public class RenameAction extends UpdateAction {
});
JPanel buttonsPane = new JPanel(new FlowLayout(FlowLayout.RIGHT, 10, 0));
buttonsPane.setBorder(BorderFactory.createEmptyBorder(10, 15, 10, 10));
JPanel buttonsPane = new JPanel(new FlowLayout(FlowLayout.RIGHT, 8, 0));
buttonsPane.setBorder(new ScaledEmptyBorder(0, 0, 10, 0));
buttonsPane.add(confirmButton);
buttonsPane.add(cancelButton);
@ -227,7 +232,7 @@ public class RenameAction extends UpdateAction {
),
BorderLayout.CENTER);
this.setSize(340, 200);
this.setSize(FineUIScale.scale(340), FineUIScale.scale(200));
this.setTitle(Toolkit.i18nText("Fine-Design_Basic_Rename"));
this.setResizable(false);
this.setIconImage(BaseUtils.readImage("/com/fr/base/images/oem/logo.png"));

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save