Skip to content

Commit

Permalink
Change BetterPopup into a Control-based one
Browse files Browse the repository at this point in the history
  • Loading branch information
MewPurPur committed Apr 15, 2024
1 parent 9d5fa3d commit 1c31986
Show file tree
Hide file tree
Showing 37 changed files with 277 additions and 357 deletions.
135 changes: 105 additions & 30 deletions src/HandlerGUI.gd
Original file line number Diff line number Diff line change
Expand Up @@ -5,53 +5,113 @@ signal _in_focus
const ImportWarningDialog = preload("res://src/ui_parts/import_warning_dialog.tscn")
const AlertDialog = preload("res://src/ui_parts/alert_dialog.tscn")

var has_overlay := false
var overlay_ref: OverlayRect
var overlay_stack: Array[ColorRect]
var popup_overlay_stack: Array[Control]


func _enter_tree() -> void:
process_mode = Node.PROCESS_MODE_ALWAYS

func _ready() -> void:
get_window().files_dropped.connect(_on_files_dropped)
if OS.has_feature("web"):
_define_web_js()


func _notification(what: int) -> void:
if what == NOTIFICATION_WM_WINDOW_FOCUS_IN:
_in_focus.emit()


# Drag-and-drop of files.
func _on_files_dropped(files: PackedStringArray) -> void:
if not has_overlay:
if overlay_stack.is_empty():
SVG.apply_svg_from_path(files[0])


func add_overlay(overlay_menu: Node) -> void:
# A bit hacky, but I couldn't find out a better way at the time.
# I'm sure there is a better way of doing things though.
if has_overlay:
for child in overlay_ref.get_children():
child.tree_exiting.disconnect(remove_overlay)
child.queue_free()
if overlay_menu is Control:
overlay_menu.set_anchors_and_offsets_preset(Control.PRESET_CENTER)
overlay_ref.add_child(overlay_menu)
overlay_menu.tree_exiting.connect(remove_overlay)
func add_overlay(overlay_menu: Control) -> void:
if not overlay_stack.is_empty():
overlay_stack.back().hide()

var overlay_ref = ColorRect.new()
overlay_ref.color = Color(0, 0, 0, 0.4)
overlay_ref.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
overlay_ref.process_mode = PROCESS_MODE_ALWAYS
overlay_stack.append(overlay_ref)
get_tree().get_root().add_child(overlay_ref)
overlay_ref.add_child(overlay_menu)
overlay_menu.set_anchors_and_offsets_preset(Control.PRESET_CENTER)
overlay_menu.tree_exiting.connect(remove_overlay.bind(overlay_stack.size() - 1))
get_tree().paused = true

func remove_overlay(idx := -1) -> void:
# If the passed index is -1 or doesn't exist, skip the operation.
# This is a safeguard against multiple actions triggering remove_overlay() at once.
if idx != -1 and idx >= overlay_stack.size():
return

var overlay_ref: ColorRect = overlay_stack.pop_back()
if is_instance_valid(overlay_ref):
overlay_ref.queue_free()
if overlay_stack.is_empty():
get_tree().paused = false
else:
overlay_ref = OverlayRect.new()
get_tree().get_root().add_child(overlay_ref)
overlay_ref.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
overlay_ref.add_child(overlay_menu)
if overlay_menu is Control:
overlay_menu.set_anchors_and_offsets_preset(Control.PRESET_CENTER)
overlay_menu.tree_exiting.connect(remove_overlay)
has_overlay = true
get_tree().paused = true

overlay_stack.back().show()


func add_popup_overlay(popup: Control, popup_position: Vector2) -> void:
var overlay_ref := Control.new()
overlay_ref.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
overlay_ref.gui_input.connect(_parse_popup_overlay_event)
overlay_ref.process_mode = PROCESS_MODE_ALWAYS
popup_overlay_stack.append(overlay_ref)
get_tree().get_root().add_child(overlay_ref)
overlay_ref.add_child(popup)
popup.tree_exiting.connect(remove_popup_overlay.bind(popup_overlay_stack.size() - 1))
popup.position = popup_position

func remove_popup_overlay(idx := -1) -> void:
# Refer to remove_overlay().
if idx != -1 and idx >= popup_overlay_stack.size():
return

var overlay_ref: Control = popup_overlay_stack.pop_back()
if is_instance_valid(overlay_ref):
overlay_ref.queue_free()

# Should usually be the global rect of a control.
func popup_under_rect(popup: Control, rect: Rect2, viewport: Viewport) -> void:
var screen_transform := viewport.get_screen_transform()
var screen_h := viewport.get_visible_rect().size.y
var popup_pos := Vector2(rect.position.x, 0)
# Popup below if there's enough space or we're in the bottom half of the screen.
if rect.position.y + rect.size.y + popup.size.y < screen_h or\
rect.position.y + rect.size.y / 2 <= screen_h / 2.0:
popup_pos.y = rect.position.y + rect.size.y
else:
popup_pos.y = rect.position.y - popup.size.y
# Horizontal alignment and other things.
popup_pos += screen_transform.get_origin() / screen_transform.get_scale()
add_popup_overlay(popup, popup_pos)

# Should usually be the global rect of a control.
func popup_under_rect_center(popup: Control, rect: Rect2, viewport: Viewport) -> void:
var screen_transform := viewport.get_screen_transform()
var screen_h := viewport.get_visible_rect().size.y
var popup_pos := Vector2(rect.position.x - popup.size.x / 2.0 + rect.size.x / 2, 0)
# Popup below if there's enough space or we're in the bottom half of the screen.
if rect.position.y + rect.size.y + popup.size.y < screen_h or\
rect.position.y + rect.size.y / 2 <= screen_h / 2.0:
popup_pos.y = rect.position.y + rect.size.y
else:
popup_pos.y = rect.position.y - popup.size.y
# Align horizontally and other things.
popup_pos += screen_transform.get_origin() / screen_transform.get_scale()
add_popup_overlay(popup, popup_pos)

func remove_overlay() -> void:
overlay_ref.queue_free()
has_overlay = false
get_tree().paused = false
# Should usually be the global position of the mouse.
func popup_under_pos(popup: Control, pos: Vector2, viewport: Viewport) -> void:
var screen_transform := viewport.get_screen_transform()
pos += screen_transform.get_origin() / screen_transform.get_scale()
add_popup_overlay(popup, pos)


var last_mouse_click_double := false
Expand All @@ -70,8 +130,23 @@ func _input(event: InputEvent) -> void:
get_viewport().set_input_as_handled()
SVG.open_save_dialog("svg", SVG.native_file_save, SVG.save_svg_to_file)

func _parse_popup_overlay_event(event: InputEvent) -> void:
if not popup_overlay_stack.is_empty():
if event is InputEventMouseButton and event.button_index in [MOUSE_BUTTON_LEFT,
MOUSE_BUTTON_MIDDLE, MOUSE_BUTTON_RIGHT]:
remove_popup_overlay()
get_viewport().set_input_as_handled()

func _unhandled_input(event: InputEvent) -> void:
# Clear popups or overlays.
if event.is_action_pressed("ui_cancel"):
if not popup_overlay_stack.is_empty():
get_viewport().set_input_as_handled()
remove_popup_overlay()
elif not overlay_stack.is_empty():
get_viewport().set_input_as_handled()
remove_overlay()

if event.is_action_pressed("redo"):
get_viewport().set_input_as_handled()
SVG.redo()
Expand Down
10 changes: 4 additions & 6 deletions src/Indications.gd
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
extends Node
## This singleton handles editor information like zoom level and selections.

const ContextPopup = preload("res://src/ui_elements/context_popup.tscn")
const PathCommandPopup = preload("res://src/ui_elements/path_popup.tscn")

const path_actions_dict := {
Expand Down Expand Up @@ -425,7 +424,7 @@ func insert_inner_after_selection(new_command: String) -> void:
normal_select(semi_selected_tid, last_selection + 1)


func get_selection_context(popup_method: Callable) -> Popup:
func get_selection_context(popup_method: Callable) -> ContextPopup:
var btn_arr: Array[Button] = []

if not selected_tids.is_empty():
Expand Down Expand Up @@ -480,8 +479,7 @@ func get_selection_context(popup_method: Callable) -> Popup:
btn_arr.append(Utils.create_btn(tr("Delete"), delete_selected, false,
load("res://visual/icons/Delete.svg")))

var tag_context := ContextPopup.instantiate()
add_child(tag_context)
var tag_context := ContextPopup.new()
tag_context.setup(btn_arr, true)
return tag_context

Expand All @@ -495,9 +493,9 @@ func popup_convert_to_context(popup_method: Callable) -> void:
!tag.can_replace(tag_name), load("res://visual/icons/tag/%s.svg" % tag_name))
btn.add_theme_font_override("font", load("res://visual/fonts/FontMono.ttf"))
btn_arr.append(btn)
var context_popup := ContextPopup.instantiate()
add_child(context_popup)
var context_popup := ContextPopup.new()
context_popup.setup(btn_arr, true)
add_child(context_popup)
popup_method.call(context_popup)
elif not inner_selections.is_empty() and not semi_selected_tid.is_empty():
var cmd_char: String = SVG.root_tag.get_tag(semi_selected_tid).\
Expand Down
44 changes: 0 additions & 44 deletions src/Utils.gd
Original file line number Diff line number Diff line change
Expand Up @@ -39,50 +39,6 @@ font_size_property := "font_size") -> void:
HORIZONTAL_ALIGNMENT_FILL, -1,
control.get_theme_font_size(font_size_property)).x + buffer, max_width)

# Should usually be the global rect of a control.
static func popup_under_rect(popup: Popup, rect: Rect2, viewport: Viewport) -> void:
Utils._popup_under_rect.call_deferred(popup, rect, viewport)

static func _popup_under_rect(popup: Popup, rect: Rect2, viewport: Viewport) -> void:
var screen_transform := viewport.get_screen_transform()
var screen_h := viewport.get_visible_rect().size.y
var popup_pos := Vector2.ZERO
# Popup below if there's enough space or we're in the bottom half of the screen.
if rect.position.y + rect.size.y + popup.size.y < screen_h or\
rect.position.y + rect.size.y / 2 <= screen_h / 2.0:
popup_pos.y = rect.position.y + rect.size.y
else:
popup_pos.y = rect.position.y - popup.size.y
# Horizontal alignment and other things.
popup_pos.x = rect.position.x
popup_pos += screen_transform.get_origin() / screen_transform.get_scale()
popup.popup(Rect2(popup_pos, popup.size))

# Should usually be the global rect of a control.
static func popup_under_rect_center(popup: Popup, rect: Rect2, viewport: Viewport) -> void:
Utils._popup_under_rect_center.call_deferred(popup, rect, viewport)

static func _popup_under_rect_center(popup: Popup, rect: Rect2, viewport: Viewport) -> void:
var screen_transform := viewport.get_screen_transform()
var screen_h := viewport.get_visible_rect().size.y
var popup_pos := Vector2.ZERO
# Popup below if there's enough space or we're in the bottom half of the screen.
if rect.position.y + rect.size.y + popup.size.y < screen_h or\
rect.position.y + rect.size.y / 2 <= screen_h / 2.0:
popup_pos.y = rect.position.y + rect.size.y
else:
popup_pos.y = rect.position.y - popup.size.y
# Align horizontally and other things.
popup_pos.x = rect.position.x - popup.size.x / 2.0 + rect.size.x / 2
popup_pos += screen_transform.get_origin() / screen_transform.get_scale()
popup.popup(Rect2(popup_pos, popup.size))

# Should usually be the global position of the mouse.
static func popup_under_pos(popup: Popup, pos: Vector2, viewport: Viewport) -> void:
var screen_transform := viewport.get_screen_transform()
pos += screen_transform.get_origin() / screen_transform.get_scale()
popup.popup(Rect2(pos, popup.size))


static func create_btn(text: String, press_action: Callable, disabled := false,
icon: Texture2D = null) -> Button:
Expand Down
10 changes: 4 additions & 6 deletions src/ui_elements/BetterLineEdit.gd
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ class_name BetterLineEdit extends LineEdit
signal text_change_canceled

const code_font = preload("res://visual/fonts/FontMono.ttf")
const ContextPopup = preload("res://src/ui_elements/context_popup.tscn")

var hovered := false

Expand Down Expand Up @@ -86,9 +85,8 @@ func _gui_input(event: InputEvent) -> void:
hovered = true
queue_redraw()
elif event is InputEventMouseButton:
if event.button_index == MOUSE_BUTTON_RIGHT:
if event.button_index == MOUSE_BUTTON_RIGHT and event.is_pressed():
grab_focus()
var context_popup := ContextPopup.instantiate()
var btn_arr: Array[Button] = []
var separator_arr: Array[int] = []
if editable:
Expand All @@ -113,10 +111,10 @@ func _gui_input(event: InputEvent) -> void:
menu_option.bind(LineEdit.MENU_COPY),
text.is_empty(), load("res://visual/icons/Copy.svg")))

add_child(context_popup)
var vp := get_viewport()
var context_popup := ContextPopup.new()
context_popup.setup(btn_arr, true, -1, separator_arr)
var viewport := get_viewport()
Utils.popup_under_pos(context_popup, viewport.get_mouse_position(), viewport)
HandlerGUI.popup_under_pos(context_popup, vp.get_mouse_position(), vp)
accept_event()
# Wow, no way to find out the column of a given click? Okay...
# TODO Make it so LineEdit caret automatically moves to the clicked position.
15 changes: 0 additions & 15 deletions src/ui_elements/BetterPopup.gd

This file was deleted.

10 changes: 4 additions & 6 deletions src/ui_elements/BetterTextEdit.gd
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
class_name BetterTextEdit extends TextEdit

const code_font = preload("res://visual/fonts/FontMono.ttf")
const ContextPopup = preload("res://src/ui_elements/context_popup.tscn")
const caret_color = Color("defd")

var surface := RenderingServer.canvas_item_create()
Expand Down Expand Up @@ -109,9 +108,8 @@ func _gui_input(event: InputEvent) -> void:
hovered = true
queue_redraw()
if event is InputEventMouseButton:
if event.button_index == MOUSE_BUTTON_RIGHT:
if event.button_index == MOUSE_BUTTON_RIGHT and event.is_pressed():
grab_focus()
var context_popup := ContextPopup.instantiate()
var btn_arr: Array[Button] = []
var separator_arr: Array[int] = []
if editable:
Expand All @@ -130,10 +128,10 @@ func _gui_input(event: InputEvent) -> void:
btn_arr.append(Utils.create_btn(tr("Copy"), copy, text.is_empty(),
load("res://visual/icons/Copy.svg")))

add_child(context_popup)
var context_popup := ContextPopup.new()
context_popup.setup(btn_arr, true, -1, separator_arr)
var viewport := get_viewport()
Utils.popup_under_pos(context_popup, viewport.get_mouse_position(), viewport)
var vp := get_viewport()
HandlerGUI.popup_under_pos(context_popup, vp.get_mouse_position(), vp)
accept_event()
var click_pos := get_line_column_at_pos(event.position)
set_caret_line(click_pos.y, false)
Expand Down
11 changes: 0 additions & 11 deletions src/ui_elements/OverlayRect.gd

This file was deleted.

5 changes: 2 additions & 3 deletions src/ui_elements/color_edit.gd
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const checkerboard = preload("res://visual/icons/backgrounds/ColorButtonBG.svg")

@onready var color_button: Button = $Button
@onready var color_edit: LineEdit = $LineEdit
@onready var color_picker: Popup
@onready var color_picker: Control

@export var enable_palettes := true
@export var enable_alpha := false
Expand Down Expand Up @@ -48,9 +48,8 @@ func _on_button_pressed() -> void:
if enable_alpha:
color_picker.enable_alpha = true
color_picker.current_value = ColorParser.add_hash_if_hex(value)
add_child(color_picker)
HandlerGUI.popup_under_rect(color_picker, color_edit.get_global_rect(), get_viewport())
color_picker.color_picked.connect(_on_color_picked)
Utils.popup_under_rect(color_picker, color_edit.get_global_rect(), get_viewport())

func _draw() -> void:
var button_size := color_button.get_size()
Expand Down
4 changes: 2 additions & 2 deletions src/ui_elements/color_field.gd
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const checkerboard = preload("res://visual/icons/backgrounds/ColorButtonBG.svg")

@onready var color_button: Button = $Button
@onready var color_edit: BetterLineEdit = $LineEdit
@onready var color_popup: BetterPopup
@onready var color_popup: Control

var ci := get_canvas_item()

Expand Down Expand Up @@ -48,7 +48,7 @@ func _on_button_pressed() -> void:
color_popup.current_value = attribute.get_value()
add_child(color_popup)
color_popup.color_picked.connect(_on_color_picked)
Utils.popup_under_rect(color_popup, color_edit.get_global_rect(), get_viewport())
HandlerGUI.popup_under_rect(color_popup, color_edit.get_global_rect(), get_viewport())

func _draw() -> void:
var button_size := color_button.get_size()
Expand Down
Loading

0 comments on commit 1c31986

Please sign in to comment.