diff --git a/.travis.yml b/.travis.yml index 07debcee9..be978e9f4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,8 @@ jdk: branches: only: - master +before_install: +- chmod +x gradlew before_deploy: - git config --global user.email ${GITHUB_EMAIL} - git config --global user.name ${GITHUB_NAME} @@ -14,8 +16,7 @@ deploy: provider: releases api_key: secure: KxGIpE83MsgSdWNwCyqgIKJevZgLAef3hpBEVZjqZ09mA3JjQzWCbVFEfWpv8yRqe8ue7YF0aH7YoWuqOiE9q93Qsvv3GRtVcnZqZiGZbCZer1ShtqcjSseMvsw66dtHNcdK6onHna+OrCh2TQjxE2tKMf3CPCP9K2RI6dYOTyYUWmiOmiYQfcd2MEGSRXdnCGi8nf5oBZOYfHforRH3QYJXA7AxI+I9xaEWimFKs1c73sE1pypIGw5rlc+tiKuG8f5QoMeEOy+D30Qe3Vlre13RTi73r6GVt1ZoRpAwlNLEgjD393V1mxGd9wYNBMRKIZ/dfvIAN4m/jltVpgSyuCiUj3sjNs39HV8Jk0ki6RoSoAsjIyWHWfag946sk5wuBjnIZajlQhpGoc94ml8ujxOqP0npQT8azm3CwkAmBx0cxQ09Td9WPREk9BL4bWZrp5t50PsB9SZHPV2ET98QQH6+ArldONYWDTNZMJ2Lc0s6rFZoInq2px1srbR7Cxq2rNsVRp15UFvQp5xueONXz68/wFet6Gbm2ob8TGKm1bQOh5MRO/fq+fkrIIjoD6ztlRaO3xtePXlyEbnJmyxXOdA+Rd9WFXsT9gzjKtlxQjdHZNnI0YiEjR2qvHIWguAQtuV4pydWi8VtlBQ2gT37CpF4ApfC6jTfMsEwqZZ29YM= - file: - - HMCL/build/libs + file: HMCL/build/libs on: repo: huanghongxun/HMCL script: "bash ./gradlew clean build --stacktrace" diff --git a/HMCL/build.gradle b/HMCL/build.gradle index da4148a4a..d0a5f9325 100755 --- a/HMCL/build.gradle +++ b/HMCL/build.gradle @@ -41,7 +41,7 @@ if (buildnumber == null) def versionroot = System.getenv("VERSION_ROOT") if (versionroot == null) - versionroot = "2.7.3" + versionroot = "2.7.4" String mavenGroupId = 'HMCL' String mavenVersion = versionroot + '.' + buildnumber diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/Main.java b/HMCL/src/main/java/org/jackhuang/hmcl/Main.java index 1f78a0316..799ea9e1a 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/Main.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/Main.java @@ -24,7 +24,6 @@ import java.net.Authenticator; import java.net.PasswordAuthentication; import java.security.GeneralSecurityException; import java.security.cert.X509Certificate; -import java.text.ParseException; import java.util.Locale; import java.util.logging.Level; import java.util.logging.Logger; @@ -34,14 +33,11 @@ import javax.net.ssl.SSLContext; import javax.net.ssl.X509TrustManager; import javax.swing.ImageIcon; import javax.swing.RepaintManager; -import javax.swing.UIManager; -import javax.swing.UnsupportedLookAndFeelException; import org.jackhuang.hmcl.api.HMCLApi; import org.jackhuang.hmcl.api.HMCLog; import org.jackhuang.hmcl.api.ILogger; import org.jackhuang.hmcl.api.PluginManager; import org.jackhuang.hmcl.api.VersionNumber; -import org.jackhuang.hmcl.laf.HelloMinecraftLookAndFeel; import org.jackhuang.hmcl.setting.Settings; import org.jackhuang.hmcl.ui.LogWindow; import org.jackhuang.hmcl.ui.MainFrame; @@ -57,6 +53,7 @@ import org.jackhuang.hmcl.util.log.layout.DefaultLayout; import org.jackhuang.hmcl.util.sys.ProcessManager; import org.jackhuang.hmcl.util.ui.MyRepaintManager; import org.jackhuang.hmcl.util.upgrade.IUpgrader; +import org.jackhuang.hmcl.laf.BeautyEyeLNFHelper; /** * @@ -97,7 +94,7 @@ public final class Main implements Runnable { return "HMCL" + ' ' + LAUNCHER_VERSION; } - private static HelloMinecraftLookAndFeel LOOK_AND_FEEL; + //private static HelloMinecraftLookAndFeel LOOK_AND_FEEL; private static final Logger LOGGER = Logger.getLogger(Main.class.getName()); @@ -190,10 +187,9 @@ public final class Main implements Runnable { MessageBox.showLocalized("ui.message.open_jdk"); try { - LOOK_AND_FEEL = new HelloMinecraftLookAndFeel(Settings.getInstance().getTheme().settings); - UIManager.setLookAndFeel(LOOK_AND_FEEL); + BeautyEyeLNFHelper.launchBeautyEyeLNF(); RepaintManager.setCurrentManager(new MyRepaintManager()); - } catch (ParseException | UnsupportedLookAndFeelException ex) { + } catch (Exception ex) { HMCLog.warn("Failed to set look and feel...", ex); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameDownloadPanel.form b/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameDownloadPanel.form index 1b40154f7..5de046455 100755 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameDownloadPanel.form +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameDownloadPanel.form @@ -58,7 +58,7 @@ - + diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameDownloadPanel.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameDownloadPanel.java index 93d378f15..fb35ba573 100755 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameDownloadPanel.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameDownloadPanel.java @@ -19,6 +19,7 @@ package org.jackhuang.hmcl.ui; import org.jackhuang.hmcl.util.ui.Page; import javax.swing.table.DefaultTableModel; +import org.jackhuang.hmcl.api.ui.TopTabPage; import org.jackhuang.hmcl.core.download.MinecraftRemoteVersions; import org.jackhuang.hmcl.setting.Settings; import org.jackhuang.hmcl.util.C; @@ -64,7 +65,7 @@ public class GameDownloadPanel extends Page { } }); - lstDownloads.setModel(SwingUtils.makeDefaultTableModel(new String[]{C.i18n("install.version"), C.i18n("install.time"), C.i18n("install.type")},new Class[]{String.class, String.class, String.class}, new boolean[]{false, false, false})); + lstDownloads.setModel(SwingUtils.makeDefaultTableModel(new String[]{C.i18n("install.version"), C.i18n("install.release_time"), C.i18n("install.time"), C.i18n("install.type")},new Class[]{String.class, String.class, String.class, String.class}, new boolean[]{false, false, false, false})); lstDownloads.setToolTipText(""); lstDownloads.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); jScrollPane2.setViewportView(lstDownloads); @@ -110,7 +111,7 @@ public class GameDownloadPanel extends Page { DefaultTableModel model = SwingUtils.clearDefaultTable(lstDownloads); model.addRow(new Object[] { C.i18n("message.loading"), "", "" }); MinecraftRemoteVersions.refreshRomoteVersions(Settings.getLastProfile().service().getDownloadType()) - .reg((ver) -> model.addRow(new Object[] { ver.id, ver.time, + .reg((ver) -> model.addRow(new Object[] { ver.id, ver.releaseTime, ver.time, StrUtils.equalsOne(ver.type, "old_beta", "old_alpha", "release", "snapshot") ? C.i18n("versions." + ver.type) : ver.type })) .regDone(SwingUtils.invokeLater(() -> { lstDownloads.requestFocus(); @@ -138,8 +139,8 @@ public class GameDownloadPanel extends Page { boolean refreshedDownloads = false; @Override - public void onSelect() { - super.onSelect(); + public void onSelect(TopTabPage page) { + super.onSelect(page); if (!refreshedDownloads) { refreshedDownloads = true; refreshDownloads(); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameSettingsPanel.form b/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameSettingsPanel.form index 36be70935..f57dc3dc5 100755 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameSettingsPanel.form +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameSettingsPanel.form @@ -26,7 +26,7 @@ - + @@ -42,7 +42,7 @@ - + @@ -50,7 +50,7 @@ - + @@ -63,7 +63,7 @@ - + @@ -119,7 +119,7 @@ - + @@ -194,7 +194,7 @@ - + @@ -408,7 +408,7 @@ - + @@ -421,7 +421,7 @@ - + @@ -627,7 +627,7 @@ - + @@ -635,7 +635,7 @@ - + @@ -650,7 +650,7 @@ - + @@ -723,6 +723,9 @@ + + + diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameSettingsPanel.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameSettingsPanel.java index ae02ad4e6..820d6810f 100755 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameSettingsPanel.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameSettingsPanel.java @@ -322,7 +322,7 @@ public final class GameSettingsPanel extends RepaintPage implements DropTargetLi btnAddMod = new javax.swing.JButton(); btnRemoveMod = new javax.swing.JButton(); lblModInfo = new javax.swing.JLabel(); - pnlAutoInstall = new javax.swing.JPanel(); + pnlAutoInstall = new Page(); tabInstallers = new NewTabPane(); pnlTop = new javax.swing.JPanel(); pnlSelection = new javax.swing.JPanel(); @@ -479,7 +479,7 @@ public final class GameSettingsPanel extends RepaintPage implements DropTargetLi .addComponent(lblDimensionX) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(txtHeight, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 88, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 182, Short.MAX_VALUE) .addComponent(chkFullscreen)) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, pnlSettingsLayout.createSequentialGroup() .addComponent(txtMaxMemory) @@ -539,7 +539,7 @@ public final class GameSettingsPanel extends RepaintPage implements DropTargetLi .addComponent(lblDimensionX, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(lblDimension) .addComponent(txtWidth, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 39, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 51, Short.MAX_VALUE) .addGroup(pnlSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(btnDownloadAllAssets) .addComponent(btnCleanGame)) @@ -632,7 +632,7 @@ public final class GameSettingsPanel extends RepaintPage implements DropTargetLi .addComponent(lblJavaArgs)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(pnlAdvancedSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(txtJavaArgs, javax.swing.GroupLayout.DEFAULT_SIZE, 325, Short.MAX_VALUE) + .addComponent(txtJavaArgs, javax.swing.GroupLayout.DEFAULT_SIZE, 457, Short.MAX_VALUE) .addComponent(txtMinecraftArgs) .addComponent(txtPermSize, javax.swing.GroupLayout.Alignment.TRAILING))) .addGroup(pnlAdvancedSettingsLayout.createSequentialGroup() @@ -643,7 +643,7 @@ public final class GameSettingsPanel extends RepaintPage implements DropTargetLi .addComponent(chkNoJVMArgs) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(chkNoCommon) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 96, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 190, Short.MAX_VALUE) .addComponent(chkDontCheckGame)) .addGroup(pnlAdvancedSettingsLayout.createSequentialGroup() .addGroup(pnlAdvancedSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -728,13 +728,13 @@ public final class GameSettingsPanel extends RepaintPage implements DropTargetLi pnlModManagementContentLayout.setHorizontalGroup( pnlModManagementContentLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(pnlModManagementContentLayout.createSequentialGroup() - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 550, Short.MAX_VALUE) + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 644, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(pnlModManagementContentLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) .addComponent(btnRemoveMod, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(btnAddMod, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, pnlModManagementContentLayout.createSequentialGroup() - .addComponent(lblModInfo, javax.swing.GroupLayout.DEFAULT_SIZE, 646, Short.MAX_VALUE) + .addComponent(lblModInfo, javax.swing.GroupLayout.DEFAULT_SIZE, 751, Short.MAX_VALUE) .addContainerGap()) ); pnlModManagementContentLayout.setVerticalGroup( @@ -746,7 +746,7 @@ public final class GameSettingsPanel extends RepaintPage implements DropTargetLi .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(btnRemoveMod) .addGap(0, 0, Short.MAX_VALUE)) - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 259, Short.MAX_VALUE)) + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 271, Short.MAX_VALUE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(lblModInfo)) ); @@ -950,7 +950,7 @@ public final class GameSettingsPanel extends RepaintPage implements DropTargetLi .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(tabVersionEdit, javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(tabVersionEdit, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 766, Short.MAX_VALUE) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addGap(0, 0, Short.MAX_VALUE) .addComponent(btnMakeLaunchScript) @@ -963,12 +963,12 @@ public final class GameSettingsPanel extends RepaintPage implements DropTargetLi .addGroup(layout.createSequentialGroup() .addContainerGap() .addComponent(btnIncludeMinecraft) - .addContainerGap(577, Short.MAX_VALUE))) + .addContainerGap(677, Short.MAX_VALUE))) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addComponent(pnlTop, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(pnlTop, javax.swing.GroupLayout.PREFERRED_SIZE, 70, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(tabVersionEdit) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) @@ -979,7 +979,7 @@ public final class GameSettingsPanel extends RepaintPage implements DropTargetLi .addContainerGap()) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addContainerGap(400, Short.MAX_VALUE) + .addContainerGap(403, Short.MAX_VALUE) .addComponent(btnIncludeMinecraft) .addContainerGap())) ); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/InstallerPanel.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/InstallerPanel.java index 3796d1b18..61eb575ba 100755 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/InstallerPanel.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/InstallerPanel.java @@ -21,6 +21,7 @@ import org.jackhuang.hmcl.util.ui.Page; import java.util.List; import javax.swing.SwingUtilities; import javax.swing.table.DefaultTableModel; +import org.jackhuang.hmcl.api.ui.TopTabPage; import org.jackhuang.hmcl.util.C; import org.jackhuang.hmcl.setting.Settings; import org.jackhuang.hmcl.core.install.InstallerType; @@ -164,7 +165,8 @@ public class InstallerPanel extends Page { boolean refreshed = false; @Override - public void onSelect() { + public void onSelect(TopTabPage page) { + super.onSelect(page); if (!refreshed) { TaskWindow.factory().execute(refreshVersionsTask()); refreshed = true; diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/LaunchingUIDaemon.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/LaunchingUIDaemon.java index 185fed309..3438e3198 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/LaunchingUIDaemon.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/LaunchingUIDaemon.java @@ -37,6 +37,7 @@ import org.jackhuang.hmcl.util.C; import org.jackhuang.hmcl.util.MessageBox; import org.jackhuang.hmcl.api.func.Consumer; import org.jackhuang.hmcl.api.HMCLog; +import org.jackhuang.hmcl.util.DefaultPlugin; import org.jackhuang.hmcl.util.sys.FileUtils; import org.jackhuang.hmcl.util.sys.ProcessMonitor; import org.jackhuang.hmcl.util.net.WebFrame; @@ -111,6 +112,7 @@ public class LaunchingUIDaemon { void runGame(Profile profile) { MainFrame.INSTANCE.showMessage(C.i18n("ui.message.launching")); profile.launcher().genLaunchCode(value -> { + DefaultPlugin.INSTANCE.saveAuthenticatorConfig(); ((HMCLGameLauncher.GameLauncherTag) value.getTag()).state = 1; }, MainFrame.INSTANCE::failed, Settings.getInstance().getAuthenticator().getPassword()); } @@ -118,6 +120,7 @@ public class LaunchingUIDaemon { void makeLaunchScript(Profile profile) { MainFrame.INSTANCE.showMessage(C.i18n("ui.message.launching")); profile.launcher().genLaunchCode(value -> { + DefaultPlugin.INSTANCE.saveAuthenticatorConfig(); ((HMCLGameLauncher.GameLauncherTag) value.getTag()).state = 2; }, MainFrame.INSTANCE::failed, Settings.getInstance().getAuthenticator().getPassword()); } @@ -154,9 +157,8 @@ public class LaunchingUIDaemon { if (v != LauncherVisibility.KEEP && !LogWindow.INSTANCE.isVisible()) { HMCLog.log("Launcher will exit now."); System.exit(0); - } else { + } else HMCLog.log("Launcher will not exit now."); - } } private static final Consumer LAUNCH_SCRIPT_FINISHER = event -> { diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/MainFrame.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/MainFrame.java index 7da386b2e..c24ec0c92 100755 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/MainFrame.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/MainFrame.java @@ -40,6 +40,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; +import java.util.Map; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.BoxLayout; @@ -49,6 +50,7 @@ import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.SwingUtilities; +import javax.swing.UIManager; import org.jackhuang.hmcl.api.HMCLApi; import org.jackhuang.hmcl.Main; import org.jackhuang.hmcl.api.PluginManager; @@ -165,7 +167,6 @@ public final class MainFrame extends DraggableFrame implements IRepaint { private void initComponents() { setLayout(null); - initBorderColor(Settings.getInstance().getTheme()); realPanel = new JPanel(); realPanel.setLayout(null); @@ -255,6 +256,8 @@ public final class MainFrame extends DraggableFrame implements IRepaint { realPanel.setBounds(1, 0, 800, 511); add(realPanel); + + reloadColor(Settings.getInstance().getTheme()); } private transient final ActionListener tabListener = e -> MainFrame.this.selectTab(e.getActionCommand()); @@ -277,11 +280,12 @@ public final class MainFrame extends DraggableFrame implements IRepaint { public void selectTab(String tabName) { int chosen = -1; - TopTabPage onCreate = null, onSelect = null; + TopTabPage onCreate = null, onSelect = null, lastPage = null; for (int i = 0; i < tabHeader.size(); i++) if (tabName.equalsIgnoreCase(tabHeader.get(i).getActionCommand())) { if (!tabContent.get(i).isCreated()) { onCreate = tabContent.get(i); + onCreate.setId(i); tabWrapper[i].add(tabContent.get(i)); } else if (tabContent.get(i).isSelected()) continue; @@ -290,8 +294,10 @@ public final class MainFrame extends DraggableFrame implements IRepaint { } if (chosen != -1) { for (int i = 0; i < tabHeader.size(); i++) - if (i != chosen && tabContent.get(i) != null && tabContent.get(i).isSelected()) - tabContent.get(i).onLeave(); + if (i != chosen && tabContent.get(i) != null && tabContent.get(i).isSelected()) { + lastPage = tabContent.get(i); + lastPage.onLeave(); + } for (int i = 0; i < tabHeader.size(); i++) if (i == chosen) { for (int j = 0; j < tabHeader.size(); j++) @@ -305,7 +311,7 @@ public final class MainFrame extends DraggableFrame implements IRepaint { if (onCreate != null) onCreate.onCreate(); if (onSelect != null) - onSelect.onSelect(); + onSelect.onSelect(lastPage); } } @@ -382,13 +388,18 @@ public final class MainFrame extends DraggableFrame implements IRepaint { Color borderColor; Color borderColorDarker; - private void initBorderColor(Theme t) { - borderColor = GraphicsUtils.getWebColor(t.settings.get("Customized.MainFrame.background")); - borderColorDarker = GraphicsUtils.getWebColor(t.settings.get("Customized.MainFrame.selected_background")); + private void initBorderColor() { + borderColor = UIManager.getColor("Customized.MainFrame.background"); + borderColorDarker = UIManager.getColor("Customized.MainFrame.selected_background"); } public void reloadColor(Theme t) { - initBorderColor(t); + for (Map.Entry entry : t.settings.entrySet()) { + if (entry.getValue().startsWith("#")) + UIManager.put(entry.getKey(), GraphicsUtils.getWebColor(entry.getValue())); + } + + initBorderColor(); if (border != null) border.setColor(borderColor); header.setBackground(borderColor); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/MainPagePanel.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/MainPagePanel.java index 1e7643a28..0750285ba 100755 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/MainPagePanel.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/MainPagePanel.java @@ -45,7 +45,7 @@ import org.jackhuang.hmcl.core.version.MinecraftVersion; import org.jackhuang.hmcl.setting.Settings; import org.jackhuang.hmcl.core.mod.ModpackManager; import org.jackhuang.hmcl.ui.modpack.ModpackWizard; -import org.jackhuang.hmcl.laf.ConstomButton; +import org.jackhuang.hmcl.laf.button.CustomButton; import org.jackhuang.hmcl.api.func.Consumer; import org.jackhuang.hmcl.util.sys.FileUtils; import org.jackhuang.hmcl.util.task.TaskWindow; @@ -54,6 +54,7 @@ import org.jackhuang.hmcl.util.ui.JSystemFileChooser; import org.jackhuang.hmcl.util.ui.SwingUtils; import org.jackhuang.hmcl.util.ui.wizard.api.WizardDisplayer; import org.jackhuang.hmcl.api.auth.IAuthenticator; +import org.jackhuang.hmcl.laf.button.CustomButtonUI; /** * @@ -67,13 +68,11 @@ public class MainPagePanel extends Page { void initGui() { initComponents(); - animationEnabled = false; - pnlButtons = new javax.swing.JPanel(); pnlButtons.setLayout(null); int w = 150, h = 50; - btnRun = new ConstomButton(); + btnRun = new CustomButton(); btnRun.setBounds(0, 0, w, h); Font font = btnRun.getFont(); Font newFont = new Font(font.getName(), font.getStyle(), 15); @@ -82,6 +81,7 @@ public class MainPagePanel extends Page { btnRun.setText(C.i18n("ui.button.run")); btnRun.setFont(newFont); btnRun.addActionListener(e -> MainFrame.INSTANCE.daemon.runGame(Settings.getLastProfile())); + btnRun.setUI(new CustomButtonUI()); pnlRoot.add(pnlButtons); pnlButtons.setBounds(0, 0, w, h); @@ -434,7 +434,7 @@ public class MainPagePanel extends Page { boolean preparingAuth = true; private boolean isLoading = false; private javax.swing.JPanel pnlButtons; - private ConstomButton btnRun; + private CustomButton btnRun; private static final int DEFAULT_WIDTH = 800, DEFAULT_HEIGHT = 480; // diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/NewTabPane.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/NewTabPane.java index e4aa60f2d..8f21f7231 100755 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/NewTabPane.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/NewTabPane.java @@ -40,10 +40,20 @@ public class NewTabPane extends JTabbedPane implements ChangeListener { if (initializing) return; for (int i = 0; i < getComponentCount(); ++i) - if (getSelectedIndex() != i && getComponent(i) instanceof TopTabPage) - ((TopTabPage) getComponent(i)).onLeave(); - if (getSelectedComponent() instanceof TopTabPage) - ((TopTabPage) getSelectedComponent()).onSelect(); + if (getComponent(i) instanceof TopTabPage) { + TopTabPage comp = (TopTabPage) getComponent(i); + comp.setId(i); + if (getSelectedIndex() != i) + ((TopTabPage) getComponent(i)).onLeave(); + } + if (getSelectedComponent() instanceof TopTabPage) { + if (page == null && getComponentCount() > 0 && getComponent(0) instanceof TopTabPage) + page = (TopTabPage) getComponent(0); + ((TopTabPage) getSelectedComponent()).onSelect(page); + page = (TopTabPage) getSelectedComponent(); + } } + TopTabPage page = null; + } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/util/DefaultPlugin.java b/HMCL/src/main/java/org/jackhuang/hmcl/util/DefaultPlugin.java index 9f8dd7555..9127e3633 100755 --- a/HMCL/src/main/java/org/jackhuang/hmcl/util/DefaultPlugin.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/util/DefaultPlugin.java @@ -37,8 +37,10 @@ import org.jackhuang.hmcl.laf.LAFTheme; * @author huangyuhui */ public class DefaultPlugin implements IPlugin { + public static DefaultPlugin INSTANCE; public DefaultPlugin() { + INSTANCE = this; for (Theme t : LAFTheme.THEMES) Theme.THEMES.put(t.getId(), t); } @@ -52,11 +54,8 @@ public class DefaultPlugin implements IPlugin { auths.add(new YggdrasilAuthenticator(clientToken)); try { - Runtime.getRuntime().addShutdownHook(new Thread(() -> { - for (IAuthenticator i : auths) - Settings.getInstance().setAuthenticatorConfig(i.id(), i.onSaveSettings()); - })); - } catch(IllegalStateException ignore) { // Shutdown in progress + Runtime.getRuntime().addShutdownHook(new Thread(this::saveAuthenticatorConfig)); + } catch (IllegalStateException ignore) { // Shutdown in progress } for (IAuthenticator i : auths) { i.onLoadSettings(Settings.getInstance().getAuthenticatorConfig(i.id())); @@ -64,6 +63,11 @@ public class DefaultPlugin implements IPlugin { } } + public void saveAuthenticatorConfig() { + for (IAuthenticator i : auths) + Settings.getInstance().setAuthenticatorConfig(i.id(), i.onSaveSettings()); + } + @Override public void onAddTab(JFrame frame, AddTabCallback callback) { callback.addTab(new MainPagePanel(), "main", C.i18n("launcher.title.main")); diff --git a/HMCLAPI/src/main/java/org/jackhuang/hmcl/api/ui/TopTabPage.java b/HMCLAPI/src/main/java/org/jackhuang/hmcl/api/ui/TopTabPage.java index f443e6034..3d9c7c50b 100644 --- a/HMCLAPI/src/main/java/org/jackhuang/hmcl/api/ui/TopTabPage.java +++ b/HMCLAPI/src/main/java/org/jackhuang/hmcl/api/ui/TopTabPage.java @@ -29,9 +29,13 @@ public abstract class TopTabPage extends JPanel { public abstract boolean isCreated(); - public abstract void onSelect(); + public abstract void onSelect(TopTabPage lastSelectedPage); public abstract boolean isSelected(); public abstract void onLeave(); + + public abstract int getId(); + + public abstract void setId(int id); } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/sys/OS.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/sys/OS.java index 925acd962..eed9b44e7 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/sys/OS.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/sys/OS.java @@ -17,15 +17,10 @@ */ package org.jackhuang.hmcl.util.sys; -import com.sun.management.OperatingSystemMXBean; -import java.io.BufferedReader; import java.io.File; import java.io.IOException; -import java.io.InputStreamReader; import java.lang.management.ManagementFactory; import java.util.Locale; -import java.util.StringTokenizer; -import org.jackhuang.hmcl.util.code.Charsets; import org.jackhuang.hmcl.api.HMCLog; /** @@ -68,56 +63,20 @@ public enum OS { */ public static long getTotalPhysicalMemory() { try { - if (os() == LINUX) - return memoryInfoForLinux()[0] * 1024; - else { - OperatingSystemMXBean o = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean(); - return o.getTotalPhysicalMemorySize(); - } + return ReflectionHelper.get(ManagementFactory.getOperatingSystemMXBean(), "getTotalPhysicalMemorySize"); } catch (Throwable t) { HMCLog.warn("Failed to get total physical memory size", t); - return -1; + return 1024; } } public static int getSuggestedMemorySize() { long total = getTotalPhysicalMemory(); - if (total == -1) - return 1024; int memory = (int) (total / 1024 / 1024) / 4; memory = Math.round((float) memory / 128.0f) * 128; return memory; } - public static long[] memoryInfoForLinux() throws IOException { - File file = new File("/proc/meminfo"); - try (BufferedReader br = new BufferedReader(new InputStreamReader(FileUtils.openInputStream(file), Charsets.UTF_8))) { - long[] result = new long[4]; - String str; - StringTokenizer token; - while ((str = br.readLine()) != null) { - token = new StringTokenizer(str); - if (!token.hasMoreTokens()) - continue; - - str = token.nextToken(); - if (!token.hasMoreTokens()) - continue; - - if (str.equalsIgnoreCase("MemTotal:")) - result[0] = Long.parseLong(token.nextToken()); - else if (str.equalsIgnoreCase("MemFree:")) - result[1] = Long.parseLong(token.nextToken()); - else if (str.equalsIgnoreCase("SwapTotal:")) - result[2] = Long.parseLong(token.nextToken()); - else if (str.equalsIgnoreCase("SwapFree:")) - result[3] = Long.parseLong(token.nextToken()); - } - - return result; - } - } - public static String getLinuxReleaseVersion() throws IOException { return FileUtils.read(new File("/etc/issue")); } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/sys/ProcessThread.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/sys/ProcessThread.java index de4723738..bcb8bf494 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/sys/ProcessThread.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/sys/ProcessThread.java @@ -34,7 +34,7 @@ import org.jackhuang.hmcl.api.IProcess; public class ProcessThread extends Thread { IProcess p; - + public final EventHandler> printlnEvent = new EventHandler<>(); public final EventHandler> stopEvent = new EventHandler<>(); diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/sys/ReflectionHelper.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/sys/ReflectionHelper.java new file mode 100644 index 000000000..461fb01f8 --- /dev/null +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/sys/ReflectionHelper.java @@ -0,0 +1,66 @@ +/* + * Hello Minecraft! Launcher. + * Copyright (C) 2013 huangyuhui + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see {http://www.gnu.org/licenses/}. + */ +package org.jackhuang.hmcl.util.sys; + +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.security.AccessController; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import sun.misc.Unsafe; + +/** + * + * @author huang + */ +public class ReflectionHelper { + + private static Unsafe unsafe = null; + private static long objectFieldOffset; + + static { + try { + unsafe = AccessController.doPrivileged(new PrivilegedExceptionAction () { + @Override + public Unsafe run() throws Exception { + Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); + theUnsafe.setAccessible(true); + return (Unsafe) theUnsafe.get(null); + } + }); + Field overrideField = AccessibleObject.class.getDeclaredField("override"); + objectFieldOffset = unsafe.objectFieldOffset(overrideField); + } catch (Throwable ex) { + } + } + + private static void setAccessible(AccessibleObject obj) { + unsafe.putBoolean(obj, objectFieldOffset, true); + } + + public static T get(Object obj, String fieldName) { + try { + Method method = obj.getClass().getDeclaredMethod(fieldName); + setAccessible(method); + return (T) method.invoke(obj); + } catch (Throwable ex) { + return null; + } + } +} diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/ui/Page.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/ui/Page.java index fd12f16c2..4469c5c71 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/ui/Page.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/ui/Page.java @@ -32,6 +32,17 @@ import javax.swing.Timer; public class Page extends TopTabPage { boolean selected = false; + public int id; + + @Override + public int getId() { + return id; + } + + @Override + public void setId(int id) { + this.id = id; + } @Override public boolean isSelected() { @@ -39,9 +50,11 @@ public class Page extends TopTabPage { } @Override - public void onSelect() { - if (!selected) + public void onSelect(TopTabPage lastSelectedPage) { + if (!selected) { + lastPage = (Page) lastSelectedPage; animate(); + } selected = true; } @@ -65,13 +78,13 @@ public class Page extends TopTabPage { // ------------------- // Animation // ------------------- - private static final int ANIMATION_LENGTH = 10; + private static final int ANIMATION_LENGTH = 5; public Page() { timer = new Timer(1, (e) -> { SwingUtilities.invokeLater(() -> { Page.this.repaint(); - offsetX += 0.15; + offsetX += 0.14; if (offsetX >= ANIMATION_LENGTH) { timer.stop(); Page.this.repaint(); @@ -80,7 +93,7 @@ public class Page extends TopTabPage { }); } - BufferedImage cache = null; + BufferedImage cache = null, lastCache = null; @Override public void paint(Graphics g) { @@ -88,33 +101,50 @@ public class Page extends TopTabPage { super.paint(g); return; } - double pgs = 1 - Math.sin(Math.PI / 2 / ANIMATION_LENGTH * offsetX); + Graphics2D gg = (Graphics2D) g; + double pgs = Math.sin(Math.PI / 2 / ANIMATION_LENGTH * offsetX); if (Math.abs(ANIMATION_LENGTH - offsetX) < 0.1) { super.paint(g); return; } if (offsetX == 0) { - cache = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB); - Graphics2D g2d = cache.createGraphics(); - if (isOpaque()) { - g2d.setColor(getBackground()); - g2d.fillRect(0, 0, getWidth(), getHeight()); - } - super.paint(g2d); - g2d.dispose(); + cache = cacheImpl(this); + if (lastPage != null) + lastCache = cacheImpl(lastPage); } - if (pgs > 1) - pgs = 1; - if (pgs < 0) - pgs = 0; - Graphics2D gg = (Graphics2D) g; - gg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, (float) (1 - pgs))); - g.drawImage(cache, (int) (pgs * 50), 0, this); + int ori = lastPage != null ? (lastPage.getId() < getId() ? 1 : -1) : 1; + if (pgs >= 0.5) + animateImpl(gg, cache, (int) (((1 - (pgs - 0.5) * 2)) * totalOffset * ori), (float) ((pgs - 0.5) * 2)); + else + animateImpl(gg, lastCache, (int) (((- pgs * 2)) * totalOffset * ori), (float) (1 - pgs * 2)); } - double offsetX = ANIMATION_LENGTH; + BufferedImage cacheImpl(Page page) { + BufferedImage image = new BufferedImage(page.getWidth(), page.getHeight(), BufferedImage.TYPE_INT_ARGB); + Graphics2D g2d = image.createGraphics(); + if (isOpaque()) { + g2d.setColor(page.getBackground()); + g2d.fillRect(0, 0, page.getWidth(), page.getHeight()); + } + page.superPaint(g2d); + g2d.dispose(); + return image; + } + void animateImpl(Graphics2D g, BufferedImage image, int left, float alpha) { + if (image == null) + return; + g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha)); + g.drawImage(image, left, 0, this); + } + + protected void superPaint(Graphics2D g) { + super.paint(g); + } + + double offsetX = ANIMATION_LENGTH, totalOffset = 20; + Page lastPage; Timer timer; protected boolean animationEnabled = true; diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/BeautyEyeLNFHelper.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/BeautyEyeLNFHelper.java new file mode 100644 index 000000000..1b071290a --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/BeautyEyeLNFHelper.java @@ -0,0 +1,391 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * BeautyEyeLNFHelper.java at 2015-2-1 20:25:40, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf; + +import java.awt.Color; + +import javax.swing.BorderFactory; +import javax.swing.LookAndFeel; +import javax.swing.UIManager; +import javax.swing.border.Border; + +import org.jackhuang.hmcl.laf.widget.border.BEShadowBorder; +import org.jackhuang.hmcl.laf.widget.border.BEShadowBorder3; +import org.jackhuang.hmcl.laf.widget.border.PlainGrayBorder; + +/** + *

+ * BeautyEye Swing外观实现方案 - L&F核心辅助类.
+ *

+ * 项目托管地址:https://github.com/JackJiang2011/beautyeye + * + * @author Jack Jiang(jb2011@163.com), 2012-05 + * @version 1.0 + */ +public class BeautyEyeLNFHelper { + + /** + * 开关量:用于开启/关闭BeautyEye LNF的调试信息输出. + *

+ * 默认false,即不开启调试信息输出. + * + * @since 3.2 + */ + public static boolean debug = false; + /** + * 开关量:用于开启/关闭当窗口(包括JFrame、JDialog)处于非活动 状态(inactivity)时的半透明视觉效果. + *

+ * 默认true,即表示默认开启半透明效果. + * + * @since 3.2 + */ + public static boolean translucencyAtFrameInactive = true; + + /** + * BeautyEye LNF 的窗口边框样式. + *

+ * 默认值:运行在java1.6.0_u10及以上版本时使用 + * {@link FrameBorderStyle#translucencyAppleLike}, + * 运行在java1.5版本时使用{@link FrameBorderStyle#generalNoTranslucencyShadow}. + * + *

+ * 注意:如需设置本参数,请确保它在UIManager.setLookAndFeel前被设置,否则将不会起效哦. + * + * @see FrameBorderStyle + */ + public static FrameBorderStyle frameBorderStyle = FrameBorderStyle.translucencyAppleLike; + + /** + * 颜色全局变量:正常情况下的窗口文本颜色. + *

+ * 你可设置本变量,也可直接通过{@code UIManager.put("activeCaptionText",new ColorUIResource(c))}和 + * {@code UIManager.put("inactiveCaptionText",new ColorUIResource(c))}来实现窗口文本颜色的改变. + *

+ * 窗体不活动(inactivite)时的颜色将据此自动计算出来,无需额外设置. 默认是黑色(new Color(0,0,0)). + */ + public static Color activeCaptionTextColor = new Color(0, 0, 0);//黑色 + + /** + * 颜色全局变量:多数组件的背景色. + *

+ * 你可设置本变量,也可直接通过各自的UIManager属性来改变它们. + *

+ * 默认是浅灰色(new Color(250,250,250)). + * + * @since 3.2 + */ + public static Color commonBackgroundColor = new Color(250, 250, 250);//240,240,240); //248,248,248);//255,255,255);// + /** + * 颜色全局变量:多数组件的前景色(文本颜色). + *

+ * 你可设置本变量,也可直接通过各自的UIManager属性来改变它们. + *

+ * 默认是深灰色(new Color(60,60,60)). + * + * @since 3.2 + */ + public static Color commonForegroundColor = new Color(60, 60, 60);//102,102,102); + /** + * 颜色全局变量:某些组件的焦点边框颜色. 当前主要用于按钮等焦点边框的绘制颜色. + *

+ * 你可设置本变量,也可直接通过各自的UIManager属性来改变它们. + *

+ * 默认是浅灰色(new Color(250,250,250)). + * + * @since 3.2 + */ + public static Color commonFocusedBorderColor = new Color(162, 162, 162); + /** + * 颜色全局变量:某些组件被禁用时的文本颜色. 当前主要用于菜单项中. + *

+ * 你可设置本变量,也可直接通过各自的UIManager属性来改变它们. + *

+ * 默认是浅灰色(new Color(172,168,153)). + * + * @since 3.2 + */ + public static Color commonDisabledForegroundColor = new Color(172, 168, 153); + /** + * 颜色全局变量:多数组件中文本被选中时的背景色.当前主要用于各文本组件等. + *

+ * 你可设置本变量,也可直接通过各自的UIManager属性来改变它们. + *

+ * 默认是深灰色(new Color(2,129,216)). + * + * @since 3.2 + */ + public static Color commonSelectionBackgroundColor = new Color(2, 129, 216);//78,155,193));//58,135,173));//235,217,147));//new Color(255,237,167)); + /** + * 颜色全局变量:多数组件中文本被选中时的前景色(文本颜色).当前主要用于各文本组件、菜单项等. + *

+ * 你可设置本变量,也可直接通过各自的UIManager属性来改变它们. + *

+ * 默认是深灰色(new Color(255,255,255)). + * + * @since 3.2 + */ + public static Color commonSelectionForegroundColor = new Color(255, 255, 255); + + /** + * 开关量:用于默认设置或不设置窗口(Frame及其子类)的设置此窗体的最大化边界. + *

+ * 此开关量是它是为了解决这样一个问题 :
+ * 当不使用操作系统的窗口装饰(即使用完全自定义的窗口标题、边框)时,在windows上最 大化窗口时将会全屏显示从而覆盖了下方的任务栏(task + * bar),这个问题 据说自2002年 就已存在,SUN一直未解决或者根本不认为是bug。目前的解决方案是当本变量是true时则 + * 默认为每一个窗体设置最大化边界,否则保持系统默认。不过这样设置并非完美方案:一旦 设置了最大边界,则此后无论Task Bar再怎么调 + * 整大小,比如被hide了,则窗体永远是设 置时的最大边界,不过目前也只能这么折中解决了,因为窗体最大化事件处理并非L&F中实现 + * ,暂未找到其它更好的方法。 + *

+ * 默认true,即表示默认开启此设置. + * + * @since 3.2 + * @see javax.swing.JFrame#setMaximizedBounds(java.awt.Rectangle) + */ + public static boolean setMaximizedBoundForFrame = true; + + /** + * BeautyEye LNF的外观实现核心方法. + *

+ * 本方法可以直接从外部调用,这意味着BeautyEye LNF的外观核心实现无需特定于LookAndFeel的实例. + *

+ * 也就是说任意外观都可应用本方法所作的外观实现(并保证跨平台),以使之可灵活应用. + * + * @see org.jb2011.lnf.beautyeye.titlepane.__UI__#uiImpl() + * @see org.jb2011.lnf.beautyeye.tab.__UI__#uiImpl() + * @see org.jb2011.lnf.beautyeye.button.__UI__#uiImpl() + * @see org.jb2011.lnf.beautyeye.separator.__UI__#uiImpl() + * @see org.jb2011.lnf.beautyeye.scroll.__UI__#uiImpl() + * @see org.jb2011.lnf.beautyeye.table.__UI__#uiImpl() + * @see org.jb2011.lnf.beautyeye.textcoms.__UI__#uiImpl() + * @see org.jb2011.lnf.beautyeye.popup.__UI__#uiImpl() + * @see org.jb2011.lnf.beautyeye.toolbar.__UI__#uiImpl() + * @see org.jb2011.lnf.beautyeye.menu.__UI__#uiImpl() + * @see org.jb2011.lnf.beautyeye.internalframe.__UI__#uiImpl() + * @see org.jb2011.lnf.beautyeye.progress.__UI__#uiImpl() + * @see org.jb2011.lnf.beautyeye.radio$cb_btn.__UI__#uiImpl() + * @see org.jb2011.lnf.beautyeye.combox.__UI__#uiImpl() + * @see org.jb2011.lnf.beautyeye.slider.__UI__#uiImpl() + * @see org.jb2011.lnf.beautyeye.tree.__UI__#uiImpl() + * @see org.jb2011.lnf.beautyeye.split.__UI__#uiImpl() + * @see org.jb2011.lnf.beautyeye.spinner.__UI__#uiImpl() + * @see org.jb2011.lnf.beautyeye.list.__UI__#uiImpl() + * @see org.jb2011.lnf.beautyeye.filechooser.__UI__#uiImpl_win() + */ + protected static void implLNF() { + //自定义窗口的L&F实现 + org.jackhuang.hmcl.laf.titlepane.__UI__.uiImpl(); + //自定义JTabbedPane的L&F实现 + org.jackhuang.hmcl.laf.tab.__UI__.uiImpl(); + //自定义按钮的L&F实现 + org.jackhuang.hmcl.laf.button.__UI__.uiImpl(); + //各种杂七杂八的设置 + org.jackhuang.hmcl.laf.separator.__UI__.uiImpl(); + //自定义滚动条的L&F实现 + org.jackhuang.hmcl.laf.scroll.__UI__.uiImpl(); + //自定义表格头的L&F实现 + org.jackhuang.hmcl.laf.table.__UI__.uiImpl(); + //自定义文本组件的L&F实现 + org.jackhuang.hmcl.laf.textcoms.__UI__.uiImpl(); + //自定义弹出组件(包括toolTip组件和弹出菜单等)的L&F实现 + org.jackhuang.hmcl.laf.popup.__UI__.uiImpl(); + //自定义ToggleButton的L&F实现 + org.jackhuang.hmcl.laf.toolbar.__UI__.uiImpl(); + //自定义菜单项的L&F实现 + org.jackhuang.hmcl.laf.menu.__UI__.uiImpl(); + //自定义DesktopPane及内部窗体的L&F实现 + org.jackhuang.hmcl.laf.internalframe.__UI__.uiImpl(); + //自定义进度条的L&F实现 + org.jackhuang.hmcl.laf.progress.__UI__.uiImpl(); + //自定义单选按钮的L&F实现 + org.jackhuang.hmcl.laf.radio$cb_btn.__UI__.uiImpl(); + //自定义下拉框的L&F实现 + org.jackhuang.hmcl.laf.combox.__UI__.uiImpl(); + //自定义JSlider的L&F实现 + org.jackhuang.hmcl.laf.slider.__UI__.uiImpl(); + //自定义Jtree的L&F实现 + org.jackhuang.hmcl.laf.tree.__UI__.uiImpl(); + //自定义JSplitPane的L&F实现 + org.jackhuang.hmcl.laf.split.__UI__.uiImpl(); + //自定义JSpinner的L&F实现 + org.jackhuang.hmcl.laf.spinner.__UI__.uiImpl(); + //自定义JList的L&F实现 + org.jackhuang.hmcl.laf.list.__UI__.uiImpl(); + //自定义JFileChooser的L&F实现 + org.jackhuang.hmcl.laf.filechooser.__UI__.uiImpl(); + } + + /** + * Gets the beauty eye lnf platform. + * + * @return {@code new BeautyEyeLookAndFeel()} + */ + public static LookAndFeel getBeautyEyeLNFPlatform() { + return new BeautyEyeLookAndFeel(); + } + + /** + * 实施BeautyEye外观.开发者使用BeautyEye L&F时应首选本方法. + *

+ * 本方法会据操作系统类型不同,来决定主类是使用BeautyEyeLookAndFeelWin还是BeautyEyeLookAndFeelWin. + * 使用BeautyEye外观时推荐使用本方法来设置外观.之所以有平台不同主类不同的区分,是为了 + * 在Windows上平台上能更好的使用与操作系统相同的字体等设置. + * + * @throws Exception {@link UIManager#setLookAndFeel(String)}过程中出现的任何异常 + * @see #getBeautyEyeLNFStrWindowsPlatform() + * @see #getBeautyEyeLNFPlatform() + * @see org.jb2011.lnf.beautyeye.utils.Platform + */ + public static void launchBeautyEyeLNF() throws Exception { + System.setProperty("sun.java2d.noddraw", "true"); + UIManager.setLookAndFeel(getBeautyEyeLNFPlatform()); + } + + /** + * 开发者无需关注本方法. + *

+ * true表示当前正在使用的窗口边框是不透明的,否则表示透明. 本方法目前作为BERootPaneUI中设置窗口是否透明的开关使用. + *

+ * #### 官方API中存的Bug: ####
+ * 在jdk1.6.0_u33下+win7平台下(其它版本是否也有这情况尚未完全验证),JFrame窗口 + * 被设置成透明后,该窗口内所有文本都会被反走样(不管你有没有要求反走样),真悲具。 + * 这应该是官方AWTUtilities.setWindowOpaque(..)bug导致的,1.7.0_u6同样存在该问题, + * 使用BeautyEye时,遇到这样的问题只能自行使用本方法中指定的不透明边框才行(这样 + * BERootPaneUI类的设置窗口透明的代码就不用执行,也就不用触发该bug了),但JDialog 不受此bug影响,诡异! + * + * @return true, if successful + * @since 3.2 + */ + public static boolean isFrameBorderOpaque() { + return frameBorderStyle == FrameBorderStyle.osLookAndFeelDecorated + || frameBorderStyle == FrameBorderStyle.generalNoTranslucencyShadow; + } + + /** + * 开发者无需关注本方法. + *

+ * 根据设置的frameBorderStyle来返回正确的窗口边框. + * + * @return + * 当frameBorderStyle=={@link FrameBorderStyle#defaultLookAndFeelDecorated} + * 时返回无意义的BorderFactory.createEmptyBorder(),否则返回指定边框对象 + */ + public static Border getFrameBorder() { + switch (frameBorderStyle) { + case osLookAndFeelDecorated: + return BorderFactory.createEmptyBorder(); + case translucencyAppleLike: + return new BEShadowBorder3(); + case translucencySmallShadow: + return new BEShadowBorder(); + case generalNoTranslucencyShadow: + default: + return new PlainGrayBorder(); + } + } +// /** +// * 开发者无需关注本方法. +// *

+// * 根据设置的frameBorderStyle来返回正确的窗口边框边角的拖动区大小. +// *

+// * 重要说明:本方法中的边框类型及其对应的边框类必须与方法 {@link #__getFrameBorder()} +// * 完全一致! +// * +// * @return 当frameBorderStyle=={@link FrameBorderStyle#defaultLookAndFeelDecorated} +// * 时返回null,否则返回指定边框对象 +// */ +// public static int __getFrameBorder_CORNER_DRAG_WIDTH() +// { +// switch(frameBorderStyle) +// { +// case osLookAndFeelDecorated: +// return 16; +// case translucencyAppleLike: +// return BEShadowBorder3.CORNER_DRAG_WIDTH(); +// case translucencySmallShadow: +// return new BEShadowBorder().CORNER_DRAG_WIDTH(); +// case generalNoTranslucencyShadow: +// default: +// return new PlainGrayBorder().CORNER_DRAG_WIDTH(); +// } +// } +// /** +// * 开发者无需关注本方法. +// *

+// * 根据设置的frameBorderStyle来返回正确的窗口边框拖动区大小. +// *

+// * 重要说明:本方法中的边框类型及其对应的边框类必须与方法 {@link #__getFrameBorder()} +// * 完全一致! +// * +// * @return 当frameBorderStyle=={@link FrameBorderStyle#defaultLookAndFeelDecorated} +// * 时返回null,否则返回指定边框对象 +// */ +// public static int __getFrameBorder_BORDER_DRAG_THICKNESS() +// { +// switch(frameBorderStyle) +// { +// case osLookAndFeelDecorated: +// return 5; +// case translucencyAppleLike: +// return BEShadowBorder3.BORDER_DRAG_THICKNESS(); +// case translucencySmallShadow: +// return new BEShadowBorder().BORDER_DRAG_THICKNESS(); +// case generalNoTranslucencyShadow: +// default: +// return new PlainGrayBorder().BORDER_DRAG_THICKNESS(); +// } +// } + + /** + * BeautyEye LNF 的窗口边框样式. + */ + public enum FrameBorderStyle { + + /** + * 使用本地系统的窗口装饰样式(本样式将能带来最佳性能,使用操作系统默认窗口样式). + */ + osLookAndFeelDecorated, + /** + * 使用类似于MacOSX的强烈立体感半透明阴影边框(本样式性能尚可,视觉效果最佳). + */ + translucencyAppleLike, + /** + * 使用不太强烈立体感半透明阴影边框(本样式性能尚可,视觉效果较soft). + */ + translucencySmallShadow, + /** + * 使用不透明的普通边框(这是本LNF在Java1.5版默认使用的样式,因为java1.5不支持窗口透明) + */ + generalNoTranslucencyShadow + } + + /** + * 开发者暂时无需关注此接口. + *

+ * 实现了此接口的UI类意味着用户可以通过自行设置诸如border等,来 取消默认的NainePatch图实现的边框填充、背景填充等,具体设置哪 + * 些东西可以取消默认的NinePatch图填充的方式详见各自的类注释。 + */ + public interface __UseParentPaintSurported { + + /** + * 是否使用父类的绘制实现方法,true表示是. + *

+ * 因为在BE LNF中,进度条和背景都是使用N9图,比如没法通过设置JProgressBar的背景色和前景 + * 色来控制进度条的颜色,本方法的目的就是当用户设置了进度条的Background或Foreground 时告之本实现类不使用BE + * LNF中默认的N9图填充绘制而改用父类中的方法(父类中的方法 + * 就可以支持颜色的设置罗,只是丑点,但总归是能适应用户的需求场景要求,其实用户完全可以 通过JProgressBar.setUI(new + * MetalProgressBar())方式来自定义进度的UI哦). + * + * @return true, if is use parent paint + */ + boolean isUseParentPaint(); + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/BeautyEyeLookAndFeel.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/BeautyEyeLookAndFeel.java new file mode 100644 index 000000000..7ac4af719 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/BeautyEyeLookAndFeel.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * BeautyEyeLookAndFeel.java at 2015-2-1 20:25:40, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf; + +import java.awt.Font; +import java.util.Enumeration; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.plaf.FontUIResource; +import javax.swing.plaf.metal.MetalLookAndFeel; + +/** + *

+ * BeautyEye Swing外观实现方案 - 跨平台通用外观实现主类.
+ *

+ * 本主题主类仅供跨平台时使用,它可用于Java支持的所有操作系统. + * + * 如果要继承BasicLookAndFeel实现跨平台lnf 则还需要做更多的工作,目前 + * 跨平台时干脆继承MetalLookAndFeel以便站在巨人的肩膀上,节省一些工作量 + * + * @author Jack Jiang(jb2011@163.com) + * @version 1.0 + */ +public class BeautyEyeLookAndFeel extends MetalLookAndFeel { + private static void initGlobalFont(Font font) { + FontUIResource fontRes = new FontUIResource(font); + for (Enumeration keys = UIManager.getDefaults().keys(); + keys.hasMoreElements(); ) { + Object key = keys.nextElement(); + Object value = UIManager.get(key); + if (value instanceof FontUIResource) { + UIManager.put(key, fontRes); + } + } + } + + public BeautyEyeLookAndFeel() { + super(); + +// //本属性仅对windows平台有效?! -> Jack Jiang最终证实没效果!!!!!!!!!!! +// UIManager.put("Application.useSystemFontSettings", Boolean.TRUE); + //取消Metal LNF中默认的粗体字 + UIManager.put("swing.boldMetal", Boolean.FALSE); + //此项如是true,则将会为TabbedPane的内容面板填充天蓝色背景 + UIManager.put("TabbedPane.contentOpaque", Boolean.FALSE); + //此项如是true,则将会为TabbedPane的标签填充天蓝色背景 + UIManager.put("TabbedPane.tabsOpaque", Boolean.FALSE); + initGlobalFont(new Font("微软雅黑", Font.PLAIN, 12)); + BeautyEyeLNFHelper.implLNF(); + } + + @Override + public String getName() { + return "BeautyEye"; + } + + @Override + public String getID() { + return "BeautyEye"; + } + + @Override + public String getDescription() { + return "BeautyEye L&F developed by Jack Jiang(jb2011@163.com)."; + } + + /** + * Gets the supports window decorations. + * + * @return the supports window decorations {@inheritDoc} + */ + @Override + public boolean getSupportsWindowDecorations() { + return true; + } + + @Override + public boolean isNativeLookAndFeel() { + return false; + } + + @Override + public boolean isSupportedLookAndFeel() { + return true; + } + + @Override + protected void initComponentDefaults(UIDefaults table) { + super.initComponentDefaults(table); + initOtherResourceBundle(table); + } + + /** + * Initialize the defaults table with the name of the other ResourceBundle + * used for getting localized defaults. + */ + protected void initOtherResourceBundle(UIDefaults table) { + table.addResourceBundle("org.jb2011.lnf.beautyeye.resources.beautyeye"); + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/HelloMinecraftLookAndFeel.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/HelloMinecraftLookAndFeel.java deleted file mode 100755 index 2abfb8e63..000000000 --- a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/HelloMinecraftLookAndFeel.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright 2013 huangyuhui - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. - */ -package org.jackhuang.hmcl.laf; - -import java.awt.Color; -import java.awt.image.BufferedImage; -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.text.ParseException; -import java.util.Map; -import javax.imageio.ImageIO; -import javax.swing.UIDefaults; -import javax.swing.plaf.synth.SynthLookAndFeel; -import org.jackhuang.hmcl.api.HMCLog; -import org.jackhuang.hmcl.util.sys.IOUtils; -import org.jackhuang.hmcl.util.ui.GraphicsUtils; - -/** - * - * @author huangyuhui - */ -public class HelloMinecraftLookAndFeel extends SynthLookAndFeel { - - public static final Map DEFAULT_SETTINGS = LAFTheme.BLUE.settings; - - /** - * Creates a new instance of NimbusLookAndFeel - * - * @throws java.text.ParseException error parsing the xml, it must not - * happen. - */ - public HelloMinecraftLookAndFeel() throws ParseException { - this(DEFAULT_SETTINGS); - } - - public HelloMinecraftLookAndFeel(Map settings) throws ParseException { - try { - try (InputStream is = HelloMinecraftLookAndFeel.class.getResourceAsStream("/org/jackhuang/hmcl/laf/synth.xml")) { - String s = IOUtils.toString(is, "UTF-8"); - for (Map.Entry ss : settings.entrySet()) - s = s.replace("${" + ss.getKey() + "}", ss.getValue()); - load(new ByteArrayInputStream(s.getBytes("UTF-8")), HelloMinecraftLookAndFeel.class); - } - } catch (Throwable ex) { - HMCLog.err("This fucking exception should not happen. Retry backup solution.", ex); - try { - try (InputStream is = HelloMinecraftLookAndFeel.class.getResourceAsStream("/org/jackhuang/hmcl/laf/synth_backup.xml")) { - load(is, HelloMinecraftLookAndFeel.class); - } - } catch (Throwable e) { - HMCLog.err("User fault", e); - } - } - } - - UIDefaults uiDefaults; - - @Override - public UIDefaults getDefaults() { - if (uiDefaults != null) - return uiDefaults; - uiDefaults = super.getDefaults(); - //ui.put("Table.selectionForeground", new ColorUIResource(Color.red)); - //ui.put("Table.focusCellForeground", new ColorUIResource(Color.red)); - //ui.put("TabbedPane.isTabRollover", false); - //ui.put("ComboBox.selectionBackground", new ColorUIResource(Color.red)); - //ui.put("List.background", new ColorUIResource(Color.red)); - //uiDefaults.put("TabbedPane.selectedLabelShift", 0); - uiDefaults.put("Table.selectionBackground", Color.red); - return uiDefaults; - } - - /** - * Return a short string that identifies this look and feel. - * - * @return a short string identifying this look and feel. - */ - @Override - public String getName() { - return "HelloMinecraftLookAndFeel"; - } - - /** - * Return a string that identifies this look and feel. - * - * @return a short string identifying this look and feel. - */ - @Override - public String getID() { - return "HelloMinecraftLookAndFeel"; - } - - /** - * Returns a textual description of this look and feel. - * - * @return textual description of this look and feel. - */ - @Override - public String getDescription() { - return "HelloMinecraftLookAndFeel"; - } - - /** - * Load an image using ImageIO from resource in - * org.jdesktop.swingx.plaf.nimbus.images. Catches and prints all Exceptions - * so that it can safely be used in a static context. - * - * @param imgName The name of the image to load, eg. "border.png" - * - * @return The loaded image - */ - public static BufferedImage loadImage(String imgName) { - try { - return ImageIO.read(GraphicsUtils.class.getClassLoader().getResource("org/jackhuang/hmcl/laf/images/" + imgName)); - } catch (Exception e) { - System.err.println("Error loading image \"org/jackhuang/hmcl/laf/images/" + imgName + "\""); - e.printStackTrace(); - } - return null; - } -} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/Icon9Factory.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/Icon9Factory.java new file mode 100644 index 000000000..25b07bbd9 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/Icon9Factory.java @@ -0,0 +1,180 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.jackhuang.hmcl.laf.utils; + +import java.util.HashMap; +import org.jb2011.ninepatch4j.NinePatch; + +/** + * + * @author huang + */ +public class Icon9Factory extends RawCache { + + /** + * 相对路径根(默认是相对于本类的相对物理路径). + */ + public final static String IMGS_ROOT = "imgs/np"; + + @Override + protected NinePatch getResource(String relativePath, Class baseClass) { + return NinePatchHelper.createNinePatch(baseClass.getResource(relativePath), false); + } + + public Icon9Factory(String namespace) { + ns = namespace; + init(); + } + + String ns; + + /** + * Gets the raw. + * + * @param relativePath the relative path + * @return the raw + */ + public NinePatch getRaw(String relativePath) { + return getRaw(relativePath, this.getClass()); + } + + HashMap icons = new HashMap<>(); + + protected void put(String namespace, String key, String filename) { + if (!ns.equals(namespace)) + return; + icons.put(namespace + ":" + key, getRaw(IMGS_ROOT + "/" + filename + ".9.png")); + } + + public NinePatch get(String key) { + return icons.get(ns + ":" + key); + } + + public NinePatch get(String key, String state) { + return Icon9Factory.this.get(concat(key, state)); + } + + public NinePatch getWithEnabled(String key, boolean enabled) { + return get(key, enabled ? "" : "disabled"); + } + + public NinePatch getWithHorizontal(String key, boolean isHorizontal) { + return get(key, isHorizontal ? "" : "vertical"); + } + + public NinePatch getWithButtonState(String key, boolean enabled, boolean pressed) { + return get(key, (enabled ? (pressed ? "pressed" : "normal") : "disabled")); + } + + public NinePatch getWithScrollState(String key, boolean pressed, boolean over) { + return get(key, (pressed ? "pressed" : (over ? "rollover" : ""))); + } + + public NinePatch getWithComboState(String key, boolean enabled, boolean pressed, boolean over) { + return get(key, (enabled ? (pressed ? "pressed" : (over ? "rollover" : "normal")) : "disabled")); + } + + private String concat(String a, String b) { + if (a.isEmpty() && b.isEmpty()) + return ""; + else if (a.isEmpty()) + return b; + else if (b.isEmpty()) + return a; + else + return a + "_" + b; + } + + private void init() { + put("slider_track", "", "slider_track2"); + put("slider_track", "vertical", "slider_track2_v"); + put("slider_track", "disabled", "slider_track2_dark"); + put("slider_track", "vertical_disabled", "slider_track2_v_dark"); + put("slider_track", "foreground", "slider_track2_forgroud"); + put("slider_track", "foreground_disabled", "slider_track2_forgroud_disable"); + put("slider_track", "vertical_foreground", "slider_track2_forgroud_v"); + put("slider_track", "vertical_foreground_disabled", "slider_track2_forgroud_v_disable"); + + put("button_arrow", "normal", "button_arrow"); + put("button_arrow", "pressed", "button_arrow_pressed"); + put("button_arrow", "rollover", "button_arrow_rollover"); + put("button_arrow", "disabled", "button_arrow_disable"); + + put("progress_bar", "bg", "progress_bar_bg"); + put("progress_bar", "bg_vertical", "progress_bar_bg_v"); + put("progress_bar", "green", "progress_bar_green"); + put("progress_bar", "blue_vertical", "progress_bar_grean_v"); + + put("split_touch", "bg1", "split_touch_bg1"); + + put("list", "selected_icon_bg", "list_cell_selected_bg2"); + + put("spinner", "", "spinner1_bg"); + put("spinner", "button_up", "spinner1_btn_up_bg"); + put("spinner", "button_down", "spinner1_btn_down_bg"); + put("spinner", "button_up_pressed", "spinner1_btn_up_pressed_bg"); + put("spinner", "button_down_pressed", "spinner1_btn_down_pressed_bg"); + put("spinner", "disabled", "spinner1_disable_bg"); + + put("button", "normal", "btn_special_default"); + put("button", "disabled", "btn_special_disabled"); + put("button", "pressed", "btn_general_pressed"); + put("button", "rollover", "btn_general_rover"); + + put("toggle_button", "selected", "toggle_button_selected"); + put("toggle_button", "rollover", "toggle_button_rover"); + + put("scroll_bar", "vertical", "scroll_bar_v"); + put("scroll_bar", "vertical_rollover", "scroll_bar_rover_v"); + put("scroll_bar", "vertical_pressed", "scroll_bar_pressed_v"); + put("scroll_bar", "horizontal", "scroll_bar_h"); + put("scroll_bar", "horizontal_rollover", "scroll_bar_rover_h"); + put("scroll_bar", "horizontal_pressed", "scroll_bar_rover_h"); + put("scroll_bar", "arrow_bottom", "arrow_toBottom"); + put("scroll_bar", "arrow_top", "arrow_toTop"); + put("scroll_bar", "arrow_left", "arrow_toLeft"); + put("scroll_bar", "arrow_right", "arrow_toRight"); + put("scroll_bar", "arrow_bottom_rollover", "arrow_toBottom_rover"); + put("scroll_bar", "arrow_top_rollover", "arrow_toTop_rover"); + put("scroll_bar", "arrow_left_rollover", "arrow_toLeft_rover"); + put("scroll_bar", "arrow_right_rollover", "arrow_toRight_rover"); + put("scroll_bar", "scroll_pane_border", "scroll_pane_bg1"); + + put("popup", "popup", "shadow_bg_popup"); + put("popup", "tooltip", "shadow_bg_tooltip2"); + + put("table", "scroll_border", "table_scrollborder1"); + put("table", "header_cell", "table_header_bg1"); + put("table", "header_cell_separator", "table_header_separator1"); + + put("text", "normal", "bg_login_text_normal"); + put("text", "pressed", "bg_login_text_pressed"); + put("text", "disabled", "bg_login_text_disable"); + put("text", "white", "null_white_bg"); + + put("toolbar", "north", "toolbar_bg1"); + put("toolbar", "south", "toolbar_bg1_SOUTH"); + put("toolbar", "west", "toolbar_bg1_WEST"); + put("toolbar", "east", "toolbar_bg1_EAST"); + + put("menu", "selected", "menu_bg"); + + put("widget", "panel", "query_item_bg_2"); + put("widget", "hint_light_blue", "hint_bg_lightblue"); + put("widget", "hint_light_gray", "hint_bg_lightblue_gray"); + put("widget", "tips", "tips_bg"); + put("widget", "orange_balloon", "orange_baloon1"); + put("widget", "border_shadow1", "shadow1"); + put("widget", "border_shadow2", "shadow2"); + put("widget", "border_plain_gray", "plain_gray1"); + put("widget", "border_shadow3", "frame_shadow_border4"); + + put("combo", "normal", "combo_normal"); + put("combo", "disabled", "combo_disabled"); + put("combo", "rollover", "combo_over"); + put("combo", "pressed", "combo_pressed"); + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/IconFactory.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/IconFactory.java new file mode 100644 index 000000000..9283111f7 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/IconFactory.java @@ -0,0 +1,150 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.jackhuang.hmcl.laf.utils; + +import java.util.HashMap; +import javax.swing.ImageIcon; + +/** + * + * @author huang + */ +public class IconFactory extends RawCache { + + /** + * 相对路径根(默认是相对于本类的相对物理路径). + */ + public final static String IMGS_ROOT = "imgs"; + + public IconFactory(String namespace) { + ns = namespace; + init(); + } + + String ns; + + @Override + protected ImageIcon getResource(String relativePath, Class baseClass) { + return new ImageIcon(baseClass.getResource(relativePath)); + } + + /** + * Gets the image. + * + * @param relativePath the relative path + * @return the image + */ + protected ImageIcon getImage(String relativePath) { + return getRaw(relativePath, IconFactory.class); + } + + HashMap icons = new HashMap<>(); + + protected void put(String namespace, String key, String filename) { + if (!ns.equals(namespace)) + return; + icons.put(namespace + ":" + key, getImage(IMGS_ROOT + "/" + filename + ".png")); + } + + public ImageIcon get(String... states) { + String s = ""; + for (String k : states) + s = concat(s, k); + return icons.get(ns + ":" + s); + } + + public ImageIcon getWithButtonState(String key, boolean enabled, boolean pressed) { + return get(key, (enabled ? (pressed ? "pressed" : "normal") : "disabled")); + } + + private String concat(String a, String b) { + if (a.isEmpty() && b.isEmpty()) + return ""; + else if (a.isEmpty()) + return b; + else if (b.isEmpty()) + return a; + else + return a + "_" + b; + } + + void init() { + put("menu", "radio_check", "RadioButtonMenuItemCheckIcon2"); + put("menu", "radio_normal", "RadioButtonMenuItemCheckIcon_none"); + put("menu", "check_selected", "checkbox_menuitem_selected_normal"); + put("menu", "check_none", "checkbox_menuitem_none"); + + put("internal_frame", "close", "frame_close_over"); + put("internal_frame", "min", "frame_windowize_over"); + put("internal_frame", "max", "frame_maximize_over"); + put("internal_frame", "iconify", "frame_minimize_over"); + put("internal_frame", "icon", "ifi1"); + + put("radio", "disabled", "radio_btn_disabled_selected"); + put("radio", "normal", "radio_btn_selected"); + put("radio", "pressed", "radio_btn_selected_pressed"); + put("radio", "over", "radio_btn_selected_over"); + put("radio", "unchecked_disabled", "radio_btn_disabled_normal"); + put("radio", "unchecked_normal", "radio_btn"); + put("radio", "unchecked_pressed", "radio_btn_pressed"); + put("radio", "unchecked_over", "radio_btn_over"); + + put("check", "disabled", "checkbox_on_disabled"); + put("check", "normal", "checkbox_on"); + put("check", "pressed", "checkbox_on_pressed"); + put("check", "over", "checkbox_on_over"); + put("check", "unchecked_disabled", "checkbox_off_disabled"); + put("check", "unchecked_normal", "checkbox_off"); + put("check", "unchecked_pressed", "checkbox_off_pressed"); + put("check", "unchecked_over", "checkbox_off_over"); + + put("menu_radio", "checked", "RadioButtonMenuItemCheckIcon2"); + put("menu_radio", "normal", "RadioButtonMenuItemCheckIcon_none"); + put("menu_check", "checked", "checkbox_menuitem_selected_normal"); + put("menu_check", "normal", "checkbox_menuitem_none"); + + put("table", "descending_sort", "desc2"); + put("table", "ascending_sort", "asc2"); + + put("tree", "open", "treeDefaultOpen1"); + put("tree", "closed", "treeDefaultClosed1"); + put("tree", "leaf", "leaf1"); + put("tree", "expanded", "a"); + put("tree", "collapsed", "b"); + + put("option_pane", "warn", "warn"); + put("option_pane", "error", "error"); + put("option_pane", "info", "info"); + put("option_pane", "question", "question"); + + put("slider", "", "slider_tick1"); + put("slider", "disabled", "slider_tick1_dark"); + put("slider", "vertical", "slider_tick1_v"); + put("slider", "vertical_disabled", "slider_tick1_v_dark"); + put("slider", "notriangle", "slider_tick1_notrangle"); + put("slider", "notriangle_disabled", "slider_tick1_notrangle_dark"); + put("slider", "notriangle_vertical", "slider_tick1_notrangle_v"); + put("slider", "notriangle_vertical_disabled", "slider_tick1_notrangle_v_dark"); + + put("frame", "close", "frame_close_normal"); + put("frame", "close_over", "frame_close_rover"); + put("frame", "close_pressed", "frame_close_pressed"); + put("frame", "min", "frame_maxwin"); + put("frame", "min_over", "frame_maxwin_rover"); + put("frame", "min_pressed", "frame_maxwin_pressed"); + put("frame", "max", "frame_max_normal"); + put("frame", "max_over", "frame_max_rover"); + put("frame", "max_pressed", "frame_max_pressed"); + put("frame", "iconify", "frame_min_normal"); + put("frame", "iconify_over", "frame_min_rover"); + put("frame", "iconify_pressed", "frame_min_pressed"); + put("frame", "icon", "default_frame_icon"); + put("frame", "setup", "frame_setup_normal"); + put("frame", "title_active", "head_bg"); + put("frame", "title_inactive", "head_inactive"); + } + +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/LAFTheme.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/LAFTheme.java index 5430fdec9..cda967bfb 100755 --- a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/LAFTheme.java +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/LAFTheme.java @@ -31,6 +31,9 @@ public final class LAFTheme { put("Customized.TabbedPaneTab.selected_foreground", "#106CA3"); put("Customized.ComboBox.selected_background", "#A0D8F0"); put("Customized.MainFrame.background", "#106CA3"); + put("TabbedPane.selectedForeground", "#106CA3"); + put("TextField.focused", "#106CA3"); + put("MenuItem.selectionBackground", "#106CA3"); put("Customized.MainFrame.selected_background", "#0C5E91"); put("Customized.MainFrame.background_image", "background.jpg"); } @@ -40,6 +43,9 @@ public final class LAFTheme { put("Customized.TabbedPaneTab.selected_foreground", "#1ABC9C"); put("Customized.ComboBox.selected_background", "#1ABC9C"); put("Customized.MainFrame.background", "#1ABC9C"); + put("TabbedPane.selectedForeground", "#1ABC9C"); + put("TextField.focused", "#1ABC9C"); + put("MenuItem.selectionBackground", "#1ABC9C"); put("Customized.MainFrame.selected_background", "#16A085"); put("Customized.MainFrame.background_image", "background.jpg"); } @@ -49,6 +55,9 @@ public final class LAFTheme { put("Customized.TabbedPaneTab.selected_foreground", "#9B59B6"); put("Customized.ComboBox.selected_background", "#9B59B6"); put("Customized.MainFrame.background", "#9B59B6"); + put("TabbedPane.selectedForeground", "#9B59B6"); + put("TextField.focused", "#9B59B6"); + put("MenuItem.selectionBackground", "#9B59B6"); put("Customized.MainFrame.selected_background", "#8E44AD"); put("Customized.MainFrame.background_image", "background.jpg"); } @@ -58,6 +67,9 @@ public final class LAFTheme { put("Customized.TabbedPaneTab.selected_foreground", "#34495E"); put("Customized.ComboBox.selected_background", "#34495E"); put("Customized.MainFrame.background", "#34495E"); + put("TabbedPane.selectedForeground", "#34495E"); + put("TextField.focused", "#34495E"); + put("MenuItem.selectionBackground", "#34495E"); put("Customized.MainFrame.selected_background", "#2C3E50"); put("Customized.MainFrame.background_image", "background.jpg"); } @@ -67,6 +79,9 @@ public final class LAFTheme { put("Customized.TabbedPaneTab.selected_foreground", "#E67E22"); put("Customized.ComboBox.selected_background", "#F39C12"); put("Customized.MainFrame.background", "#E67E22"); + put("TabbedPane.selectedForeground", "#E67E22"); + put("TextField.focused", "#E67E22"); + put("MenuItem.selectionBackground", "#E67E22"); put("Customized.MainFrame.selected_background", "#D35400"); put("Customized.MainFrame.background_image", "background.jpg"); } @@ -76,6 +91,9 @@ public final class LAFTheme { put("Customized.TabbedPaneTab.selected_foreground", "#E74C3C"); put("Customized.ComboBox.selected_background", "#E74C3C"); put("Customized.MainFrame.background", "#E74C3C"); + put("TabbedPane.selectedForeground", "#E74C3C"); + put("TextField.focused", "#E74C3C"); + put("MenuItem.selectionBackground", "#E74C3C"); put("Customized.MainFrame.selected_background", "#C0392B"); put("Customized.MainFrame.background_image", "background.jpg"); } diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/MySwingUtilities2.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/MySwingUtilities2.java new file mode 100644 index 000000000..d24ab69b5 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/MySwingUtilities2.java @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * MySwingUtilities2.java at 2015-2-1 20:25:40, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.utils; + +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.Toolkit; + +import javax.swing.JComponent; + +/** + * 本类中的方法一一对应于SUN未公开的类SwingUtilities2中的方法. + * + * 部分代码摘自JDK 1.5. + * + * @author Jack Jiang(jb2011@163.com) + * @author huangyuhui + */ +public class MySwingUtilities2 { + + /** + * Returns the FontMetrics for the current Font of the passed in Graphics. + * This method is used when a Graphics is available, typically when + * painting. If a Graphics is not available the JComponent method of the + * same name should be used. + *

+ * Callers should pass in a non-null JComponent, the exception to this is if + * a JComponent is not readily available at the time of painting. + *

+ * This does not necessarily return the FontMetrics from the Graphics. + * + * @param c JComponent requesting FontMetrics, may be null + * @param g Graphics Graphics + * @return the font metrics + */ + public static FontMetrics getFontMetrics(JComponent c, Graphics g) { + return getFontMetrics(c, g, g.getFont()); + } + + /** + * Returns the FontMetrics for the specified Font. This method is used when + * a Graphics is available, typically when painting. If a Graphics is not + * available the JComponent method of the same name should be used. + *

+ * Callers should pass in a non-null JComonent, the exception to this is if + * a JComponent is not readily available at the time of painting. + *

+ * This does not necessarily return the FontMetrics from the Graphics. + * + * @param c Graphics Graphics + * @param g the g + * @param font Font to get FontMetrics for + * @return the font metrics + */ + public static FontMetrics getFontMetrics(JComponent c, Graphics g, + Font font) { + if (c != null) + // Note: We assume that we're using the FontMetrics + // from the widget to layout out text, otherwise we can get + // mismatches when printing. + return c.getFontMetrics(font); + return Toolkit.getDefaultToolkit().getFontMetrics(font); + } + + /** + * Returns the width of the passed in String. + * + * @param c JComponent that will display the string, may be null + * @param fm FontMetrics used to measure the String width + * @param string String to get the width of + * @return the int + */ + public static int stringWidth(JComponent c, FontMetrics fm, String string) { + return fm.stringWidth(string); + } + + /** + * Draws the string at the specified location. + * + * @param c JComponent that will display the string, may be null + * @param g Graphics to draw the text to + * @param text String to display + * @param x X coordinate to draw the text at + * @param y Y coordinate to draw the text at + */ + public static void drawString(JComponent c, Graphics g, String text, + int x, int y) { + Graphics2D g2d = (Graphics2D) g; + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g2d.drawString(text, x, y); + } + + /** + * Draws the string at the specified location underlining the specified + * character. + * + * @param c JComponent that will display the string, may be null + * @param g Graphics to draw the text to + * @param text String to display + * @param underlinedIndex Index of a character in the string to underline + * @param x X coordinate to draw the text at + * @param y Y coordinate to draw the text at + */ + public static void drawStringUnderlineCharAt(JComponent c, Graphics g, + String text, int underlinedIndex, int x, int y) { + drawString(c, g, text, x, y); + if (underlinedIndex >= 0 && underlinedIndex < text.length()) { + // PENDING: this needs to change. + FontMetrics fm = g.getFontMetrics(); + int underlineRectX = x + stringWidth(c, + fm, text.substring(0, underlinedIndex)); + int underlineRectY = y; + int underlineRectWidth = fm.charWidth(text. + charAt(underlinedIndex)); + int underlineRectHeight = 1; + g.fillRect(underlineRectX, underlineRectY + 1, + underlineRectWidth, underlineRectHeight); + } + } + + /** + * Clips the passed in String to the space provided. + * + * @param c JComponent that will display the string, may be null + * @param fm FontMetrics used to measure the String width + * @param string String to display + * @param availTextWidth Amount of space that the string can be drawn in + * @return Clipped string that can fit in the provided space. + */ + public static String clipStringIfNecessary(JComponent c, FontMetrics fm, + String string, int availTextWidth) { + if ((string == null) || (string.equals(""))) + return ""; + int textWidth = stringWidth(c, fm, string); + if (textWidth > availTextWidth) + return clipString(c, fm, string, availTextWidth); + return string; + } + + /** + * Clips the passed in String to the space provided. NOTE: this assumes the + * string does not fit in the available space. + * + * @param c JComponent that will display the string, may be null + * @param fm FontMetrics used to measure the String width + * @param string String to display + * @param availTextWidth Amount of space that the string can be drawn in + * @return Clipped string that can fit in the provided space. + */ + public static String clipString(JComponent c, FontMetrics fm, + String string, int availTextWidth) { + // c may be null here. + String clipString = "..."; + int width = stringWidth(c, fm, clipString); + // NOTE: This does NOT work for surrogate pairs and other fun + // stuff + int nChars = 0; + for (int max = string.length(); nChars < max; nChars++) { + width += fm.charWidth(string.charAt(nChars)); + if (width > availTextWidth) + break; + } + string = string.substring(0, nChars) + clipString; + return string; + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/NinePatchHelper.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/NinePatchHelper.java new file mode 100644 index 000000000..6c9f15421 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/NinePatchHelper.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * NinePatchHelper.java at 2015-2-1 20:25:36, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.utils; + +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; + +import org.jb2011.ninepatch4j.NinePatch; + +/** + * NinePatch图辅助工厂类. + * + * @author Jack Jiang(jb2011@163.com), 2011-12-22 + * @version 1.0 + */ +public class NinePatchHelper { + + /** + * Creates the nine patch. + * + * @param fileUrl the file url + * @param convert the convert + * @return the nine patch + * @see NinePatch#load(URL, boolean) + */ + public static NinePatch createNinePatch(URL fileUrl, boolean convert) { + try { + return NinePatch.load(fileUrl, convert); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + /** + * Creates the nine patch. + * + * @param stream the stream + * @param is9Patch the is9 patch + * @param convert the convert + * @return the nine patch + * @throws IOException Signals that an I/O exception has occurred. + * @see NinePatch#load(InputStream, boolean, boolean) + */ + public static NinePatch createNinePatch(InputStream stream, boolean is9Patch, boolean convert) throws IOException { + return NinePatch.load(stream, is9Patch, convert); + } + + /** + * Creates the nine patch. + * + * @param image the image + * @param is9Patch the is9 patch + * @param convert the convert + * @return the nine patch + * @see NinePatch#load(BufferedImage, boolean, boolean) + */ + public static NinePatch createNinePatch(BufferedImage image, boolean is9Patch, boolean convert) { + return NinePatch.load(image, is9Patch, convert); + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/UI.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/UI.java new file mode 100644 index 000000000..711350ec4 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/UI.java @@ -0,0 +1,66 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.jackhuang.hmcl.laf.utils; + +import java.awt.Color; +import javax.swing.BorderFactory; +import javax.swing.UIManager; +import javax.swing.border.Border; +import javax.swing.plaf.BorderUIResource; +import javax.swing.plaf.ColorUIResource; +import javax.swing.plaf.DimensionUIResource; +import javax.swing.plaf.InsetsUIResource; + +/** + * + * @author huang + */ +public class UI { + + protected static void put(String key, int i) { + UIManager.put(key, i); + } + + protected static void put(String key, boolean b) { + UIManager.put(key, b); + } + + protected static void put(String key, Color c) { + UIManager.put(key, new ColorUIResource(c)); + } + + protected static void put(String key, Border b) { + UIManager.put(key, new BorderUIResource(b)); + } + + protected static void putDim(String key, int w, int h) { + UIManager.put(key, new DimensionUIResource(h, h)); + } + + protected static void putInsets(String key, int top, int left, int bottom, int right) { + UIManager.put(key, new InsetsUIResource(top, left, bottom, right)); + } + + protected static void putBorder(String key) { + UIManager.put(key, BorderFactory.createEmptyBorder()); + } + + protected static void putBorder(String key, int top, int left, int bottom, int right) { + UIManager.put(key, new BorderUIResource(BorderFactory.createEmptyBorder(top, left, bottom, right))); + } + + protected static void putColor(String key, int r, int g, int b) { + put(key, new Color(r, g, b)); + } + + protected static void putColor(String key, int r, int g, int b, int a) { + put(key, new Color(r, g, b, a)); + } + + protected static void put(String key, Class c) { + UIManager.put(key, c.getName()); + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/WinUtils.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/WinUtils.java new file mode 100644 index 000000000..7519b3f8f --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/WinUtils.java @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * WinUtils.java at 2015-2-1 20:25:37, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.utils; + +import java.awt.Color; +import java.awt.Component; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Rectangle; + +import javax.swing.AbstractButton; +import javax.swing.ButtonModel; +import javax.swing.JMenu; +import javax.swing.JMenuItem; +import javax.swing.UIManager; + +/** + * The Class WinUtils. + * + * @see com.sun.java.swing.plaf.windows.WindowsGraphicsUtils + */ +public class WinUtils { + //* copy from WindowsLookAndFeel START 未做修改 + // Toggle flag for drawing the mnemonic state + + /** + * The is mnemonic hidden. + */ + private static boolean isMnemonicHidden = true; + + /** + * Gets the state of the hide mnemonic flag. This only has meaning if this + * feature is supported by the underlying OS. + * + * @return true if mnemonics are hidden, otherwise, false + * @see #setMnemonicHidden + * @since 1.4 + */ + public static boolean isMnemonicHidden() { + if (UIManager.getBoolean("Button.showMnemonics") == true) + // Do not hide mnemonics if the UI defaults do not support this + isMnemonicHidden = false; + return isMnemonicHidden; + } + //* copy from WindowsLookAndFeel END + + //* copy from WindowsGraphicsUtils START (modified by jack jiang) + /** + * Renders a text String in Windows without the mnemonic. This is here + * because the WindowsUI hiearchy doesn't match the Component heirarchy. All + * the overriden paintText methods of the ButtonUI delegates will call this + * static method. + *

+ * + * @param g Graphics context + * @param b Current button to render + * @param textRect Bounding rectangle to render the text. + * @param text String to render + * @param textShiftOffset the text shift offset + */ + public static void paintText(Graphics g, AbstractButton b, + Rectangle textRect, String text, + int textShiftOffset) { + FontMetrics fm = MySwingUtilities2.getFontMetrics(b, g); + + int mnemIndex = b.getDisplayedMnemonicIndex(); + // W2K Feature: Check to see if the Underscore should be rendered. + if (isMnemonicHidden() == true) + mnemIndex = -1; + paintClassicText(b, g, textRect.x + textShiftOffset, + textRect.y + fm.getAscent() + textShiftOffset, + text, mnemIndex); + } + + /** + * Paint classic text. + * + * @param b the b + * @param g the g + * @param x the x + * @param y the y + * @param text the text + * @param mnemIndex the mnem index + */ + static void paintClassicText(AbstractButton b, Graphics g, int x, int y, + String text, int mnemIndex) { + ButtonModel model = b.getModel(); + + /* Draw the Text */ + Color color = b.getForeground(); + if (model.isEnabled()) { + /** + * * paint the text normally + */ + if (!(b instanceof JMenuItem && model.isArmed()) + && !(b instanceof JMenu && (model.isSelected() || model.isRollover()))) + /* We shall not set foreground color for selected menu or + * armed menuitem. Foreground must be set in appropriate + * Windows* class because these colors passes from + * BasicMenuItemUI as protected fields and we can't + * reach them from this class */ + g.setColor(b.getForeground()); + MySwingUtilities2.drawStringUnderlineCharAt(b, g, text, mnemIndex, x, y); + } else { + /** + * * paint the text disabled ** + */ + color = UIManager.getColor("Button.shadow"); + Color shadow = UIManager.getColor("Button.disabledShadow"); + if (model.isArmed()) + color = UIManager.getColor("Button.disabledForeground"); + else { + if (shadow == null) + shadow = b.getBackground().darker(); + g.setColor(shadow); + MySwingUtilities2.drawStringUnderlineCharAt(b, g, text, mnemIndex, x + 1, y + 1); + } + if (color == null) + color = b.getBackground().brighter(); + g.setColor(color); + MySwingUtilities2.drawStringUnderlineCharAt(b, g, text, mnemIndex, x, y); + + } + } + //* copy from WindowsGraphicsUtils END (modified by jack jiang) + + //* copy from WindowsGraphicsUtils START + /** + * 是否组件的排列方向是从左到右. + * + * @param c the c + * @return true, if is left to right + */ + public static boolean isLeftToRight(Component c) { + return c.getComponentOrientation().isLeftToRight(); + } + //* copy from WindowsGraphicsUtils END +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/button/BEButtonUI.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/button/BEButtonUI.java new file mode 100644 index 000000000..32cdebbb9 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/button/BEButtonUI.java @@ -0,0 +1,334 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * BEButtonUI.java at 2015-2-1 20:25:36, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.button; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Insets; +import java.awt.Rectangle; + +import javax.swing.AbstractButton; +import javax.swing.ButtonModel; +import javax.swing.JCheckBox; +import javax.swing.JComponent; +import javax.swing.JRadioButton; +import javax.swing.JToggleButton; +import javax.swing.JToolBar; +import javax.swing.LookAndFeel; +import javax.swing.UIManager; +import javax.swing.border.Border; +import javax.swing.border.CompoundBorder; +import javax.swing.border.EmptyBorder; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.InsetsUIResource; +import javax.swing.plaf.UIResource; +import javax.swing.plaf.basic.BasicButtonUI; +import javax.swing.text.JTextComponent; +import org.jackhuang.hmcl.laf.BEUtils; + +import org.jackhuang.hmcl.laf.utils.Icon9Factory; + +/** + * JButton的UI实现类. + * + * @author Jack Jiang(jb2011@163.com) + * @version 1.0 + * @see com.sun.java.swing.plaf.windows.WindowsButtonUI + */ +public class BEButtonUI extends BasicButtonUI { + + private static final Icon9Factory ICON_9 = new Icon9Factory("button"); + + private final static BEButtonUI INSTANCE = new BEButtonUI(); + + /** + * The dashed rect gap x. + */ + protected int dashedRectGapX; + + /** + * The dashed rect gap y. + */ + protected int dashedRectGapY; + + /** + * The dashed rect gap width. + */ + protected int dashedRectGapWidth; + + /** + * The dashed rect gap height. + */ + protected int dashedRectGapHeight; + + /** + * The focus color. + */ + protected Color focusColor; + + /** + * The defaults_initialized. + */ + private boolean defaults_initialized = false; + + // ******************************** + // Create PLAF + // ******************************** + public static ComponentUI createUI(JComponent c) { + if (c instanceof CustomButton) + return new CustomButtonUI(); + return INSTANCE; + } + + // ******************************** + // Defaults + // ******************************** + @Override + protected void installDefaults(AbstractButton b) { + super.installDefaults(b); + LookAndFeel.installProperty(b, "opaque", Boolean.FALSE); + + if (!defaults_initialized) { + String pp = getPropertyPrefix(); + dashedRectGapX = UIManager.getInt(pp + "dashedRectGapX"); + dashedRectGapY = UIManager.getInt(pp + "dashedRectGapY"); + dashedRectGapWidth = UIManager.getInt(pp + "dashedRectGapWidth"); + dashedRectGapHeight = UIManager.getInt(pp + "dashedRectGapHeight"); + focusColor = UIManager.getColor(pp + "focus"); + defaults_initialized = true; + } + + { + LookAndFeel.installProperty(b, "rolloverEnabled", Boolean.TRUE); + } + } + + @Override + protected void uninstallDefaults(AbstractButton b) { + super.uninstallDefaults(b); + defaults_initialized = false; + } + + /** + * Gets the focus color. + * + * @return the focus color + */ + protected Color getFocusColor() { + return focusColor; + } + + // ******************************** + // Paint Methods + // ******************************** + @Override + protected void paintFocus(Graphics g, AbstractButton b, Rectangle viewRect, Rectangle textRect, Rectangle iconRect) { + // focus painted same color as text on Basic?? + int width = b.getWidth(); + int height = b.getHeight(); + g.setColor(getFocusColor()); + + //** modified by jb2011:绘制虚线方法改成可以设置虚线步进的方法,步进设为2则更好看一点 +// BasicGraphicsUtils.drawDashedRect(g, dashedRectGapX, dashedRectGapY, +// width - dashedRectGapWidth, height - dashedRectGapHeight); + // 绘制虚线框 + BEUtils.drawDashedRect(g, dashedRectGapX, dashedRectGapY, + width - dashedRectGapWidth, height - dashedRectGapHeight); + // 绘制虚线框的半透明白色立体阴影(半透明的用处在于若隐若现的效果比纯白要来的柔和的多) + g.setColor(new Color(255, 255, 255, 50)); + // 立体阴影就是向右下偏移一个像素实现的 + BEUtils.drawDashedRect(g, dashedRectGapX + 1, dashedRectGapY + 1, + width - dashedRectGapWidth, height - dashedRectGapHeight); + } + + // ******************************** + // Layout Methods + // ******************************** + @Override + public Dimension getPreferredSize(JComponent c) { + Dimension d = super.getPreferredSize(c); + + /* Ensure that the width and height of the button is odd, + * to allow for the focus line if focus is painted + */ + AbstractButton b = (AbstractButton) c; + if (d != null && b.isFocusPainted()) { + if (d.width % 2 == 0) + d.width += 1; + if (d.height % 2 == 0) + d.height += 1; + } + return d; + } + + + /* These rectangles/insets are allocated once for all + * ButtonUI.paint() calls. Re-using rectangles rather than + * allocating them in each paint call substantially reduced the time + * it took paint to run. Obviously, this method can't be re-entered. + */ +// private static Rectangle viewRect = new Rectangle(); + @Override + public void paint(Graphics g, JComponent c) { + paintXPButtonBackground(g, c); + super.paint(g, c); + } + + /** + * Paint xp button background. + * + * @param nomalColor the nomal color + * @param g the g + * @param c the c + */ + public static void paintXPButtonBackground(Graphics g, JComponent c) { + AbstractButton b = (AbstractButton) c; + boolean toolbar = b.getParent() instanceof JToolBar; + + if (b.isContentAreaFilled()) { + ButtonModel model = b.getModel(); + Dimension d = c.getSize(); + int dx = 0; + int dy = 0; + int dw = d.width; + int dh = d.height; + + Border border = c.getBorder(); + Insets insets; + if (border != null) + // Note: The border may be compound, containing an outer + // opaque border (supplied by the application), plus an + // inner transparent margin border. We want to size the + // background to fill the transparent part, but stay + // inside the opaque part. + insets = BEButtonUI.getOpaqueInsets(border, c); + else + insets = c.getInsets(); + if (insets != null) { + dx += insets.left; + dy += insets.top; + dw -= (insets.left + insets.right); + dh -= (insets.top + insets.bottom); + } + + if (toolbar) + //此状态下JToggleButton和JButton使用各自的背景实现,2012-10-16前无论是不是JToggleButton都是使用该种实是不太合理的 + if (model.isRollover() || model.isPressed()) + if (c instanceof JToggleButton) + BEToggleButtonUI.ICON_9.get("rollover").draw((Graphics2D) g, dx, dy, dw, dh); + else + ICON_9.get("pressed").draw((Graphics2D) g, dx, dy, dw, dh); + else if (model.isSelected()) + BEToggleButtonUI.ICON_9.get("selected").draw((Graphics2D) g, dx, dy, dw, dh); + else { + //TODO 其它状态下的按钮背景样式需要完善,要不然看起来太硬! +// skin.paintSkin(g, dx, dy, dw, dh, state); + } + else { + //TODO 其它状态下的按钮背景样式需要完善,要不然看起来太硬! + String key; + if (model.isArmed() && model.isPressed() || model.isSelected()) + key = "pressed"; + else if (!model.isEnabled()) + key = "disabled"; + else if (model.isRollover()) + key = "rollover"; + else + key = "normal"; + ICON_9.get(key).draw((Graphics2D) g, dx, dy, dw, dh); + } + } + } + + /** + * returns - b.getBorderInsets(c) if border is opaque - null if border is + * completely non-opaque - somewhere inbetween if border is compound and + * outside border is opaque and inside isn't + * + * @param b the b + * @param c the c + * @return the opaque insets + */ + private static Insets getOpaqueInsets(Border b, Component c) { + if (b == null) + return null; + if (b.isBorderOpaque()) + return b.getBorderInsets(c); + else if (b instanceof CompoundBorder) { + CompoundBorder cb = (CompoundBorder) b; + Insets iOut = getOpaqueInsets(cb.getOutsideBorder(), c); + if (iOut != null && iOut.equals(cb.getOutsideBorder().getBorderInsets(c))) { + // Outside border is opaque, keep looking + Insets iIn = getOpaqueInsets(cb.getInsideBorder(), c); + if (iIn == null) + // Inside is non-opaque, use outside insets + return iOut; + else + // Found non-opaque somewhere in the inside (which is + // also compound). + return new Insets(iOut.top + iIn.top, iOut.left + iIn.left, + iOut.bottom + iIn.bottom, iOut.right + iIn.right); + } else + // Outside is either all non-opaque or has non-opaque + // border inside another compound border + return iOut; + } else + return null; + } + + public static class BEEmptyBorder extends EmptyBorder implements UIResource { + + public BEEmptyBorder(Insets m) { + super(m.top + 2, m.left + 2, m.bottom + 2, m.right + 2); + } + + @Override + public Insets getBorderInsets(Component c) { + return getBorderInsets(c, getBorderInsets()); + } + + @Override + public Insets getBorderInsets(Component c, Insets insets) { + insets = super.getBorderInsets(c, insets); + + Insets margin = null; + if (c instanceof AbstractButton) { + Insets m = ((AbstractButton) c).getMargin(); + // if this is a toolbar button then ignore getMargin() + // and subtract the padding added by the constructor + if (c.getParent() instanceof JToolBar + && !(c instanceof JRadioButton) + && !(c instanceof JCheckBox) + && m instanceof InsetsUIResource) { + insets.top -= 2; + insets.left -= 2; + insets.bottom -= 2; + insets.right -= 2; + } else + margin = m; + } else if (c instanceof JToolBar) + margin = ((JToolBar) c).getMargin(); + else if (c instanceof JTextComponent) + margin = ((JTextComponent) c).getMargin(); + if (margin != null) { + insets.top = margin.top + 2; + insets.left = margin.left + 2; + insets.bottom = margin.bottom + 2; + insets.right = margin.right + 2; + } + return insets; + } + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/button/BEToggleButtonUI.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/button/BEToggleButtonUI.java new file mode 100644 index 000000000..38a97ff22 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/button/BEToggleButtonUI.java @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * BEToggleButtonUI.java at 2015-2-1 20:25:40, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.button; + +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Rectangle; + +import javax.swing.AbstractButton; +import javax.swing.ButtonModel; +import javax.swing.JComponent; +import javax.swing.LookAndFeel; +import javax.swing.UIManager; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicToggleButtonUI; + +import org.jackhuang.hmcl.laf.BEUtils; +import org.jackhuang.hmcl.laf.utils.Icon9Factory; +import org.jackhuang.hmcl.laf.utils.MySwingUtilities2; + +/** + * JToggleButton的UI实现类. + * + * @author Jack Jiang(jb2011@163.com) + * @see com.sun.java.swing.plaf.windows.WindowsToggleButtonUI + */ +public class BEToggleButtonUI extends BasicToggleButtonUI { + + protected static final Icon9Factory ICON_9 = new Icon9Factory("toggle_button"); + + private static final BEToggleButtonUI INSTANCE = new BEToggleButtonUI(); + + public static ComponentUI createUI(JComponent b) { + return INSTANCE; + } + + //* 由Jack Jiang于2012-10-12日加入:重写本方法的目的是使得JToggleButton不填充 + //* BasicToggleButtonUI里的白色距形区,否则在JToolBar上时会因该白色距形区的存 + //* 在而使得与BEToolBarUI的渐变背景不协调(丑陋的创可贴效果),实际上 + //* WindowsToolButtonUI里有同名方法里也是它样处理的,详情参见WindowsToolButtonUI + @Override + protected void installDefaults(AbstractButton b) { + super.installDefaults(b); + LookAndFeel.installProperty(b, "opaque", Boolean.FALSE); + } + + // ******************************** + // Paint Methods + // ******************************** + @Override + public void paint(Graphics g, JComponent c) { + BEButtonUI.paintXPButtonBackground(g, c); + super.paint(g, c); + } + + //修改的目的是让它在获得焦点(或说点中时)改变前景色,可惜父类中没有实现它,只能自已来解决了 + /** + * As of Java 2 platform v 1.4 this method should not be used or overriden. + * Use the paintText method which takes the AbstractButton argument. + * + * @param g the g + * @param c the c + * @param textRect the text rect + * @param text the text + * @see + * javax.swing.plaf.basic.BasicToggleButtonUI#paintText(java.awt.Graphics, + * javax.swing.JComponent, java.awt.Rectangle, java.lang.String) + */ + @Override + protected void paintText(Graphics g, JComponent c, Rectangle textRect, String text) { + AbstractButton b = (AbstractButton) c; + ButtonModel model = b.getModel(); + FontMetrics fm = MySwingUtilities2.getFontMetrics(c, g); + int mnemonicIndex = b.getDisplayedMnemonicIndex(); + + if (model.isEnabled()) { + if (model.isSelected()) + g.setColor(UIManager.getColor(getPropertyPrefix() + "focus")); + else + g.setColor(b.getForeground()); + + MySwingUtilities2.drawStringUnderlineCharAt(c, g, text, mnemonicIndex, + textRect.x + getTextShiftOffset(), + textRect.y + fm.getAscent() + getTextShiftOffset()); + } else { + g.setColor(b.getBackground().brighter()); + MySwingUtilities2.drawStringUnderlineCharAt(c, g, text, mnemonicIndex, + textRect.x, textRect.y + fm.getAscent()); + g.setColor(b.getBackground().darker()); + MySwingUtilities2.drawStringUnderlineCharAt(c, g, text, mnemonicIndex, + textRect.x - 1, textRect.y + fm.getAscent() - 1); + } + } + + /** + * {@inheritDoc} + * + * Method signature defined here overriden in subclasses. Perhaps this class + * should be abstract? + */ + @Override + protected void paintFocus(Graphics g, AbstractButton b, + Rectangle viewRect, Rectangle textRect, Rectangle iconRect) { + Rectangle bound = b.getVisibleRect(); + //决定焦点要制的位置(当前实现是往内缩3个像素,与当前按钮背景配合) + final int delta = 3; + int x = bound.x + delta, y = bound.y + delta, w = bound.width - delta * 2, h = bound.height - delta * 2; + + //绘制焦点虚线框 + g.setColor(UIManager.getColor("ToggleButton.focusLine"));//*~ 这是Jack Jiang自定义的属性哦 + BEUtils.drawDashedRect(g, x, y, w, h, 17, 17, 2, 2); + //再绘制焦点虚线框的立体高亮阴影,以便形成立体感 + g.setColor(UIManager.getColor("ToggleButton.focusLineHilight"));//*~ 这是Jack Jiang自定义的属性哦 + BEUtils.drawDashedRect(g, x + 1, y + 1, w, h, 17, 17, 2, 2); + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/ConstomButton.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/button/CustomButton.java similarity index 92% rename from HMCLaF/src/main/java/org/jackhuang/hmcl/laf/ConstomButton.java rename to HMCLaF/src/main/java/org/jackhuang/hmcl/laf/button/CustomButton.java index 2b930f0cb..ca3285982 100755 --- a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/ConstomButton.java +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/button/CustomButton.java @@ -14,7 +14,7 @@ * You should have received a copy of the GNU General Public License * along with this program. */ -package org.jackhuang.hmcl.laf; +package org.jackhuang.hmcl.laf.button; import java.awt.Color; import org.jackhuang.hmcl.util.ui.GraphicsUtils; @@ -23,7 +23,7 @@ import org.jackhuang.hmcl.util.ui.GraphicsUtils; * * @author huangyuhui */ -public class ConstomButton extends javax.swing.JButton { +public class CustomButton extends javax.swing.JButton { public Color normalFg = GraphicsUtils.getWebColorWithAlpha("DDDDDD6F"), normalBg = GraphicsUtils.getWebColorWithAlpha("DDDDDD6F"), prelightFg = GraphicsUtils.getWebColorWithAlpha("FFFFFF7F"), prelightBg = GraphicsUtils.getWebColorWithAlpha("FFFFFF7F"), activeFg = GraphicsUtils.getWebColorWithAlpha("EAEDF83F"), activeBg = GraphicsUtils.getWebColorWithAlpha("EAEDF83F"); diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/button/CustomButtonUI.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/button/CustomButtonUI.java new file mode 100644 index 000000000..0cc0800f2 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/button/CustomButtonUI.java @@ -0,0 +1,140 @@ +/* + * Hello Minecraft! Launcher. + * Copyright (C) 2013 huangyuhui + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see {http://www.gnu.org/licenses/}. + */ +package org.jackhuang.hmcl.laf.button; + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.geom.RoundRectangle2D; +import javax.swing.AbstractButton; +import javax.swing.ButtonModel; +import javax.swing.JComponent; +import javax.swing.LookAndFeel; +import javax.swing.Timer; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicButtonUI; +import org.jackhuang.hmcl.util.ui.GraphicsUtils; +import org.jackhuang.hmcl.laf.button.BEButtonUI; + +/** + * + * @author huang + */ +public class CustomButtonUI extends BasicButtonUI { + + private static final String DEFAULT_NORMAL = "D5D5D5"; + private static final Color[] DEFAULT_NORMAL_FG = new Color[] { + GraphicsUtils.getWebColor(DEFAULT_NORMAL), + GraphicsUtils.getWebColor(DEFAULT_NORMAL) + }; + private static final String DEFAULT_PRELIGHT = "A9A9A9"; + private static final Color[] DEFAULT_PRELIGHT_FG = new Color[] { + GraphicsUtils.getWebColor(DEFAULT_PRELIGHT), + GraphicsUtils.getWebColor(DEFAULT_PRELIGHT) + }; + private static final String DEFAULT_ACTIVE = "222222"; + private static final Color[] DEFAULT_ACTIVE_FG = new Color[] { + GraphicsUtils.getWebColor(DEFAULT_ACTIVE), + GraphicsUtils.getWebColor(DEFAULT_ACTIVE) + }; + + private static final Color[] DISABLED_BG = new Color[] { + GraphicsUtils.getWebColor("E3EFE9"), + GraphicsUtils.getMidWebColor("E3EFE9", "DFE2E6"), + GraphicsUtils.getWebColor("DFE2E6"), + GraphicsUtils.getMidWebColor("DFE2E6", "D6D9DF"), + GraphicsUtils.getWebColor("D6D9DF"), + GraphicsUtils.getWebColor("D6D9DF"), + GraphicsUtils.getMidWebColor("D6D9DF", "D8DBE1"), + GraphicsUtils.getWebColor("D8DBE1"), + GraphicsUtils.getWebColor("DADDE3") + }; + private static final Color[] DISABLED_FG = new Color[] { + GraphicsUtils.getWebColor("C9CCD2"), + GraphicsUtils.getWebColor("C9CCD2"), + GraphicsUtils.getWebColor("BCBFC5"), + GraphicsUtils.getWebColor("BCBFC5") + }; + + private static boolean processCustomButton(final CustomButton c, int add) { + if (c.drawPercent == 0 || c.drawPercent == 100) { + Timer t = new Timer(1, null); + t.addActionListener(x -> { + c.drawPercent += add; + if (c.drawPercent > 100 && add > 0) { + c.drawPercent = 100; + t.stop(); + } else if (c.drawPercent < 0 && add < 0) { + c.drawPercent = 0; + t.stop(); + } else + c.updateUI(); + }); + t.start(); + } + return true; + } + + @Override + protected void installDefaults(AbstractButton b) { + super.installDefaults(b); + LookAndFeel.installProperty(b, "opaque", Boolean.FALSE); + } + + @Override + public void paint(Graphics g, JComponent component) { + CustomButton c = (CustomButton) component; + ButtonModel model = c.getModel(); + Graphics2D g2 = (Graphics2D) g.create(); + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + Color[] fg, bg; + if (model.isPressed()) { + fg = new Color[] { c.activeFg, c.activeFg }; + bg = new Color[] { c.activeFg, c.activeFg }; + } else if (!c.isEnabled()) + return; + else if (model.isRollover()) { + if (!processCustomButton(c, 1)) + return; + Color fgs = GraphicsUtils.getMidWebColor(c.normalFg, c.prelightFg, c.drawPercent); + Color bgs = GraphicsUtils.getMidWebColor(c.normalBg, c.prelightBg, c.drawPercent); + fg = new Color[] { fgs, fgs }; + bg = new Color[] { bgs, bgs }; + } else { + if (!processCustomButton(c, -1)) + return; + Color fgs = GraphicsUtils.getMidWebColor(c.normalFg, c.prelightFg, c.drawPercent); + Color bgs = GraphicsUtils.getMidWebColor(c.normalBg, c.prelightBg, c.drawPercent); + fg = new Color[] { fgs, fgs }; + bg = new Color[] { bgs, bgs }; + } + + int radix = c.radix; + int x = 0, y = 0, w = c.getWidth(), h = c.getHeight(); + + g2.setColor(fg[0]); + RoundRectangle2D fgshape = new RoundRectangle2D.Float(x, y, w, h, radix, radix); + g2.draw(fgshape); + g2.setColor(bg[0]); + RoundRectangle2D bgshape = new RoundRectangle2D.Float(x, y, w, h, radix, radix); + g2.fill(bgshape); + + super.paint(g, c); + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/button/__UI__.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/button/__UI__.java new file mode 100644 index 000000000..6d9f192fd --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/button/__UI__.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * __UI__.java at 2015-2-1 20:25:40, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.button; + +import java.awt.Insets; + +import javax.swing.UIManager; +import javax.swing.plaf.basic.BasicBorders.MarginBorder; + +import org.jackhuang.hmcl.laf.BeautyEyeLNFHelper; +import org.jackhuang.hmcl.laf.utils.UI; + +public class __UI__ extends UI { + + public static void uiImpl() { + //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> JButton相关ui属性设定 + put("Button.background", BeautyEyeLNFHelper.commonBackgroundColor); + //Button.foreground的设定不起效,这可能是LNF里的bug,因NLLookAndFeel + //是继承自它们所以暂时无能为力,就这么的吧,以后再说 + put("Button.foreground", BeautyEyeLNFHelper.commonForegroundColor); + + //以下属性将决定按钮获得焦点时的焦点虚线框的绘制偏移量哦 + put("Button.dashedRectGapX", 3); + put("Button.dashedRectGapY", 3); + put("Button.dashedRectGapWidth", 6); + put("Button.dashedRectGapHeight", 6); + + put("ButtonUI", BEButtonUI.class); + putInsets("Button.margin", 2, 5, 2, 5); + //此border可以与Button.margin连合使用,而者之和即查整个Button的内衬哦 + UIManager.put("Button.border", new BEButtonUI.BEEmptyBorder(new Insets(3, 3, 3, 3))); + //获得焦点时的虚线框颜色 + putColor("Button.focus", 130, 130, 130); + + //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> JToggleButton相关ui属性设定 + //注意:本属性不要与ToggleButton.border混用,因为没有它的优先级高, + //另本参数如用InsetsUIResource则不会有效果,具体原因待查(本属性也将决定toolbar的整体高度和宽度哦) + putInsets("ToggleButton.margin", 3, 11, 3, 11);//4, 8, 4, 8));////4, 12, 4, 12)); + put("ToggleButton.background", BeautyEyeLNFHelper.commonBackgroundColor); + put("ToggleButton.foreground", BeautyEyeLNFHelper.commonForegroundColor); + //用于ToggleButon被选中时的前景色 + //注:在原WindowsLookAndFeel中,本属性存在(值是Color(0,0,0,))但在UI里没有用到 + //,此处被jb2011定义为“选中时的前景色”,当然也可以自已定名称,参见 NLWindowsToggleButtonUI2.paintText(..) + put("ToggleButton.focus", BeautyEyeLNFHelper.commonForegroundColor);// Color.white + put("ToggleButtonUI", BEToggleButtonUI.class); + //以下设置对ToggleButton在不加入到JToolBar时是有效果的哦!!!!!!!!!!! +// UIManager.put("ToggleButton.margin",new InsetsUIResource(2, 30, 2, 30)); + put("ToggleButton.border", new MarginBorder()); + /* ~~注:这个属性是Jack Jiang为了更好的ui效果自已加的属性:焦点虚线的颜色 */ + put("ToggleButton.focusLine", BeautyEyeLNFHelper.commonFocusedBorderColor.darker()); + /* ~~注:这个属性是Jack Jiang为了更好的ui效果自已加的属性:焦点虚线的高亮立体阴影颜色 */ + putColor("ToggleButton.focusLineHilight", 240, 240, 240); + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/combox/BEComboBoxRenderer.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/combox/BEComboBoxRenderer.java new file mode 100644 index 000000000..2855f6315 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/combox/BEComboBoxRenderer.java @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * BEComboBoxRenderer.java at 2015-2-1 20:25:38, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.combox; + +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Insets; + +import javax.swing.BorderFactory; +import javax.swing.JList; +import javax.swing.plaf.basic.BasicComboBoxRenderer; +import org.jackhuang.hmcl.laf.menu.BEMenuUI; +import org.jackhuang.hmcl.laf.BEUtils; + +/** + * JComboBox组件下拉选项的render默认实现类. + * + * @author Jack Jiang(jb2011@163.com), 2012-07-05 + * @see BEComboBoxUI + */ +public class BEComboBoxRenderer extends BasicComboBoxRenderer { + + /** + * 当前下拉框里的item是否被选中:用于是否要将背景填充选中样式时使用. + */ + private boolean selected = false; + + /** + * 记下本render对应的JComboBox的UI. + */ + private BEComboBoxUI comboBoxUI = null; + + public BEComboBoxRenderer(BEComboBoxUI ui) { + super(); + this.comboBoxUI = ui; + //设置成透明背景则意味着不需要背景填充,但本类中的应用场景有点特殊 + //——默认的render的UI里不需要绘制背景的情况下本类才可进行NinePatch图作为背景进行填充 + setOpaque(false); + //TODO 此border(render的内衬)可以作为一个UIManager的属性哦,方便以后设置 + //注:此内衬是决定列表单元间的上下左右空白的关键哦! + setBorder(BorderFactory.createEmptyBorder(5, 4, 5, 8));//此设置是与Combox.border UI属性配合哦 + } + + /** + * {@inheritDoc} + * + * @see + * javax.swing.plaf.basic.BasicComboBoxRenderer#getListCellRendererComponent + * (javax.swing.JList, java.lang.Object, int, boolean, boolean) + */ + @Override + public Component getListCellRendererComponent(JList list, + Object value, int index, boolean isSelected, boolean cellHasFocus) { + Component c = super.getListCellRendererComponent(list, + value, index, isSelected, cellHasFocus); + //add by jb2011:保存选中状态 + this.selected = isSelected; + return c; + } + + /** + * {@inheritDoc} + * + * 按理说本方法中的是否选中背景填充实现逻辑在Render的UI中实现最为合理,但由于 + * 本类就是处理于UI实现中,所以容易产生冲突,故而不适宜自定义Ui实现,干脆硬编码则更直接 + */ + @Override + public void paintComponent(Graphics g) { + //当下拉选项弹出时 且 该item是被选中时才需要把背景填充成选中样式 + if (comboBoxUI.isPopupVisible(null) && selected) + BEMenuUI.drawSelectedBackground(g, 0, 0, this.getWidth(), this.getHeight()); + //下拉选项未弹出时JComboBox的背景样式 + //按理说,本类已设置成透明而无须填充背景,但本应用场景中,只能在默认Ui不填充背景的情况下才 + //能完成自定义NinePatch背景的填充。见 ComponentUI.update(Graphics g, JComponent c)方法 + + //注意:本组件已经被设置成opaque=false即透明,否则本方法还会填充默认背景,那么选中时的 + //N9图背景因先绘将会被覆盖哦。所以要使用N9图作为选中时的背景则前提是本组件必须是透明 + super.paintComponent(g); + } + + //copy from BasicComboBoxRenderer and modified by jb2011 + /** + * A subclass of BasicComboBoxRenderer that implements UIResource. + * BasicComboBoxRenderer doesn't implement UIResource directly so that + * applications can safely override the cellRenderer property with + * BasicListCellRenderer subclasses. + *

+ * Warning: + * Serialized objects of this class will not be compatible with future Swing + * releases. The current serialization support is appropriate for short term + * storage or RMI between applications running the same version of Swing. As + * of 1.4, support for long term storage of all + * JavaBeansTM + * has been added to the java.beans package. Please see + * {@link java.beans.XMLEncoder}. + */ + public static class UIResource extends BEComboBoxRenderer implements javax.swing.plaf.UIResource { + + /** + * Instantiates a new uI resource. + * + * @param ui the ui + */ + public UIResource(BEComboBoxUI ui) { + super(ui); + } + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/combox/BEComboBoxUI.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/combox/BEComboBoxUI.java new file mode 100644 index 000000000..3a7a5b2fd --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/combox/BEComboBoxUI.java @@ -0,0 +1,362 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * BEComboBoxUI.java at 2015-2-1 20:25:38, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.combox; + +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Insets; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; + +import javax.swing.ComboBoxEditor; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JComponent; +import javax.swing.JScrollPane; +import javax.swing.ListCellRenderer; +import javax.swing.LookAndFeel; +import javax.swing.UIManager; +import javax.swing.border.Border; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.UIResource; +import javax.swing.plaf.basic.BasicComboBoxEditor; +import javax.swing.plaf.basic.BasicComboBoxUI; +import javax.swing.plaf.basic.BasicComboPopup; +import javax.swing.plaf.basic.ComboPopup; +import org.jackhuang.hmcl.laf.utils.Icon9Factory; + +/** + * JComboBox的UI实现类. + * + * @author Jack Jiang(jb2011@163.com), 2012-06-30 + * @version 1.0 + * @see com.sun.java.swing.plaf.windows.WindowsComboBoxUI + */ +public class BEComboBoxUI extends BasicComboBoxUI + implements org.jackhuang.hmcl.laf.BeautyEyeLNFHelper.__UseParentPaintSurported, MouseListener { + + private static final Icon9Factory ICON_9 = new Icon9Factory("combo"); + private static final Dimension BTN_SIZE = new Dimension(17, 20); + private final Dimension btnSize = new Dimension(BTN_SIZE); + + public static ComponentUI createUI(JComponent c) { + return new BEComboBoxUI(); + } + + //* 本方法由Jack Jiang于2012-09-07日加入 + /** + * 是否使用父类的绘制实现方法,true表示是. + *

+ * 因为在BE LNF中,边框和背景等都是使用N9图,没法通过设置背景色和前景 + * 色来控制JComboBox的颜色和边框,本方法的目的就是当用户设置了进度条的border或背景色 时告之本实现类不使用BE + * LNF中默认的N9图填充绘制而改用父类中的方法(父类中的方法 就可以支持颜色的设置罗,只是丑点,但总归是能适应用户的需求场景要求,其实用户完全可以 + * 通过JComboBox.setUI(..)方式来自定义UI哦). + * + * @return true, if is use parent paint + */ + @Override + public boolean isUseParentPaint() { + return comboBox != null + && (!(comboBox.getBorder() instanceof UIResource) + || !(comboBox.getBackground() instanceof UIResource)); + } + + @Override + public void installUI(JComponent c) { + super.installUI(c); + + //2012-08-30*******************************************************【重要说明】 START 对应BEListUI中的【重要说明】 + //* 【重要说明】因BEListUI中为了使列表行单元高变的更高(在MyDefaultListCellRenderer.java中 + //* 像COmboxRender一样通过增到border不起效果,它可能是BasicListUI的设计缺陷,它要么取FixedCellHeight + //* 固定值,要么取getPreferSize()即自动计算高度——它似乎是不计入border的,所以render设置border不起效) + //* 所以只能为列表单元设置因定值:list.setFixedCellHeight(30),但它将影响Combox里的行高(也会变成30高) + //* 所以此处要把列表UI中强制设定的30高针对Combox还原成自动计算(API中规定FixedCellHeight==-1即表示自动计算) + popup.getList().setFixedCellHeight(-1); + //**************************************************************** 【重要说明】 END + + //* 以下代码由jb2011加入 +// comboBox.setMaximumRowCount(8);//这个最大行可以起效,但似乎它的行高指的是一个固定值而不是计算值,像本LNF里因cell本身行高就很高 + //即使设置了最大显示行,但是显示的并不是指定值,有待进一步研究 + //为下拉框的弹出弹加border,这样上下空白外一点好看一些 + // install the scrollpane border + Container parent = popup.getList().getParent(); // should be viewport + if (parent != null) { + parent = parent.getParent(); // should be the scrollpane + if (parent != null && parent instanceof JScrollPane) + LookAndFeel.installBorder((JScrollPane) parent, "ComboBox.scrollPaneBorder");//*~ 注:这个属性是Jack Jiang仿照JTabel里的实现自已加的属性 + } + } + + @Override + protected void installListeners() { + super.installListeners(); + comboBox.addMouseListener(this); + } + + @Override + protected void uninstallListeners() { + super.uninstallListeners(); + comboBox.removeMouseListener(this); + } + + /** + * Gets the combox. + * + * @return the combox + */ + public JComboBox getCombox() { + return this.comboBox; + } + + /** + * {@inheritDoc} + * + * 自定义下接框箭头按钮实现类 + */ + @Override + protected JButton createArrowButton() { + JButton button = new JButton() { + @Override + protected void paintComponent(Graphics g) { + if (comboBox.isEditable()) + ICON_9.getWithComboState("", comboBox.isEnabled(), mouseDown, mouseInside) + .draw((Graphics2D) g, 0, 0, getWidth(), getHeight()); + } + }; + button.addMouseListener(this); + button.setMinimumSize(BTN_SIZE); + button.setPreferredSize(BTN_SIZE); + button.setMargin(new Insets(0, 0, 0, 0)); + return button; + } + + @Override + public void paint(Graphics g, JComponent c) { + hasFocus = comboBox.hasFocus(); + ListCellRenderer renderer = comboBox.getRenderer(); + Rectangle r = new Rectangle(0, 0, comboBox.getWidth(), comboBox.getHeight()); + paintCurrentValueBackground(g, r, hasFocus); + if (!comboBox.isEditable()) + paintCurrentValue(g, rectangleForCurrentValue(), false); + } + + /** + * Paints the background of the currently selected item. + * + * @param g the g + * @param bounds the bounds + * @param hasFocus the has focus + * @see javax.swing.plaf.basic.BasicComboBoxUI#paintCurrentValueBackground(java.awt.Graphics, java.awt.Rectangle, boolean) + */ + @Override + public void paintCurrentValueBackground(Graphics g, Rectangle bounds, boolean hasFocus) { + ICON_9.getWithComboState("", comboBox.isEnabled(), mouseDown, mouseInside) + .draw((Graphics2D) g, bounds.x, bounds.y, bounds.width, bounds.height); + } + + //* copy from BasicComboBoxUI and modified by jb2011 + /** + * Creates the default renderer that will be used in a non-editiable combo + * box. A default renderer will used only if a renderer has not been + * explicitly set with setRenderer. + * + * @return a ListCellRender used for the combo box + * @see javax.swing.JComboBox#setRenderer + */ + @Override + protected ListCellRenderer createRenderer() { + return new BEComboBoxRenderer.UIResource(this); + } + + /** + * {@inheritDoc} + * + * 改变方法可见性 + */ + @Override + public Insets getInsets() { + return super.getInsets(); + } + + /** + * Creates the popup portion of the combo box. + * + * 目的是修正弹出popup窗口的x、y坐标,不像菜单UI里有 + * Menu.menuPopupOffsetX等4个属性可设置以备对坐标进行调整,BeautyEye LNF中由Jack Jiang + * 依照Menu中的实现自定义了2个属性,以便以后配置。参考自jdk1.6.0_u18源码. + * + * @return an instance of ComboPopup + * @see javax.swing.plaf.basic.BasicComboBoxUI#createPopup() + */ + @Override + protected ComboPopup createPopup() { + return new BasicComboPopup(comboBox) { + /** + * popupOffsetX是jb2011自定的属性,用于修正下拉框的弹出窗的X坐标 + */ + private final int popupOffsetX = UIManager.getInt("ComboBox.popupOffsetX"); + /** + * popupOffsetY是jb2011自定的属性,用于修正下拉框的弹出窗的Y坐标 + */ + private final int popupOffsetY = UIManager.getInt("ComboBox.popupOffsetY"); + + @Override + public void show() { + setListSelection(comboBox.getSelectedIndex()); + Point location = getPopupLocation(); + show(comboBox, //以下x、y坐标修正代码由Jack Jiang增加 + location.x + popupOffsetX, //*~ popupOffsetX是自定属性,用于修改弹出窗的X坐标 + location.y + popupOffsetY //*~ popupOffsetY是自定属性,用于修改弹出窗的Y坐标 + ); + } + + /** + * Sets the list selection index to the selectedIndex. This method + * is used to synchronize the list selection with the combo box + * selection. + * + * @param selectedIndex the index to set the list + * @see javax.swing.plaf.basic.BasicComboPopup#setListSelection(int) + */ + private void setListSelection(int selectedIndex) { + if (selectedIndex == -1) + list.clearSelection(); + else { + list.setSelectedIndex(selectedIndex); + list.ensureIndexIsVisible(selectedIndex); + } + } + + /** + * Calculates the upper left location of the Popup. + * + * @see javax.swing.plaf.basic.BasicComboPopup#getPopupLocation() + */ + private Point getPopupLocation() { + Dimension popupSize = comboBox.getSize(); + Insets insets = getInsets(); + + // reduce the width of the scrollpane by the insets so that the popup + // is the same width as the combo box. + popupSize.setSize(popupSize.width - (insets.right + insets.left), + getPopupHeightForRowCount(comboBox.getMaximumRowCount())); + Rectangle popupBounds = computePopupBounds(0, comboBox.getBounds().height, + popupSize.width, popupSize.height); + Dimension scrollSize = popupBounds.getSize(); + Point popupLocation = popupBounds.getLocation(); + + scroller.setMaximumSize(scrollSize); + scroller.setPreferredSize(scrollSize); + scroller.setMinimumSize(scrollSize); + + list.revalidate(); + + return popupLocation; + } + }; + } + + /** + * Creates the default editor that will be used in editable combo boxes. A + * default editor will be used only if an editor has not been explicitly set + * with setEditor. + * + * 重写父类方法的目的是使得默认的 + * Editor透明(即不填充默认背景),因为BE LNF中JTextField的LNF是用NP图 + * 实现的,此处不透明的话就会遮住NP背景图,从而使得外观难看。 + * + * Fixed Issue 49(https://code.google.com/p/beautyeye/issues/detail?id=49) + * + * @return a ComboBoxEditor used for the combo box + * @see javax.swing.JComboBox#setEditor + * @see com.sun.java.swing.plaf.windows.WindowsComboBoxUI.WindowsComboBoxEditor + */ + @Override + protected ComboBoxEditor createEditor() { + BasicComboBoxEditor.UIResource bcbe = new BasicComboBoxEditor.UIResource(); + Component c = bcbe.getEditorComponent(); + if (c != null) { + //把默认的Editor设置成透明(editor不透明的话就会遮住NP背景图,从而使得外观难看) + ((JComponent) c).setOpaque(false); + + //* 以下这段是为了给默认Editor加上border而加(没有它个border将使 + //* 得与不可编辑comboBox的内容组件看起来有差异哦), + //* 在WindowsComboBoxUI中,这段代码是放在WindowsComboBoxEditor + //* 中的方法createEditorComponent中实现,由于该 方法是1.6里才有的, + //* BE LNF因要兼容java1.5,所以不作类似实现就在本方法中实现也没有问题。 + //* 类似实现请参考WindowsComboBoxUI.WindowsComboBoxEditor类 +// JTextField editor = (JTextField)c; + Border border = (Border) UIManager.get("ComboBox.editorBorder"); + if (border != null) + ((JComponent) c).setBorder(border); + } + return bcbe; + } + + // ================================================================================================================= + // MouseListener Methods + private boolean mouseInside = false; + private boolean mouseDown = false; + + @Override + public void mouseClicked(MouseEvent e) { + } + + @Override + public void mouseEntered(MouseEvent e) { + if (comboBox.isEditable()) { + if (e.getComponent() == arrowButton) + mouseInside = true; + } else { + mouseInside = true; + comboBox.repaint(); + } + } + + @Override + public void mouseExited(MouseEvent e) { + if (comboBox.isEditable()) { + if (e.getComponent() == arrowButton) + mouseInside = false; + } else { + mouseInside = false; + comboBox.repaint(); + } + } + + @Override + public void mousePressed(MouseEvent e) { + if (comboBox.isEditable()) { + if (e.getComponent() == arrowButton) + mouseDown = true; + } else { + mouseDown = true; + comboBox.repaint(); + } + } + + @Override + public void mouseReleased(MouseEvent e) { + if (comboBox.isEditable()) { + if (e.getComponent() == arrowButton) + mouseDown = false; + } else { + mouseDown = false; + comboBox.repaint(); + } + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/combox/__UI__.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/combox/__UI__.java new file mode 100644 index 000000000..715025107 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/combox/__UI__.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * __UI__.java at 2015-2-1 20:25:37, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.combox; + +import java.awt.Color; + +import javax.swing.UIManager; + +import org.jackhuang.hmcl.laf.BeautyEyeLNFHelper; +import org.jackhuang.hmcl.laf.utils.UI; + +public class __UI__ extends UI { + + public static void uiImpl() { + /* ~~注:这个属性是Jack Jiang仿照JTabel里的实现自已加的属性,目的是控制选择框的弹出列表的边框空白 */ + putBorder("ComboBox.scrollPaneBorder", 0, 0, 0, 0); + + // 不能设置alpha通道小于255的透明颜色,否则会出现无法重paint的问题 + putColor("ComboBox.background", 242, 242, 242); + put("ComboBox.disabledBackground", BeautyEyeLNFHelper.commonBackgroundColor); +// put("ComboBox.buttonBackground", BeautyEyeLNFHelper.commonBackgroundColor); + putColor("ComboBox.buttonBackground", 242, 242, 242); + put("ComboBox.selectionForeground", BeautyEyeLNFHelper.commonSelectionForegroundColor); + put("ComboBox.selectionBackground", BeautyEyeLNFHelper.commonSelectionBackgroundColor); + put("ComboBox.foreground", BeautyEyeLNFHelper.commonForegroundColor); + + //render之外的衬距,此设置将改变下拉框的整体占位大小 + putInsets("ComboBox.padding", 0, 0, 0, 0);//5,8,5,8)); + //true表示下拉箭头按钮的宽度无条件=高度,否则宽度不与高度保持等长(使用自身长度) + UIManager.put("ComboBox.squareButton", true); + + //此border将决定ArrowButton的外衬大小(即框内衬空白大小),此大小决定conbox的高度和宽度,另一种方法 + //是通过设置render的border也能达到调整combox的高度和宽度,而且对lnf来说通过设置render的border是最佳方案 + putBorder("ComboBox.border", 0, 4, 0, 0);//new BERoundBorder(0).setThickness(10)));//.setArcWidth(10).setLineColor(new Color(0,0,0,0))));//使用全透明色绘边框,目的就是要让它的背景显现出来(NipePatch图实现) + putBorder("ComboBox.editorBorder", 0, 4, 0, 0);//windows 外观下认是1,2,1,1))); + + put("ComboBoxUI", BEComboBoxUI.class); + /* ~~注:这个属性是Jack Jiang为了更好的ui效果和方便未来的设定自已加的属性 */ + //用于修正下拉框的弹出窗的X坐标 + put("ComboBox.popupOffsetX", 0); + /* ~~注:这个属性是Jack Jiang为了更好的ui效果和方便未来的设定自已加的属性 */ + //用于修正下拉框的弹出窗的Y坐标 + put("ComboBox.popupOffsetY", 0); + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/filechooser/BEFileChooserUI.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/filechooser/BEFileChooserUI.java new file mode 100644 index 000000000..534a87d6b --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/filechooser/BEFileChooserUI.java @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * BEFileChooserUI.java at 2015-2-1 20:25:39, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.filechooser; + +import java.awt.Component; +import java.awt.Graphics; + +import javax.swing.JComponent; +import javax.swing.JFileChooser; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JViewport; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.metal.MetalFileChooserUI; + +/** + * BeautyEye L&F implementation of a FileChooser. + *

+ * 目前属通用跨平台专用UI实现类. + * + * @author Jack Jiang(jb2011@163.com), 2012-09-17 + * @version 1.0 + */ +public class BEFileChooserUI extends MetalFileChooserUI { + + public BEFileChooserUI(JFileChooser filechooser) { + super(filechooser); + } + + // + // ComponentUI Interface Implementation methods + // + + public static ComponentUI createUI(JComponent c) { + return new BEFileChooserUI((JFileChooser) c); + } + + /** + * {@inheritDoc} + * + * 注:目前仅发现Windows平台的WindowsFileChooserUI存在它个问题 ! 本方法由Jack + * Jiang实现,没有以下默认背景绘制则在BE LNF中因透明窗口而使得 + * 文件选择框内容面板的空白处出现全透明现的丑陋现象,注释掉本方法即可见之前的问题 + */ + @Override + public void paint(Graphics g, JComponent c) { + g.setColor(c.getBackground()); + g.fillRect(0, 0, c.getWidth(), c.getHeight()); + } + + /** + * 重写父类方法,以实现对文件查看列表的额外设置. + *

+ * 为什么要重写此方法,没有更好的方法吗?
+ * 答:因父类的封装结构不佳,filePane是private私有,子类中无法直接引用, + * 要想对filePane中的文列表额外设置,目前重写本方法是个没有办法的方法. + *

+ * sun.swing.FilePane源码可查看地址:Click + * here. + * + * @param fc the fc + * @return the j panel + */ + @Override + protected JPanel createList(JFileChooser fc) { + JPanel p = super.createList(fc); + + //* 以下代码的作用就是将文件列表JList对象引用给找回来(通过从它的父面板中层层向下搜索) + //* ,因无法从父类中直接获得列表对象的直接引用,只能用此笨办法了 + if (p.getComponentCount() > 0) { + Component scollPane = p.getComponent(0); + if (scollPane != null && scollPane instanceof JScrollPane) { + JViewport vp = ((JScrollPane) scollPane).getViewport(); + if (vp != null) { + Component fileListView = vp.getView(); + //终于找到了文件列表的实例引用 + if (fileListView != null && fileListView instanceof JList) + //把列表的行高改成-1(即自动计算列表每个单元的行高而不指定固定值) + //* 说明:在BeautyEye LNF中,为了便JList的UI更好看,在没有其它方法有前 + //* 提下就在JList的BEListUI中给它设置了默写行高32,而JFildChooser中的 + //* 文件列表将会因此而使得单元行高很大——从而导致文件列表很难看,此处就是恢复 + //* 文件列表单元行高的自动计算,而非指定固定行高。 + //* + //* 说明2:为什么不能利用list.getClientProperty("List.isFileList")从而在JList + //* 的ui中进行判断并区别对待是否是文件列表呢? + //* 答:因为"List.isFileList"是在BasicFileChooserUI中设置的,也就是说当为个属性被 + //* 设置的时候JFileChooser中的文件列表已经实例化完成(包括它的ui初始化),所以此时 + //* 如果在JList的ui中想区分是不可能的,因它还没有被调置,这个设置主要是供BasicListUI + //* 在被实例化完成后,来异步处理这个属性的(通过监听属性改变事件来实现的) + ((JList) fileListView).setFixedCellHeight(-1); + } + } + } + + return p; + } + +// // +// // Renderer for Types ComboBox +// // +// protected FilterComboBoxRenderer createFilterComboBoxRenderer() +// { +// return new BEFilterComboBoxRenderer(); +// } +// /** +// * Render different type sizes and styles. +// */ +// protected class BEFilterComboBoxRenderer extends FilterComboBoxRenderer +// { +// public BEFilterComboBoxRenderer() +// { +// super(); +// +//// //设置成透明背景则意味着不需要背景填充,但本类中的应用场景有点特殊 +//// //——默认的render的UI里不需要绘制背景的情况下本类才可进行NinePatch图作为背景进行填充 +//// setOpaque(false); +// //TODO 此border(render的内衬)可以作为一个UIManager的属性哦,方便以后设置 +// //注:此内衬是决定列表单元间的上下左右空白的关键哦! +//// setBorder(BorderFactory.createEmptyBorder(5, 8, 5, 8)); +// } +// +// //按理说本方法中的是否选中背景填充实现逻辑在Render的UI中实现最为合理,但由于 +// //本类就是处理于UI实现中,所以容易产生冲突,故而不适宜自定义Ui实现,干脆硬编码则更直接 +// public void paintComponent(Graphics g) +// { +// //** 本HACK是为了解决 Issue 30:因JFileChooser中的文件类型选择下拉框的render +// //** (即本render)是自定义的(不是使用的ComboxUI里由BE LNF定义好的render而 +// //** 导致的视觉效果不佳的问题 +// //##### HACK:强行把绘制坐标右移、下移——以便使得与左边的空折多一点,要不然就太难看了 +// g.translate(5, 1); +// +// //照常绘制(只是之前的坐标被移了一下而已) +// super.paintComponent(g); +// +// //##### HACK:恢复坐标 +// g.translate(-5, -1); +// } +// } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/filechooser/__UI__.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/filechooser/__UI__.java new file mode 100644 index 000000000..689c4dae3 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/filechooser/__UI__.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * __UI__.java at 2015-2-1 20:25:38, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.filechooser; + +import java.awt.Color; + +import javax.swing.UIManager; +import javax.swing.plaf.BorderUIResource; +import javax.swing.plaf.ColorUIResource; +import org.jackhuang.hmcl.laf.utils.IconFactory; +import org.jackhuang.hmcl.laf.utils.UI; + +/** + * The Class __UI__. + */ +public class __UI__ extends UI { + + private static final IconFactory ICON = new IconFactory("tree"); + + public static void uiImpl() { + //文件查看列表的边框实现 + put("FileChooser.listViewBorder", new org.jackhuang.hmcl.laf.scroll.ScrollPaneBorder()); + //此颜色将决定windows平台下文件选择面板的左边WindowsPlaceBar的背景色 + putColor("ToolBar.shadow", 249, 248, 243); + put("FileChooserUI", BEFileChooserUI.class); + + UIManager.put("FileView.directoryIcon", ICON.get("closed")); + UIManager.put("FileView.fileIcon", ICON.get("leaf")); + + /* + "FileView.directoryIcon", new SwingLazyValue("javax.swing.plaf.metal.MetalIconFactory", "getTreeFolderIcon"), + "FileView.fileIcon", new SwingLazyValue("javax.swing.plaf.metal.MetalIconFactory", "getTreeLeafIcon"), + "FileView.computerIcon", new SwingLazyValue("javax.swing.plaf.metal.MetalIconFactory", "getTreeComputerIcon"), + "FileView.hardDriveIcon", new SwingLazyValue("javax.swing.plaf.metal.MetalIconFactory", "getTreeHardDriveIcon"), + "FileView.floppyDriveIcon", new SwingLazyValue("javax.swing.plaf.metal.MetalIconFactory", "getTreeFloppyDriveIcon"), + + // File Chooser + "FileChooser.detailsViewIcon", new SwingLazyValue("javax.swing.plaf.metal.MetalIconFactory", "getFileChooserDetailViewIcon"), + "FileChooser.homeFolderIcon", new SwingLazyValue("javax.swing.plaf.metal.MetalIconFactory", "getFileChooserHomeFolderIcon"), + "FileChooser.listViewIcon", new SwingLazyValue("javax.swing.plaf.metal.MetalIconFactory", "getFileChooserListViewIcon"), + "FileChooser.newFolderIcon", new SwingLazyValue("javax.swing.plaf.metal.MetalIconFactory", "getFileChooserNewFolderIcon"), + "FileChooser.upFolderIcon", new SwingLazyValue("javax.swing.plaf.metal.MetalIconFactory", "getFileChooserUpFolderIcon"), + */ + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/internalframe/BEDesktopIconUI.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/internalframe/BEDesktopIconUI.java new file mode 100644 index 000000000..13d581d75 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/internalframe/BEDesktopIconUI.java @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * BEDesktopIconUI.java at 2015-2-1 20:25:36, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.internalframe; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Insets; + +import javax.swing.JComponent; +import javax.swing.UIManager; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicDesktopIconUI; + +/** + * 内部窗体最小化时的图标ui实现类. + * + * @author Jack Jiang(jb2011@163.com) + * @see com.sun.java.swing.plaf.windows.WindowsDesktopIconUI + */ +public class BEDesktopIconUI extends BasicDesktopIconUI { + + private int width; + + public static ComponentUI createUI(JComponent c) { + return new BEDesktopIconUI(); + } + + /** + * {@inheritDoc} + * + * @see com.sun.java.swing.plaf.windows.WindowsDesktopIconUI#installDefaults + */ + @Override + public void installDefaults() { + super.installDefaults(); + width = UIManager.getInt("DesktopIcon.width"); + } + + @Override + public void installUI(JComponent c) { + super.installUI(c); + c.setOpaque(false); + } + + /** + * {@inheritDoc} + * + * @see com.sun.java.swing.plaf.windows.WindowsDesktopIconUI#uninstallUI + */ + @Override + public void uninstallUI(JComponent c) { + BEInternalFrameTitlePane thePane = (BEInternalFrameTitlePane) iconPane; + super.uninstallUI(c); + thePane.uninstallListeners(); + } + + @Override + protected void installComponents() { + iconPane = new BEInternalFrameTitlePane(frame) { + @Override + protected void paintTitlePaneImpl(Insets frameInsets, Graphics g, + int width, int height, boolean isSelected) { + //** Swing BUG补尝:重写父类的目的就是想用Insets(0,0,0,0)来调用paintTitlePaneImpl(否则因 + //** BasicInternalFrameTitlePane中的布局bug,将会导致填充错位) + Insets instes = new Insets(0, 0, 0, 0); + super.paintTitlePaneImpl(instes, g, width, height, isSelected); + } + }; + desktopIcon.setLayout(new BorderLayout()); + desktopIcon.add(iconPane, BorderLayout.CENTER); + desktopIcon.setBorder(UIManager.getBorder("InternalFrame.border")); + } + + /** + * {@inheritDoc} + * + * @see + * com.sun.java.swing.plaf.windows.WindowsDesktopIconUI#getPreferredSize(javax.swing.JComponent) + */ + @Override + public Dimension getPreferredSize(JComponent c) { + // Windows desktop icons can not be resized. Therefore, we should + // always return the minimum size of the desktop icon. See + // getMinimumSize(JComponent c). + return getMinimumSize(c); + } + + /** + * Windows desktop icons are restricted to a width of 160 pixels by default. + * This value is retrieved by the DesktopIcon.width property. + * + * @param c the c + * @return the minimum size + * @see + * com.sun.java.swing.plaf.windows.WindowsDesktopIconUI#getPreferredSize(javax.swing.JComponent) + */ + @Override + public Dimension getMinimumSize(JComponent c) { + //## Bug FIX:see Issue 60(https://code.google.com/p/beautyeye/issues/detail?id=60&can=1) + //## bug起源:此bug源自WindowsDesktopIconUI,BeautyEye因参考了它的实现因而也把该bug带了过来。 + //## 是否解决:已于2012-10-19日由Jack Jiang解决。 + //## bug描述:在某些情况下(比如在cpcns的定制be lnf项目中,它的内部窗口先最大化后再最小化时,该DesptopIcon + //## 的高度就变的较小(与正常状态下有差异),具体原因待深究。 + //## 解决方法:参考MetalDesktopIconUI里的实现,用现在的代码即可解决这个问题。 +// Dimension dim = super.getMinimumSize(c); +// dim.width = width; +// return dim; + return new Dimension(width, + desktopIcon.getLayout().minimumLayoutSize(desktopIcon).height); + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/internalframe/BEInternalFrameTitlePane.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/internalframe/BEInternalFrameTitlePane.java new file mode 100644 index 000000000..05870a6d4 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/internalframe/BEInternalFrameTitlePane.java @@ -0,0 +1,631 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * BEInternalFrameTitlePane.java at 2015-2-1 20:25:36, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.internalframe; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.LayoutManager; +import java.awt.Rectangle; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import javax.swing.Icon; +import javax.swing.JInternalFrame; +import javax.swing.JMenu; +import javax.swing.JOptionPane; +import javax.swing.UIManager; +import javax.swing.border.Border; +import javax.swing.border.EmptyBorder; +import javax.swing.plaf.basic.BasicInternalFrameTitlePane; +import javax.swing.plaf.metal.MetalLookAndFeel; + +import org.jackhuang.hmcl.laf.titlepane.BETitlePane; +import org.jackhuang.hmcl.laf.utils.MySwingUtilities2; +import org.jackhuang.hmcl.laf.utils.WinUtils; + +/** + * 内部窗体的标题栏UI实现. + * + * BeautyEye外观实现中取消了isPalette的所有特殊处理,isPalette及相关属性在 + *该外观中将失去意义,请注意! + *虽然beautyEye是参考自MetalLookAndFeel,但因beautyEye使用了Insets很大的立体边框, + * 则如果还要像MetalLookAndFeel实现Palette类型的JInternalFrame则效果会很难看,干脆就就像 + * WindowsLookAndFeel一样,不去理会什么Palette,在当前的L&F下没有任何减分。 + * + * @see com.sun.java.swing.plaf.windows.WindowsInternalFrameTitlePane + * @author Jack Jiang + */ +public class BEInternalFrameTitlePane extends BasicInternalFrameTitlePane { +// protected boolean isPalette = false; +// protected Icon paletteCloseIcon; +// protected int paletteTitleHeight; + + /** + * The Constant handyEmptyBorder. + */ + private static final Border handyEmptyBorder = new EmptyBorder(0, 0, 0, 0); + + /** + * Key used to lookup Color from UIManager. If this is null, + * getWindowTitleBackground is used. + */ + private String selectedBackgroundKey; + /** + * Key used to lookup Color from UIManager. If this is null, + * getWindowTitleForeground is used. + */ + private String selectedForegroundKey; + /** + * Key used to lookup shadow color from UIManager. If this is null, + * getPrimaryControlDarkShadow is used. + */ + private String selectedShadowKey; + /** + * Boolean indicating the state of the JInternalFrames closable + * property at updateUI time. + */ + private boolean wasClosable; + + /** + * The buttons width. + */ + int buttonsWidth = 0; + + /** + * Instantiates a new bE internal frame title pane. + * + * @param f the f + */ + public BEInternalFrameTitlePane(JInternalFrame f) { + super(f); + } + + @Override + public void addNotify() { + super.addNotify(); + // This is done here instead of in installDefaults as I was worried + // that the BasicInternalFrameUI might not be fully initialized, and + // that if this resets the closable state the BasicInternalFrameUI + // Listeners that get notified might be in an odd/uninitialized state. + updateOptionPaneState(); + } + + @Override + protected void installDefaults() { + super.installDefaults(); + setFont(UIManager.getFont("InternalFrame.titleFont")); +// paletteTitleHeight = UIManager +// .getInt("InternalFrame.paletteTitleHeight"); +// paletteCloseIcon = UIManager.getIcon("InternalFrame.paletteCloseIcon"); + wasClosable = frame.isClosable(); + selectedForegroundKey = selectedBackgroundKey = null; + if (true) + setOpaque(false); + } + + @Override + protected void uninstallDefaults() { + super.uninstallDefaults(); + if (wasClosable != frame.isClosable()) + frame.setClosable(wasClosable); + } + + @Override + protected void createButtons() { + super.createButtons(); + + Boolean paintActive = frame.isSelected() ? Boolean.TRUE : Boolean.FALSE; + iconButton.putClientProperty("paintActive", paintActive); + iconButton.setBorder(handyEmptyBorder); + + maxButton.putClientProperty("paintActive", paintActive); + maxButton.setBorder(handyEmptyBorder); + + closeButton.putClientProperty("paintActive", paintActive); + closeButton.setBorder(handyEmptyBorder); + + // The palette close icon isn't opaque while the regular close icon is. + // This makes sure palette close buttons have the right background. + closeButton.setBackground(MetalLookAndFeel.getPrimaryControlShadow()); + + if (true) { + iconButton.setContentAreaFilled(false); + maxButton.setContentAreaFilled(false); + closeButton.setContentAreaFilled(false); + } + } + + /** + * Override the parent's method to do nothing. Metal frames do not have + * system menus. + */ + @Override + protected void assembleSystemMenu() { + } + + /** + * Override the parent's method to do nothing. Metal frames do not have + * system menus. + * + * @param systemMenu the system menu + */ + @Override + protected void addSystemMenuItems(JMenu systemMenu) { + } + + /** + * Override the parent's method to do nothing. Metal frames do not have + * system menus. + */ + @Override + protected void showSystemMenu() { + } + + /** + * Override the parent's method avoid creating a menu bar. Metal frames do + * not have system menus. + */ + @Override + protected void addSubComponents() { + add(iconButton); + add(maxButton); + add(closeButton); + } + + @Override + protected PropertyChangeListener createPropertyChangeListener() { + return new MetalPropertyChangeHandler(); + } + + @Override + protected LayoutManager createLayout() { + return new XMetalTitlePaneLayout(); + } + + class MetalPropertyChangeHandler extends + BasicInternalFrameTitlePane.PropertyChangeHandler { + + @Override + public void propertyChange(PropertyChangeEvent evt) { + String prop = (String) evt.getPropertyName(); + if (prop.equals(JInternalFrame.IS_SELECTED_PROPERTY)) { + Boolean b = (Boolean) evt.getNewValue(); + iconButton.putClientProperty("paintActive", b); + closeButton.putClientProperty("paintActive", b); + maxButton.putClientProperty("paintActive", b); + } else if ("JInternalFrame.messageType".equals(prop)) { + updateOptionPaneState(); + frame.repaint(); + } + super.propertyChange(evt); + } + } + + class XMetalTitlePaneLayout extends TitlePaneLayout { + + @Override + public void addLayoutComponent(String name, Component c) { + } + + @Override + public void removeLayoutComponent(Component c) { + } + + @Override + public Dimension preferredLayoutSize(Container c) { + return minimumLayoutSize(c); + } + + @Override + public Dimension minimumLayoutSize(Container c) { + // Compute width. + int width = 30; + if (frame.isClosable()) + width += 21; + if (frame.isMaximizable()) + width += 16 + (frame.isClosable() ? 10 : 4); + if (frame.isIconifiable()) + width += 16 + (frame.isMaximizable() ? 2 + : (frame.isClosable() ? 10 : 4)); + FontMetrics fm = frame.getFontMetrics(getFont()); + String frameTitle = frame.getTitle(); + int title_w = frameTitle != null ? MySwingUtilities2.stringWidth( + frame, fm, frameTitle) : 0; + int title_length = frameTitle != null ? frameTitle.length() : 0; + + if (title_length > 2) { + int subtitle_w = MySwingUtilities2.stringWidth(frame, fm, frame + .getTitle().substring(0, 2) + + "..."); + width += (title_w < subtitle_w) ? title_w : subtitle_w; + } else + width += title_w; + + // Compute height. + int height = 0; + +// if (isPalette) +// { +// height = paletteTitleHeight; +// } +// else + { + int fontHeight = fm.getHeight(); + fontHeight += 4;//默认是 +=7 + Icon icon = frame.getFrameIcon(); + int iconHeight = 0; + if (icon != null) + // SystemMenuBar forces the icon to be 16x16 or less. + iconHeight = Math.min(icon.getIconHeight(), 16); + iconHeight += 5; + height = Math.max(fontHeight, iconHeight) + 5;//默认是 +0,modified by jb2011 2012-06-18 + } + + return new Dimension(width, height); + } + + @Override + public void layoutContainer(Container c) { + boolean leftToRight = WinUtils.isLeftToRight(frame); + + int w = getWidth(); + int x = leftToRight ? w : 0; + int y = 5;//默认是0,modified by jb2011 + int spacing; + + // assumes all buttons have the same dimensions + // these dimensions include the borders + int buttonHeight = closeButton.getIcon().getIconHeight(); + int buttonWidth = closeButton.getIcon().getIconWidth(); + + if (frame.isClosable()) // if (isPalette) + // { + // spacing = 3; + // x += leftToRight ? -spacing - (buttonWidth + 2) : spacing; + // closeButton.setBounds(x, y, buttonWidth + 2, + // getHeight() - 4); + // if (!leftToRight) + // x += (buttonWidth + 2); + // } + // else + { + spacing = 4; + x += leftToRight ? -spacing - buttonWidth : spacing; + closeButton.setBounds(x, y, buttonWidth, buttonHeight); + if (!leftToRight) + x += buttonWidth; + } + + if (frame.isMaximizable())// && !isPalette) + { + spacing = frame.isClosable() ? 2 : 4; //10 : 40 + x += leftToRight ? -spacing - buttonWidth : spacing; + maxButton.setBounds(x, y, buttonWidth, buttonHeight); + if (!leftToRight) + x += buttonWidth; + } + + if (frame.isIconifiable())// && !isPalette) + { + spacing = frame.isMaximizable() ? 2 : (frame.isClosable() ? 10 + : 4); + x += leftToRight ? -spacing - buttonWidth : spacing; + iconButton.setBounds(x, y, buttonWidth, buttonHeight); + if (!leftToRight) + x += buttonWidth; + } + + buttonsWidth = leftToRight ? w - x : x; + } + } + +// public void paintPalette(Graphics g) +// { +// boolean leftToRight = WinUtils.isLeftToRight(frame); +// +// int width = getWidth(); +// int height = getHeight(); +// +// Color background = MetalLookAndFeel.getPrimaryControlShadow(); +// Color darkShadow = MetalLookAndFeel.getPrimaryControlDarkShadow(); +// +// NLTitlePane.paintTitlePane(g, 0, 0, width , height, false +// , background, darkShadow); +// } + + @Override + public void paintComponent(Graphics g) { +// if (isPalette) +// { +// paintPalette(g); +// return; +// } + + boolean leftToRight = WinUtils.isLeftToRight(frame); + boolean isSelected = frame.isSelected();//! 选中与否的判断方式,参见border部分的注释 + + int width = getWidth(); + int height = getHeight(); + + Color background = null; + Color foreground = null; + Color shadow = null; + + if (isSelected) { +// if (!true) +// { +// closeButton.setContentAreaFilled(true); +// maxButton.setContentAreaFilled(true); +// iconButton.setContentAreaFilled(true); +// } + if (selectedBackgroundKey != null) + background = UIManager.getColor(selectedBackgroundKey); + if (background == null) + background = UIManager.getColor("activeCaption"); + if (selectedForegroundKey != null) + foreground = UIManager.getColor(selectedForegroundKey); + if (selectedShadowKey != null) + shadow = UIManager.getColor(selectedShadowKey); + if (shadow == null) + shadow = UIManager.getColor("activeCaptionBorder"); + if (foreground == null) + foreground = UIManager.getColor("activeCaptionText"); + } else { + if (!true) { + closeButton.setContentAreaFilled(false); + maxButton.setContentAreaFilled(false); + iconButton.setContentAreaFilled(false); + } + background = UIManager.getColor("inactiveCaption"); + foreground = UIManager.getColor("inactiveCaptionText"); + shadow = UIManager.getColor("inactiveCaptionBorder"); + } + + //---------------------------------------------------绘制标题栏背景 +// Color topDarkShadow2 = LNFUtils.getColor( +// background, -40, -40, -40) +// ,topHightLight2 = LNFUtils.getColor(background, +// 60, 60, 60) +// ,topDarkHightLight2 = LNFUtils.getColor(background, +// 20, 20, 20); + /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 绘制标题栏背景START */ + /* + * ** bug修正 by js,2009-09-30(这因是JDK1.5的Swing底层BUG) + * + * BUG描述:当操作系统的主题切换时,JInternalFrame有时相同的方法this.getBounds()获得的结果是不一样的 + * ,这种差异主要在于有时this.getBounds()获得的结果并未包括它的border,主要表现就是结果 + * 的(x,y)的坐标是未包含border的坐标,因而这种情况下它的(x=0,y=0),而正确应该 + * (x=border.insets.left,y=border.insets.top),如果无视此bug,则titlePane + * 在填充时会变的丑陋。 + * + * 解决方法:当确知这个bug发生后,只能以人工方式弥补这种异相,如 强制修正其(x,y)的坐标,并相应地调整 + * titlePane的填充区域。 + */ +// Border b=frame.getBorder(); +// Insets is=b.getBorderInsets(frame); +// Rectangle bounds = this.getBounds(); +// int paintTitlePaneX = bounds.x,paintTitlePaneY = bounds.y; +//// boolean isBUG = false; +////// System.out.println("JInternalFrame的UI是否处于正常isBUG="+isBUG); +//// if(isBUG=(is.left!=bounds.x))//当is.left!=bounds.x即可认定已经产生了BUG +//// paintTitlePaneX = is.left; +//// if(isBUG=(is.top!=bounds.y))//当is.left!=bounds.x同样可认定已经产生了BUG +//// paintTitlePaneY = is.top; +//// if(isBUG)//有BUG时的填充 +//// { +//// //----------------------------- 以下代码是为了弥补因BUG而产生的填充异常 +//// //*以下(1),(2),(3)部分代码是用于弥补BUG下的border外观被titlePane覆盖的错误 +//// //*请参见JInternalFrameDialogBorder的边框填充代码(尽量在此处模拟出边框的TOP部分效果)> +//// //水平第一条线(1) +//// g.setColor(topDarkShadow2); +//// g.drawLine(0, 0, width, 0); +//// g.drawLine(0, 1, 0, height);//左坚线 +//// g.drawLine(width, 1, width, height);//右坚线 +//// //水平第二条线(2) +//// g.setColor(topHightLight2); +//// g.drawLine(1, 1, width-NLMetalBorders.InternalFrameDialogBorder.insets.left, 1); +//// //水平第三条线(3) +//// g.setColor(topDarkHightLight2); +//// g.drawLine(2, 2, width-NLMetalBorders.InternalFrameDialogBorder.insets.left, 2); +//// +//// NLTitlePane.paintTitlePane(g//左右空起的部分由Border绘制 +//// , paintTitlePaneX//ZCMetalBorders.InternalFrameDialogBorder.insets.left +//// , paintTitlePaneY//ZCMetalBorders.InternalFrameDialogBorder.insets.left +//// , width-is.left*2 //注意此处也因BUG而作了填充区域的调整 +//// , height, isSelected +//// , background, shadow); +//// //----------------------------- END +//// } +//// //正常无BUG时的填充 +//// else + { + Insets frameInsets = frame.getInsets(); + //** Swing BUG:按理说,此处是不需要传入frameInstes的,因父类BasicInternalFrameTitlePane的布局 + //是存在BUG(布计算时没有把BorderInstes算入到x、y的偏移中,导致UI中paint时只能自行 + //进行增益,否则填充的图璩形肯定就因没有算上borderInstes而错位,详见父类中的 + //BasicInternalFrameTitlePane中内部类Handler的layoutContainer方法里 + //getNorthPane().setBounds(..)这一段 +// NLTitlePane.paintTitlePane(g +// , frameInsets.left//0 +// , frameInsets.top//0 +// , width-frameInsets.left-frameInsets.right//-0 +// , height, isSelected +//// , background, shadow +// ); + paintTitlePaneImpl(frameInsets, g, width, height, isSelected); + } + /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 绘制标题栏背景END */ + + //----------------------------------------------------绘制标题及图标 + int titleLength = 0; + int xOffset = leftToRight ? 5 : width - 5; + String frameTitle = frame.getTitle(); + + Icon icon = frame.getFrameIcon(); + if (icon != null) { + if (!leftToRight) + xOffset -= icon.getIconWidth(); + int iconY = ((height / 2) - (icon.getIconHeight() / 2)); + icon.paintIcon(frame, g, xOffset + 2, iconY + 1);//默认是xOffset +0, iconY+0 + xOffset += leftToRight ? icon.getIconWidth() + 5 : -5; + } + + if (frameTitle != null) { + Font f = getFont(); + g.setFont(f); + FontMetrics fm = MySwingUtilities2.getFontMetrics(frame, g, f); + int fHeight = fm.getHeight(); + + int yOffset = ((height - fm.getHeight()) / 2) + fm.getAscent(); + + Rectangle rect = new Rectangle(0, 0, 0, 0); + if (frame.isIconifiable()) + rect = iconButton.getBounds(); + else if (frame.isMaximizable()) + rect = maxButton.getBounds(); + else if (frame.isClosable()) + rect = closeButton.getBounds(); + int titleW; + + if (leftToRight) { + if (rect.x == 0) + rect.x = frame.getWidth() - frame.getInsets().right - 2; + titleW = rect.x - xOffset - 4; + frameTitle = getTitle(frameTitle, fm, titleW); + } else { + titleW = xOffset - rect.x - rect.width - 4; + frameTitle = getTitle(frameTitle, fm, titleW); + xOffset -= MySwingUtilities2.stringWidth(frame, fm, frameTitle); + } + + titleLength = MySwingUtilities2.stringWidth(frame, fm, frameTitle); + +// g.setColor(Color.DARK_GRAY);// +// NLUtils.drawString(frame, g, frameTitle, xOffset+1, yOffset+1); + g.setColor(foreground); +// if(NLLookAndFeel.windowTitleAntialising) +// NLLookAndFeel.setAntiAliasing((Graphics2D) g,true); + MySwingUtilities2.drawString(frame, g, frameTitle, xOffset, yOffset); +// if(NLLookAndFeel.windowTitleAntialising) +// NLLookAndFeel.setAntiAliasing((Graphics2D) g,false); + xOffset += leftToRight ? titleLength + 5 : -5; + } + } + + /** + * Paint title pane impl. + * + * @param frameInsets the frame insets + * @param g the g + * @param width the width + * @param height the height + * @param isSelected the is selected + */ + protected void paintTitlePaneImpl(Insets frameInsets, Graphics g, + int width, int height, boolean isSelected) { + BETitlePane.paintTitlePane(g, + frameInsets.left//0 + , + frameInsets.top//0 + , + width - frameInsets.left - frameInsets.right//-0 + , + height, isSelected + // , background, shadow + ); + } + +// public void setPalette(boolean b) +// { +// isPalette = b; +// +// if (isPalette) +// { +// closeButton.setIcon(paletteCloseIcon); +// if (frame.isMaximizable()) +// remove(maxButton); +// if (frame.isIconifiable()) +// remove(iconButton); +// } +// else +// { +// closeButton.setIcon(closeIcon); +// if (frame.isMaximizable()) +// add(maxButton); +// if (frame.isIconifiable()) +// add(iconButton); +// } +// revalidate(); +// repaint(); +// } + /** + * Updates any state dependant upon the JInternalFrame being shown in a + * JOptionPane. + */ + private void updateOptionPaneState() { + int type = -2; + boolean closable = wasClosable; + Object obj = frame.getClientProperty("JInternalFrame.messageType"); + + if (obj == null) + // Don't change the closable state unless in an JOptionPane. + return; + if (obj instanceof Integer) + type = ((Integer) obj).intValue(); + switch (type) { + case JOptionPane.ERROR_MESSAGE: + selectedBackgroundKey = "OptionPane.errorDialog.titlePane.background"; + selectedForegroundKey = "OptionPane.errorDialog.titlePane.foreground"; + selectedShadowKey = "OptionPane.errorDialog.titlePane.shadow"; + closable = false; + break; + case JOptionPane.QUESTION_MESSAGE: + selectedBackgroundKey = "OptionPane.questionDialog.titlePane.background"; + selectedForegroundKey = "OptionPane.questionDialog.titlePane.foreground"; + selectedShadowKey = "OptionPane.questionDialog.titlePane.shadow"; + closable = false; + break; + case JOptionPane.WARNING_MESSAGE: + selectedBackgroundKey = "OptionPane.warningDialog.titlePane.background"; + selectedForegroundKey = "OptionPane.warningDialog.titlePane.foreground"; + selectedShadowKey = "OptionPane.warningDialog.titlePane.shadow"; + closable = false; + break; + case JOptionPane.INFORMATION_MESSAGE: + case JOptionPane.PLAIN_MESSAGE: + selectedBackgroundKey = selectedForegroundKey = selectedShadowKey = null; + closable = false; + break; + default: + selectedBackgroundKey = selectedForegroundKey = selectedShadowKey = null; + break; + } + if (closable != frame.isClosable()) + frame.setClosable(closable); + } + + /** + * {@inheritDoc} + * + * 改变父类的方法的可见性为public,方便外界调用,仅此而已. + */ + @Override + public void uninstallListeners() { + super.uninstallListeners(); + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/internalframe/BEInternalFrameUI.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/internalframe/BEInternalFrameUI.java new file mode 100644 index 000000000..e2ae2fdf9 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/internalframe/BEInternalFrameUI.java @@ -0,0 +1,225 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * BEInternalFrameUI.java at 2015-2-1 20:25:37, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.internalframe; + +import java.awt.Container; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import javax.swing.ActionMap; +import javax.swing.JComponent; +import javax.swing.JInternalFrame; +import javax.swing.LookAndFeel; +import javax.swing.SwingUtilities; +import javax.swing.border.Border; +import javax.swing.border.EmptyBorder; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.UIResource; +import javax.swing.plaf.basic.BasicInternalFrameUI; + +/** + * 内部窗体UI实现类. + * + * BeautyEye外观实现中取消了isPalette的所有特殊处理,isPalette及相关属性在 + * 该外观中将失去意义,请注意。 + * + * @author Jack Jiang + */ +public class BEInternalFrameUI extends BasicInternalFrameUI { + + /** + * The title pane. + */ + private BEInternalFrameTitlePane titlePane; + + /** + * The Constant metalPropertyChangeListener. + */ + private static final PropertyChangeListener metalPropertyChangeListener = new XZCMetalPropertyChangeHandler(); + + /** + * The Constant handyEmptyBorder. + */ + private static final Border handyEmptyBorder = new EmptyBorder(0, 0, 0, 0); + +// protected static String IS_PALETTE = "JInternalFrame.isPalette"; + /** + * The FRAM e_ type. + */ + private static String FRAME_TYPE = "JInternalFrame.frameType"; + + /** + * The NORMA l_ frame. + */ + private static String NORMAL_FRAME = "normal"; +// private static String PALETTE_FRAME = "palette"; + /** + * The OPTIO n_ dialog. + */ + private static String OPTION_DIALOG = "optionDialog"; + + /** + * Instantiates a new bE internal frame ui. + * + * @param b the b + */ + public BEInternalFrameUI(JInternalFrame b) { + super(b); + } + + public static ComponentUI createUI(JComponent c) { + return new BEInternalFrameUI((JInternalFrame) c); + } + + @Override + public void installUI(JComponent c) { + super.installUI(c); + +// Object paletteProp = c.getClientProperty(IS_PALETTE); +// if (paletteProp != null) +// { +// setPalette(((Boolean) paletteProp).booleanValue()); +// } + Container content = frame.getContentPane(); + stripContentBorder(content); + //c.setOpaque(false); + + frame.setOpaque(false); + } + + @Override + public void uninstallUI(JComponent c) { + frame = (JInternalFrame) c; + + Container cont = ((JInternalFrame) (c)).getContentPane(); + if (cont instanceof JComponent) { + JComponent content = (JComponent) cont; + if (content.getBorder() == handyEmptyBorder) + content.setBorder(null); + } + super.uninstallUI(c); + } + + @Override + protected void installListeners() { + super.installListeners(); + frame.addPropertyChangeListener(metalPropertyChangeListener); + } + + @Override + protected void uninstallListeners() { + frame.removePropertyChangeListener(metalPropertyChangeListener); + super.uninstallListeners(); + } + + @Override + protected void installKeyboardActions() { + super.installKeyboardActions(); + ActionMap map = SwingUtilities.getUIActionMap(frame); + if (map != null) + // BasicInternalFrameUI creates an action with the same name, we override + // it as Metal frames do not have system menus. + map.remove("showSystemMenu"); + } + + @Override + protected void uninstallKeyboardActions() { + super.uninstallKeyboardActions(); + } + + @Override + protected void uninstallComponents() { + titlePane = null; + super.uninstallComponents(); + } + + /** + * Strip content border. + * + * @param c the c + */ + private void stripContentBorder(Object c) { + if (c instanceof JComponent) { + JComponent contentComp = (JComponent) c; + Border contentBorder = contentComp.getBorder(); + if (contentBorder == null || contentBorder instanceof UIResource) + contentComp.setBorder(handyEmptyBorder); + } + } + + @Override + protected JComponent createNorthPane(JInternalFrame w) { + titlePane = new BEInternalFrameTitlePane(w); + return titlePane; + } + + /** + * Sets the frame type. + * + * @param frameType the new frame type + */ + private void setFrameType(String frameType) { + if (frameType.equals(OPTION_DIALOG)) + LookAndFeel.installBorder(frame, "InternalFrame.optionDialogBorder"); // titlePane.setPalette(false); +// else if (frameType.equals(PALETTE_FRAME)) +// { +// LookAndFeel.installBorder(frame, "InternalFrame.paletteBorder"); +//// titlePane.setPalette(true); +// } + else + LookAndFeel.installBorder(frame, "InternalFrame.border"); // titlePane.setPalette(false); + } + +// // this should be deprecated - jcs +// public void setPalette(boolean isPalette) +// { +//// if (isPalette) +//// { +//// LookAndFeel.installBorder(frame, "InternalFrame.paletteBorder"); +//// } +//// else +// { +// LookAndFeel.installBorder(frame, "InternalFrame.border"); +// } +//// titlePane.setPalette(isPalette); +// } + private static class XZCMetalPropertyChangeHandler implements + PropertyChangeListener { + + @Override + public void propertyChange(PropertyChangeEvent e) { + String name = e.getPropertyName(); + JInternalFrame jif = (JInternalFrame) e.getSource(); + + if (!(jif.getUI() instanceof BEInternalFrameUI)) + return; + + BEInternalFrameUI ui = (BEInternalFrameUI) jif.getUI(); + if (name.equals(FRAME_TYPE)) { + if (e.getNewValue() instanceof String) + ui.setFrameType((String) e.getNewValue()); + } // else if (name.equals(IS_PALETTE)) + // { + // if (e.getNewValue() != null) + // { + // ui.setPalette(((Boolean) e.getNewValue()).booleanValue()); + // } + // else + // { + // ui.setPalette(false); + // } + // } + else if (name.equals(JInternalFrame.CONTENT_PANE_PROPERTY)) + ui.stripContentBorder(e.getNewValue()); + } + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/internalframe/__UI__.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/internalframe/__UI__.java new file mode 100644 index 000000000..bf0043f3a --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/internalframe/__UI__.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * __UI__.java at 2015-2-1 20:25:41, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.internalframe; + +import javax.swing.UIManager; +import javax.swing.plaf.BorderUIResource; + +import org.jackhuang.hmcl.laf.BeautyEyeLNFHelper; +import org.jackhuang.hmcl.laf.utils.IconFactory; +import org.jackhuang.hmcl.laf.utils.UI; +import org.jackhuang.hmcl.laf.widget.border.BEShadowBorder; + +public class __UI__ extends UI { + + private static final IconFactory ICON = new IconFactory("internal_frame"); + + public static void uiImpl() { + //内部窗体的边框颜色(BueaytyEye中无意义,原因是BeautyEye LNF中的border是使用NP图实现) + put("InternalFrame.borderColor", BeautyEyeLNFHelper.commonBackgroundColor); + put("InternalFrame.minimizeIconBackground", BeautyEyeLNFHelper.commonBackgroundColor); +// UIManager.put("InternalFrame.paletteCloseIcon", ICON.get("close")); //本属性在beautyEye中不会起效的 + UIManager.put("InternalFrame.icon", ICON.get("icon")); + UIManager.put("InternalFrame.iconifyIcon", ICON.get("iconify")); + UIManager.put("InternalFrame.minimizeIcon", ICON.get("min")); + UIManager.put("InternalFrame.maximizeIcon", ICON.get("max")); + UIManager.put("InternalFrame.closeIcon", ICON.get("close")); + put("InternalFrameUI", BEInternalFrameUI.class); +// put("InternalFrame.paletteTitleHeight", 40); //本属性在beautyEye中不会起效的 +// put("InternalFrame.titlePaneHeight", 38); //default is 25 +// put("InternalFrame.borderWidth", 10); + Object internalFrameBorder = new BorderUIResource(new BEShadowBorder()); + UIManager.put("InternalFrame.border", internalFrameBorder); + UIManager.put("InternalFrame.paletteBorder", internalFrameBorder); + UIManager.put("InternalFrame.optionDialogBorder", internalFrameBorder); + + //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> JDesktopPane相关ui属性设定 + //JDesktopPane的背景色 + put("Desktop.background", BeautyEyeLNFHelper.commonBackgroundColor); + //此属性暂无意义 +// putInsetc("Desktop.minOnScreenInsets", 10, 10, 10, 10);//default is 3,3,3,3 + //JDesktopPane中内部窗体最小化时的窗体组件宽度 + put("DesktopIcon.width", 180); //默认是160 + //BeautyEye LNF中内部窗体标题栏实现 + put("DesktopIconUI", BEDesktopIconUI.class); + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/list/BEListUI.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/list/BEListUI.java new file mode 100644 index 000000000..1dffd6dbe --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/list/BEListUI.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * BEListUI.java at 2015-2-1 20:25:40, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.list; + +import javax.swing.CellRendererPane; +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicListUI; + +/** + * JList的UI实现类. + * + * @author Jack Jiang(jb2011@163.com) + * @version 1.0 + */ +public class BEListUI extends BasicListUI { + + public static ComponentUI createUI(JComponent c) { + return new BEListUI(); + } + + /** + * Initialize JList properties, e.g. font, foreground, and background, and + * add the CellRendererPane. The font, foreground, and background properties + * are only set if their current value is either null or a UIResource, other + * properties are set if the current value is null. + * + * @see #uninstallDefaults + * @see #installUI + * @see CellRendererPane + */ + @Override + protected void installDefaults() { + super.installDefaults(); + + //2012-08-30*******************************************************【重要说明】 START 对应BEComboBoxUI中的【重要说明】 + //* 【重要说明】因BEListUI中为了使列表行单元高变的更高(在MyDefaultListCellRenderer.java中 + //* 像COmboxRender一样通过增到border不起效果,它可能是BasicListUI的设计缺陷,它要么取FixedCellHeight + //* 固定值,要么取getPreferSize()即自动计算高度——它似乎是不计入border的,所以render设置border不起效) + //* 所以只能为列表单元设置因定值:list.setFixedCellHeight(30),但它将影响Combox里的行高(也会变成30高) + //* 所以BEComboBoxUI中要把本列表UI中强制设定的30高针对Combox还原成自动计算(API中规定FixedCellHeight==-1即表示自动计算) + //*************************************************************** 【重要说明】 END + //* 则jb2011加入,表示列表单元固定高度,默认值=-1(即意味着行高自动计算) + //* 使用BE LNF的项目,如要恢复行高算动计算则显示设置列表的固定行高为-1即可! + list.setFixedCellHeight(27);//32//30);// TODO 此设置值作一个UIManager属性就可以方便以后设置了,-1是原系统默认值哦(即自动计算单元高) + + //* 不需要了,它样强制要求它为透明可能会影响以后用户的定制需求,干脆 + //* 设置它的背景为认白色,也能达到想到的N9白色背景 +// //此设置将取消列表背景的绘制(以便BE LNF中绘制N9背景图哦) +// list.setOpaque(false); + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/list/MyDefaultListCellRenderer.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/list/MyDefaultListCellRenderer.java new file mode 100644 index 000000000..fdfbe16a5 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/list/MyDefaultListCellRenderer.java @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * MyDefaultListCellRenderer.java at 2015-2-1 20:25:36, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.list; + +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Graphics2D; + +import javax.swing.DefaultListCellRenderer; +import javax.swing.JList; +import org.jackhuang.hmcl.laf.utils.Icon9Factory; + +/** + * 列表单元的默认renderer实现类. + * + * @author Jack Jiang(jb2011@163.com), 2012-08-30 + * @version 1.0 + */ +public class MyDefaultListCellRenderer extends DefaultListCellRenderer { + + private static final Icon9Factory ICON_9 = new Icon9Factory("list"); + + /** + * The is selected. + */ + protected boolean isSelected = false; + + /** + * The is focuesed. + */ + protected boolean isFocuesed = false; + + /** + * Instantiates a new my default list cell renderer. + */ + public MyDefaultListCellRenderer() { + //设置成透明背景则意味着不需要背景填充,但本类中的应用场景有点特殊 + //——默认的render的UI里不需要绘制背景的情况下本类才可进行NinePatch图作为背景进行填充 + setOpaque(false); + + //** 要像Combox的render一样设置border没用,因为列表单元不获得焦点时的border由UIManager属性List.cellNoFocusBorder决定 +// //注:此内衬是决定列表单元间的上下左右空白的关键哦! +// setBorder(BorderFactory.createEmptyBorder(5, 8, 5, 8)); + } + + @Override + public void paintComponent(Graphics g) { + if (isSelected) + //注意:2012-09-03日用的该图片右边有一个像素的空白哦,其实它是可以通过List.border的UI属性来调整的 + //之所以没有用它调整就是为了日后可以使用N9图来自由调整而无需调整代码(List.border的代码没置) + ICON_9.get("selected_icon_bg") + .draw((Graphics2D) g, 0, 0, this.getWidth(), this.getHeight()); + else { +// g.setColor(this.getBackground()); +// //本Insets取this.getInsets()是符合Sun的设计初衷的,但是不合理(本身isPopupVisible==false +// //时的背景就是特殊情况,不能与下拉项同等视之),所以此处用自定义的Insets来处理则在UI展现上更为合理 。 +// //TODO 这个Instes可以作为UI属性“ComboBox.popupNoVisibleBgInstes”方便以后设置,暂时先硬编码吧,以后再说 +// Insets is = new Insets(2,3,2,3);//this.getInsets(); +//// g.fillRect(is.left, is.top +//// , this.getWidth()-is.left-is.right +//// , this.getHeight()-is.top-is.bottom); +// BEUtils.fillTextureRoundRec((Graphics2D)g, this.getBackground(), is.left, is.top +// , this.getWidth()-is.left-is.right +// , this.getHeight()-is.top-is.bottom,20,0);//20,20 + } +// else + //注意:本组件已经被设置成opaque=false即透明,否则本方法还会填充默认背景,那么选中时的 + //N9图背景因先绘将会被覆盖哦。所以要使用N9图作为选中时的背景则前提是本组件必须是透明 + super.paintComponent(g); + } + + @Override + public Component getListCellRendererComponent( + JList list, + Object value, + int index, + boolean isSelected, + boolean cellHasFocus) { + Component c = super.getListCellRendererComponent(list, + value, index, isSelected, cellHasFocus); + + this.isSelected = isSelected; + this.isFocuesed = cellHasFocus; + return c; + } + + /** + * A subclass of DefaultListCellRenderer that implements UIResource. + * DefaultListCellRenderer doesn't implement UIResource directly so that + * applications can safely override the cellRenderer property with + * DefaultListCellRenderer subclasses. + *

+ * Warning: + * Serialized objects of this class will not be compatible with future Swing + * releases. The current serialization support is appropriate for short term + * storage or RMI between applications running the same version of Swing. As + * of 1.4, support for long term storage of all + * JavaBeansTM + * has been added to the java.beans package. Please see + * {@link java.beans.XMLEncoder}. + */ + public static class UIResource extends MyDefaultListCellRenderer + implements javax.swing.plaf.UIResource { + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/list/__UI__.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/list/__UI__.java new file mode 100644 index 000000000..beffd70d9 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/list/__UI__.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * __UI__.java at 2015-2-1 20:25:40, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.list; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Insets; + +import javax.swing.UIManager; +import javax.swing.border.AbstractBorder; + +import org.jackhuang.hmcl.laf.BeautyEyeLNFHelper; +import org.jackhuang.hmcl.laf.utils.UI; + +public class __UI__ extends UI { + + public static void uiImpl() { + //通过此border可以调整整个列表的上下左右的空白 + putBorder("List.border", 0, 0, 0, 0); + //本属性将决定已被选中的列表单元显示文本的上下左右空白哦 + putBorder("List.focusCellHighlightBorder", 1, 8, 5, 3); + /* ~~注:这个属性是jb2011为了更好的ui效果自已加的属性 */ + putColor("List.focusSelectedCellHighlightBorderColor", 252, 87, 84); //Color.red + /* ~~注:这个属性是jb2011为了更好的ui效果自已加的属性,目的是使List.focusSelectedCellHighlightBorderColor有点立体效果哦 */ + putColor("List.focusSelectedCellHighlightBorderHighlightColor", 255, 255, 255, 70);//注意:这个颜色是半透明的哦 + //列表单元获得焦点时的边框(windows主题下是一个距形虚线框)——之前老也想不通的与左边隔一个像素的白边问题就是没设置它造成的 + put("List.focusSelectedCellHighlightBorder", new FocusSelectedCellHighlightBorder()); + //将决定正状态下的列表单元显示文本的上下左右空白哦 + putBorder("List.cellNoFocusBorder", 1, 8, 5, 3); + + put("List.background", Color.white); + put("List.foreground", BeautyEyeLNFHelper.commonForegroundColor); + put("List.selectionForeground", Color.white);//fgColor); + put("List.selectionBackground", BeautyEyeLNFHelper.commonSelectionBackgroundColor); + + UIManager.put("List.cellRenderer", new MyDefaultListCellRenderer.UIResource()); + put("ListUI", BEListUI.class); + } + + /** + * 本border由Jack Jiang实现,它是列表单元获得焦点时的边框(windows外观 + * 下是一个距形虚线框),本border当前的样式是在在最左边画的一条红色竖线 + */ + static class FocusSelectedCellHighlightBorder extends AbstractBorder { + + @Override + public Insets getBorderInsets(Component c) { + //Insets跟List.focusCellHighlightBorder 一样即可,这样就能在视觉上保持一致罗(不一样则会有移位的难看效果)! + return UIManager.getBorder("List.focusCellHighlightBorder").getBorderInsets(c); + } + + @Override + public Insets getBorderInsets(Component c, Insets insets) { + return getBorderInsets(c); + } + + @Override + public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { + //在左边划一条2像素宽的竖线 + g.setColor(UIManager.getColor("List.focusSelectedCellHighlightBorderColor")); + g.fillRect(x, y + 0, 2, height - 1);//-2);//上下各空白一个像素,目的是为了与render的N9图片背景配合形成更好的视觉效果 + + //再在上面的竖线右边划一条1像素宽的亮色竖线,以便为上面的2像素竖线营造立体效果 + /* ~~注:这个属性是jb2011为了更好的ui效果自已加的属性,目的是使List.focusSelectedCellHighlightBorder有点立体效果哦 */ + g.setColor(UIManager.getColor("List.focusSelectedCellHighlightBorderHighlightColor")); + g.fillRect(x + 2, y + 0, 1, height - 1);//-2); + } + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/menu/BECheckBoxMenuItemUI.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/menu/BECheckBoxMenuItemUI.java new file mode 100644 index 000000000..a395e1daf --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/menu/BECheckBoxMenuItemUI.java @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * BECheckBoxMenuItemUI.java at 2015-2-1 20:25:39, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.menu; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.io.Serializable; + +import javax.swing.AbstractButton; +import javax.swing.ButtonModel; +import javax.swing.Icon; +import javax.swing.JComponent; +import javax.swing.JMenu; +import javax.swing.JMenuItem; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.UIResource; +import javax.swing.plaf.basic.BasicCheckBoxMenuItemUI; +import org.jackhuang.hmcl.laf.utils.IconFactory; + +/** + * JCheckBoxMenuItem的UI实现类. + * + * @author Jack Jiang(jb2011@163.com) + */ +public class BECheckBoxMenuItemUI extends BasicCheckBoxMenuItemUI { + + private static final IconFactory ICON = new IconFactory("menu_check"); + + /** + * 是否强制单项透明(当强制不透明时,在普通状态下该item将不会被绘制背景). + */ + private static boolean enforceTransparent = true; + + public static ComponentUI createUI(JComponent b) { + return new BECheckBoxMenuItemUI(); + } + + @Override + protected void paintBackground(Graphics g, JMenuItem menuItem, + Color bgColor) { +// if (WindowsMenuItemUI.isVistaPainting()) { +// WindowsMenuItemUI.paintBackground(accessor, g, menuItem, bgColor); +// return; +// } +// super.paintBackground(g, menuItem, bgColor); + // see parent! + ButtonModel model = menuItem.getModel(); + Color oldColor = g.getColor(); + int menuWidth = menuItem.getWidth(); + int menuHeight = menuItem.getHeight(); + + Graphics2D g2 = (Graphics2D) g; + + if (model.isArmed() + || (menuItem instanceof JMenu && model.isSelected())) { + g.setColor(bgColor); + + BEMenuUI.drawSelectedBackground(g, 0, 0, menuWidth, menuHeight); + +// /****** 选中的背景样式现在是渐变加圆角填充了,impled by js */ +// NLLookAndFeel.setAntiAliasing(g2, true); +// //矩形填充 +// Paint oldpaint = g2.getPaint(); +// GradientPaint gp = new GradientPaint(0, 0 +// ,GraphicHandler.getColor(bgColor, 35, 35, 35) +// ,0, menuHeight,bgColor +// ); +// g2.setPaint(gp); +// g.fillRoundRect(0, 0, menuWidth, menuHeight,5,5); +// g2.setPaint(oldpaint); +// NLLookAndFeel.setAntiAliasing(g2, false); + } else if (!enforceTransparent) { + g.setColor(menuItem.getBackground()); + g.fillRect(0, 0, menuWidth, menuHeight); + } + g.setColor(oldColor); + } + + /** + * @see + * com.sun.java.swing.plaf.windows.WindowsIconFactory.CheckBoxMenuItemIcon + */ + public static class CheckBoxMenuItemIcon implements Icon, UIResource, Serializable { + + @Override + public void paintIcon(Component c, Graphics g, int x, int y) { + g.drawImage(ICON.get(((AbstractButton) c).getModel().isSelected() ? "checked" : "normal").getImage(), + x - 4, y - 3, null); + } + + @Override + public int getIconWidth() { + return 16; + }// default 9 + + @Override + public int getIconHeight() { + return 16; + }// default 9 + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/menu/BEMenuBarUI.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/menu/BEMenuBarUI.java new file mode 100644 index 000000000..fcb8b847c --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/menu/BEMenuBarUI.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * BEMenuBarUI.java at 2015-2-1 20:25:37, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.menu; + +import java.awt.Graphics; + +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicMenuBarUI; + +/** + * JMenuBar的UI实现类. + * + * @author Jack Jiang(jb2011@163.com) + * @see com.sun.java.swing.plaf.windows.WindowsMenuBarUI + */ +public class BEMenuBarUI extends BasicMenuBarUI { + + public static ComponentUI createUI(JComponent x) { + return new BEMenuBarUI(); + } + + @Override + public void paint(Graphics g, JComponent c) { + int width = c.getWidth(); + int height = c.getHeight(); + + //背景划一个灰色底线(方便与JMenuBar的顶层菜单项的底色融合) + g.setColor(BEMenuUI.MENU_UNSELECTED_UNDERLINE_COLOR); + g.fillRect(0, height - BEMenuUI.DECORATED_UNDERLINE_HEIGHT, width, height); + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/menu/BEMenuItemUI.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/menu/BEMenuItemUI.java new file mode 100644 index 000000000..ca364459d --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/menu/BEMenuItemUI.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * BEMenuItemUI.java at 2015-2-1 20:25:38, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.menu; + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Graphics2D; + +import javax.swing.ButtonModel; +import javax.swing.JComponent; +import javax.swing.JMenu; +import javax.swing.JMenuItem; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicMenuItemUI; + +/** + * JMenuItem的UI实现类. + * + * 特别注意:BasicMenuItemUI中针对Vista及后来的Windows版本预设了很多其它LNF不需要的属性, + * 预设的属性详见BasicMenuItemUI及WindowsLookAndFeel中的initVistaComponentDefaults(..)方法. + * 这些属性只能会在vista及更新的windows平台上过运行时才会起效,所以除此之外的windows测不出来, + * 容易出现ui视觉差异. + * + * @author Jack Jiang(jb2011@163.com) + */ +public class BEMenuItemUI extends BasicMenuItemUI { + + /** + * 是否强制单项透明(当强制不透明时,在普通状态下该item将不会被绘制背景). + */ + private static boolean enforceTransparent = true;// TODO 可以提炼成UI属性 + + public static ComponentUI createUI(JComponent c) { + return new BEMenuItemUI(); + } + + /** + * {@inheritDoc} + * + * @see com.sun.java.swing.plaf.windows.WindowsMenuItemUI#paintBackground(java.awt.Graphics, javax.swing.JMenuItem, java.awt.Color) + * @see javax.swing.plaf.basic.BasicMenuItemUI#paintBackground(java.awt.Graphics, javax.swing.JMenuItem, java.awt.Color) + */ + @Override + protected void paintBackground(Graphics g, JMenuItem menuItem, Color bgColor) { + ButtonModel model = menuItem.getModel(); + Color oldColor = g.getColor(); + int menuWidth = menuItem.getWidth(); + int menuHeight = menuItem.getHeight(); + + Graphics2D g2 = (Graphics2D) g; + + if (model.isArmed() + || (menuItem instanceof JMenu && model.isSelected())) + //菜单项的样式绘制(用NinePatch图来填充) + BEMenuUI.drawSelectedBackground(g, 0, 0, menuWidth, menuHeight); + else if (!enforceTransparent) { + g.setColor(menuItem.getBackground()); + g.fillRect(0, 0, menuWidth, menuHeight); + } + g.setColor(oldColor); + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/menu/BEMenuUI.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/menu/BEMenuUI.java new file mode 100644 index 000000000..b9d98e42c --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/menu/BEMenuUI.java @@ -0,0 +1,306 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * BEMenuUI.java at 2015-2-1 20:25:40, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.menu; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.event.MouseEvent; + +import javax.swing.ButtonModel; +import javax.swing.Icon; +import javax.swing.JComponent; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.MenuElement; +import javax.swing.UIManager; +import javax.swing.event.MouseInputListener; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicMenuUI; + +import org.jackhuang.hmcl.laf.BEUtils; +import org.jackhuang.hmcl.laf.utils.Icon9Factory; +import org.jackhuang.hmcl.laf.utils.WinUtils; + +/** + * JMenuU的UI实现类. + * + * @author Jack Jiang(jb2011@163.com) + * @see com.sun.java.swing.plaf.windows.WindowsMenuUI + */ +public class BEMenuUI extends BasicMenuUI { + + //JMenuBar的顶层菜单项的装饰底线高度 + public final static int DECORATED_UNDERLINE_HEIGHT = 2;// TODO 可以提炼成Ui属性哦 + + //顶层菜单项被选中的颜色 + public final static Color MENU_SELECTED_UNDERLINE_COLOR = new Color(37, 147, 217);// TODO 可以提炼成Ui属性哦 + + //顶层菜单项未被选中的颜色 + public final static Color MENU_UNSELECTED_UNDERLINE_COLOR = new Color(226, 230, 232);// TODO 可以提炼成Ui属性哦 + + protected Integer menuBarHeight; + + protected boolean hotTrackingOn; + + public static ComponentUI createUI(JComponent x) { + return new BEMenuUI(); + } + + /** + * {@inheritDoc} + * + * @see com.sun.java.swing.plaf.windows.WindowsMenuUI#installDefaults() + */ + @Override + protected void installDefaults() { + super.installDefaults(); +// if (!WindowsLookAndFeel.isClassicWindows()) + { + menuItem.setRolloverEnabled(true); + } + + menuBarHeight = (Integer) UIManager.getInt("MenuBar.height"); + Object obj = UIManager.get("MenuBar.rolloverEnabled"); + hotTrackingOn = (obj instanceof Boolean) ? (Boolean) obj : true; + } + + /** + * Draws the background of the menu. + * + * @param g the g + * @param menuItem the menu item + * @param bgColor the bg color + * @since 1.4 + * + * @see com.sun.java.swing.plaf.windows.WindowsMenuUI#paintBackground(java.awt.Graphics, javax.swing.JMenuItem, java.awt.Color) + */ + @Override + protected void paintBackground(Graphics g, JMenuItem menuItem, Color bgColor) { + JMenu menu = (JMenu) menuItem; + ButtonModel model = menu.getModel(); + + Color oldColor = g.getColor(); + int menuWidth = menu.getWidth(); + int menuHeight = menu.getHeight(); + +// UIDefaults table = UIManager.getLookAndFeelDefaults(); +// Color highlight = table.getColor("controlLtHighlight"); +// Color shadow = table.getColor("controlShadow"); + g.setColor(menu.getBackground()); + g.fillRect(0, 0, menuWidth, menuHeight); + + //给JMEnuBar的顶层菜单项中画一个灰色底线(看起来美观) + //位于菜单项里的MenuItem则不需要画这个底线(要不然不好看哦) + if (menu.isTopLevelMenu()) { + //未选中的装饰底线 + //只要放在MenuBar最顶层的JMenu才需要画哦(从而与底色融为一体) + g.setColor(MENU_UNSELECTED_UNDERLINE_COLOR); + g.fillRect(0, menuHeight - DECORATED_UNDERLINE_HEIGHT, menuWidth, menuHeight); + } + + //* >注意:官方是判断menu.isOpaque()==false时才进入此if-else分支, + //* >其实以下代码的意义是:当是顶级Menu(即直接放在MenuBar上的那层)时 + //* >才需要调用以下分支,而在win7下,以下分支是不会被调用的(WindowsLookAndfeel.initVistaComponentDefaults中 + //* >处理了如果是vista则"MenuItem.opaque", "Menu.opaque", "CheckBoxMenuItem.opaque", "RadioButtonMenuItem.opaque" + //* >默认都设置成了false,即默认透明(官方逻辑可能是透明体就意味着是顶级menu了)!) + //* >,那么win7下将会出现错误的表现:无法区分是不是顶级menu也就无法区别paint出不同的样子了. + //* >那么官方为何没收到bug报告呢?我分析可能还没有人面对到BeautyEye这样需要对Menu进行较复杂样式需求的场景 + //* >,即把顶级menu和内层menu分的很清。 + //* >目前BeautyEye的实现即menu.isTopLevelMenu()==true时即进入本分支 + //* >才是比较合理的,当然,有待实践检验,或许官方有其它考虑。 -- commet by Jack Jiang 2012-09-14 + if (menu.isTopLevelMenu())//menu.isOpaque()) + { + //JMebuBar的顶层菜单项被选中或鼠标停留时 + if (model.isArmed() || model.isSelected()) { + Color c = MENU_SELECTED_UNDERLINE_COLOR; + g.setColor(c); + + //先填充一个装饰3角形(用于在UI上提示用户它被选中了) + // x2,y2 + // + //x1,y1 x3,y3 + int tW = 7, tH = 3; + int x1 = menuWidth / 2 - tW / 2; + int y1 = menuHeight - DECORATED_UNDERLINE_HEIGHT; + int x2 = menuWidth / 2; + int y2 = menuHeight - DECORATED_UNDERLINE_HEIGHT - tH; + int x3 = menuWidth / 2 + tW / 2; + int y3 = menuHeight - DECORATED_UNDERLINE_HEIGHT; + //反走样 + BEUtils.setAntiAliasing((Graphics2D) g, true); + BEUtils.fillTriangle(g, x1, y1, x2, y2, x3, y3, c); + BEUtils.setAntiAliasing((Graphics2D) g, false); + + //再填充一个底线(用于装饰) + g.fillRect(0, menuHeight - DECORATED_UNDERLINE_HEIGHT, menuWidth, DECORATED_UNDERLINE_HEIGHT);//menuHeight); + } else if (model.isRollover() && model.isEnabled()) { + // Only paint rollover if no other menu on menubar is selected + boolean otherMenuSelected = false; + MenuElement[] menus = ((JMenuBar) menu.getParent()) + .getSubElements(); + for (MenuElement menu1 : menus) + if (((JMenuItem) menu1).isSelected()) { + otherMenuSelected = true; + break; + } + + if (!otherMenuSelected) { + g.setColor(MENU_SELECTED_UNDERLINE_COLOR);//selectionBackground);// Uses protected +// g.fillRect(0, 0, menuWidth, menuHeight); + //再填充一个底线(用于装饰) + g.fillRect(0, menuHeight - DECORATED_UNDERLINE_HEIGHT, menuWidth, DECORATED_UNDERLINE_HEIGHT);//menuHeight); + } + } + } // add by Jack Jiang,JMebuBar的内层父级菜单项的样式绘制 + else if (model.isArmed() || (menuItem instanceof JMenu + && model.isSelected())) { + //用NinePatch图来填充 + drawSelectedBackground(g, 0, 0, menuWidth, menuHeight); + } + g.setColor(oldColor); + } + + public static void drawSelectedBackground(Graphics g, int x, int y, int w, int h) { + g.setColor(UIManager.getColor("MenuItem.selectionBackground")); + g.fillRect(0, 0, w, h); + } + + /** + * Method which renders the text of the current menu item. + *

+ * @param g Graphics context + * @param menuItem Current menu item to render + * @param textRect Bounding rectangle to render the text. + * @param text String to render + * @since 1.4 + * + * @see com.sun.java.swing.plaf.windows.WindowsMenuUI#paintText(java.awt.Graphics, javax.swing.JMenuItem, java.awt.Rectangle, java.lang.String) + */ + @Override + protected void paintText(Graphics g, JMenuItem menuItem, + Rectangle textRect, String text) { + //================= commet by Jack Jiang START +// if (WindowsMenuItemUI.isVistaPainting()) { +// WindowsMenuItemUI.paintText(accessor, g, menuItem, textRect, text); +// return; +// } + //================= commet by Jack Jiang END + JMenu menu = (JMenu) menuItem; + ButtonModel model = menuItem.getModel(); + Color oldColor = g.getColor(); + + // Only paint rollover if no other menu on menubar is selected + boolean paintRollover = model.isRollover(); + if (paintRollover && menu.isTopLevelMenu()) { + MenuElement[] menus = ((JMenuBar) menu.getParent()).getSubElements(); + for (MenuElement menu1 : menus) + if (((JMenuItem) menu1).isSelected()) { + paintRollover = false; + break; + } + } + + if ((model.isSelected() + && ( // WindowsLookAndFeel.isClassicWindows() || + !menu.isTopLevelMenu())) + || ( // BEXPStyle.getXP() != null && + (paintRollover || model.isArmed() || model.isSelected()))) + g.setColor(selectionForeground); // Uses protected field. + + //================= add by Jack Jiang START + //特殊处理顶级菜单项(就是直接放在JMenuBar上的那一层),使之在被选中或rover等状态时保持黑色(或其它颜色) + //,目的是为了配合整个菜单项的L&F效果,并没有过多的用途,此颜色可提取作为UIManager的自定义属性哦 + if (menu.isTopLevelMenu()) + g.setColor(new Color(35, 35, 35));//用MaxOS X的经典黑 + //================= add by Jack Jiang END + +// WindowsGraphicsUtils.paintText(g, menuItem, textRect, text, 0); + WinUtils.paintText(g, menuItem, textRect, text, 0); + + g.setColor(oldColor); + } + + /** + * {@inheritDoc} + * + * @see + * com.sun.java.swing.plaf.windows.WindowsMenuUI#createMouseInputListener(javax.swing.JComponent) + */ + @Override + protected MouseInputListener createMouseInputListener(JComponent c) { + return new BEMouseInputHandler(); + } + + /** + * This class implements a mouse handler that sets the rollover flag to true + * when the mouse enters the menu and false when it exits. + * + * @since 1.4 + * @see com.sun.java.swing.plaf.windows.WindowsMenuUI.MouseInputHandler + */ + protected class BEMouseInputHandler extends BasicMenuUI.MouseInputHandler { + + @Override + public void mouseEntered(MouseEvent evt) { + super.mouseEntered(evt); + + JMenu menu = (JMenu) evt.getSource(); + if (hotTrackingOn && menu.isTopLevelMenu() && menu.isRolloverEnabled()) { + menu.getModel().setRollover(true); + menuItem.repaint(); + } + } + + @Override + public void mouseExited(MouseEvent evt) { + super.mouseExited(evt); + + JMenu menu = (JMenu) evt.getSource(); + ButtonModel model = menu.getModel(); + if (menu.isRolloverEnabled()) { + model.setRollover(false); + menuItem.repaint(); + } + } + } + + /** + * {@inheritDoc} + * + * @see + * com.sun.java.swing.plaf.windows.WindowsMenuUI#getPreferredMenuItemSize(javax.swing.JComponent, + * javax.swing.Icon, javax.swing.Icon, int) + */ + @Override + protected Dimension getPreferredMenuItemSize(JComponent c, + Icon checkIcon, + Icon arrowIcon, + int defaultTextIconGap) { + + Dimension d = super.getPreferredMenuItemSize(c, checkIcon, arrowIcon, + defaultTextIconGap); + + // Note: When toolbar containers (rebars) are implemented, only do + // this if the JMenuBar is not in a rebar (i.e. ignore the desktop + // property win.menu.height if in a rebar.) + if (c instanceof JMenu && ((JMenu) c).isTopLevelMenu() + && menuBarHeight != null && d.height < menuBarHeight) + + d.height = menuBarHeight; + + return d; + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/menu/BEPopupMenuSeparatorUI.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/menu/BEPopupMenuSeparatorUI.java new file mode 100644 index 000000000..37a59dba5 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/menu/BEPopupMenuSeparatorUI.java @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * BEPopupMenuSeparatorUI.java at 2015-2-1 20:25:36, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.menu; + +import java.awt.BasicStroke; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Stroke; + +import javax.swing.JComponent; +import javax.swing.JSeparator; +import javax.swing.LookAndFeel; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.SeparatorUI; + +/** + * JPopupMenuSeparator的UI实现. + * + * @author Jack Jiang(jb2011@163.com) + * @version 1.0 + */ +public class BEPopupMenuSeparatorUI extends SeparatorUI { + + public static ComponentUI createUI(JComponent c) { + return new BEPopupMenuSeparatorUI(); + } + + @Override + public void installUI(JComponent c) { + installDefaults((JSeparator) c); + installListeners((JSeparator) c); + } + + @Override + public void uninstallUI(JComponent c) { + uninstallDefaults((JSeparator) c); + uninstallListeners((JSeparator) c); + } + + protected void installDefaults(JSeparator s) { + LookAndFeel.installColors(s, "Separator.background", "Separator.foreground"); + LookAndFeel.installProperty(s, "opaque", Boolean.FALSE); + } + + protected void uninstallDefaults(JSeparator s) { + } + + protected void installListeners(JSeparator s) { + } + + protected void uninstallListeners(JSeparator s) { + } + + @Override + public void paint(Graphics g, JComponent c) { + int w = c.getWidth(), h = c.getHeight(); + Graphics2D g2 = (Graphics2D) g; + + if (((JSeparator) c).getOrientation() == JSeparator.VERTICAL) { + //垂直坚线原始代码 + //TODO 垂直样式的竖线有时间再实现吧,垂直竖线默认用于JToolBar里 + g.setColor(c.getForeground()); + g.drawLine(0, 0, 0, c.getHeight()); + g.setColor(c.getBackground()); + g.drawLine(1, 0, 1, c.getHeight()); + } else // HORIZONTAL + + drawHorizonal(g2, c, w, h); + } + + /** + * 以水平方向绘制分隔线样式. + */ + private void drawHorizonal(Graphics2D g2, JComponent c, int w, int h) { + //** 绘制border的底线 + //虚线样式 + Stroke oldStroke = g2.getStroke(); + Stroke sroke = new BasicStroke(1, BasicStroke.CAP_BUTT, + BasicStroke.JOIN_BEVEL, 0, new float[] { 2, 2 }, 0);//实线,空白 + g2.setStroke(sroke); + //底边上(浅灰色) +// g2.setColor(new Color(180,180,180)); + g2.setColor(c.getForeground()); + g2.drawLine(0, h - 2, w - 1, h - 2); // draw bottom1 + //底边下(白色):绘制一条白色虚线的目的是与上面的灰线产生较强对比度从而形成立体效果 + //,本L&F实现中因与Panel的底色对比度不够强烈而立体感不明显(颜色越深的底色最终效果越明显) +// g2.setColor(Color.white); + g2.setColor(c.getBackground()); + g2.drawLine(0, h - 1, w - 1, h - 1);//draw bottom2 + + g2.setStroke(oldStroke); + } + + @Override + public Dimension getPreferredSize(JComponent c) { + if (((JSeparator) c).getOrientation() == JSeparator.VERTICAL) + return new Dimension(2, 0); + else + return new Dimension(0, 3); + } + + @Override + public Dimension getMinimumSize(JComponent c) { + return null; + } + + @Override + public Dimension getMaximumSize(JComponent c) { + return null; + } + +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/menu/BEPopupMenuUI.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/menu/BEPopupMenuUI.java new file mode 100644 index 000000000..ebcf066b8 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/menu/BEPopupMenuUI.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * BEPopupMenuUI.java at 2015-2-1 20:25:36, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.menu; + +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicPopupMenuUI; + +/** + * BeautyEye L&F的弹出菜单主类实现类. + * + * 兼容性说明:WindowsPopupMenuUI类在java1.6.0_u10(可能不仅限于1.6.0_u10,但java1.6.0中不存在这个问题) + * 中会判断,如果是在Vista或者说xp平台时(测试证明是在win7平台会有这些问题)会用windows系 + * 统实现进行背景填充,而在1.6.0_u18(可能不限于此版本中)取消了这样的判断,改为直接继续 + * BasicPopupMenuUI的实默认实现。因此而带来的差异使得BE LNF在不同的java版本里(u10)会 + * 错误地使用windows系统实现.本类的目的就是要去掉这种差异,仍然交由父类BasicPopupMenuUI 实现即可(类似的官方Metal + * LNF也是采用了BeautyEye一样的处理逻辑). + * + * @author Jack Jiang(jb2011@163.com), 2012-09-14 + * @version 1.0 + * @since 3.1 + * + * @see com.sun.java.swing.plaf.windows.WindowsPopupMenuUI + */ +public class BEPopupMenuUI extends BasicPopupMenuUI { + + public static ComponentUI createUI(JComponent c) { + return new BEPopupMenuUI(); + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/menu/BERadioButtonMenuItemUI.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/menu/BERadioButtonMenuItemUI.java new file mode 100644 index 000000000..31b43ff57 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/menu/BERadioButtonMenuItemUI.java @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * BERadioButtonMenuItemUI.java at 2015-2-1 20:25:37, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.menu; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.io.Serializable; + +import javax.swing.AbstractButton; +import javax.swing.ButtonModel; +import javax.swing.Icon; +import javax.swing.JComponent; +import javax.swing.JMenu; +import javax.swing.JMenuItem; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.UIResource; +import javax.swing.plaf.basic.BasicRadioButtonMenuItemUI; +import org.jackhuang.hmcl.laf.utils.IconFactory; + +/** + * JRadioButtonMenuItem的UI实现. + * + * @author Jack Jiang(jb2011@163.com) + * @version 1.0 + */ +public class BERadioButtonMenuItemUI extends BasicRadioButtonMenuItemUI { + + private static final IconFactory ICON = new IconFactory("menu_radio"); + + public static ComponentUI createUI(JComponent b) { + return new BERadioButtonMenuItemUI(); + } + + /** + * Draws the background of the menu item. + * + * @param g the paint graphics + * @param menuItem menu item to be painted + * @param bgColor selection background color + * @since 1.4 + * @see + * javax.swing.plaf.basic.BasicMenuItemUI#paintBackground(java.awt.Graphics, + * javax.swing.JMenuItem, java.awt.Color) + */ + @Override + protected void paintBackground(Graphics g, JMenuItem menuItem, Color bgColor) { + ButtonModel model = menuItem.getModel(); + Color oldColor = g.getColor(); + int menuWidth = menuItem.getWidth(); + int menuHeight = menuItem.getHeight(); + + if (menuItem.isOpaque()) { + if (model.isArmed() || (menuItem instanceof JMenu && model.isSelected())) { + g.setColor(bgColor); + g.fillRect(0, 0, menuWidth, menuHeight); + } else { + g.setColor(menuItem.getBackground()); + g.fillRect(0, 0, menuWidth, menuHeight); + } + g.setColor(oldColor); + } else if (model.isArmed() || (menuItem instanceof JMenu + && model.isSelected())) +// g.setColor(bgColor); +// g.fillRect(0,0, menuWidth, menuHeight); +// g.setColor(oldColor); + + //由jb2011改用NinePatch图来填充 + BEMenuUI.drawSelectedBackground(g, 0, 0, menuWidth, menuHeight); + } + + /** + * @see com.sun.java.swing.plaf.windows.WindowsIconFactory.RadioButtonMenuItemIcon + */ + public static class RadioButtonMenuItemIcon implements Icon, UIResource, Serializable { + + @Override + public void paintIcon(Component c, Graphics g, int x, int y) { + //* 注意:当用于windows平台专用主类且处于Vista及更高版win时要做不一样的处理哦 + g.drawImage(ICON.get(((AbstractButton) c).getModel().isSelected() ? "checked" : "normal").getImage(), + x - 4, y - 4, null); + } + + @Override + public int getIconWidth() { + return 16; + }//default 6 + + @Override + public int getIconHeight() { + return 16; + }//default 6 + + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/menu/__UI__.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/menu/__UI__.java new file mode 100644 index 000000000..67331cbf7 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/menu/__UI__.java @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * __UI__.java at 2015-2-1 20:25:36, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.menu; + +import java.awt.Color; + +import javax.swing.UIManager; + +import org.jackhuang.hmcl.laf.BeautyEyeLNFHelper; +import org.jackhuang.hmcl.laf.utils.UI; + +public class __UI__ extends UI { + + public static void uiImpl() { + //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> margin和border设置 START +// UIManager.put("MenuBar.border",new org.jb2011.lnf.windows2.ch10.EWindowsMenuBarUI.MenuBarBorder(Color.red,Color.BLUE)); + //去掉菜单条下方的border(默认是一个2个像素高的横线,参见WindowsMenuBarUI.MenuBarBorder) + putBorder("MenuBar.border"); + + //提示:margin与border并存设置情况容易产生混知,其实官方实现是:当设置margin时,则Border就使用 + //marginBorder,该Border就是用的这个margin来作它的Insets的 + //BueatyEye LNF中推荐实践是:抛弃margin的概念(省的混淆),直接使用border(在其上直接给于insets)即可 + putInsets("CheckBoxMenuItem.margin", 0, 0, 0, 0); + putInsets("RadioButtonMenuItem.margin", 0, 0, 0, 0);//iuir); + putInsets("Menu.margin", 0, 0, 0, 0);//windows lnf中默认是2,2,2,2 + putInsets("MenuItem.margin", 0, 0, 0, 0);//windows lnf中默认是2,2,2,2 +// putInsets("MenuItem.margin", 10, 2, 10, 2);//top=2,left=2,bottom=2,right=2 + + //请注意:上面的margin已经全设为0了哦 + putBorder("Menu.border", 4, 3, 5, 3);//javax.swing.plaf.basic.BasicBorders.MarginBorder; + putBorder("MenuItem.border", 4, 3, 5, 3);// + putBorder("CheckBoxMenuItem.border", 4, 3, 5, 3);//javax.swing.plaf.basic.BasicBorders.MarginBorder; + putBorder("RadioButtonMenuItem.border", 4, 3, 5, 3);// +// putBorder("PopupMenu.border", 20, 10, 20, 10); // + //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> margin和border设置 END + + //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 颜色设置 START + put("MenuBar.foreground", BeautyEyeLNFHelper.commonForegroundColor); + put("RadioButtonMenuItem.foreground", BeautyEyeLNFHelper.commonForegroundColor); + put("Menu.foreground", BeautyEyeLNFHelper.commonForegroundColor); + put("PopupMenu.foreground", BeautyEyeLNFHelper.commonForegroundColor); + put("CheckBoxMenuItem.foreground", BeautyEyeLNFHelper.commonForegroundColor); + put("MenuItem.foreground", BeautyEyeLNFHelper.commonForegroundColor); + + put("MenuBar.background", BeautyEyeLNFHelper.commonBackgroundColor); + put("Menu.background", new Color(255, 255, 255, 0)); + put("PopupMenu.background", new Color(255, 255, 255, 0)); + + put("RadioButtonMenuItem.disabledForeground", BeautyEyeLNFHelper.commonDisabledForegroundColor); + put("MenuItem.disabledForeground", BeautyEyeLNFHelper.commonDisabledForegroundColor); + + put("Menu.selectionForeground", BeautyEyeLNFHelper.commonSelectionForegroundColor); + put("MenuItem.selectionForeground", BeautyEyeLNFHelper.commonSelectionForegroundColor); + put("CheckBoxMenuItem.selectionForeground", BeautyEyeLNFHelper.commonSelectionForegroundColor); + put("RadioButtonMenuItem.selectionForeground", BeautyEyeLNFHelper.commonSelectionForegroundColor); + + put("Menu.selectionBackground", BeautyEyeLNFHelper.commonSelectionBackgroundColor); + put("MenuItem.selectionBackground", BeautyEyeLNFHelper.commonSelectionBackgroundColor); + put("CheckBoxMenuItem.selectionBackground", BeautyEyeLNFHelper.commonSelectionBackgroundColor); + put("RadioButtonMenuItem.selectionBackground", BeautyEyeLNFHelper.commonSelectionBackgroundColor); + //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 颜色设置 END + + //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 杂项设置 START + //本值意味着弹出菜单X轴方向上的偏移量,因BE LNF中加了边框,所以要负偏移以便得弹出菜单主体能与菜单项对齐好看一些 + put("Menu.menuPopupOffsetX", -3);//win lnf中默认值是0 + //本值意味着弹出菜单Y轴方向上的偏移量,因BE LNF中加了边框,所以要负偏移以便得弹出菜单主体能与菜单项对齐好看一些 + put("Menu.menuPopupOffsetY", 2);///win lnf默认值是0 + //本值意味着弹出子菜单X轴方向上的偏移量,因BE LNF中加了边框,所以要负偏移以便得弹出菜单主体能与菜单项对齐好看一些 + put("Menu.submenuPopupOffsetX", -2);///win lnf默认值是-4 + //本值意味着弹出子菜单Y轴方向上的偏移量,因BE LNF中加了边框,所以要负偏移以便得弹出菜单主体能与菜单项对齐好看一些 + put("Menu.submenuPopupOffsetY", -5);///win lnf默认值是-3 + + //多选按钮式的菜单项选中与否的图标实现设定 + UIManager.put("CheckBoxMenuItem.checkIcon", new BECheckBoxMenuItemUI.CheckBoxMenuItemIcon()); + //单选按钮式的菜单项选中与否的图标实现设定 + UIManager.put("RadioButtonMenuItem.checkIcon", new BERadioButtonMenuItemUI.RadioButtonMenuItemIcon()); + + //加高菜单条,提升视觉体验 + put("MenuBar.height", 30);//default value is 19 + + //此属性true时表明禁用的菜单项将不能被rover,否则有rover效果(BE LNF中 + //因禁用状态rover时的字体色影响视觉效果,所以干脆禁用之,逻辑上也很合理) + put("MenuItem.disabledAreNavigable", false);// windows lnf中默认是true + //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 杂项设置 END + + //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> UI实现类设置 START + put("MenuBarUI", BEMenuBarUI.class); + put("MenuUI", BEMenuUI.class); + put("MenuItemUI", BEMenuItemUI.class); + put("RadioButtonMenuItemUI", BERadioButtonMenuItemUI.class); + put("CheckBoxMenuItemUI", BECheckBoxMenuItemUI.class); + put("PopupMenuSeparatorUI", BEPopupMenuSeparatorUI.class); + put("PopupMenuUI", BEPopupMenuUI.class); + //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> UI实现类设置 END + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/painter/ButtonPainter.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/painter/ButtonPainter.java deleted file mode 100755 index 8fb62c8f2..000000000 --- a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/painter/ButtonPainter.java +++ /dev/null @@ -1,252 +0,0 @@ -/* - * $Id: MetroGraphicsUtils.java,v 1.9 2005/12/05 15:00:55 kizune Exp $ - * - * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, - * Santa Clara, California 95054, U.S.A. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -package org.jackhuang.hmcl.laf.painter; - -import java.awt.Color; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.RenderingHints; -import java.awt.geom.Rectangle2D; -import java.awt.geom.RoundRectangle2D; -import javax.swing.Timer; -import javax.swing.plaf.synth.SynthConstants; -import javax.swing.plaf.synth.SynthContext; -import javax.swing.plaf.synth.SynthPainter; -import org.jackhuang.hmcl.util.ui.GraphicsUtils; -import org.jackhuang.hmcl.laf.ConstomButton; - -/** - * ButtonPainter - handles painting Nimbus style buttons with Java2D - * - * @author Created by Jasper Potts (Jan 4, 2007) - * @version 1.0 - */ -public class ButtonPainter extends SynthPainter { - - private static final String DEFAULT_NORMAL = "D5D5D5"; - private static final Color[] DEFAULT_NORMAL_FG = new Color[]{ - GraphicsUtils.getWebColor(DEFAULT_NORMAL), - GraphicsUtils.getWebColor(DEFAULT_NORMAL) - }; - private static final String DEFAULT_PRELIGHT = "A9A9A9"; - private static final Color[] DEFAULT_PRELIGHT_FG = new Color[]{ - GraphicsUtils.getWebColor(DEFAULT_PRELIGHT), - GraphicsUtils.getWebColor(DEFAULT_PRELIGHT) - }; - private static final String DEFAULT_ACTIVE = "222222"; - private static final Color[] DEFAULT_ACTIVE_FG = new Color[]{ - GraphicsUtils.getWebColor(DEFAULT_ACTIVE), - GraphicsUtils.getWebColor(DEFAULT_ACTIVE) - }; - - private static final Color[] DISABLED_BG = new Color[]{ - GraphicsUtils.getWebColor("E3EFE9"), - GraphicsUtils.getMidWebColor("E3EFE9", "DFE2E6"), - GraphicsUtils.getWebColor("DFE2E6"), - GraphicsUtils.getMidWebColor("DFE2E6", "D6D9DF"), - GraphicsUtils.getWebColor("D6D9DF"), - GraphicsUtils.getWebColor("D6D9DF"), - GraphicsUtils.getMidWebColor("D6D9DF", "D8DBE1"), - GraphicsUtils.getWebColor("D8DBE1"), - GraphicsUtils.getWebColor("DADDE3") - }; - private static final Color[] DISABLED_FG = new Color[]{ - GraphicsUtils.getWebColor("C9CCD2"), - GraphicsUtils.getWebColor("C9CCD2"), - GraphicsUtils.getWebColor("BCBFC5"), - GraphicsUtils.getWebColor("BCBFC5") - }; - - private static boolean processCustomButton(final ConstomButton c, int add) { - if (c.drawPercent == 0 || c.drawPercent == 100) { - Timer t = new Timer(1, null); - t.addActionListener(x -> { - c.drawPercent += add; - if (c.drawPercent > 100 && add > 0) { - c.drawPercent = 100; - t.stop(); - } else if (c.drawPercent < 0 && add < 0) { - c.drawPercent = 0; - t.stop(); - } else - c.updateUI(); - }); - t.start(); - } - return true; - } - - /** - * {@inheritDoc} - */ - @Override - public void paintButtonBackground(SynthContext context, Graphics g, int x, int y, int w, int h) { - Graphics2D g2 = (Graphics2D) g.create(); - g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - Color[] fg, bg; - if ((context.getComponentState() & SynthConstants.DEFAULT) != 0) - if ((context.getComponentState() & SynthConstants.PRESSED) != 0) - if (context.getComponent() instanceof ConstomButton) { - ConstomButton c = (ConstomButton) context.getComponent(); - fg = new Color[]{c.activeFg, c.activeFg}; - bg = new Color[]{c.activeFg, c.activeFg}; - } else { - fg = DEFAULT_ACTIVE_FG; - bg = DEFAULT_ACTIVE_FG; - } - else if ((context.getComponentState() & SynthConstants.DISABLED) != 0) - return; //fg = DISABLED_FG; - //bg = DISABLED_BG; - else if ((context.getComponentState() & SynthConstants.MOUSE_OVER) != 0) - if (context.getComponent() instanceof ConstomButton) { - final ConstomButton c = (ConstomButton) context.getComponent(); - if (!processCustomButton(c, 1)) - return; - Color fgs = GraphicsUtils.getMidWebColor(c.normalFg, c.prelightFg, c.drawPercent); - Color bgs = GraphicsUtils.getMidWebColor(c.normalBg, c.prelightBg, c.drawPercent); - fg = new Color[]{fgs, fgs}; - bg = new Color[]{bgs, bgs}; - } else { - fg = DEFAULT_PRELIGHT_FG; - bg = DEFAULT_PRELIGHT_FG; - } - else if (context.getComponent() instanceof ConstomButton) { - final ConstomButton c = (ConstomButton) context.getComponent(); - if (!processCustomButton(c, -1)) - return; - Color fgs = GraphicsUtils.getMidWebColor(c.normalFg, c.prelightFg, c.drawPercent); - Color bgs = GraphicsUtils.getMidWebColor(c.normalBg, c.prelightBg, c.drawPercent); - fg = new Color[]{fgs, fgs}; - bg = new Color[]{bgs, bgs}; - } else { - fg = DEFAULT_NORMAL_FG; - bg = DEFAULT_NORMAL_FG; - } - else if ((context.getComponentState() & SynthConstants.PRESSED) != 0) - if (context.getComponent() instanceof ConstomButton) { - ConstomButton c = (ConstomButton) context.getComponent(); - fg = new Color[]{c.activeFg, c.activeFg}; - bg = new Color[]{c.activeFg, c.activeFg}; - } else { - fg = DEFAULT_ACTIVE_FG; - bg = DEFAULT_ACTIVE_FG; - } - else if ((context.getComponentState() & SynthConstants.DISABLED) != 0) - return; //fg = DISABLED_FG; - //bg = DISABLED_BG; - else if ((context.getComponentState() & SynthConstants.MOUSE_OVER) != 0) - if (context.getComponent() instanceof ConstomButton) { - final ConstomButton c = (ConstomButton) context.getComponent(); - if (!processCustomButton(c, 1)) - return; - Color fgs = GraphicsUtils.getMidWebColor(c.normalFg, c.prelightFg, c.drawPercent); - Color bgs = GraphicsUtils.getMidWebColor(c.normalBg, c.prelightBg, c.drawPercent); - fg = new Color[]{fgs, fgs}; - bg = new Color[]{bgs, bgs}; - } else if (context.getComponent() instanceof ConstomButton) { - ConstomButton c = (ConstomButton) context.getComponent(); - fg = new Color[]{c.prelightFg, c.prelightFg}; - bg = new Color[]{c.prelightBg, c.prelightBg}; - } else { - fg = DEFAULT_PRELIGHT_FG; - bg = DEFAULT_PRELIGHT_FG; - } - else if (context.getComponent() instanceof ConstomButton) { - final ConstomButton c = (ConstomButton) context.getComponent(); - if (!processCustomButton(c, -1)) - return; - Color fgs = GraphicsUtils.getMidWebColor(c.normalFg, c.prelightFg, c.drawPercent); - Color bgs = GraphicsUtils.getMidWebColor(c.normalBg, c.prelightBg, c.drawPercent); - fg = new Color[]{fgs, fgs}; - bg = new Color[]{bgs, bgs}; - } else { - fg = DEFAULT_NORMAL_FG; - bg = DEFAULT_NORMAL_FG; - } - /*w = w - 2; - h = h - 2; - - g2.setPaint(new LinearGradientPaint(x, y, x, y + h, - new float[]{0, 1}, bg)); - g2.fillRect(x, y, w, h); - - g2.setPaint(new LinearGradientPaint(x, y, x, y + h, - new float[]{0, 1}, fg)); - g2.drawRect(x, y, w, h);*/ - - int radix = (context.getComponent() instanceof ConstomButton) ? ((ConstomButton) context.getComponent()).radix : 0; - - g2.setColor(fg[0]); - RoundRectangle2D fgshape = new RoundRectangle2D.Float(x, y, w, h, radix, radix); - g2.draw(fgshape); - g2.setColor(bg[0]); - RoundRectangle2D bgshape = new RoundRectangle2D.Float(x, y, w, h, radix, radix); - g2.fill(bgshape); - } - - @Override - public void paintToggleButtonBackground(SynthContext context, Graphics g, int x, int y, int w, int h) { - Graphics2D g2 = (Graphics2D) g.create(); - g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - Color[] fg, bg; - //if ((context.getComponentState() & SynthConstants.DEFAULT) != 0) - if ((context.getComponentState() & SynthConstants.PRESSED) != 0 || (context.getComponentState() & SynthConstants.SELECTED) != 0) { - fg = DEFAULT_ACTIVE_FG; - bg = DEFAULT_ACTIVE_FG; - } else if ((context.getComponentState() & SynthConstants.DISABLED) != 0) { - fg = DISABLED_FG; - bg = DISABLED_BG; - } else if ((context.getComponentState() & SynthConstants.MOUSE_OVER) != 0) { - fg = DEFAULT_PRELIGHT_FG; - bg = DEFAULT_PRELIGHT_FG; - } else { - fg = DEFAULT_NORMAL_FG; - bg = DEFAULT_NORMAL_FG; - } - /*else if ((context.getComponentState() & SynthConstants.PRESSED) != 0 || (context.getComponentState() & SynthConstants.SELECTED) != 0) { - fg = DEFAULT_ACTIVE_FG; - bg = DEFAULT_ACTIVE_FG; - } else if ((context.getComponentState() & SynthConstants.DISABLED) != 0) { - fg = DISABLED_FG; - bg = DISABLED_BG; - } else if ((context.getComponentState() & SynthConstants.MOUSE_OVER) != 0) { - fg = DEFAULT_PRELIGHT_FG; - bg = DEFAULT_PRELIGHT_FG; - } else { - fg = DEFAULT_NORMAL_FG; - bg = DEFAULT_NORMAL_FG; - }*/ - g2.setColor(fg[0]); - Rectangle2D fgshape = new Rectangle2D.Float(x, y, w, h); - g2.draw(fgshape); - g2.setColor(bg[0]); - Rectangle2D bgshape = new Rectangle2D.Float(x, y, w, h); - g2.fill(bgshape); - - /*g2.setPaint(new LinearGradientPaint(x, y, x, y + h, - new float[]{0, 1}, bg)); - g2.fillRect(x, y, w, h); - - g2.setPaint(new LinearGradientPaint(x, y, x, y + h, - new float[]{0, 1}, fg)); - g2.drawRect(x, y, w, h);*/ - } -} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/painter/ProgressPainter.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/painter/ProgressPainter.java deleted file mode 100755 index 39abf7599..000000000 --- a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/painter/ProgressPainter.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * $Id: MetroGraphicsUtils.java,v 1.9 2005/12/05 15:00:55 kizune Exp $ - * - * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, - * Santa Clara, California 95054, U.S.A. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -package org.jackhuang.hmcl.laf.painter; - -import org.jackhuang.hmcl.util.ui.GraphicsUtils; - -import javax.swing.plaf.synth.SynthContext; -import javax.swing.plaf.synth.SynthPainter; -import java.awt.Color; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.LinearGradientPaint; - -/** - * ProgressPainter - Synth painter for Nimbus progressbars - * - * @author Created by Jasper Potts (Jan 3, 2007) - * @version 1.0 - */ -public class ProgressPainter extends SynthPainter { - - private static final float[] NORMAL_BG_PTS = new float[]{0, 1}; - private static final Color[] NORMAL_BG = new Color[]{ - GraphicsUtils.getWebColor("c6c6c6"), - GraphicsUtils.getWebColor("c6c6c6") - }; - private static final float[] BAR_FG_PTS = new float[]{0, 1}; - private static final Color[] BAR_FG = new Color[]{ - GraphicsUtils.getWebColor("41B1E1"), - GraphicsUtils.getWebColor("41B1E1") - }; - - /** - * {@inheritDoc} - */ - @Override - public void paintProgressBarBackground(SynthContext context, Graphics g, int x, int y, int w, int h, - int orientation) { - Graphics2D g2 = (Graphics2D) g.create(); - g2.setPaint(new LinearGradientPaint(x, y + 2, x, y + h - 4, NORMAL_BG_PTS, NORMAL_BG)); - if (x + 2 < w - 5 && y + 2 < h - 5) - g2.fillRect(x + 2, y + 2, w - 5, h - 5); - } - - /** - * {@inheritDoc} - */ - @Override - public void paintProgressBarForeground(SynthContext context, Graphics g, int x, int y, int w, int h, - int orientation) { - Graphics2D g2 = (Graphics2D) g.create(); - g2.setPaint(new LinearGradientPaint(x, y + 2, x, y + h - 2, BAR_FG_PTS, BAR_FG)); - if (x + 2 < w - 5 && y + 2 < h - 5) - g2.fillRect(x + 2, y + 2, w - 5, h - 5); - } - - /** - * {@inheritDoc} - */ - @Override - public void paintProgressBarBorder(SynthContext context, Graphics g, int x, int y, int w, int h, int orientation) { - } -} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/painter/TextFieldPainter.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/painter/TextFieldPainter.java deleted file mode 100755 index 05071b188..000000000 --- a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/painter/TextFieldPainter.java +++ /dev/null @@ -1,99 +0,0 @@ -/* -* $Id: NimbusGraphicsUtils.java,v 1.9 2005/12/05 15:00:55 kizune Exp $ -* -* Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, -* Santa Clara, California 95054, U.S.A. All rights reserved. -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -package org.jackhuang.hmcl.laf.painter; - -import javax.swing.plaf.synth.SynthContext; -import javax.swing.plaf.synth.SynthPainter; -import java.awt.Color; -import java.awt.Graphics; -import javax.swing.plaf.synth.SynthConstants; -import org.jackhuang.hmcl.util.ui.GraphicsUtils; - -/** - * TextFieldPainter - * - * @author Created by Jasper Potts (Jan 4, 2007) - * @version 1.0 - */ -public class TextFieldPainter extends SynthPainter { - - private boolean fill = true; - - private static final Color DISABLED = GraphicsUtils.getWebColor("F3F3F3"), - NORMAL = GraphicsUtils.getWebColor("CCCCCC"), - FOCUSED = GraphicsUtils.getWebColor("000000"), - OVER = GraphicsUtils.getWebColor("7F7F7F"); - - public TextFieldPainter() { - } - - public TextFieldPainter(boolean fill) { - this.fill = fill; - } - - private void paintFieldBackground(SynthContext context, Graphics g, int x, int y, int w, int h) { - w--; - h--; - if (fill) { - g.setColor(Color.WHITE); - g.fillRect(x, y, w, h); - } - Color color; - if ((context.getComponentState() & SynthConstants.MOUSE_OVER) != 0) - color = OVER; - else if ((context.getComponentState() & SynthConstants.DISABLED) != 0) - color = DISABLED; - else if ((context.getComponentState() & SynthConstants.FOCUSED) != 0) - color = FOCUSED; - else - color = NORMAL; - g.setColor(color); - g.drawLine(x, y, x + w, y); - g.drawLine(x, y, x, y + w); - g.drawLine(x + w, y, x + w, y + h); - g.drawLine(x, y + h, x + w, y + h); - } - - @Override - public void paintPasswordFieldBackground(SynthContext context, Graphics g, int x, int y, int w, int h) { - paintFieldBackground(context, g, x, y, w, h); - } - - @Override - public void paintTextAreaBackground(SynthContext context, Graphics g, int x, int y, int w, int h) { - paintFieldBackground(context, g, x, y, w, h); - } - - @Override - public void paintTextFieldBackground(SynthContext context, Graphics g, int x, int y, int w, int h) { - paintFieldBackground(context, g, x, y, w, h); - } - - @Override - public void paintTextPaneBackground(SynthContext context, Graphics g, int x, int y, int w, int h) { - paintFieldBackground(context, g, x, y, w, h); - } - - @Override - public void paintScrollPaneBackground(SynthContext context, Graphics g, int x, int y, int w, int h) { - paintFieldBackground(context, g, x, y, w, h); - } -} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/popup/TranslucentPopupFactory.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/popup/TranslucentPopupFactory.java new file mode 100644 index 000000000..43a5b4d4e --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/popup/TranslucentPopupFactory.java @@ -0,0 +1,384 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * TranslucentPopupFactory.java at 2015-2-1 20:25:38, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.popup; + +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.GraphicsEnvironment; +import java.awt.Window; + +import javax.swing.BorderFactory; +import javax.swing.JComponent; +import javax.swing.JMenuItem; +import javax.swing.JPopupMenu; +import javax.swing.JScrollPane; +import javax.swing.JToolTip; +import javax.swing.JWindow; +import javax.swing.MenuElement; +import javax.swing.Popup; +import javax.swing.PopupFactory; +import javax.swing.SwingUtilities; +import javax.swing.plaf.basic.BasicComboPopup; +import org.jackhuang.hmcl.laf.scroll.BEScrollBarUI; +import org.jackhuang.hmcl.laf.utils.Icon9Factory; +import org.jackhuang.hmcl.laf.WindowTranslucencyHelper; +import org.jackhuang.hmcl.laf.widget.ImageBgPanel; + +/** + * 自定义透明背景的弹出工厂实现类. + * + * 本类其实与Swing的UI机制关联不大,完全可以独立于L&F使用。 + * + * @author Jack Jiang(jb2011@163.com), 2012-05-18 + * @version 1.0 + */ +public class TranslucentPopupFactory extends PopupFactory { + + private static final Icon9Factory ICON_9 = new Icon9Factory("popup"); + + @Override + public Popup getPopup(Component owner, Component contents, int x, int y) + throws IllegalArgumentException { + // A more complete implementation would cache and reuse popups + return new TranslucentPopup(owner, contents, x, y); + } + + /** + * 透明背景的Popup实现类. + *

+ * 本类的大部分代码都是原封不动地参考自Popup父类(JDK版本是1.6_u18版的源码),因为Popup父 + * 类中的多数方法都是使用的包内可见性,所以没法直接继承,像这种不允许第3方自行扩展的情 + * 况在Swing标准包里比较少见,不知原作者是出于何种考虑,无疑这样的类实现是相当的欠缺远 见性,但这种情况在LNF里很常见。 + */ + protected class TranslucentPopup extends Popup { + //copy all from parent class + + /** + * The Component representing the Popup. + */ + private Component component; + + //copy all from parent class + /** + * Creates a Popup for the Component owner + * containing the Component contents. owner is + * used to determine which Window the new + * Popup will parent the Component the + * Popup creates to. A null owner implies + * there is no valid parent. x and y specify + * the preferred initial location to place the Popup at. + * Based on screen size, or other paramaters, the Popup may + * not display at x and y. + * + * @param owner Component mouse coordinates are relative to, may be null + * @param contents Contents of the Popup + * @param x Initial x screen coordinate + * @param y Initial y screen coordinate + */ + public TranslucentPopup(Component owner, Component contents, int x, + int y) { + this(); + if (contents == null) + throw new IllegalArgumentException("Contents must be non-null"); + + reset(owner, contents, x, y); + } + + /** + * Creates a Popup. This is provided for subclasses. + */ + public TranslucentPopup() { + } + + /** + *

+ * Makes the Popup visible. If the Popup is + * currently visible, this has no effect.
+ * + * 本方法的结构完全copy自父类方法,但添加了component.repaint();的调用. + *

+ */ + @Override + public void show() { + Component c = getComponent(); + + if (c != null) { + c.setVisible(true); + + //此行代码必须要有,否则可能是因为没有关闭双缓存(getRootPane(). + //setUseTrueDoubleBuffering(false),这个方法是包内可见,所以本类里没法调用 + //),而导致界面没有重绘:要不就是UI没有绘出来,要不就是出现空白的popup(没有内容组件) + c.repaint(); + } + } + + /** + * Hides and disposes of the Popup. Once a + * Popup has been disposed you should no longer invoke + * methods on it. A disposed Popup may be + * reclaimed and later used based on the PopupFactory. As + * such, if you invoke methods on a disposed + * Popup, indeterminate behavior will result. + */ + @Override + public void hide() { + Component c = getComponent(); + + if (c instanceof JWindow) { + c.hide(); + ((JWindow) c).getContentPane().removeAll(); + } + dispose(); + } + + /** + * Frees any resources the Popup may be holding onto. + */ + protected void dispose() { + Component c = getComponent(); + Window window = SwingUtilities.getWindowAncestor(c); + + if (c instanceof JWindow) { + ((Window) c).dispose(); + c = null; + } + // If our parent is a DefaultFrame, we need to dispose it, too. + if (window instanceof DefaultFrame) + window.dispose(); + } + + /** + *

+ * Resets the Popup to an initial state.
+ * + * 本方法的结构完全copy自父类方法,但进行中包括:窗口透明、用图片实现背景填充等在内的修改. + *

+ * + * @param owner the owner + * @param contents the contents + * @param ownerX the owner x + * @param ownerY the owner y + */ + protected void reset(Component owner, Component contents, int ownerX, int ownerY) { + if (getComponent() == null) + component = createComponent(owner); + + Component c = getComponent(); + if (c instanceof JWindow) { + JWindow w = (JWindow) getComponent(); + w.setLocation(ownerX, ownerY); + + boolean isTooltip = ((JComponent) contents instanceof JToolTip); + //如果contents是BasicComboPopup或其子类那当前就应该是用于下拉框的弹出列表罗 + boolean isComboBoxPopup = (contents instanceof BasicComboPopup); + + //每像素透明 + WindowTranslucencyHelper.setWindowOpaque(w, false); + //内容组件半透明 + w.setOpacity(isTooltip ? 1.0f : isComboBoxPopup ? 0.95f : 0.95f);//0.85f : 0.95f);//0.8f : 0.95f); + +// component.getContentPane().add(contents, BorderLayout.CENTER); +// contents.invalidate(); +// if (component.isVisible()) +// { +// // Do not call pack() if window is not visible to +// // avoid early native peer creation +// pack(); +// } + //图片填充背景的内容面板 + ImageBgPanel imageContentPane = new ImageBgPanel().setN9( + isTooltip + ? ICON_9.get("tooltip") + : isComboBoxPopup + ?//是下拉框列表则使一个跟JScrollPane一样的背景图,好看! + BEScrollBarUI.ICON_9.get("scroll_pane_border") + : ICON_9.get("popup") + ); + imageContentPane.setLayout(new BorderLayout()); + imageContentPane.add(contents, BorderLayout.CENTER); + + //为每一个要显示的真正的内容组件加一个空border,目的 + //是使得父面板的背景图片显示的效果更好 + if (contents instanceof JComponent) { + ((JComponent) contents).setOpaque(false); + //* ######################################### Bug FIX START ############################################ + //* 关于Java Bug 6683775,地址:http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6683775,解决于java1.6.0_14 + //* + //* 【Bug说明】: + //* 在java1.6.0_14之前(当然是>=u10版),在设置窗口透明时,即调用方法 + //* AWTUtilities.setWindowOpaque(component, false)使得窗口透明后,再设置位于 + //* Windows上的第1层JPanel也为透明时(即JPanel.setOpaque(false)),则会出现类似 + //* 于很久以前给JPanel设置一个半透明色(即alpha小于255)时出现的不正确paint情况, + //* 直接导致下拉框的弹出列表ui刷新出现混乱(根本就不能即时刷新,ui一塌糊涂)的情况. + //* + //* 【java1.6.0_14版前如何解决】: + //* 该Bug 6683775在被官方解决前,怎么才能避免出现ui刷新 + //* 混乱呢?Bug 6683775上的官方回复给出了解决方案:JPanel.setDoubleBuffered(false)(官方认为 + //* 光设置JPanel.setOpaque(false)是不够的,还得取消双缓冲才行),不过好在官方在u14及以后的版本中 + //* 彻底解决了这个问题. + //* + //* 【目前BeautyEye L&F中如何解决?】: + //* 为了能在该Bug被解决前(即java小于java1.6.0_14版)BE LNF也能正常运行,只能稍微牺牲一点ui性能, + //* 按官方解决方法——“JPanel.setDoubleBuffered(false)”来解决吧. + ((JComponent) contents).setDoubleBuffered(false); + //* ######################################### Bug FIX END ############################################## + + ((JComponent) contents).setBorder( + isTooltip + ? BorderFactory.createEmptyBorder(6, 8, 12, 12)//6,8,12,8) + : isComboBoxPopup ? BorderFactory.createEmptyBorder(6, 4, 6, 4) + : BorderFactory.createEmptyBorder(5, 3, 6, 3));//10,2,10,4));//5,5,20,5)); + } + + //如果BasicComboPopup即表明它应该是ComboBox里的弹出菜单,为了使N9 + //背景能被完整展现出来则要把combox弹出列表所在的JScrollPane进行透明设置 + //,因为如果它不被透明设置则本pop的NP图背景就只能显示边缘,而且底边有一点被 + //挡住,不好看(另注:本JScrollPane在BEComboBoxUI中被设置了一个EmptyBorder,所以 + //没有在ScrollPaneUI中定认的那个ScrollBorder哦,没有那个border的目的就是为了在些使用 + //pop的背景撒) + if (isComboBoxPopup) { + Component[] cs = ((BasicComboPopup) contents).getComponents(); + //该JScrollPane就是contents的第一层子组件里 + if (cs != null && cs.length > 0) + //遍历并找出它 + for (Component com : cs) + if (com instanceof JScrollPane) + ((JScrollPane) com).setOpaque(false); + } //如果是菜单父宿主则所有JMenuItem也设置透明,jb2011 2009-08-29 + else if (contents instanceof JPopupMenu) { + MenuElement[] mes = ((JPopupMenu) contents).getSubElements(); + for (MenuElement me : mes) + if (me instanceof JMenuItem) + ((JMenuItem) me).setOpaque(false); + } + + // add the contents to the popup + w.setContentPane(imageContentPane); +// popupWindow.getContentPane().add(p, BorderLayout.CENTER); +// contents.invalidate(); + if (w.isVisible()) + // Do not call pack() if window is not visible to + // avoid early native peer creation + pack(); + } + } + + /** + * Causes the Popup to be sized to fit the preferred size + * of the Component it contains. + */ + protected void pack() { + Component c = getComponent(); + + if (c instanceof Window) + ((Window) c).pack(); + } + + /** + * Returns the Window to use as the parent of the + * Window created for the Popup. This creates + * a new DefaultFrame, if necessary. + * + * @param owner the owner + * @return the parent window + */ + protected Window getParentWindow(Component owner) { + Window window = null; + + if (owner instanceof Window) + window = (Window) owner; + else if (owner != null) + window = SwingUtilities.getWindowAncestor(owner); + if (window == null) + window = new DefaultFrame(); + return window; + } + + /** + * Creates the Component to use as the parent of the Popup. + * The default implementation creates a Window, subclasses + * should override. + * + * @param owner the owner + * @return the component + */ + protected Component createComponent(Component owner) { + if (GraphicsEnvironment.isHeadless()) + // Generally not useful, bail. + return null; + + return new HeavyWeightWindow(getParentWindow(owner)); + } + + /** + * Returns the Component returned from + * createComponent that will hold the Popup. + * + * @return the component + */ + protected Component getComponent() { + return component; + } + + /** + * Used if no valid Window ancestor of the supplied owner is found. + *

+ * PopupFactory uses this as a way to know when the Popup shouldn't be + * cached based on the Window. + */ + protected class DefaultFrame extends Frame { + } + + /** + * Component used to house window. + */ + protected class HeavyWeightWindow extends JWindow { + + /** + * Instantiates a new heavy weight window. + * + * @param parent the parent + */ + public HeavyWeightWindow(Window parent) { + super(parent); + // FIXME: 一个外国朋友用了后,在此项被设置成false的情况下,Popup里的JTextField不能编辑了! + setFocusableWindowState(true); + setName("###overrideRedirect###"); + // Popups are typically transient and most likely won't benefit + // from true double buffering. Turn it off here. +// getRootPane().setUseTrueDoubleBuffering(false);//本方法不能在包外被调用 + // Try to set "always-on-top" for the popup window. + // Applets usually don't have sufficient permissions to do it. + // In this case simply ignore the exception. + try { + setAlwaysOnTop(true); + } catch (SecurityException se) { + // setAlwaysOnTop is restricted, + // the exception is ignored + } + } + + @Override + public void update(Graphics g) { + paint(g); + } + + @Override + public void show() { + this.pack(); + super.show(); + } + } + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/popup/__UI__.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/popup/__UI__.java new file mode 100644 index 000000000..d5ec5bc61 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/popup/__UI__.java @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * __UI__.java at 2015-2-1 20:25:40, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.popup; + +import javax.swing.PopupFactory; + +public class __UI__ { + + public static PopupFactory popupFactoryDIY = new TranslucentPopupFactory(); + + public static void uiImpl() { + PopupFactory.setSharedInstance(popupFactoryDIY); + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/progress/BEProgressBarUI.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/progress/BEProgressBarUI.java new file mode 100644 index 000000000..202e1b10b --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/progress/BEProgressBarUI.java @@ -0,0 +1,281 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * BEProgressBarUI.java at 2015-2-1 20:25:39, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.progress; + +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Insets; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.geom.AffineTransform; + +import javax.swing.JComponent; +import javax.swing.JProgressBar; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.UIResource; +import javax.swing.plaf.basic.BasicProgressBarUI; +import org.jackhuang.hmcl.laf.utils.Icon9Factory; +import org.jackhuang.hmcl.laf.utils.MySwingUtilities2; +import org.jackhuang.hmcl.laf.utils.WinUtils; +import org.jb2011.ninepatch4j.NinePatch; + +/** + * 进度条的UI实现类. + * + * @author Jack Jiang(jb2011@163.com) + * @see com.sun.java.swing.plaf.windows.WindowsProgressBarUI + */ +public class BEProgressBarUI extends BasicProgressBarUI + implements org.jackhuang.hmcl.laf.BeautyEyeLNFHelper.__UseParentPaintSurported { + + private static final Icon9Factory ICON_9 = new Icon9Factory("progress_bar"); + + public static ComponentUI createUI(JComponent x) { + return new BEProgressBarUI(); + } + + /** + * 是否使用父类的绘制实现方法,true表示是. + *

+ * 因为在BE LNF中,进度条和背景都是使用N9图,没法通过设置JProgressBar的背景色和前景 + * 色来控制进度条的颜色,本方法的目的就是当用户设置了进度条的Background或Foreground 时告之本实现类不使用BE + * LNF中默认的N9图填充绘制而改用父类中的方法(父类中的方法 就可以支持颜色的设置罗,只是丑点,但总归是能适应用户的需求场景要求,其实用户完全可以 + * 通过JProgressBar.setUI(new MetalProgressBar())方式来自定义进度的UI哦). + * + * @return true, if is use parent paint + */ + @Override + public boolean isUseParentPaint() { + return progressBar != null + && (!(progressBar.getForeground() instanceof UIResource) + || !(progressBar.getBackground() instanceof UIResource)); + } + + /** + * 绘制普通进度条的方法. + * All purpose paint method that should do the right thing for almost all + * linear, determinate progress bars. By setting a few values in the + * defaults table, things should work just fine to paint your progress bar. + * Naturally, override this if you are making a circular or semi-circular + * progress bar. + * + * @param g the g + * @param c the c + * @see #paintIndeterminate + * @see javax.swing.plaf.basic.BasicProgressBarUI#paintDeterminate(java.awt.Graphics, javax.swing.JComponent) + * @since 1.4 + */ + @Override + protected void paintDeterminate(Graphics g, JComponent c) { + if (!(g instanceof Graphics2D)) + return; + + //* 如果用户作了自定义颜色设置则使用父类方法来实现绘制,否则BE LNF中没法支持这些设置哦 + if (isUseParentPaint()) { + super.paintDeterminate(g, c); + return; + } + + Insets b = progressBar.getInsets(); // area for border + int barRectWidth = progressBar.getWidth() - (b.right + b.left); + int barRectHeight = progressBar.getHeight() - (b.top + b.bottom); + + //* add by Jack Jiang 2012-06-20 START + //绘制进度条的背景 + paintProgressBarBgImpl(progressBar.getOrientation() == JProgressBar.HORIZONTAL, + g, b, barRectWidth, barRectHeight); + //* add by Jack Jiang 2012-06-20 END + + if (barRectWidth <= 0 || barRectHeight <= 0) + return; + + int amountFull = getAmountFull(b, barRectWidth, barRectHeight); + Graphics2D g2 = (Graphics2D) g; + g2.setColor(progressBar.getForeground());//在BE LNF中本属性设置目前没有意义哦,因为用的都是n9图 + + if (progressBar.getOrientation() == JProgressBar.HORIZONTAL) + if (WinUtils.isLeftToRight(c)) + paintProgressBarContentImpl(true, g, b.left, b.top, + amountFull, barRectHeight, -1); + // TODO 以下代码未经测试 + else + paintProgressBarContentImpl(true, g, barRectWidth + b.left, b.top, + barRectWidth + b.left - amountFull, barRectHeight, -1); + else // VERTICAL + paintProgressBarContentImpl(false, g, b.left, b.top + barRectHeight - amountFull, + barRectWidth, amountFull, barRectHeight); + + // Deal with possible text painting + if (progressBar.isStringPainted()) + paintString(g, b.left, b.top, barRectWidth, barRectHeight, amountFull, b); + } + + //绘制无穷进度条的方法 + /** + * All purpose paint method that should do the right thing for all linear + * bouncing-box progress bars. Override this if you are making another kind + * of progress bar. + * + * @param g the g + * @param c the c + * @see #paintDeterminate + * @since 1.4 + * @see javax.swing.plaf.basic.BasicProgressBarUI#paintIndeterminate(java.awt.Graphics, javax.swing.JComponent) + */ + @Override + protected void paintIndeterminate(Graphics g, JComponent c) { + if (!(g instanceof Graphics2D)) + return; + + //* 如果用户作了自定义颜色设置则使用父类方法来实现绘制,否则BE LNF中没法支持这些设置哦 + if (isUseParentPaint()) { + super.paintIndeterminate(g, c); + return; + } + + Insets b = progressBar.getInsets(); // area for border + int barRectWidth = progressBar.getWidth() - (b.right + b.left); + int barRectHeight = progressBar.getHeight() - (b.top + b.bottom); + + if (barRectWidth <= 0 || barRectHeight <= 0) + return; + + //* add by Jack Jiang 2012-06-20 START + //绘制进度条的背景 + paintProgressBarBgImpl(progressBar.getOrientation() == JProgressBar.HORIZONTAL, g, b, barRectWidth, barRectHeight); + //* add by Jack Jiang 2012-06-20 END + + Graphics2D g2 = (Graphics2D) g; + + // Paint the bouncing box. + boxRect = getBox(boxRect); + if (boxRect != null) { + g2.setColor(progressBar.getForeground());//BE LNF中,目前本颜色设置无意义哦,因使用的都是N9图 + //由Jack Jiang修改 +// g2.fillRect(boxRect.x, boxRect.y, boxRect.width, boxRect.height); + paintProgressBarContentImpl(progressBar.getOrientation() == JProgressBar.HORIZONTAL, + g, boxRect.x, boxRect.y, boxRect.width, boxRect.height, boxRect.height);//水平时最后一个参数无意义哦 + } + + // Deal with possible text painting + if (progressBar.isStringPainted()) + if (progressBar.getOrientation() == JProgressBar.HORIZONTAL) + paintString(g2, b.left, b.top, barRectWidth, barRectHeight, boxRect.x, boxRect.width, b); + else + paintString(g2, b.left, b.top, barRectWidth, barRectHeight, boxRect.y, boxRect.height, b); + } + + //* add by Jack Jiang + /** + * 进度条当前值的绘制实现方法. + * + * @param isHorizontal true表示水平进度条,否则表示垂直进度条 + * @param g the g + * @param x the x + * @param y the y + * @param amountFull the amount full + * @param barContentRectHeight the bar content rect height + * @param barSumHeightForVertival 本参数只在垂直进度条时有意义,目的是为了在当前值很 + * 小的情况下为了达到N9图最小绘制高度时,作修正时需要 + */ + protected void paintProgressBarContentImpl(boolean isHorizontal, + Graphics g, int x, int y, int amountFull, int barContentRectHeight, + int barSumHeightForVertival) { + NinePatch np; + + //当前的进度条内容.9.png图片的边缘非填充部分是17像素,如果要 + //填充的总宽度小于此则会出现NinePatch填充算法无法解决的填充, + //以下判断将在总宽度小于此值时强制设置成最小宽度 + final int n9min = 17;// TODO 14是相关于.9.png图片的最小填充宽度的,最好用常量实现 + if (isHorizontal) { + //如果最小填充长度小于n9图的最小长度最设定为最小长度,否则N9的填充会很难看哦 + if (amountFull > 0 && amountFull < n9min) + amountFull = n9min; + np = ICON_9.get("green"); + } else { + //如果最小填充长度小于n9图的最小长度最设定为最小长度,否则N9的填充会很难看哦 + if (barContentRectHeight > 0 && barContentRectHeight < n9min) { + y = barSumHeightForVertival - n9min; + barContentRectHeight = n9min; + } + np = ICON_9.get("blur_vertical"); + } + //开始绘制N9图 + np.draw((Graphics2D) g, x, y, amountFull, barContentRectHeight); + } + + //* add by Jack Jiang + /** + * 进度条背景填充实现方法. + * + * @param isHorizontal the is horizontal + * @param g the g + * @param b the b + * @param barRectWidth the bar rect width + * @param barRectHeight the bar rect height + */ + protected void paintProgressBarBgImpl(boolean isHorizontal, Graphics g, Insets b, int barRectWidth, int barRectHeight) { + ICON_9.getWithHorizontal("bg", isHorizontal) + .draw((Graphics2D) g, b.left, b.top, barRectWidth, barRectHeight); + } + + /** + * Paints the progress string. + * + * @param g Graphics used for drawing. + * @param x x location of bounding box + * @param y y location of bounding box + * @param width width of bounding box + * @param height height of bounding box + * @param fillStart start location, in x or y depending on orientation, of + * the filled portion of the progress bar. + * @param amountFull size of the fill region, either width or height + * depending upon orientation. + * @param b Insets of the progress bar. + */ + private void paintString(Graphics g, int x, int y, int width, int height, + int fillStart, int amountFull, Insets b) { + if (!(g instanceof Graphics2D)) + return; + + Graphics2D g2 = (Graphics2D) g; + String progressString = progressBar.getString(); + g2.setFont(progressBar.getFont()); + Point renderLocation = getStringPlacement(g2, progressString, + x, y, width, height); + Rectangle oldClip = g2.getClipBounds(); + + if (progressBar.getOrientation() == JProgressBar.HORIZONTAL) { + g2.setColor(getSelectionBackground()); + MySwingUtilities2.drawString(progressBar, g2, progressString, + renderLocation.x, renderLocation.y); + g2.setColor(getSelectionForeground()); + g2.clipRect(fillStart, y, amountFull, height); + MySwingUtilities2.drawString(progressBar, g2, progressString, + renderLocation.x, renderLocation.y); + } else { // VERTICAL + g2.setColor(getSelectionBackground()); + AffineTransform rotate + = AffineTransform.getRotateInstance(Math.PI / 2); + g2.setFont(progressBar.getFont().deriveFont(rotate)); + renderLocation = getStringPlacement(g2, progressString, + x, y, width, height); + MySwingUtilities2.drawString(progressBar, g2, progressString, + renderLocation.x, renderLocation.y); + g2.setColor(getSelectionForeground()); + g2.clipRect(x, fillStart, width, amountFull); + MySwingUtilities2.drawString(progressBar, g2, progressString, + renderLocation.x, renderLocation.y); + } + g2.setClip(oldClip); + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/progress/__UI__.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/progress/__UI__.java new file mode 100644 index 000000000..a9ca47644 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/progress/__UI__.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * __UI__.java at 2015-2-1 20:25:36, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.progress; + +import javax.swing.BorderFactory; + +import org.jackhuang.hmcl.laf.BeautyEyeLNFHelper; +import org.jackhuang.hmcl.laf.utils.UI; + +public class __UI__ extends UI { + + public static void uiImpl() { + put("ProgressBar.background", BeautyEyeLNFHelper.commonBackgroundColor); + put("ProgressBar.selectionForeground", BeautyEyeLNFHelper.commonBackgroundColor); + + // 此属性决定水平进度条的默认最小大小:15是相关于.9.png图片的最小填充 + // 高度或长度的(小于此高度则NinePatch算法无法解决而很难看) + putDim("ProgressBar.horizontalSize", 146, 15); // 默认是146,12 + putDim("ProgressBar.verticalSize", 15, 146); // 默认是12,146 + put("ProgressBar.border", BorderFactory.createEmptyBorder(0, 0, 0, 0)); + put("ProgressBarUI", BEProgressBarUI.class); + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/radio$cb_btn/BECheckBoxUI.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/radio$cb_btn/BECheckBoxUI.java new file mode 100644 index 000000000..9f605a5b6 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/radio$cb_btn/BECheckBoxUI.java @@ -0,0 +1,44 @@ +/* + * Hello Minecraft! Launcher. + * Copyright (C) 2013 huangyuhui + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see {http://www.gnu.org/licenses/}. + */ +package org.jackhuang.hmcl.laf.radio$cb_btn; + +import javax.swing.AbstractButton; +import javax.swing.JComponent; +import javax.swing.LookAndFeel; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.metal.MetalCheckBoxUI; + +/** + * + * @author huang + */ +public class BECheckBoxUI extends MetalCheckBoxUI { + + private static final BECheckBoxUI INSTANCE = new BECheckBoxUI(); + + public static ComponentUI createUI(JComponent b) { + return INSTANCE; + } + + @Override + public void installDefaults(AbstractButton b) { + super.installDefaults(b); + + LookAndFeel.installProperty(b, "opaque", false); + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/radio$cb_btn/BERadioButtonUI.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/radio$cb_btn/BERadioButtonUI.java new file mode 100644 index 000000000..04a1fd9f0 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/radio$cb_btn/BERadioButtonUI.java @@ -0,0 +1,45 @@ +/* + * Hello Minecraft! Launcher. + * Copyright (C) 2013 huangyuhui + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see {http://www.gnu.org/licenses/}. + */ +package org.jackhuang.hmcl.laf.radio$cb_btn; + +import javax.swing.AbstractButton; +import javax.swing.JComponent; +import javax.swing.LookAndFeel; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.metal.MetalRadioButtonUI; + +/** + * + * @author huang + */ +public class BERadioButtonUI extends MetalRadioButtonUI { + + private static final BERadioButtonUI INSTANCE = new BERadioButtonUI(); + + public static ComponentUI createUI(JComponent b) { + return INSTANCE; + } + + @Override + public void installDefaults(AbstractButton b) { + super.installDefaults(b); + + LookAndFeel.installProperty(b, "opaque", false); + } + +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/radio$cb_btn/__UI__.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/radio$cb_btn/__UI__.java new file mode 100644 index 000000000..041065baa --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/radio$cb_btn/__UI__.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * __UI__.java at 2015-2-1 20:25:36, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.radio$cb_btn; + +import java.awt.Component; +import java.awt.Graphics; +import java.io.Serializable; + +import javax.swing.ButtonModel; +import javax.swing.Icon; +import javax.swing.JToggleButton; +import javax.swing.UIManager; + +import org.jackhuang.hmcl.laf.BeautyEyeLNFHelper; +import org.jackhuang.hmcl.laf.utils.IconFactory; +import org.jackhuang.hmcl.laf.utils.UI; + +public class __UI__ extends UI { + private static final IconFactory RADIO = new IconFactory("radio"); + private static final IconFactory CHECK = new IconFactory("check"); + + public static void uiImpl() { + + putInsets("CheckBox.margin", 4, 3, 4, 3); + put("CheckBox.foreground", BeautyEyeLNFHelper.commonForegroundColor); + put("CheckBox.background", BeautyEyeLNFHelper.commonBackgroundColor); + put("CheckBoxUI", BECheckBoxUI.class); + + putInsets("RadioButton.margin", 4, 3, 4, 3); // 2, 2, 2, 2 + put("RadioButton.foreground", BeautyEyeLNFHelper.commonForegroundColor); + put("RadioButton.background", BeautyEyeLNFHelper.commonBackgroundColor); + put("RadioButtonUI", BERadioButtonUI.class); + + UIManager.put("RadioButton.icon", new IconFactoryIcon(RADIO)); + UIManager.put("CheckBox.icon", new IconFactoryIcon(CHECK)); + + // 衬距设定 + putInsets("RadioButton.margin", 1, 1, 1, 1); // 2, 2, 2, 2 + putInsets("CheckBox.margin", 1, 1, 1, 1); // 2, 2, 2, 2 + } + + /** + * @see com.sun.java.swing.plaf.windows.WindowsIconFactory + * @see com.sun.java.swing.plaf.windows.WindowsIconFactory.CheckBoxIcon + * @see com.sun.java.swing.plaf.windows.WindowsIconFactory.RadioBoxIcon + */ + private static class IconFactoryIcon implements Icon, Serializable { + IconFactory icon; + + public IconFactoryIcon(IconFactory icon) { + this.icon = icon; + } + + @Override + public void paintIcon(Component c, Graphics g, int x, int y) { + JToggleButton cb = (JToggleButton) c; + ButtonModel model = cb.getModel(); + + g.drawImage(icon.get(model.isSelected() ? "" : "unchecked", + model.isEnabled() ? (model.isPressed() ? "pressed" : (model.isRollover() ? "over" : "normal")) : "disabled").getImage(), + x, y, null); + } + + @Override + public int getIconWidth() { + return 24; + } + + @Override + public int getIconHeight() { + return 24; + } + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/resources/beautyeye.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/resources/beautyeye.java new file mode 100644 index 000000000..0b7bf6804 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/resources/beautyeye.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * beautyeye.java at 2015-2-1 20:25:40, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.resources; + +import java.util.ListResourceBundle; + +public final class beautyeye extends ListResourceBundle +{ + protected final Object[][] getContents() + { + return new Object[][] { + { "BETitlePane.setupButtonText", "Setup " }, + { "BETitlePane.titleMenuToolTipText", "Window operation." }, + { "BETitlePane.closeButtonToolTipext", "Close" }, + { "BETitlePane.iconifyButtonToolTipText", "Minimize" }, + { "BETitlePane.toggleButtonToolTipText", "Maximize" }, + { "BETitlePane.iconifyButtonText", "Minimize(N)" }, + { "BETitlePane.restoreButtonText", "Restore(R)" }, + { "BETitlePane.maximizeButtonText", "Maximized(X)" }, + }; + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/resources/beautyeye_zh_CN.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/resources/beautyeye_zh_CN.java new file mode 100644 index 000000000..c0d39955f --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/resources/beautyeye_zh_CN.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * beautyeye_zh_CN.java at 2015-2-1 20:25:41, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.resources; + +import java.util.ListResourceBundle; + +public final class beautyeye_zh_CN extends ListResourceBundle +{ + protected final Object[][] getContents() + { + return new Object[][] { + { "BETitlePane.setupButtonText", "\u8bbe\u7f6e " }, + { "BETitlePane.titleMenuToolTipText", "\u7a97\u53e3\u76f8\u5173\u64cd\u4f5c." }, + { "BETitlePane.closeButtonToolTipext", "\u5173\u95ed" }, + { "BETitlePane.iconifyButtonToolTipText", "\u6700\u5c0f\u5316" }, + { "BETitlePane.toggleButtonToolTipText", "\u6700\u5927\u5316" }, + { "BETitlePane.iconifyButtonText", "\u6700\u5c0f\u5316(N)" }, + { "BETitlePane.restoreButtonText", "\u8fd8\u539f(R)" }, + { "BETitlePane.maximizeButtonText", "\u6700\u5927\u5316(X)" }, + }; + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/scroll/BEScrollBarUI.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/scroll/BEScrollBarUI.java new file mode 100644 index 000000000..bb095d58c --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/scroll/BEScrollBarUI.java @@ -0,0 +1,264 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * BEScrollBarUI.java at 2015-2-1 20:25:36, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.scroll; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Paint; +import java.awt.Rectangle; + +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JScrollBar; +import javax.swing.UIManager; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicArrowButton; +import javax.swing.plaf.basic.BasicScrollBarUI; + +import org.jackhuang.hmcl.laf.BEUtils; +import org.jackhuang.hmcl.laf.utils.Icon9Factory; +import org.jb2011.ninepatch4j.NinePatch; + +/** + * 本类是滚动条的UI实现. + * + * 注:滚动条的两端箭头按钮参考自xp主题的实现,未作修改,因而这部分逻辑代码与WindowsScrollBarUI中是完全一样的. + * + * @author Jack Jiang(jb2011@163.com), 2009-09-01 + * @version 1.0 + * @see com.sun.java.swing.plaf.windows.WindowsScrollBarUI + */ +public class BEScrollBarUI extends BasicScrollBarUI { + + public static final Icon9Factory ICON_9 = new Icon9Factory("scroll_bar"); + + public static ComponentUI createUI(JComponent c) { + return new BEScrollBarUI(); + } + + @Override + protected JButton createDecreaseButton(int orientation) { + return new BEArrowButton(orientation, + UIManager.getColor("ScrollBar.thumb"), + UIManager.getColor("ScrollBar.thumbShadow"), + UIManager.getColor("ScrollBar.thumbDarkShadow"), + UIManager.getColor("ScrollBar.thumbHighlight")); + } + + @Override + protected JButton createIncreaseButton(int orientation) { + return new BEArrowButton(orientation, + UIManager.getColor("ScrollBar.thumb"), + UIManager.getColor("ScrollBar.thumbShadow"), + UIManager.getColor("ScrollBar.thumbDarkShadow"), + UIManager.getColor("ScrollBar.thumbHighlight")); + } + + /** + * WindowsArrowButton is used for the buttons to position the document + * up/down. It differs from BasicArrowButton in that the preferred size is + * always a square. + */ + protected class BEArrowButton extends BasicArrowButton { + + /** + * Instantiates a new windows arrow button. + * + * @param direction the direction + * @param background the background + * @param shadow the shadow + * @param darkShadow the dark shadow + * @param highlight the highlight + */ + public BEArrowButton(int direction, Color background, Color shadow, + Color darkShadow, Color highlight) { + super(direction, background, shadow, darkShadow, highlight); + } + + public BEArrowButton(int direction) { + super(direction); + } + + @Override + public void paint(Graphics g) { + Graphics2D g2 = (Graphics2D) g; + String id = "arrow_"; + switch (direction) { + case NORTH: + id += "top"; + break; + case SOUTH: + id += "bottom"; + break; + case WEST: + id += "left"; + break; + case EAST: + id += "right"; + break; + } + ICON_9.get(id, getModel().isRollover() ? "rollover" : "") + .draw(g2, 0, 0, getWidth(), getHeight()); + } + + @Override + public Dimension getPreferredSize() { + int size = 16; + if (scrollbar != null) { + switch (scrollbar.getOrientation()) { + case JScrollBar.VERTICAL: + size = scrollbar.getWidth(); + break; + case JScrollBar.HORIZONTAL: + size = scrollbar.getHeight(); + break; + } + size = Math.max(size, 5); + } + return new Dimension(size, size); + } + } + //----------------------------------------------------------------------------------- END + + //----------------------------------------------------------------------------------- 本次改造的主体部分 + @Override + protected void paintTrack(Graphics g, JComponent c, Rectangle trackBounds) { + if (c == null || g == null) + return; + Graphics2D g2 = (Graphics2D) g; + + Paint oldp = g2.getPaint(); + int w = trackBounds.width; + int h = trackBounds.height; + int x = trackBounds.x; + int y = trackBounds.y; + + if (this.scrollbar.getOrientation() == JScrollBar.VERTICAL) { +// //1/2处渐变 +// GradientPaint gp = new GradientPaint(x, y +// , GraphicHandler.getColor(trackColor,-15,-15,-15), w/2, y,trackColor); +// g2.setPaint(gp); +// g2.fillRect(x, y, w/2, h); +// +// g2.setPaint(oldp); +// g2.setColor(trackColor); +// g2.fillRect(w/2, y, w/2, h); + + //** 简洁版轨迹实现 + int hhhWidth = 5; + int px = (w - hhhWidth) / 2; + int delta = 50; + //第1条 + g2.setColor(new Color(150 + delta, 151 + delta, 146 + delta)); + g2.drawLine(px + 0, y + 10, px + 0, y + h - 10); + //第2条 + g2.setColor(new Color(160 + delta, 160 + delta, 162 + delta)); + g2.drawLine(px + 1, y + 10, px + 1, y + h - 10); + //第3条 + g2.setColor(new Color(163 + delta, 162 + delta, 167 + delta)); + g2.drawLine(px + 2, y + 10, px + 2, y + h - 10); + //第4条 + g2.setColor(new Color(162 + delta, 162 + delta, 162 + delta)); + g2.drawLine(px + 3, y + 10, px + 3, y + h - 10); + //第5条 + g2.setColor(new Color(150 + delta, 150 + delta, 150 + delta)); + g2.drawLine(px + 4, y + 10, px + 4, y + h - 10); + } else { + //1/2处渐变 +// GradientPaint gp = new GradientPaint(x, y +// , GraphicHandler.getColor(trackColor,-15,-15,-15), x, h/2,trackColor); +// g2.setPaint(gp); +// g2.fillRect(x, y, w, h/2); +// +// g2.setPaint(oldp); +// g2.setColor(trackColor); +// g2.fillRect(x, h/2, w, h); + + //** 简洁版轨迹实现 + int hhhWidth = 5; + int py = (h - hhhWidth) / 2; + int delta = 50; + //第1条 + g2.setColor(new Color(150 + delta, 151 + delta, 146 + delta)); + g2.drawLine(x + 10, py + 0, x + w - 10, py + 0); + //第2条 + g2.setColor(new Color(160 + delta, 160 + delta, 162 + delta)); + g2.drawLine(x + 10, py + 1, x + w - 10, py + 1); + //第3条 + g2.setColor(new Color(163 + delta, 162 + delta, 167 + delta)); + g2.drawLine(x + 10, py + 2, x + w - 10, py + 2); + //第4条 + g2.setColor(new Color(162 + delta, 162 + delta, 162 + delta)); + g2.drawLine(x + 10, py + 3, x + w - 10, py + 3); + //第5条 + g2.setColor(new Color(150 + delta, 150 + delta, 150 + delta)); + g2.drawLine(x + 10, py + 4, x + w - 10, py + 4); + } + } + + /** + * 滚动条绘制. + */ + @Override + protected void paintThumb(Graphics g, JComponent c, Rectangle thumbBounds) { + if (thumbBounds.isEmpty() || !scrollbar.isEnabled()) + return; + Graphics2D g2 = (Graphics2D) g; + int w = thumbBounds.width - 4; + int h = thumbBounds.height - 4; + g2.translate(thumbBounds.x + 2, thumbBounds.y + 2); + +// g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + BEUtils.setAntiAliasing(g2, true); + + //防止thunmb的最小高度比图片的最小高度还要小,这样在绘制时就会出问题 + //起实,目前没还没有办法很好解决,因为即使在这里作处理,但是thumb本身 + //还是那么小,所以绘图还是会有问题,但起码在不拖动时看起来是正常的,以后再解决吧! + if (this.scrollbar.getOrientation() == JScrollBar.VERTICAL) { + NinePatch np = ICON_9.getWithScrollState("vertical", isDragging, isThumbRollover()); + if (h < np.getHeight()) + paintThumbIfSoSmall(g2, 0, 0, w, h); + else + np.draw(g2, 0, 0, w, h); + } else { + NinePatch np = ICON_9.getWithScrollState("horizontal", isDragging, isThumbRollover()); + + if (w < np.getWidth()) + paintThumbIfSoSmall(g2, 0, 0, w, h); + else + np.draw(g2, 0, 0, w, h); + } + //如果滚动行宽度小于NP图的最小宽度时则交给此方法绘制(否则NP图的填充将出现虚绘,而影响滚动条的体验哦) + + g2.translate(-thumbBounds.x, -thumbBounds.y); +// g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); + BEUtils.setAntiAliasing(g2, false); + } + //----------------------------------------------------------------------------------- END + + /** + * 如果滚动条非常小(小到小于NP图的最小大小)时调用此方法实现滚动条的精确绘制. + * + * @see javax.swing.plaf.basic.BasicScrollBarUI#paintThumb(java.awt.Graphics, javax.swing.JComponent, java.awt.Rectangle) + */ + protected void paintThumbIfSoSmall(Graphics2D g2, int x, int y, int w, int h) { + final int NORMAL_ARC = 6;//定义圆角直径 + //如果w或h太小时,则就不绘制圆角了(直角即可),要不然就没法绘全圆角而很难看 + int arc = ((w <= NORMAL_ARC || h <= NORMAL_ARC) ? 0 : NORMAL_ARC); + g2.setColor(thumbDarkShadowColor); + g2.drawRoundRect(x, y, w - 1, h - 1, arc, arc);//画滚动条的外层 + g2.setColor(thumbColor); + g2.fillRoundRect(x + 1, y + 1, w - 2, h - 2, arc, arc);//填充滚动条的内层 + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/scroll/BEScrollPaneUI.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/scroll/BEScrollPaneUI.java new file mode 100644 index 000000000..68cf9065a --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/scroll/BEScrollPaneUI.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * BEScrollPaneUI.java at 2015-2-1 20:25:39, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.scroll; + +import javax.swing.JComponent; +import javax.swing.JScrollPane; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicScrollPaneUI; + +/** + * 滚动面板的UI实现类. + * + * @author Jack Jiang(jb2011@163.com + */ +public class BEScrollPaneUI extends BasicScrollPaneUI { + + public static ComponentUI createUI(JComponent x) { + return new BEScrollPaneUI(); + } + + @Override + protected void installDefaults(JScrollPane scrollpane) { + super.installDefaults(scrollpane); + +// /* ~~注:ScrollPane.opaque这个属性是jb2011自已加的,目的是控制滚动面板及其Viewport的透明性 */ +// scrollpane.setOpaque(UIManager.getBoolean("ScrollPane.opaque")); +// scrollpane.getViewport().setOpaque(UIManager.getBoolean("ScrollPane.opaque")); + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/scroll/ScrollPaneBorder.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/scroll/ScrollPaneBorder.java new file mode 100644 index 000000000..12e11f583 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/scroll/ScrollPaneBorder.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * ScrollPaneBorder.java at 2015-2-1 20:25:41, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.scroll; + +import java.awt.Insets; + +import org.jackhuang.hmcl.laf.widget.border.NinePatchBorder; + +/** + * 滚动面板默认Border的实现类. + * + * @author Jack Jiang(jb2011@163.com) + */ +public class ScrollPaneBorder extends NinePatchBorder { + + public ScrollPaneBorder() { + super(new Insets(6, 6, 8, 6), + BEScrollBarUI.ICON_9.get("scroll_pane_border")); + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/scroll/__UI__.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/scroll/__UI__.java new file mode 100644 index 000000000..161084890 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/scroll/__UI__.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * __UI__.java at 2015-2-1 20:25:36, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.scroll; + +import java.awt.Color; + +import org.jackhuang.hmcl.laf.BeautyEyeLNFHelper; +import org.jackhuang.hmcl.laf.utils.UI; + +public class __UI__ extends UI { + + public static void uiImpl() { + //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 视口的相关ui值设定 + put("Viewport.background", BeautyEyeLNFHelper.commonBackgroundColor); + put("Viewport.foreground", BeautyEyeLNFHelper.commonForegroundColor); + + //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> JScrollPane的相关ui值设定 + put("ScrollPane.border", new ScrollPaneBorder()); // 0, 0, 0, 0 + // 不能设置alpha通道小于255的透明颜色,否则会出现无法重paint的问题 + put("ScrollPane.background", Color.white);//cc)); + put("ScrollPane.foreground", BeautyEyeLNFHelper.commonForegroundColor); + put("ScrollPaneUI", BEScrollPaneUI.class); + + //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> JScrollPane的滚动条相关ui值设定 + put("ScrollBar.thumb", BeautyEyeLNFHelper.commonBackgroundColor); + put("ScrollBar.foreground", BeautyEyeLNFHelper.commonForegroundColor); + putColor("ScrollBar.background", 250, 250, 250); + putColor("ScrollBar.trackForeground", 250, 250, 250); + putColor("scrollbar", 250, 250, 250); + put("ScrollBarUI", BEScrollBarUI.class); + +// /* ~~注:这个属性是jb2011自已加的,目的是控制滚动面板及其Viewport的透明性 */ +// //设置成透明是为了让BE LNF中它的N9图实现的border能展现出图片背景来,好看一点 +// put("ScrollPane.opaque", false); + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/separator/BEPanelUI.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/separator/BEPanelUI.java new file mode 100644 index 000000000..49e6313af --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/separator/BEPanelUI.java @@ -0,0 +1,46 @@ +/* + * Hello Minecraft! Launcher. + * Copyright (C) 2013 huangyuhui + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see {http://www.gnu.org/licenses/}. + */ +package org.jackhuang.hmcl.laf.separator; + +import javax.swing.JComponent; +import javax.swing.JPanel; +import javax.swing.LookAndFeel; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.PanelUI; +import javax.swing.plaf.basic.BasicPanelUI; + +/** + * + * @author huang + */ +public class BEPanelUI extends BasicPanelUI { + + // Shared UI object + private static PanelUI panelUI; + + public static ComponentUI createUI(JComponent c) { + if (panelUI == null) + panelUI = new BEPanelUI(); + return panelUI; + } + + @Override + protected void installDefaults(JPanel p) { + LookAndFeel.installProperty(p, "opaque", false); + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/separator/BESeparatorUI.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/separator/BESeparatorUI.java new file mode 100644 index 000000000..8286f18ae --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/separator/BESeparatorUI.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * BESeparatorUI.java at 2015-2-1 20:25:39, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.separator; + +import java.awt.BasicStroke; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Stroke; + +import javax.swing.JComponent; +import javax.swing.JSeparator; +import javax.swing.LookAndFeel; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicSeparatorUI; + +/** + * Separator外观实现类. + *

+ * + * @author Jack Jiang(jb2011@163.com), 2012-11-05 + * @version 1.0 + */ +public class BESeparatorUI extends BasicSeparatorUI { + + public static ComponentUI createUI(JComponent c) { + return new BESeparatorUI(); + } + + @Override + protected void installDefaults(JSeparator s) { + LookAndFeel.installColors(s, "Separator.background", "Separator.foreground"); + LookAndFeel.installProperty(s, "opaque", Boolean.FALSE); + } + + @Override + public void paint(Graphics g, JComponent c) { + //** 绘制border的底线 + //虚线样式 + Stroke oldStroke = ((Graphics2D) g).getStroke(); + Stroke sroke = new BasicStroke(1, BasicStroke.CAP_BUTT, + BasicStroke.JOIN_BEVEL, 0, new float[] { 2, 2 }, 0);//实线,空白 + ((Graphics2D) g).setStroke(sroke);// +// super.paint(g, c); + + Dimension s = c.getSize(); + + if (((JSeparator) c).getOrientation() == JSeparator.VERTICAL) { +// System.out.println("c.getBackground()c.getBackground()c.getBackground()="+c.getBackground()); + g.setColor(c.getForeground()); + g.drawLine(0, 0, 0, s.height); + + g.setColor(c.getBackground()); + g.drawLine(1, 0, 1, s.height); + } else // HORIZONTAL + { + g.setColor(c.getForeground()); + g.drawLine(0, 0, s.width, 0); + + g.setColor(c.getBackground()); + g.drawLine(0, 1, s.width, 1); + } + + ((Graphics2D) g).setStroke(oldStroke); + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/separator/__UI__.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/separator/__UI__.java new file mode 100644 index 000000000..fa8bc46b4 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/separator/__UI__.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * __UI__.java at 2015-2-1 20:25:36, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.separator; + +import java.awt.Color; + +import javax.swing.UIManager; + +import org.jackhuang.hmcl.laf.BeautyEyeLNFHelper; +import org.jackhuang.hmcl.laf.utils.IconFactory; +import org.jackhuang.hmcl.laf.utils.UI; +import org.jackhuang.hmcl.laf.widget.border.BEDashedRoundRecBorder; + +/** + * 各种未归类的UI属性设置实现类. 本类中的各种属性日后可能会移入相应的各独立组件的UI包. + * + * @author Jack Jiang + * @version 1.1 + */ +public class __UI__ extends UI { + + private static final IconFactory ICON = new IconFactory("option_pane"); + + public static void uiImpl() { + put("control", BeautyEyeLNFHelper.commonBackgroundColor); + put("Separator.foreground", new Color(180, 180, 180)); + put("ToolTip.foreground", BeautyEyeLNFHelper.commonForegroundColor); + + put("Separator.background", Color.white); + put("Panel.foreground", BeautyEyeLNFHelper.commonForegroundColor); + put("Panel.background", BeautyEyeLNFHelper.commonBackgroundColor); + put("PanelUI", BEPanelUI.class); + + put("Label.foreground", BeautyEyeLNFHelper.commonForegroundColor); + //put("Label.background", BeautyEyeLNFHelper.commonBackgroundColor); + + put("ColorChooser.foreground", BeautyEyeLNFHelper.commonForegroundColor); + put("ColorChooser.background", BeautyEyeLNFHelper.commonBackgroundColor); + put("ColorChooser.swatchesDefaultRecentColor", BeautyEyeLNFHelper.commonBackgroundColor); + + putColor("TitledBorder.titleColor", 58, 135, 173); // TitleBorder的标题颜色 + // TitledBorder的默认border实现(windows LNF中默认是圆色灰色实线距形) + put("TitledBorder.border", new BEDashedRoundRecBorder(BeautyEyeLNFHelper.commonFocusedBorderColor)); + +// UIManager.put("OptionPaneUI",org.jb2011.lnf.windows2.ch3.NLOptionPaneUI.class.getName()); + //** Ui里的实现逻辑:此属性为true时将导致JOptionPane里的各按钮按BasicOptionPaneUI里设定的Insets进行 + //** UI展现:当按钮数<=2时使用的Insets=new Instes(2,8,2,8),否则使用new Instes(2,4,2,4), + //** 这样的逻辑下,BeautyEye L&F实现里会使得按钮高度缩小而不好看,所以要关闭此属性 + put("OptionPane.setButtonMargin", false); + put("OptionPane.foreground", BeautyEyeLNFHelper.commonForegroundColor); + put("OptionPane.background", BeautyEyeLNFHelper.commonBackgroundColor); + UIManager.put("OptionPane.questionIcon", ICON.get("question")); + UIManager.put("OptionPane.warningIcon", ICON.get("warn")); + UIManager.put("OptionPane.informationIcon", ICON.get("info")); + UIManager.put("OptionPane.errorIcon", ICON.get("error")); + + put("SeparatorUI", BESeparatorUI.class); + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/slider/BESliderUI.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/slider/BESliderUI.java new file mode 100644 index 000000000..c53f88efb --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/slider/BESliderUI.java @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * BESliderUI.java at 2015-2-1 20:25:38, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.slider; + +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Rectangle; + +import javax.swing.JComponent; +import javax.swing.JSlider; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicSliderUI; + +import org.jackhuang.hmcl.laf.BEUtils; +import org.jackhuang.hmcl.laf.utils.Icon9Factory; +import org.jackhuang.hmcl.laf.utils.IconFactory; + +/** + * JSlider的ui实现类. + * + * @author Jack Jiang(jb2011@163.com) + * @version 1.0 + * + * @see com.sun.java.swing.plaf.windows.WindowsComboBoxUI + */ +public class BESliderUI extends BasicSliderUI { + + private static final Icon9Factory ICON_9 = new Icon9Factory("slider_track"); + private static final IconFactory ICON = new IconFactory("slider"); + + /** + * 水平Slider的Thumb高度. + */ + protected final int THUMB_HEIGHT_HORIZONAL = 7;// TODO 此属性可提取为Ui属性,方便以后配置(大小应是NP图的最小高度,最大值得看JSlider的高度了) + + /** + * 垂直Slider的Thumb宽度. + */ + protected final int THUMB_WIDTH_VERTICAL = 7;// TODO 此属性可提取为Ui属性,方便以后配置(大小应是NP图的最小高度,最大值得看JSlider的高度了) + + public BESliderUI(JSlider b) { + super(b); + } + + public static ComponentUI createUI(JComponent b) { + return new BESliderUI((JSlider) b); + } + + @Override + public void paintTrack(Graphics g) { + Rectangle trackBounds = trackRect; + if (slider.getOrientation() == JSlider.HORIZONTAL) { + int cy = (trackBounds.height / 2) - 2; + int cw = trackBounds.width; + + g.translate(trackBounds.x, trackBounds.y + cy); + + //轨道背景 + ICON_9.getWithEnabled("", slider.isEnabled()) + .draw((Graphics2D) g, 0, 0, cw, THUMB_HEIGHT_HORIZONAL); + //轨道(填充到当前刻度值处) + ICON_9.getWithEnabled("foreground", slider.isEnabled()) + .draw((Graphics2D) g, 0, 0, thumbRect.x, THUMB_HEIGHT_HORIZONAL); + g.translate(-trackBounds.x, -(trackBounds.y + cy)); + } else { + int cx = (trackBounds.width / 2) - 2; + int ch = trackBounds.height; + + g.translate(trackBounds.x + cx, trackBounds.y); + + //轨道背景 + ICON_9.getWithEnabled("vertical", slider.isEnabled()) + .draw((Graphics2D) g, 0, 0, THUMB_WIDTH_VERTICAL, ch); + //轨道(填充到当前刻度值处) + // TODO BUG:当前有个bug,即在SwingSets2演示中,当thumb高度较小时,轨道半圆形被画出,这可能父类中thumbRect中计算有部碮同,有时间再研究吧,官方以后版本或许能解决哦 + ICON_9.getWithEnabled("vertical_foreground", slider.isEnabled()) + .draw((Graphics2D) g, 0, thumbRect.y, THUMB_WIDTH_VERTICAL, ch - thumbRect.y); + + g.translate(-(trackBounds.x + cx), -trackBounds.y); + } + } + + @Override + public void paintFocus(Graphics g) { + g.setColor(getFocusColor()); + BEUtils.drawDashedRect(g, focusRect.x, focusRect.y, + focusRect.width, focusRect.height); + } + + /** + * {@inheritDoc} + * + * @see javax.swing.plaf.basic.BasicSliderUI#paintThumb(java.awt.Graphics) + */ + @Override + public void paintThumb(Graphics g) { + Rectangle knobBounds = thumbRect; + int w = knobBounds.width; + int h = knobBounds.height; + + g.translate(knobBounds.x, knobBounds.y); + if (slider.isEnabled()) + g.setColor(slider.getBackground()); + else + g.setColor(slider.getBackground().darker()); + + g.drawImage(ICON.get(isPaintNoTriangleThumb() ? "notriangle" : "", + slider.getOrientation() == JSlider.HORIZONTAL ? "" : "vertical", + slider.isEnabled() ? "" : "disabled").getImage(), 0, 0, null); + + g.translate(-knobBounds.x, -knobBounds.y); + } + + /** + * Checks if is paint no triangle thumb. + * 该thumb是否是无3角箭头的样式,true表示无3解箭头(即圆形thumb),false表示有3角箭头样式 + * + * @return true, if is paint no trangle thumb + */ + protected boolean isPaintNoTriangleThumb() { + Boolean paintThumbArrowShape = (Boolean) slider + .getClientProperty("Slider.paintThumbArrowShape"); + + //不绘制有箭头标识的thumb样式(即普通圆形thumb) + return !slider.getPaintTicks() && paintThumbArrowShape == null + || Boolean.FALSE.equals(paintThumbArrowShape); + } + + /** + * {@inheritDoc} + * + * @see javax.swing.plaf.basic.BasicSliderUI#getThumbSize() + */ + @Override + protected Dimension getThumbSize() { + boolean isPaintNoTrangle = isPaintNoTriangleThumb(); + + Dimension size = new Dimension(); + if (slider.getOrientation() == JSlider.VERTICAL) { + size.width = 17;//20; + size.height = isPaintNoTrangle ? 16 : 12;//14; + } else { + size.width = isPaintNoTrangle ? 16 : 12;//14; + size.height = 17;//20; + } + return size; + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/slider/__UI__.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/slider/__UI__.java new file mode 100644 index 000000000..4d096eeac --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/slider/__UI__.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * __UI__.java at 2015-2-1 20:25:39, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.slider; + +import org.jackhuang.hmcl.laf.BeautyEyeLNFHelper; +import org.jackhuang.hmcl.laf.utils.UI; + +public class __UI__ extends UI { + + public static void uiImpl() { + put("Slider.background", BeautyEyeLNFHelper.commonBackgroundColor); + //JSlider的刻度线绘制颜色 + putColor("Slider.tickColor", 154, 154, 154); + put("Slider.foreground", BeautyEyeLNFHelper.commonForegroundColor); + //获得焦点时的insets +// putInsets("Slider.focusInsets", 2, 2, 7, 7); //父类中默认是 2, 2, 2, 2 + //获得焦点时的焦点边框颜色 + put("Slider.focus", BeautyEyeLNFHelper.commonFocusedBorderColor); //[r=113,g=111,b=100] + put("SliderUI", BESliderUI.class); + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/spinner/BESpinnerUI.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/spinner/BESpinnerUI.java new file mode 100644 index 000000000..948f94192 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/spinner/BESpinnerUI.java @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * BESpinnerUI.java at 2015-2-1 20:25:39, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.spinner; + +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; + +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.UIManager; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicSpinnerUI; + +import org.jackhuang.hmcl.laf.spinner.BESpinnerUI.GlyphButton.Type; +import org.jackhuang.hmcl.laf.BEUtils; +import org.jackhuang.hmcl.laf.utils.Icon9Factory; + +/** + * JSPinner的UI实现类. + * + * @author Jack Jiang(jb2011@163.com) + * @version 1.0 + * @see com.sun.java.swing.plaf.windows.WindowsSpinnerUI + */ +public class BESpinnerUI extends BasicSpinnerUI { + + private static final Icon9Factory ICON_9 = new Icon9Factory("spinner"); + + public static ComponentUI createUI(JComponent c) { + return new BESpinnerUI(); + } + + @Override + protected JComponent createEditor() { + JComponent e = super.createEditor(); + e.setOpaque(false); + + //参见JSpinner.NumberEditor,super.createEditor()返回值就是它的父类 + //(是一个JPanel实例),它是由一个FormatttedTextField及其父JPanel组成 + //的,所以设置完 e.setOpaque(false),还要把它的子FormatttedTextField + //设置成透明,其实它的子只有1个,它里为了适用未来的扩展假设它有很多子, + Component[] childs = e.getComponents(); + BEUtils.componentsOpaque(childs, false); + + return e; + } + + /** + * Paint. + * + * @param g the g + * @param c the c {@inheritDoc} + */ + @Override + public void paint(Graphics g, JComponent c) { + if (spinner != null) + ICON_9.getWithEnabled("", spinner.isEnabled()). + draw((Graphics2D) g, 0, 0, c.getWidth(), c.getHeight()); + super.paint(g, c); + } + + @Override + protected Component createPreviousButton() { + JButton xpButton = new GlyphButton(spinner, Type.down); + Dimension size = UIManager.getDimension("Spinner.arrowButtonSize"); + xpButton.setPreferredSize(size); + xpButton.setRequestFocusEnabled(false); + installPreviousButtonListeners(xpButton); + return xpButton; + } + + @Override + protected Component createNextButton() { + JButton xpButton = new GlyphButton(spinner, Type.up); + Dimension size = UIManager.getDimension("Spinner.arrowButtonSize"); + xpButton.setPreferredSize(size); + xpButton.setRequestFocusEnabled(false); + installNextButtonListeners(xpButton); + return xpButton; + } + + /** + * @see com.sun.java.swing.plaf.windows.XPStyle.GlyphButton + */ + static class GlyphButton extends JButton { + + private Type type = null; + + /** + * The Enum Type. + */ + public enum Type { + down, + up + } + + /** + * Instantiates a new glyph button. + * + * @param parent the parent + * @param type the type + */ + public GlyphButton(Component parent, Type type) { +// XPStyle xp = getXP(); +// skin = xp.getSkin(parent, part); + this.type = type; + setBorder(null); + setContentAreaFilled(false); + setMinimumSize(new Dimension(5, 5)); + setPreferredSize(new Dimension(16, 16)); + setMaximumSize(new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE)); + } + + @Override + public boolean isFocusTraversable() { + return false; + } + + @Override + public void paintComponent(Graphics g) { + ICON_9.get("button_" + type.name(), !isEnabled() || getModel().isPressed() ? "pressed" : ""). + draw((Graphics2D) g, 0, 0, getWidth(), getHeight()); + } + + @Override + protected void paintBorder(Graphics g) { + } + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/spinner/__UI__.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/spinner/__UI__.java new file mode 100644 index 000000000..3a496f5ff --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/spinner/__UI__.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * __UI__.java at 2015-2-1 20:25:37, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.spinner; + +import org.jackhuang.hmcl.laf.BeautyEyeLNFHelper; +import org.jackhuang.hmcl.laf.utils.UI; + +public class __UI__ extends UI { + + public static void uiImpl() { + put("Spinner.background", BeautyEyeLNFHelper.commonBackgroundColor); + put("Spinner.foreground", BeautyEyeLNFHelper.commonForegroundColor); + put("SpinnerUI", BESpinnerUI.class); + + //Spinner组件的边框 + putBorder("Spinner.border", 5, 5, 10, 5); // 3, 3, 3, 3 + //Spinner组件的2个箭头按钮的内衬距 + putInsets("Spinner.arrowButtonInsets", 1, 0, 2, 2); // 1, 1, 1, 1 + //Spinner组件的2个箭头按钮的默认大小 + putDim("Spinner.arrowButtonSize", 17, 9); + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/split/BESplitPaneDivider.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/split/BESplitPaneDivider.java new file mode 100644 index 000000000..e6719b924 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/split/BESplitPaneDivider.java @@ -0,0 +1,293 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * BESplitPaneDivider.java at 2015-2-1 20:25:40, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.split; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Stroke; + +import javax.swing.JButton; +import javax.swing.JSplitPane; +import javax.swing.UIManager; +import javax.swing.border.Border; +import javax.swing.plaf.basic.BasicSplitPaneDivider; +import javax.swing.plaf.basic.BasicSplitPaneUI; + +import org.jackhuang.hmcl.laf.BEUtils; +import org.jackhuang.hmcl.laf.utils.Icon9Factory; + +/** + * 分栏面板上的分隔线实现类. + *

+ * TODO 两个Touch按钮的位置等都是可以定制的,目前没有更好的美化灵感,以后可以再深入优先。 + * + * @author Jack Jiang(jb2011@163.com), 2012-07-13 + * @version 1.0 + */ +public class BESplitPaneDivider extends BasicSplitPaneDivider { + + private static final Icon9Factory ICON_9 = new Icon9Factory("split_touch"); + + private final int oneTouchSize; + + /** + * TODO 本常量可以做成UIManager属性以便未来使用者进行配置哦. + */ + protected final Color TOUCH_BUTTON_COLOR = new Color(58, 135, 173); + + /** + * 在水平SplitePane状态下,中间触碰装饰区装饰按钮的宽度. + */ + protected final static int TOUCH_DECRATED_BUTTON_W = 5;//* TODO 本常量可以做成UIManager属性以便未来使用者进行配置哦 + + /** + * 在水平SplitePane状态下,中间触碰装饰区装饰按钮的高度. + */ + protected final static int TOUCH_DECRATED_BUTTON_H = 30;//* TODO 本常量可以做成UIManager属性以便未来使用者进行配置哦 + + /** + * 分隔条线直线的颜色. + */ + protected final static Color TOUCH_DECRATED_BUTTON_COLOR = new Color(180, 180, 180);//* TODO 本颜色常量可以做成UIManager属性以便未来使用者进行配置哦 + + /** + * 分隔条线直线的高亮颜色(用来形成高对比度的立体效果) . + */ + protected final static Color TOUCH_DECRATED_BUTTON_HILIGHT_COLOR = Color.white;//* TODO 本颜色常量可以做成UIManager属性以便未来使用者进行配置哦 + + public BESplitPaneDivider(BasicSplitPaneUI ui) { + super(ui); + oneTouchSize = UIManager.getInt("SplitPane.oneTouchButtonSize", ui.getSplitPane().getLocale()); + } + + @Override + public void paint(Graphics g) { + Color bgColor = (splitPane.hasFocus()) + ? UIManager.getColor("SplitPane.shadow") : getBackground(); + Dimension size = getSize(); + Graphics2D g2 = ((Graphics2D) g); + BEUtils.setAntiAliasing((Graphics2D) g, true); +// g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, +// RenderingHints.VALUE_ANTIALIAS_ON); + if (bgColor != null) { + int orient = this.splitPane.getOrientation(); + if (orient == JSplitPane.HORIZONTAL_SPLIT) { + int halfWidth = size.width / 2; + int halfHeight = size.height / 2; + + //------------------------先水平居中画隔条竖线 + //虚线样式 + Stroke oldStroke = ((Graphics2D) g).getStroke(); + Stroke sroke = new BasicStroke(1, BasicStroke.CAP_BUTT, + BasicStroke.JOIN_BEVEL, 0, new float[] { 2, 2 }, 0);//实线,空白 + ((Graphics2D) g).setStroke(sroke); + + g.setColor(TOUCH_DECRATED_BUTTON_COLOR);//bgColor); +// g.fillRect(0, 0, size.width, size.height); + g.drawLine(halfWidth + 0, 0, halfWidth + 0, size.height); + //在竖线右边再画一个高对比度的竖线从而形成立体效果 + g.setColor(TOUCH_DECRATED_BUTTON_HILIGHT_COLOR); + g.drawLine(halfWidth + 1, 0, halfWidth + 1, size.height); + + ((Graphics2D) g).setStroke(oldStroke); + + //------------------------再填充触碰装饰区 + int decratedButton_w = TOUCH_DECRATED_BUTTON_W; + int decratedButton_h = TOUCH_DECRATED_BUTTON_H;//18; + int diverTouchStartX = halfWidth - decratedButton_w / 2; + ICON_9.get("bg1") + .draw((Graphics2D) g, diverTouchStartX, halfHeight - decratedButton_h / 2, + decratedButton_w, decratedButton_h); + } else { + int halfHeight = size.height / 2; + int halfWidth = size.width / 2; + + //------------------------先垂直居中画分隔条横线 + //虚线样式 + Stroke oldStroke = ((Graphics2D) g).getStroke(); + Stroke sroke = new BasicStroke(1, BasicStroke.CAP_BUTT, + BasicStroke.JOIN_BEVEL, 0, new float[] { 2, 2 }, 0);//实线,空白 + ((Graphics2D) g).setStroke(sroke); + + g.setColor(TOUCH_DECRATED_BUTTON_COLOR);//bgColor); +// g.fillRect(0, 0, size.width, size.height); + g.drawLine(0, halfHeight + 0, size.width, halfHeight + 0); + //在竖线下边再画一个高对比度的横线从而形成立体效果 + g.setColor(TOUCH_DECRATED_BUTTON_HILIGHT_COLOR); + g.drawLine(0, halfHeight + 1, size.width, halfHeight + 1); + + ((Graphics2D) g).setStroke(oldStroke); + + //------------------------再填充触碰装饰区 + int decratedButton_w = TOUCH_DECRATED_BUTTON_W; + int decratedButton_h = TOUCH_DECRATED_BUTTON_H;//18; + int diverTouchStartY = halfHeight - decratedButton_w / 2; + ICON_9.get("bg1") + .draw((Graphics2D) g, halfWidth - decratedButton_h, diverTouchStartY, + decratedButton_h, decratedButton_w); + } +// g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, +// RenderingHints.VALUE_ANTIALIAS_OFF); + BEUtils.setAntiAliasing((Graphics2D) g, false); + } + + super.paint(g); + } + + /** + * Creates and return an instance of JButton that can be used to collapse + * the left component in the split pane. + * + * 因父类方法继承重用设计不佳,此处只能全部拷过来代码,再行修改。 + * 至2012-07-13:本方法只作了关于箭头按钮的填充颜色的改变。 + * + * @return the j button + * @see javax.swing.plaf.basic.BasicSplitPaneDivider#createLeftOneTouchButton() + */ + @Override + protected JButton createLeftOneTouchButton() { + JButton b = new JButton() { + @Override + public void setBorder(Border b) { + } + + @Override + public void paint(Graphics g) { + if (splitPane != null) { + int[] xs = new int[3]; + int[] ys = new int[3]; + int blockSize; + + // Fill the background first ... + g.setColor(this.getBackground()); + g.fillRect(0, 0, this.getWidth(), this.getHeight()); + + // ... then draw the arrow. + g.setColor(TOUCH_BUTTON_COLOR);//Color.black); + + //* 开启反走样 + BEUtils.setAntiAliasing((Graphics2D) g, true); + + if (orientation == JSplitPane.VERTICAL_SPLIT) { + blockSize = Math.min(getHeight(), oneTouchSize); + xs[0] = blockSize; + xs[1] = 0; + xs[2] = blockSize << 1; + ys[0] = 0; + ys[1] = ys[2] = blockSize; + g.drawPolygon(xs, ys, 3); // Little trick to make the + // arrows of equal size + } else { + blockSize = Math.min(getWidth(), oneTouchSize); + xs[0] = xs[2] = blockSize; + xs[1] = 0; + ys[0] = 0; + ys[1] = blockSize; + ys[2] = blockSize << 1; + } + g.fillPolygon(xs, ys, 3); + + //* 关闭反走样 + BEUtils.setAntiAliasing((Graphics2D) g, false); + } + } + + // Don't want the button to participate in focus traversable. + @Override + public boolean isFocusTraversable() { + return false; + } + }; + b.setMinimumSize(new Dimension(oneTouchSize, oneTouchSize)); + b.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + b.setFocusPainted(false); + b.setBorderPainted(false); + b.setRequestFocusEnabled(false); + return b; + } + + /** + * Creates and return an instance of JButton that can be used to collapse + * the right component in the split pane. + * + * 因父类方法继承重用设计不佳,此处只能全部拷过来代码,再行修改。 + * 至2012-07-13:本方法只作了关于箭头按钮的填充颜色的改变。 + * + * @return the j button + * @see javax.swing.plaf.basic.BasicSplitPaneDivider#createRightOneTouchButton() + */ + @Override + protected JButton createRightOneTouchButton() { + JButton b = new JButton() { + @Override + public void setBorder(Border border) { + } + + @Override + public void paint(Graphics g) { + if (splitPane != null) { + int[] xs = new int[3]; + int[] ys = new int[3]; + int blockSize; + + // Fill the background first ... + g.setColor(this.getBackground()); + g.fillRect(0, 0, this.getWidth(), + this.getHeight()); + + //* 开启反走样 + BEUtils.setAntiAliasing((Graphics2D) g, true); + + // ... then draw the arrow. + if (orientation == JSplitPane.VERTICAL_SPLIT) { + blockSize = Math.min(getHeight(), oneTouchSize); + xs[0] = blockSize; + xs[1] = blockSize << 1; + xs[2] = 0; + ys[0] = blockSize; + ys[1] = ys[2] = 0; + } else { + blockSize = Math.min(getWidth(), oneTouchSize); + xs[0] = xs[2] = 0; + xs[1] = blockSize; + ys[0] = 0; + ys[1] = blockSize; + ys[2] = blockSize << 1; + } + + g.setColor(TOUCH_BUTTON_COLOR);//Color.black); + + g.fillPolygon(xs, ys, 3); + + //* 关闭反走样 + BEUtils.setAntiAliasing((Graphics2D) g, false); + } + } + + // Don't want the button to participate in focus traversable. + @Override + public boolean isFocusTraversable() { + return false; + } + }; + b.setMinimumSize(new Dimension(oneTouchSize, oneTouchSize)); + b.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + b.setFocusPainted(false); + b.setBorderPainted(false); + b.setRequestFocusEnabled(false); + return b; + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/split/BESplitPaneUI.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/split/BESplitPaneUI.java new file mode 100644 index 000000000..9ea484fcd --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/split/BESplitPaneUI.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * BESplitPaneUI.java at 2015-2-1 20:25:40, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.split; + +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicSplitPaneDivider; +import javax.swing.plaf.basic.BasicSplitPaneUI; + +/** + * 分栏面板的UI实现. + * + * @author Jack Jiang(jb2011@163.com), 2012-07-10 + * @version 1.0 + */ +public class BESplitPaneUI extends BasicSplitPaneUI { + + public BESplitPaneUI() { + super(); + } + + public static ComponentUI createUI(JComponent x) { + return new BESplitPaneUI(); + } + + @Override + public BasicSplitPaneDivider createDefaultDivider() { + return new BESplitPaneDivider(this); + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/split/SplitPaneDividerBorder.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/split/SplitPaneDividerBorder.java new file mode 100644 index 000000000..ea8baf499 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/split/SplitPaneDividerBorder.java @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * SplitPaneDividerBorder.java at 2015-2-1 20:25:41, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.split; + +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Insets; + +import javax.swing.JSplitPane; +import javax.swing.border.Border; +import javax.swing.plaf.UIResource; +import javax.swing.plaf.basic.BasicSplitPaneDivider; +import javax.swing.plaf.basic.BasicSplitPaneUI; + +/** + * 分隔条的border实现类. + *

+ * Draws the border around the divider in a splitpane. To get the appropriate + * effect, this needs to be used with a SplitPaneBorder. + * + * 主要修改了UI填充实现部分 + * + * @author Jack Jiang(jb2011@163.com) + * @see javax.swing.plaf.basic.BasicBorders + */ +public class SplitPaneDividerBorder implements Border, UIResource { +// javax.swing.plaf.basic.BasicBorders.SplitPaneDividerBorder +// private Color highlight; +// private Color shadow; + +// public SplitPaneDividerBorder(Color highlight, Color shadow) +// { +// this.highlight = highlight; +// this.shadow = shadow; +// } + @Override + public void paintBorder(Component c, Graphics g, int x, int y, int width, + int height) { + //在目前的视觉效果下不需要这个border的绘制哦 +// Graphics2D g2d = (Graphics2D) g; +// Component child; +// Rectangle cBounds; +// JSplitPane splitPane = ((BasicSplitPaneDivider) c).getBasicSplitPaneUI().getSplitPane(); +// Dimension size = c.getSize(); +// +// child = splitPane.getLeftComponent(); +// // This is needed for the space between the divider and end of +// // splitpane. +// g.setColor(c.getBackground()); +// g.drawRect(x, y, width - 1, height - 1); +// +// if (splitPane.getOrientation() == JSplitPane.HORIZONTAL_SPLIT) +// { +//// if (child != null) +//// { +//// g.setColor(shadow);//highlight); +//// g.drawLine(0, 0, 0, size.height); +//// } +//// child = splitPane.getRightComponent(); +//// if (child != null) +//// { +//// g.setColor(shadow); +//// g.drawLine(size.width - 1, 0, size.width - 1, size.height); +//// } +// } +// else +// { +//// if (child != null) +//// { +//// g.setColor(shadow);//highlight); +//// g.drawLine(0, 0, size.width, 0); +//// } +//// child = splitPane.getRightComponent(); +//// if (child != null) +//// { +//// g.setColor(shadow); +//// g.drawLine(0, size.height - 1, size.width,size.height - 1); +//// +//// } +// } + } + + @Override + public Insets getBorderInsets(Component c) { + Insets insets = new Insets(0, 0, 0, 0); + if (c instanceof BasicSplitPaneDivider) { + BasicSplitPaneUI bspui = ((BasicSplitPaneDivider) c) + .getBasicSplitPaneUI(); + + if (bspui != null) { + JSplitPane splitPane = bspui.getSplitPane(); + + if (splitPane != null) { + if (splitPane.getOrientation() == JSplitPane.HORIZONTAL_SPLIT) { + insets.top = insets.bottom = 0; + insets.left = insets.right = 1; + return insets; + } + // VERTICAL_SPLIT + insets.top = insets.bottom = 1; + insets.left = insets.right = 0; + return insets; + } + } + } + insets.top = insets.bottom = insets.left = insets.right = 1; + return insets; + } + + @Override + public boolean isBorderOpaque() { + return true; + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/split/__UI__.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/split/__UI__.java new file mode 100644 index 000000000..677fb1174 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/split/__UI__.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * __UI__.java at 2015-2-1 20:25:39, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.split; + +import org.jackhuang.hmcl.laf.utils.UI; + +public class __UI__ extends UI { + + public static void uiImpl() { + putColor("SplitPane.shadow", 200, 200, 200); // 本属性在BE LNF中暂时没用到 + //JSplitePane的默认背景色 + putColor("SplitPane.background", 250, 250, 250); // 238, 241, 243 + //JSplitePane的边框实现 + put("SplitPane.border", new org.jackhuang.hmcl.laf.scroll.ScrollPaneBorder());// 0, 0, 0, 0 + put("SplitPaneUI", BESplitPaneUI.class); + + //分隔条拖动时的颜色(说明:此值可以设置alpha通道以便达到半透明效果哦) + putColor("SplitPaneDivider.draggingColor", 0, 0, 0, 50); + //触碰按钮的默认大小 + // see javax.swing.plaf.basic.BasicSplitPaneDivider.ONE_TOUCH_SIZE = 6 + put("SplitPane.oneTouchButtonSize", 4); + //分隔条的默认大小 + put("SplitPane.dividerSize", 7); //drfault is 5 + //分隔条的边框实现 + put("SplitPaneDivider.border", new SplitPaneDividerBorder()); + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/tab/BETabbedPaneUI.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/tab/BETabbedPaneUI.java new file mode 100644 index 000000000..5c74fcfe2 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/tab/BETabbedPaneUI.java @@ -0,0 +1,334 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * BETabbedPaneUI.java at 2015-2-1 20:25:36, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.tab; + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Rectangle; + +import javax.swing.JComponent; +import javax.swing.UIManager; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicTabbedPaneUI; + +import org.jackhuang.hmcl.laf.BEUtils; + +/** + * JTabbedPane的UI实现类. + * + * @author Jack Jiang(jb2011@163.com), 2012-01-12 + * @version 1.1 + * @see com.sun.java.swing.plaf.windows.WindowsTabbedPaneUI + */ +public class BETabbedPaneUI extends BasicTabbedPaneUI { + + public static ComponentUI createUI(JComponent c) { + return new BETabbedPaneUI(); + } + + /** + * 本方法的重写copy自 com.sun.java.swing.plaf.windows.WindowsTabbedPaneUI,基本未修改代码 + * 重写父类方法实现rover状态下的tab的ui重绘(父类方法只是实现了rolloverTab 的设置,不步及ui重绘制,因Basic + * LNF中没有实现rover状态的ui样式) + * + * @see javax.swing.plaf.basic.BasicTabbedPaneUI#setRolloverTab(int) + */ + @Override + protected void setRolloverTab(int index) { + int oldRolloverTab = getRolloverTab(); + super.setRolloverTab(index); + Rectangle r1 = null; + Rectangle r2 = null; + if ((oldRolloverTab >= 0) && (oldRolloverTab < tabPane.getTabCount())) + r1 = getTabBounds(tabPane, oldRolloverTab); + if (index >= 0) + r2 = getTabBounds(tabPane, index); + if (r1 != null) + if (r2 != null) + tabPane.repaint(r1.union(r2)); + else + tabPane.repaint(r1); + else if (r2 != null) + tabPane.repaint(r2); + } + + /** + * this function draws the border around each tab note that this function + * does now draw the background of the tab. that is done elsewhere. + * + * @param g the g + * @param tabPlacement the tab placement + * @param tabIndex the tab index + * @param x the x + * @param y the y + * @param w the w + * @param h the h + * @param isSelected the is selected + * @see javax.swing.plaf.basic.BasicTabbedPaneUI#paintTabBorder(java.awt.Graphics, int, int, int, int, int, int, boolean) + */ + @Override + protected void paintTabBorder(Graphics g, int tabPlacement, + int tabIndex, int x, int y, int w, int h, boolean isSelected) { +// g.setColor(lightHighlight); +// Graphics2D g2d = (Graphics2D)g; + Graphics2D g2d = (Graphics2D) g.create(); + g2d.translate(x, y); + + //* 由Jack Jiang添加:true表示该tab当前正处于鼠标rover其上的状态 + //* this.getRolloverTab()的返回值由父类方法 setRolloverTab()设定并实现ui重绘的 + boolean isRover = (this.getRolloverTab() == tabIndex); + //* 由Jack Jiang添加:true表示该tab处于可用状态,否则表示处于禁用状态 + boolean isEnableAt = this.tabPane.isEnabledAt(tabIndex); + + switch (tabPlacement) { + case LEFT: + g2d.scale(-1.0, 1.0); + g2d.rotate(Math.toRadians(90.0)); + paintTabBorderImpl(g2d, isEnableAt, isSelected, isRover, 0, 0, h, w); + break; + case RIGHT: + g2d.translate(w, 0); + g2d.rotate(Math.toRadians(90.0)); + paintTabBorderImpl(g2d, isEnableAt, isSelected, isRover, 0, 0, h, w); + break; + case BOTTOM: + g2d.translate(0, h); + g2d.scale(-1.0, 1.0); + g2d.rotate(Math.toRadians(180.0)); + paintTabBorderImpl(g2d, isEnableAt, isSelected, isRover, 0, 0, w, h); + break; + case TOP: + default: + paintTabBorderImpl(g2d, isEnableAt, isSelected, isRover, 0, 0, w, h); + break; + } + } + //* paintTabBorder的绘制实现方法,2012-01-12日 BY Jack Jiang + + /** + * Paint tab border impl. + * + * @param g2d the g2d + * @param isEnableAt the is enable at + * @param isSelected the is selected + * @param isRover the is rover + * @param x the x + * @param y the y + * @param w the w + * @param h the h + */ + private void paintTabBorderImpl(Graphics2D g2d, boolean isEnableAt, boolean isSelected, + boolean isRover, int x, int y, int w, int h) { + //** modified by jb2011 改为NinePatch图片实现,Y + 1 的目的是使得选中时的底线能往下画一个像素(这样好看点) + if (isSelected) { + g2d.setColor(UIManager.getColor("TabbedPane.selectedForeground")); + g2d.fillRect(x, y + h - 1, w, 2); + } + //ICON_9.get("", isSelected ? "selected" : (isEnableAt && isRover ? "normal_rollover" : "normal")) + // .draw(g2d, x, y + 1, w, h); + } + + /** + * 重写本方法的目的仅是把原来的默认实线变成虚线而已哦 + * + * @see + * javax.swing.plaf.basic.BasicTabbedPaneUI#paintContentBorder(java.awt.Graphics, + * int, int) + */ + @Override + protected void paintContentBorder(Graphics g, int tabPlacement, int selectedIndex) { + /*//*** add by jb2011 2012-08-23 START + //虚线样式 + Stroke oldStroke = ((Graphics2D) g).getStroke(); + Stroke sroke = new BasicStroke(1, BasicStroke.CAP_BUTT, + BasicStroke.JOIN_BEVEL, 0, new float[] { 2, 2 }, 0);//实线,空白 + ((Graphics2D) g).setStroke(sroke); + //*** add by jb2011 2012-08-23 END +*/ + //调用父类默认实现 + super.paintContentBorder(g, tabPlacement, selectedIndex); +/* + //*** add by jb2011 2012-08-23 START + ((Graphics2D) g).setStroke(oldStroke); + //*** add by jb2011 2012-08-23 END*/ + } + + // + /** + * JTabbedPaneUI 内容面板的上边框绘制方法(默认就是内容面板上方的那条灰色). + * + * @see + * javax.swing.plaf.basic.BasicTabbedPaneUI#paintContentBorderTopEdge(java.awt.Graphics, + * int, int, int, int, int, int) + */ + @Override + protected void paintContentBorderTopEdge(Graphics g, int tabPlacement, + int selectedIndex, + int x, int y, int w, int h) { + //此模式下不绘制其它3条边框,视觉上好看一些 + if (tabPlacement == TOP) + //调用父类默认实现 + super.paintContentBorderTopEdge(g, tabPlacement, selectedIndex, x, y, w, h); + } + + /** + * JTabbedPaneUI 内容面板的左边框绘制方法. + * + * @see + * javax.swing.plaf.basic.BasicTabbedPaneUI#paintContentBorderLeftEdge(java.awt.Graphics, + * int, int, int, int, int, int) + */ + @Override + protected void paintContentBorderLeftEdge(Graphics g, int tabPlacement, + int selectedIndex, + int x, int y, int w, int h) { + //此模式下不绘制其它3条边框,视觉上好看一些 + if (tabPlacement == LEFT) + //调用父类默认实现 + super.paintContentBorderLeftEdge(g, tabPlacement, selectedIndex, x, y, w, h); + } + + /** + * JTabbedPaneUI 内容面板的底边框绘制方法. + * + * @see + * javax.swing.plaf.basic.BasicTabbedPaneUI#paintContentBorderBottomEdge(java.awt.Graphics, + * int, int, int, int, int, int) + */ + @Override + protected void paintContentBorderBottomEdge(Graphics g, int tabPlacement, + int selectedIndex, + int x, int y, int w, int h) { + //此模式下不绘制其它3条边框,视觉上好看一些 + if (tabPlacement == BOTTOM) + //调用父类默认实现 + super.paintContentBorderBottomEdge(g, tabPlacement, selectedIndex, x, y, w, h); + } + + /** + * JTabbedPaneUI 内容面板的右边框绘制方法. + * + * @see + * javax.swing.plaf.basic.BasicTabbedPaneUI#paintContentBorderRightEdge(java.awt.Graphics, + * int, int, int, int, int, int) + */ + @Override + protected void paintContentBorderRightEdge(Graphics g, int tabPlacement, + int selectedIndex, + int x, int y, int w, int h) { + //此模式下不绘制其它3条边框,视觉上好看一些 + if (tabPlacement == RIGHT) + //调用父类默认实现 + super.paintContentBorderRightEdge(g, tabPlacement, selectedIndex, x, y, w, h); + } + + /** + * 获得焦点时的虚线框绘制方法 + * + * @see + * javax.swing.plaf.basic.BasicTabbedPaneUI#paintFocusIndicator(java.awt.Graphics, + * int, java.awt.Rectangle[], int, java.awt.Rectangle, java.awt.Rectangle, + * boolean) + */ + @Override + protected void paintFocusIndicator(Graphics g, int tabPlacement, + Rectangle[] rects, int tabIndex, + Rectangle iconRect, Rectangle textRect, + boolean isSelected) { + Rectangle tabRect = rects[tabIndex]; + if (tabPane.hasFocus() && isSelected) { + int x, y, w, h; + g.setColor(focus); + switch (tabPlacement) { + case LEFT: + x = tabRect.x + 4;//父类中默认是+3 + y = tabRect.y + 6;//父类中默认是+3 + w = tabRect.width - 7;//父类中默认是 - 5 + h = tabRect.height - 12;//父类中默认是-6 + break; + case RIGHT: + x = tabRect.x + 4;//父类中默认是+ 2 + y = tabRect.y + 6;//父类中默认是+ 3 + w = tabRect.width - 9;//父类中默认是- 5 + h = tabRect.height - 12;//父类中默认是- 6 + break; + case BOTTOM: + x = tabRect.x + 6;//父类中默认是+ 3 + y = tabRect.y + 4;//父类中默认是+ 2 + w = tabRect.width - 12;//父类中默认是- 6 + h = tabRect.height - 9;//父类中默认是- 5 + break; + case TOP: + default: + //** modified by jb2011:根据整体效果进行偏移修正 + x = tabRect.x + 6;//父类中默认是+3 + //** modified by jb2011:根据整体效果进行偏移修正 + y = tabRect.y + 4;//父类中默认是+3 + //** modified by jb2011:根据整体效果进行偏移修正 + w = tabRect.width - 12;//父类中默认是-6 + //** modified by jb2011:-8的目的是使得焦点虚线框与选中底边保持一个像素的距离,否则挨在一起在视觉上效果会较差 + h = tabRect.height - 8;//父类中默认是 - 5 + } + + //** modified by jb2011:绘制虚线方法改成可以设置虚线步进的方法,步进设为2则更好看一点 +// BasicGraphicsUtils.drawDashedRect(g, x, y, w, h); + BEUtils.drawDashedRect(g, x, y, w, h); + // 绘制虚线框的半透明白色立体阴影(因主背景色较淡,效果不明显,但显然比没有要好) + g.setColor(new Color(255, 255, 255, 255));// TODO 此值可提炼成UIManager属性哦 + // 立体阴影就是向右下偏移一个像素实现的 + BEUtils.drawDashedRect(g, x + 1, y + 1, w, h); + } + } + + /** + * 重写并修改本方法的目的是修正tab上的文本显示Y坐标方向上的偏移,以便与背景协调 + * @see javax.swing.plaf.basic.BasicTabbedPaneUI#getTabLabelShiftY(int, int, boolean) + */ + @Override + protected int getTabLabelShiftY(int tabPlacement, int tabIndex, boolean isSelected) { + return 0; + /* + switch (tabPlacement) { + case BOTTOM: + return isSelected ? 1 : -1; + case LEFT: + case RIGHT: + return rects[tabIndex].height % 2; + case TOP: + default: + //** 由jb2011 2012-08-24修改:目的是使得选中时和未选中时的文本(包括图标 + //** 默认实现中之所以要产生它个效果是为了营造立体效果,而BE LNF中并不需要 + //** )不要往上或往下偏移的太多(太多则相当难看) +// nudge = isSelected? -1 : 1;//本行是原父类中的默认实现哦 + return -2;//由jb2011修改,目的是让文本相对现在的背景往上偏移一点,好看一些 + }*/ + } + + @Override + protected int getTabLabelShiftX(int tabPlacement, int tabIndex, boolean isSelected) { + Rectangle tabRect = rects[tabIndex]; + String propKey = "labelShift"; + int nudge = UIManager.getInt("TabbedPane." + propKey); + + switch (tabPlacement) { + case LEFT: + return nudge; + case RIGHT: + return -nudge; + case BOTTOM: + case TOP: + default: + return tabRect.width % 2; + } + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/tab/__UI__.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/tab/__UI__.java new file mode 100644 index 000000000..122c1f274 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/tab/__UI__.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * __UI__.java at 2015-2-1 20:25:40, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.tab; + +import java.awt.Font; +import javax.swing.UIManager; +import javax.swing.plaf.FontUIResource; +import org.jackhuang.hmcl.laf.BeautyEyeLNFHelper; +import org.jackhuang.hmcl.laf.utils.UI; + +public class __UI__ extends UI { + + public static void uiImpl() { + FontUIResource f = (FontUIResource) UIManager.get("TabbedPane.font"); + UIManager.put("TabbedPane.font", new FontUIResource(new Font(f.getName(), f.getStyle(), 14))); + put("TabbedPane.background", BeautyEyeLNFHelper.commonBackgroundColor); + put("TabbedPane.foreground", BeautyEyeLNFHelper.commonForegroundColor); + put("TabbedPane.opaque", false); +// put("TabbedPane.tabRunOverlay", 2);//本属性无效果 + //false表示tab在边框虑线之上而不是重叠效果 + put("TabbedPane.tabsOverlapBorder", true); + put("TabbedPaneUI", BETabbedPaneUI.class); + //此属性决定了整个JTabbedPane区域的内衬 + putInsets("TabbedPane.tabAreaInsets", 3, 20, 2, 20);// 3, 2, 2, 2 + //此属性决定了tab与内容面板间的空白 + putInsets("TabbedPane.contentBorderInsets", 2, 0, 3, 0);// 2, 2, 3, 3 + //此参数将决定选中时的tab与左右相邻tab的重合度,正值表示重合、负值表示间隔(空白) + //* 注意与NP图的边缘留白配合使用能达到更灵活的效果 + putInsets("TabbedPane.selectedTabPadInsets", 0, 1, 0, 2);// 2, 2, 2, 1 + //此属性决定了JTabbedPane的tab标签的内衬 + putInsets("TabbedPane.tabInsets", 7, 7, 7, 7); + //获得焦点时的虚线框颜色 + putColor("TabbedPane.focus", 130, 130, 130); + //在BE LNF中,此颜色将决定TabPlacement=TOP和LEFT二种类型TabbedPane的内容面板那条虚线的颜色 + putColor("TabbedPane.highlight", 228, 228, 231);//new Color(200,200,200))); + //在BE LNF中,此颜色将决定TabPlacement=RIGHT和BOTTOM二种类型TabbedPane的内容面板那条虚线的颜色 + put("TabbedPane.shadow", BeautyEyeLNFHelper.commonFocusedBorderColor);//192,192,192); + //在BE LNF中,因TabPlacement=RIGHT和BOTTOM二种类型时,父类方法会默认再多画一条深色立体线而使得在BE LNF中 + //不好看,此颜色设置的目的就是让此立体阴影线与背景色一致从而看不出它的效果,进而不影响内容面板那条虚线在BE LNF中的视觉效果 + put("TabbedPane.darkShadow", BeautyEyeLNFHelper.commonBackgroundColor); + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/table/BETableHeaderUI.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/table/BETableHeaderUI.java new file mode 100644 index 000000000..02659e6ac --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/table/BETableHeaderUI.java @@ -0,0 +1,479 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * BETableHeaderUI.java at 2015-2-1 20:25:38, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.table; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Insets; +import java.awt.Point; +import java.awt.Rectangle; +import java.io.Serializable; + +import javax.swing.Icon; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JTable; +import javax.swing.RowSorter; +import javax.swing.SortOrder; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.border.Border; +import javax.swing.border.EmptyBorder; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.UIResource; +import javax.swing.plaf.basic.BasicTableHeaderUI; +import javax.swing.table.DefaultTableCellRenderer; +import javax.swing.table.JTableHeader; +import javax.swing.table.TableCellRenderer; +import org.jackhuang.hmcl.laf.utils.Icon9Factory; + +/** + * 表格头UI实现类。 + *

+ * 本类代码只能用于JDK1.6及以上版本,因JDK1.5及以下版本没法兼容本类中的很大一部分关键代码。 + * + * @author Jack Jiang(jb2011@163.com), 2011-03-28 + * @see com.sun.java.swing.plaf.windows.WindowsTableHeaderUI + */ +public class BETableHeaderUI extends BasicTableHeaderUI { + + protected static final Icon9Factory ICON_9 = new Icon9Factory("table"); + + private TableCellRenderer originalHeaderRenderer; + + public static ComponentUI createUI(JComponent h) { + return new BETableHeaderUI(); + } + + @Override + public void installUI(JComponent c) { + super.installUI(c); + originalHeaderRenderer = header.getDefaultRenderer(); + if (originalHeaderRenderer instanceof UIResource) + header.setDefaultRenderer(new XPDefaultRenderer()); + } + + @Override + public void uninstallUI(JComponent c) { + if (header.getDefaultRenderer() instanceof XPDefaultRenderer) + header.setDefaultRenderer(originalHeaderRenderer); + super.uninstallUI(c); + } + + @Override + protected void rolloverColumnUpdated(int oldColumn, int newColumn) { + header.repaint(header.getHeaderRect(oldColumn)); + header.repaint(header.getHeaderRect(newColumn)); + } + + //绘制头Ui内容,本方法提取出来是为了在ELineNumTable里也可以用到(它是进行了自定义Ui头实现) + /** + * Paint head cell. + * + * @param g the g + * @param headCellSize the head cell size + */ + public static void paintHeadCell(Graphics g, Dimension headCellSize) { + int w = headCellSize.width, h = headCellSize.height - 1; + +// Graphics2D g2 = (Graphics2D)g; +// //渐变背景 +// Paint oldp= g2.getPaint(); +// GradientPaint gp = new GradientPaint(0, 0 +// , new Color(250,250,250) +// , 0, h,new Color(241,241,241)); +// g2.setPaint(gp); +// g.fillRect(0, 0, w, h); +// //矩形区下1/2处非渐变填充(为了产生立体效果) +// g2.setPaint(oldp); +// +// //上下线条,突出立体感 +// g.setColor(new Color(215,215,215)); +// g.drawLine(0, 0, w, 0); +// g.setColor(new Color(249,250,249)); +// g.drawLine(0, h-1, w, h-1); +// g.setColor(new Color(209,209,209)); +// g.drawLine(0, h, w, h); + ICON_9.get("header_cell") + .draw((Graphics2D) g, 0, 0, w, h);//表头背景 + ICON_9.get("header_cell_separator") + .draw((Graphics2D) g, w - 2, 0, 4, h - 1);//表头右边的分隔线,h-1是为了让分隔线往上移一个像素,好看一点 + } + + public class DefaultTableCellHeaderRenderer extends DefaultTableCellRenderer + implements UIResource { + + private boolean horizontalTextPositionSet; + private Icon sortArrow; + private final EmptyIcon emptyIcon = new EmptyIcon(); + + public DefaultTableCellHeaderRenderer() { + setHorizontalAlignment(JLabel.CENTER); + } + + @Override + public void setHorizontalTextPosition(int textPosition) { + horizontalTextPositionSet = true; + super.setHorizontalTextPosition(textPosition); + } + + @Override + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column) { + Icon sortIcon = null; + + boolean isPaintingForPrint = false; + + if (table != null) { + JTableHeader header = table.getTableHeader(); + if (header != null) { + Color fgColor = null; + Color bgColor = null; + if (hasFocus) { + fgColor = UIManager.getColor("TableHeader.focusCellForeground", this.getLocale()); + bgColor = UIManager.getColor("TableHeader.focusCellBackground", this.getLocale()); + } + if (fgColor == null) + fgColor = header.getForeground(); + if (bgColor == null) + bgColor = header.getBackground(); + setForeground(fgColor); + setBackground(bgColor); + + setFont(header.getFont()); + + isPaintingForPrint = header.isPaintingForPrint(); + } + + if (!isPaintingForPrint && table.getRowSorter() != null) { + if (!horizontalTextPositionSet) + // There is a row sorter, and the developer hasn't + // set a text position, change to leading. + setHorizontalTextPosition(JLabel.LEADING); + SortOrder sortOrder = getColumnSortOrder(table, column); + if (sortOrder != null) + switch (sortOrder) { + case ASCENDING: + sortIcon = UIManager.getIcon("Table.ascendingSortIcon", this.getLocale()); + break; + case DESCENDING: + sortIcon = UIManager.getIcon("Table.descendingSortIcon", this.getLocale()); + break; + case UNSORTED: + sortIcon = UIManager.getIcon("Table.naturalSortIcon", this.getLocale()); + break; + } + } + } + + setText(value == null ? "" : value.toString()); + setIcon(sortIcon); + sortArrow = sortIcon; + + Border border = null; + if (hasFocus) + border = UIManager.getBorder("TableHeader.focusCellBorder", this.getLocale()); + if (border == null) + border = UIManager.getBorder("TableHeader.cellBorder", this.getLocale()); + setBorder(border); + + return this; + } + + public SortOrder getColumnSortOrder(JTable table, int column) { + SortOrder rv = null; + if (table == null || table.getRowSorter() == null) + return rv; + java.util.List sortKeys + = table.getRowSorter().getSortKeys(); + if (sortKeys.size() > 0 && sortKeys.get(0).getColumn() + == table.convertColumnIndexToModel(column)) + rv = sortKeys.get(0).getSortOrder(); + return rv; + } + + @Override + public void paintComponent(Graphics g) { + boolean b = UIManager.getBoolean("TableHeader.rightAlignSortArrow", this.getLocale()); + if (b && sortArrow != null) { + //emptyIcon is used so that if the text in the header is right + //aligned, or if the column is too narrow, then the text will + //be sized appropriately to make room for the icon that is about + //to be painted manually here. + emptyIcon.width = sortArrow.getIconWidth(); + emptyIcon.height = sortArrow.getIconHeight(); + setIcon(emptyIcon); + super.paintComponent(g); + Point position = computeIconPosition(g); + sortArrow.paintIcon(this, g, position.x, position.y); + } else + super.paintComponent(g); + } + + private Point computeIconPosition(Graphics g) { + FontMetrics fontMetrics = g.getFontMetrics(); + Rectangle viewR = new Rectangle(); + Rectangle textR = new Rectangle(); + Rectangle iconR = new Rectangle(); + Insets i = getInsets(); + viewR.x = i.left; + viewR.y = i.top; + viewR.width = getWidth() - (i.left + i.right); + viewR.height = getHeight() - (i.top + i.bottom); + SwingUtilities.layoutCompoundLabel( + this, + fontMetrics, + getText(), + sortArrow, + getVerticalAlignment(), + getHorizontalAlignment(), + getVerticalTextPosition(), + getHorizontalTextPosition(), + viewR, + iconR, + textR, + getIconTextGap()); + int x = getWidth() - i.right - sortArrow.getIconWidth(); + int y = iconR.y; + return new Point(x, y); + } + + private class EmptyIcon implements Icon, Serializable { + + int width = 0; + int height = 0; + + @Override + public void paintIcon(Component c, Graphics g, int x, int y) { + } + + @Override + public int getIconWidth() { + return width; + } + + @Override + public int getIconHeight() { + return height; + } + } + } + + private class XPDefaultRenderer extends DefaultTableCellHeaderRenderer { + + XPDefaultRenderer() { + setHorizontalAlignment(LEADING); + setVerticalAlignment(CENTER); + } + + @Override + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column) { + + //** 本方法里可以有默认设置render字体和颜色的设置,所以即使在上面构造方法里设置自已的字体等都不起效 + //,在此方法调用之后调置是没有问题的 + super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + +// this.isSelected = isSelected; +// this.hasFocus = hasFocus; +// this.column = column; +// this.hasRollover = (column == getRolloverColumn()); +// if (skin == null) +// { +// skin = BEXPStyle.getXP().getSkin(header, Part.HP_HEADERITEM); +// } + Insets margins = UIManager.getInsets("TableHeader.cellMargin");//skin.getContentMargin(); + Border border; + int contentTop = 0; + int contentLeft = 0; + int contentBottom = 0; + int contentRight = 0; + if (margins != null) { + contentTop = margins.top; + contentLeft = margins.left; + contentBottom = margins.bottom; + contentRight = margins.right; + } + /* idk: + * Both on Vista and XP there is some offset to the + * HP_HEADERITEM content. It does not seem to come from + * Prop.CONTENTMARGINS. Do not know where it is defined. + * using some hardcoded values. + */ + contentLeft += 5; + contentBottom += 4; + contentRight += 5; + + /* On Vista sortIcon is painted above the header's text. + * We use border to paint it. + */ + Icon sortIcon; + //原UI代码 +// if (ZCWindowsLookAndFeel.isOnVista()&& +// ((sortIcon = getIcon()) instanceof javax.swing.plaf.UIResource +// || sortIcon == null)) + //现代码:上面原Java源代码里有WindowsLookAndFeel.isOnVista()==true时才会进入下面的代码 + //逻辑是不对的,也就是只要不是vista,就不可能绘制排序图标,这估计是Jdk自带的Java源代码很可能不是最新的! + if ( //去掉vista判断 + // ZCWindowsLookAndFeel.isOnVista() + // && + ((sortIcon = getIcon()) instanceof javax.swing.plaf.UIResource || sortIcon == null)) { + //原UI代码:原代码里为了仿vista样式,标头高度很高,现注释掉! +// contentTop += 1; + + setIcon(null); + sortIcon = null; + + SortOrder sortOrder = getColumnSortOrder(table, column); + if (sortOrder != null) + switch (sortOrder) { + case ASCENDING: + sortIcon + = UIManager.getIcon("Table.ascendingSortIcon"); + break; + case DESCENDING: + sortIcon + = UIManager.getIcon("Table.descendingSortIcon"); + break; + } + + if (sortIcon != null) + //原UI代码:原代码里为了仿vista样式,标头高度很高,现注释掉! +// contentBottom = sortIcon.getIconHeight(); + border = new IconBorder(sortIcon, contentTop, contentLeft, + contentBottom, contentRight); + else { + sortIcon = UIManager.getIcon("Table.ascendingSortIcon"); + int sortIconHeight = (sortIcon != null) ? sortIcon.getIconHeight() : 0; + if (sortIconHeight != 0) { + //原UI代码:原代码里为了仿vista样式,标头高度很高,现注释掉! +// contentBottom = sortIconHeight; + } + border = new EmptyBorder( + //原UI代码:原代码里为了仿vista样式,标头高度很高,现注释掉! + // sortIconHeight + contentTop, contentLeft, contentBottom, contentRight); + // /现代码:border的top不要那么(原代码是为了仿vista的) + contentTop, contentLeft, contentBottom, contentRight); + } + } else { + contentTop += 3; + border = new EmptyBorder(contentTop, contentLeft, contentBottom, contentRight); + } + setBorder(border); + + //** jb2011设置字体颜色和加粗 +// this.setForeground(ColorHelper.DARK_GRAY1_LIKE_APPLE); +// this.setFont(this.getFont().deriveFont(Font.BOLD)); + return this; + } + + @Override + public void paint(Graphics g) { + Dimension size = getSize(); +// State state = State.NORMAL; +// TableColumn draggedColumn = header.getDraggedColumn(); +// if (draggedColumn != null && +// column == SwingUtilities2.convertColumnIndexToView( +// header.getColumnModel(), +// draggedColumn.getModelIndex())) +// { +// state = State.PRESSED; +// } +// else if (isSelected || hasFocus || hasRollover) +// { +// state = State.HOT; +// } + /* on Vista there are more states for sorted columns */ +// if (WinUtils.isOnVista()) +// { +// SortOrder sortOrder = getColumnSortOrder(header.getTable(), column); +// if (sortOrder != null) +// { +// switch(sortOrder) +// { +// case ASCENDING: +// /* falls through */ +// case DESCENDING: +// switch (state) +// { +// case NORMAL: +// state = State.SORTEDNORMAL; +// break; +// case PRESSED: +// state = State.SORTEDPRESSED; +// break; +// case HOT: +// state = State.SORTEDHOT; +// break; +// default: +// /* do nothing */ +// } +// default : +// /* do nothing */ +// } +// } +// } + + paintHeadCell(g, size); +// skin.paintSkin(g, 0, 0, size.width-1, size.height-1, state); + + super.paint(g); + } + } + + //* 由jb2011 修改自WindowsTableHeaderUI里的同名类. + /** + * A border with an Icon at the middle of the top side. Outer insets can be + * provided for this border. + */ + private static class IconBorder implements Border, UIResource { + + private final Icon icon; + + private final int top, left, bottom, right; + + public IconBorder(Icon icon, int top, int left, int bottom, int right) { + this.icon = icon; + this.top = top; + this.left = left; + this.bottom = bottom; + this.right = right; + } + + @Override + public Insets getBorderInsets(Component c) { + //原UI代码:原代码里为了仿vista样式,标头高度很高,现注释掉! +// return new Insets(icon.getIconHeight() + top, left, bottom, right); + //现代码 + return new Insets(top, left, bottom, right); + } + + @Override + public boolean isBorderOpaque() { + return false; + } + + @Override + public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { + icon.paintIcon(c, g, + //原UI代码:原代码里为了仿vista样式,标头高度很高且图标的位置是放在top中央,现注释掉! + // x + left + (width - left - right - icon.getIconWidth()) / 2, y + top); + + //现代码:图标放在右边利往左来2个像素的位置(好看一点) + x + left + width - right - icon.getIconWidth() - 2, y); + } + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/table/BETableUI.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/table/BETableUI.java new file mode 100644 index 000000000..bf0ec03e0 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/table/BETableUI.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * BETableUI.java at 2015-2-1 20:25:41, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.table; + +import java.awt.Dimension; + +import javax.swing.JComponent; +import javax.swing.LookAndFeel; +import javax.swing.UIDefaults; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicTableUI; + +/** + * JTable的UI实现类. + * + * @author Jack Jiang(jb2011@163.com) + */ +public class BETableUI extends BasicTableUI { + + UIDefaults defaultRenderersByColumnClass; + + public static ComponentUI createUI(JComponent c) { + return new BETableUI(); + } + + /** + * Initialize JTable properties, e.g. font, foreground, and background. The + * font, foreground, and background properties are only set if their current + * value is either null or a UIResource, other properties are set if the + * current value is null. + * + * @see #installUI + */ + @Override + protected void installDefaults() { + super.installDefaults(); + //行高设置为25看起来会舒服些 + table.setRowHeight(25); + //不显示垂直的网格线 + table.setShowVerticalLines(false); + //设置单元格间的空白(默认是1个像素宽和高) + //说明:设置本参数可以实现单元格间的间隔空制,间隔里通常是实现网格线的绘制,但 + //网格维绘制与否并不影响间隔的存在(如果间隔存在但网格线不绘的话它就是是透明的空 + //间),参数中width表示水平间隔,height表示垂直间隔,为0则表示没有间隔 + table.setIntercellSpacing(new Dimension(0, 1)); + LookAndFeel.installProperty(table, "opaque", Boolean.FALSE); + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/table/FocusCellHighlightBorder.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/table/FocusCellHighlightBorder.java new file mode 100644 index 000000000..aa2ebb414 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/table/FocusCellHighlightBorder.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * FocusCellHighlightBorder.java at 2015-2-1 20:25:40, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.table; + +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Insets; + +import javax.swing.UIManager; +import javax.swing.border.AbstractBorder; + +import org.jackhuang.hmcl.laf.BEUtils; + +/** + * 表格单元获得焦点时的Border实现类. + * + * 本border由Jack Jiang实现,它是表格单元获得焦点时的边框(类似的功能在windows LNF下是一个距形虚线框) + * + * @author Jack Jiang(jb2011@163.com) + */ +class FocusCellHighlightBorder extends AbstractBorder { + + @Override + public Insets getBorderInsets(Component c) { +// return new Insets(0,3,0,1); + return new Insets(2, 2, 2, 2); // @since 3.5 + } + + @Override + public Insets getBorderInsets(Component c, Insets insets) { + return getBorderInsets(c); + } + + @Override + public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { + //* old impl +// //在左边划一条2像素宽的竖线 +// g.setColor(UIManager.getColor("Table.focusCellHighlightBorderColor")); +// g.fillRect(x, y, 2, height );//上下各空白一个像素,目的是为了与render的N9图片背景配合形成更好的视觉效果 +// +// //再在上面的竖线右边划一条1像素宽的亮色竖线,以便为上面的2像素竖线营造立体效果 +// /* ~~注:这个属性是jb2011为了更好的ui效果自已加的属性,目的是使Table.focusCellHighlightBorder有点立体效果哦 */ +// g.setColor(UIManager.getColor("Table.focusCellHighlightBorderHighlightColor")); +// g.fillRect(x+2, y, 1, height ); + + //* @since 3.5 + BEUtils.draw4RecCorner(g, x, y, width - 2, height - 2, 5, + UIManager.getColor("Table.focusCellHighlightBorderColor")); + BEUtils.draw4RecCorner(g, x + 1, y + 1, width - 2, height - 2, 5, + UIManager.getColor("Table.focusCellHighlightBorderHighlightColor")); + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/table/TableScrollBorder.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/table/TableScrollBorder.java new file mode 100644 index 000000000..316419be1 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/table/TableScrollBorder.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * TableScrollBorder.java at 2015-2-1 20:25:36, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.table; + +import java.awt.Insets; + +import org.jackhuang.hmcl.laf.widget.border.NinePatchBorder; + +/** + * 表格UI所在滚动条的边框实现类. + * + * @author Jack Jiang(jb2011@163.com), 2012-08-30 + * @version 1.0 + */ +class TableScrollBorder extends NinePatchBorder { + + public TableScrollBorder() { + super(new Insets(3, 5, 10, 5), BETableHeaderUI.ICON_9.get("scroll_border")); + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/table/__UI__.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/table/__UI__.java new file mode 100644 index 000000000..c792eaebc --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/table/__UI__.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * __UI__.java at 2015-2-1 20:25:39, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.table; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Insets; + +import javax.swing.UIManager; + +import org.jackhuang.hmcl.laf.BeautyEyeLNFHelper; +import org.jackhuang.hmcl.laf.utils.IconFactory; +import org.jackhuang.hmcl.laf.utils.UI; + +public class __UI__ extends UI { + + private static final IconFactory ICON = new IconFactory("table"); + + public static void uiImpl() { + //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> JTable的相关ui属性设定 + //JTable所属的滚动面板的border实现(不像JList,JTable的UI自动为它配备的一个JScrollPane) + put("Table.scrollPaneBorder", new TableScrollBorder());//defaut is com.sun.java.swing.plaf.windows.XPStyle.XPFillBorder + put("Table.focusCellHighlightBorder", new FocusCellHighlightBorder());//new BEDashedBorder(new Color(0,160,0),1,0,true,false,true,false))); + /* ~~注:这个属性是jb2011为了更好的ui效果自已加的属性 */ + put("Table.focusCellHighlightBorderColor", Color.white);//new ColorUIResource(Color.red)); + /* ~~注:这个属性是jb2011为了更好的ui效果自已加的属性,目的是使Table.focusCellHighlightBorder有点立体效果哦 */ + putColor("Table.focusCellHighlightBorderHighlightColor", 255, 255, 255, 70);//注意:这个颜色是半透明的哦 + put("Table.background", Color.white); + //** 2011-03-16 add by jb2011 为了使JDK1.6及以上表格头在排序时能显示排序箭头(1.6里的排序图标是在UI里设定的) + UIManager.put("Table.descendingSortIcon", ICON.get("descending_sort")); + UIManager.put("Table.ascendingSortIcon", ICON.get("ascending_sort")); + put("Table.selectionForeground", BeautyEyeLNFHelper.commonSelectionForegroundColor); + putColor("Table.gridColor", 220, 220, 220); + put("Table.selectionBackground", BeautyEyeLNFHelper.commonSelectionBackgroundColor); + put("Table.foreground", BeautyEyeLNFHelper.commonForegroundColor); + put("TableUI", BETableUI.class); + + //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> JTable表头相关ui属性设定 +// UIManager.put("TableHeader.font",new Font("宋体",Font.PLAIN,12));//此属性将决定表头的字体 + put("TableHeader.background", BeautyEyeLNFHelper.commonBackgroundColor); + put("TableHeader.foreground", BeautyEyeLNFHelper.commonForegroundColor); + + //不建议完全定制表头ui,因为BasicTableHeaderUI里的关键方法都是private,无法继承重写,要实现自已 + //的绘制逻辑需要重写大段代码,而因JTable在不同jdk版本里的变动较大:比如1.6里才有的排序(及图标)及相关方法 + //在不同的版本里都不尽相同,而且调用了若干sun的非公开包里的api。虽存在兼容性问题,为了UI美观,还是自定义实现吧 + put("TableHeaderUI", BETableHeaderUI.class); + //** BE LNF的本属性只在Java版本高于1.5时起效 + //* 由jb2011自已加的属性,因原BasicTableHeaderUI里用TableHeader.cellBorder来设置 + //border,但WindowsTableHeaderUI的border则是自已实现的IconBorder,而BE LNF中则是仿 + //照Windows LNF实现,所以只能实现一个自已的属性来供以后的使用者灵活设定(否则只能像Windows LNF一样硬编码在代码里) + putInsets("TableHeader.cellMargin", 7, 0, 7, 0); + } + + /** + * Border for a Table Header. + * + * @see javax.swing.plaf.metal.TableHeaderBorder + */ + public static class TableHeaderBorder extends javax.swing.border.AbstractBorder { + + protected Insets editorBorderInsets = new Insets(7, 0, 7, 0);//默认是2, 2, 2, 0 ); + + @Override + public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) { + g.translate(x, y); + +// g.setColor(MetalLookAndFeel.getControlDarkShadow() ); +// g.drawLine( w-1, 0, w-1, h-1 ); +// g.drawLine( 1, h-1, w-1, h-1 ); +// g.setColor( MetalLookAndFeel.getControlHighlight() ); +// g.drawLine( 0, 0, w-2, 0 ); +// g.drawLine( 0, 0, 0, h-2 ); + //* add by Jack Jiang START + //绘制表头单元的底部水平线(跟网格线颜色一样就可以了) + g.setColor(UIManager.getColor("Table.gridColor")); + g.drawLine(0, h - 1, w, h - 1); + + //绘制表头单元的右分隔竖线 + BETableHeaderUI.ICON_9.get("header_cell_separator") + .draw((Graphics2D) g, w - 4, 0, 4, h); + //* add by Jack Jiang END + + g.translate(-x, -y); + } + + @Override + public Insets getBorderInsets(Component c) { + return editorBorderInsets; + } + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/textcoms/BEEditorPaneUI.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/textcoms/BEEditorPaneUI.java new file mode 100644 index 000000000..5a6281d10 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/textcoms/BEEditorPaneUI.java @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * BEEditorPaneUI.java at 2015-2-1 20:25:41, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.textcoms; + +import java.awt.Color; +import java.awt.Graphics; + +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.UIResource; +import javax.swing.plaf.basic.BasicEditorPaneUI; +import javax.swing.text.JTextComponent; + +import org.jackhuang.hmcl.laf.textcoms.__UI__.BgSwitchable; +import org.jb2011.ninepatch4j.NinePatch; + +/** + * 文本组件JEditorPane的UI实现类. + * + * @author Jack Jiang(jb2011@163.com), 2012-08-25 + * @see com.sun.java.swing.plaf.windows.WindowsEditorPaneUI + */ +public class BEEditorPaneUI extends BasicEditorPaneUI implements BgSwitchable, + org.jackhuang.hmcl.laf.BeautyEyeLNFHelper.__UseParentPaintSurported { + //默认是纯白色背景,因为JEditorPane肯定是要放在JScrollPane中的,而ScrollPane也是有边框的 + //如果JEditorPane再有边框就很难看了,所以JEditorPane在没有获得焦点时就已无边框效果出现会好看很多 + + private NinePatch bg = __UI__.ICON_9.get("white"); + + public static ComponentUI createUI(JComponent c) { + BETextFieldUI.addOtherListener(c); +// c.addMouseListener(new NLLookAndFeel.EditMenu()); + return new BEEditorPaneUI(); + } + + //* 本方法由Jack Jiang于2012-09-07日加入 + /** + * 是否使用父类的绘制实现方法,true表示是. + *

+ * 因为在BE LNF中,边框和背景等都是使用N9图,没法通过设置背景色和前景 + * 色来控制JEditorPane的颜色和边框,本方法的目的就是当用户设置了进度条的border或背景色 时告之本实现类不使用BE + * LNF中默认的N9图填充绘制而改用父类中的方法(父类中的方法 就可以支持颜色的设置罗,只是丑点,但总归是能适应用户的需求场景要求,其实用户完全可以 + * 通过JEditorPane.setUI(..)方式来自定义UI哦). + * + * @return true, if is use parent paint + */ + @Override + public boolean isUseParentPaint() { + return getComponent() != null + && (!(getComponent().getBorder() instanceof UIResource) + || !(getComponent().getBackground() instanceof UIResource)); + } + + /** + * Paints a background for the view. This will only be called if isOpaque() + * on the associated component is true. The default is to paint the + * background color of the component. + * + * @param g the graphics context + */ + @Override + protected void paintBackground(Graphics g) { + //先调用父类方法把背景刷新下(比如本UI里使用的大圆角NP图如不先刷新背景则会因上下拉动滚动条 + //而致4个圆角位置得不到刷新,从而影响视觉效果(边角有前面的遗留),置于透明边角不被透明像素填 + //充的问题,它有可能是Android的NinePatch技术为了性能做作出的优化——一切全透明像素即意味着不需绘制) + super.paintBackground(g); // TODO 出于节约计算资源考生虑,本行代码换成父类中默认填充背景的代码即可 + + //* 如果用户作了自定义颜色设置则使用父类方法来实现绘制,否则BE LNF中没法支持这些设置哦 + if (!isUseParentPaint()) { + //用新的NP图实现真正的背景填充 + JTextComponent editor = this.getComponent(); + BETextFieldUI.paintBg(g, 0, 0, editor.getWidth(), editor.getHeight(), + editor.isEnabled(), border); + } + } + + @Override + public void switchBgToNormal() { + border = __UI__.BORDER_NORMAL; + } + + @Override + public void switchBgToFocused() { + border = __UI__.border_focused(); + } + + @Override + public void switchBgToOver() { + border = __UI__.BORDER_OVER; + } + + Color border = __UI__.BORDER_NORMAL; + +// /** +// * Creates the object to use for a caret. By default an +// * instance of WindowsCaret is created. This method +// * can be redefined to provide something else that implements +// * the InputPosition interface or a subclass of DefaultCaret. +// * +// * @return the caret object +// */ +// protected Caret createCaret() { +// return new WindowsTextUI.WindowsCaret(); +// } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/textcoms/BEFormattedTextFieldUI.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/textcoms/BEFormattedTextFieldUI.java new file mode 100644 index 000000000..7b1649c27 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/textcoms/BEFormattedTextFieldUI.java @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * BEPasswordFieldUI.java at 2015-2-1 20:25:36, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.textcoms; + +import java.awt.Color; +import java.awt.Graphics; + +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.UIResource; +import javax.swing.plaf.basic.BasicFormattedTextFieldUI; +import javax.swing.text.JTextComponent; + +import org.jackhuang.hmcl.laf.textcoms.__UI__.BgSwitchable; +import org.jb2011.ninepatch4j.NinePatch; + +/** + * 文本组件JFormattedTextField的UI实现类. + * + * @author Jack Jiang(jb2011@163.com), 2015-11-13 + * @since 3.7 + */ +public class BEFormattedTextFieldUI extends BasicFormattedTextFieldUI implements BgSwitchable, + org.jackhuang.hmcl.laf.BeautyEyeLNFHelper.__UseParentPaintSurported { + + private NinePatch bg = __UI__.ICON_9.get("normal"); + + public static ComponentUI createUI(JComponent c) { + c.addFocusListener(FocusListenerImpl.getInstance()); + return new BEFormattedTextFieldUI(); + } + + //* 本方法由Jack Jiang于2012-09-07日加入 + /** + * 是否使用父类的绘制实现方法,true表示是. + *

+ * 因为在BE LNF中,边框和背景等都是使用N9图,没法通过设置背景色和前景 + * 色来控制JPasswordField的颜色和边框,本方法的目的就是当用户设置了进度条的border或背景色 时告之本实现类不使用BE + * LNF中默认的N9图填充绘制而改用父类中的方法(父类中的方法 就可以支持颜色的设置罗,只是丑点,但总归是能适应用户的需求场景要求,其实用户完全可以 + * 通过JPasswordField.setUI(..)方式来自定义UI哦). + * + * @return true, if is use parent paint + */ + @Override + public boolean isUseParentPaint() { + return getComponent() != null + && (!(getComponent().getBorder() instanceof UIResource) + || !(getComponent().getBackground() instanceof UIResource)); + } + + /** + * Paints a background for the view. This will only be called if isOpaque() + * on the associated component is true. The default is to paint the + * background color of the component. + * + * @param g the graphics context + */ + @Override + protected void paintBackground(Graphics g) { + //先调用父类方法把背景刷新下(比如本UI里使用的大圆角NP图如不先刷新背景则会因上下拉动滚动条 + //而致4个圆角位置得不到刷新,从而影响视觉效果(边角有前面的遗留),置于透明边角不被透明像素填 + //充的问题,它有可能是Android的NinePatch技术为了性能做作出的优化——一切全透明像素即意味着不需绘制) + super.paintBackground(g);// TODO 出于节约计算资源考生虑,本行代码换成父类中默认填充背景的代码即可 + + //* 如果用户作了自定义颜色设置则使用父类方法来实现绘制,否则BE LNF中没法支持这些设置哦 + if (!isUseParentPaint()) { + //用新的NP图实现真正的背景填充 + JTextComponent editor = this.getComponent(); + BETextFieldUI.paintBg(g, 0, 0, editor.getWidth(), editor.getHeight(), + editor.isEnabled(), border); + } + } + + @Override + public void switchBgToNormal() { + border = __UI__.BORDER_NORMAL; + } + + @Override + public void switchBgToFocused() { + border = __UI__.border_focused(); + } + + @Override + public void switchBgToOver() { + border = __UI__.BORDER_OVER; + } + + Color border = __UI__.BORDER_NORMAL; + +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/textcoms/BEPasswordFieldUI.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/textcoms/BEPasswordFieldUI.java new file mode 100644 index 000000000..4f1627b66 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/textcoms/BEPasswordFieldUI.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * BEPasswordFieldUI.java at 2015-2-1 20:25:36, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.textcoms; + +import java.awt.Color; +import java.awt.Graphics; + +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.UIResource; +import javax.swing.plaf.basic.BasicPasswordFieldUI; +import javax.swing.text.JTextComponent; + +import org.jackhuang.hmcl.laf.textcoms.__UI__.BgSwitchable; +import org.jb2011.ninepatch4j.NinePatch; + +/** + * 文本组件JPasswordField的UI实现类. + * + * @author Jack Jiang(jb2011@163.com) + */ +public class BEPasswordFieldUI extends BasicPasswordFieldUI implements BgSwitchable, + org.jackhuang.hmcl.laf.BeautyEyeLNFHelper.__UseParentPaintSurported { + + private NinePatch bg = __UI__.ICON_9.get("normal"); + + public static ComponentUI createUI(JComponent c) { + c.addFocusListener(FocusListenerImpl.getInstance()); +// c.addMouseListener(new NLLookAndFeel.EditMenu()); + return new BEPasswordFieldUI(); + } + + //* 本方法由Jack Jiang于2012-09-07日加入 + /** + * 是否使用父类的绘制实现方法,true表示是. + *

+ * 因为在BE LNF中,边框和背景等都是使用N9图,没法通过设置背景色和前景 + * 色来控制JPasswordField的颜色和边框,本方法的目的就是当用户设置了进度条的border或背景色 时告之本实现类不使用BE + * LNF中默认的N9图填充绘制而改用父类中的方法(父类中的方法 就可以支持颜色的设置罗,只是丑点,但总归是能适应用户的需求场景要求,其实用户完全可以 + * 通过JPasswordField.setUI(..)方式来自定义UI哦). + * + * @return true, if is use parent paint + */ + @Override + public boolean isUseParentPaint() { + return getComponent() != null + && (!(getComponent().getBorder() instanceof UIResource) + || !(getComponent().getBackground() instanceof UIResource)); + } + + /** + * Paints a background for the view. This will only be called if isOpaque() + * on the associated component is true. The default is to paint the + * background color of the component. + * + * @param g the graphics context + */ + @Override + protected void paintBackground(Graphics g) { + //先调用父类方法把背景刷新下(比如本UI里使用的大圆角NP图如不先刷新背景则会因上下拉动滚动条 + //而致4个圆角位置得不到刷新,从而影响视觉效果(边角有前面的遗留),置于透明边角不被透明像素填 + //充的问题,它有可能是Android的NinePatch技术为了性能做作出的优化——一切全透明像素即意味着不需绘制) + super.paintBackground(g);// TODO 出于节约计算资源考生虑,本行代码换成父类中默认填充背景的代码即可 + + //* 如果用户作了自定义颜色设置则使用父类方法来实现绘制,否则BE LNF中没法支持这些设置哦 + if (!isUseParentPaint()) { + //用新的NP图实现真正的背景填充 + JTextComponent editor = this.getComponent(); + BETextFieldUI.paintBg(g, 0, 0, editor.getWidth(), editor.getHeight(), + editor.isEnabled(), border); + } + } + + @Override + public void switchBgToNormal() { + border = __UI__.BORDER_NORMAL; + } + + @Override + public void switchBgToFocused() { + border = __UI__.border_focused(); + } + + @Override + public void switchBgToOver() { + border = __UI__.BORDER_OVER; + } + + Color border = __UI__.BORDER_NORMAL; +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/textcoms/BETextAreaUI.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/textcoms/BETextAreaUI.java new file mode 100644 index 000000000..ecd85737c --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/textcoms/BETextAreaUI.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * BETextAreaUI.java at 2015-2-1 20:25:41, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.textcoms; + +import java.awt.Color; +import java.awt.Graphics; + +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.UIResource; +import javax.swing.plaf.basic.BasicTextAreaUI; +import javax.swing.text.JTextComponent; + +import org.jackhuang.hmcl.laf.textcoms.__UI__.BgSwitchable; +import org.jb2011.ninepatch4j.NinePatch; + +/** + * 文本组件JTextArea的UI实现类. + * + * @author Jack Jiang(jb2011@163.com) + */ +public class BETextAreaUI extends BasicTextAreaUI implements BgSwitchable, + org.jackhuang.hmcl.laf.BeautyEyeLNFHelper.__UseParentPaintSurported//WindowsTextAreaUI +{ + //默认是纯白色背景,因为JTextArea肯定是要放在JScrollPane中的,而ScrollPane也是有边框的 + //如果JTextArea再有边框就很难看了,所以JTextArea在没有获得焦点时就已无边框效果出现会好看很多 + + private NinePatch bg = __UI__.ICON_9.get("white"); + + public static ComponentUI createUI(JComponent c) { + BETextFieldUI.addOtherListener(c); +// c.addMouseListener(new NLLookAndFeel.EditMenu()); + return new BETextAreaUI(); + } + + //* 本方法由Jack Jiang于2012-09-07日加入 + /** + * 是否使用父类的绘制实现方法,true表示是. + *

+ * 因为在BE LNF中,边框和背景等都是使用N9图,没法通过设置背景色和前景 + * 色来控制JTextField的颜色和边框,本方法的目的就是当用户设置了进度条的border或背景色 时告之本实现类不使用BE + * LNF中默认的N9图填充绘制而改用父类中的方法(父类中的方法 就可以支持颜色的设置罗,只是丑点,但总归是能适应用户的需求场景要求,其实用户完全可以 + * 通过JTextField.setUI(..)方式来自定义UI哦). + * + * @return true, if is use parent paint + */ + @Override + public boolean isUseParentPaint() { + return getComponent() != null + && (!(getComponent().getBorder() instanceof UIResource) + || !(getComponent().getBackground() instanceof UIResource)); + } + + /** + * Paints a background for the view. This will only be called if isOpaque() + * on the associated component is true. The default is to paint the + * background color of the component. + * + * @param g the graphics context + */ + @Override + protected void paintBackground(Graphics g) { + //先调用父类方法把背景刷新下(比如本UI里使用的大圆角NP图如不先刷新背景则会因上下拉动滚动条 + //而致4个圆角位置得不到刷新,从而影响视觉效果(边角有前面的遗留),置于透明边角不被透明像素填 + //充的问题,它有可能是Android的NinePatch技术为了性能做作出的优化——一切全透明像素即意味着不需绘制) + super.paintBackground(g);// TODO 出于节约计算资源考生虑,本行代码换成父类中默认填充背景的代码即可 + + //* 如果用户作了自定义颜色设置则使用父类方法来实现绘制,否则BE LNF中没法支持这些设置哦 + if (!isUseParentPaint()) { + //用新的NP图实现真正的背景填充 + JTextComponent editor = this.getComponent(); + BETextFieldUI.paintBg(g, 0, 0, editor.getWidth(), editor.getHeight(), + editor.isEnabled(), border); + } + } + + @Override + public void switchBgToNormal() { + border = __UI__.BORDER_NORMAL; + } + + @Override + public void switchBgToFocused() { + border = __UI__.border_focused(); + } + + @Override + public void switchBgToOver() { + border = __UI__.BORDER_OVER; + } + + Color border = __UI__.BORDER_NORMAL; +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/textcoms/BETextFieldUI.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/textcoms/BETextFieldUI.java new file mode 100644 index 000000000..0253dcd2f --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/textcoms/BETextFieldUI.java @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * BETextFieldUI.java at 2015-2-1 20:25:37, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.textcoms; + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Graphics2D; + +import javax.swing.JComponent; +import javax.swing.plaf.UIResource; +import javax.swing.plaf.basic.BasicTextFieldUI; +import javax.swing.text.JTextComponent; + +import org.jackhuang.hmcl.laf.textcoms.__UI__.BgSwitchable; +import org.jb2011.ninepatch4j.NinePatch; + +/** + * 文本组件JTextField的UI实现类. + * + * @author Jack Jiang(jb2011@163.com) + */ +public class BETextFieldUI extends BasicTextFieldUI implements BgSwitchable, + org.jackhuang.hmcl.laf.BeautyEyeLNFHelper.__UseParentPaintSurported { + + private NinePatch bg = __UI__.ICON_9.get("normal"); + + public static BETextFieldUI createUI(JComponent c) { + addOtherListener(c); + return new BETextFieldUI(); + } + + //* 本方法由Jack Jiang于2012-09-07日加入 + /** + * 是否使用父类的绘制实现方法,true表示是. + *

+ * 因为在BE LNF中,边框和背景等都是使用N9图,没法通过设置背景色和前景 + * 色来控制JTextField的颜色和边框,本方法的目的就是当用户设置了进度条的border或背景色 时告之本实现类不使用BE + * LNF中默认的N9图填充绘制而改用父类中的方法(父类中的方法 就可以支持颜色的设置罗,只是丑点,但总归是能适应用户的需求场景要求,其实用户完全可以 + * 通过JTextField.setUI(..)方式来自定义UI哦). + * + * @return true, if is use parent paint + */ + @Override + public boolean isUseParentPaint() { + return getComponent() != null + && (!(getComponent().getBorder() instanceof UIResource) + || !(getComponent().getBackground() instanceof UIResource)); + } + + /** + * Paints a background for the view. This will only be called if isOpaque() + * on the associated component is true. The default is to paint the + * background color of the component. + * + * @param g the graphics context + */ + @Override + protected void paintBackground(Graphics g) { +// Color bgc = editor.getBackground(); +// g.setColor(bgc); +// //先填 充背景 +// g.fillRect(0, 0, editor.getWidth(), editor.getHeight()); +// +// //(1) ---- 仿Numbus文本框效果 +// //** top立体效果实现 +// //第(0,0)开始的第一条线会被后来的border覆盖掉的,所以此处绘制没有意义,不搞了 +//// g.setColor(new Color(0,0,0)); +//// g.drawLine(0, 0, editor.getWidth(), 0); +// //第2条线颜色淡一点 +// g.setColor(new Color(208,208,208)); +// g.drawLine(0, 1, editor.getWidth(), 1); +// //第3条线颜色更淡一点 +// g.setColor(new Color(231,231,225)); +// g.drawLine(0, 2, editor.getWidth(), 2); + + //先调用父类方法把背景刷新下(比如本UI里使用的大圆角NP图如不先刷新背景则会因上下拉动滚动条 + //而致4个圆角位置得不到刷新,从而影响视觉效果(边角有前面的遗留),置于透明边角不被透明像素填 + //充的问题,它有可能是Android的NinePatch技术为了性能做作出的优化——一切全透明像素即意味着不需绘制) + super.paintBackground(g);// TODO 出于节约计算资源考生虑,本行代码换成父类中默认填充背景的代码即可 + + //* 如果用户作了自定义颜色设置则使用父类方法来实现绘制,否则BE LNF中没法支持这些设置哦 + if (!isUseParentPaint()) { + //用新的NP图实现真正的背景填充 + JTextComponent editor = this.getComponent(); + BETextFieldUI.paintBg(g, 0, 0, editor.getWidth(), editor.getHeight(), + editor.isEnabled(), border); + } + +// if(this.getComponent().isEnabled()) +// //*** 重要说明:因使用的NinePatch图片作填充背景,所以后绪任何对JTextField设置 +// //*** 背景色将不会起效,因为背景是用图片填充而非传统方法绘制出来的 +// bg.draw((Graphics2D)g, 0, 0, editor.getWidth(), editor.getHeight()); +// else +// __Icon9Factory__.getInstance().getTextFieldBgDisabled() +// .draw((Graphics2D)g, 0, 0, editor.getWidth(), editor.getHeight()); +//// //(2) ---- 仿360软件管家文本框效果(不太好看) +// //** top立体效果实现 +// //第(0,0)开始的第一条线会被后来的border覆盖掉的,所以此处绘制没有意义,不搞了 +//// g.setColor(new Color(0,0,0)); +//// g.drawLine(0, 0, editor.getWidth(), 0); +// //第2条线颜色淡一点 +// g.setColor(new Color(232,232,232)); +// g.drawLine(1, 1, editor.getWidth()-1, 1); +// //第3条线颜色更淡一点 +// g.setColor(new Color(241,241,241)); +// g.drawLine(1, 2, editor.getWidth()-1, 2); +// //第4条线颜色更淡一点 +// g.setColor(new Color(248,248,248)); +// g.drawLine(1, 3, editor.getWidth()-1, 3); +// //第5条线颜色更淡一点 +// g.setColor(new Color(252,252,252)); +// g.drawLine(1, 4, editor.getWidth()-1, 4); +// +// //** left +// //第2条线颜色淡一点 +// g.setColor(new Color(241,241,241)); +// g.drawLine(1, 1, 1, editor.getHeight()-1); +// //第3条线颜色淡一点 +// g.setColor(new Color(248,248,248)); +// g.drawLine(2, 1, 2, editor.getHeight()-1); +// //第4条线颜色淡一点 +// g.setColor(new Color(253,253,253)); +// g.drawLine(3, 1, 3, editor.getHeight()-1); +// +// //** right +// //第2条线颜色淡一点 +// g.setColor(new Color(241,241,241)); +// g.drawLine(editor.getWidth()-1, 1, editor.getWidth()-1, editor.getHeight()-1); +// //第3条线颜色淡一点 +// g.setColor(new Color(248,248,248)); +// g.drawLine(editor.getWidth()-2, 1, editor.getWidth()-2, editor.getHeight()-1); +// //第4条线颜色淡一点 +// g.setColor(new Color(253,253,253)); +// g.drawLine(editor.getWidth()-3, 1, editor.getWidth()-3, editor.getHeight()-1); +// +// //** bottom +// //第2条线颜色淡一点 +// g.setColor(new Color(248,248,248)); +// g.drawLine(1, editor.getHeight()-1, editor.getWidth()-1, editor.getHeight()-1); +// //第3条线颜色淡一点 +// g.setColor(new Color(252,252,252)); +// g.drawLine(1, editor.getHeight()-2, editor.getWidth()-1, editor.getHeight()-2); + } + + @Override + public void switchBgToNormal() { + border = __UI__.BORDER_NORMAL; + } + + @Override + public void switchBgToFocused() { + border = __UI__.border_focused(); + } + + @Override + public void switchBgToOver() { + border = __UI__.BORDER_OVER; + } + + Color border = __UI__.BORDER_NORMAL; + + /** + * Paint bg. + * + * @param g the g + * @param x the x + * @param y the y + * @param w the w + * @param h the h + * @param enabled the enabled + * @param bg the bg + */ + public static void paintBg(Graphics g, int x, int y, int w, int h, + boolean enabled, Color border) { + if (enabled) { + g.setColor(border); + g.fillRect(x, y, w, h); + g.setColor(Color.white); + g.fillRect(x + 2, y + 2, w - 4, h - 4); + } + else + __UI__.ICON_9.get("disabled") + .draw((Graphics2D) g, x, y, w, h); + } + + /** + * 为组件添加焦点监听器(获得/取消焦点时可以自动设置/取消一个彩色的边框效果,以体高UI体验) 、右键菜单监听器(有复制/粘贴等功能). + * + * @param c the c + */ + public static void addOtherListener(JComponent c) { + c.addFocusListener(FocusListenerImpl.getInstance()); + c.addMouseListener(FocusListenerImpl.getInstance()); + } + +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/textcoms/BETextPaneUI.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/textcoms/BETextPaneUI.java new file mode 100644 index 000000000..98fd7b293 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/textcoms/BETextPaneUI.java @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * BETextPaneUI.java at 2015-2-1 20:25:40, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.textcoms; + +import java.awt.Color; +import java.awt.Graphics; + +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.UIResource; +import javax.swing.plaf.basic.BasicTextPaneUI; +import javax.swing.text.JTextComponent; + +import org.jackhuang.hmcl.laf.textcoms.__UI__.BgSwitchable; +import org.jb2011.ninepatch4j.NinePatch; + +/** + * 文本组件JTextPane的UI实现类. + * + * @author Jack Jiang(jb2011@163.com), 2012-08-25 + * @see com.sun.java.swing.plaf.windows.WindowsTextPaneUI + */ +public class BETextPaneUI extends BasicTextPaneUI implements BgSwitchable, + org.jackhuang.hmcl.laf.BeautyEyeLNFHelper.__UseParentPaintSurported { + //默认是纯白色背景,因为JTextPane肯定是要放在JScrollPane中的,而ScrollPane也是有边框的 + //如果JTextPane再有边框就很难看了,所以JTextPane在没有获得焦点时就已无边框效果出现会好看很多 + + private NinePatch bg = __UI__.ICON_9.get("white"); + + public static ComponentUI createUI(JComponent c) { + BETextFieldUI.addOtherListener(c); +// c.addMouseListener(new NLLookAndFeel.EditMenu()); + return new BETextPaneUI(); + } + + /** + * 是否使用父类的绘制实现方法,true表示是. + *

+ * 因为在BE LNF中,边框和背景等都是使用N9图,没法通过设置背景色和前景 + * 色来控制JTextPane的颜色和边框,本方法的目的就是当用户设置了进度条的border或背景色 时告之本实现类不使用BE + * LNF中默认的N9图填充绘制而改用父类中的方法(父类中的方法 就可以支持颜色的设置罗,只是丑点,但总归是能适应用户的需求场景要求,其实用户完全可以 + * 通过JTextPane.setUI(..)方式来自定义UI哦). + * + * @return true, if is use parent paint + */ + @Override + public boolean isUseParentPaint() { + return getComponent() != null + && (!(getComponent().getBorder() instanceof UIResource) + || !(getComponent().getBackground() instanceof UIResource)); + } + + /** + * Paints a background for the view. This will only be called if isOpaque() + * on the associated component is true. The default is to paint the + * background color of the component. + * + * @param g the graphics context + */ + @Override + protected void paintBackground(Graphics g) { + //先调用父类方法把背景刷新下(比如本UI里使用的大圆角NP图如不先刷新背景则会因上下拉动滚动条 + //而致4个圆角位置得不到刷新,从而影响视觉效果(边角有前面的遗留),置于透明边角不被透明像素填 + //充的问题,它有可能是Android的NinePatch技术为了性能做作出的优化——一切全透明像素即意味着不需绘制) + super.paintBackground(g);// TODO 出于节约计算资源考生虑,本行代码换成父类中默认填充背景的代码即可 + + //* 如果用户作了自定义颜色设置则使用父类方法来实现绘制,否则BE LNF中没法支持这些设置哦 + if (!isUseParentPaint()) { + //用新的NP图实现真正的背景填充 + JTextComponent editor = this.getComponent(); + BETextFieldUI.paintBg(g, 0, 0, editor.getWidth(), editor.getHeight(), + editor.isEnabled(), border); + } + } + + @Override + public void switchBgToNormal() { + border = __UI__.BORDER_NORMAL; + } + + @Override + public void switchBgToFocused() { + border = __UI__.border_focused(); + } + + @Override + public void switchBgToOver() { + border = __UI__.BORDER_OVER; + } + + Color border = __UI__.BORDER_NORMAL; + +// /** +// * Creates the object to use for a caret. By default an +// * instance of WindowsCaret is created. This method +// * can be redefined to provide something else that implements +// * the InputPosition interface or a subclass of DefaultCaret. +// * +// * @return the caret object +// */ +// protected Caret createCaret() { +// return new WindowsTextUI.WindowsCaret(); +// } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/textcoms/FocusListenerImpl.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/textcoms/FocusListenerImpl.java new file mode 100644 index 000000000..c990596d2 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/textcoms/FocusListenerImpl.java @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * FocusListenerImpl.java at 2015-2-1 20:25:40, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.textcoms; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; + +import javax.swing.JComboBox; +import javax.swing.JComponent; +import javax.swing.JTextField; +import javax.swing.UIManager; +import javax.swing.border.Border; +import javax.swing.plaf.ComponentUI; +import javax.swing.text.JTextComponent; + +import org.jackhuang.hmcl.laf.textcoms.__UI__.BgSwitchable; +import org.jackhuang.hmcl.laf.BEUtils; +import org.jackhuang.hmcl.laf.widget.border.BERoundBorder; + +/** + * 焦点改变时的监听器实现类. + *

+ * 目前主要用于各文本组件. + * + * @author Jack Jiang(jb2011@163.com) + */ +public class FocusListenerImpl implements FocusListener, MouseListener { + + /** + * 文本组件等获得焦点后的边框线条宽度. + */ + public static int defaultFocusedThikness = 2; + + /** + * Gets the single instance of FocusListenerImpl. + * + * @return single instance of FocusListenerImpl + */ + public static FocusListenerImpl getInstance() { +// return INSTANCE; + return new FocusListenerImpl(); + } + + /** + * The focused thikness. + */ + protected int focusedThikness = defaultFocusedThikness; + + /** + * Gets the focused thikness. + * + * @return the focused thikness + */ + public int getFocusedThikness() { + return focusedThikness; + } + + /** + * Sets the focused thikness. + * + * @param focusedThikness the focused thikness + * @return the focus listener impl + */ + public FocusListenerImpl setFocusedThikness(int focusedThikness) { + this.focusedThikness = focusedThikness; + return this; + } + + @Override + public void focusGained(FocusEvent e) { + if (e.getSource() instanceof JComponent) { + JComponent com = (JComponent) e.getSource(); + Border orignalBorder = com.getBorder(); + + if (orignalBorder != null) { + //决定获得焦点时的连框色调 + Color focusedColor = getTextFieldFocusedColor(); + + //JTextField获得焦点时特殊处理:自动切换它的背景图即可(用NinePatch图实现) + if (com instanceof JTextComponent) { + JTextComponent text = (JTextComponent) com; + ComponentUI ui = text.getUI(); + text.putClientProperty("BEFocused", true); + if (ui instanceof BgSwitchable) { + ((BgSwitchable) ui).switchBgToFocused(); + com.repaint(); + return; + } + } else if (com instanceof JComboBox) + focusedColor = getComboBoxFocusedColor(); + + //获得焦点后的新边框 + BERoundBorder cc; + if (orignalBorder instanceof BERoundBorder) + cc = (BERoundBorder) (((BERoundBorder) orignalBorder).clone()); + else + cc = new BERoundBorder(1).setArcWidth(0); + cc.setLineColor(focusedColor); + cc.setThickness(focusedThikness); + + //* !当组件是JPasswordField,它的反应会有bug,也就是在setBorder之后它的 + //* preferredSize会变的很小,这里针对其作的特殊处理就是为了使其size与setBorder前保持一致 + Dimension oldDm = null; + if (com instanceof JTextField) + oldDm = com.getSize(); + com.setBorder(cc); + if (com instanceof JTextField) + com.setPreferredSize(oldDm); + } + } + } + + @Override + public void focusLost(FocusEvent e) { + if (e.getSource() instanceof JComponent) { + JComponent com = (JComponent) e.getSource(); + + //JTextField获得焦点时特殊处理:自动切换它的背景图即可(用NinePatch图实现) + if (com instanceof JTextComponent) { + JTextComponent text = (JTextComponent) com; + ComponentUI ui = text.getUI(); + text.putClientProperty("BEFocused", false); + if (ui instanceof BgSwitchable) { + ((BgSwitchable) ui).switchBgToNormal(); + com.repaint(); + return; + } + } + + //失去焦点时还原边框样式 + Border orignalBorder = com.getBorder(); + if (orignalBorder != null) + if (orignalBorder instanceof BERoundBorder) { + BERoundBorder cc = (BERoundBorder) (((BERoundBorder) orignalBorder).clone()); + cc.setLineColor(BERoundBorder.defaultLineColor); + cc.setThickness(1); + com.setBorder(cc); + } + } + } + + /** + * Gets the text field focused color. + * + * @return the text field focused color + */ + public static Color getTextFieldFocusedColor() { + return BEUtils.getColor(UIManager.getColor("TextField.selectionBackground"), 30, 30, 30); + } + + /** + * Gets the combo box focused color. + * + * @return the combo box focused color + */ + public static Color getComboBoxFocusedColor() { + return BEUtils.getColor(UIManager.getColor("ComboBox.selectionBackground"), 30, 30, 30); + } +// public static Color getTextPaneFocusedColor() +// { +// return LNFUtils.getColor(UIManager.getColor("TextPane.selectionBackground"),30,30,30); +// } + + @Override + public void mouseClicked(MouseEvent e) { + } + + @Override + public void mousePressed(MouseEvent e) { + } + + @Override + public void mouseReleased(MouseEvent e) { + } + + @Override + public void mouseEntered(MouseEvent e) { + if (e.getSource() instanceof JComponent) { + JComponent com = (JComponent) e.getSource(); + + //JTextField获得焦点时特殊处理:自动切换它的背景图即可(用NinePatch图实现) + if (com instanceof JTextComponent) { + JTextComponent text = (JTextComponent) com; + ComponentUI ui = text.getUI(); + Object o = text.getClientProperty("BEFocused"); + if (o == null || o == Boolean.FALSE) + if (ui instanceof BgSwitchable) { + ((BgSwitchable) ui).switchBgToOver(); + com.repaint(); + return; + } + } + + //失去焦点时还原边框样式 + Border orignalBorder = com.getBorder(); + if (orignalBorder != null) + if (orignalBorder instanceof BERoundBorder) { + BERoundBorder cc = (BERoundBorder) (((BERoundBorder) orignalBorder).clone()); + cc.setLineColor(BERoundBorder.defaultLineColor); + cc.setThickness(1); + com.setBorder(cc); + } + } + } + + @Override + public void mouseExited(MouseEvent e) { + if (e.getSource() instanceof JComponent) { + JComponent com = (JComponent) e.getSource(); + + //JTextField获得焦点时特殊处理:自动切换它的背景图即可(用NinePatch图实现) + if (com instanceof JTextComponent) { + JTextComponent text = (JTextComponent) com; + ComponentUI ui = text.getUI(); + Object o = text.getClientProperty("BEFocused"); + if (o == null || o == Boolean.FALSE) + if (ui instanceof BgSwitchable) { + ((BgSwitchable) ui).switchBgToNormal(); + com.repaint(); + return; + } + } + + //失去焦点时还原边框样式 + Border orignalBorder = com.getBorder(); + if (orignalBorder != null) + if (orignalBorder instanceof BERoundBorder) { + BERoundBorder cc = (BERoundBorder) (((BERoundBorder) orignalBorder).clone()); + cc.setLineColor(BERoundBorder.defaultLineColor); + cc.setThickness(1); + com.setBorder(cc); + } + } + } + +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/textcoms/__UI__.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/textcoms/__UI__.java new file mode 100644 index 000000000..7b1e07b04 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/textcoms/__UI__.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * __UI__.java at 2015-2-1 20:25:38, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.textcoms; + +import java.awt.Color; + +import javax.swing.UIManager; +import javax.swing.plaf.InsetsUIResource; +import org.jackhuang.hmcl.util.ui.GraphicsUtils; + +import org.jackhuang.hmcl.laf.BeautyEyeLNFHelper; +import org.jackhuang.hmcl.laf.utils.Icon9Factory; +import org.jackhuang.hmcl.laf.utils.UI; +import org.jackhuang.hmcl.laf.widget.border.BERoundBorder; + +public class __UI__ extends UI { + static final Color BORDER_NORMAL = GraphicsUtils.getWebColor("#999999"); + static final Color BORDER_OVER = GraphicsUtils.getWebColor("#666666"); + + static Color border_focused() { + return (Color) UIManager.get("TextField.focused"); + } + + public static final Icon9Factory ICON_9 = new Icon9Factory("text"); + + public static void uiImpl() { + final InsetsUIResource iuir = new InsetsUIResource(4, 7, 4, 7); + final BERoundBorder berb = new BERoundBorder().setLineColor(new Color(0, 0, 0, 0)); + + //使用全透明色绘边框(用什么边框无所谓,关键是读取它的margin并透明),目的就是要让它的背景显现出来(NinePatch图实现) + UIManager.put("TextField.margin", iuir); + put("TextField.border", berb); + put("TextField.selectionForeground", BeautyEyeLNFHelper.commonSelectionForegroundColor); + put("TextField.selectionBackground", BeautyEyeLNFHelper.commonSelectionBackgroundColor); + put("TextField.foreground", BeautyEyeLNFHelper.commonForegroundColor); + put("TextFieldUI", BETextFieldUI.class); + + UIManager.put("FormattedTextField.margin", iuir); + put("FormattedTextField.border", new BERoundBorder(1).setArcWidth(10).setLineColor(new Color(0, 0, 0, 0))); + put("FormattedTextField.foreground", BeautyEyeLNFHelper.commonForegroundColor); + put("FormattedTextField.inactiveBackground", BeautyEyeLNFHelper.commonBackgroundColor); + put("FormattedTextField.selectionForeground", BeautyEyeLNFHelper.commonSelectionForegroundColor); + put("FormattedTextField.selectionBackground", BeautyEyeLNFHelper.commonSelectionBackgroundColor); + put("FormattedTextFieldUI", BEFormattedTextFieldUI.class); + + UIManager.put("PasswordField.margin", iuir); + put("PasswordField.border", berb); + put("PasswordField.selectionForeground", BeautyEyeLNFHelper.commonSelectionForegroundColor); + put("PasswordField.selectionBackground", BeautyEyeLNFHelper.commonSelectionBackgroundColor); + put("PasswordField.foreground", BeautyEyeLNFHelper.commonForegroundColor); + put("PasswordFieldUI", BEPasswordFieldUI.class); + + UIManager.put("TextArea.margin", iuir); + put("TextArea.border", berb); + put("TextArea.selectionForeground", BeautyEyeLNFHelper.commonSelectionForegroundColor); + put("TextArea.selectionBackground", BeautyEyeLNFHelper.commonSelectionBackgroundColor); + put("TextArea.foreground", BeautyEyeLNFHelper.commonForegroundColor); + put("TextAreaUI", BETextAreaUI.class); + + put("TextPane.border", berb); + put("TextPane.selectionForeground", BeautyEyeLNFHelper.commonSelectionForegroundColor); + put("TextPane.selectionBackground", BeautyEyeLNFHelper.commonSelectionBackgroundColor); + put("TextPane.foreground", BeautyEyeLNFHelper.commonForegroundColor); + put("TextPaneUI", BETextPaneUI.class); + + put("EditorPane.border", berb); + put("EditorPane.selectionForeground", BeautyEyeLNFHelper.commonSelectionForegroundColor); + put("EditorPane.selectionBackground", BeautyEyeLNFHelper.commonSelectionBackgroundColor); + put("EditorPane.foreground", BeautyEyeLNFHelper.commonForegroundColor); + put("EditorPaneUI", BEEditorPaneUI.class); + } + + public interface BgSwitchable { + + void switchBgToNormal(); + + void switchBgToFocused(); + + void switchBgToOver(); + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/titlepane/BERootPaneUI.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/titlepane/BERootPaneUI.java new file mode 100644 index 000000000..ddaa963bc --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/titlepane/BERootPaneUI.java @@ -0,0 +1,1232 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * BERootPaneUI.java at 2015-2-1 20:25:40, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.titlepane; + +import java.awt.Component; +import java.awt.Container; +import java.awt.Cursor; +import java.awt.Dialog; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.HeadlessException; +import java.awt.Insets; +import java.awt.LayoutManager; +import java.awt.LayoutManager2; +import java.awt.MouseInfo; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Toolkit; +import java.awt.Window; +import java.awt.event.InputEvent; +import java.awt.event.MouseEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.event.WindowListener; +import java.beans.PropertyChangeEvent; +import java.security.AccessController; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; + +import javax.swing.JComponent; +import javax.swing.JLayeredPane; +import javax.swing.JRootPane; +import javax.swing.LookAndFeel; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.border.Border; +import javax.swing.event.MouseInputListener; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.UIResource; +import javax.swing.plaf.basic.BasicRootPaneUI; + +import org.jackhuang.hmcl.laf.BeautyEyeLNFHelper; +import org.jackhuang.hmcl.laf.WindowTranslucencyHelper; + +/** + * 窗体的UI实现. + * + * @author Jack Jiang(jb2011@163.com) + * @see javax.swing.plaf.metal.MetalRootPaneUI + */ +public class BERootPaneUI extends BasicRootPaneUI { + + /** + * Keys to lookup borders in defaults table. + */ + private static final String[] BORDER_KEYS = new String[] { + null, + "RootPane.frameBorder", + "RootPane.plainDialogBorder", + "RootPane.informationDialogBorder", + "RootPane.errorDialogBorder", + "RootPane.colorChooserDialogBorder", + "RootPane.fileChooserDialogBorder", + "RootPane.questionDialogBorder", + "RootPane.warningDialogBorder" + }; + + //* 2012-09-19 在BeautyEye v3.2中此常量被Jack Jiang取消了,因为 + //* v3.2中启用了相比原MetalRootPaneUI中更精确更好的边框拖放算法 +// /** +// * The amount of space (in pixels) that the cursor is changed on. +// */ +// //MetalLookAndFeel中默认是16 +// private static final int CORNER_DRAG_WIDTH = 16; +// //BeautyEyeLNFHelper.__getFrameBorder_CORNER_DRAG_WIDTH();//为了便 得用户的敏感触点区更大,提高用户体验,此值可加大 + /** + * Region from edges that dragging is active from. + */ + //窗口可拖动敏感触点区域大小要设置多大取决于你知定义border的insets,默认是 5; + private static final int BORDER_DRAG_THICKNESS = 5; + //BeautyEyeLNFHelper.__getFrameBorder_BORDER_DRAG_THICKNESS();//为了便 得用户的敏感触点区更大,提高用户体验,此值可加大 + + /** + * Window the JRootPane is in. + */ + private Window window; + + /** + * JComponent providing window decorations. This will be null + * if not providing window decorations. + */ + private JComponent titlePane; + + /** + * MouseInputListener that is added to the parent + * Window the JRootPane is contained in. + */ + private MouseInputListener mouseInputListener; + + /** + * The LayoutManager that is set on the JRootPane. + */ + private LayoutManager layoutManager; + + /** + * LayoutManager of the JRootPane before we + * replaced it. + */ + private LayoutManager savedOldLayout; + + /** + * JRootPane providing the look and feel for. + */ + private JRootPane root; + + /** + * Cursor used to track the cursor set by the user. This is + * initially Cursor.DEFAULT_CURSOR. + */ + private Cursor lastCursor + = Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR); + + /** + * 用于在窗口被激活与不激活时自动设置它的透明度(不激活时设为半透明). + */ + private WindowListener windowsListener = null; + + public static ComponentUI createUI(JComponent c) { + return new BERootPaneUI(); + } + + /** + * Invokes supers implementation of installUI to install the + * necessary state onto the passed in JRootPane to render the + * metal look and feel implementation of RootPaneUI. If the + * windowDecorationStyle property of the JRootPane + * is other than JRootPane.NONE, this will add a custom + * Component to render the widgets to JRootPane, + * as well as installing a custom Border and + * LayoutManager on the JRootPane. + * + * @param c the JRootPane to install state onto + */ + @Override + public void installUI(JComponent c) { + super.installUI(c); + + root = (JRootPane) c; + int style = root.getWindowDecorationStyle(); + + if (style != JRootPane.NONE) + installClientDecorations(root); + } + + /** + * Invokes supers implementation to uninstall any of its state. This will + * also reset the LayoutManager of the JRootPane. + * If a Component has been added to the JRootPane + * to render the window decoration style, this method will remove it. + * Similarly, this will revert the Border and LayoutManager of the + * JRootPane to what it was before installUI was + * invoked. + * + * @param c the JRootPane to uninstall state from + */ + @Override + public void uninstallUI(JComponent c) { + super.uninstallUI(c); + uninstallClientDecorations(root); + + layoutManager = null; + mouseInputListener = null; + root = null; + } + + /** + * Installs the appropriate Border onto the + * JRootPane. + * + * @param root the root + */ + void installBorder(JRootPane root) { + int style = root.getWindowDecorationStyle(); + + if (style == JRootPane.NONE) + LookAndFeel.uninstallBorder(root); + else { + Border b = root.getBorder(); + if (b == null || b instanceof UIResource) { + root.setBorder(null); + root.setBorder(UIManager.getBorder(BORDER_KEYS[style])); + } + } + } + + /** + * Removes any border that may have been installed. + * + * @param root the root + */ + private void uninstallBorder(JRootPane root) { + LookAndFeel.uninstallBorder(root); + } + + /** + * Installs the necessary Listeners on the parent Window, if + * there is one. + *

+ * This takes the parent so that cleanup can be done from + * removeNotify, at which point the parent hasn't been reset + * yet. + * + * @param root the root + * @param parent The parent of the JRootPane + */ + private void installWindowListeners(JRootPane root, Component parent) { + if (parent instanceof Window) + window = (Window) parent; + else + window = SwingUtilities.getWindowAncestor(parent); + if (window != null) { + if (mouseInputListener == null) + mouseInputListener = createWindowMouseInputListener(root); + + window.addMouseListener(mouseInputListener); + window.addMouseMotionListener(mouseInputListener); + + //* add by JS 2011-12-27,给窗口增加监听器:在不活动时设置窗口半透明,活动时还原 + if (BeautyEyeLNFHelper.translucencyAtFrameInactive) { + if (windowsListener == null) + windowsListener = new WindowAdapter() { + @Override + public void windowActivated(WindowEvent e) { + if (window != null) + window.setOpacity(1); + } + + @Override + public void windowDeactivated(WindowEvent e) { + if (window != null) + window.setOpacity(0.94f); + } + }; + window.addWindowListener(windowsListener); + } + } + } + + /** + * Uninstalls the necessary Listeners on the Window the + * Listeners were last installed on. + * + * @param root the root + */ + private void uninstallWindowListeners(JRootPane root) { + if (window != null) { + window.removeMouseListener(mouseInputListener); + window.removeMouseMotionListener(mouseInputListener); + } + } + + /** + * Installs the appropriate LayoutManager on the JRootPane to + * render the window decorations. + * + * @param root the root + */ + private void installLayout(JRootPane root) { + if (layoutManager == null) + layoutManager = createLayoutManager(); + savedOldLayout = root.getLayout(); + root.setLayout(layoutManager); + } + + /** + * Uninstalls the previously installed LayoutManager. + * + * @param root the root + */ + private void uninstallLayout(JRootPane root) { + if (savedOldLayout != null) { + root.setLayout(savedOldLayout); + savedOldLayout = null; + } + } + + /** + * Installs the necessary state onto the JRootPane to render client + * decorations. This is ONLY invoked if the JRootPane has a + * decoration style other than JRootPane.NONE. + * + * @param root the root + */ + private void installClientDecorations(JRootPane root) { + installBorder(root); + + JComponent p = createTitlePane(root); + + setTitlePane(root, p); + installWindowListeners(root, root.getParent()); + installLayout(root); + + //只有在窗口边框是半透明的情况下,以下才需要设置窗口透明 + //* 注意:本类中的此处代码的目的就是为了实现半透明边框窗口的 + //* 正常显示,而且仅针对此目的。如果该边框不为透明,则此处也就不需要设置 + //* 窗口透明了,那么如果你的程序其它地方需要窗口透明的话,自行.setWindowOpaque(..) + //* 就行了,由开发者自先决定,此处就不承载过多的要求了 + if (!BeautyEyeLNFHelper.isFrameBorderOpaque() + && window != null) { + //** 20111222 by jb2011,让窗口全透明(用以实现窗口的透明边框效果) +// AWTUtilities.setWindowOpaque(window, false); + // TODO BUG:1)目前可知,在jdk1.7.0_u6下,JDialog的半透明边框的透明度比原设计深一倍 + // TODO BUG:2)目前可知,在jdk1.6.0_u33下+win7平台下,JFrame窗口被调置成透明后, + // 该窗口内所在文本都会被反走样(不管你要没有要求反走样),真悲具,这应该 + // 是官方AWTUtilities.setWindowOpaque(..)bug导致的,1.7.0_u6同样存在该问题, + // 使用BeautyEye时,遇到这样的问题只能自行使用__isFrameBorderOpaque中指定的 + // 不透明边框才行(这样此类的以下代码就不用执行,也就不用触发该bug了),但 + // JDialog不受此bug影响,诡异! + WindowTranslucencyHelper.setWindowOpaque(window, false); + root.revalidate(); + root.repaint(); + } + } + + /** + * Uninstalls any state that installClientDecorations has + * installed. + *

+ * NOTE: This may be called if you haven't installed client decorations yet + * (ie before installClientDecorations has been invoked). + * + * @param root the root + */ + private void uninstallClientDecorations(JRootPane root) { + uninstallBorder(root); + uninstallWindowListeners(root); + setTitlePane(root, null); + uninstallLayout(root); + // We have to revalidate/repaint root if the style is JRootPane.NONE + // only. When we needs to call revalidate/repaint with other styles + // the installClientDecorations is always called after this method + // imediatly and it will cause the revalidate/repaint at the proper + // time. + int style = root.getWindowDecorationStyle(); + if (style == JRootPane.NONE) { + root.repaint(); + root.revalidate(); + } + // Reset the cursor, as we may have changed it to a resize cursor + if (window != null) + window.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + window = null; + } + + /** + * Returns the JComponent to render the window decoration + * style. + * + * @param root the root + * @return the j component + */ + private JComponent createTitlePane(JRootPane root) { + return new BETitlePane(root, this); + } + + /** + * Returns a MouseListener that will be added to the + * Window containing the JRootPane. + * + * @param root the root + * @return the mouse input listener + */ + private MouseInputListener createWindowMouseInputListener(JRootPane root) { + return new MouseInputHandler(); + } + + /** + * Returns a LayoutManager that will be set on the + * JRootPane. + * + * @return the layout manager + */ + private LayoutManager createLayoutManager() { + return new XMetalRootLayout(); + } + + /** + * Sets the window title pane -- the JComponent used to provide a plaf a way + * to override the native operating system's window title pane with one + * whose look and feel are controlled by the plaf. The plaf creates and sets + * this value; the default is null, implying a native operating system + * window title pane. + * + * @param root the root + * @param titlePane the title pane + */ + private void setTitlePane(JRootPane root, JComponent titlePane) { + JLayeredPane layeredPane = root.getLayeredPane(); + JComponent oldTitlePane = getTitlePane(); + + if (oldTitlePane != null) { + oldTitlePane.setVisible(false); + layeredPane.remove(oldTitlePane); + } + if (titlePane != null) { + layeredPane.add(titlePane, JLayeredPane.FRAME_CONTENT_LAYER); + titlePane.setVisible(true); + } + this.titlePane = titlePane; + } + + /** + * Returns the JComponent rendering the title pane. If this + * returns null, it implies there is no need to render window decorations. + * + * @return the current window title pane, or null + * @see #setTitlePane + */ + private JComponent getTitlePane() { + return titlePane; + } + + /** + * Returns the JRootPane we're providing the look and feel for. + * + * @return the root pane + */ + private JRootPane getRootPane() { + return root; + } + + /** + * Invoked when a property changes. MetalRootPaneUI is + * primarily interested in events originating from the + * JRootPane it has been installed on identifying the property + * windowDecorationStyle. If the + * windowDecorationStyle has changed to a value other than + * JRootPane.NONE, this will add a Component to + * the JRootPane to render the window decorations, as well as + * installing a Border on the JRootPane. On the + * other hand, if the windowDecorationStyle has changed to + * JRootPane.NONE, this will remove the Component + * that has been added to the JRootPane as well resetting the + * Border to what it was before installUI was invoked. + * + * @param e A PropertyChangeEvent object describing the event source and the + * property that has changed. + */ + @Override + public void propertyChange(PropertyChangeEvent e) { + super.propertyChange(e); + + String propertyName = e.getPropertyName(); + if (propertyName == null) + return; + + if (propertyName.equals("windowDecorationStyle")) { + JRootPane r = (JRootPane) e.getSource(); + int style = r.getWindowDecorationStyle(); + + // This is potentially more than needs to be done, + // but it rarely happens and makes the install/uninstall process + // simpler. MetalTitlePane also assumes it will be recreated if + // the decoration style changes. + uninstallClientDecorations(r); + if (style != JRootPane.NONE) + installClientDecorations(r); + } else if (propertyName.equals("ancestor")) { + uninstallWindowListeners(root); + if (((JRootPane) e.getSource()).getWindowDecorationStyle() + != JRootPane.NONE) + installWindowListeners(root, root.getParent()); + } + } + + /** + * A custom layout manager that is responsible for the layout of + * layeredPane, glassPane, menuBar and titlePane, if one has been installed. + */ + // NOTE: Ideally this would extends JRootPane.RootLayout, but that + // would force this to be non-static. + private static class XMetalRootLayout implements LayoutManager2 { + + /** + * Returns the amount of space the layout would like to have. + * + * @param parent the parent + * @return a Dimension object containing the layout's preferred size + */ + @Override + public Dimension preferredLayoutSize(Container parent) { + Dimension cpd, mbd, tpd; + int cpWidth = 0; + int cpHeight = 0; + int mbWidth = 0; + int mbHeight = 0; + int tpWidth = 0; + int tpHeight = 0; + Insets i = parent.getInsets(); + JRootPane root = (JRootPane) parent; + + if (root.getContentPane() != null) + cpd = root.getContentPane().getPreferredSize(); + else + cpd = root.getSize(); + if (cpd != null) { + cpWidth = cpd.width; + cpHeight = cpd.height; + } + + if (root.getMenuBar() != null) { + mbd = root.getMenuBar().getPreferredSize(); + if (mbd != null) { + mbWidth = mbd.width; + mbHeight = mbd.height; + } + } + + if (root.getWindowDecorationStyle() != JRootPane.NONE + && (root.getUI() instanceof BERootPaneUI)) { + JComponent titlePane = ((BERootPaneUI) root.getUI()). + getTitlePane(); + if (titlePane != null) { + tpd = titlePane.getPreferredSize(); + if (tpd != null) { + tpWidth = tpd.width; + tpHeight = tpd.height; + } + } + } + + return new Dimension(Math.max(Math.max(cpWidth, mbWidth), tpWidth) + i.left + i.right, + cpHeight + mbHeight + tpWidth + i.top + i.bottom); + } + + /** + * Returns the minimum amount of space the layout needs. + * + * @param parent the parent + * @return a Dimension object containing the layout's minimum size + */ + @Override + public Dimension minimumLayoutSize(Container parent) { + Dimension cpd, mbd, tpd; + int cpWidth = 0; + int cpHeight = 0; + int mbWidth = 0; + int mbHeight = 0; + int tpWidth = 0; + int tpHeight = 0; + Insets i = parent.getInsets(); + JRootPane root = (JRootPane) parent; + + if (root.getContentPane() != null) + cpd = root.getContentPane().getMinimumSize(); + else + cpd = root.getSize(); + if (cpd != null) { + cpWidth = cpd.width; + cpHeight = cpd.height; + } + + if (root.getMenuBar() != null) { + mbd = root.getMenuBar().getMinimumSize(); + if (mbd != null) { + mbWidth = mbd.width; + mbHeight = mbd.height; + } + } + if (root.getWindowDecorationStyle() != JRootPane.NONE + && (root.getUI() instanceof BERootPaneUI)) { + JComponent titlePane = ((BERootPaneUI) root.getUI()). + getTitlePane(); + if (titlePane != null) { + tpd = titlePane.getMinimumSize(); + if (tpd != null) { + tpWidth = tpd.width; + tpHeight = tpd.height; + } + } + } + + return new Dimension(Math.max(Math.max(cpWidth, mbWidth), tpWidth) + i.left + i.right, + cpHeight + mbHeight + tpWidth + i.top + i.bottom); + } + + /** + * Returns the maximum amount of space the layout can use. + * + * @param target the target + * @return a Dimension object containing the layout's maximum size + */ + @Override + public Dimension maximumLayoutSize(Container target) { + Dimension cpd, mbd, tpd; + int cpWidth = Integer.MAX_VALUE; + int cpHeight = Integer.MAX_VALUE; + int mbWidth = Integer.MAX_VALUE; + int mbHeight = Integer.MAX_VALUE; + int tpWidth = Integer.MAX_VALUE; + int tpHeight = Integer.MAX_VALUE; + Insets i = target.getInsets(); + JRootPane root = (JRootPane) target; + + if (root.getContentPane() != null) { + cpd = root.getContentPane().getMaximumSize(); + if (cpd != null) { + cpWidth = cpd.width; + cpHeight = cpd.height; + } + } + + if (root.getMenuBar() != null) { + mbd = root.getMenuBar().getMaximumSize(); + if (mbd != null) { + mbWidth = mbd.width; + mbHeight = mbd.height; + } + } + + if (root.getWindowDecorationStyle() != JRootPane.NONE + && (root.getUI() instanceof BERootPaneUI)) { + JComponent titlePane = ((BERootPaneUI) root.getUI()). + getTitlePane(); + if (titlePane != null) { + tpd = titlePane.getMaximumSize(); + if (tpd != null) { + tpWidth = tpd.width; + tpHeight = tpd.height; + } + } + } + + int maxHeight = Math.max(Math.max(cpHeight, mbHeight), tpHeight); + // Only overflows if 3 real non-MAX_VALUE heights, sum to > MAX_VALUE + // Only will happen if sums to more than 2 billion units. Not likely. + if (maxHeight != Integer.MAX_VALUE) + maxHeight = cpHeight + mbHeight + tpHeight + i.top + i.bottom; + + int maxWidth = Math.max(Math.max(cpWidth, mbWidth), tpWidth); + // Similar overflow comment as above + if (maxWidth != Integer.MAX_VALUE) + maxWidth += i.left + i.right; + + return new Dimension(maxWidth, maxHeight); + } + + /** + * Instructs the layout manager to perform the layout for the specified + * container. + * + * @param parent the parent + */ + @Override + public void layoutContainer(Container parent) { + JRootPane root = (JRootPane) parent; + Rectangle b = root.getBounds(); + Insets i = root.getInsets(); + int nextY = 0; + int w = b.width - i.right - i.left; + int h = b.height - i.top - i.bottom; + + if (root.getLayeredPane() != null) + root.getLayeredPane().setBounds(i.left, i.top, w, h); + if (root.getGlassPane() != null) + root.getGlassPane().setBounds(i.left, i.top, w, h); + // Note: This is laying out the children in the layeredPane, + // technically, these are not our children. + if (root.getWindowDecorationStyle() != JRootPane.NONE + && (root.getUI() instanceof BERootPaneUI)) { + JComponent titlePane = ((BERootPaneUI) root.getUI()). + getTitlePane(); + if (titlePane != null) { + Dimension tpd = titlePane.getPreferredSize(); + if (tpd != null) { + int tpHeight = tpd.height; + titlePane.setBounds(0, 0, w, tpHeight); + nextY += tpHeight; + } + } + } + if (root.getJMenuBar() != null + //* 该 行代码由Jack Jiang于2012-10-20增加:目的是为解决当 + //* MebuBar被设置不可见时任然被错误地当作可视组件占据布局空间,这 + //* 在BE LNF中的表现就是当menuBar不可见,它占据的那块空间将会是全透明 + //* 的空白区。这个问题在Metal主题中仍然存在(就是设置JFrame.setDefaultLookAndFeelDecorated(true); + //* JDialog.setDefaultLookAndFeelDecorated(true);后的Metal主题状态), + //* 可能官方不认为这是个bug吧。 + //* 为什么无论什么外观当在使用系统窗口边框类型时不会出现这样的情况呢?它 + //* 可能是由于窗口外观的实现原理决定的吧(按理说是同一原理),有待深究!!! + && root.getJMenuBar().isVisible()) { + Dimension mbd = root.getJMenuBar().getPreferredSize(); + root.getJMenuBar().setBounds(0, nextY, w, mbd.height); + nextY += mbd.height; + } + if (root.getContentPane() != null + //* 该 行代码由Jack Jiang于2012-10-20增加:目的是为解决与menubar在设置可见性时遇难到的一样的问题 + && root.getContentPane().isVisible()) { + Dimension cpd = root.getContentPane().getPreferredSize(); + root.getContentPane().setBounds(0, nextY, w, + h < nextY ? 0 : h - nextY); + } + } + + @Override + public void addLayoutComponent(String name, Component comp) { + } + + @Override + public void removeLayoutComponent(Component comp) { + } + + @Override + public void addLayoutComponent(Component comp, Object constraints) { + } + + @Override + public float getLayoutAlignmentX(Container target) { + return 0.0f; + } + + @Override + public float getLayoutAlignmentY(Container target) { + return 0.0f; + } + + @Override + public void invalidateLayout(Container target) { + } + } + + /** + * Maps from positions to cursor type. Refer to calculateCorner and + * calculatePosition for details of this. + */ + private static final int[] cursorMapping = new int[] { Cursor.NW_RESIZE_CURSOR, + Cursor.NW_RESIZE_CURSOR, + Cursor.N_RESIZE_CURSOR, + Cursor.NE_RESIZE_CURSOR, + Cursor.NE_RESIZE_CURSOR, + Cursor.NW_RESIZE_CURSOR, + 0, + 0, + 0, + Cursor.NE_RESIZE_CURSOR, + Cursor.W_RESIZE_CURSOR, + 0, + 0, + 0, + Cursor.E_RESIZE_CURSOR, + Cursor.SW_RESIZE_CURSOR, + 0, + 0, + 0, + Cursor.SE_RESIZE_CURSOR, + Cursor.SW_RESIZE_CURSOR, + Cursor.SW_RESIZE_CURSOR, + Cursor.S_RESIZE_CURSOR, + Cursor.SE_RESIZE_CURSOR, + Cursor.SE_RESIZE_CURSOR + }; + + /** + * MouseInputHandler is responsible for handling resize/moving of the + * Window. It sets the cursor directly on the Window when then mouse moves + * over a hot spot. + */ + private class MouseInputHandler implements MouseInputListener { + + /** + * Set to true if the drag operation is moving the window. + */ + private boolean isMovingWindow; + + /** + * Used to determine the corner the resize is occuring from. + */ + private int dragCursor; + + /** + * X location the mouse went down on for a drag operation. + */ + private int dragOffsetX; + + /** + * Y location the mouse went down on for a drag operation. + */ + private int dragOffsetY; + + /** + * Width of the window when the drag started. + */ + private int dragWidth; + + /** + * Height of the window when the drag started. + */ + private int dragHeight; + + /* + * PrivilegedExceptionAction needed by mouseDragged method to + * obtain new location of window on screen during the drag. + */ + /** + * The get location action. + */ + private final PrivilegedExceptionAction getLocationAction = new PrivilegedExceptionAction() { + @Override + public Object run() throws HeadlessException { + return MouseInfo.getPointerInfo().getLocation(); + } + }; + + @Override + public void mousePressed(MouseEvent ev) { + JRootPane rootPane = getRootPane(); + + if (rootPane.getWindowDecorationStyle() == JRootPane.NONE) + return; + Point dragWindowOffset = ev.getPoint(); + Window w = (Window) ev.getSource(); + if (w != null) + w.toFront(); + Point convertedDragWindowOffset = SwingUtilities.convertPoint(w, + dragWindowOffset, getTitlePane()); + + Frame f = null; + Dialog d = null; + + if (w instanceof Frame) + f = (Frame) w; + else if (w instanceof Dialog) + d = (Dialog) w; + + int frameState = (f != null) ? f.getExtendedState() : 0; + + if (getTitlePane() != null + && getTitlePane().contains(convertedDragWindowOffset)) { + if ((f != null && ((frameState & Frame.MAXIMIZED_BOTH) == 0) || (d != null)) + && dragWindowOffset.y >= BORDER_DRAG_THICKNESS + && dragWindowOffset.x >= BORDER_DRAG_THICKNESS + && dragWindowOffset.x < w.getWidth() + - BORDER_DRAG_THICKNESS) { + isMovingWindow = true; + dragOffsetX = dragWindowOffset.x; + dragOffsetY = dragWindowOffset.y; + } + } else if (f != null && f.isResizable() + && ((frameState & Frame.MAXIMIZED_BOTH) == 0) + || (d != null && d.isResizable())) { +// System.out.println("dragOffsetX="+dragOffsetX+" dragOffsetY="+dragOffsetY); TODO + dragOffsetX = dragWindowOffset.x; + dragOffsetY = dragWindowOffset.y; + dragWidth = w.getWidth(); + dragHeight = w.getHeight(); + dragCursor + = // getCursor(calculateCorner(w, dragWindowOffset.x,dragWindowOffset.y)); // TODO TEST + getCursor_new(w, dragWindowOffset.x, dragWindowOffset.y); + } + } + + @Override + public void mouseReleased(MouseEvent ev) { + if (dragCursor != 0 && window != null && !window.isValid()) { + // Some Window systems validate as you resize, others won't, + // thus the check for validity before repainting. + window.validate(); + getRootPane().repaint(); + } + isMovingWindow = false; + dragCursor = 0; + } + + @Override + public void mouseMoved(MouseEvent ev) { + JRootPane root = getRootPane(); + + if (root.getWindowDecorationStyle() == JRootPane.NONE) + return; + + Window w = (Window) ev.getSource(); + + Frame f = null; + Dialog d = null; + + if (w instanceof Frame) + f = (Frame) w; + else if (w instanceof Dialog) + d = (Dialog) w; + + // Update the cursor + int cursor + = //接下来1)测试算法的正确性 2)测试极端情况:即border小于或部分小于BORDER_THINNESS,3)写注释、整理代码! + // getCursor(calculateCorner(w, ev.getX(), ev.getY()));// TODO Test!! + getCursor_new(w, ev.getX(), ev.getY()); + + if (cursor != 0 + && ((f != null && (f.isResizable() && (f.getExtendedState() & Frame.MAXIMIZED_BOTH) == 0)) || (d != null && d + .isResizable()))) + w.setCursor(Cursor.getPredefinedCursor(cursor)); + else + w.setCursor(lastCursor); + } + + /** + * Adjust. + * + * @param bounds the bounds + * @param min the min + * @param deltaX the delta x + * @param deltaY the delta y + * @param deltaWidth the delta width + * @param deltaHeight the delta height + */ + private void adjust(Rectangle bounds, Dimension min, int deltaX, + int deltaY, int deltaWidth, int deltaHeight) { + bounds.x += deltaX; + bounds.y += deltaY; + bounds.width += deltaWidth; + bounds.height += deltaHeight; + if (min != null) { + if (bounds.width < min.width) { + int correction = min.width - bounds.width; + if (deltaX != 0) + bounds.x -= correction; + bounds.width = min.width; + } + if (bounds.height < min.height) { + int correction = min.height - bounds.height; + if (deltaY != 0) + bounds.y -= correction; + bounds.height = min.height; + } + } + } + + @Override + public void mouseDragged(MouseEvent ev) { + Window w = (Window) ev.getSource(); + Point pt = ev.getPoint(); + + if (isMovingWindow) { + Point windowPt; + try { + windowPt = (Point) AccessController + .doPrivileged(getLocationAction); + windowPt.x = windowPt.x - dragOffsetX; + windowPt.y = windowPt.y - dragOffsetY; + w.setLocation(windowPt); + } catch (PrivilegedActionException e) { + } + } else if (dragCursor != 0) { + Rectangle r = w.getBounds(); + Rectangle startBounds = new Rectangle(r); + Dimension min = w.getMinimumSize(); + + switch (dragCursor) { + case Cursor.E_RESIZE_CURSOR: + adjust(r, min, 0, 0, pt.x + (dragWidth - dragOffsetX) + - r.width, 0); + break; + case Cursor.S_RESIZE_CURSOR: + adjust(r, min, 0, 0, 0, pt.y + + (dragHeight - dragOffsetY) - r.height); + break; + case Cursor.N_RESIZE_CURSOR: + adjust(r, min, 0, pt.y - dragOffsetY, 0, + -(pt.y - dragOffsetY)); + break; + case Cursor.W_RESIZE_CURSOR: + adjust(r, min, pt.x - dragOffsetX, 0, + -(pt.x - dragOffsetX), 0); + break; + case Cursor.NE_RESIZE_CURSOR: + adjust(r, min, 0, pt.y - dragOffsetY, pt.x + + (dragWidth - dragOffsetX) - r.width, + -(pt.y - dragOffsetY)); + break; + case Cursor.SE_RESIZE_CURSOR: + adjust(r, min, 0, 0, pt.x + (dragWidth - dragOffsetX) + - r.width, pt.y + (dragHeight - dragOffsetY) + - r.height); + break; + case Cursor.NW_RESIZE_CURSOR: + adjust(r, min, pt.x - dragOffsetX, pt.y - dragOffsetY, + -(pt.x - dragOffsetX), -(pt.y - dragOffsetY)); + break; + case Cursor.SW_RESIZE_CURSOR: + adjust(r, min, pt.x - dragOffsetX, 0, + -(pt.x - dragOffsetX), pt.y + + (dragHeight - dragOffsetY) - r.height); + break; + default: + break; + } + if (!r.equals(startBounds)) { + w.setBounds(r); + // Defer repaint/validate on mouseReleased unless dynamic + // layout is active. + if (Toolkit.getDefaultToolkit().isDynamicLayoutActive()) { + w.validate(); + getRootPane().repaint(); + } + } + } + } + + @Override + public void mouseEntered(MouseEvent ev) { + Window w = (Window) ev.getSource(); + lastCursor = w.getCursor(); + mouseMoved(ev); + } + + @Override + public void mouseExited(MouseEvent ev) { + Window w = (Window) ev.getSource(); + // TODO ###### Hack:因Swing鼠标事件问题,拖动过快的话很多时候没法正常地保留和设置lastCursor + // 从而导致经常性的退出拖动后,拖动时的鼠标样式还在,这样很不爽,这应该是swing + // 的鼠标事件不精确导致的或其它问题。目前不如干脃在退出拖动时强制还原到默认鼠标, + // 虽然在极少情况下可能回不到用户真正的lastCursor,但起码能解决目前在BueatyEye中 + // 因大border而频繁出现的这个问题了,先这么滴吧! +// w.setCursor(lastCursor); + w.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + } + + @Override + public void mouseClicked(MouseEvent ev) { + Window w = (Window) ev.getSource(); + Frame f; + + if (w instanceof Frame) + f = (Frame) w; + else + return; + + Point convertedPoint = SwingUtilities.convertPoint(w, + ev.getPoint(), getTitlePane()); + + int state = f.getExtendedState(); + if (getTitlePane() != null + && getTitlePane().contains(convertedPoint)) + if ((ev.getClickCount() % 2) == 0 + && ((ev.getModifiers() & InputEvent.BUTTON1_MASK) != 0)) + if (f.isResizable()) + if ((state & Frame.MAXIMIZED_BOTH) != 0) + f.setExtendedState(state & ~Frame.MAXIMIZED_BOTH); + else + f.setExtendedState(state | Frame.MAXIMIZED_BOTH); + } + + //*************************************************************** v3.2前参考自MetalRootPaneUI中的老边框拖放核心算法 START + //** 老算法说明:Metal中的算法是假设窗口边框的border是规划的,即上下左右的inset都是一样的,它假定可拖动范围是整个 + //** 窗体大小(包括border在内的大小)的BORDER_DRAG_THICKNESS常量范围内的上下左右区域,所以它的 算法在 + //** 此前题下通过较巧妙的方法简单实现没有问题。 + //** 老算法缺陷:当窗口的边框不规划,如FrameBorderStyle.translucencyAppleLik这种时(上=17,左=27,右=27,下=37), + //** 此情况下只能假定一个最小值了,以前是取的17作为统一边框范围距离,那么像下部原本是37的inset,现在拖动 + //** 范围是17,余下的原本是border里insets的10个像素也被算进窗口内容面板了,这样导致移动到下方时,明明 + //** 是在边缘位置,却不是处于拖动范围内(要再往下移10像素到达inset的第10~27像素范围内才行),这样就严重 + //** 影响了用户体验。 + //* 2012-09-19 在BeautyEye v3.2中的BERootPaneUI,Jack Jiang启用了相比 + //* 原MetalRootPaneUI中更精确更好的边框拖放算法,以下方法暂时弃用,以后可以删除了! START +// /** +// * Returns the corner that contains the point x, +// * y, or -1 if the position doesn't match a corner. +// */ +// private int calculateCorner(Window w, int x, int y) +// { +// Insets insets = w.getInsets(); +// int xPosition = calculatePosition(x - insets.left, w.getWidth() +// - insets.left - insets.right); +// int yPosition = calculatePosition(y - insets.top, w.getHeight() +// - insets.top - insets.bottom); +// +// if (xPosition == -1 || yPosition == -1) +// { +// return -1; +// } +// return yPosition * 5 + xPosition; +// } +// /** +// * Returns the Cursor to render for the specified corner. This returns +// * 0 if the corner doesn't map to a valid Cursor +// */ +// private int getCursor(int corner) +// { +// if (corner == -1) +// { +// return 0; +// } +// return cursorMapping[corner]; +// } +// /** +// * Returns an integer indicating the position of spot +// * in width. The return value will be: +// * 0 if < BORDER_DRAG_THICKNESS +// * 1 if < CORNER_DRAG_WIDTH +// * 2 if >= CORNER_DRAG_WIDTH && < width - BORDER_DRAG_THICKNESS +// * 3 if >= width - CORNER_DRAG_WIDTH +// * 4 if >= width - BORDER_DRAG_THICKNESS +// * 5 otherwise +// */ +// private int calculatePosition(int spot, int width) +// { +//// Insets iss = getRootPane().getInsets(); +//// System.out.println("ississ="+iss); //TODO +// +// if (spot < BORDER_DRAG_THICKNESS) +// { +// return 0; +// } +// if (spot < CORNER_DRAG_WIDTH) +// { +// return 1; +// } +// if (spot >= (width - BORDER_DRAG_THICKNESS)) +// { +// return 4; +// } +// if (spot >= (width - CORNER_DRAG_WIDTH)) +// { +// return 3; +// } +// return 2; +// }//********************************************************************* v3.2前的老边框拖放核心算法 END + //********************************************************************* v3.2版启用的新边框拖放核心算法 SART + //** 新算法说明:v3.2中启用的新算法的原理是把可拖动范围限定在内容区(即整个窗体大小减去Border后的真正工作区) + //** 往外的一个固定的BORDER_DRAG_THICKNESS区域内,即不管理你把窗口的border设置多么不规划,我的用户拖 + //** 动区永远是这一个范围内,这就保证用户体验,较好的解决了老算法的缺陷。 + /** + * Gets the cursor_new. + * + * @param w the w + * @param x the x + * @param y the y + * @return the cursor_new + */ + public int getCursor_new(Window w, int x, int y) { + Insets insets = w.getInsets(); + return getCursor_new(x - insets.left, y - insets.top, + w.getWidth() - insets.left - insets.right, + w.getHeight() - insets.top - insets.bottom); + } + + /** + * 新的窗口边框拖动算法的实现是把可拖动区分成8个距形区,当鼠标动到对应 + * 的区里就计算出是是向哪个方向拖动,比MetalRootPaneUI中的简易方法要明确和精确。 + *

+ * 可拖动判断区示意图:
+ * 红色到蓝色的整个区域是窗口的border范围,红色到灰色的区域是固定的可拖动区,红色到灰色的区域是固定的, + * 红色到蓝色的区域因border不同而不一样。
+ * 注意:算法中要注意一种极端情况,就是Border的一部分或全部都小于可拖动区的情况,以下算法应该也 + * 是没有问题的,无非算出的8可拖动距形区坐标有负的情况,初步测试过没影响,以后还是注意一下! + * + * + * + * + *
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
R1R2R3
R8可视工作区R4
R7R6R5
+ *
. + * + * @param x the x + * @param y the y + * @param w the w + * @param h the h + * @return the cursor_new + */ + public int getCursor_new(int x, int y, int w, int h) { + int B = BORDER_DRAG_THICKNESS; + + Insets iss = getRootPane().getInsets(); + int topI = iss.top, bottomI = iss.bottom, leftI = iss.left, rightI = iss.right; + + //8个拖动检测距形区 + Rectangle r1 = new Rectangle(leftI - B, topI - B, B, B); + Rectangle r2 = new Rectangle(leftI, topI - B, w - leftI - rightI, B); + Rectangle r3 = new Rectangle(w - rightI, topI - B, B, B); + Rectangle r4 = new Rectangle(w - rightI, topI, B, h - topI - bottomI); + Rectangle r5 = new Rectangle(w - rightI, h - bottomI, B, B); + Rectangle r6 = new Rectangle(leftI, h - bottomI, w - leftI - rightI, B); + Rectangle r7 = new Rectangle(leftI - B, h - bottomI, B, B); + Rectangle r8 = new Rectangle(leftI - B, topI, B, h - topI - bottomI); + + Point p = new Point(x, y); + int cc = 0; + + if (r1.contains(p)) + cc = Cursor.NW_RESIZE_CURSOR; + else if (r3.contains(p)) + cc = Cursor.NE_RESIZE_CURSOR; + else if (r5.contains(p)) + cc = Cursor.SE_RESIZE_CURSOR; + else if (r7.contains(p)) + cc = Cursor.SW_RESIZE_CURSOR; + else if (r2.contains(p)) + cc = Cursor.N_RESIZE_CURSOR; + else if (r4.contains(p)) + cc = Cursor.E_RESIZE_CURSOR; + else if (r6.contains(p)) + cc = Cursor.S_RESIZE_CURSOR; + else if (r8.contains(p)) + cc = Cursor.W_RESIZE_CURSOR; + + return cc; + } + }//********************************************************************* v3.2版启用的新边框拖放核心算法 END +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/titlepane/BETitlePane.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/titlepane/BETitlePane.java new file mode 100644 index 000000000..aceac56c6 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/titlepane/BETitlePane.java @@ -0,0 +1,1259 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * BETitlePane.java at 2015-2-1 20:25:36, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.titlepane; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dialog; +import java.awt.Dimension; +import java.awt.FontMetrics; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.Image; +import java.awt.Insets; +import java.awt.LayoutManager; +import java.awt.Paint; +import java.awt.Rectangle; +import java.awt.Toolkit; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.event.WindowListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.Locale; + +import javax.swing.AbstractAction; +import javax.swing.AbstractButton; +import javax.swing.Action; +import javax.swing.Icon; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.JRootPane; +import javax.swing.JSeparator; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.border.Border; +import javax.swing.border.EmptyBorder; +import javax.swing.plaf.UIResource; + +import org.jackhuang.hmcl.laf.BeautyEyeLNFHelper; +import org.jackhuang.hmcl.laf.BEUtils; +import org.jackhuang.hmcl.laf.utils.MySwingUtilities2; + +/** + * 窗体的标题栏UI实现. + * + * @author Jack Jiang(jb2011@163.com) + * @see javax.swing.plaf.metal.MetalTitlePane//(Java 1.5) + */ +public class BETitlePane extends JComponent { +// MetalTitlePane + +// MetalLookAndFeel +// WindowsLookAndFeel + /** + * The Constant handyEmptyBorder. + */ + private static final Border handyEmptyBorder = new EmptyBorder(0, 0, 0, 0); + + /** + * The Constant IMAGE_HEIGHT. + */ + private static final int IMAGE_HEIGHT = 16; + + /** + * The Constant IMAGE_WIDTH. + */ + private static final int IMAGE_WIDTH = 16; + + /** + * PropertyChangeListener added to the JRootPane. + */ + private PropertyChangeListener propertyChangeListener; + + /** + * JMenuBar, typically renders the system menu items. + */ + private JMenuBar menuBar; + /** + * Action used to close the Window. + */ + private Action closeAction; + + /** + * Action used to iconify the Frame. + */ + private Action iconifyAction; + + /** + * Action to restore the Frame size. + */ + private Action restoreAction; + + /** + * Action to restore the Frame size. + */ + private Action maximizeAction; + + /** + * 设置action(功能暂未实现!). + */ + private Action setupAction; + + /** + * Button used to maximize or restore the Frame. + */ + private JButton toggleButton; + + /** + * Button used to maximize or restore the Frame. + */ + private JButton iconifyButton; + + /** + * Button used to maximize or restore the Frame. + */ + private JButton closeButton; + + /** + * Icon used for toggleButton when window is normal size. + */ + private Icon maximizeIcon; + private Icon maximizeIcon_rover; + private Icon maximizeIcon_pressed; + + /** + * Icon used for toggleButton when window is maximized. + */ + private Icon minimizeIcon; + private Icon minimizeIcon_rover; + private Icon minimizeIcon_pressed; + + /** + * 设置按钮(功能暂未实现!). + */ + private JButton setupButton; + + /** + * Listens for changes in the state of the Window listener to update the + * state of the widgets. + */ + private WindowListener windowListener; + + /** + * Window we're currently in. + */ + private Window window; + + /** + * JRootPane rendering for. + */ + private JRootPane rootPane; + + /** + * Room remaining in title for bumps. + */ + private int buttonsWidth; + + /** + * Buffered Frame.state property. As state isn't bound, this is kept to + * determine when to avoid updating widgets. + */ + private int state; + + /** + * MetalRootPaneUI that created us. + */ + private BERootPaneUI rootPaneUI; + + // Colors + /** + * The inactive background. + */ + private Color inactiveBackground = UIManager.getColor("inactiveCaption"); + + /** + * The inactive foreground. + */ + private Color inactiveForeground = UIManager.getColor("inactiveCaptionText"); + + /** + * The inactive shadow. + */ + private Color inactiveShadow = UIManager.getColor("inactiveCaptionBorder"); + + /** + * The active background. + */ + private Color activeBackground = null; + + /** + * The active foreground. + */ + private Color activeForeground = null; + + /** + * The active shadow. + */ + private Color activeShadow = null; + + /** + * Instantiates a new bE title pane. + * + * @param root the root + * @param ui the ui + */ + public BETitlePane(JRootPane root, BERootPaneUI ui) { + this.rootPane = root; + rootPaneUI = ui; + + state = -1; + + installSubcomponents(); + determineColors(); + installDefaults(); + + setLayout(createLayout()); + } + + /** + * Uninstalls the necessary state. + */ + private void uninstall() { + uninstallListeners(); + window = null; + removeAll(); + } + + /** + * Installs the necessary listeners. + */ + private void installListeners() { + if (window != null) { + windowListener = createWindowListener(); + window.addWindowListener(windowListener); + propertyChangeListener = createWindowPropertyChangeListener(); + window.addPropertyChangeListener(propertyChangeListener); + } + } + + /** + * Uninstalls the necessary listeners. + */ + private void uninstallListeners() { + if (window != null) { + window.removeWindowListener(windowListener); + window.removePropertyChangeListener(propertyChangeListener); + } + } + + /** + * Returns the WindowListener to add to the + * Window. + * + * @return the window listener + */ + private WindowListener createWindowListener() { + return new WindowHandler(); + } + + /** + * Returns the PropertyChangeListener to install on the + * Window. + * + * @return the property change listener + */ + private PropertyChangeListener createWindowPropertyChangeListener() { + return new PropertyChangeHandler(); + } + + /** + * Returns the JRootPane this was created for. + * + * @return the root pane + */ + @Override + public JRootPane getRootPane() { + return rootPane; + } + + /** + * Returns the decoration style of the JRootPane. + * + * @return the window decoration style + */ + private int getWindowDecorationStyle() { + return getRootPane().getWindowDecorationStyle(); + } + + @Override + public void addNotify() { + try { + super.addNotify(); + } catch (Exception e) { + } + uninstallListeners(); + + window = SwingUtilities.getWindowAncestor(this); + if (window != null) { + if (window instanceof Frame) { + setState(((Frame) window).getExtendedState()); + + //* 说明请见:BeautyEyeLNFHelper.setMaximizedBoundForFrame + if (BeautyEyeLNFHelper.setMaximizedBoundForFrame) + //* 此处设置窗口的最大边界是为了解决窗口最大化时覆盖 + //* 操作系统的task bar 的问题,它是sun一直没有解决的问题 + //* ,目前没有其它好方法,只能如此解决了 + setFrameMaxBound((Frame) window); + } else + setState(0); + setActive(window.isActive()); + installListeners(); + } + } + + /** + * 设置窗口的最大边界. + *

+ * 本方法由Jack Jiang 于2012-09-20添加的。 + * + * @param f the new frame max bound + * @see + * org.jb2011.lnf.beautyeye.BeautyEyeLNFHelper#setMaximizedBoundForFrame + * @since 3.2 + */ + private void setFrameMaxBound(Frame f) { + GraphicsConfiguration gc = f.getGraphicsConfiguration(); + Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets(gc); + Rectangle screenBounds = gc.getBounds(); + int x = Math.max(0, screenInsets.left); + int y = Math.max(0, screenInsets.top); + int w = screenBounds.width - (screenInsets.left + screenInsets.right); + int h = screenBounds.height - (screenInsets.top + screenInsets.bottom); + // Keep taskbar visible + f.setMaximizedBounds(new Rectangle(x, y, w, h)); + } + + @Override + public void removeNotify() { + super.removeNotify(); + + uninstallListeners(); + window = null; + } + + /** + * Adds any sub-Components contained in the MetalTitlePane. + */ + private void installSubcomponents() { + int decorationStyle = getWindowDecorationStyle(); + + if (decorationStyle == JRootPane.FRAME || decorationStyle == JRootPane.PLAIN_DIALOG) { + createActions(); + menuBar = createMenuBar(); + add(menuBar); + createButtons(); + + add(closeButton); + + //~* RootPane.setupButtonVisible是jb2011自定义的属性哦,目的是控制这个当前用于演示的设置按钮的可见性 + Object isSetupButtonVisibleObj = UIManager.get("RootPane.setupButtonVisible"); + //如果开发者没有设置此属性则默认认为是true(即显示该按钮) + boolean isSetupButtonVisible = (isSetupButtonVisibleObj == null ? true : (Boolean) isSetupButtonVisibleObj); + if (isSetupButtonVisible) + //加入设置按钮 + add(setupButton); + + if (decorationStyle != JRootPane.PLAIN_DIALOG)//! + { + add(iconifyButton); + add(toggleButton); + menuBar.setEnabled(false); + } + } else if ( // decorationStyle == JRootPane.PLAIN_DIALOG + // || + decorationStyle == JRootPane.INFORMATION_DIALOG + || decorationStyle == JRootPane.ERROR_DIALOG + || decorationStyle == JRootPane.COLOR_CHOOSER_DIALOG + || decorationStyle == JRootPane.FILE_CHOOSER_DIALOG + || decorationStyle == JRootPane.QUESTION_DIALOG + || decorationStyle == JRootPane.WARNING_DIALOG) { + createActions(); + createButtons(); + add(closeButton); + } + } + + /** + * Determines the Colors to draw with. + */ + private void determineColors() { + switch (getWindowDecorationStyle()) { + case JRootPane.FRAME: + activeBackground = UIManager.getColor("activeCaption"); + activeForeground = UIManager.getColor("activeCaptionText"); + activeShadow = UIManager.getColor("activeCaptionBorder"); + break; + case JRootPane.ERROR_DIALOG: + activeBackground = UIManager + .getColor("OptionPane.errorDialog.titlePane.background"); + activeForeground = UIManager + .getColor("OptionPane.errorDialog.titlePane.foreground"); + activeShadow = UIManager + .getColor("OptionPane.errorDialog.titlePane.shadow"); + break; + case JRootPane.QUESTION_DIALOG: + case JRootPane.COLOR_CHOOSER_DIALOG: + case JRootPane.FILE_CHOOSER_DIALOG: + activeBackground = UIManager + .getColor("OptionPane.questionDialog.titlePane.background"); + activeForeground = UIManager + .getColor("OptionPane.questionDialog.titlePane.foreground"); + activeShadow = UIManager + .getColor("OptionPane.questionDialog.titlePane.shadow"); + break; + case JRootPane.WARNING_DIALOG: + activeBackground = UIManager + .getColor("OptionPane.warningDialog.titlePane.background"); + activeForeground = UIManager + .getColor("OptionPane.warningDialog.titlePane.foreground"); + activeShadow = UIManager + .getColor("OptionPane.warningDialog.titlePane.shadow"); + break; + case JRootPane.PLAIN_DIALOG: + case JRootPane.INFORMATION_DIALOG: + default: + activeBackground = UIManager.getColor("activeCaption"); + activeForeground = UIManager.getColor("activeCaptionText"); + activeShadow = UIManager.getColor("activeCaptionBorder"); + break; + } + } + + /** + * Installs the fonts and necessary properties on the MetalTitlePane. + */ + private void installDefaults() { + setFont(UIManager.getFont("InternalFrame.titleFont", getLocale())); + } + + /** + * Uninstalls any previously installed UI values. + */ + private void uninstallDefaults() { + } + + /** + * Returns the JMenuBar displaying the appropriate system menu + * items. + * + * @return the j menu bar + */ + protected JMenuBar createMenuBar() { + menuBar = new SystemMenuBar(); + menuBar.setOpaque(false); + menuBar.setFocusable(false); + menuBar.setBorderPainted(true); + menuBar.add(createMenu()); + return menuBar; + } + + /** + * Closes the Window. + */ + private void close() { + Window w = getWindow(); + + if (w != null) + w.dispatchEvent(new WindowEvent(w, + WindowEvent.WINDOW_CLOSING)); + } + + /** + * Iconifies the Frame. + */ + private void iconify() { + Frame frame = getFrame(); + if (frame != null) + frame.setExtendedState(state | Frame.ICONIFIED); + } + + /** + * Maximizes the Frame. + */ + private void maximize() { + Frame frame = getFrame(); + if (frame != null) + frame.setExtendedState(state | Frame.MAXIMIZED_BOTH); + } + + /** + * Restores the Frame size. + */ + private void restore() { + Frame frame = getFrame(); + + if (frame == null) + return; + + if ((state & Frame.ICONIFIED) != 0) + frame.setExtendedState(state & ~Frame.ICONIFIED); + else + frame.setExtendedState(state & ~Frame.MAXIMIZED_BOTH); + } + + /** + * Create the Actions that get associated with the buttons and + * menu items. + */ + private void createActions() { + closeAction = new CloseAction(); + if (getWindowDecorationStyle() == JRootPane.FRAME) { + iconifyAction = new IconifyAction(); + restoreAction = new RestoreAction(); + maximizeAction = new MaximizeAction(); + + setupAction = new AbstractAction(UIManager.getString("BETitlePane.setupButtonText", getLocale())) { + @Override + public void actionPerformed(ActionEvent e) { + JOptionPane.showMessageDialog(rootPane, "This button just used for demo." + + "In the future,you can customize it.\n" + + "Now, you can set UIManager.put(\"RootPane.setupButtonVisible\", false) to hide it(detault is true).\n" + + "BeautyEye L&F developed by Jack Jiang, you can mail with jb2011@163.com."); + } + }; + } + } + + /** + * Returns the JMenu displaying the appropriate menu items for + * manipulating the Frame. + * + * @return the j menu + */ + private JMenu createMenu() { + JMenu menu = new JMenu(""); + menu.setOpaque(false);//本行一定要,否则将导致窗口图标区会绘制Menu的背景!这是Java Metal主题的Bug! -- jack,2009-09-11 + if (getWindowDecorationStyle() == JRootPane.FRAME + || getWindowDecorationStyle() == JRootPane.PLAIN_DIALOG//现在也给dialog加上菜单项(但只有关闭项) + ) + addMenuItems(menu); + return menu; + } + + /** + * Adds the necessary JMenuItems to the passed in menu. + * + * @param menu the menu + */ + private void addMenuItems(JMenu menu) { + Locale locale = getRootPane().getLocale(); + menu.setToolTipText(//"窗口相关操作."); + UIManager.getString("BETitlePane.titleMenuToolTipText", getLocale())); + + JMenuItem mi; + int mnemonic; + if (getWindowDecorationStyle() == JRootPane.FRAME)//! 只有frame才有这些菜单项 + { + mi = menu.add(restoreAction); + mnemonic = BEUtils.getInt("MetalTitlePane.restoreMnemonic", -1); + if (mnemonic != -1) + mi.setMnemonic(mnemonic); + + mi = menu.add(iconifyAction); + mnemonic = BEUtils.getInt("MetalTitlePane.iconifyMnemonic", -1); + if (mnemonic != -1) + mi.setMnemonic(mnemonic); + + if (Toolkit.getDefaultToolkit().isFrameStateSupported( + Frame.MAXIMIZED_BOTH)) { + mi = menu.add(maximizeAction); + mnemonic = BEUtils.getInt("MetalTitlePane.maximizeMnemonic", + -1); + if (mnemonic != -1) + mi.setMnemonic(mnemonic); + } + + menu.add(new JSeparator()); + } + + mi = menu.add(closeAction); + mnemonic = BEUtils.getInt("MetalTitlePane.closeMnemonic", -1); + if (mnemonic != -1) + mi.setMnemonic(mnemonic); + } + + /** + * Returns a JButton appropriate for placement on the + * TitlePane. + * + * @return the j button + */ + private JButton createTitleButton() { + JButton button = new JButton(); + + button.setFocusPainted(false); + button.setFocusable(false); + button.setOpaque(true); + return button; + } + + /** + * Creates the Buttons that will be placed on the TitlePane. + */ + private void createButtons() { + + setupButton = createTitleButton(); + setupButton.setAction(setupAction); +// setupButton.setText("设置 "); +// setupButton.putClientProperty("paintActive", Boolean.TRUE); + setupButton.setBorder(handyEmptyBorder); +// setupButton.getAccessibleContext().setAccessibleName("Close"); + setupButton.setIcon(UIManager.getIcon("Frame.setupIcon")); + setButtonIcon(setupButton, setupButton.getIcon());// @since 3.5:同时设置rover和pressed时的icon效果 + setupButton.setContentAreaFilled(false); +// setupButton.setToolTipText("设置"); + + closeButton = createTitleButton(); + closeButton.setAction(closeAction); + closeButton.setText(null); + closeButton.putClientProperty("paintActive", Boolean.TRUE); + closeButton.setBorder(handyEmptyBorder); + closeButton.getAccessibleContext().setAccessibleName("Close"); + closeButton.setIcon(UIManager.getIcon("Frame.closeIcon")); +// setButtonIcon(closeButton, closeButton.getIcon());// @since 3.5:同时设置rover和pressed时的icon效果 + closeButton.setRolloverIcon(UIManager.getIcon("Frame.closeIcon_rover")); + closeButton.setPressedIcon(UIManager.getIcon("Frame.closeIcon_pressed")); + closeButton.setContentAreaFilled(false); + closeButton.setToolTipText(//"关闭"); + UIManager.getString("BETitlePane.closeButtonToolTipext", getLocale())); + + if (getWindowDecorationStyle() == JRootPane.FRAME) { + maximizeIcon = UIManager.getIcon("Frame.maximizeIcon"); + maximizeIcon_rover = UIManager.getIcon("Frame.maximizeIcon_rover"); + maximizeIcon_pressed = UIManager.getIcon("Frame.maximizeIcon_pressed"); + + minimizeIcon = UIManager.getIcon("Frame.minimizeIcon"); + minimizeIcon_rover = UIManager.getIcon("Frame.minimizeIcon_rover"); + minimizeIcon_pressed = UIManager.getIcon("Frame.minimizeIcon_pressed"); + + iconifyButton = createTitleButton(); + iconifyButton.setAction(iconifyAction); + iconifyButton.setText(null); + iconifyButton.putClientProperty("paintActive", Boolean.TRUE); + iconifyButton.setBorder(handyEmptyBorder); + iconifyButton.getAccessibleContext().setAccessibleName("Iconify"); + iconifyButton.setIcon(UIManager.getIcon("Frame.iconifyIcon")); +// setButtonIcon(iconifyButton, iconifyButton.getIcon());// @since 3.5:同时设置rover和pressed时的icon效果 + iconifyButton.setRolloverIcon(UIManager.getIcon("Frame.iconifyIcon_rover")); + iconifyButton.setPressedIcon(UIManager.getIcon("Frame.iconifyIcon_pressed")); + iconifyButton.setContentAreaFilled(false); + iconifyButton.setToolTipText(//"最小化"); + UIManager.getString("BETitlePane.iconifyButtonToolTipText", getLocale())); + + toggleButton = createTitleButton(); + toggleButton.setAction(restoreAction); + toggleButton.putClientProperty("paintActive", Boolean.TRUE); + toggleButton.setBorder(handyEmptyBorder); + toggleButton.getAccessibleContext().setAccessibleName("Maximize"); + toggleButton.setIcon(maximizeIcon); +// setButtonIcon(toggleButton, toggleButton.getIcon());// @since 3.5:同时设置rover和pressed时的icon效果 + toggleButton.setRolloverIcon(maximizeIcon_rover); + toggleButton.setPressedIcon(maximizeIcon_pressed); + toggleButton.setContentAreaFilled(false); + toggleButton.setToolTipText(//"最大化"); + UIManager.getString("BETitlePane.toggleButtonToolTipText", getLocale())); + } + } + + /** + * 为按钮设置图标,并据原图icon自动调用方法 + * {@link #filterWithRescaleOp(ImageIcon, float, float, float, float)} + * 使用滤镜分别生成RolloverIcon、PressedIcon并设置之. + * + * @param btn + * @param ico + * @since 3.5 + * @deprecated since 3.6 + */ + public static void setButtonIcon(AbstractButton btn, Icon ico) { + //* 图片设定 + btn.setIcon(ico); + if (ico != null && ico instanceof ImageIcon) { + //rover时图片颜色变成红色 + btn.setRolloverIcon(BEUtils.filterWithRescaleOp((ImageIcon) ico, 2f, 1f, 1f, 1f)); + //press时图片颜色变成淡红色 + btn.setPressedIcon(BEUtils.filterWithRescaleOp((ImageIcon) ico, 2f, 1f, 1f, 0.5f)); + } + } + + /** + * Returns the LayoutManager that should be installed on the + * MetalTitlePane. + * + * @return the layout manager + */ + private LayoutManager createLayout() { + return new TitlePaneLayout(); + } + + /** + * Updates state dependant upon the Window's active state. + * + * @param isActive the new active + */ + private void setActive(boolean isActive) { + Boolean activeB = isActive ? Boolean.TRUE : Boolean.FALSE; + closeButton.putClientProperty("paintActive", activeB); + if (getWindowDecorationStyle() == JRootPane.FRAME) { + iconifyButton.putClientProperty("paintActive", activeB); + toggleButton.putClientProperty("paintActive", activeB); + } + // Repaint the whole thing as the Borders that are used have + // different colors for active vs inactive + getRootPane().repaint(); + } + + /** + * Sets the state of the Window. + * + * @param state the new state + */ + private void setState(int state) { + setState(state, false); + } + + /** + * Sets the state of the window. If updateRegardless is true + * and the state has not changed, this will update anyway. + * + * @param state the state + * @param updateRegardless the update regardless + */ + private void setState(int state, boolean updateRegardless) { + Window w = getWindow(); + + if (w != null && getWindowDecorationStyle() == JRootPane.FRAME) { + if (this.state == state && !updateRegardless) + return; + Frame frame = getFrame(); + + if (frame != null) { + JRootPane p = getRootPane(); + + if (((state & Frame.MAXIMIZED_BOTH) != 0) + && (p.getBorder() == null || (p + .getBorder() instanceof UIResource)) + && frame.isShowing()) + p.setBorder(null); + else if ((state & Frame.MAXIMIZED_BOTH) == 0) + // This is a croak, if state becomes bound, this can + // be nuked. + rootPaneUI.installBorder(p); + if (frame.isResizable()) { + if ((state & Frame.MAXIMIZED_BOTH) != 0) { + updateToggleButton(restoreAction, minimizeIcon, minimizeIcon_rover, minimizeIcon_pressed); + maximizeAction.setEnabled(false); + restoreAction.setEnabled(true); + } else { + updateToggleButton(maximizeAction, maximizeIcon, maximizeIcon_rover, maximizeIcon_pressed); + maximizeAction.setEnabled(true); + restoreAction.setEnabled(false); + } + if (toggleButton.getParent() == null + || iconifyButton.getParent() == null) { + add(toggleButton); + add(iconifyButton); + revalidate(); + repaint(); + } + toggleButton.setText(null); + } else { + maximizeAction.setEnabled(false); + restoreAction.setEnabled(false); + if (toggleButton.getParent() != null) { + remove(toggleButton); + revalidate(); + repaint(); + } + } + } else { + // Not contained in a Frame + maximizeAction.setEnabled(false); + restoreAction.setEnabled(false); + iconifyAction.setEnabled(false); + remove(toggleButton); + remove(iconifyButton); + revalidate(); + repaint(); + } + closeAction.setEnabled(true); + this.state = state; + } + } + + /** + * Updates the toggle button to contain the Icon icon, and + * Action action. + * + * @param action the action + * @param icon the icon + */ + private void updateToggleButton(Action action, Icon icon, + Icon iconRover, Icon iconPressed) { + toggleButton.setAction(action); + toggleButton.setIcon(icon); +// setButtonIcon(toggleButton, toggleButton.getIcon());// @since 3.5:同时设置rover和pressed时的icon效果:同时设置rover和pressed时的icon效果 + toggleButton.setRolloverIcon(iconRover); + toggleButton.setPressedIcon(iconPressed); + toggleButton.setText(null); + } + + /** + * Returns the Frame rendering in. This will return null if the + * JRootPane is not contained in a Frame. + * + * @return the frame + */ + private Frame getFrame() { + Window w = getWindow(); + + if (w instanceof Frame) + return (Frame) w; + return null; + } + + /** + * Returns the Window the JRootPane is contained + * in. This will return null if there is no parent ancestor of the + * JRootPane. + * + * @return the window + */ + private Window getWindow() { + return window; + } + + /** + * Returns the String to display as the title. + * + * @return the title + */ + private String getTitle() { + Window w = getWindow(); + + if (w instanceof Frame) + return ((Frame) w).getTitle(); + else if (w instanceof Dialog) + return ((Dialog) w).getTitle(); + return null; + } + + /** + * Renders the TitlePane. + * + * @param g the g + */ + @Override + public void paintComponent(Graphics g) { + // As state isn't bound, we need a convenience place to check + // if it has changed. Changing the state typically changes the + if (getFrame() != null) + setState(getFrame().getExtendedState()); + JRootPane p = getRootPane(); + Window w = getWindow(); + boolean leftToRight = (w == null) ? p + .getComponentOrientation().isLeftToRight() : w + .getComponentOrientation().isLeftToRight(); + boolean isSelected = (w == null) ? true : w.isActive(); + int width = getWidth(); + int height = getHeight(); + + Color background; + Color foreground; + Color darkShadow; + + if (isSelected) { + background = activeBackground; + foreground = activeForeground; + darkShadow = activeShadow; + } else { + background = inactiveBackground; + foreground = inactiveForeground; + darkShadow = inactiveShadow; +// bumps = inactiveBumps; + } + //----------------------------------------------- 标题背景 + paintTitlePane(g, 0, 0, width, height, isSelected); + + //----------------------------------------------- 标题文字和图片 + int xOffset = leftToRight ? 5 : width - 5; + + if (getWindowDecorationStyle() == JRootPane.FRAME || getWindowDecorationStyle() == JRootPane.PLAIN_DIALOG) + xOffset += leftToRight ? IMAGE_WIDTH + 5 : -IMAGE_WIDTH - 5; + + String theTitle = getTitle(); + if (theTitle != null) { + FontMetrics fm = MySwingUtilities2.getFontMetrics(p, g); + int yOffset = ((height - fm.getHeight()) / 2) + fm.getAscent(); + + Rectangle rect = new Rectangle(0, 0, 0, 0); + if (iconifyButton != null && iconifyButton.getParent() != null) + rect = iconifyButton.getBounds(); + int titleW; + + if (leftToRight) { + if (rect.x == 0) + rect.x = w.getWidth() - w.getInsets().right - 2; + titleW = rect.x - xOffset - 4; + theTitle = MySwingUtilities2.clipStringIfNecessary(p, fm, + theTitle, titleW); + } else { + titleW = xOffset - rect.x - rect.width - 4; + theTitle = MySwingUtilities2.clipStringIfNecessary(p, fm, + theTitle, titleW); + xOffset -= MySwingUtilities2.stringWidth(p, fm, theTitle); + } + + int titleLength = MySwingUtilities2.stringWidth(p, fm, theTitle); + g.setColor(foreground); + MySwingUtilities2.drawString(p, g, theTitle, xOffset, yOffset); + xOffset += leftToRight ? titleLength + 5 : -5; + } + } + + /** + * Paint title pane. + * + * @param g the g + * @param x the x + * @param y the y + * @param width the width + * @param height the height + * @param actived the actived + */ + public static void paintTitlePane(Graphics g, int x, int y, int width, + int height, boolean actived) { + Graphics2D g2 = (Graphics2D) g; + + //是用图形进行填充的 + Paint oldpaint = g2.getPaint(); + g2.setPaint(BEUtils.createTexturePaint( + __UI__.ICON.get("title", actived ? "active" : "inactive").getImage())); + g2.fillRect(x, y, width, height); + g2.setPaint(oldpaint); + } + + /** + * Actions used to close the Window. + */ + private class CloseAction extends AbstractAction { + + /** + * Instantiates a new close action. + */ + public CloseAction() { + super(UIManager.getString("BETitlePane.closeButtonToolTipext", getLocale())); + } + + @Override + public void actionPerformed(ActionEvent e) { + close(); + } + } + + /** + * Actions used to iconfiy the Frame. + */ + private class IconifyAction extends AbstractAction { + + /** + * Instantiates a new iconify action. + */ + public IconifyAction() { + super(UIManager.getString("BETitlePane.iconifyButtonText", getLocale())); + } + + @Override + public void actionPerformed(ActionEvent e) { + iconify(); + } + } + + /** + * Actions used to restore the Frame. + */ + private class RestoreAction extends AbstractAction { + + /** + * Instantiates a new restore action. + */ + public RestoreAction() { + super(UIManager.getString("BETitlePane.restoreButtonText", getLocale())); + } + + @Override + public void actionPerformed(ActionEvent e) { + restore(); + } + } + + /** + * Actions used to restore the Frame. + */ + private class MaximizeAction extends AbstractAction { + + public MaximizeAction() { + super(UIManager.getString("BETitlePane.maximizeButtonText", getLocale())); + } + + @Override + public void actionPerformed(ActionEvent e) { + maximize(); + } + } + + /** + * Class responsible for drawing the system menu. Looks up the image to draw + * from the Frame associated with the JRootPane. + */ + private class SystemMenuBar extends JMenuBar { + + @Override + public void paint(Graphics g) { + //## Bug FIX: Issue BELNF-10, 之前是用的MetalLNF中的代码( + //## 它设计为不显示Dialog及其子类的图标),此处就是要加上Dialog及其子类 + //## 窗口图标的处理 +// Frame frame = getFrame();// getFrame()方法意味只处理Frame及其子类图标(Dialog的就错误地跳过了) + Window frame = getWindow(); + + if (isOpaque()) { + g.setColor(getBackground()); + g.fillRect(0, 0, getWidth(), getHeight()); + } + + //## Bug FIX: Issue BELNF-10 +// Image image = (frame != null) ? frame.getIconImage() : null; + Image image = null; + if (frame != null) + // 如果是Frame及其子类则调用getIconImage取回最合适 + // 图标(跨平台时可能尺寸不一样,此方法返回最合适的) + if (frame instanceof Frame) + image = ((Frame) frame).getIconImage(); + // 其它情况那就Dialog及其子类了,因它们没有getIconImage方法, + // 那就只取frame.getIconImages()里的第1个图标吧(如蛤存在多个图标的话), + // 它样处理虽跨平台考虑不足但总比MetalTitlePane里不显示Dialog图标强 + else if (frame.getIconImages() != null && frame.getIconImages().size() > 0) + image = frame.getIconImages().get(0); + + if (image != null) + g.drawImage(image, 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT, null); + else { + Icon icon = UIManager.getIcon("Frame.icon");//"InternalFrame.icon"); + if (icon != null) + icon.paintIcon(this, g, 0, 0); + } + } + + @Override + public Dimension getMinimumSize() { + return getPreferredSize(); + } + + @Override + public Dimension getPreferredSize() { + Dimension size = super.getPreferredSize(); + + return new Dimension(Math.max(IMAGE_WIDTH, size.width), Math.max( + size.height, IMAGE_HEIGHT)); + } + } + + private class TitlePaneLayout implements LayoutManager { + + @Override + public void addLayoutComponent(String name, Component c) { + } + + @Override + public void removeLayoutComponent(Component c) { + } + + @Override + public Dimension preferredLayoutSize(Container c) { + int height = computeHeight(); + return new Dimension(height, height); + } + + @Override + public Dimension minimumLayoutSize(Container c) { + return preferredLayoutSize(c); + } + + /** + * Compute height. + * + * @return the int + */ + private int computeHeight() { + FontMetrics fm = rootPane.getFontMetrics(getFont()); + int fontHeight = fm.getHeight(); + fontHeight += 7; + int iconHeight = 0; + if (getWindowDecorationStyle() == JRootPane.FRAME) // ||getWindowDecorationStyle() == JRootPane.PLAIN_DIALOG)// + + iconHeight = IMAGE_HEIGHT; + + int finalHeight = Math.max(fontHeight, iconHeight); + return finalHeight + 2;//* 改变此处的返回结果将直接改变窗口标题的高度哦 + } + + @Override + public void layoutContainer(Container c) { + boolean leftToRight = (window == null) ? getRootPane() + .getComponentOrientation().isLeftToRight() : window + .getComponentOrientation().isLeftToRight(); + + int w = getWidth(); + int x; + int y = 3; + int spacing; + int buttonHeight; + int buttonWidth; + + if (closeButton != null && closeButton.getIcon() != null) { + buttonHeight = closeButton.getIcon().getIconHeight(); + buttonWidth = closeButton.getIcon().getIconWidth(); + } else { + buttonHeight = IMAGE_HEIGHT; + buttonWidth = IMAGE_WIDTH; + } + + // assumes all buttons have the same dimensions + // these dimensions include the borders + x = leftToRight ? w : 0; + + spacing = 5; + x = leftToRight ? spacing : w - buttonWidth - spacing; + if (menuBar != null) + //* js 2010-03-30 + //* 原MetalTitledPane的Bug:当存在关闭按钮时,窗口图标的大小是已关闭按钮的大小来决定的,这样不合理 + menuBar.setBounds(x, + y + 2//+2偏移量由Jack Jiang于2012-09-24日加上,目的是使得图标与文本保持在同一中心位置 + // TODO 目前BueautyEye和MetalLookAndFeel的标题图标位置算法都有优化的余地:y轴坐标自动按title高度居中会 + // 适用更多场景,现在的算法如果title高度变的很大,则这些位置都是固定。不过按MetalLNF的思路,这些高度 + // 是与整体美感一样,不应被随意改动的,也可以说不需要优化,目前就这么的吧,没有关系。 + , + IMAGE_HEIGHT, IMAGE_WIDTH);//buttonWidth, buttonHeight); + + x = leftToRight ? w : 0; + spacing = 4; + x += leftToRight ? -spacing - buttonWidth : spacing; + if (closeButton != null) + closeButton.setBounds(x, y, buttonWidth, buttonHeight); + + if (!leftToRight) + x += buttonWidth; + + if (getWindowDecorationStyle() == JRootPane.FRAME) { + if (Toolkit.getDefaultToolkit().isFrameStateSupported( + Frame.MAXIMIZED_BOTH)) + if (toggleButton.getParent() != null) { + spacing = 2;//10!!! + x += leftToRight ? -spacing - buttonWidth : spacing; + toggleButton.setBounds(x, y, buttonWidth, buttonHeight); + if (!leftToRight) + x += buttonWidth; + } + + if (iconifyButton != null && iconifyButton.getParent() != null) { + spacing = 2; + x += leftToRight ? -spacing - buttonWidth : spacing; + iconifyButton.setBounds(x, y, buttonWidth, buttonHeight); + if (!leftToRight) + x += buttonWidth; + } + + //“设置”按钮 + if (setupButton != null) { + spacing = 2; + int stringWidth = BEUtils.getStrPixWidth(setupButton.getFont(), setupButton.getText()); + x += leftToRight ? -spacing - buttonWidth - stringWidth : spacing; + setupButton.setBounds(x, y, buttonWidth + stringWidth, buttonHeight); + if (!leftToRight) + x += buttonWidth; + } + } + buttonsWidth = leftToRight ? w - x : x; + } + } + + /** + * PropertyChangeListener installed on the Window. Updates the necessary + * state as the state of the Window changes. + */ + private class PropertyChangeHandler implements PropertyChangeListener { + + @Override + public void propertyChange(PropertyChangeEvent pce) { + String name = pce.getPropertyName(); + + if (null != name) // Frame.state isn't currently bound. + switch (name) { + case "resizable": + case "state": + Frame frame = getFrame(); + if (frame != null) + setState(frame.getExtendedState(), true); + if ("resizable".equals(name)) + getRootPane().repaint(); + break; + case "title": + repaint(); + break; + case "componentOrientation": + case "iconImage": + revalidate(); + repaint(); + break; + default: + break; + } + } + } + + /** + * WindowListener installed on the Window, updates the state as necessary. + */ + private class WindowHandler extends WindowAdapter { + + @Override + public void windowActivated(WindowEvent ev) { + setActive(true); + } + + @Override + public void windowDeactivated(WindowEvent ev) { + setActive(false); + } + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/titlepane/__UI__.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/titlepane/__UI__.java new file mode 100644 index 000000000..3802c25b8 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/titlepane/__UI__.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * __UI__.java at 2015-2-1 20:25:39, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.titlepane; + +import javax.swing.UIManager; +import javax.swing.plaf.BorderUIResource; + +import org.jackhuang.hmcl.laf.BeautyEyeLNFHelper; +import org.jackhuang.hmcl.laf.BEUtils; +import org.jackhuang.hmcl.laf.utils.IconFactory; +import org.jackhuang.hmcl.laf.utils.UI; + +public class __UI__ extends UI { + + protected static final IconFactory ICON = new IconFactory("frame"); + + public static void uiImpl() { + //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 窗体ui的各项属性设定 + //*~ 本属性是Jack Jiang自已设定的,Java的Metal主题默认对非Frame对象的窗口图标取的是InternalFrame.icon,这是不对的 + UIManager.put("Frame.icon", ICON.get("icon")); + + UIManager.put("Frame.iconifyIcon", ICON.get("iconify")); + UIManager.put("Frame.iconifyIcon_rover", ICON.get("iconify_over")); + UIManager.put("Frame.iconifyIcon_pressed", ICON.get("iconify_pressed")); + + UIManager.put("Frame.minimizeIcon", ICON.get("min")); + UIManager.put("Frame.minimizeIcon_rover", ICON.get("min_over")); + UIManager.put("Frame.minimizeIcon_pressed", ICON.get("min_pressed")); + + UIManager.put("Frame.maximizeIcon", ICON.get("max")); + UIManager.put("Frame.maximizeIcon_rover", ICON.get("max_over")); + UIManager.put("Frame.maximizeIcon_pressed", ICON.get("max_pressed")); + + UIManager.put("Frame.closeIcon", ICON.get("close")); + UIManager.put("Frame.closeIcon_rover", ICON.get("close_over")); + UIManager.put("Frame.closeIcon_pressed", ICON.get("close_pressed")); + + //设定用于演示之用的“设置”按钮图标 + UIManager.put("Frame.setupIcon", ICON.get("setup")); + +// put("activeCaption", Windows2LookAndFeel.activeCaption); + put("activeCaptionText", BeautyEyeLNFHelper.activeCaptionTextColor); +// put("activeCaptionBorder", Windows2LookAndFeel.activeCaptionBorder); +// put("inactiveCaption", GraphicHandler.getColor(activeCaption, 64, 42, 22)); + put("inactiveCaptionText", BEUtils.getColor(BeautyEyeLNFHelper.activeCaptionTextColor, -49, -27, -7)); +// put("inactiveCaptionBorder", GraphicHandler.getColor(activeCaptionBorder, 64, 42, 22)); + + //此属性即是BeautyEye LNF的窗口标题栏实现 + put("RootPaneUI", BERootPaneUI.class); + + // These bindings are only enabled when there is a default + // button set on the rootpane. + UIManager.put("RootPane.defaultButtonWindowKeyBindings", new Object[] { + "ENTER", "press", + "released ENTER", "release", + "ctrl ENTER", "press", + "ctrl released ENTER", "release" + }); + + //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> OptionPane的各项ui属性设定 + Object dialogBorder = new BorderUIResource(BeautyEyeLNFHelper.getFrameBorder());//BorderFactory.createLineBorder(new Color(181,181,181))); + UIManager.put("RootPane.frameBorder", dialogBorder); + UIManager.put("RootPane.plainDialogBorder", dialogBorder); + UIManager.put("RootPane.informationDialogBorder", dialogBorder); + UIManager.put("RootPane.errorDialogBorder", dialogBorder); + UIManager.put("RootPane.colorChooserDialogBorder", dialogBorder); + UIManager.put("RootPane.fileChooserDialogBorder", dialogBorder); + UIManager.put("RootPane.questionDialogBorder", dialogBorder); + UIManager.put("RootPane.warningDialogBorder", dialogBorder); + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/toolbar/BEToolBarSeparatorUI.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/toolbar/BEToolBarSeparatorUI.java new file mode 100644 index 000000000..f61e7216d --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/toolbar/BEToolBarSeparatorUI.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * BEToolBarSeparatorUI.java at 2015-2-1 20:25:36, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.toolbar; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Stroke; + +import javax.swing.JComponent; +import javax.swing.JSeparator; +import javax.swing.JToolBar; +import javax.swing.SwingConstants; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicToolBarSeparatorUI; + +/** + * JToolBar的分隔条UI实现类. + * + * @author Jack Jiang(jb2011@163.com) + * @see com.sun.java.swing.plaf.windows.WindowsToolBarSeparatorUI + */ +public class BEToolBarSeparatorUI extends BasicToolBarSeparatorUI { + + public static ComponentUI createUI(JComponent c) { + return new BEToolBarSeparatorUI(); + } + + @Override + public Dimension getPreferredSize(JComponent c) { + Dimension size = ((JToolBar.Separator) c).getSeparatorSize(); + + if (size != null) + size = size.getSize(); + else { + size = new Dimension(6, 6); + + if (((JSeparator) c).getOrientation() == SwingConstants.VERTICAL) + size.height = 0; + else + size.width = 0; + } + return size; + } + + @Override + public Dimension getMaximumSize(JComponent c) { + Dimension pref = getPreferredSize(c); + if (((JSeparator) c).getOrientation() == SwingConstants.VERTICAL) + return new Dimension(pref.width, Short.MAX_VALUE); + else + return new Dimension(Short.MAX_VALUE, pref.height); + } + + @Override + public void paint(Graphics g, JComponent c) { + boolean vertical = ((JSeparator) c).getOrientation() == SwingConstants.VERTICAL; + Dimension size = c.getSize(); + + //虚线样式 + Stroke oldStroke = ((Graphics2D) g).getStroke(); + Stroke sroke = new BasicStroke(1, BasicStroke.CAP_BUTT, + BasicStroke.JOIN_BEVEL, 0, new float[] { 2, 2 }, 0);//实线,空白 + ((Graphics2D) g).setStroke(sroke);// + + Color temp = g.getColor(); + UIDefaults table = UIManager.getLookAndFeelDefaults(); + Color shadow = table.getColor("ToolBar.shadow"); + Color highlight = table.getColor("ToolBar.highlight"); + + // TODO BUG_001:不知何故,垂直分隔条并不能像水平分隔条一样,拥有默认设置的new Dimension(6, 6) + // 而只有new Dimension(1, ...),而当它floating时却能正常表现(只能绘出hilight而不能绘出shadow) + //,有待深入研究,垂直的分隔条则不会有此种情况 + if (vertical) { + int x = (size.width / 2) - 1; + + //* 当BUG_001存在时,暂时使用以下代码解决:把本该显示hilight的 + //* 线条用shadow颜色绘制,最大可能保证ui的正常展现 +// g.setColor(shadow); +// g.drawLine(x, 2, x, size.height - 2); + g.setColor(shadow);//highlight); + g.drawLine(x + 1, 2, x + 1, size.height - 2); + + //* 当BUG_001不存在时,应该使用以下代码 +// g.setColor(shadow); +// g.drawLine(x, 2, x, size.height - 2); +// g.setColor(highlight); +// g.drawLine(x + 1, 2, x + 1, size.height - 2); + } else { + int y = (size.height / 2) - 1; + g.setColor(shadow); + g.drawLine(2, y, size.width - 2, y); + + g.setColor(highlight); + g.drawLine(2, y + 1, size.width - 2, y + 1); + } + g.setColor(temp); + + ((Graphics2D) g).setStroke(oldStroke); + } + +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/toolbar/BEToolBarUI.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/toolbar/BEToolBarUI.java new file mode 100644 index 000000000..6b806bf25 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/toolbar/BEToolBarUI.java @@ -0,0 +1,362 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * BEToolBarUI.java at 2015-2-1 20:25:41, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.toolbar; + +import java.awt.BasicStroke; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Insets; +import java.awt.LayoutManager; +import java.awt.Stroke; +import java.awt.event.ContainerEvent; +import java.awt.event.ContainerListener; + +import javax.swing.AbstractButton; +import javax.swing.JComponent; +import javax.swing.JToolBar; +import javax.swing.SwingConstants; +import javax.swing.UIManager; +import javax.swing.border.AbstractBorder; +import javax.swing.border.Border; +import javax.swing.border.EmptyBorder; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.UIResource; +import javax.swing.plaf.basic.BasicToolBarUI; + +import org.jackhuang.hmcl.laf.button.BEButtonUI; +import org.jackhuang.hmcl.laf.utils.Icon9Factory; +import org.jb2011.ninepatch4j.NinePatch; + +/** + * JToolBar的UI实现类。 + * + *

+ * Since v3.4:
+ * 可以使用"ToolBar.isPaintPlainBackground"来控制BEToolBarUI还是 + * 默认的渐变NinePatch图实现背景的填充(效果好,但是背景比较强烈,不适于组件密集的场景). + * 全局控制可以通过UIManager.put("ToolBar.isPaintPlainBackground", + * Boolean.FALSE)(UIManager中默认是false) + * 或者通过JToolBar.putClientProperty("ToolBar.isPaintPlainBackground", + * Boolean.FALSE) 独立控制,ClientProperty中的设置拥有最高优先级。 + * + * 特别说明:JToolBar比较特殊,加入到JToolBar中的组件,其UI(主要是Border)将由ToolBarUI额 + * 外控制而不受自身UI控制,比如放入到JToolBar中的JToggleButton,它的border就是受ToolBarUI + * 控制,这些JToggleButton将无论如何修改ToolgleButtonUI.border也不会起效。 + * + * @author Jack Jiang(jb2011@163.com) + * @see com.sun.java.swing.plaf.windows.WindowsToolBarUI + */ +public class BEToolBarUI extends BasicToolBarUI + implements org.jackhuang.hmcl.laf.BeautyEyeLNFHelper.__UseParentPaintSurported { + + private static final Icon9Factory ICON_9 = new Icon9Factory("toolbar"); + + public static ComponentUI createUI(JComponent c) { + return new BEToolBarUI(); + } + + @Override + protected void installDefaults() { + setRolloverBorders(true); + super.installDefaults(); + } + + //* 本方法由Jack Jiang于2012-09-07日加入 + /** + * 是否使用父类的绘制实现方法,true表示是. + *

+ * 因为在BE LNF中,工具条背景是使用N9图,没法通过设置背景色和前景 + * 色来控制工具条的颜色,本方法的目的就是当用户设置了工具条的Background 时告之本实现类不使用BE + * LNF中默认的N9图填充绘制而改用父类中的方法(父类中的方法 就可以支持颜色的设置罗,只是丑点,但总归是能适应用户的需求场景要求,其实用户完全可以 + * 通过JToolBar.setUI(new MetalToolBar())等方式来自定义UI哦). + * + * @return true, if is use parent paint + */ + @Override + public boolean isUseParentPaint() { + return toolBar != null + && (!(toolBar.getBackground() instanceof UIResource)); + } + + @Override + protected Border createRolloverBorder() { + return new EmptyBorder(3, 3, 3, 3); + } + + @Override + protected Border createNonRolloverBorder() { + return new EmptyBorder(3, 3, 3, 3); + } + + @Override + public void paint(Graphics g, JComponent c) { + //~* @since 3.4, add by Jack Jiang 2012-11-05 + //~* 【BeautyEye外观的特有定制属性】:true表示BEToolBarUI里,将使用其它典型外观 + //~* 一样的默认纯色填充背景(颜色由ToolBar.background属性指定), 否则将使用BeautyEye + //~* 默认的渐变NinePatch图实现背景的填充。另外,还可以使用 + //~* JToolBar.putClientProperty("ToolBar.isPaintPlainBackground", Boolean.TRUE);来进行 + //~* 独立控制背景的填充方法,ClientProperty相比UIManager中的本方法拥有最高优先级 + boolean isPaintPlainBackground = false; + String isPaintPlainBackgroundKey = "ToolBar.isPaintPlainBackground";//~* 【BeautyEye外观的特有定制属性】@since 3.4 + //首先看看有没有独立在ClientProperty中设置"ToolBar.isPaintPlainBackground"属性(ClientProperty中设置拥有最高优先级) + Object isPaintPlainBackgroundObj = c.getClientProperty(isPaintPlainBackgroundKey); + //如果ClientProperty中没有设置,则尝试取UIManager中的该属性默认值 + if (isPaintPlainBackgroundObj == null) + isPaintPlainBackgroundObj = UIManager.getBoolean(isPaintPlainBackgroundKey); + if (isPaintPlainBackgroundObj != null) + isPaintPlainBackground = (Boolean) isPaintPlainBackgroundObj; + + //* 如果用户作了自定义颜色设置则使用父类方法来实现绘制,否则BE LNF中没法支持这些设置哦 + if (isPaintPlainBackground || isUseParentPaint()) + super.paint(g, c); + else { + //* 根据工具条所放在父类的位置不同来决定它的背景该使用哪个图片(图片的差别在于方向不同,主要是边缘阴影的方向) + NinePatch np = ICON_9.get("north"); + //int orientation = toolBar.getOrientation(); + Container parent = toolBar.getParent(); + if (parent != null) { + LayoutManager lm = parent.getLayout(); + if (lm instanceof BorderLayout) { + Object cons = ((BorderLayout) lm).getConstraints(toolBar); + if (cons != null) + if (cons.equals(BorderLayout.NORTH)) + np = ICON_9.get("north"); + else if (cons.equals(BorderLayout.SOUTH)) + np = ICON_9.get("south"); + else if (cons.equals(BorderLayout.WEST)) + np = ICON_9.get("west"); + else if (cons.equals(BorderLayout.EAST)) + np = ICON_9.get("east"); + } + } + np.draw((Graphics2D) g, 0, 0, c.getWidth(), c.getHeight()); + } + } + + /** + * Gets the rollover border. + * + * @param b the b + * @return the rollover border {@inheritDoc} + */ + @Override + protected Border getRolloverBorder(AbstractButton b) { + return new BEButtonUI.BEEmptyBorder(new Insets(3, 3, 3, 3)); + } + + //* 由jb2011修改,只加了一行代码哦 + /** + * 重写父类方法实现自已的容器监听器. 自定义的目的就是为了把加入到其中的组件设置为透明,因为BE LNF的工具栏是有背景,否则 + * 因有子组件的背景存在而使得整体很难看. + * + * @return the container listener + */ + @Override + protected ContainerListener createToolBarContListener() { + return new ToolBarContListenerJb2011(); + } + //* 由jb2011修改自父类的Handler里的ContainerListener监听代码 + + /** + * The Class ToolBarContListenerJb2011. + */ + protected class ToolBarContListenerJb2011 implements ContainerListener { + // + // ContainerListener + // + + @Override + public void componentAdded(ContainerEvent evt) { + Component c = evt.getChild(); + + if (toolBarFocusListener != null) + c.addFocusListener(toolBarFocusListener); + + if (isRolloverBorders()) + setBorderToRollover(c); + else + setBorderToNonRollover(c); + + //## Bug FIX:Issue 51(https://code.google.com/p/beautyeye/issues/detail?id=51) + //* 由Jack Jiang201210-12日注释掉:它样做将导致各种放入的组 + //* 件(如文本框)等都将透明,从而不绘制该 组件的背景,那就错误了哦 + //* 其实以下代码原本是为了解决放入到JToggleButton的白色背景问题,现在它 + //* 已经在BEToolgleButtonUI里解决了,此处就不需要了,也不应该要! +// //* 只有它一行是由jb2011加的 +// if(c instanceof JComponent) +// ((JComponent)c).setOpaque(false); + } + + @Override + public void componentRemoved(ContainerEvent evt) { + Component c = evt.getChild(); + + if (toolBarFocusListener != null) + c.removeFocusListener(toolBarFocusListener); + + // Revert the button border + setBorderToNormal(c); + } + } + + //* 本类由Jack Jiang实现,参考了com.sun.java.swing.plaf.windows.WindowsBorders.getToolBarBorder + /** + * 工具条边框,左边(或右、或上方)有拖动触点的绘制,方便 告之用户它是可以拖动的 A border for the ToolBar. If the + * ToolBar is floatable then the handle grip is drawn + *

+ * @since 1.4 + */ + public static class ToolBarBorder extends AbstractBorder implements UIResource, SwingConstants { + + /** + * The shadow. + */ + protected Color shadow; + /** + * The highlight. + */ + protected Color highlight; + protected Insets insets; + + /** + * Instantiates a new tool bar border. + * + * @param shadow the shadow + * @param highlight the highlight + */ + public ToolBarBorder(Color shadow, Color highlight, Insets insets) { + this.highlight = highlight; + this.shadow = shadow; + this.insets = insets; + } + + @Override + public void paintBorder(Component c, Graphics g, int x, int y, + int width, int height) { + g.translate(x, y); + + //需要绘制拖动触点 + if (((JToolBar) c).isFloatable()) { + boolean vertical = ((JToolBar) c).getOrientation() == VERTICAL; + + //虚线样式 + Stroke oldStroke = ((Graphics2D) g).getStroke(); + Stroke sroke = new BasicStroke(1, BasicStroke.CAP_BUTT, + BasicStroke.JOIN_BEVEL, 0, new float[] { 1, 1 }, 0);//实线,空白 + ((Graphics2D) g).setStroke(sroke); +// int gap_top = 5,gap_bottom = 4; //!!10,-1 + if (!vertical) { + int gap_top = 8, gap_bottom = 8; + if (c.getComponentOrientation().isLeftToRight()) { + int drawX = 3; + drawTouchH(g, drawX, gap_top - 1, drawX, height - gap_bottom - 1); + } else { + int drawX = 3 - 1; + drawTouchH(g, width - drawX, gap_top - 1, width - drawX, height - gap_bottom - 1); + } + } else // Vertical + { + int gap_left = 8, gap_right = 8; + int drawY = 3; + drawTouchV(g, gap_left - 1, drawY, width - gap_right - 1, drawY); + } + + ((Graphics2D) g).setStroke(oldStroke); + } + + g.translate(-x, -y); + } + + //水平工具条的触点绘制方法 + private void drawTouchH(Graphics g, int x1, int y1, int x2, int y2) { + //第1条竖虚线(深色) + g.setColor(shadow); + g.drawLine(x1, y1, x1, y2 - 1); + //第2条竖虚线(与第1条形成立体效果的浅色,Y坐标相对第1条下偏一个像素) + g.setColor(highlight); + g.drawLine(x1 + 1, y1 + 1, x1 + 1, y2); + + //第3条竖虚线 + g.setColor(shadow); + g.drawLine(x1 + 2, y1, x1 + 2, y2 - 1); + //第4条竖虚线(与第3条形成立体效果的浅色,Y坐标相对第3条下偏一个像素) + g.setColor(highlight); + g.drawLine(x1 + 3, y1 + 1, x1 + 3, y2); + } + //垂直工具条的触点绘制方法 + + private void drawTouchV(Graphics g, int x1, int y1, int x2, int y2) { + //第1条横虚线(深色) + g.setColor(shadow); + g.drawLine(x1, y1, x2 - 1, y2); + //第2条横虚线(与第1条形成立体效果的浅色,X坐标相对第1条右偏一个像素) + g.setColor(highlight); + g.drawLine(x1 + 1, y1 + 1, x2, y2 + 1); + + //第3条横虚线 + g.setColor(shadow); + g.drawLine(x1, y1 + 2, x2 - 1, y2 + 2); + //第4条横虚线(与第3条形成立体效果的浅色,X坐标相对第3条右偏一个像素) + g.setColor(highlight); + g.drawLine(x1 + 1, y1 + 3, x2, y2 + 3); + } + + @Override + public Insets getBorderInsets(Component c) { + //** 根据toolbar所放面板的方位不同而设置不一样的border(参照的目标是水平toolbar时的insets)! + //tollbar上下设置的空白多一点看起来大气一些(它也将决定toolbar的整体高度和宽度哦) + final Insets DEFAILT_IS = insets;//8,0,9,0);//6, 0, 11, 0); + Insets is = DEFAILT_IS; + if (c instanceof JToolBar) { + Container parent = c.getParent(); + if (parent != null) { + LayoutManager lm = parent.getLayout(); + if (lm instanceof BorderLayout) { + Object cons = ((BorderLayout) lm).getConstraints((JToolBar) c); + if (cons != null) + if (cons.equals(BorderLayout.NORTH)) + is = DEFAILT_IS; + else if (cons.equals(BorderLayout.SOUTH)) + is = new Insets(DEFAILT_IS.bottom, 0, DEFAILT_IS.top, 0); + else if (cons.equals(BorderLayout.WEST)) + is = new Insets(0, DEFAILT_IS.top, 0, DEFAILT_IS.bottom); + else if (cons.equals(BorderLayout.EAST)) + is = new Insets(0, DEFAILT_IS.bottom, 0, DEFAILT_IS.top); + } + } + } + + return getBorderInsets(c, is);//5, 0, 10, 0));//默认是 1,1,1,1 + } + + @Override + public Insets getBorderInsets(Component c, Insets insets) { +// insets.top = insets.left = insets.bottom = insets.right = 1; + if (((JToolBar) c).isFloatable()) { +// int gripInset = (XPStyle.getXP() != null) ? 12 : 9;//原windows外观中默认的 + int gripInset = 9; + if (((JToolBar) c).getOrientation() == HORIZONTAL) + if (c.getComponentOrientation().isLeftToRight()) + insets.left = gripInset; + else + insets.right = gripInset; + else + insets.top = gripInset; + } + return insets; + } + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/toolbar/__UI__.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/toolbar/__UI__.java new file mode 100644 index 000000000..8e0375cac --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/toolbar/__UI__.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * __UI__.java at 2015-2-1 20:25:39, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.toolbar; + +import java.awt.Color; +import java.awt.Insets; + +import javax.swing.UIManager; + +import org.jackhuang.hmcl.laf.BeautyEyeLNFHelper; +import org.jackhuang.hmcl.laf.utils.UI; + +public class __UI__ extends UI { + + public static void uiImpl() { + //~* @since 3.4, add by Jack Jiang 2012-11-05 + //~* 【BeautyEye外观的特有定制属性】:true表示BEToolBarUI里,将使用其它典型外观 + //~* 一样的默认纯色填充背景(颜色由ToolBar.background属性指定), 否则将使用BeautyEye + //~* 默认的渐变NinePatch图实现背景的填充。另外,还可以使用 + //~* JToolBar.putClientProperty("ToolBar.isPaintPlainBackground", Boolean.TRUE);来进行 + //~* 独立控制背景的填充方法,ClientProperty相比UIManager中的本方法拥有最高优先级 + put("ToolBar.isPaintPlainBackground", false); + //此属性目前用于ToolBar.border中表示触点的颜色 + putColor("ToolBar.shadow", 180, 183, 187); + //此属性目前用于ToolBar.border中表示触点的立体阴影效果颜色 + put("ToolBar.highlight", Color.white); + put("ToolBar.dockingBackground", BeautyEyeLNFHelper.commonBackgroundColor); + put("ToolBar.floatingBackground", BeautyEyeLNFHelper.commonBackgroundColor); + put("ToolBar.background", BeautyEyeLNFHelper.commonBackgroundColor); + put("ToolBar.foreground", BeautyEyeLNFHelper.commonForegroundColor); + //工具栏的border实现 + UIManager.put("ToolBar.border", + new BEToolBarUI.ToolBarBorder(UIManager.getColor("ToolBar.shadow"), + UIManager.getColor("ToolBar.highlight"), new Insets(6, 0, 11, 0))); +// BorderFactory.createEmptyBorder(5, 0, 8, 0)));//5, 5, 8, 5))); + //分隔条ui实现 + put("ToolBarSeparatorUI", BEToolBarSeparatorUI.class); + put("ToolBarUI", BEToolBarUI.class); + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/tree/BETreeUI.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/tree/BETreeUI.java new file mode 100644 index 000000000..e74bd7ee6 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/tree/BETreeUI.java @@ -0,0 +1,234 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * BETreeUI.java at 2015-2-1 20:25:36, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.tree; + +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicTreeUI; +import javax.swing.tree.DefaultTreeCellRenderer; +import javax.swing.tree.TreeCellRenderer; + +/** + * JTree的UI实现类. + * + * 目前,本类中暂未对UI方面代码进行修改,对Tree的UI修改主要是基于UIManager对应Tree + * 属性的配置,目前已经足够达到预期效果,如有必要可开放本类中的代码进行深入修改。 + * + * @author Jack Jiang(jb2011@163.com) + * @version 1.0 + * @see com.sun.java.swing.plaf.windows.WindowsTreeUI + */ +public class BETreeUI extends BasicTreeUI { + + public static ComponentUI createUI(JComponent c) { + return new BETreeUI(); + } + +// //copy from BasicTreeUI and modified by jb2011 +// // This method is slow -- revisit when Java2D is ready. +// // assumes x1 <= x2 +// /** +// * 绘制水平层次虚线. +// * Jack Jiang重写此方法的目的是加调整虚线的步进值. +// */ +// protected void drawDashedHorizontalLine(Graphics g, int y, int x1, int x2) +// { +// // Drawing only even coordinates helps join line segments so they +// // appear as one line. This can be defeated by translating the +// // Graphics by an odd amount. +//// x1 += (x1 % 2); +// x1 += (x1 % 6); +// +//// for (int x = x1; x <= x2; x+=2) +//// { +//// g.drawLine(x, y, x, y); +//// } +// for (int x = x1; x <= x2; x+=6) +// { +// g.drawLine(x, y, x, y); +// } +// } +// +// //copy from BasicTreeUI and modified by jb2011 +// // This method is slow -- revisit when Java2D is ready. +// // assumes y1 <= y2 +// /** +// * 绘制垂直层次虚线. +// * Jack Jiang重写此方法的目的是加调整虚线的步进值. +// */ +// protected void drawDashedVerticalLine(Graphics g, int x, int y1, int y2) +// { +// // Drawing only even coordinates helps join line segments so they +// // appear as one line. This can be defeated by translating the +// // Graphics by an odd amount. +//// y1 += (y1 % 2); +// y1 += (y1 % 6); +// +//// for (int y = y1; y <= y2; y+=2) { +//// g.drawLine(x, y, x, y); +//// } +// for (int y = y1; y <= y2; y+=6) { +// g.drawLine(x, y, x, y); +// } +// } +// static protected final int HALF_SIZE = 4; +// static protected final int SIZE = 9; + /** + * Returns the default cell renderer that is used to do the stamping of each + * node. + * + * @return the tree cell renderer + * @see + * com.sun.java.swing.plaf.windows.WindowsTreeUI#createDefaultCellRenderer() + */ + @Override + protected TreeCellRenderer createDefaultCellRenderer() { + return new WindowsTreeCellRenderer(); + } + +// /** +// * The minus sign button icon +// *

+// * Warning: +// * Serialized objects of this class will not be compatible with +// * future Swing releases. The current serialization support is appropriate +// * for short term storage or RMI between applications running the same +// * version of Swing. A future release of Swing will provide support for +// * long term persistence. +// */ +// public static class ExpandedIcon implements Icon, Serializable +// { +// +// static public Icon createExpandedIcon() +// { +// return new ExpandedIcon(); +// } +// +//// Skin getSkin(Component c) +//// { +//// XPStyle xp = XPStyle.getXP(); +//// return (xp != null) ? xp.getSkin(c, Part.TVP_GLYPH) : null; +//// } +// +// public void paintIcon(Component c, Graphics g, int x, int y) +// { +//// Skin skin = getSkin(c); +//// if (skin != null) { +//// skin.paintSkin(g, x, y, State.OPENED); +//// return; +//// } +// +// Color backgroundColor = c.getBackground(); +// +// if(backgroundColor != null) +// g.setColor(backgroundColor); +// else +// g.setColor(Color.white); +// +// g.fillRect(x, y, SIZE-1, SIZE-1); +// g.setColor(Color.gray); +// g.drawRect(x, y, SIZE-1, SIZE-1); +// g.setColor(Color.black); +// g.drawLine(x + 2, y + HALF_SIZE, x + (SIZE - 3), y + HALF_SIZE); +// } +// +// public int getIconWidth() { +//// Skin skin = getSkin(null); +// return //(skin != null) ? skin.getWidth() : +// SIZE; +// } +// +// public int getIconHeight() +// { +//// Skin skin = getSkin(null); +// return //(skin != null) ? skin.getHeight() : +// SIZE; +// } +// } +// /** +// * The plus sign button icon +// *

+// * Warning: +// * Serialized objects of this class will not be compatible with +// * future Swing releases. The current serialization support is appropriate +// * for short term storage or RMI between applications running the same +// * version of Swing. A future release of Swing will provide support for +// * long term persistence. +// */ +// public static class CollapsedIcon extends ExpandedIcon { +// static public Icon createCollapsedIcon() { +// return new CollapsedIcon(); +// } +// +// public void paintIcon(Component c, Graphics g, int x, int y) +// { +//// Skin skin = getSkin(c); +//// if (skin != null) +//// { +//// skin.paintSkin(g, x, y, State.CLOSED); +//// } +//// else +// { +// super.paintIcon(c, g, x, y); +// g.drawLine(x + HALF_SIZE, y + 2, x + HALF_SIZE, y + (SIZE - 3)); +// } +// } +// } + /** + * The Class WindowsTreeCellRenderer. + * + * @see + * com.sun.java.swing.plaf.windows.WindowsTreeUI.WindowsTreeCellRenderer + */ + public class WindowsTreeCellRenderer extends DefaultTreeCellRenderer {//目前没有定制内容,本来想让render绘制成圆角,但尝试后发现DefaultTreeCellRenderer类里 + //的代码设计欠佳,很难继承,要改的代码非常多,干脆作罢 +// /** +// * Configures the renderer based on the passed in components. +// * The value is set from messaging the tree with +// * convertValueToText, which ultimately invokes +// * toString on value. +// * The foreground color is set based on the selection and the icon +// * is set based on on leaf and expanded. +// */ +// public Component getTreeCellRendererComponent(JTree tree, Object value, +// boolean sel, +// boolean expanded, +// boolean leaf, int row, +// boolean hasFocus) { +// super.getTreeCellRendererComponent(tree, value, sel, +// expanded, leaf, row, +// hasFocus); +// // Windows displays the open icon when the tree item selected. +// if (!tree.isEnabled()) { +// setEnabled(false); +// if (leaf) { +// setDisabledIcon(getLeafIcon()); +// } else if (sel) { +// setDisabledIcon(getOpenIcon()); +// } else { +// setDisabledIcon(getClosedIcon()); +// } +// } +// else { +// setEnabled(true); +// if (leaf) { +// setIcon(getLeafIcon()); +// } else if (sel) { +// setIcon(getOpenIcon()); +// } else { +// setIcon(getClosedIcon()); +// } +// } +// return this; +// } + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/tree/__UI__.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/tree/__UI__.java new file mode 100644 index 000000000..e80b28201 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/tree/__UI__.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * __UI__.java at 2015-2-1 20:25:36, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.tree; + +import java.awt.Color; + +import javax.swing.UIManager; + +import org.jackhuang.hmcl.laf.BeautyEyeLNFHelper; +import org.jackhuang.hmcl.laf.utils.IconFactory; +import org.jackhuang.hmcl.laf.utils.UI; + +public class __UI__ extends UI { + + private static final IconFactory ICON = new IconFactory("tree"); + + public static void uiImpl() { + put("Tree.background", Color.white); + put("Tree.textBackground", Color.white); +// put("Tree.drawsFocusBorderAroundIcon", false); + put("Tree.selectionForeground", BeautyEyeLNFHelper.commonSelectionForegroundColor); + put("Tree.selectionBackground", BeautyEyeLNFHelper.commonSelectionBackgroundColor); + put("Tree.foreground", BeautyEyeLNFHelper.commonForegroundColor); + put("Tree.selectionBorderColor", BeautyEyeLNFHelper.commonFocusedBorderColor);//windows父类中默认是0,0,0 + + UIManager.put("Tree.openIcon", ICON.get("open")); + UIManager.put("Tree.closedIcon", ICON.get("closed")); + UIManager.put("Tree.leafIcon", ICON.get("leaf")); + UIManager.put("Tree.expandedIcon", ICON.get("expanded")); + UIManager.put("Tree.collapsedIcon", ICON.get("collapsed")); + + //不绘制层次线 + put("Tree.paintLines", false);//default is true + //行高 + put("Tree.rowHeight", 18);//default is 16 + //未选中时单元前景色(备选MacOSX黑 (35,35,35)) + putColor("Tree.textForeground", 70, 70, 70); + //处于编辑状态时的文本框边框,因BE LNF中文本框无边框(事实上它是用N9图实现的背景 + //边框视觉效果),所以此处要去掉,但加多点空白,与背景配合起来好看点 + putBorder("Tree.editorBorder", 1, 5, 1, 5);//Windows LNF中默认是LineBorderUIResource + + put("TreeUI", BETreeUI.class); + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/ui/ComboBoxUI.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/ui/ComboBoxUI.java deleted file mode 100755 index 628cc0d73..000000000 --- a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/ui/ComboBoxUI.java +++ /dev/null @@ -1,292 +0,0 @@ -package org.jackhuang.hmcl.laf.ui; - -import static org.jackhuang.hmcl.laf.HelloMinecraftLookAndFeel.loadImage; - -import javax.swing.plaf.ComponentUI; -import javax.swing.plaf.basic.BasicComboBoxUI; -import javax.swing.JComponent; -import javax.swing.JButton; -import javax.swing.JComboBox; -import javax.swing.ListCellRenderer; -import java.awt.Graphics; -import java.awt.Rectangle; -import java.awt.Insets; -import java.awt.LayoutManager; -import java.awt.Component; -import java.awt.Dimension; -import java.awt.Container; -import java.awt.image.BufferedImage; -import java.awt.event.MouseListener; -import java.awt.event.MouseEvent; -import javax.swing.plaf.basic.BasicComboPopup; -import javax.swing.plaf.basic.ComboPopup; - -/** - * NimbusComboBoxUI - * - * @author Created by Jasper Potts (Feb 1, 2007) - * @version 1.0 - */ -public class ComboBoxUI extends BasicComboBoxUI implements MouseListener { - - private static final BufferedImage COMBO_NORMAL = loadImage("combo_normal.png"); - private static final BufferedImage COMBO_OVER = loadImage("combo_over.png"); - private static final BufferedImage COMBO_PRESSED = loadImage("combo_pressed.png"); - private static final BufferedImage COMBO_DISABLED = loadImage("combo_disabled.png"); - private static final Dimension BTN_SIZE = new Dimension(17, 20); - private final Dimension btnSize = new Dimension(BTN_SIZE); - - /** - * Creates a new UI deligate for the given component. It is a standard - * method that all UI deligates must have. - * - * @param c The component that the UI is for - * - * @return a new instance of NimbusComboBoxUI - */ - public static ComponentUI createUI(JComponent c) { - return new ComboBoxUI(); - } - - @Override - public void installUI(JComponent c) { - super.installUI(c); - c.setOpaque(false); - } - - @Override - protected void installListeners() { - super.installListeners(); - comboBox.addMouseListener(this); - } - - @Override - protected void uninstallListeners() { - super.uninstallListeners(); - comboBox.removeMouseListener(this); - } - - /** - * The minumum size is the size of the display area plus insets plus the - * button. - * - * @return the size yeah. - */ - @Override - public Dimension getMinimumSize(JComponent c) { - if (!isMinimumSizeDirty) - return new Dimension(cachedMinimumSize); - Dimension size = getDisplaySize(); - Insets insets = getInsets(); - btnSize.height = size.height = Math.max(size.height, BTN_SIZE.height); - btnSize.width = (int) ((double) (BTN_SIZE.width / (double) BTN_SIZE.height) * btnSize.height); - size.height += insets.top + insets.bottom; - size.width += insets.left + insets.right + btnSize.width; - - cachedMinimumSize.setSize(size.width, size.height); - isMinimumSizeDirty = false; - - return new Dimension(size); - } - - @Override - protected ComboPopup createPopup() { - BasicComboPopup p = new BasicComboPopup(comboBox); - //p.setPopupSize(100, comboBox.getPreferredSize().height); - return p; - } - - @Override - protected JButton createArrowButton() { - JButton button = new JButton() { - @Override - protected void paintComponent(Graphics g) { - if (comboBox.isEditable()) { - BufferedImage img = COMBO_NORMAL; - if (mouseDown) - img = COMBO_PRESSED; - else if (!comboBox.isEnabled()) - img = COMBO_NORMAL; - else if (mouseInside) - img = COMBO_OVER; - g.drawImage(img, - 0, 0, getWidth(), getHeight(), - 0, 0, img.getWidth(), img.getHeight(), comboBox); - } - } - }; - button.addMouseListener(this); - button.setMinimumSize(BTN_SIZE); - button.setPreferredSize(BTN_SIZE); - button.setMargin(new Insets(0, 0, 0, 0)); - return button; - } - - @Override - public void paint(Graphics g, JComponent c) { - hasFocus = comboBox.hasFocus(); - ListCellRenderer renderer = comboBox.getRenderer(); - Rectangle r = new Rectangle(0, 0, comboBox.getWidth(), comboBox.getHeight()); - paintCurrentValueBackground(g, r, hasFocus); - if (!comboBox.isEditable()) { - if (renderer instanceof JComponent) { - ((JComponent) renderer).setOpaque(false); - ((JComponent) renderer).setForeground(comboBox.getForeground()); - } - paintCurrentValue(g, rectangleForCurrentValue(), false); - if (renderer instanceof JComponent) { - ((JComponent) renderer).setOpaque(true); - } - } - } - - @Override - public void paintCurrentValueBackground(Graphics g, Rectangle bounds, boolean hasFocus) { - if (!comboBox.isEditable()) { - BufferedImage img = COMBO_NORMAL; - if (!comboBox.isEnabled()) - img = COMBO_DISABLED; - else if (mouseDown) - img = COMBO_PRESSED; - else if (mouseInside) - img = COMBO_OVER; - g.drawImage(img, - bounds.x, bounds.y, bounds.x + 4, bounds.y + bounds.height, - 0, 0, 1, 26, comboBox); - g.drawImage(img, - bounds.x + 1, bounds.y, bounds.x + bounds.width - 25, bounds.y + bounds.height, - 1, 0, 3, 26, comboBox); - g.drawImage(img, - bounds.x + bounds.width - 25, bounds.y, bounds.x + bounds.width, bounds.y + bounds.height, - 4, 0, 29, 26, comboBox); - } else { - /*g.setColor(Color.WHITE); - g.fillRect(bounds.x, bounds.y, bounds.width - btnSize.width, bounds.height - 1); - int x = bounds.x, y = bounds.y, w = bounds.width - btnSize.width, h = bounds.height - 1; - Insets insets = getInsets(); - g.setColor(new Color(141, 142, 143)); - g.drawLine(x, y, x + insets.left, y); - g.setColor(new Color(203, 203, 204)); - g.drawLine(x + 1, y + 1, x + insets.left, y + 1); - g.setColor(new Color(152, 152, 153)); - g.drawLine(x, y + 1, x, y + 1); - g.setColor(new Color(242, 242, 242)); - g.drawLine(x + 1, y + 2, x + insets.left, y + 2); - g.setColor(new Color(176, 176, 177)); - g.drawLine(x, y + 2, x, y + 2); - g.setColor(new Color(192, 192, 193)); - g.drawLine(x, y + h, x + insets.left, y + h); - g.setColor(new Color(184, 184, 185)); - g.drawLine(x, y + 3, x, y + h);*/ - } - } - - @Override - protected LayoutManager createLayoutManager() { - return new ComboLayout(); - } - - @Override - protected Insets getInsets() { - return new Insets(0, 5, 0, 0); - } - // ================================================================================================================= - // MouseListener Methods - private boolean mouseInside = false; - private boolean mouseDown = false; - - @Override - public void mouseClicked(MouseEvent e) { - } - - @Override - public void mouseEntered(MouseEvent e) { - if (comboBox.isEditable()) { - if (e.getComponent() == arrowButton) - mouseInside = true; - } else { - mouseInside = true; - comboBox.repaint(); - } - } - - @Override - public void mouseExited(MouseEvent e) { - if (comboBox.isEditable()) { - if (e.getComponent() == arrowButton) - mouseInside = false; - } else { - mouseInside = false; - comboBox.repaint(); - } - } - - @Override - public void mousePressed(MouseEvent e) { - if (comboBox.isEditable()) { - if (e.getComponent() == arrowButton) - mouseDown = true; - } else { - mouseDown = true; - comboBox.repaint(); - } - } - - @Override - public void mouseReleased(MouseEvent e) { - if (comboBox.isEditable()) { - if (e.getComponent() == arrowButton) - mouseDown = false; - } else { - mouseDown = false; - comboBox.repaint(); - } - } - - // ================================================================================================================= - // LayoutManager - private class ComboLayout implements LayoutManager { - - @Override - public void addLayoutComponent(String name, Component comp) { - } - - @Override - public void removeLayoutComponent(Component comp) { - } - - @Override - public Dimension preferredLayoutSize(Container parent) { - return parent.getPreferredSize(); - } - - @Override - public Dimension minimumLayoutSize(Container parent) { - return parent.getMinimumSize(); - } - - @Override - public void layoutContainer(Container parent) { - if (parent instanceof JComboBox) { - JComboBox cb = (JComboBox) parent; - int width = cb.getWidth(); - - Insets insets = getInsets(); - Rectangle cvb; - - if (arrowButton != null) - if (cb.getComponentOrientation().isLeftToRight()) - arrowButton.setBounds(width - (insets.right + btnSize.width), - insets.top, - btnSize.width, btnSize.height); - else - arrowButton.setBounds(insets.left, insets.top, - btnSize.width, btnSize.height); - if (editor != null) { - cvb = rectangleForCurrentValue(); - editor.setBounds(cvb.x, cvb.y, cvb.width, cvb.height); - } - } - } - } -} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/ui/ListCellRender.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/ui/ListCellRender.java deleted file mode 100755 index e0aa02410..000000000 --- a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/ui/ListCellRender.java +++ /dev/null @@ -1,43 +0,0 @@ -/* -* $Id: NimbusGraphicsUtils.java,v 1.9 2005/12/05 15:00:55 kizune Exp $ -* -* Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, -* Santa Clara, California 95054, U.S.A. All rights reserved. -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -package org.jackhuang.hmcl.laf.ui; - -import javax.swing.DefaultListCellRenderer; -import javax.swing.JList; -import java.awt.Color; -import java.awt.Component; - -/** - * NimbusListCellRender - * - * @author Created by Jasper Potts (Jan 19, 2007) - * @version 1.0 - */ -public class ListCellRender extends DefaultListCellRenderer { - - @Override - public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, - boolean cellHasFocus) { - setOpaque(true); - setBackground(Color.magenta); - return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); - } -} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/ui/ScrollBarUI.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/ui/ScrollBarUI.java deleted file mode 100755 index 2813b964e..000000000 --- a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/ui/ScrollBarUI.java +++ /dev/null @@ -1,179 +0,0 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ -package org.jackhuang.hmcl.laf.ui; - -import static org.jackhuang.hmcl.laf.HelloMinecraftLookAndFeel.loadImage; - -import javax.swing.JButton; -import javax.swing.JComponent; -import javax.swing.JScrollBar; -import javax.swing.plaf.ComponentUI; -import javax.swing.plaf.metal.MetalScrollBarUI; -import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.Rectangle; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.awt.geom.AffineTransform; -import java.awt.image.BufferedImage; - -/** - * NimbusScrollBarUI - A custom scrollbar ui for nimbus. It is special as it handles all the painting for the buttons as - * well so that it can cope with the buttons being non-recangular. - * - * @author Created by Jasper Potts (Jan 17, 2007) - * @version 1.0 - */ -public class ScrollBarUI extends MetalScrollBarUI { - - private static final BufferedImage BACKGROUND_ENABLED = loadImage("scroll_enabled.png"); - private static final BufferedImage BACKGROUND_DISABLED = loadImage("scroll_disabled.png"); - private static final BufferedImage SCROLL_DEC_NORMAL = loadImage("scroll_dec_normal.png"); - private static final BufferedImage SCROLL_DEC_OVER = loadImage("scroll_dec_over.png"); - private static final BufferedImage SCROLL_DEC_PRESSED = loadImage("scroll_dec_pressed.png"); - private static final BufferedImage SCROLL_INC_NORMAL = loadImage("scroll_inc_normal.png"); - private static final BufferedImage SCROLL_INC_OVER = loadImage("scroll_inc_over.png"); - private static final BufferedImage SCROLL_INC_PRESSED = loadImage("scroll_inc_pressed.png"); - private static final BufferedImage SCROLL_THUMB_NORMAL = loadImage("scroll_thumb_normal.png"); - private static final BufferedImage SCROLL_THUMB_OVER = loadImage("scroll_thumb_over.png"); - private static final BufferedImage SCROLL_THUMB_PRESSED = loadImage("scroll_thumb_pressed.png"); - - private boolean incBtnMouseOver, incBtnMousePressed; - private boolean decBtnMouseOver, decBtnMousePressed; - private boolean thumbMousePressed; - - /** - * Creates a new UI deligate for the given component. It is a standard method that all UI deligates must have. - * - * @param c The component that the UI is for - * @return a new instance of NimbusScrollBarUI - */ - public static ComponentUI createUI(JComponent c) { - return new ScrollBarUI(); - } - - /** {@inheritDoc} */ - @Override public void installUI(JComponent c) { - super.installUI(c); - c.setOpaque(true); - c.addMouseListener(new MouseAdapter() { - @Override public void mousePressed(MouseEvent e) { - if (isThumbRollover()) { - thumbMousePressed = true; - scrollbar.repaint(); - } - } - - @Override public void mouseReleased(MouseEvent e) { - thumbMousePressed = false; - } - }); - } - - /** {@inheritDoc} */ - @Override protected Dimension getMinimumThumbSize() { - return new Dimension(15, 15); - } - - /** {@inheritDoc} */ - @Override protected JButton createDecreaseButton(int orientation) { - decreaseButton = new ScrollButton(orientation, scrollBarWidth, isFreeStanding); - decreaseButton.addMouseListener(new MouseAdapter() { - @Override public void mouseEntered(MouseEvent e) { - decBtnMouseOver = true; - } - - @Override public void mouseExited(MouseEvent e) { - decBtnMouseOver = false; - } - - @Override public void mousePressed(MouseEvent e) { - decBtnMousePressed = true; - } - - @Override public void mouseReleased(MouseEvent e) { - decBtnMousePressed = false; - } - }); - return decreaseButton; - } - - /** {@inheritDoc} */ - @Override protected JButton createIncreaseButton(int orientation) { - increaseButton = new ScrollButton(orientation, scrollBarWidth, isFreeStanding); - increaseButton.addMouseListener(new MouseAdapter() { - @Override public void mouseEntered(MouseEvent e) { - incBtnMouseOver = true; - } - - @Override public void mouseExited(MouseEvent e) { - incBtnMouseOver = false; - } - - @Override public void mousePressed(MouseEvent e) { - incBtnMousePressed = true; - } - - @Override public void mouseReleased(MouseEvent e) { - incBtnMousePressed = false; - } - }); - return increaseButton; - } - - /** {@inheritDoc} */ - @Override protected void paintTrack(Graphics g, JComponent c, Rectangle trackBounds) { - BufferedImage decImg = - decBtnMousePressed ? SCROLL_DEC_PRESSED : decBtnMouseOver ? SCROLL_DEC_OVER : SCROLL_DEC_NORMAL; - BufferedImage incImg = - incBtnMousePressed ? SCROLL_INC_PRESSED : incBtnMouseOver ? SCROLL_INC_OVER : SCROLL_INC_NORMAL; - Graphics2D g2 = (Graphics2D) g; - AffineTransform origTransform = g2.getTransform(); - int scrollWidth = scrollbar.getWidth(); - if (scrollbar.getOrientation() == JScrollBar.VERTICAL) { - scrollWidth = scrollbar.getHeight(); - g2.scale(1, -1); - g2.rotate(-Math.PI / 2, 0, 0); - } - // draw track & bottons - if (scrollbar.isEnabled()) { - g.drawImage(decImg, 0, 0, scrollbar); - //g.drawImage(BACKGROUND_ENABLED, 15, 0, scrollWidth - 15, 15, 0, 0, 1, 15, scrollbar); - g.drawImage(incImg, scrollWidth - 15, 0, scrollbar); - } else { - //g.drawImage(BACKGROUND_DISABLED, 0, 0, scrollWidth, 15, 0, 0, 1, 15, scrollbar); - } - // undo any transform - g2.setTransform(origTransform); - } - - /** {@inheritDoc} */ - @Override protected void paintThumb(Graphics g, JComponent c, Rectangle thumbBounds) { - if (scrollbar.isEnabled()) { - BufferedImage thumbImg = thumbMousePressed ? SCROLL_THUMB_PRESSED : - isThumbRollover() ? SCROLL_THUMB_OVER : SCROLL_THUMB_NORMAL; - Graphics2D g2 = (Graphics2D) g; - AffineTransform origTransform = g2.getTransform(); - Rectangle b = thumbBounds; - if (scrollbar.getOrientation() == JScrollBar.VERTICAL) { - b = new Rectangle(thumbBounds.y, thumbBounds.x, thumbBounds.height, thumbBounds.width); - g2.scale(1, -1); - g2.rotate(-Math.PI / 2, 0, 0); - } - g.drawImage(thumbImg, - b.x, b.y, b.x + 14, b.y + 15, - 0, 0, 14, 15, scrollbar); - g.drawImage(thumbImg, - b.x + 14, b.y, b.x + b.width - 14, b.y + 15, - 16, 0, 17, 15, scrollbar); - g.drawImage(thumbImg, - b.x + b.width - 14, b.y, b.x + b.width, b.y + 15, - 24, 0, 38, 15, scrollbar); - // undo any transform - g2.setTransform(origTransform); - } - } -} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/ui/ScrollButton.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/ui/ScrollButton.java deleted file mode 100755 index c517629f3..000000000 --- a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/ui/ScrollButton.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * $Id: NimbusGraphicsUtils.java,v 1.9 2005/12/05 15:00:55 kizune Exp $ - * - * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, - * Santa Clara, California 95054, U.S.A. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -package org.jackhuang.hmcl.laf.ui; - -import javax.swing.plaf.metal.MetalScrollButton; -import java.awt.Dimension; -import java.awt.Graphics; - -/** - * NimbusScrollButton - a fixed size 15x17 vertical 17x15 horizontal transparent - * button. - * - * @author Created by Jasper Potts (Jan 17, 2007) - * @version 1.0 - */ -public class ScrollButton extends MetalScrollButton { - - private final int btnWidth, btnHeight; - - ScrollButton(int direction, int width, boolean freeStanding) { - super(direction, width, freeStanding); - setOpaque(false); - if (direction == NORTH || direction == SOUTH) { - btnWidth = 15; - btnHeight = 17; - } else { - btnWidth = 17; - btnHeight = 15; - } - } - - @Override - public Dimension getMaximumSize() { - return this.getPreferredSize(); - } - - @Override - public Dimension getMinimumSize() { - return this.getPreferredSize(); - } - - @Override - public Dimension getPreferredSize() { - return new Dimension(btnWidth, btnHeight); - } - - @Override - public void repaint(long tm, int x, int y, int width, int height) { - if (getParent() != null) getParent().repaint(); - } - - /** - * Don't paint anything as all painting is done by the scrollbar - * - * @param g {@inheritDoc} - */ - @Override - public void paint(Graphics g) { - } -} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/utils/BEUtils.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/utils/BEUtils.java new file mode 100644 index 000000000..ace5a6250 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/utils/BEUtils.java @@ -0,0 +1,448 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * BEUtils.java at 2015-2-1 20:25:38, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.GradientPaint; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.Paint; +import java.awt.Polygon; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.Stroke; +import java.awt.TexturePaint; +import java.awt.Toolkit; +import java.awt.image.BufferedImage; +import java.awt.image.RescaleOp; + +import javax.swing.ImageIcon; +import javax.swing.JComponent; +import javax.swing.UIManager; + +/** + * The Class BEUtils. + */ +public class BEUtils { + + /** + * 使用RescaleOp对图片进行滤镜处理. + * + * @param iconBottom 原图 + * @param redFilter 红色通道滤镜值,1.0f表示保持不变 + * @param greenFilter 绿色通道滤镜值,1.0f表示保持不变 + * @param blueFilter 蓝色通道滤镜值,1.0f表示保持不变 + * @param alphaFilter alpha通道滤镜值,1.0f表示保持不变 + * @return 处理后的图片新对象 + * @author Jack Jiang, 2013-04-05 + * @since 3.5 + */ + public static ImageIcon filterWithRescaleOp(ImageIcon iconBottom, + float redFilter, float greenFilter, float blueFilter, float alphaFilter) { + try { + int w = iconBottom.getIconWidth(), h = iconBottom.getIconHeight(); + + //原图 + BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); + Graphics2D gg = (Graphics2D) bi.getGraphics(); + gg.drawImage(iconBottom.getImage(), 0, 0, w, h, null); + + //设置滤镜效果 + float[] scales = { redFilter, greenFilter, blueFilter, alphaFilter }; + float[] offsets = new float[4]; + RescaleOp rop = new RescaleOp(scales, offsets, null); + + //执行 + // gg.drawImage(bi, rop, 0, 0);//用这一行代码没效果,用下一行代码即可! + rop.filter(bi, bi); + return new ImageIcon(bi); + + } catch (Exception e) { + LogHelper.error("filterWithRescaleOp出错了," + e.getMessage() + ",iconBottom=" + iconBottom); + return new ImageIcon(); + } + } + + /** + *

+     * 给一个距形区域绘制4个角效果,形状和坐标如下:
+     * A(x,y)----B(x+β)                  C(x+(w-β),y)---D(x+w,y)
+     * |                                                |
+     * |                                                |
+     * |                                                |
+     * E(x,y+β)                                     L(x+w,y+β)
+     *
+     *
+     * F(x,y+(h-β))                               K(x+w,y+(h-β))
+     * |                                                |
+     * |                                                |
+     * |                                                |
+     * G(x,y+h)----H(x+β,y+h)         I(x+(w-β),y+h)----J(x+w,y+h)
+     * 
+ * + * @param g + * @param x 距形区的X坐标 + * @param y 距形区的Y坐标 + * @param w 距形区的宽 + * @param h 距形区的高 + * @param β 每个角的角长 + * @author Jack Jiang, 2013-04-05 + * @since 3.5 + */ + public static void draw4RecCorner(Graphics g, int x, int y, int w, int h, int β, Color c) { + Color oldColor = g.getColor(); + + g.setColor(c); + //top(A~B,C~D) + g.drawLine(x, y, x + β, y); + g.drawLine(x + (w - β), y, x + w, y); + + //left(A~E,F~G) + g.drawLine(x, y, x, y + β); + g.drawLine(x, y + (h - β), x, y + h); + + //bottom(G~H,I~J) + g.drawLine(x, y + h, x + β, y + h); + g.drawLine(x + (w - β), y + h, x + w, y + h); + + //right(J~K,L~D) + g.drawLine(x + w, y + h, x + w, y + (h - β)); + g.drawLine(x + w, y + β, x + w, y); + g.setColor(oldColor); + } + + /** + * 设置对象集的透明性,如果该组件是Container及其子类则递归设 + * 置该组件内的所有子组件的透明性,直到组件中的任何组件都被设置完毕. + * + * @param comps 对象集 + * @param opaque true表示要设置成不透明,否则表示要设置成透明 + */ + public static void componentsOpaque(java.awt.Component[] comps, + boolean opaque) { + if (comps == null) + return; + for (Component c : comps) + //递归设置它的子组件 + if (c instanceof Container) { + if (c instanceof JComponent) + ((JComponent) c).setOpaque(opaque); + componentsOpaque(((Container) c).getComponents(), opaque); + } else + if (c instanceof JComponent) + ((JComponent) c).setOpaque(opaque); + } + + /** + * 图形绘制反走样设置. + * + * @param g2 the g2 + * @param antiAliasing 是否反走样 + */ + public static void setAntiAliasing(Graphics2D g2, boolean antiAliasing) { + if (antiAliasing) + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + else + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_OFF); + } + + /** + * 填充3角形区域. + * + * @param g the g + * @param x1 3个点之一的x坐标 + * @param y1 3个点之一的y坐标 + * @param x2 3个点之一的x坐标 + * @param y2 3个点之一的y坐标 + * @param x3 3个点之一的x坐标 + * @param y3 3个点之一的y坐标 + * @param c the c + */ + public static void fillTriangle(Graphics g, + int x1, int y1, int x2, int y2, + int x3, int y3, Color c) { + int[] x = new int[3], y = new int[3]; + // A simple triangle. + x[0] = x1; + x[1] = x2; + x[2] = x3; + y[0] = y1; + y[1] = y2; + y[2] = y3; + int n = 3; + + Polygon p = new Polygon(x, y, n); // This polygon represents a triangle with the above + // vertices. + g.setColor(c); + g.fillPolygon(p); // Fills the triangle above. + } + + /** + * 绘制虚线框(本方法适用于对4个边的可选绘制情况下,可能会有4舍5入的小误差 + * ,除了要可选绘制4个边外,一般不推荐使用).
. + * + * @param g the g + * @param x the x + * @param y the y + * @param width the width + * @param height the height + */ + public static void drawDashedRect(Graphics g, int x, int y, int width, int height) { + drawDashedRect(g, x, y, width, height, 6, 6, 2, 2); + } + + /** + * 绘制虚线框(本方法适用于对4个边的可选绘制情况下,可能会有4舍5入的小误差 + * ,除了要可选绘制4个边外,一般不推荐使用). + * + * @param g the g + * @param x the x + * @param y the y + * @param width the width + * @param height the height + * @param arcWidth the arc width + * @param arcHeight the arc height + * @param separator_solid 虚线段实线长度 + * @param separator_space 虚线段空白长度 + * add by js,2009-08-30 + */ + public static void drawDashedRect(Graphics g, int x, int y, int width, int height, + int arcWidth, int arcHeight, int separator_solid, int separator_space) { +// drawDashedRect(g,x,y,width,height,step,true,true,true,true); + BEUtils.setAntiAliasing((Graphics2D) g, true); + + //虚线样式 + Stroke oldStroke = ((Graphics2D) g).getStroke(); + Stroke sroke = new BasicStroke(1, BasicStroke.CAP_BUTT, + BasicStroke.JOIN_BEVEL, 0, new float[] { separator_solid, separator_space }, 0);//实线,空白 + ((Graphics2D) g).setStroke(sroke); + + g.drawRoundRect(x, y, + width - 1, height - 1 //* 一个很诡异的问题:使用BasicStroke实现虚线绘制后,似乎绘制的距形 + //* 要比普通方法绘制实线距形往下偏移一个坐标,此处-1是为了修正这个问题,这难道是java的bug? + //* 难怪当初打印工具开发时也遇到了莫名其妙偏移一个像素的现象,具体有待进一步研究! + , + arcWidth, arcHeight); + + ((Graphics2D) g).setStroke(oldStroke); + BEUtils.setAntiAliasing((Graphics2D) g, false); + } + + /** + * Draw dashed rect. + * + * @param g the g + * @param x the x + * @param y the y + * @param width the width + * @param height the height + * @param step the step + * @param top the top + * @param left the left + * @param bottom the bottom + * @param right the right + */ + public static void drawDashedRect(Graphics g, int x, int y, int width, int height, int step//,boolean drawLeft$Right + , + boolean top, boolean left, boolean bottom, boolean right) { + int vx, vy; + + int drawStep = step == 0 ? 1 : 2 * step; + int drawLingStep = step == 0 ? 1 : step; + // draw upper and lower horizontal dashes + for (vx = x; vx < (x + width); vx += drawStep) { + if (top) + g.fillRect(vx, y, drawLingStep, 1); + if (bottom) + g.fillRect(vx, y + height - 1, drawLingStep, 1); + } + +// if(drawLeft$Right) + // draw left and right vertical dashes + for (vy = y; vy < (y + height); vy += drawStep) { + if (left) + g.fillRect(x, vy, 1, drawLingStep); + if (right) + g.fillRect(x + width - 1, vy, 1, drawLingStep); + } + } + + /** + * 对基准颜色的RGB通道进行加减后得到的新色调. + * + * @param basic 基准色调 + * @param r Red通道的增加值(可以是负) + * @param g Geen通道的增加值(可以是负) + * @param b Blue通道的增加值(可以是负) + * @return the color + */ + public static Color getColor(Color basic, int r, int g, int b) { + return new Color(getColorInt(basic.getRed() + r), + getColorInt(basic.getGreen() + g), + getColorInt(basic.getBlue() + b), + getColorInt(basic.getAlpha())); + } + + /** + * 对基准颜色的RGBA通道进行加减后得到的新色调. + * + * @param basic 基准色调 + * @param r Red通道的增加值(可以是负) + * @param g Geen通道的增加值(可以是负) + * @param b Blue通道的增加值(可以是负) + * @param a Alpha通道的增加值(可以是负) + * @return the color + */ + public static Color getColor(Color basic, int r, int g, int b, int a) { + return new Color(getColorInt(basic.getRed() + r), + getColorInt(basic.getGreen() + g), + getColorInt(basic.getBlue() + b), + getColorInt(basic.getAlpha() + a)); + } + + /** + * Gets the color int. + * + * @param rgb the rgb + * @return the color int + */ + public static int getColorInt(int rgb) { + return rgb < 0 ? 0 : (rgb > 255 ? 255 : rgb); + } + + /** + * 获得字符串的像素宽度. + * + * @param fm the fm + * @param str the str + * @return the str pix width + * @see FontMetrics#stringWidth(String) + */ + public static int getStrPixWidth(FontMetrics fm, String str) { + return fm.stringWidth(str + ""); + } + + /** + * 获得字符串的像素宽度. + * + * @param f the f + * @param str the str + * @return the str pix width + * @see #getStrPixWidth(FontMetrics, String) + */ + public static int getStrPixWidth(Font f, String str) { + return getStrPixWidth(Toolkit.getDefaultToolkit().getFontMetrics(f), str); + } + + /** + * 获得一个可按指定图片进行纹理填充方式的对象,利用此对象可实现图片填充背景效果。 + * + *
+     * 示例如下(在这个例子里将实现一个以指定图片填充效果为背景的面板对象):
+     * private FixedLayoutPane inputPane = new FixedLayoutPane() {
+     * //给它弄一个图片平铺的背景
+     * private TexturePaint paint = createTexturePaint(LaunchIconFactory.getInstance()
+     * .getImage("/login_background.png").getImage());
+     * //重写本方法实现图片平铺的背景
+     * protected void paintComponent(Graphics g) {
+     * super.paintComponent(g);
+     * Graphics2D g2d = (Graphics2D) g;
+     * g2d.setPaint(paint);
+     * g2d.fillRect(0, 0, this.getWidth(), this.getHeight());
+     * }
+     * };
+     * 
+ * + * @param image 填充图片,该图片一宽1像素高N像素(据这1像素宽进行重复填充即可达到目的) + * @return the texture paint + */ + public static TexturePaint createTexturePaint(Image image) { + int imageWidth = image.getWidth(null); + int imageHeight = image.getHeight(null); + BufferedImage bi = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_ARGB); + Graphics2D g2d = bi.createGraphics(); + g2d.drawImage(image, 0, 0, null); + g2d.dispose(); + return new TexturePaint(bi, new Rectangle(0, 0, imageWidth, imageHeight)); + } + + /** + * Gets the int. + * + * @param key the key + * @param defaultValue the default value + * @return the int + */ + public static int getInt(Object key, int defaultValue) { + Object value = UIManager.get(key); + + if (value instanceof Integer) + return (Integer) value; + if (value instanceof String) + try { + return Integer.parseInt((String) value); + } catch (NumberFormatException nfe) { + } + return defaultValue; + } + + /** + * 在指定的区域内填充出厚重质感立体效果. + * + * @param g2 the g2 + * @param baseColor the base color + * @param x the x + * @param y the y + * @param w the w + * @param h the h + * @param arc the arc + */ + public static void fillTextureRoundRec(Graphics2D g2, Color baseColor, + int x, int y, int w, int h, int arc) { + fillTextureRoundRec(g2, baseColor, + x, y, w, h, arc, 35); + } + + /** + * 在指定的区域内填充出厚重质感立体效果. + * + * @param g2 the g2 + * @param baseColor the base color + * @param x the x + * @param y the y + * @param w the w + * @param h the h + * @param arc the arc + * @param colorDelta 渐变起色(上)与渐变止色(下)的RGB色差(矢量),正表示变淡,负表示加深 + */ + public static void fillTextureRoundRec(Graphics2D g2, Color baseColor, + int x, int y, int w, int h, int arc, int colorDelta) { + setAntiAliasing(g2, true); + //矩形填充 + Paint oldpaint = g2.getPaint(); + GradientPaint gp = new GradientPaint(x, y, //渐变的起色比止色RGB浅35 + getColor(baseColor, colorDelta, colorDelta, colorDelta), + x, y + h, baseColor); + g2.setPaint(gp); + g2.fillRoundRect(x, y, w, h, arc, arc); + g2.setPaint(oldpaint); + setAntiAliasing(g2, false); + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/utils/LogHelper.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/utils/LogHelper.java new file mode 100644 index 000000000..d87b121d7 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/utils/LogHelper.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * LogHelper.java at 2015-2-1 20:25:40, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf; + +import org.jackhuang.hmcl.laf.BeautyEyeLNFHelper; + +/** + * The Class LogHelper. + * + * @author Jack Jiang, 2013-04-05 + * @since 3.5 + * @see BeautyEyeLNFHelper#debug + */ +public class LogHelper +{ + /** + * Error. + * + * @param msg the msg + */ + public static void error(String msg) + { + if(BeautyEyeLNFHelper.debug) + System.err.println("[BE-ERROR] - "+msg); + } + + /** + * Debug. + * + * @param msg the msg + */ + public static void debug(String msg) + { + if(BeautyEyeLNFHelper.debug) + System.err.println("[BE-DEBUG] - "+msg); + } + + /** + * Info. + * + * @param msg the msg + */ + public static void info(String msg) + { + System.err.println("[BE-INFO] - "+msg); + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/utils/RawCache.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/utils/RawCache.java new file mode 100644 index 000000000..ac79ca077 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/utils/RawCache.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * RawCache.java at 2015-2-1 20:25:40, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.utils; + +import java.util.HashMap; + +/** + * 本地磁盘资源文件缓存中心超类,子类可继承本类以实现磁盘资源的集中缓存. + * + * @param the generic type + * @author Jack Jiang(jb2011@163.com), 2010-09-11 + * @version 1.0 + */ +public abstract class RawCache { + + /** + * 本地磁盘资源缓存中心(key=path,value=image对象). + */ + private final HashMap rawCache = new HashMap<>(); + + /** + * 本地磁盘资源(如果缓存中已存在,则从中取之,否则从磁盘读取并缓存之). + * + * @param relativePath + * 本地磁盘资源相对于baseClass类的相对路径,比如它如果在/res/imgs/pic/下,baseClass在 + * /res下,则本地磁盘资源此处传过来的相对路径应该是/imgs/pic/some.png + * @param baseClass 基准类,指定此类则获取本地磁盘资源时会以此类为基准取本地磁盘资源的相对物理目录 + * @return T + */ + public T getRaw(String relativePath, Class baseClass) { + T ic = null; + + String key = relativePath + baseClass.getCanonicalName(); + if (rawCache.containsKey(key)) + ic = rawCache.get(key); + else + try { + ic = getResource(relativePath, baseClass); + rawCache.put(key, ic); + } catch (Exception e) { + System.out.println("取本地磁盘资源文件出错,path=" + key + "," + e.getMessage()); + e.printStackTrace(); + } + return ic; + } + + /** + * 本地资源获取方法实现. + * + * @param relativePath 相对路径 + * @param baseClass 基准类 + * @return the resource + */ + protected abstract T getResource(String relativePath, Class baseClass); +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/utils/WindowTranslucencyHelper.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/utils/WindowTranslucencyHelper.java new file mode 100644 index 000000000..a3711dcf9 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/utils/WindowTranslucencyHelper.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * WindowTranslucencyHelper.java at 2015-2-1 20:25:40, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf; + +import java.awt.Color; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.Window; + +/** + * 关于java支持窗口透明的详细信息请见:http://docs.oracle.com/javase/tutorial/uiswing/misc/trans_shaped_windows.html#uniform + */ +public class WindowTranslucencyHelper { + + /** + * Checks if is translucency supported. + * + * @return true, if is translucency supported + */ + public static boolean isTranslucencySupported() { + return GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().isWindowTranslucencySupported(GraphicsDevice.WindowTranslucency.TRANSLUCENT); + } + + /** + * Sets the window opaque. + * + * @param w the w + * @param opaque the opaque + */ + public static void setWindowOpaque(Window w, boolean opaque) { + Color bgc = w.getBackground(); + /* + * 在群友机器上(win7+java1.7.0.1)的生产系统下 + * 下使用BeautyEye有时w.getBackground()返回值是null,但为什么返回是null,Jack 没 + * 有测出来(Jack测试都是正常的),暂且认为是其系统代码有问题吧,在此容错一下 + */ + if (bgc == null) + bgc = Color.black;//暂不知道用此黑色作为容错值合不合适 + Color newBgn = new Color(bgc.getRed(), bgc.getGreen(), bgc.getBlue(), opaque ? 255 : 0); + w.setBackground(newBgn); + } + +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/widget/ImageBgPanel.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/widget/ImageBgPanel.java new file mode 100644 index 000000000..d8cc53c45 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/widget/ImageBgPanel.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * ImageBgPanel.java at 2015-2-1 20:25:38, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.widget; + +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Graphics2D; + +import javax.swing.JComponent; +import javax.swing.JPanel; + +import org.jb2011.ninepatch4j.NinePatch; + +/** + * 一个使用NinePatch图作为背景的面板实现类. + * + * @author Jack Jiang(jb2011@163.com) + */ +public class ImageBgPanel extends JPanel { + + private boolean drawBg = true; + + private NinePatch n9 = null; + + public ImageBgPanel() { + this.setOpaque(false); + } + + @Override + public void paintChildren(Graphics g) { + if (drawBg && n9 != null) + n9.draw((Graphics2D) g, 0, 0, this.getWidth(), this.getHeight()); + super.paintChildren(g); + } + + /** + * 重写父类方法,以实现添加到它的所有子组件的透明性是按字段childOpaque指明的方式呈现. + * + * @param comp the comp + * @param constraints the constraints + * @param index the index + */ + @Override + protected void addImpl(Component comp, Object constraints, int index) { + if (comp != null && comp instanceof JComponent) + ((JComponent) comp).setOpaque(false); + super.addImpl(comp, constraints, index); + } + + /** + * Checks if is draw bg. + * + * @return true, if is draw bg + */ + public boolean isDrawBg() { + return drawBg; + } + + /** + * Sets the draw bg. + * + * @param drawBg the draw bg + * @return the image bg panel + */ + public ImageBgPanel setDrawBg(boolean drawBg) { + this.drawBg = drawBg; + return this; + } + + /** + * Gets the n9. + * + * @return the n9 + */ + public NinePatch getN9() { + return n9; + } + + /** + * Sets the n9. + * + * @param n9 the n9 + * @return the image bg panel + */ + public ImageBgPanel setN9(NinePatch n9) { + this.n9 = n9; + return this; + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/widget/N9ComponentFactory.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/widget/N9ComponentFactory.java new file mode 100644 index 000000000..806462c0a --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/widget/N9ComponentFactory.java @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * N9ComponentFactory.java at 2015-2-1 20:25:36, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.widget; + +import java.awt.Color; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Insets; + +import javax.swing.BorderFactory; +import javax.swing.JLabel; +import org.jackhuang.hmcl.laf.utils.Icon9Factory; + +import org.jb2011.ninepatch4j.NinePatch; + +/** + * 使用NinePatch作为背景的一些可重用组件工厂类. + *

+ * 目前这些组件主要用于SwingSets2的演示代码,以便改造官方的SwingSets2使 得它们的美感与BeautyEye形成较好的搭配。 + * + * @author Jack Jiang(jb2011@163.com) + */ +public class N9ComponentFactory extends JLabel { + + public static final Icon9Factory ICON_9 = new Icon9Factory("widget"); + + /** + * Creates a new N9Component object. + * + * @param text the text + * @param n9 the n9 + * @param is the is + * @param foregroundColor the foreground color + * @param f the f + * @return the j label + */ + public static JLabel createLabel_root(String text, + final NinePatch n9, Insets is, + Color foregroundColor, Font f) { + JLabel l = new JLabel(text) { + @Override + public void paintComponent(Graphics g) { + n9.draw((Graphics2D) g, 0, 0, this.getWidth(), this.getHeight()); + super.paintComponent(g); + } + }; + if (is != null) + l.setBorder(BorderFactory.createEmptyBorder(is.top, is.left, is.bottom, is.right)); + if (foregroundColor != null) + l.setForeground(foregroundColor); + if (f != null) + l.setFont(f); + + return l; + } + + /** + * Creates a new N9Component object. + * + * @param txt the txt + * @return the j label + */ + public static JLabel createLabel_style1(String txt) { + return createLabel_root(txt, ICON_9.get("hint_light_blue"), + new Insets(1, 6, 1, 6), Color.white, new Font("宋体", Font.BOLD, 12)); + } + + /** + * Creates a new N9Component object. + * + * @param txt the txt + * @return the j label + */ + public static JLabel createLabel_style2(String txt) { + return createLabel_root(txt, ICON_9.get("tips"), + new Insets(15, 3, 28, 3), new Color(139, 119, 75), + null); + } + + /** + * Creates a new N9Component object. + * + * @param txt the txt + * @return the j label + */ + public static JLabel createLabel_style3(String txt) { + return createLabel_root(txt, ICON_9.get("orange_balloon"), + new Insets(4, 9, 9, 9)//3, 9, 8, 9) + , + new Color(255, 255, 255), + null); + } + + /** + * Creates a new N9Component object. + * + * @param txt the txt + * @return the j label + */ + public static JLabel createLabel_style4(String txt) { + return createLabel_root(txt, ICON_9.get("hint_light_gray"), + new Insets(2, 8, 2, 8), Color.white, new Font("宋体", Font.PLAIN, 12)); + } + + /** + * Creates a new N9Component object. + * + * @return the image bg panel + */ + public static ImageBgPanel createPanel_style1() { + return createPanel_style1(new Insets(8, 0, 26, 10)); + } + + /** + * Creates a new N9Component object. + * + * @param is the is + * @return the image bg panel + */ + public static ImageBgPanel createPanel_style1(Insets is) { + ImageBgPanel p = new ImageBgPanel().setN9(ICON_9.get("panel")); + if (is != null) + p.setBorder(BorderFactory.createEmptyBorder(is.top, is.left, is.bottom, is.right)); + return p; + } + +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/widget/border/BEDashedBorder.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/widget/border/BEDashedBorder.java new file mode 100644 index 000000000..df6bbc8a3 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/widget/border/BEDashedBorder.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * BEDashedBorder.java at 2015-2-1 20:25:41, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.widget.border; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics; + +import javax.swing.border.LineBorder; +import javax.swing.plaf.UIResource; + +import org.jackhuang.hmcl.laf.BEUtils; + +/** + * 虚线边框Border. + * + * @author Jack Jiang(jb2011@163.com) + */ +public class BEDashedBorder extends LineBorder implements UIResource { + + /** + * 虚线段绘制步进. + */ + private int step = 3; + + private boolean top = true, left = true, bottom = true, right = true; + + public BEDashedBorder(Color color, boolean top, boolean left, boolean bottom, boolean right) { + super(color); + this.top = top; + this.left = left; + this.bottom = bottom; + this.right = right; + } + + /** + * 构造方法. + * + * @param color 虚线颜色 + * @param thickness 线框宽度 + * @param step 步进 + * @param top the top + * @param left the left + * @param bottom the bottom + * @param right the right + */ + public BEDashedBorder(Color color, int thickness, int step, + boolean top, boolean left, boolean bottom, boolean right) { + super(color, thickness); + this.step = step; + this.top = top; + this.left = left; + this.bottom = bottom; + this.right = right; + } + + @Override + public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { + Color oldColor = g.getColor(); + int i; + + g.setColor(lineColor); + for (i = 0; i < thickness; i++) + BEUtils.drawDashedRect(g, x + i, y + i, width - i - i, height - i - i, step, top, left, bottom, right); + g.setColor(oldColor); + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/widget/border/BEDashedRoundRecBorder.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/widget/border/BEDashedRoundRecBorder.java new file mode 100644 index 000000000..10f09c07c --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/widget/border/BEDashedRoundRecBorder.java @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * BEDashedRoundRecBorder.java at 2015-2-1 20:25:39, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.widget.border; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics; + +import javax.swing.border.LineBorder; +import javax.swing.plaf.UIResource; + +import org.jackhuang.hmcl.laf.BEUtils; + +/** + * 虚线圆角边框Border. + *

+ * TODO 目前圆角大小和虚线间隔等目前都是固定的,进一步重构后可以进行重用哦. + * + * @author Jack Jiang(jb2011@163.com) + */ +public class BEDashedRoundRecBorder extends LineBorder implements UIResource { + + /** + * The separator space. + */ + private int arcWidth = 6, arcHeight = 6, separatorSolid = 2, separatorSpace = 2; + + /** + * 构造方法. + * + * @param color 虚线颜色 + */ + public BEDashedRoundRecBorder(Color color) { + super(color); + } + + @Override + public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { + Color oldColor = g.getColor(); + g.setColor(lineColor); + BEUtils.drawDashedRect(g, x, y, width, height, arcWidth, arcHeight, separatorSolid, separatorSpace); + g.setColor(oldColor); + } + + /** + * Gets the arc width. + * + * @return the arc width + */ + public int getArcWidth() { + return arcWidth; + } + + /** + * Sets the arc width. + * + * @param arcWidth the arc width + * @return the bE dashed round rec border + */ + public BEDashedRoundRecBorder setArcWidth(int arcWidth) { + this.arcWidth = arcWidth; + return this; + } + + /** + * Gets the arc height. + * + * @return the arc height + */ + public int getArcHeight() { + return arcHeight; + } + + /** + * Sets the arc height. + * + * @param arcHeight the arc height + * @return the bE dashed round rec border + */ + public BEDashedRoundRecBorder setArcHeight(int arcHeight) { + this.arcHeight = arcHeight; + return this; + } + + /** + * Gets the separator solid. + * + * @return the separator solid + */ + public int getSeparatorSolid() { + return separatorSolid; + } + + /** + * Sets the separator solid. + * + * @param separatorSolid the separator solid + * @return the bE dashed round rec border + */ + public BEDashedRoundRecBorder setSeparatorSolid(int separatorSolid) { + this.separatorSolid = separatorSolid; + return this; + } + + /** + * Gets the separator space. + * + * @return the separator space + */ + public int getSeparatorSpace() { + return separatorSpace; + } + + /** + * Sets the separator space. + * + * @param separatorSpace the separator space + * @return the bE dashed round rec border + */ + public BEDashedRoundRecBorder setSeparatorSpace(int separatorSpace) { + this.separatorSpace = separatorSpace; + return this; + } + +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/widget/border/BERoundBorder.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/widget/border/BERoundBorder.java new file mode 100644 index 000000000..a19f772b2 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/widget/border/BERoundBorder.java @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * BERoundBorder.java at 2015-2-1 20:25:39, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.widget.border; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Insets; + +import javax.swing.AbstractButton; +import javax.swing.JToolBar; +import javax.swing.border.LineBorder; +import javax.swing.plaf.UIResource; +import javax.swing.text.JTextComponent; + +import org.jackhuang.hmcl.laf.BEUtils; + +/** + * 圆角实线边框Border. + * + * @author Jack Jiang(jb2011@163.com) + */ +public class BERoundBorder extends LineBorder implements UIResource { + + /** + * 默认绘制的色调. + */ + public final static Color defaultLineColor = new Color(188, 188, 188);//154,154,155);// new Color(171,168,163); + + /** + * 圆角的半径. + */ + protected int arcWidth = 0;//6 + + /** + * Instantiates a new bE round border. + */ + public BERoundBorder() { + this(defaultLineColor, 1); + } + + /** + * Instantiates a new bE round border. + * + * @param color the color + */ + public BERoundBorder(Color color) { + this(color, 1); + } + + /** + * Instantiates a new bE round border. + * + * @param thickness the thickness + */ + public BERoundBorder(int thickness) { + this(defaultLineColor, thickness); + } + + /** + * Instantiates a new bE round border. + * + * @param color the color + * @param thickness the thickness + */ + public BERoundBorder(Color color, int thickness) { + super(color, thickness); + } + + @Override + public Insets getBorderInsets(Component c) { + return getBorderInsets(c, new Insets(0, 0, 0, 0)); + } + + @Override + public Insets getBorderInsets(Component c, Insets insets) { + Insets margin = null; + + if (c instanceof AbstractButton) + margin = ((AbstractButton) c).getMargin(); + else if (c instanceof JToolBar) + margin = ((JToolBar) c).getMargin(); + else if (c instanceof JTextComponent) + margin = ((JTextComponent) c).getMargin(); + insets.top = (margin != null ? margin.top : 0) + thickness; + insets.left = (margin != null ? margin.left : 0) + thickness; + insets.bottom = (margin != null ? margin.bottom : 0) + thickness; + insets.right = (margin != null ? margin.right : 0) + thickness; + + return insets; + } + + @Override + public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { + Color oldColor = g.getColor(); + + BEUtils.setAntiAliasing((Graphics2D) g, true); +// ((Graphics2D)g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, +// RenderingHints.VALUE_ANTIALIAS_ON); + Component cp = c.getParent(); + if (cp != null) { + //** 因java的textField边框默认是直角的,为了在LNF级别使加上圆连框后自然些,就得给这原始的直角先做隐藏处理(不要看见它) + // Color parentBackground=c.getParent().getBackground(); + // g.setColor(parentBackground); + // g.drawRect(x, y, width-1, height-1); + } + + //据thickness画出边框(当前是圆角的) + g.setColor(lineColor); + int i; + for (i = 0; i < thickness; i++) { + g.drawRoundRect(x + i, y + i, width - i - i - 1, height - i - i - 1, this.arcWidth, this.arcWidth); + if (thickness > 1) + g.setColor(BEUtils.getColor(g.getColor(), 70, 70, 70, -50)); + } + + g.setColor(oldColor); +// ((Graphics2D)g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, +// RenderingHints.VALUE_ANTIALIAS_OFF); + BEUtils.setAntiAliasing((Graphics2D) g, false); + } + + /** + * Sets the line color. + * + * @param c the c + * @return the bE round border + */ + public BERoundBorder setLineColor(Color c) { + lineColor = c; + return this; + } + + @Override + public Color getLineColor() { + return lineColor; + } + + /** + * Sets the thickness. + * + * @param t the t + * @return the bE round border + */ + public BERoundBorder setThickness(int t) { + thickness = t; + return this; + } + + @Override + public Object clone() { + BERoundBorder bb = new BERoundBorder(this.getLineColor(), this.getThickness()); + return bb; + } + + /** + * Gets the arc width. + * + * @return the arc width + */ + public int getArcWidth() { + return arcWidth; + } + + /** + * Sets the arc width. + * + * @param arcWidth the arc width + * @return the bE round border + */ + public BERoundBorder setArcWidth(int arcWidth) { + this.arcWidth = arcWidth; + return this; + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/widget/border/BEShadowBorder.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/widget/border/BEShadowBorder.java new file mode 100644 index 000000000..ad47367e4 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/widget/border/BEShadowBorder.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * BEShadowBorder.java at 2015-2-1 20:25:39, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.widget.border; + +import java.awt.Insets; +import org.jackhuang.hmcl.laf.widget.N9ComponentFactory; + +/** + * 一个用9格图实现的边框阴影效果,目前用于内部窗口的边框(阴影效果是半透明的). + * + * @author Jack Jiang(jb2011@163.com) + * @see + * org.jb2011.lnf.beautyeye.BeautyEyeLNFHelper.FrameBorderStyle#translucencySmallShadow + */ +public class BEShadowBorder extends NinePatchBorder { + + private final static int TOP = 5, LEFT = 5, RIGHT = 5, BOTTOM = 6; + + public BEShadowBorder() { + super(new Insets(TOP, LEFT, BOTTOM, RIGHT), + N9ComponentFactory.ICON_9.get("border_shadow1")); + } + + //* 2012-09-19 在BeautyEye v3.2中的BERootPaneUI,Jack Jiang启用了相比 + //* 原MetalRootPaneUI中更精确更好的边框拖放算法,以下方法暂时弃用,以后可以删除了! +// //当用本border作边框时,窗口可拖动敏感触点区大小值 +// public static int BORDER_DRAG_THICKNESS() +// { +// return Math.min(Math.min(Math.min(TOP, LEFT),RIGHT),BOTTOM); +// } +// +// //当用本border作边框时,窗口边角可拖动敏感触点区大小值 +// public static int CORNER_DRAG_WIDTH() +// { +// return Math.max(Math.max(Math.max(TOP, LEFT),RIGHT),BOTTOM); +// } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/widget/border/BEShadowBorder3.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/widget/border/BEShadowBorder3.java new file mode 100644 index 000000000..7b5e98a76 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/widget/border/BEShadowBorder3.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * BEShadowBorder3.java at 2015-2-1 20:25:39, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.widget.border; + +import java.awt.Insets; +import org.jackhuang.hmcl.laf.widget.N9ComponentFactory; + +/** + * 一个用9格图实现的边框阴影效果,目前主要用于窗口的边框(阴影效果是半透明的). + * + * @author Jack Jiang(jb201@163.com) + * @see + * org.jb2011.lnf.beautyeye.BeautyEyeLNFHelper.FrameBorderStyle#translucencyAppleLike + */ +public class BEShadowBorder3 extends NinePatchBorder { + + private final static int TOP = 17, LEFT = 27, RIGHT = 27, BOTTOM = 37; + + public BEShadowBorder3() { + super(new Insets(TOP, LEFT, BOTTOM, RIGHT), + N9ComponentFactory.ICON_9.get("border_shadow3")); + } + + //* 2012-09-19 在BeautyEye v3.2中的BERootPaneUI,Jack Jiang启用了相比 + //* 原MetalRootPaneUI中更精确更好的边框拖放算法,以下方法暂时弃用,以后可以删除了! +// //当用本border作边框时,窗口可拖动敏感触点区大小值 +// public static int BORDER_DRAG_THICKNESS() +// { +// return Math.min(Math.min(Math.min(TOP, LEFT),RIGHT),BOTTOM); +// } +// //当用本border作边框时,窗口边角可拖动敏感触点区大小值 +// public static int CORNER_DRAG_WIDTH() +// { +// return Math.max(Math.max(Math.max(TOP, LEFT),RIGHT),BOTTOM); +// } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/widget/border/NinePatchBorder.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/widget/border/NinePatchBorder.java new file mode 100644 index 000000000..548d94621 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/widget/border/NinePatchBorder.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * NinePatchBorder.java at 2015-2-1 20:25:36, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.widget.border; + +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Insets; + +import javax.swing.border.AbstractBorder; + +import org.jb2011.ninepatch4j.NinePatch; + +/** + * 一个利用NinePatch图实现边框的border实现类. + *

+ * 本类可以很好地被重用于NinePatch图作为border实现的场景哦. + * + * @author Jack Jiang(jb2011@163.com), 2012-09-04 + * @version 1.0 + */ +public class NinePatchBorder extends AbstractBorder { + + /** + * The insets. + */ + private Insets insets = null; + + /** + * The np. + */ + private NinePatch np = null; + + /** + * Instantiates a new nine patch border. + * + * @param insets the insets + * @param np the np + */ + public NinePatchBorder(Insets insets, NinePatch np) { + this.insets = insets; + this.np = np; + } + + @Override + public Insets getBorderInsets(Component c) { + return insets; + } + + @Override + public Insets getBorderInsets(Component c, Insets insets) { + return insets; + } + + @Override + public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { + this.np.draw((Graphics2D) g, x, y, width, height); + } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/widget/border/PlainGrayBorder.java b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/widget/border/PlainGrayBorder.java new file mode 100644 index 000000000..ff5d14098 --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/widget/border/PlainGrayBorder.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. + * All rights reserved. + * Project URL:https://github.com/JackJiang2011/beautyeye + * Version 3.6 + * + * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * PlainGrayBorder.java at 2015-2-1 20:25:38, original version by Jack Jiang. + * You can contact author with jb2011@163.com. + */ +package org.jackhuang.hmcl.laf.widget.border; + +import java.awt.Insets; +import org.jackhuang.hmcl.laf.widget.N9ComponentFactory; + +/** + * 一个NinePatch图实现的不透明边框border. + *

+ * 目前主要用于jdk1.5及以下版本的窗口边框(因为该版本下java不支持窗口透明). + * + * @author Jack Jiang(jb2011@163.com), 2012-09-04 + * @version 1.0 + * @see + * org.jb2011.lnf.beautyeye.BeautyEyeLNFHelper.FrameBorderStyle#generalNoTranslucencyShadow + */ +public class PlainGrayBorder extends NinePatchBorder { + + private final static int IS = 5; + + public PlainGrayBorder() { + super(new Insets(IS, IS, IS, IS), + N9ComponentFactory.ICON_9.get("border_plain_gray")); + } + + //* 2012-09-19 在BeautyEye v3.2中的BERootPaneUI,Jack Jiang启用了相比 + //* 原MetalRootPaneUI中更精确更好的边框拖放算法,以下方法暂时弃用,以后可以删除了! +// //当用本border作边框时,窗口可拖动敏感触点区大小值 +// public static int BORDER_DRAG_THICKNESS() +// { +// return IS; +// } +// //当用本border作边框时,窗口边角可拖动敏感触点区大小值 +// public static int CORNER_DRAG_WIDTH() +// { +// return 16;//使用MetalLookAndFeel的默认值比较合适哦 +// } +} diff --git a/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/widget/border/package.html b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/widget/border/package.html new file mode 100644 index 000000000..1664d615f --- /dev/null +++ b/HMCLaF/src/main/java/org/jackhuang/hmcl/laf/widget/border/package.html @@ -0,0 +1,7 @@ + + + + + 本包内包含了各种自定义border实现类。 + + \ No newline at end of file diff --git a/HMCLaF/src/main/java/org/jb2011/ninepatch4j/GraphicsUtilities.java b/HMCLaF/src/main/java/org/jb2011/ninepatch4j/GraphicsUtilities.java new file mode 100644 index 000000000..7d28c980f --- /dev/null +++ b/HMCLaF/src/main/java/org/jb2011/ninepatch4j/GraphicsUtilities.java @@ -0,0 +1,83 @@ +/* + * Decompiled with CFR 0_118. + */ +package org.jb2011.ninepatch4j; + +import java.awt.Graphics; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.Image; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.ImageObserver; +import java.awt.image.WritableRaster; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import javax.imageio.ImageIO; + +public class GraphicsUtilities { + public static BufferedImage loadCompatibleImage(URL resource) throws IOException { + BufferedImage image = ImageIO.read(resource); + return GraphicsUtilities.toCompatibleImage(image); + } + + public static BufferedImage loadCompatibleImage(InputStream stream) throws IOException { + BufferedImage image = ImageIO.read(stream); + return GraphicsUtilities.toCompatibleImage(image); + } + + public static BufferedImage createCompatibleImage(int width, int height) { + return GraphicsUtilities.getGraphicsConfiguration().createCompatibleImage(width, height); + } + + public static BufferedImage toCompatibleImage(BufferedImage image) { + if (GraphicsUtilities.isHeadless()) { + return image; + } + if (image.getColorModel().equals(GraphicsUtilities.getGraphicsConfiguration().getColorModel())) { + return image; + } + BufferedImage compatibleImage = GraphicsUtilities.getGraphicsConfiguration().createCompatibleImage(image.getWidth(), image.getHeight(), image.getTransparency()); + Graphics g = compatibleImage.getGraphics(); + g.drawImage(image, 0, 0, null); + g.dispose(); + return compatibleImage; + } + + public static BufferedImage createCompatibleImage(BufferedImage image, int width, int height) { + return GraphicsUtilities.getGraphicsConfiguration().createCompatibleImage(width, height, image.getTransparency()); + } + + private static GraphicsConfiguration getGraphicsConfiguration() { + GraphicsEnvironment environment = GraphicsEnvironment.getLocalGraphicsEnvironment(); + return environment.getDefaultScreenDevice().getDefaultConfiguration(); + } + + private static boolean isHeadless() { + return GraphicsEnvironment.isHeadless(); + } + + public static BufferedImage createTranslucentCompatibleImage(int width, int height) { + return GraphicsUtilities.getGraphicsConfiguration().createCompatibleImage(width, height, 3); + } + + public static int[] getPixels(BufferedImage img, int x, int y, int w, int h, int[] pixels) { + if (w == 0 || h == 0) { + return new int[0]; + } + if (pixels == null) { + pixels = new int[w * h]; + } else if (pixels.length < w * h) { + throw new IllegalArgumentException("Pixels array must have a length >= w * h"); + } + int imageType = img.getType(); + if (imageType == 2 || imageType == 1) { + WritableRaster raster = img.getRaster(); + return (int[])raster.getDataElements(x, y, w, h, pixels); + } + return img.getRGB(x, y, w, h, pixels, 0, w); + } +} + diff --git a/HMCLaF/src/main/java/org/jb2011/ninepatch4j/NinePatch.java b/HMCLaF/src/main/java/org/jb2011/ninepatch4j/NinePatch.java new file mode 100644 index 000000000..20e10f300 --- /dev/null +++ b/HMCLaF/src/main/java/org/jb2011/ninepatch4j/NinePatch.java @@ -0,0 +1,130 @@ +/* + * Decompiled with CFR 0_118. + */ +package org.jb2011.ninepatch4j; + +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.image.BufferedImage; +import java.awt.image.ImageObserver; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import org.jb2011.ninepatch4j.GraphicsUtilities; +import org.jb2011.ninepatch4j.NinePatchChunk; + +public class NinePatch { + public static final String EXTENSION_9PATCH = ".9.png"; + private BufferedImage mImage; + private NinePatchChunk mChunk; + + public BufferedImage getImage() { + return this.mImage; + } + + public NinePatchChunk getChunk() { + return this.mChunk; + } + + public static NinePatch load(URL fileUrl, boolean convert) throws IOException { + BufferedImage image = null; + try { + image = GraphicsUtilities.loadCompatibleImage(fileUrl); + } + catch (MalformedURLException e) { + return null; + } + boolean is9Patch = fileUrl.getPath().toLowerCase().endsWith(".9.png"); + return NinePatch.load(image, is9Patch, convert); + } + + public static NinePatch load(InputStream stream, boolean is9Patch, boolean convert) throws IOException { + BufferedImage image = null; + try { + image = GraphicsUtilities.loadCompatibleImage(stream); + } + catch (MalformedURLException e) { + return null; + } + return NinePatch.load(image, is9Patch, convert); + } + + /* + * Enabled force condition propagation + * Lifted jumps to return sites + */ + public static NinePatch load(BufferedImage image, boolean is9Patch, boolean convert) { + if (!is9Patch) { + if (!convert) return null; + image = NinePatch.convertTo9Patch(image); + return new NinePatch(image); + } else { + NinePatch.ensure9Patch(image); + } + return new NinePatch(image); + } + + public int getWidth() { + return this.mImage.getWidth(); + } + + public int getHeight() { + return this.mImage.getHeight(); + } + + public boolean getPadding(int[] padding) { + this.mChunk.getPadding(padding); + return true; + } + + public void draw(Graphics2D graphics2D, int x, int y, int scaledWidth, int scaledHeight) { + this.mChunk.draw(this.mImage, graphics2D, x, y, scaledWidth, scaledHeight, 0, 0); + } + + private NinePatch(BufferedImage image) { + this.mChunk = NinePatchChunk.create(image); + this.mImage = this.extractBitmapContent(image); + } + + private static void ensure9Patch(BufferedImage image) { + int pixel; + int width = image.getWidth(); + int height = image.getHeight(); + int i = 0; + while (i < width) { + pixel = image.getRGB(i, 0); + if (pixel != 0 && pixel != -16777216) { + image.setRGB(i, 0, 0); + } + if ((pixel = image.getRGB(i, height - 1)) != 0 && pixel != -16777216) { + image.setRGB(i, height - 1, 0); + } + ++i; + } + i = 0; + while (i < height) { + pixel = image.getRGB(0, i); + if (pixel != 0 && pixel != -16777216) { + image.setRGB(0, i, 0); + } + if ((pixel = image.getRGB(width - 1, i)) != 0 && pixel != -16777216) { + image.setRGB(width - 1, i, 0); + } + ++i; + } + } + + private static BufferedImage convertTo9Patch(BufferedImage image) { + BufferedImage buffer = GraphicsUtilities.createTranslucentCompatibleImage(image.getWidth() + 2, image.getHeight() + 2); + Graphics2D g2 = buffer.createGraphics(); + g2.drawImage(image, 1, 1, null); + g2.dispose(); + return buffer; + } + + private BufferedImage extractBitmapContent(BufferedImage image) { + return image.getSubimage(1, 1, image.getWidth() - 2, image.getHeight() - 2); + } +} + diff --git a/HMCLaF/src/main/java/org/jb2011/ninepatch4j/NinePatchChunk.java b/HMCLaF/src/main/java/org/jb2011/ninepatch4j/NinePatchChunk.java new file mode 100644 index 000000000..592583d43 --- /dev/null +++ b/HMCLaF/src/main/java/org/jb2011/ninepatch4j/NinePatchChunk.java @@ -0,0 +1,386 @@ +/* + * Decompiled with CFR 0_118. + */ +package org.jb2011.ninepatch4j; + +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.image.BufferedImage; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +/* + * This class specifies class file version 49.0 but uses Java 6 signatures. Assumed Java 6. + */ +public class NinePatchChunk +implements Serializable { + private static final long serialVersionUID = -7353439224505296217L; + private static final int[] sPaddingRect = new int[4]; + private boolean mVerticalStartWithPatch; + private boolean mHorizontalStartWithPatch; + private List mFixed; + private List mPatches; + private List mHorizontalPatches; + private List mVerticalPatches; + private Pair mHorizontalPadding; + private Pair mVerticalPadding; + + public static NinePatchChunk create(BufferedImage image) { + NinePatchChunk chunk = new NinePatchChunk(); + chunk.findPatches(image); + return chunk; + } + + public void draw(BufferedImage image, Graphics2D graphics2D, int x, int y, int scaledWidth, int scaledHeight, int destDensity, int srcDensity) { + boolean scaling; + boolean bl = scaling = destDensity != srcDensity && destDensity != 0 && srcDensity != 0; + if (scaling) { + try { + graphics2D = (Graphics2D)graphics2D.create(); + float densityScale = (float)destDensity / (float)srcDensity; + graphics2D.translate(x, y); + graphics2D.scale(densityScale, densityScale); + scaledWidth = (int)((float)scaledWidth / densityScale); + scaledHeight = (int)((float)scaledHeight / densityScale); + y = 0; + x = 0; + this.draw(image, graphics2D, x, y, scaledWidth, scaledHeight); + } + finally { + graphics2D.dispose(); + } + } else { + this.draw(image, graphics2D, x, y, scaledWidth, scaledHeight); + } + } + + private void draw(BufferedImage image, Graphics2D graphics2D, int x, int y, int scaledWidth, int scaledHeight) { + if (scaledWidth <= 1 || scaledHeight <= 1) { + return; + } + Graphics2D g = (Graphics2D)graphics2D.create(); + g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); + try { + if (this.mPatches.isEmpty()) { + g.drawImage(image, x, y, scaledWidth, scaledHeight, null); + return; + } + g.translate(x, y); + y = 0; + x = 0; + DrawingData data = this.computePatches(scaledWidth, scaledHeight); + int fixedIndex = 0; + int horizontalIndex = 0; + int verticalIndex = 0; + int patchIndex = 0; + float vWeightSum = 1.0f; + float vRemainder = data.mRemainderVertical; + boolean vStretch = this.mVerticalStartWithPatch; + while (y < scaledHeight - 1) { + boolean hStretch = this.mHorizontalStartWithPatch; + int height = 0; + float vExtra = 0.0f; + float hWeightSum = 1.0f; + float hRemainder = data.mRemainderHorizontal; + while (x < scaledWidth - 1) { + float extra; + int width; + Rectangle r; + if (!vStretch) { + if (hStretch) { + r = this.mHorizontalPatches.get(horizontalIndex++); + extra = (float)r.width / data.mHorizontalPatchesSum; + width = (int)(extra * hRemainder / hWeightSum); + hWeightSum -= extra; + hRemainder -= (float)width; + g.drawImage(image, x, y, x + width, y + r.height, r.x, r.y, r.x + r.width, r.y + r.height, null); + x += width; + } else { + r = this.mFixed.get(fixedIndex++); + g.drawImage(image, x, y, x + r.width, y + r.height, r.x, r.y, r.x + r.width, r.y + r.height, null); + x += r.width; + } + height = r.height; + } else if (hStretch) { + r = this.mPatches.get(patchIndex++); + vExtra = (float)r.height / data.mVerticalPatchesSum; + height = (int)(vExtra * vRemainder / vWeightSum); + extra = (float)r.width / data.mHorizontalPatchesSum; + width = (int)(extra * hRemainder / hWeightSum); + hWeightSum -= extra; + hRemainder -= (float)width; + g.drawImage(image, x, y, x + width, y + height, r.x, r.y, r.x + r.width, r.y + r.height, null); + x += width; + } else { + r = this.mVerticalPatches.get(verticalIndex++); + vExtra = (float)r.height / data.mVerticalPatchesSum; + height = (int)(vExtra * vRemainder / vWeightSum); + g.drawImage(image, x, y, x + r.width, y + height, r.x, r.y, r.x + r.width, r.y + r.height, null); + x += r.width; + } + boolean bl = hStretch = !hStretch; + } + x = 0; + y += height; + if (vStretch) { + vWeightSum -= vExtra; + vRemainder -= (float)height; + } + boolean bl = vStretch = !vStretch; + } + } + finally { + g.dispose(); + } + } + + public void getPadding(int[] padding) { + padding[0] = this.mHorizontalPadding.mFirst; + padding[2] = this.mHorizontalPadding.mSecond; + padding[1] = this.mVerticalPadding.mFirst; + padding[3] = this.mVerticalPadding.mSecond; + } + + public int[] getPadding() { + this.getPadding(sPaddingRect); + return sPaddingRect; + } + + private DrawingData computePatches(int scaledWidth, int scaledHeight) { + int start; + DrawingData data = new DrawingData(); + boolean measuredWidth = false; + boolean endRow = true; + int remainderHorizontal = 0; + int remainderVertical = 0; + if (this.mFixed.size() > 0) { + start = this.mFixed.get((int)0).y; + for (Rectangle rect : this.mFixed) { + if (rect.y > start) { + endRow = true; + measuredWidth = true; + } + if (!measuredWidth) { + remainderHorizontal += rect.width; + } + if (!endRow) continue; + remainderVertical += rect.height; + endRow = false; + start = rect.y; + } + } + DrawingData.access$4(data, scaledWidth - remainderHorizontal); + DrawingData.access$5(data, scaledHeight - remainderVertical); + DrawingData.access$6(data, 0.0f); + if (this.mHorizontalPatches.size() > 0) { + start = -1; + for (Rectangle rect : this.mHorizontalPatches) { + if (rect.x <= start) continue; + DrawingData drawingData = data; + DrawingData.access$6(drawingData, drawingData.mHorizontalPatchesSum + (float)rect.width); + start = rect.x; + } + } else { + start = -1; + for (Rectangle rect : this.mPatches) { + if (rect.x <= start) continue; + DrawingData drawingData = data; + DrawingData.access$6(drawingData, drawingData.mHorizontalPatchesSum + (float)rect.width); + start = rect.x; + } + } + DrawingData.access$7(data, 0.0f); + if (this.mVerticalPatches.size() > 0) { + start = -1; + for (Rectangle rect : this.mVerticalPatches) { + if (rect.y <= start) continue; + DrawingData drawingData = data; + DrawingData.access$7(drawingData, drawingData.mVerticalPatchesSum + (float)rect.height); + start = rect.y; + } + } else { + start = -1; + for (Rectangle rect : this.mPatches) { + if (rect.y <= start) continue; + DrawingData drawingData = data; + DrawingData.access$7(drawingData, drawingData.mVerticalPatchesSum + (float)rect.height); + start = rect.y; + } + } + return data; + } + + private void findPatches(BufferedImage image) { + int width = image.getWidth() - 2; + int height = image.getHeight() - 2; + int[] row = null; + int[] column = null; + row = GraphicsUtilities.getPixels(image, 1, 0, width, 1, row); + column = GraphicsUtilities.getPixels(image, 0, 1, 1, height, column); + boolean[] result = new boolean[1]; + Pair>> left = this.getPatches(column, result); + this.mVerticalStartWithPatch = result[0]; + result = new boolean[1]; + Pair>> top = this.getPatches(row, result); + this.mHorizontalStartWithPatch = result[0]; + this.mFixed = this.getRectangles((List)left.mFirst, (List)top.mFirst); + this.mPatches = this.getRectangles((List)left.mSecond, (List)top.mSecond); + if (this.mFixed.size() > 0) { + this.mHorizontalPatches = this.getRectangles((List)left.mFirst, (List)top.mSecond); + this.mVerticalPatches = this.getRectangles((List)left.mSecond, (List)top.mFirst); + } else if (((List)top.mFirst).size() > 0) { + this.mHorizontalPatches = new ArrayList<>(0); + this.mVerticalPatches = this.getVerticalRectangles(height, (List)top.mFirst); + } else if (((List)left.mFirst).size() > 0) { + this.mHorizontalPatches = this.getHorizontalRectangles(width, (List)left.mFirst); + this.mVerticalPatches = new ArrayList<>(0); + } else { + this.mVerticalPatches = new ArrayList<>(0); + this.mHorizontalPatches = this.mVerticalPatches; + } + row = GraphicsUtilities.getPixels(image, 1, height + 1, width, 1, row); + column = GraphicsUtilities.getPixels(image, width + 1, 1, 1, height, column); + top = this.getPatches(row, result); + this.mHorizontalPadding = this.getPadding((List)top.mFirst); + left = this.getPatches(column, result); + this.mVerticalPadding = this.getPadding((List)left.mFirst); + } + + private List getVerticalRectangles(int imageHeight, List> topPairs) { + ArrayList rectangles = new ArrayList<>(); + for (Pair top : topPairs) { + int x = top.mFirst; + int width = top.mSecond - top.mFirst; + rectangles.add(new Rectangle(x, 0, width, imageHeight)); + } + return rectangles; + } + + private List getHorizontalRectangles(int imageWidth, List> leftPairs) { + ArrayList rectangles = new ArrayList<>(); + for (Pair left : leftPairs) { + int y = left.mFirst; + int height = left.mSecond - left.mFirst; + rectangles.add(new Rectangle(0, y, imageWidth, height)); + } + return rectangles; + } + + private Pair getPadding(List> pairs) { + if (pairs.isEmpty()) { + return new Pair<>(0, 0); + } + if (pairs.size() == 1) { + if (pairs.get((int)0).mFirst == 0) { + return new Pair<>(pairs.get((int)0).mSecond - pairs.get((int)0).mFirst, 0); + } + return new Pair<>(0, pairs.get((int)0).mSecond - pairs.get((int)0).mFirst); + } + int index = pairs.size() - 1; + return new Pair<>(pairs.get((int)0).mSecond - pairs.get((int)0).mFirst, pairs.get((int)index).mSecond - pairs.get((int)index).mFirst); + } + + private List getRectangles(List> leftPairs, List> topPairs) { + ArrayList rectangles = new ArrayList<>(); + for (Pair left : leftPairs) { + int y = left.mFirst; + int height = left.mSecond - left.mFirst; + for (Pair top : topPairs) { + int x = top.mFirst; + int width = top.mSecond - top.mFirst; + rectangles.add(new Rectangle(x, y, width, height)); + } + } + return rectangles; + } + + private Pair>> getPatches(int[] pixels, boolean[] startWithPatch) { + int lastIndex = 0; + int lastPixel = pixels[0]; + boolean first = true; + List> fixed = new ArrayList<>(); + List> patches = new ArrayList<>(); + int i = 0; + while (i < pixels.length) { + int pixel = pixels[i]; + if (pixel != lastPixel) { + if (lastPixel == -16777216) { + if (first) { + startWithPatch[0] = true; + } + patches.add(new Pair<>(lastIndex, i)); + } else { + fixed.add(new Pair<>(lastIndex, i)); + } + first = false; + lastIndex = i; + lastPixel = pixel; + } + ++i; + } + if (lastPixel == -16777216) { + if (first) { + startWithPatch[0] = true; + } + patches.add(new Pair<>(lastIndex, pixels.length)); + } else { + fixed.add(new Pair<>(lastIndex, pixels.length)); + } + if (patches.isEmpty()) { + patches.add(new Pair<>(1, pixels.length)); + startWithPatch[0] = true; + fixed.clear(); + } + return new Pair<>(fixed, patches); + } + + static final class DrawingData { + private int mRemainderHorizontal; + private int mRemainderVertical; + private float mHorizontalPatchesSum; + private float mVerticalPatchesSum; + + DrawingData() { + } + + static /* synthetic */ void access$4(DrawingData drawingData, int n) { + drawingData.mRemainderHorizontal = n; + } + + static /* synthetic */ void access$5(DrawingData drawingData, int n) { + drawingData.mRemainderVertical = n; + } + + static /* synthetic */ void access$6(DrawingData drawingData, float f) { + drawingData.mHorizontalPatchesSum = f; + } + + static /* synthetic */ void access$7(DrawingData drawingData, float f) { + drawingData.mVerticalPatchesSum = f; + } + } + + /* + * This class specifies class file version 49.0 but uses Java 6 signatures. Assumed Java 6. + */ + static class Pair + implements Serializable { + private static final long serialVersionUID = -2204108979541762418L; + E mFirst; + E mSecond; + + Pair(E first, E second) { + this.mFirst = first; + this.mSecond = second; + } + + @Override + public String toString() { + return "Pair[" + this.mFirst + ", " + this.mSecond + "]"; + } + } + +} + diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/checkbox_off.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/checkbox_off.png deleted file mode 100755 index a0afbaed2..000000000 Binary files a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/checkbox_off.png and /dev/null differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/checkbox_off_disabled.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/checkbox_off_disabled.png deleted file mode 100755 index bb507cdb0..000000000 Binary files a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/checkbox_off_disabled.png and /dev/null differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/checkbox_off_over.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/checkbox_off_over.png deleted file mode 100755 index 738e2030d..000000000 Binary files a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/checkbox_off_over.png and /dev/null differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/checkbox_off_pressed.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/checkbox_off_pressed.png deleted file mode 100755 index 974d1d65a..000000000 Binary files a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/checkbox_off_pressed.png and /dev/null differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/checkbox_on.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/checkbox_on.png deleted file mode 100755 index 5a2cda110..000000000 Binary files a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/checkbox_on.png and /dev/null differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/checkbox_on_disabled.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/checkbox_on_disabled.png deleted file mode 100755 index 453ca15d0..000000000 Binary files a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/checkbox_on_disabled.png and /dev/null differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/checkbox_on_over.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/checkbox_on_over.png deleted file mode 100755 index 0842c1139..000000000 Binary files a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/checkbox_on_over.png and /dev/null differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/checkbox_on_pressed.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/checkbox_on_pressed.png deleted file mode 100755 index 7baafae75..000000000 Binary files a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/checkbox_on_pressed.png and /dev/null differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/combo_disabled.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/combo_disabled.png deleted file mode 100755 index 538f02b64..000000000 Binary files a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/combo_disabled.png and /dev/null differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/combo_normal.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/combo_normal.png deleted file mode 100755 index eb8b16585..000000000 Binary files a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/combo_normal.png and /dev/null differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/combo_over.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/combo_over.png deleted file mode 100755 index ba4df60d6..000000000 Binary files a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/combo_over.png and /dev/null differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/combo_pressed.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/combo_pressed.png deleted file mode 100755 index a8d2c44bc..000000000 Binary files a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/combo_pressed.png and /dev/null differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/option_pane_error.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/option_pane_error.png deleted file mode 100755 index 6baa7d9a5..000000000 Binary files a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/option_pane_error.png and /dev/null differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/option_pane_info.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/option_pane_info.png deleted file mode 100755 index 00552523f..000000000 Binary files a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/option_pane_info.png and /dev/null differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/option_pane_question.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/option_pane_question.png deleted file mode 100755 index 208fef537..000000000 Binary files a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/option_pane_question.png and /dev/null differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/option_pane_warning.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/option_pane_warning.png deleted file mode 100755 index 2b42e6c84..000000000 Binary files a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/option_pane_warning.png and /dev/null differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/radio_btn.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/radio_btn.png deleted file mode 100755 index b87150ff1..000000000 Binary files a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/radio_btn.png and /dev/null differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/radio_btn_disabled_normal.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/radio_btn_disabled_normal.png deleted file mode 100755 index a081781ea..000000000 Binary files a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/radio_btn_disabled_normal.png and /dev/null differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/radio_btn_disabled_selected.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/radio_btn_disabled_selected.png deleted file mode 100755 index 932ec20c1..000000000 Binary files a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/radio_btn_disabled_selected.png and /dev/null differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/radio_btn_over.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/radio_btn_over.png deleted file mode 100755 index d6a3a608f..000000000 Binary files a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/radio_btn_over.png and /dev/null differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/radio_btn_pressed.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/radio_btn_pressed.png deleted file mode 100755 index d4519c5a8..000000000 Binary files a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/radio_btn_pressed.png and /dev/null differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/radio_btn_selected.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/radio_btn_selected.png deleted file mode 100755 index d4b998c2e..000000000 Binary files a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/radio_btn_selected.png and /dev/null differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/radio_btn_selected_over.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/radio_btn_selected_over.png deleted file mode 100755 index a51c6c3a7..000000000 Binary files a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/radio_btn_selected_over.png and /dev/null differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/radio_btn_selected_pressed.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/radio_btn_selected_pressed.png deleted file mode 100755 index 6a5fed0c9..000000000 Binary files a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/radio_btn_selected_pressed.png and /dev/null differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/scroll_dec_normal.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/scroll_dec_normal.png deleted file mode 100755 index afccc9998..000000000 Binary files a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/scroll_dec_normal.png and /dev/null differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/scroll_dec_over.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/scroll_dec_over.png deleted file mode 100755 index fa21afbe5..000000000 Binary files a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/scroll_dec_over.png and /dev/null differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/scroll_dec_pressed.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/scroll_dec_pressed.png deleted file mode 100755 index afccc9998..000000000 Binary files a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/scroll_dec_pressed.png and /dev/null differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/scroll_disabled.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/scroll_disabled.png deleted file mode 100755 index fe990d02f..000000000 Binary files a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/scroll_disabled.png and /dev/null differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/scroll_enabled.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/scroll_enabled.png deleted file mode 100755 index 29055171e..000000000 Binary files a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/scroll_enabled.png and /dev/null differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/scroll_inc_normal.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/scroll_inc_normal.png deleted file mode 100755 index 74fe160ea..000000000 Binary files a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/scroll_inc_normal.png and /dev/null differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/scroll_inc_over.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/scroll_inc_over.png deleted file mode 100755 index 1c4f3f5e4..000000000 Binary files a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/scroll_inc_over.png and /dev/null differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/scroll_inc_pressed.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/scroll_inc_pressed.png deleted file mode 100755 index 74fe160ea..000000000 Binary files a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/scroll_inc_pressed.png and /dev/null differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/scroll_thumb_normal.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/scroll_thumb_normal.png deleted file mode 100755 index 7f80ad314..000000000 Binary files a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/scroll_thumb_normal.png and /dev/null differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/scroll_thumb_over.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/scroll_thumb_over.png deleted file mode 100755 index 4bfc80afd..000000000 Binary files a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/scroll_thumb_over.png and /dev/null differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/scroll_thumb_pressed.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/scroll_thumb_pressed.png deleted file mode 100755 index 4bfc80afd..000000000 Binary files a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/scroll_thumb_pressed.png and /dev/null differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/tree_closed.gif b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/tree_closed.gif deleted file mode 100644 index fa34e2f5e..000000000 Binary files a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/tree_closed.gif and /dev/null differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/tree_collapsed.gif b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/tree_collapsed.gif deleted file mode 100644 index a93f61b10..000000000 Binary files a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/tree_collapsed.gif and /dev/null differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/tree_expanded.gif b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/tree_expanded.gif deleted file mode 100644 index 85da77acf..000000000 Binary files a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/tree_expanded.gif and /dev/null differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/tree_leaf.gif b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/tree_leaf.gif deleted file mode 100644 index 800b56293..000000000 Binary files a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/tree_leaf.gif and /dev/null differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/tree_open.gif b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/tree_open.gif deleted file mode 100644 index fa34e2f5e..000000000 Binary files a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/images/tree_open.gif and /dev/null differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/synth.xml b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/synth.xml deleted file mode 100755 index 99985f5d9..000000000 --- a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/synth.xml +++ /dev/null @@ -1,448 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0 - 0 - false - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/synth_backup.xml b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/synth_backup.xml deleted file mode 100644 index 7f7a48f81..000000000 --- a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/synth_backup.xml +++ /dev/null @@ -1,439 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0 - 0 - false - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 6 - - - - - - - - \ No newline at end of file diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/RadioButtonMenuItemCheckIcon2.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/RadioButtonMenuItemCheckIcon2.png new file mode 100644 index 000000000..0164f3ba3 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/RadioButtonMenuItemCheckIcon2.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/RadioButtonMenuItemCheckIcon2_1.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/RadioButtonMenuItemCheckIcon2_1.png new file mode 100644 index 000000000..0164f3ba3 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/RadioButtonMenuItemCheckIcon2_1.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/RadioButtonMenuItemCheckIcon_none.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/RadioButtonMenuItemCheckIcon_none.png new file mode 100644 index 000000000..163435382 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/RadioButtonMenuItemCheckIcon_none.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/RadioButtonMenuItemCheckIcon_none_1.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/RadioButtonMenuItemCheckIcon_none_1.png new file mode 100644 index 000000000..163435382 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/RadioButtonMenuItemCheckIcon_none_1.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/a.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/a.png new file mode 100644 index 000000000..405193860 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/a.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/asc2.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/asc2.png new file mode 100644 index 000000000..f44526e4f Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/asc2.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/b.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/b.png new file mode 100644 index 000000000..9a304d91c Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/b.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/button_arrow.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/button_arrow.png new file mode 100644 index 000000000..6f134e9db Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/button_arrow.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/button_arrow_disable.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/button_arrow_disable.png new file mode 100644 index 000000000..2a1ffc6ff Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/button_arrow_disable.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/button_arrow_pressed.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/button_arrow_pressed.9.png new file mode 100644 index 000000000..6751b4165 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/button_arrow_pressed.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/button_arrow_pressed.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/button_arrow_pressed.png new file mode 100644 index 000000000..6751b4165 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/button_arrow_pressed.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/checkbox_menuitem_none.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/checkbox_menuitem_none.png new file mode 100644 index 000000000..6a49a7343 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/checkbox_menuitem_none.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/checkbox_menuitem_none_1.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/checkbox_menuitem_none_1.png new file mode 100644 index 000000000..6a49a7343 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/checkbox_menuitem_none_1.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/checkbox_menuitem_selected_normal.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/checkbox_menuitem_selected_normal.png new file mode 100644 index 000000000..cf4fe6d8c Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/checkbox_menuitem_selected_normal.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/checkbox_menuitem_selected_normal_1.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/checkbox_menuitem_selected_normal_1.png new file mode 100644 index 000000000..cf4fe6d8c Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/checkbox_menuitem_selected_normal_1.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/checkbox_off.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/checkbox_off.png new file mode 100644 index 000000000..9a7056633 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/checkbox_off.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/checkbox_off_disabled.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/checkbox_off_disabled.png new file mode 100644 index 000000000..a2d4466ee Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/checkbox_off_disabled.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/checkbox_off_over.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/checkbox_off_over.png new file mode 100644 index 000000000..cf238f3de Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/checkbox_off_over.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/checkbox_off_pressed.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/checkbox_off_pressed.png new file mode 100644 index 000000000..6575fff11 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/checkbox_off_pressed.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/checkbox_on.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/checkbox_on.png new file mode 100644 index 000000000..1a9e52d9a Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/checkbox_on.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/checkbox_on_disabled.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/checkbox_on_disabled.png new file mode 100644 index 000000000..e5542d0c3 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/checkbox_on_disabled.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/checkbox_on_over.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/checkbox_on_over.png new file mode 100644 index 000000000..b50a34bc6 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/checkbox_on_over.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/checkbox_on_pressed.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/checkbox_on_pressed.png new file mode 100644 index 000000000..79f84d35b Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/checkbox_on_pressed.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/default_frame_icon.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/default_frame_icon.png new file mode 100644 index 000000000..5237cb891 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/default_frame_icon.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/desc2.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/desc2.png new file mode 100644 index 000000000..ee05a9c31 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/desc2.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/error.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/error.png new file mode 100644 index 000000000..b4605fecd Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/error.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_close_normal.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_close_normal.png new file mode 100644 index 000000000..537d7c086 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_close_normal.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_close_over.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_close_over.png new file mode 100644 index 000000000..820970458 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_close_over.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_close_pressed.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_close_pressed.png new file mode 100644 index 000000000..7ad8a17e0 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_close_pressed.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_close_rover.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_close_rover.png new file mode 100644 index 000000000..162d9c295 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_close_rover.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_max_normal.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_max_normal.png new file mode 100644 index 000000000..4769b8f64 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_max_normal.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_max_pressed.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_max_pressed.png new file mode 100644 index 000000000..65439c76b Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_max_pressed.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_max_rover.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_max_rover.png new file mode 100644 index 000000000..b8dd5ae1f Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_max_rover.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_maximize_over.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_maximize_over.png new file mode 100644 index 000000000..100b8a575 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_maximize_over.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_maxwin.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_maxwin.png new file mode 100644 index 000000000..05b6ade5a Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_maxwin.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_maxwin_pressed.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_maxwin_pressed.png new file mode 100644 index 000000000..f8eaa6198 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_maxwin_pressed.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_maxwin_rover.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_maxwin_rover.png new file mode 100644 index 000000000..ba0993572 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_maxwin_rover.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_min_normal.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_min_normal.png new file mode 100644 index 000000000..f4d1d1a7f Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_min_normal.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_min_pressed.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_min_pressed.png new file mode 100644 index 000000000..7b27bb1d2 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_min_pressed.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_min_rover.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_min_rover.png new file mode 100644 index 000000000..20e47f8bb Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_min_rover.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_minimize_over.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_minimize_over.png new file mode 100644 index 000000000..dcdf733b8 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_minimize_over.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_setup_normal.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_setup_normal.png new file mode 100644 index 000000000..d079e041c Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_setup_normal.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_windowize_over.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_windowize_over.png new file mode 100644 index 000000000..00ed5217c Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/frame_windowize_over.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/head_bg.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/head_bg.png new file mode 100644 index 000000000..27e0ee397 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/head_bg.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/head_inactive.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/head_inactive.png new file mode 100644 index 000000000..74480a4cd Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/head_inactive.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/ifi1.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/ifi1.png new file mode 100644 index 000000000..c547747fe Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/ifi1.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/info.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/info.png new file mode 100644 index 000000000..76d4706a1 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/info.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/leaf1.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/leaf1.png new file mode 100644 index 000000000..78cc00f86 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/leaf1.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/arrow_toBottom.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/arrow_toBottom.9.png new file mode 100644 index 000000000..ef86e03ef Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/arrow_toBottom.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/arrow_toBottom_rover.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/arrow_toBottom_rover.9.png new file mode 100644 index 000000000..798217ea5 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/arrow_toBottom_rover.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/arrow_toLeft.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/arrow_toLeft.9.png new file mode 100644 index 000000000..e5b48bc84 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/arrow_toLeft.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/arrow_toLeft_rover.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/arrow_toLeft_rover.9.png new file mode 100644 index 000000000..75e8c7917 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/arrow_toLeft_rover.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/arrow_toRight.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/arrow_toRight.9.png new file mode 100644 index 000000000..e07033660 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/arrow_toRight.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/arrow_toRight_rover.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/arrow_toRight_rover.9.png new file mode 100644 index 000000000..e177ceafd Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/arrow_toRight_rover.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/arrow_toTop.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/arrow_toTop.9.png new file mode 100644 index 000000000..d60f59dae Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/arrow_toTop.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/arrow_toTop_rover.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/arrow_toTop_rover.9.png new file mode 100644 index 000000000..3f96effa4 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/arrow_toTop_rover.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/bg_login_text_disable.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/bg_login_text_disable.9.png new file mode 100644 index 000000000..e9373d200 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/bg_login_text_disable.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/bg_login_text_normal.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/bg_login_text_normal.9.png new file mode 100644 index 000000000..b082b623a Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/bg_login_text_normal.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/bg_login_text_pressed.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/bg_login_text_pressed.9.png new file mode 100644 index 000000000..e7f837a0b Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/bg_login_text_pressed.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/btn_general_default.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/btn_general_default.9.png new file mode 100644 index 000000000..8d1c7608e Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/btn_general_default.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/btn_general_pressed.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/btn_general_pressed.9.png new file mode 100644 index 000000000..4180b6966 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/btn_general_pressed.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/btn_general_rover.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/btn_general_rover.9.png new file mode 100644 index 000000000..d11cfa163 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/btn_general_rover.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/btn_special_default.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/btn_special_default.9.png new file mode 100644 index 000000000..be66964f9 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/btn_special_default.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/btn_special_disabled.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/btn_special_disabled.9.png new file mode 100644 index 000000000..e72ec14de Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/btn_special_disabled.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/combo_disabled.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/combo_disabled.9.png new file mode 100644 index 000000000..7d4ae68b6 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/combo_disabled.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/combo_normal.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/combo_normal.9.png new file mode 100644 index 000000000..262014217 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/combo_normal.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/combo_over.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/combo_over.9.png new file mode 100644 index 000000000..91d5740fc Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/combo_over.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/combo_pressed.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/combo_pressed.9.png new file mode 100644 index 000000000..9d2739a79 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/combo_pressed.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/frame_shadow_border4.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/frame_shadow_border4.9.png new file mode 100644 index 000000000..e39216016 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/frame_shadow_border4.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/hint_bg_lightblue.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/hint_bg_lightblue.9.png new file mode 100644 index 000000000..b871cea83 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/hint_bg_lightblue.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/hint_bg_lightblue_gray.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/hint_bg_lightblue_gray.9.png new file mode 100644 index 000000000..2135b8a30 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/hint_bg_lightblue_gray.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/list_cell_selected_bg2.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/list_cell_selected_bg2.9.png new file mode 100644 index 000000000..b71c45467 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/list_cell_selected_bg2.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/menu_bg.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/menu_bg.9.png new file mode 100644 index 000000000..b71c45467 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/menu_bg.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/null_white_bg.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/null_white_bg.9.png new file mode 100644 index 000000000..3b6aa1f2b Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/null_white_bg.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/orange_baloon1.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/orange_baloon1.9.png new file mode 100644 index 000000000..485b60a1a Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/orange_baloon1.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/plain_gray1.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/plain_gray1.9.png new file mode 100644 index 000000000..bb92b4f40 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/plain_gray1.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/progress_bar_bg.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/progress_bar_bg.9.png new file mode 100644 index 000000000..bb2391fa3 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/progress_bar_bg.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/progress_bar_bg_v.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/progress_bar_bg_v.9.png new file mode 100644 index 000000000..3f6235849 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/progress_bar_bg_v.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/progress_bar_grean_v.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/progress_bar_grean_v.9.png new file mode 100644 index 000000000..35a39f8bb Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/progress_bar_grean_v.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/progress_bar_green.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/progress_bar_green.9.png new file mode 100644 index 000000000..f4b176d45 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/progress_bar_green.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/query_item_bg_2.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/query_item_bg_2.9.png new file mode 100644 index 000000000..f52b41567 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/query_item_bg_2.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/scroll_bar_h.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/scroll_bar_h.9.png new file mode 100644 index 000000000..653ef0e2e Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/scroll_bar_h.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/scroll_bar_pressed_h.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/scroll_bar_pressed_h.9.png new file mode 100644 index 000000000..bfbb5162f Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/scroll_bar_pressed_h.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/scroll_bar_pressed_v.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/scroll_bar_pressed_v.9.png new file mode 100644 index 000000000..ff7a1733d Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/scroll_bar_pressed_v.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/scroll_bar_rover_h.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/scroll_bar_rover_h.9.png new file mode 100644 index 000000000..1382fc043 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/scroll_bar_rover_h.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/scroll_bar_rover_v.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/scroll_bar_rover_v.9.png new file mode 100644 index 000000000..0af3327c7 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/scroll_bar_rover_v.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/scroll_bar_v.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/scroll_bar_v.9.png new file mode 100644 index 000000000..8b187aed9 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/scroll_bar_v.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/scroll_pane_bg1.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/scroll_pane_bg1.9.png new file mode 100644 index 000000000..443e8a808 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/scroll_pane_bg1.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/shadow1.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/shadow1.9.png new file mode 100644 index 000000000..c2c135c46 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/shadow1.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/shadow2.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/shadow2.9.png new file mode 100644 index 000000000..304cf82c2 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/shadow2.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/shadow_bg_popup.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/shadow_bg_popup.9.png new file mode 100644 index 000000000..08845d6e7 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/shadow_bg_popup.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/shadow_bg_tooltip2.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/shadow_bg_tooltip2.9.png new file mode 100644 index 000000000..3a5dde252 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/shadow_bg_tooltip2.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/slider_track2.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/slider_track2.9.png new file mode 100644 index 000000000..10c090273 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/slider_track2.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/slider_track2_dark.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/slider_track2_dark.9.png new file mode 100644 index 000000000..bc63449af Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/slider_track2_dark.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/slider_track2_forgroud.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/slider_track2_forgroud.9.png new file mode 100644 index 000000000..f5a387e43 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/slider_track2_forgroud.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/slider_track2_forgroud_disable.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/slider_track2_forgroud_disable.9.png new file mode 100644 index 000000000..65cf89d1e Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/slider_track2_forgroud_disable.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/slider_track2_forgroud_v.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/slider_track2_forgroud_v.9.png new file mode 100644 index 000000000..fcbc5a73c Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/slider_track2_forgroud_v.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/slider_track2_forgroud_v_disable.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/slider_track2_forgroud_v_disable.9.png new file mode 100644 index 000000000..ecd9fc6b4 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/slider_track2_forgroud_v_disable.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/slider_track2_v.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/slider_track2_v.9.png new file mode 100644 index 000000000..f4c1aa5a1 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/slider_track2_v.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/slider_track2_v_dark.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/slider_track2_v_dark.9.png new file mode 100644 index 000000000..5d2eef8e5 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/slider_track2_v_dark.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/spinner1_bg.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/spinner1_bg.9.png new file mode 100644 index 000000000..ee3ed8640 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/spinner1_bg.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/spinner1_btn_down_bg.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/spinner1_btn_down_bg.9.png new file mode 100644 index 000000000..d583a0691 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/spinner1_btn_down_bg.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/spinner1_btn_down_pressed_bg.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/spinner1_btn_down_pressed_bg.9.png new file mode 100644 index 000000000..ea636b573 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/spinner1_btn_down_pressed_bg.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/spinner1_btn_up_bg.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/spinner1_btn_up_bg.9.png new file mode 100644 index 000000000..21a6103f9 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/spinner1_btn_up_bg.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/spinner1_btn_up_pressed_bg.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/spinner1_btn_up_pressed_bg.9.png new file mode 100644 index 000000000..fc6e40147 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/spinner1_btn_up_pressed_bg.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/spinner1_disable_bg.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/spinner1_disable_bg.9.png new file mode 100644 index 000000000..c8c1f5736 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/spinner1_disable_bg.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/split_touch_bg1.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/split_touch_bg1.9.png new file mode 100644 index 000000000..81bde58ac Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/split_touch_bg1.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/table_header_bg1.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/table_header_bg1.9.png new file mode 100644 index 000000000..878f78235 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/table_header_bg1.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/table_header_separator1.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/table_header_separator1.9.png new file mode 100644 index 000000000..a2d19c6e8 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/table_header_separator1.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/table_scrollborder1.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/table_scrollborder1.9.png new file mode 100644 index 000000000..db0ef8872 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/table_scrollborder1.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/tips_bg.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/tips_bg.9.png new file mode 100644 index 000000000..614279b28 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/tips_bg.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/toggle_button_rover.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/toggle_button_rover.9.png new file mode 100644 index 000000000..85aef0fc6 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/toggle_button_rover.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/toggle_button_selected.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/toggle_button_selected.9.png new file mode 100644 index 000000000..d71e39502 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/toggle_button_selected.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/toolbar_bg1.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/toolbar_bg1.9.png new file mode 100644 index 000000000..dbfdde138 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/toolbar_bg1.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/toolbar_bg1_EAST.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/toolbar_bg1_EAST.9.png new file mode 100644 index 000000000..ab64686ae Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/toolbar_bg1_EAST.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/toolbar_bg1_SOUTH.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/toolbar_bg1_SOUTH.9.png new file mode 100644 index 000000000..707e93e8d Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/toolbar_bg1_SOUTH.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/toolbar_bg1_WEST.9.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/toolbar_bg1_WEST.9.png new file mode 100644 index 000000000..b44edd495 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/np/toolbar_bg1_WEST.9.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/question.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/question.png new file mode 100644 index 000000000..8d76136f5 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/question.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/radio_btn.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/radio_btn.png new file mode 100644 index 000000000..0555fd6c0 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/radio_btn.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/radio_btn_disabled_normal.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/radio_btn_disabled_normal.png new file mode 100644 index 000000000..8ff03034f Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/radio_btn_disabled_normal.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/radio_btn_disabled_selected.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/radio_btn_disabled_selected.png new file mode 100644 index 000000000..d6b2a45e6 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/radio_btn_disabled_selected.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/radio_btn_over.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/radio_btn_over.png new file mode 100644 index 000000000..e61b940bc Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/radio_btn_over.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/radio_btn_pressed.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/radio_btn_pressed.png new file mode 100644 index 000000000..59ef38126 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/radio_btn_pressed.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/radio_btn_selected.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/radio_btn_selected.png new file mode 100644 index 000000000..f342194d1 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/radio_btn_selected.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/radio_btn_selected_over.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/radio_btn_selected_over.png new file mode 100644 index 000000000..869f43493 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/radio_btn_selected_over.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/radio_btn_selected_pressed.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/radio_btn_selected_pressed.png new file mode 100644 index 000000000..7f0aa27ff Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/radio_btn_selected_pressed.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/slider_tick1.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/slider_tick1.png new file mode 100644 index 000000000..5517c7dba Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/slider_tick1.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/slider_tick1_dark.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/slider_tick1_dark.png new file mode 100644 index 000000000..600cb9040 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/slider_tick1_dark.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/slider_tick1_notrangle.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/slider_tick1_notrangle.png new file mode 100644 index 000000000..e845918b0 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/slider_tick1_notrangle.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/slider_tick1_notrangle_dark.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/slider_tick1_notrangle_dark.png new file mode 100644 index 000000000..230f576e3 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/slider_tick1_notrangle_dark.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/slider_tick1_notrangle_v.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/slider_tick1_notrangle_v.png new file mode 100644 index 000000000..d875bbe46 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/slider_tick1_notrangle_v.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/slider_tick1_notrangle_v_dark.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/slider_tick1_notrangle_v_dark.png new file mode 100644 index 000000000..dc1b41cdf Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/slider_tick1_notrangle_v_dark.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/slider_tick1_v.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/slider_tick1_v.png new file mode 100644 index 000000000..554fcdcd0 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/slider_tick1_v.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/slider_tick1_v_dark.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/slider_tick1_v_dark.png new file mode 100644 index 000000000..06c56a1ec Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/slider_tick1_v_dark.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/treeDefaultClosed1.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/treeDefaultClosed1.png new file mode 100644 index 000000000..59d697799 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/treeDefaultClosed1.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/treeDefaultOpen1.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/treeDefaultOpen1.png new file mode 100644 index 000000000..661a77ca5 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/treeDefaultOpen1.png differ diff --git a/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/warn.png b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/warn.png new file mode 100644 index 000000000..ad841c163 Binary files /dev/null and b/HMCLaF/src/main/resources/org/jackhuang/hmcl/laf/utils/imgs/warn.png differ