Merge branch 'color-picker' of https://github.com/Menotdan/FlaxEngine into Menotdan-color-picker
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
using FlaxEditor.GUI.Input;
|
||||
using FlaxEditor.Windows;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using System;
|
||||
|
||||
namespace FlaxEditor.GUI.Dialogs
|
||||
{
|
||||
@@ -25,6 +27,7 @@ namespace FlaxEditor.GUI.Dialogs
|
||||
{
|
||||
private const float ButtonsWidth = 60.0f;
|
||||
private const float PickerMargin = 6.0f;
|
||||
private const float EyedropperMargin = 8.0f;
|
||||
private const float RGBAMargin = 12.0f;
|
||||
private const float HSVMargin = 0.0f;
|
||||
private const float ChannelsMargin = 4.0f;
|
||||
@@ -34,6 +37,7 @@ namespace FlaxEditor.GUI.Dialogs
|
||||
private Color _value;
|
||||
private bool _disableEvents;
|
||||
private bool _useDynamicEditing;
|
||||
private bool _activeEyedropper;
|
||||
private ColorValueBox.ColorPickerEvent _onChanged;
|
||||
private ColorValueBox.ColorPickerClosedEvent _onClosed;
|
||||
|
||||
@@ -48,6 +52,7 @@ namespace FlaxEditor.GUI.Dialogs
|
||||
private TextBox _cHex;
|
||||
private Button _cCancel;
|
||||
private Button _cOK;
|
||||
private IconButton _cEyedropper;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the selected color.
|
||||
@@ -104,6 +109,7 @@ namespace FlaxEditor.GUI.Dialogs
|
||||
{
|
||||
_initialValue = initialValue;
|
||||
_useDynamicEditing = useDynamicEditing;
|
||||
_activeEyedropper = false;
|
||||
_value = Color.Transparent;
|
||||
_onChanged = colorChanged;
|
||||
_onClosed = pickerClosed;
|
||||
@@ -192,10 +198,49 @@ namespace FlaxEditor.GUI.Dialogs
|
||||
};
|
||||
_cOK.Clicked += OnSubmit;
|
||||
|
||||
// Eyedropper button
|
||||
_cEyedropper = new IconButton(_cOK.X - EyedropperMargin, _cHex.Bottom + PickerMargin, Editor.Instance.Icons.Add64, hideBorder: false)
|
||||
{
|
||||
Parent = this,
|
||||
};
|
||||
_cEyedropper.Clicked += OnEyedropStart;
|
||||
_cEyedropper.Height = (_cValue.Bottom - _cEyedropper.Y) * 0.5f;
|
||||
_cEyedropper.Width = _cEyedropper.Height;
|
||||
_cEyedropper.X -= _cEyedropper.Width;
|
||||
//_cEyedropper.SetColors(_cEyedropper.BackgroundColor);
|
||||
|
||||
// Set initial color
|
||||
SelectedColor = initialValue;
|
||||
}
|
||||
|
||||
private Color32 GetEyedropColor()
|
||||
{
|
||||
Int2 mousePosition = ScreenUtilities.GetScreenCursorPosition();
|
||||
Color32 pixelColor = ScreenUtilities.GetPixelAt(mousePosition.X, mousePosition.Y);
|
||||
|
||||
return pixelColor;
|
||||
}
|
||||
|
||||
private void ColorPicked(Color32 colorPicked)
|
||||
{
|
||||
_activeEyedropper = false;
|
||||
SelectedColor = colorPicked;
|
||||
ScreenUtilities.PickColorDone -= ColorPicked;
|
||||
}
|
||||
|
||||
private void OnEyedropStart()
|
||||
{
|
||||
_activeEyedropper = true;
|
||||
ScreenUtilities.PickColor();
|
||||
ScreenUtilities.PickColorDone += ColorPicked;
|
||||
}
|
||||
|
||||
private void UpdateEyedrop()
|
||||
{
|
||||
Color32 pixelColor = GetEyedropColor();
|
||||
SelectedColor = pixelColor;
|
||||
}
|
||||
|
||||
private void OnRGBAChanged()
|
||||
{
|
||||
if (_disableEvents)
|
||||
@@ -221,6 +266,18 @@ namespace FlaxEditor.GUI.Dialogs
|
||||
SelectedColor = color;
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Update(float deltaTime)
|
||||
{
|
||||
base.Update(deltaTime);
|
||||
|
||||
if (_activeEyedropper)
|
||||
{
|
||||
UpdateEyedrop();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Draw()
|
||||
{
|
||||
|
||||
40
Source/Editor/Utilities/ScreenUtilities/ScreenUtilities.h
Normal file
40
Source/Editor/Utilities/ScreenUtilities/ScreenUtilities.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#include "Engine/Core/Types/BaseTypes.h"
|
||||
#include "Engine/Core/Delegate.h"
|
||||
|
||||
API_INJECT_CODE(cpp, "#include \"Editor/Utilities/ScreenUtilities/ScreenUtilities.h\"");
|
||||
|
||||
/// <summary>
|
||||
/// Platform-dependent screen utilties.
|
||||
/// </summary>
|
||||
API_CLASS(Static, Name = "ScreenUtilities", Tag = "NativeInvokeUseName")
|
||||
class FLAXENGINE_API ScreenUtilities
|
||||
{
|
||||
public:
|
||||
static struct FLAXENGINE_API ScriptingTypeInitializer TypeInitializer;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the pixel color at the specified coordinates.
|
||||
/// </summary>
|
||||
/// <param name="x">X Coordinate to read.</param>
|
||||
/// <param name="y">Y Coordinate to read.</param>
|
||||
/// <returns>Pixel color at the specified coordinates.</returns>
|
||||
API_FUNCTION() static Color32 GetPixelAt(int32 x, int32 y);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the cursor position, in screen cooridnates.
|
||||
/// </summary>
|
||||
/// <returns>Cursor position, in screen coordinates.</returns>
|
||||
API_FUNCTION() static Int2 GetScreenCursorPosition();
|
||||
|
||||
/// <summary>
|
||||
/// Starts async color picking. Will return a color through ColorReturnCallback.
|
||||
/// </summary
|
||||
API_FUNCTION() static void PickColor();
|
||||
|
||||
/// <summary>
|
||||
/// Called when PickColor() is finished.
|
||||
/// </summary>
|
||||
API_EVENT() static Delegate<Color32> PickColorDone;
|
||||
};
|
||||
104
Source/Editor/Utilities/ScreenUtilities/ScreenUtilitiesLinux.cpp
Normal file
104
Source/Editor/Utilities/ScreenUtilities/ScreenUtilitiesLinux.cpp
Normal file
@@ -0,0 +1,104 @@
|
||||
#if PLATFORM_LINUX
|
||||
|
||||
#include "ScreenUtilities.h"
|
||||
#include "Engine/Core/Math/Color32.h"
|
||||
#include "Engine/Core/Math/Vector2.h"
|
||||
#include "Engine/Core/Delegate.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Platform/Linux/LinuxPlatform.h"
|
||||
|
||||
#include "Engine/Platform/Linux/IncludeX11.h"
|
||||
|
||||
Color32 ScreenUtilities::GetPixelAt(int32 x, int32 y)
|
||||
{
|
||||
X11::XColor color;
|
||||
Color32 outputColor;
|
||||
|
||||
X11::Display* display = (X11::Display*) LinuxPlatform::GetXDisplay();
|
||||
int defaultScreen = X11::XDefaultScreen(display);
|
||||
|
||||
X11::XImage* image;
|
||||
image = X11::XGetImage(display, X11::XRootWindow(display, defaultScreen), x, y, 1, 1, AllPlanes, XYPixmap);
|
||||
color.pixel = XGetPixel(image, 0, 0);
|
||||
X11::XFree(image);
|
||||
|
||||
X11::XQueryColor(display, X11::XDefaultColormap(display, defaultScreen), &color);
|
||||
outputColor.R = color.red / 256;
|
||||
outputColor.G = color.green / 256;
|
||||
outputColor.B = color.blue / 256;
|
||||
|
||||
return outputColor;
|
||||
}
|
||||
|
||||
Int2 ScreenUtilities::GetScreenCursorPosition()
|
||||
{
|
||||
Int2 cursorPosition = { 0, 0 };
|
||||
X11::Display* display = (X11::Display*) LinuxPlatform::GetXDisplay();
|
||||
X11::Window rootWindow = X11::XRootWindow(display, X11::XDefaultScreen(display));
|
||||
|
||||
// Buffers (Some useful, some not.)
|
||||
X11::Window rootWindowBuffer;
|
||||
int rootX, rootY;
|
||||
int winXBuffer, winYBuffer;
|
||||
unsigned int maskBuffer;
|
||||
|
||||
int gotPointer = X11::XQueryPointer(display, rootWindow, &rootWindowBuffer, &rootWindowBuffer, &rootX, &rootY, &winXBuffer, &winYBuffer, &maskBuffer);
|
||||
if (!gotPointer) {
|
||||
LOG(Error, "Failed to find the mouse pointer (Are you using multiple displays?)");
|
||||
return cursorPosition;
|
||||
}
|
||||
|
||||
cursorPosition.X = rootX;
|
||||
cursorPosition.Y = rootY;
|
||||
|
||||
return cursorPosition;
|
||||
}
|
||||
|
||||
class ScreenUtilitiesLinux
|
||||
{
|
||||
public:
|
||||
static void BlockAndReadMouse();
|
||||
static void xEventHandler(void* event);
|
||||
};
|
||||
|
||||
void ScreenUtilitiesLinux::xEventHandler(void* eventPtr) {
|
||||
X11::XEvent* event = (X11::XEvent*) eventPtr;
|
||||
|
||||
X11::Display* display = (X11::Display*) LinuxPlatform::GetXDisplay();
|
||||
|
||||
if (event->type == ButtonPress) {
|
||||
Int2 cursorPosition = ScreenUtilities::GetScreenCursorPosition();
|
||||
Color32 colorPicked = ScreenUtilities::GetPixelAt(cursorPosition.X, cursorPosition.Y);
|
||||
|
||||
ScreenUtilities::PickColorDone(colorPicked); // Run the callback for picking colors being complete.
|
||||
LinuxPlatform::xEventRecieved.Unbind(xEventHandler); // Unbind the event, we only want to handle one click event
|
||||
X11::XUngrabPointer(display, CurrentTime);
|
||||
}
|
||||
}
|
||||
|
||||
void ScreenUtilitiesLinux::BlockAndReadMouse()
|
||||
{
|
||||
X11::Display* display = (X11::Display*) LinuxPlatform::GetXDisplay();
|
||||
X11::Window rootWindow = X11::XRootWindow(display, X11::XDefaultScreen(display));
|
||||
|
||||
X11::Cursor cursor = XCreateFontCursor(display, 130);
|
||||
int grabbedPointer = X11::XGrabPointer(display, rootWindow, 0, ButtonPressMask, GrabModeAsync, GrabModeAsync, rootWindow, cursor, CurrentTime);
|
||||
if (grabbedPointer != GrabSuccess) {
|
||||
LOG(Error, "Failed to grab cursor for events.");
|
||||
|
||||
X11::XFreeCursor(display, cursor);
|
||||
return;
|
||||
}
|
||||
|
||||
X11::XFreeCursor(display, cursor);
|
||||
LinuxPlatform::xEventRecieved.Bind(xEventHandler);
|
||||
}
|
||||
|
||||
Delegate<Color32> ScreenUtilities::PickColorDone;
|
||||
|
||||
void ScreenUtilities::PickColor()
|
||||
{
|
||||
ScreenUtilitiesLinux::BlockAndReadMouse();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,46 @@
|
||||
#if PLATFORM_MAC
|
||||
#include <Cocoa/Cocoa.h>
|
||||
#include <AppKit/AppKit.h>
|
||||
|
||||
#include "ScreenUtilities.h"
|
||||
#include "Engine/Core/Math/Color32.h"
|
||||
#include "Engine/Core/Math/Vector2.h"
|
||||
#include "Engine/Core/Delegate.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
|
||||
Color32 ScreenUtilities::GetPixelAt(int32 x, int32 y)
|
||||
{
|
||||
// Called from C# for live updates to the color.
|
||||
|
||||
return { 0, 0, 0, 255 };
|
||||
}
|
||||
|
||||
Int2 ScreenUtilities::GetScreenCursorPosition()
|
||||
{
|
||||
// Called from C# for live updates to the color.
|
||||
|
||||
return { 0, 0 };
|
||||
}
|
||||
|
||||
class ScreenUtilitiesMac
|
||||
{
|
||||
public:
|
||||
static void BlockAndReadMouse();
|
||||
};
|
||||
|
||||
void ScreenUtilitiesMac::BlockAndReadMouse()
|
||||
{
|
||||
// Maybe you don't need this if you go with NSColorSampler
|
||||
}
|
||||
|
||||
Delegate<Color32> ScreenUtilities::PickColorDone;
|
||||
|
||||
void ScreenUtilities::PickColor()
|
||||
{
|
||||
// This is what C# calls to start the color picking sequence
|
||||
// This should stop mouse clicks from working for one click, and that click is on the selected color
|
||||
// There is a class called NSColorSample that might implement that for you, but maybe not.
|
||||
// It also might just work to copy the Linux Impl since Mac uses X as well, right?
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,94 @@
|
||||
#if PLATFORM_WINDOWS
|
||||
|
||||
#include "ScreenUtilities.h"
|
||||
#include "Engine/Core/Math/Color32.h"
|
||||
#include "Engine/Core/Math/Vector2.h"
|
||||
#include "Engine/Core/Delegate.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Scripting/ManagedCLR/MCore.h"
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
|
||||
#pragma comment(lib, "Gdi32.lib")
|
||||
|
||||
|
||||
Color32 ScreenUtilities::GetPixelAt(int32 x, int32 y)
|
||||
{
|
||||
HDC deviceContext = GetDC(NULL);
|
||||
COLORREF color = GetPixel(deviceContext, x, y);
|
||||
ReleaseDC(NULL, deviceContext);
|
||||
|
||||
Color32 returnColor = { GetRValue(color), GetGValue(color), GetBValue(color), 255 };
|
||||
return returnColor;
|
||||
}
|
||||
|
||||
Int2 ScreenUtilities::GetScreenCursorPosition()
|
||||
{
|
||||
POINT cursorPos;
|
||||
GetCursorPos(&cursorPos);
|
||||
|
||||
Int2 returnCursorPos = { cursorPos.x, cursorPos.y };
|
||||
return returnCursorPos;
|
||||
}
|
||||
|
||||
class ScreenUtilitiesWindows
|
||||
{
|
||||
public:
|
||||
static void PickSelected();
|
||||
static void BlockAndReadMouse();
|
||||
};
|
||||
|
||||
void ScreenUtilitiesWindows::PickSelected() {
|
||||
Int2 cursorPos = ScreenUtilities::GetScreenCursorPosition();
|
||||
Color32 colorPicked = ScreenUtilities::GetPixelAt(cursorPos.X, cursorPos.Y);
|
||||
|
||||
// Push event with the picked color.
|
||||
ScreenUtilities::PickColorDone(colorPicked);
|
||||
}
|
||||
|
||||
static HHOOK _mouseCallbackHook;
|
||||
LRESULT CALLBACK ScreenUtilsMouseCallback(
|
||||
_In_ int nCode,
|
||||
_In_ WPARAM wParam,
|
||||
_In_ LPARAM lParam
|
||||
)
|
||||
{
|
||||
if (wParam != WM_LBUTTONDOWN) { // Return as early as possible.
|
||||
return CallNextHookEx(NULL, nCode, wParam, lParam);
|
||||
}
|
||||
|
||||
if (nCode < 0) {
|
||||
return CallNextHookEx(NULL, nCode, wParam, lParam);
|
||||
}
|
||||
|
||||
|
||||
if (nCode >= 0 && wParam == WM_LBUTTONDOWN) { // Now try to run our code.
|
||||
UnhookWindowsHookEx(_mouseCallbackHook);
|
||||
|
||||
ScreenUtilitiesWindows::PickSelected();
|
||||
return 1;
|
||||
}
|
||||
|
||||
return CallNextHookEx(NULL, nCode, wParam, lParam);
|
||||
}
|
||||
|
||||
void ScreenUtilitiesWindows::BlockAndReadMouse()
|
||||
{
|
||||
_mouseCallbackHook = SetWindowsHookEx(WH_MOUSE_LL, ScreenUtilsMouseCallback, NULL, NULL);
|
||||
if (_mouseCallbackHook == NULL)
|
||||
{
|
||||
LOG(Warning, "Failed to set mouse hook.");
|
||||
LOG(Warning, "Error: {0}", GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
Delegate<Color32> ScreenUtilities::PickColorDone;
|
||||
|
||||
void ScreenUtilities::PickColor()
|
||||
{
|
||||
ScreenUtilitiesWindows::BlockAndReadMouse();
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1037,7 +1037,9 @@ namespace FlaxEditor.Utilities
|
||||
/// <returns>The processed name path.</returns>
|
||||
public static string GetAssetNamePath(string path)
|
||||
{
|
||||
path = GetAssetNamePathWithExt(path);
|
||||
var projectFolder = Globals.ProjectFolder;
|
||||
if (path.StartsWith(projectFolder))
|
||||
path = path.Substring(projectFolder.Length + 1);
|
||||
return StringUtils.GetPathWithoutExtension(path);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "LinuxPlatform.h"
|
||||
#include "LinuxWindow.h"
|
||||
#include "LinuxInput.h"
|
||||
#include "IncludeX11.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Core/Types/Guid.h"
|
||||
#include "Engine/Core/Types/String.h"
|
||||
@@ -30,7 +31,6 @@
|
||||
#include "Engine/Input/Input.h"
|
||||
#include "Engine/Input/Mouse.h"
|
||||
#include "Engine/Input/Keyboard.h"
|
||||
#include "IncludeX11.h"
|
||||
#include <sys/resource.h>
|
||||
#include <sys/sysinfo.h>
|
||||
#include <sys/time.h>
|
||||
@@ -2217,6 +2217,8 @@ void LinuxPlatform::BeforeRun()
|
||||
{
|
||||
}
|
||||
|
||||
Delegate<void*> LinuxPlatform::xEventRecieved;
|
||||
|
||||
void LinuxPlatform::Tick()
|
||||
{
|
||||
UnixPlatform::Tick();
|
||||
@@ -2234,7 +2236,9 @@ void LinuxPlatform::Tick()
|
||||
|
||||
if (X11::XFilterEvent(&event, 0))
|
||||
continue;
|
||||
|
||||
|
||||
xEventRecieved(&event); // Fire this event, since we recieved an event.
|
||||
|
||||
LinuxWindow* window;
|
||||
switch (event.type)
|
||||
{
|
||||
|
||||
@@ -33,6 +33,11 @@ public:
|
||||
/// <returns>The user home directory.</returns>
|
||||
static const String& GetHomeDirectory();
|
||||
|
||||
/// <summary>
|
||||
/// An event that is fired when an XEvent is recieved by Flax.
|
||||
/// </summary>
|
||||
static Delegate<void*> xEventRecieved;
|
||||
|
||||
public:
|
||||
|
||||
// [UnixPlatform]
|
||||
|
||||
74
Source/Engine/UI/GUI/Common/IconButton.cs
Normal file
74
Source/Engine/UI/GUI/Common/IconButton.cs
Normal file
@@ -0,0 +1,74 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
|
||||
namespace FlaxEngine.GUI
|
||||
{
|
||||
/// <summary>
|
||||
/// Button with an icon.
|
||||
/// </summary>
|
||||
public class IconButton : Button
|
||||
{
|
||||
/// <summary>
|
||||
/// The sprite rendered on the button.
|
||||
/// </summary>
|
||||
public SpriteHandle ButtonSprite { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not to hide the border of the button.
|
||||
/// </summary>
|
||||
public bool HideBorder = true;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="IconButton"/> class.
|
||||
/// </summary>
|
||||
/// <param name="buttonSprite">The sprite used by the button.</param>
|
||||
public IconButton(SpriteHandle buttonSprite)
|
||||
: this(0, 0, buttonSprite)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="IconButton"/> class.
|
||||
/// </summary>
|
||||
/// <param name="x">Position X coordinate</param>
|
||||
/// <param name="y">Position Y coordinate</param>
|
||||
/// <param name="buttonSprite">The sprite used by the button.</param>
|
||||
/// <param name="width">Width</param>
|
||||
/// <param name="height">Height</param>
|
||||
/// <param name="hideBorder">Whether or not to hide the border.</param>
|
||||
public IconButton(float x, float y, SpriteHandle buttonSprite, float width = 120, float height = DefaultHeight, bool hideBorder = true)
|
||||
: base(x, y, width, height)
|
||||
{
|
||||
ButtonSprite = buttonSprite;
|
||||
BackgroundBrush = new SpriteBrush(ButtonSprite);
|
||||
HideBorder = hideBorder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="IconButton"/> class.
|
||||
/// </summary>
|
||||
/// <param name="location">Position</param>
|
||||
/// <param name="size">Size</param>
|
||||
/// <param name="buttonSprite">The sprite used by the button.</param>
|
||||
public IconButton(Float2 location, Float2 size, SpriteHandle buttonSprite)
|
||||
: this(location.X, location.Y, buttonSprite, size.X, size.Y)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the colors of the button, taking into account the <see cref="HideBorder"/> field.>
|
||||
/// </summary>
|
||||
/// <param name="color">The color to use.</param>
|
||||
public override void SetColors(Color color)
|
||||
{
|
||||
BackgroundColor = color;
|
||||
BackgroundColorSelected = color.RGBMultiplied(0.8f);
|
||||
BackgroundColorHighlighted = color.RGBMultiplied(1.2f);
|
||||
|
||||
BorderColor = HideBorder ? Color.Transparent : color.RGBMultiplied(0.5f);
|
||||
BorderColorSelected = BorderColor;
|
||||
BorderColorHighlighted = BorderColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "Screenshot.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Core/Math/Math.h"
|
||||
#include "Engine/Core/Math/Color32.h"
|
||||
#include "Engine/Graphics/RenderTask.h"
|
||||
#include "Engine/Platform/FileSystem.h"
|
||||
#include "Engine/Graphics/Textures/TextureData.h"
|
||||
|
||||
Reference in New Issue
Block a user