[Editor only] Undecorated style for macOS

This commit is contained in:
fgnm
2022-01-30 18:33:08 +01:00
parent a1cd3969f4
commit cfcaedbe04
6 changed files with 135 additions and 21 deletions
+1 -1
View File
@@ -6,7 +6,7 @@
= Editor =
- New polygons management with open-ended shapes
- Fully undecorated in Windows OS
- Fully undecorated in Windows OS and macOS
- Better UI
= Runtime =
@@ -76,6 +76,9 @@ public class HyperLap2DApp extends ApplicationAdapter {
if (SystemUtils.IS_OS_WINDOWS) {
Gdx.app.postRunnable(() -> HyperLap2DUtils.overwriteWindowProc2(mainWindow.getWindowHandle()));
}
if (SystemUtils.IS_OS_MAC) {
Gdx.app.postRunnable(() -> HyperLap2DUtils.setCocoaCustomTitleBar(mainWindow.getWindowHandle(), true));
}
});
}
@@ -118,7 +118,7 @@ public class FontManager extends Proxy {
systemFontMap.put(f.getName(), file.getAbsolutePath());
}
} catch (FontFormatException | IOException e) {
e.printStackTrace();
System.err.println("Could not load " + file.getName() + " font file.");
}
}
@@ -2,6 +2,9 @@ package games.rednblack.editor.utils;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.InputListener;
import games.rednblack.editor.HyperLap2DFacade;
import games.rednblack.editor.view.ui.UIWindowTitle;
import games.rednblack.editor.view.ui.UIWindowTitleMediator;
@@ -9,9 +12,12 @@ import org.apache.commons.io.filefilter.SuffixFileFilter;
import org.apache.commons.lang3.SystemUtils;
import org.lwjgl.BufferUtils;
import org.lwjgl.glfw.GLFW;
import org.lwjgl.glfw.GLFWNativeCocoa;
import org.lwjgl.glfw.GLFWNativeWin32;
import org.lwjgl.system.JNI;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.system.SharedLibrary;
import org.lwjgl.system.macosx.ObjCRuntime;
import org.lwjgl.system.windows.RECT;
import org.lwjgl.system.windows.User32;
import org.lwjgl.system.windows.WINDOWPLACEMENT;
@@ -20,6 +26,7 @@ import org.lwjgl.system.windows.WindowProc;
import java.io.File;
import java.io.FilenameFilter;
import java.nio.DoubleBuffer;
import java.nio.IntBuffer;
public class HyperLap2DUtils {
public static final FilenameFilter PNG_FILTER = new SuffixFileFilter(".png");
@@ -46,6 +53,114 @@ public class HyperLap2DUtils {
return System.getProperty("user.home") + File.separator + "Documents";
}
/**
* Fairly based on this article: http://svenandersson.se/2016/rendering-to-full-size-of-an-nswindow-using-glfw3.html
* Still not finished (Window dragging is not working) but useful stuff here to interact with native OS
*
* @param lwjglWindow lwjgl pointer to window object
* @param FullSizeContentView apply the FullSizeContentView styleMask
*/
public static void setCocoaCustomTitleBar(long lwjglWindow, boolean FullSizeContentView) {
System.out.println(lwjglWindow);
long nswindow = GLFWNativeCocoa.glfwGetCocoaWindow(lwjglWindow);
System.out.println(nswindow);
SharedLibrary objc = ObjCRuntime.getLibrary();
long objc_msgSend = objc.getFunctionAddress("objc_msgSend");
boolean bool = JNI.invokePPZ(nswindow, ObjCRuntime.sel_getUid("titlebarAppearsTransparent"), objc_msgSend);
System.out.println("titlebarAppearsTransparent = " + bool);
JNI.invokePPV(nswindow, ObjCRuntime.sel_getUid("setTitlebarAppearsTransparent:"), true, objc_msgSend);
JNI.invokePPV(nswindow, ObjCRuntime.sel_getUid("setMovableByWindowBackground:"), true, objc_msgSend);
bool = JNI.invokePPZ(nswindow, ObjCRuntime.sel_getUid("titlebarAppearsTransparent"), objc_msgSend);
System.out.println("titlebarAppearsTransparent = " + bool);
long NSColor = ObjCRuntime.objc_getClass("NSColor");
long darkGrayColor = JNI.invokePPP(NSColor, ObjCRuntime.sel_getUid("darkGrayColor"), objc_msgSend);
JNI.invokePPPV(nswindow, ObjCRuntime.sel_getUid("setBackgroundColor:"), darkGrayColor, objc_msgSend);
//0 - visible
//1 - hidden
JNI.invokePPV(nswindow, ObjCRuntime.sel_getUid("setTitleVisibility:"), 1, objc_msgSend);
if (FullSizeContentView) {
//Borderless - 0b0000000000000000
//Titled - 0b0000000000000001
//Closable - 0b0000000000000010
//Miniaturizable - 0b0000000000000100
//Resizable - 0b0000000000001000
//UtilityWindow - 0b0000000000010000
//DocumentModalWindow - 0b0000000001000000
//NonActivatingPanel - 0b0000000010000000
//Textured - 0b0000000100000000
//UnifiedTitleAndToolbar - 0b0001000000000000
//HudWindow - 0b0010000000000000
//FullScreen - 0b0100000000000000
//FullSizeContentView - 0b1000000000010010
JNI.invokePPV(nswindow, ObjCRuntime.sel_getUid("setStyleMask:"), 0b1001000000001111, objc_msgSend);
int defaultMask = JNI.invokePPI(nswindow, ObjCRuntime.sel_getUid("styleMask"), objc_msgSend);
System.out.println("styleMask = " + defaultMask);
GLFW.glfwMaximizeWindow(lwjglWindow);
/**
* NSView* glView = [wnd contentView];
* Method originalMethod = class_getInstanceMethod([glView class], @selector(mouseDownCanMoveWindow));
* Method categoryMethod = class_getInstanceMethod(FakeView.class, @selector(fakeMouseDownCanMoveWindow));
* method_exchangeImplementations(originalMethod, categoryMethod);
*/
/*long glView = JNI.invokePPP(nswindow, ObjCRuntime.sel_getUid("contentView"), objc_msgSend);
System.out.println("glView: " + glView);
long glViewClass = ObjCRuntime.object_getClass(glView);
System.out.println("glViewClass: " + glViewClass);
long originalMethod = ObjCRuntime.class_getInstanceMethod(glViewClass, ObjCRuntime.sel_getUid("mouseDownCanMoveWindow"));
System.out.println("originalMethod: " + originalMethod);
//TODO Missing a way to create the categoryMethod
ObjCRuntime.method_exchangeImplementations(originalMethod, categoryMethod);
*/
}
}
public static void setWindowDragListener(Actor actor) {
actor.addListener(new InputListener() {
private final long context = GLFW.glfwGetCurrentContext();
private float startX = 0;
private float startY = 0;
private final DoubleBuffer cursorX = BufferUtils.createDoubleBuffer(1);
private final DoubleBuffer cursorY = BufferUtils.createDoubleBuffer(1);
private final IntBuffer windowX = BufferUtils.createIntBuffer(1);
private final IntBuffer windowY = BufferUtils.createIntBuffer(1);
private int getX() {
return MathUtils.floor((float) cursorX.get(0));
}
private int getY() {
return MathUtils.floor((float) cursorY.get(0));
}
@Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
GLFW.glfwGetCursorPos(context, cursorX, cursorY);
startX = getX();
startY = getY();
return true;
}
@Override
public void touchDragged(InputEvent event, float x, float y, int pointer) {
GLFW.glfwGetCursorPos(context, cursorX, cursorY);
float offsetX = getX() - startX;
float offsetY = getY() - startY;
GLFW.glfwGetWindowPos(context, windowX, windowY);
GLFW.glfwSetWindowPos(context, (int)(windowX.get(0) + offsetX), (int)(windowY.get(0) + offsetY));
}
});
}
/**
* Function to override Windows behavior to use undecorated style while preserving snap to edge and resize.
* Works only on Windows OS
@@ -20,6 +20,7 @@ package games.rednblack.editor.view.ui;
import com.kotcrab.vis.ui.widget.VisTable;
import games.rednblack.editor.HyperLap2DFacade;
import games.rednblack.editor.utils.HyperLap2DUtils;
import games.rednblack.editor.view.menu.HyperLap2DMenuBar;
import games.rednblack.editor.view.menu.HyperLap2DMenuBarMediator;
import games.rednblack.editor.view.ui.box.*;
@@ -65,6 +66,13 @@ public class UIMainTable extends VisTable {
UIWindowActionMediator uiWindowActionMediator = facade.retrieveMediator(UIWindowActionMediator.NAME);
UIWindowAction uiWindowAction = uiWindowActionMediator.getViewComponent();
topTable.add(uiWindowAction).padTop(-1).fillY();
} else if (SystemUtils.IS_OS_MAC) {
topTable.add(menuBar.getTable()).height(32);
UIWindowTitleMediator uiWindowTitleMediator = facade.retrieveMediator(UIWindowTitleMediator.NAME);
UIWindowTitle uiWindowTitle = uiWindowTitleMediator.getViewComponent();
HyperLap2DUtils.setWindowDragListener(uiWindowTitle);
topTable.add(uiWindowTitle).growX().fillY();
} else {
topTable.add(menuBar.getTable()).growX().height(32);
}
@@ -1,21 +1,3 @@
/*
* ******************************************************************************
* * Copyright 2015 See AUTHORS file.
* *
* * Licensed under the Apache License, Version 2.0 (the "License");
* * you may not use this file except in compliance with the License.
* * You may obtain a copy of the License at
* *
* * http://www.apache.org/licenses/LICENSE-2.0
* *
* * Unless required by applicable law or agreed to in writing, software
* * distributed under the License is distributed on an "AS IS" BASIS,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * See the License for the specific language governing permissions and
* * limitations under the License.
* *****************************************************************************
*/
package games.rednblack.editor.view.ui.widget;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
@@ -25,13 +7,19 @@ import com.kotcrab.vis.ui.VisUI;
import com.kotcrab.vis.ui.widget.VisImage;
import com.kotcrab.vis.ui.widget.VisTable;
import games.rednblack.editor.HyperLap2DApp;
import games.rednblack.editor.HyperLap2DFacade;
import games.rednblack.editor.proxy.SettingsManager;
import org.apache.commons.lang3.SystemUtils;
public class H2DLogo extends VisTable {
public H2DLogo() {
SettingsManager settingsManager = HyperLap2DFacade.getInstance().retrieveProxy(SettingsManager.NAME);
Skin skin = VisUI.getSkin();
setBackground(skin.getDrawable("menu-bg"));
VisImage logo = new VisImage(VisUI.getSkin().getDrawable("logo"));
add(logo).width(logo.getWidth()).height(logo.getHeight()).padLeft(7);
float pad = SystemUtils.IS_OS_MAC ? 73 : 7;
pad *= settingsManager.editorConfigVO.uiScaleDensity;
add(logo).width(logo.getWidth()).height(logo.getHeight()).padLeft(pad);
logo.addListener(new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {