Merge pull request #72764 from Sauermann/fix-color-picking
Fix Color Picking
This commit is contained in:
commit
b90d70d592
5 changed files with 108 additions and 53 deletions
|
@ -31,10 +31,12 @@
|
|||
#include "color_picker.h"
|
||||
|
||||
#include "core/input/input.h"
|
||||
#include "core/io/image.h"
|
||||
#include "core/math/color.h"
|
||||
#include "core/os/keyboard.h"
|
||||
#include "core/os/os.h"
|
||||
#include "scene/gui/color_mode.h"
|
||||
#include "servers/display_server.h"
|
||||
#include "thirdparty/misc/ok_color.h"
|
||||
#include "thirdparty/misc/ok_color_shader.h"
|
||||
|
||||
|
@ -90,8 +92,8 @@ void ColorPicker::_notification(int p_what) {
|
|||
} break;
|
||||
|
||||
case NOTIFICATION_WM_CLOSE_REQUEST: {
|
||||
if (screen != nullptr && screen->is_visible()) {
|
||||
screen->hide();
|
||||
if (picker_window != nullptr && picker_window->is_visible()) {
|
||||
picker_window->hide();
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
@ -1372,30 +1374,26 @@ void ColorPicker::_recent_preset_pressed(const bool p_pressed, ColorPresetButton
|
|||
emit_signal(SNAME("color_changed"), p_preset->get_preset_color());
|
||||
}
|
||||
|
||||
void ColorPicker::_screen_input(const Ref<InputEvent> &p_event) {
|
||||
void ColorPicker::_picker_texture_input(const Ref<InputEvent> &p_event) {
|
||||
if (!is_inside_tree()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Ref<InputEventMouseButton> bev = p_event;
|
||||
if (bev.is_valid() && bev->get_button_index() == MouseButton::LEFT && !bev->is_pressed()) {
|
||||
set_pick_color(picker_color);
|
||||
emit_signal(SNAME("color_changed"), color);
|
||||
screen->hide();
|
||||
picker_window->hide();
|
||||
}
|
||||
|
||||
Ref<InputEventMouseMotion> mev = p_event;
|
||||
if (mev.is_valid()) {
|
||||
Viewport *r = get_tree()->get_root();
|
||||
if (!r->get_visible_rect().has_point(mev->get_global_position())) {
|
||||
return;
|
||||
}
|
||||
|
||||
Ref<Image> img = r->get_texture()->get_image();
|
||||
Ref<Image> img = picker_texture_rect->get_texture()->get_image();
|
||||
if (img.is_valid() && !img->is_empty()) {
|
||||
Vector2 ofs = mev->get_global_position();
|
||||
Color c = img->get_pixel(ofs.x, ofs.y);
|
||||
|
||||
set_pick_color(c);
|
||||
Vector2 ofs = mev->get_position();
|
||||
picker_color = img->get_pixel(ofs.x, ofs.y);
|
||||
picker_preview_style_box->set_bg_color(picker_color);
|
||||
picker_preview_label->set_self_modulate(picker_color.get_luminance() < 0.5 ? Color(1.0f, 1.0f, 1.0f) : Color(0.0f, 0.0f, 0.0f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1409,27 +1407,79 @@ void ColorPicker::_add_preset_pressed() {
|
|||
emit_signal(SNAME("preset_added"), color);
|
||||
}
|
||||
|
||||
void ColorPicker::_screen_pick_pressed() {
|
||||
void ColorPicker::_pick_button_pressed() {
|
||||
if (!is_inside_tree()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Viewport *r = get_tree()->get_root();
|
||||
if (!screen) {
|
||||
screen = memnew(Control);
|
||||
r->add_child(screen);
|
||||
screen->set_as_top_level(true);
|
||||
screen->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
|
||||
screen->set_default_cursor_shape(CURSOR_POINTING_HAND);
|
||||
screen->connect("gui_input", callable_mp(this, &ColorPicker::_screen_input));
|
||||
// It immediately toggles off in the first press otherwise.
|
||||
screen->call_deferred(SNAME("connect"), "hidden", Callable(btn_pick, "set_pressed").bind(false));
|
||||
} else {
|
||||
screen->show();
|
||||
if (!picker_window) {
|
||||
picker_window = memnew(Popup);
|
||||
picker_window->hide();
|
||||
picker_window->set_transient(true);
|
||||
add_child(picker_window);
|
||||
|
||||
picker_texture_rect = memnew(TextureRect);
|
||||
picker_texture_rect->set_anchors_preset(Control::PRESET_FULL_RECT);
|
||||
picker_window->add_child(picker_texture_rect);
|
||||
picker_texture_rect->set_default_cursor_shape(CURSOR_POINTING_HAND);
|
||||
picker_texture_rect->connect(SNAME("gui_input"), callable_mp(this, &ColorPicker::_picker_texture_input));
|
||||
|
||||
picker_preview = memnew(Panel);
|
||||
picker_preview->set_anchors_preset(Control::PRESET_CENTER_TOP);
|
||||
picker_preview->set_mouse_filter(MOUSE_FILTER_IGNORE);
|
||||
picker_window->add_child(picker_preview);
|
||||
|
||||
picker_preview_label = memnew(Label);
|
||||
picker_preview->set_anchors_preset(Control::PRESET_CENTER_TOP);
|
||||
picker_preview_label->set_text("Color Picking active");
|
||||
picker_preview->add_child(picker_preview_label);
|
||||
|
||||
picker_preview_style_box = (Ref<StyleBoxFlat>)memnew(StyleBoxFlat);
|
||||
picker_preview_style_box->set_bg_color(Color(1.0, 1.0, 1.0));
|
||||
picker_preview->add_theme_style_override("panel", picker_preview_style_box);
|
||||
}
|
||||
screen->move_to_front();
|
||||
// TODO: show modal no longer works, needs to be converted to a popup.
|
||||
//screen->show_modal();
|
||||
|
||||
Rect2i screen_rect;
|
||||
if (picker_window->is_embedded()) {
|
||||
screen_rect = picker_window->get_embedder()->get_visible_rect();
|
||||
picker_window->set_position(Point2i());
|
||||
picker_texture_rect->set_texture(ImageTexture::create_from_image(picker_window->get_embedder()->get_texture()->get_image()));
|
||||
} else {
|
||||
screen_rect = picker_window->get_parent_rect();
|
||||
picker_window->set_position(screen_rect.position);
|
||||
|
||||
Ref<Image> target_image = Image::create_empty(screen_rect.size.x, screen_rect.size.y, false, Image::FORMAT_RGB8);
|
||||
DisplayServer *ds = DisplayServer::get_singleton();
|
||||
|
||||
// Add the Texture of each Window to the Image.
|
||||
Vector<DisplayServer::WindowID> wl = ds->get_window_list();
|
||||
// FIXME: sort windows by visibility.
|
||||
for (int index = 0; index < wl.size(); index++) {
|
||||
DisplayServer::WindowID wid = wl[index];
|
||||
if (wid == DisplayServer::INVALID_WINDOW_ID) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ObjectID woid = DisplayServer::get_singleton()->window_get_attached_instance_id(wid);
|
||||
if (woid == ObjectID()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Window *w = Object::cast_to<Window>(ObjectDB::get_instance(woid));
|
||||
Ref<Image> img = w->get_texture()->get_image();
|
||||
if (!img.is_valid() || img->is_empty()) {
|
||||
continue;
|
||||
}
|
||||
img->convert(Image::FORMAT_RGB8);
|
||||
target_image->blit_rect(img, Rect2i(Point2i(0, 0), img->get_size()), w->get_position());
|
||||
}
|
||||
|
||||
picker_texture_rect->set_texture(ImageTexture::create_from_image(target_image));
|
||||
}
|
||||
|
||||
picker_window->set_size(screen_rect.size);
|
||||
picker_preview->set_size(screen_rect.size / 10.0); // 10% of size in each axis.
|
||||
picker_window->popup();
|
||||
}
|
||||
|
||||
void ColorPicker::_html_focus_exit() {
|
||||
|
@ -1595,9 +1645,8 @@ ColorPicker::ColorPicker() {
|
|||
|
||||
btn_pick = memnew(Button);
|
||||
sample_hbc->add_child(btn_pick);
|
||||
btn_pick->set_toggle_mode(true);
|
||||
btn_pick->set_tooltip_text(RTR("Pick a color from the editor window."));
|
||||
btn_pick->connect("pressed", callable_mp(this, &ColorPicker::_screen_pick_pressed));
|
||||
btn_pick->set_tooltip_text(RTR("Pick a color from the application window."));
|
||||
btn_pick->connect(SNAME("pressed"), callable_mp(this, &ColorPicker::_pick_button_pressed));
|
||||
|
||||
sample = memnew(TextureRect);
|
||||
sample_hbc->add_child(sample);
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include "scene/gui/line_edit.h"
|
||||
#include "scene/gui/menu_button.h"
|
||||
#include "scene/gui/option_button.h"
|
||||
#include "scene/gui/panel.h"
|
||||
#include "scene/gui/popup.h"
|
||||
#include "scene/gui/separator.h"
|
||||
#include "scene/gui/slider.h"
|
||||
|
@ -111,7 +112,12 @@ private:
|
|||
|
||||
Vector<ColorMode *> modes;
|
||||
|
||||
Control *screen = nullptr;
|
||||
Popup *picker_window = nullptr;
|
||||
TextureRect *picker_texture_rect = nullptr;
|
||||
Panel *picker_preview = nullptr;
|
||||
Label *picker_preview_label = nullptr;
|
||||
Ref<StyleBoxFlat> picker_preview_style_box;
|
||||
Color picker_color;
|
||||
Control *uv_edit = nullptr;
|
||||
Control *w_edit = nullptr;
|
||||
AspectRatioContainer *wheel_edit = nullptr;
|
||||
|
@ -211,10 +217,10 @@ private:
|
|||
void _line_edit_input(const Ref<InputEvent> &p_event);
|
||||
void _preset_input(const Ref<InputEvent> &p_event, const Color &p_color);
|
||||
void _recent_preset_pressed(const bool pressed, ColorPresetButton *p_preset);
|
||||
void _screen_input(const Ref<InputEvent> &p_event);
|
||||
void _picker_texture_input(const Ref<InputEvent> &p_event);
|
||||
void _text_changed(const String &p_new_text);
|
||||
void _add_preset_pressed();
|
||||
void _screen_pick_pressed();
|
||||
void _pick_button_pressed();
|
||||
void _html_focus_exit();
|
||||
|
||||
inline int _get_preset_size();
|
||||
|
|
|
@ -1330,7 +1330,7 @@ void Viewport::_gui_show_tooltip() {
|
|||
Window *window = gui.tooltip_popup->get_parent_visible_window();
|
||||
Rect2i vr;
|
||||
if (gui.tooltip_popup->is_embedded()) {
|
||||
vr = gui.tooltip_popup->_get_embedder()->get_visible_rect();
|
||||
vr = gui.tooltip_popup->get_embedder()->get_visible_rect();
|
||||
} else {
|
||||
vr = window->get_usable_parent_rect();
|
||||
}
|
||||
|
@ -1851,7 +1851,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
|
|||
Window *w = Object::cast_to<Window>(this);
|
||||
if (w) {
|
||||
if (w->is_embedded()) {
|
||||
embedder = w->_get_embedder();
|
||||
embedder = w->get_embedder();
|
||||
|
||||
viewport_pos = get_final_transform().xform(mpos) + w->get_position(); // To parent coords.
|
||||
}
|
||||
|
|
|
@ -485,7 +485,7 @@ void Window::set_ime_position(const Point2i &p_pos) {
|
|||
bool Window::is_embedded() const {
|
||||
ERR_FAIL_COND_V(!is_inside_tree(), false);
|
||||
|
||||
return _get_embedder() != nullptr;
|
||||
return get_embedder() != nullptr;
|
||||
}
|
||||
|
||||
bool Window::is_in_edited_scene_root() const {
|
||||
|
@ -710,7 +710,7 @@ void Window::set_visible(bool p_visible) {
|
|||
// Stop any queued resizing, as the window will be resized right now.
|
||||
updating_child_controls = false;
|
||||
|
||||
Viewport *embedder_vp = _get_embedder();
|
||||
Viewport *embedder_vp = get_embedder();
|
||||
|
||||
if (!embedder_vp) {
|
||||
if (!p_visible && window_id != DisplayServer::INVALID_WINDOW_ID) {
|
||||
|
@ -1053,7 +1053,7 @@ void Window::_update_window_callbacks() {
|
|||
DisplayServer::get_singleton()->window_set_drop_files_callback(callable_mp(this, &Window::_window_drop_files), window_id);
|
||||
}
|
||||
|
||||
Viewport *Window::_get_embedder() const {
|
||||
Viewport *Window::get_embedder() const {
|
||||
Viewport *vp = get_parent_viewport();
|
||||
|
||||
while (vp) {
|
||||
|
@ -1088,7 +1088,7 @@ void Window::_notification(int p_what) {
|
|||
case NOTIFICATION_ENTER_TREE: {
|
||||
bool embedded = false;
|
||||
{
|
||||
embedder = _get_embedder();
|
||||
embedder = get_embedder();
|
||||
if (embedder) {
|
||||
embedded = true;
|
||||
if (!visible) {
|
||||
|
@ -1431,7 +1431,7 @@ void Window::popup_centered_clamped(const Size2i &p_size, float p_fallback_ratio
|
|||
Rect2 parent_rect;
|
||||
|
||||
if (is_embedded()) {
|
||||
parent_rect = _get_embedder()->get_visible_rect();
|
||||
parent_rect = get_embedder()->get_visible_rect();
|
||||
} else {
|
||||
DisplayServer::WindowID parent_id = get_parent_visible_window()->get_window_id();
|
||||
int parent_screen = DisplayServer::get_singleton()->window_get_current_screen(parent_id);
|
||||
|
@ -1462,7 +1462,7 @@ void Window::popup_centered(const Size2i &p_minsize) {
|
|||
Rect2 parent_rect;
|
||||
|
||||
if (is_embedded()) {
|
||||
parent_rect = _get_embedder()->get_visible_rect();
|
||||
parent_rect = get_embedder()->get_visible_rect();
|
||||
} else {
|
||||
DisplayServer::WindowID parent_id = get_parent_visible_window()->get_window_id();
|
||||
int parent_screen = DisplayServer::get_singleton()->window_get_current_screen(parent_id);
|
||||
|
@ -1488,7 +1488,7 @@ void Window::popup_centered_ratio(float p_ratio) {
|
|||
Rect2 parent_rect;
|
||||
|
||||
if (is_embedded()) {
|
||||
parent_rect = _get_embedder()->get_visible_rect();
|
||||
parent_rect = get_embedder()->get_visible_rect();
|
||||
} else {
|
||||
DisplayServer::WindowID parent_id = get_parent_visible_window()->get_window_id();
|
||||
int parent_screen = DisplayServer::get_singleton()->window_get_current_screen(parent_id);
|
||||
|
@ -1509,7 +1509,7 @@ void Window::popup_centered_ratio(float p_ratio) {
|
|||
void Window::popup(const Rect2i &p_screen_rect) {
|
||||
emit_signal(SNAME("about_to_popup"));
|
||||
|
||||
if (!_get_embedder() && get_flag(FLAG_POPUP)) {
|
||||
if (!get_embedder() && get_flag(FLAG_POPUP)) {
|
||||
// Send a focus-out notification when opening a Window Manager Popup.
|
||||
SceneTree *scene_tree = get_tree();
|
||||
if (scene_tree) {
|
||||
|
@ -1545,7 +1545,7 @@ void Window::popup(const Rect2i &p_screen_rect) {
|
|||
|
||||
Rect2i parent_rect;
|
||||
if (is_embedded()) {
|
||||
parent_rect = _get_embedder()->get_visible_rect();
|
||||
parent_rect = get_embedder()->get_visible_rect();
|
||||
} else {
|
||||
int screen_id = DisplayServer::get_singleton()->window_get_current_screen(get_window_id());
|
||||
parent_rect = DisplayServer::get_singleton()->screen_get_usable_rect(screen_id);
|
||||
|
@ -1587,7 +1587,7 @@ Rect2i Window::get_usable_parent_rect() const {
|
|||
ERR_FAIL_COND_V(!is_inside_tree(), Rect2());
|
||||
Rect2i parent_rect;
|
||||
if (is_embedded()) {
|
||||
parent_rect = _get_embedder()->get_visible_rect();
|
||||
parent_rect = get_embedder()->get_visible_rect();
|
||||
} else {
|
||||
const Window *w = is_visible() ? this : get_parent_visible_window();
|
||||
//find a parent that can contain us
|
||||
|
@ -2154,9 +2154,9 @@ Transform2D Window::get_final_transform() const {
|
|||
|
||||
Transform2D Window::get_screen_transform_internal(bool p_absolute_position) const {
|
||||
Transform2D embedder_transform;
|
||||
if (_get_embedder()) {
|
||||
if (get_embedder()) {
|
||||
embedder_transform.translate_local(get_position());
|
||||
embedder_transform = _get_embedder()->get_screen_transform_internal(p_absolute_position) * embedder_transform;
|
||||
embedder_transform = get_embedder()->get_screen_transform_internal(p_absolute_position) * embedder_transform;
|
||||
} else if (p_absolute_position) {
|
||||
embedder_transform.translate_local(get_position());
|
||||
}
|
||||
|
@ -2170,8 +2170,8 @@ Transform2D Window::get_popup_base_transform() const {
|
|||
Transform2D popup_base_transform;
|
||||
popup_base_transform.set_origin(get_position());
|
||||
popup_base_transform *= get_final_transform();
|
||||
if (_get_embedder()) {
|
||||
return _get_embedder()->get_popup_base_transform() * popup_base_transform;
|
||||
if (get_embedder()) {
|
||||
return get_embedder()->get_popup_base_transform() * popup_base_transform;
|
||||
}
|
||||
return popup_base_transform;
|
||||
}
|
||||
|
|
|
@ -192,7 +192,6 @@ private:
|
|||
Ref<Shortcut> debugger_stop_shortcut;
|
||||
|
||||
protected:
|
||||
Viewport *_get_embedder() const;
|
||||
virtual Rect2i _popup_adjust_rect() const { return Rect2i(); }
|
||||
|
||||
virtual void _update_theme_item_cache();
|
||||
|
@ -278,6 +277,7 @@ public:
|
|||
void set_ime_position(const Point2i &p_pos);
|
||||
|
||||
bool is_embedded() const;
|
||||
Viewport *get_embedder() const;
|
||||
|
||||
void set_content_scale_size(const Size2i &p_size);
|
||||
Size2i get_content_scale_size() const;
|
||||
|
|
Loading…
Reference in a new issue