Browse Source

Made PopupMenus heavyweight by default.

Added shadows to popupmenus on windows.
Added demo for PopupMenu.
Removed duplicate line in jni-library.gradle.kts
pull/109/head
weisj 5 years ago
parent
commit
5fcf020ace
  1. 1
      buildSrc/src/main/kotlin/jni-library.gradle.kts
  2. 25
      core/src/main/java/com/github/weisj/darklaf/DarkLaf.java
  3. 74
      core/src/main/java/com/github/weisj/darklaf/decorators/MouseDelegate.java
  4. 5
      core/src/main/java/com/github/weisj/darklaf/platform/Decorations.java
  5. 42
      core/src/main/java/com/github/weisj/darklaf/ui/menu/DarkMenuUI.java
  6. 2
      core/src/main/java/com/github/weisj/darklaf/ui/popupmenu/DarkPopupMenuUI.java
  7. 13
      core/src/main/resources/com/github/weisj/darklaf/properties/platform/mac.properties
  8. 9
      core/src/main/resources/com/github/weisj/darklaf/properties/platform/windows.properties
  9. 9
      core/src/main/resources/com/github/weisj/darklaf/properties/ui/popupMenu.properties
  10. 67
      core/src/test/java/ui/popupMenu/PopupMenuDemo.java
  11. 7
      decorations-base/src/main/java/com/github/weisj/darklaf/decorations/DecorationsProvider.java
  12. 47
      windows/src/main/cpp/JNIDecorations.cpp
  13. 3
      windows/src/main/cpp/JNIDecorations.h
  14. 2
      windows/src/main/java/com/github/weisj/darklaf/platform/windows/JNIDecorationsWindows.java
  15. 21
      windows/src/main/java/com/github/weisj/darklaf/platform/windows/WindowsDecorationsProvider.java

1
buildSrc/src/main/kotlin/jni-library.gradle.kts

@ -104,7 +104,6 @@ afterEvaluate {
binary.linkTask.get().debuggable.set(false)
//Build and copy library
dependsOn(binary.linkTask)
val variantName = binary.targetMachine.variantName
into("$libraryPath/$variantName") {
from(binary.runtimeFile)
}

25
core/src/main/java/com/github/weisj/darklaf/DarkLaf.java

@ -119,7 +119,12 @@ public class DarkLaf extends BasicLookAndFeel implements PropertyChangeListener
patchMacOSFonts(defaults);
}
setupDecorations();
String key = DarkPopupMenuUI.KEY_DEFAULT_LIGHTWEIGHT_POPUPS;
if (SystemInfo.isWindows10 && Decorations.isCustomDecorationSupported()) {
JPopupMenu.setDefaultLightWeightPopupEnabled(defaults.getBoolean(key + ".windows"));
} else {
JPopupMenu.setDefaultLightWeightPopupEnabled(defaults.getBoolean(key));
}
return defaults;
} catch (final Exception e) {
LOGGER.log(Level.SEVERE, e.toString(), e.getStackTrace());
@ -349,7 +354,23 @@ public class DarkLaf extends BasicLookAndFeel implements PropertyChangeListener
* This is disadvantageous for the behaviour of custom tooltips.
*/
call("initialize");
PopupFactory.setSharedInstance(new PopupFactory());
PopupFactory.setSharedInstance(new PopupFactory() {
@Override
public Popup getPopup(final Component owner, final Component contents,
final int x, final int y) throws IllegalArgumentException {
Popup popup = super.getPopup(owner, contents, x, y);
// Sometimes the background is java.awt.SystemColor[i=7]
// It results in a flash of white background that is repainted with
// the proper popup background later.
// That is why we set window background explicitly.
Window window = SwingUtilities.getWindowAncestor(contents);
if (window != null) {
window.setBackground(UIManager.getColor("PopupMenu.translucentBackground"));
Decorations.initPopupWindow(window);
}
return popup;
}
});
PropertyLoader.reset();
UIManager.addPropertyChangeListener(this);
}

74
core/src/main/java/com/github/weisj/darklaf/decorators/MouseDelegate.java

@ -0,0 +1,74 @@
/*
* MIT License
*
* Copyright (c) 2020 Jannis Weis
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.github.weisj.darklaf.decorators;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
public class MouseDelegate implements MouseListener {
protected MouseListener delegate;
public MouseDelegate(final MouseListener delegate) {
setDelegate(delegate);
}
public MouseListener getDelegate() {
return delegate;
}
public void setDelegate(final MouseListener delegate) {
this.delegate = delegate;
if (delegate == null) {
this.delegate = new MouseAdapter() {
};
}
}
@Override
public void mouseClicked(final MouseEvent e) {
delegate.mouseClicked(e);
}
@Override
public void mousePressed(final MouseEvent e) {
delegate.mousePressed(e);
}
@Override
public void mouseReleased(final MouseEvent e) {
delegate.mousePressed(e);
}
@Override
public void mouseEntered(final MouseEvent e) {
delegate.mouseEntered(e);
}
@Override
public void mouseExited(final MouseEvent e) {
delegate.mouseExited(e);
}
}

5
core/src/main/java/com/github/weisj/darklaf/platform/Decorations.java

@ -33,6 +33,7 @@ import com.github.weisj.darklaf.util.PropertyValue;
import com.github.weisj.darklaf.util.SystemInfo;
import javax.swing.*;
import java.awt.*;
import java.util.Properties;
public final class Decorations {
@ -63,6 +64,10 @@ public final class Decorations {
return decorationsProvider.createTitlePane(rootPane, decorationStyle);
}
public static void initPopupWindow(final Window window) {
decorationsProvider.initPopupWindow(window);
}
public static boolean isCustomDecorationSupported() {
return decorationsProvider.isCustomDecorationSupported()

42
core/src/main/java/com/github/weisj/darklaf/ui/menu/DarkMenuUI.java

@ -23,6 +23,7 @@
*/
package com.github.weisj.darklaf.ui.menu;
import com.github.weisj.darklaf.decorators.MouseDelegate;
import com.github.weisj.darklaf.util.DarkUIUtil;
import com.github.weisj.darklaf.util.GraphicsContext;
import com.github.weisj.darklaf.util.GraphicsUtil;
@ -34,15 +35,56 @@ import javax.swing.*;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicMenuUI;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
public class DarkMenuUI extends BasicMenuUI {
protected Icon arrowIconHover;
protected JMenu menu;
protected MouseListener mouseListener;
public static ComponentUI createUI(final JComponent x) {
return new DarkMenuUI();
}
@Override
public void installUI(final JComponent c) {
menu = (JMenu) c;
super.installUI(c);
}
@Override
protected void installListeners() {
super.installListeners();
for (MouseListener listener : menu.getMouseListeners()) {
if (listener.getClass().getEnclosingClass().equals(BasicMenuUI.class)) {
menu.removeMouseListener(listener);
mouseListener = new MouseDelegate(listener) {
@Override
public void mouseEntered(final MouseEvent e) {
MenuSelectionManager manager = MenuSelectionManager.defaultManager();
MenuElement[] selectedPath = manager.getSelectedPath();
for (MenuElement element : selectedPath) {
if (element.equals(menu)) {
return;
}
}
super.mouseEntered(e);
}
};
menu.addMouseListener(mouseListener);
break;
}
}
}
@Override
protected void uninstallListeners() {
super.uninstallListeners();
menu.removeMouseListener(mouseListener);
}
@Override
protected void installDefaults() {
super.installDefaults();

2
core/src/main/java/com/github/weisj/darklaf/ui/popupmenu/DarkPopupMenuUI.java

@ -57,7 +57,7 @@ public class DarkPopupMenuUI extends BasicPopupMenuUI {
"doNotCancelPopup"));
public static final StringBuilder MOUSE_GRABBER_KEY = new StringBuilder(
"javax.swing.plaf.basic.BasicPopupMenuUI.MouseGrabber");
public static final String KEY_DEFAULT_LIGHTWEIGHT_POPUPS = "PopupMenu.defaultLightWeightPopups";
public static ComponentUI createUI(final JComponent x) {
return new DarkPopupMenuUI();

13
core/src/main/resources/com/github/weisj/darklaf/properties/platform/mac.properties

@ -14,9 +14,10 @@
# limitations under the License.
#
# suppress inspection "UnusedProperty" for whole file
Table.alternateRowColor = true
Tree.alternateRowColor = true
List.alternateRowColor = true
FileChooser.listViewWindowsStyle = false
CheckBox.borderInsets = 2,2,2,2
RadioButton.borderInsets = 2,2,2,2
Table.alternateRowColor = true
Tree.alternateRowColor = true
List.alternateRowColor = true
FileChooser.listViewWindowsStyle = false
CheckBox.borderInsets = 2,2,2,2
RadioButton.borderInsets = 2,2,2,2
PopupMenu.defaultLightWeightPopups = false

9
core/src/main/resources/com/github/weisj/darklaf/properties/platform/windows.properties

@ -21,8 +21,9 @@
#SOFTWARE.
#
# suppress inspection "UnusedProperty" for whole file
FileChooser.listViewWindowsStyle = true
FileChooser.listViewWindowsStyle = true
Table.alternateRowColor = false
Tree.alternateRowColor = false
List.alternateRowColor = false
Table.alternateRowColor = false
Tree.alternateRowColor = false
List.alternateRowColor = false
PopupMenu.defaultLightWeightPopups.windows = false

9
core/src/main/resources/com/github/weisj/darklaf/properties/ui/popupMenu.properties

@ -22,7 +22,8 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
PopupMenuUI = com.github.weisj.darklaf.ui.popupmenu.DarkPopupMenuUI
PopupMenu.border = com.github.weisj.darklaf.ui.popupmenu.DarkPopupMenuBorder
PopupMenu.translucentBackground = %backgroundContainer
PopupMenu.borderColor = %borderSecondary
PopupMenuUI = com.github.weisj.darklaf.ui.popupmenu.DarkPopupMenuUI
PopupMenu.border = com.github.weisj.darklaf.ui.popupmenu.DarkPopupMenuBorder
PopupMenu.translucentBackground = %backgroundContainer
PopupMenu.borderColor = %borderSecondary
PopupMenu.defaultLightWeightPopups = true

67
core/src/test/java/ui/popupMenu/PopupMenuDemo.java

@ -0,0 +1,67 @@
/*
* MIT License
*
* Copyright (c) 2020 Jannis Weis
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package ui.popupMenu;
import ui.ComponentDemo;
import javax.swing.*;
import java.awt.*;
public class PopupMenuDemo implements ComponentDemo {
public static void main(final String[] args) {
ComponentDemo.showDemo(new PopupMenuDemo());
}
@Override
public JComponent createComponent() {
JPanel panel = new JPanel();
panel.setLayout(new GridBagLayout());
panel.add(new JLabel("Right click anywhere to open menu.") {{
setInheritsPopupMenu(true);
}});
panel.setPreferredSize(new Dimension(200, 200));
panel.setComponentPopupMenu(new JPopupMenu() {{
for (int i = 0; i < 3; i++) {
add(new JMenu("Menu " + i) {{
for (int j = 0; j < 2; j++) {
add(new JMenu("SubMenu " + j) {{
add(new JMenuItem("Item"));
}});
add(new JMenuItem("Item 1"));
add(new JMenuItem("Item 2"));
}
add(new JMenuItem("Item 1"));
add(new JMenuItem("Item 2"));
}});
}
}});
return panel;
}
@Override
public String getTitle() {
return "PopupMenu Demo";
}
}

7
decorations-base/src/main/java/com/github/weisj/darklaf/decorations/DecorationsProvider.java

@ -24,6 +24,7 @@
package com.github.weisj.darklaf.decorations;
import javax.swing.*;
import java.awt.*;
import java.util.Properties;
public interface DecorationsProvider {
@ -57,4 +58,10 @@ public interface DecorationsProvider {
* @param currentDefaults the current ui defaults.
*/
void loadDecorationProperties(Properties properties, UIDefaults currentDefaults);
/**
* Initialize the window of a popup menu.
*/
default void initPopupWindow(final Window window) {
}
}

47
windows/src/main/cpp/JNIDecorations.cpp

@ -34,6 +34,7 @@ std::map<HWND, WindowWrapper *> wrapper_map = std::map<HWND, WindowWrapper *>();
LRESULT HitTestNCA(HWND hWnd, WPARAM wParam, LPARAM lParam, WindowWrapper *wrapper)
{
if (wrapper->popup_menu) return HTCLIENT;
// Get the point coordinates for the hit test.
POINT ptMouse = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
@ -75,7 +76,9 @@ LRESULT HitTestNCA(HWND hWnd, WPARAM wParam, LPARAM lParam, WindowWrapper *wrapp
if (hit == HTNOWHERE || !wrapper->resizable)
{
//Handle window drag.
if (ptMouse.y < rcWindow.top + wrapper->height && ptMouse.x >= rcWindow.left + wrapper->left && ptMouse.x <= rcWindow.right - wrapper->right)
if (ptMouse.y < rcWindow.top + wrapper->height
&& ptMouse.x >= rcWindow.left + wrapper->left
&& ptMouse.x <= rcWindow.right - wrapper->right)
{
return HTCAPTION;
}
@ -165,32 +168,43 @@ Java_com_github_weisj_darklaf_platform_windows_JNIDecorationsWindows_setBackgrou
}
}
JNIEXPORT void JNICALL
Java_com_github_weisj_darklaf_platform_windows_JNIDecorationsWindows_installDecorations(JNIEnv *env, jclass obj, jlong hwnd)
void extend_client_frame(HWND handle)
{
HWND handle = reinterpret_cast<HWND>(hwnd);
auto it = wrapper_map.find(handle);
if (it != wrapper_map.end())
{
//Prevent multiple installations overriding the real window procedure.
return;
}
MARGINS margins = {0, 0, 0, 1};
DwmExtendFrameIntoClientArea(handle, &margins);
}
void setup_window_style(HWND handle)
{
auto style = GetWindowLongPtr(handle, GWL_STYLE);
SetWindowLongPtr(handle, GWL_STYLE, style | WS_THICKFRAME);
}
void install_decorations(HWND handle, bool is_popup)
{
//Prevent multiple installations overriding the real window procedure.
auto it = wrapper_map.find(handle);
if (it != wrapper_map.end()) return;
extend_client_frame(handle);
setup_window_style(handle);
SetWindowPos(handle, NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
WNDPROC proc = reinterpret_cast<WNDPROC>(GetWindowLongPtr(handle, GWL_WNDPROC));
WindowWrapper *wrapper = new WindowWrapper();
wrapper->prev_proc = proc;
wrapper->popup_menu = is_popup;
wrapper_map[handle] = wrapper;
SetWindowLongPtr((HWND)hwnd, GWL_WNDPROC, (LONG_PTR)WindowWrapper::WindowProc);
SetWindowLongPtr(handle, GWL_WNDPROC, (LONG_PTR)WindowWrapper::WindowProc);
}
JNIEXPORT void JNICALL
Java_com_github_weisj_darklaf_platform_windows_JNIDecorationsWindows_installDecorations(JNIEnv *env, jclass obj, jlong hwnd)
{
HWND handle = reinterpret_cast<HWND>(hwnd);
install_decorations(handle, false);
}
JNIEXPORT void JNICALL
@ -206,6 +220,13 @@ Java_com_github_weisj_darklaf_platform_windows_JNIDecorationsWindows_uninstallDe
}
}
JNIEXPORT void JNICALL
Java_com_github_weisj_darklaf_platform_windows_JNIDecorationsWindows_installPopupMenuDecorations(JNIEnv *env, jclass obj, jlong hwnd)
{
HWND handle = reinterpret_cast<HWND>(hwnd);
install_decorations(handle, true);
}
//Window functions.
JNIEXPORT void JNICALL

3
windows/src/main/cpp/JNIDecorations.h

@ -29,6 +29,7 @@ class WindowWrapper
{
public:
bool resizable = true;
bool popup_menu = false;
WNDPROC prev_proc;
COLORREF background = RGB(255, 255, 255);
@ -37,4 +38,4 @@ public:
int height = 0;
static LRESULT CALLBACK WindowProc(_In_ HWND hwnd, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam);
};
};

2
windows/src/main/java/com/github/weisj/darklaf/platform/windows/JNIDecorationsWindows.java

@ -54,6 +54,8 @@ public class JNIDecorationsWindows {
public static native void uninstallDecorations(final long hwnd);
public static native void installPopupMenuDecorations(final long hwnd);
/**
* Load the decorations-library if necessary.
*/

21
windows/src/main/java/com/github/weisj/darklaf/platform/windows/WindowsDecorationsProvider.java

@ -27,9 +27,13 @@ import com.github.weisj.darklaf.PropertyLoader;
import com.github.weisj.darklaf.decorations.CustomTitlePane;
import com.github.weisj.darklaf.decorations.DecorationsProvider;
import com.github.weisj.darklaf.icons.IconLoader;
import com.github.weisj.darklaf.platform.PointerUtil;
import com.github.weisj.darklaf.platform.windows.ui.WindowsTitlePane;
import javax.swing.*;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Properties;
public class WindowsDecorationsProvider implements DecorationsProvider {
@ -49,6 +53,23 @@ public class WindowsDecorationsProvider implements DecorationsProvider {
JNIDecorationsWindows.updateLibrary();
}
@Override
public void initPopupWindow(final Window window) {
if (!window.isDisplayable()) {
window.addNotify();
}
long hwnd = PointerUtil.getHWND(window);
if (hwnd != 0) {
JNIDecorationsWindows.installPopupMenuDecorations(hwnd);
window.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(final WindowEvent e) {
JNIDecorationsWindows.uninstallDecorations(hwnd);
}
});
}
}
@Override
public void loadDecorationProperties(final Properties properties, final UIDefaults currentDefaults) {
IconLoader iconLoader = IconLoader.get(WindowsDecorationsProvider.class);

Loading…
Cancel
Save