414 lines
15 KiB
GDScript
414 lines
15 KiB
GDScript
class_name EditorToolbar
|
|
extends HBoxContainer
|
|
|
|
const Icon = preload("icon.svg")
|
|
|
|
enum DirectionPreset {
|
|
Column,ColumnReverse,Row,RowReverse,Reverse
|
|
}
|
|
enum WrapPreset {
|
|
NoWrap,Wrap,WrapReverse
|
|
}
|
|
enum AlignContentPreset {
|
|
Auto,FlexStart,Center,FlexEnd,Stretch,Baseline,SpaceBetween,SpaceAround
|
|
}
|
|
enum JustifyPreset {
|
|
FlexStart,Center,FlexEnd,SpaceBetween,SpaceAround,SpaceEvenly
|
|
}
|
|
enum AlignItemsPreset {
|
|
Auto,FlexStart,Center,FlexEnd,Stretch,Baseline,SpaceBetween,SpaceAround
|
|
}
|
|
|
|
var plugin:EditorPlugin
|
|
var presets_button: EditorPopupButton
|
|
|
|
var container_h_picker
|
|
var container_v_picker
|
|
|
|
var presets = {}
|
|
var _current_node:FlexContainer
|
|
var _selection:EditorSelection
|
|
var undo_redo:EditorUndoRedoManager
|
|
var flex_picker:FlexPresetPicker
|
|
var EDSCALE = 1
|
|
|
|
func _init(p_editor_scale):
|
|
EDSCALE = p_editor_scale
|
|
presets_button = EditorPopupButton.new(EDSCALE)
|
|
presets_button.set_tooltip_text("Presets for the direction values of a Flexbox node.")
|
|
add_child(presets_button)
|
|
#
|
|
var presets_label = Label.new()
|
|
presets_label.text = "Flexbox Presets"
|
|
presets_button.get_popup_hbox().add_child(presets_label)
|
|
#set default direction
|
|
presets["flex_direction"] = 2
|
|
|
|
|
|
func _ready():
|
|
flex_picker = FlexPresetPicker.new(EDSCALE)
|
|
flex_picker.set_h_size_flags(SIZE_SHRINK_CENTER);
|
|
presets_button.get_popup_hbox().add_child(flex_picker)
|
|
flex_picker.flexbox_preset_selected.connect(_flexbox_preset_selected)
|
|
|
|
_selection = plugin.get_editor_interface().get_selection()
|
|
_selection.selection_changed.connect(_selection_changed)
|
|
_selection_changed()
|
|
|
|
|
|
func _exit_tree():
|
|
_selection.selection_changed.disconnect(_selection_changed)
|
|
|
|
|
|
func _selection_changed():
|
|
var nodes = _selection.get_selected_nodes()
|
|
if nodes.size()<=0:
|
|
_current_node = null
|
|
return
|
|
|
|
var node = nodes[0]
|
|
if node is FlexContainer:
|
|
_current_node =node
|
|
set_visible(true)
|
|
flex_picker.map_state(_current_node.state)
|
|
else:
|
|
_current_node = null
|
|
set_visible(false)
|
|
|
|
|
|
func _flexbox_preset_selected(p_category, p_preset, p_state):
|
|
var old_preset = presets.get(p_category, null)
|
|
#flex direction reverse
|
|
if p_category == "reverse":
|
|
p_category = "flex_direction"
|
|
old_preset = presets.get(p_category, null)
|
|
if p_state:
|
|
var is_row = old_preset == DirectionPreset.Row or old_preset == DirectionPreset.RowReverse
|
|
p_preset = DirectionPreset.RowReverse if is_row else DirectionPreset.ColumnReverse
|
|
else:#reverse
|
|
p_preset = DirectionPreset.Row if old_preset == DirectionPreset.RowReverse else DirectionPreset.Column
|
|
presets[p_category] = p_preset
|
|
else:
|
|
presets[p_category] = p_preset if p_state else -1
|
|
|
|
undo_redo.create_action(p_category)
|
|
undo_redo.add_do_method(_current_node, "edit_set_state", presets)
|
|
undo_redo.add_undo_method(_current_node, "edit_set_state", _current_node.edit_get_state())
|
|
undo_redo.commit_action()
|
|
|
|
|
|
func _notification(what):
|
|
match what:
|
|
NOTIFICATION_ENTER_TREE, NOTIFICATION_THEME_CHANGED:
|
|
pass
|
|
|
|
class EditorPopupButton extends Button:
|
|
var arrow_icon:Texture2D
|
|
var popup_panel:PopupPanel
|
|
var popup_vbox:VBoxContainer
|
|
|
|
func _init(EDSCALE):
|
|
flat = true
|
|
toggle_mode = true
|
|
focus_mode = Control.FOCUS_NONE
|
|
texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST
|
|
var image = Icon.get_image()
|
|
image.resize(image.get_width(), image.get_width(),Image.INTERPOLATE_NEAREST)
|
|
var resize_icon = ImageTexture.new().create_from_image(image)
|
|
icon = resize_icon
|
|
|
|
popup_panel = PopupPanel.new()
|
|
popup_panel.theme_type_variation = "ControlEditorPopupPanel"
|
|
add_child(popup_panel)
|
|
popup_panel.about_to_popup.connect(_popup_visibility_changed.bind(true))
|
|
popup_panel.popup_hide.connect(_popup_visibility_changed.bind(false))
|
|
|
|
popup_vbox = VBoxContainer.new()
|
|
popup_panel.add_child(popup_vbox)
|
|
|
|
func _toggled(p_pressed):
|
|
if !p_pressed:
|
|
return
|
|
var size = get_size() * get_viewport().get_canvas_transform().get_scale()
|
|
popup_panel.size = Vector2(size.x, 0)
|
|
var gp = get_screen_position()
|
|
gp.y+= size.y
|
|
popup_panel.position = gp
|
|
popup_panel.popup()
|
|
|
|
func _popup_visibility_changed(p_visible):
|
|
button_pressed = p_visible
|
|
|
|
func _notification(what):
|
|
match what:
|
|
NOTIFICATION_ENTER_TREE, NOTIFICATION_THEME_CHANGED:
|
|
#arrow_icon = get_theme_icon("select_arrow", "Tree");
|
|
pass
|
|
NOTIFICATION_DRAW:
|
|
pass
|
|
#if is_instance_valid(arrow_icon):
|
|
#var arrow_pos = Vector2(26,0)
|
|
#arrow_pos.y = get_size().y / 2 - arrow_icon.get_height() / 2;
|
|
#draw_texture(arrow_icon, arrow_pos);
|
|
NOTIFICATION_VISIBILITY_CHANGED:
|
|
if is_visible_in_tree():
|
|
popup_panel.hide()
|
|
|
|
func get_popup_hbox():
|
|
return popup_vbox
|
|
|
|
|
|
class Space extends Control:
|
|
var ms = Vector2(3, 0)
|
|
func _init(x_space):
|
|
ms.x = x_space
|
|
func _get_minimum_size():
|
|
return ms
|
|
|
|
|
|
class EditorPresetPicker extends MarginContainer:
|
|
var grid_separation = 0
|
|
var preset_buttons = {}
|
|
var EDSCALE = 1
|
|
var BASE_SIZE = Vector2(32,32)
|
|
func _init(scale):
|
|
EDSCALE = scale
|
|
|
|
func _add_button(p_category, p_preset, b):
|
|
if preset_buttons.get(p_category) == null:
|
|
preset_buttons[p_category] = {}
|
|
preset_buttons[p_category][p_preset] = b
|
|
|
|
|
|
func _add_row_button(p_row, p_category, p_preset, p_name):
|
|
var b = Button.new()
|
|
b.auto_translate = false
|
|
b.toggle_mode = true
|
|
b.set_custom_minimum_size(BASE_SIZE * EDSCALE)
|
|
b.set_size(BASE_SIZE * EDSCALE)
|
|
b.set_icon_alignment(HORIZONTAL_ALIGNMENT_CENTER)
|
|
b.set_tooltip_text(p_name)
|
|
b.set_flat(true)
|
|
b.texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST
|
|
b.expand_icon = true
|
|
p_row.add_child(b)
|
|
b.pressed.connect(_preset_button_pressed.bind(p_category, p_preset))
|
|
_add_button(p_category, p_preset, b)
|
|
|
|
|
|
func _add_text_button(p_row, p_category, p_preset, p_name):
|
|
var b = Button.new()
|
|
b.toggle_mode = true
|
|
b.set("theme_override_font_sizes/font_size",12)
|
|
b.set_custom_minimum_size(BASE_SIZE * EDSCALE)
|
|
b.set_size(BASE_SIZE * EDSCALE)
|
|
b.set_text(p_name)
|
|
p_row.add_child(b)
|
|
b.pressed.connect(_preset_button_pressed.bind(p_category, p_preset))
|
|
_add_button(p_category, p_preset, b)
|
|
|
|
|
|
func _add_separator(p_box, p_separator):
|
|
p_separator.add_theme_constant_override("separation", grid_separation)
|
|
p_separator.set_custom_minimum_size(Vector2(1, 1))
|
|
p_box.add_child(p_separator)
|
|
|
|
func _preset_button_pressed(p_category, p_preset):
|
|
print("catgory: ", p_category, "preset: ", p_preset)
|
|
|
|
|
|
class FlexPresetPicker extends EditorPresetPicker:
|
|
signal flexbox_preset_selected
|
|
var state:Dictionary
|
|
|
|
const Category = {
|
|
Direction = "flex_direction",
|
|
DirectionReverse = "reverse",
|
|
Wrap = "flex_wrap",
|
|
Align = "align_items",
|
|
Justify = "justify_content",
|
|
AlignContent = "align_content",
|
|
}
|
|
|
|
const LABEL_WIDTH = 70
|
|
func _init(scale):
|
|
EDSCALE = scale
|
|
var main_vb = VBoxContainer.new()
|
|
main_vb.add_theme_constant_override("separation", grid_separation)
|
|
add_child(main_vb)
|
|
|
|
#direction
|
|
var dir_row = HBoxContainer.new()
|
|
dir_row.set_alignment(HBoxContainer.ALIGNMENT_BEGIN)
|
|
dir_row.add_theme_constant_override("separation", grid_separation)
|
|
main_vb.add_child(dir_row)
|
|
|
|
var direction_label = Label.new()
|
|
direction_label.set_text("Direction")
|
|
direction_label.custom_minimum_size.x = LABEL_WIDTH
|
|
dir_row.add_child(direction_label)
|
|
_add_row_button(dir_row, Category.Direction, DirectionPreset.Row, " Row ")
|
|
_add_row_button(dir_row, Category.Direction, DirectionPreset.Column, " Column ")
|
|
_add_separator(dir_row, VSeparator.new());
|
|
_add_row_button(dir_row, Category.DirectionReverse, DirectionPreset.Reverse, "Reverse");
|
|
|
|
#wrap
|
|
var wrap_row = HBoxContainer.new()
|
|
wrap_row.set_alignment(HBoxContainer.ALIGNMENT_BEGIN)
|
|
wrap_row.add_theme_constant_override("separation", grid_separation)
|
|
main_vb.add_child(wrap_row)
|
|
var wrap_label = Label.new()
|
|
wrap_label.set_text("Wrap")
|
|
wrap_label.custom_minimum_size.x = LABEL_WIDTH
|
|
wrap_row.add_child(wrap_label)
|
|
_add_row_button(wrap_row, Category.Wrap, WrapPreset.NoWrap, "NoWrap")
|
|
_add_row_button(wrap_row, Category.Wrap, WrapPreset.Wrap, "Wrap")
|
|
|
|
#align
|
|
var align_row = HBoxContainer.new()
|
|
align_row.set_alignment(HBoxContainer.ALIGNMENT_BEGIN)
|
|
align_row.add_theme_constant_override("separation", grid_separation)
|
|
main_vb.add_child(align_row)
|
|
|
|
var align_label = Label.new()
|
|
align_label.custom_minimum_size.x = LABEL_WIDTH
|
|
align_label.set_text("Align")
|
|
align_row.add_child(align_label)
|
|
_add_row_button(align_row, Category.Align, AlignItemsPreset.FlexStart, "Start");
|
|
_add_row_button(align_row, Category.Align, AlignItemsPreset.Center, "Center");
|
|
_add_row_button(align_row, Category.Align, AlignItemsPreset.FlexEnd, "End");
|
|
_add_row_button(align_row, Category.Align, AlignItemsPreset.Stretch, "Stretch");
|
|
_add_row_button(align_row, Category.Align, AlignItemsPreset.Baseline, "Baseline");
|
|
|
|
#justify
|
|
var justify_row = HBoxContainer.new()
|
|
justify_row.set_alignment(HBoxContainer.ALIGNMENT_BEGIN)
|
|
justify_row.add_theme_constant_override("separation", grid_separation)
|
|
main_vb.add_child(justify_row)
|
|
|
|
var justify_label = Label.new()
|
|
justify_label.custom_minimum_size.x = LABEL_WIDTH
|
|
justify_label.set_text("Justify")
|
|
justify_row.add_child(justify_label)
|
|
_add_row_button(justify_row, Category.Justify, JustifyPreset.FlexStart, "Start");
|
|
_add_row_button(justify_row, Category.Justify, JustifyPreset.Center, "Center");
|
|
_add_row_button(justify_row, Category.Justify, JustifyPreset.FlexEnd, "End");
|
|
_add_row_button(justify_row, Category.Justify, JustifyPreset.SpaceBetween, "SpaceBetween");
|
|
_add_row_button(justify_row, Category.Justify, JustifyPreset.SpaceAround, "SpaceAround");
|
|
_add_row_button(justify_row, Category.Justify, JustifyPreset.SpaceEvenly, "SpaceEvenly");
|
|
|
|
#
|
|
_add_separator(main_vb, HSeparator.new());
|
|
var content_row = HBoxContainer.new()
|
|
content_row.set_alignment(HBoxContainer.ALIGNMENT_BEGIN)
|
|
content_row.add_theme_constant_override("separation", grid_separation)
|
|
main_vb.add_child(content_row)
|
|
|
|
var content_label = Label.new()
|
|
content_label.custom_minimum_size.x = LABEL_WIDTH
|
|
content_label.set_text("Content")
|
|
content_row.add_child(content_label)
|
|
_add_row_button(content_row, Category.AlignContent, AlignContentPreset.FlexStart, "Start");
|
|
_add_row_button(content_row, Category.AlignContent, AlignContentPreset.Center, "Center");
|
|
_add_row_button(content_row, Category.AlignContent, AlignContentPreset.FlexEnd, "End");
|
|
_add_row_button(content_row, Category.AlignContent, AlignContentPreset.SpaceBetween, "SpaceBetween");
|
|
_add_row_button(content_row, Category.AlignContent, AlignContentPreset.SpaceAround, "SpaceAround");
|
|
_add_row_button(content_row, Category.AlignContent, AlignContentPreset.Stretch, "Stretch");
|
|
|
|
|
|
func map_state(p_state):
|
|
state = p_state
|
|
#reset all
|
|
for cat in preset_buttons:
|
|
var cat_btns = preset_buttons[cat]
|
|
for btn in cat_btns.values():
|
|
btn.button_pressed = false
|
|
#
|
|
for category in p_state:
|
|
var value = p_state[category]
|
|
if category == Category.Direction:
|
|
var is_reverse = value == DirectionPreset.RowReverse or value == DirectionPreset.ColumnReverse
|
|
if value == DirectionPreset.Row or value == DirectionPreset.RowReverse:
|
|
preset_buttons[Category.Direction][DirectionPreset.Row].button_pressed = true
|
|
else:
|
|
preset_buttons[Category.Direction][DirectionPreset.Column].button_pressed = true
|
|
preset_buttons[Category.DirectionReverse][DirectionPreset.Reverse].button_pressed = is_reverse
|
|
else:
|
|
preset_buttons[category][value].button_pressed = true
|
|
update_icons()
|
|
|
|
func is_reverse():
|
|
var direction = state[Category.Direction]
|
|
return direction == DirectionPreset.ColumnReverse or direction == DirectionPreset.RowReverse
|
|
|
|
func is_row():
|
|
var direction = state[Category.Direction]
|
|
return direction == DirectionPreset.RowReverse or direction == DirectionPreset.Row
|
|
|
|
func get_icon(icon):
|
|
return IconAssets.get_icon(icon)
|
|
|
|
|
|
func _preset_button_pressed(p_category, p_preset):
|
|
var update_icon = false
|
|
var select_btn = preset_buttons[p_category][p_preset]
|
|
for b in preset_buttons[p_category].values():
|
|
if b == select_btn:
|
|
continue
|
|
b.button_pressed = false
|
|
#
|
|
if p_category == "flex_direction":
|
|
var row_selected = preset_buttons[Category.Direction][DirectionPreset.Row].button_pressed
|
|
var column_selected = preset_buttons[Category.Direction][DirectionPreset.Column].button_pressed
|
|
if !row_selected && !column_selected:
|
|
select_btn.button_pressed = true
|
|
update_icon = true
|
|
elif p_category == "reverse":
|
|
update_icon = true
|
|
|
|
flexbox_preset_selected.emit(p_category, p_preset, select_btn.button_pressed)
|
|
if update_icon:
|
|
update_icons()
|
|
|
|
|
|
func _notification(what):
|
|
match what:
|
|
NOTIFICATION_ENTER_TREE,NOTIFICATION_THEME_CHANGED:
|
|
if state.is_empty(): return
|
|
update_icons()
|
|
|
|
|
|
func update_icons():
|
|
await get_tree().process_frame
|
|
var direction = "Row" if is_row() else "Column"
|
|
var reverse = is_reverse()
|
|
|
|
preset_buttons[Category.Direction][DirectionPreset.Row].icon = get_icon("DisplayFlexRow")
|
|
preset_buttons[Category.Direction][DirectionPreset.Column].icon = get_icon("DisplayFlexColumn")
|
|
preset_buttons[Category.DirectionReverse][DirectionPreset.Reverse].icon = get_icon("ArrowReverseIcon")
|
|
#
|
|
preset_buttons[Category.Wrap][WrapPreset.NoWrap].icon = get_icon("FlexWrapNoWrap%sIcon" % direction)
|
|
preset_buttons[Category.Wrap][WrapPreset.Wrap].icon = get_icon("FlexWrapWrap%sIcon" % direction)
|
|
#
|
|
preset_buttons[Category.Align][AlignItemsPreset.FlexStart].icon = get_icon("AlignItemsStart%sIcon" % direction)
|
|
preset_buttons[Category.Align][AlignItemsPreset.Center].icon = get_icon("AlignItemsCenter%sIcon" % direction)
|
|
preset_buttons[Category.Align][AlignItemsPreset.FlexEnd].icon = get_icon("AlignItemsEnd%sIcon" % direction)
|
|
preset_buttons[Category.Align][AlignItemsPreset.Stretch].icon = get_icon("AlignItemsStretch%sIcon" % direction)
|
|
preset_buttons[Category.Align][AlignItemsPreset.Baseline].icon = get_icon("AlignItemsBaseline%sIcon" % direction)
|
|
#
|
|
var justify_content_start_icon = get_icon("JustifyContentStart%sIcon" % direction)
|
|
var justify_content_end_icon = get_icon("JustifyContentEnd%sIcon" % direction)
|
|
preset_buttons[Category.Justify][JustifyPreset.Center].icon = get_icon("JustifyContentCenter%sIcon" % direction)
|
|
preset_buttons[Category.Justify][JustifyPreset.FlexStart].icon = justify_content_end_icon if reverse else justify_content_start_icon
|
|
preset_buttons[Category.Justify][JustifyPreset.FlexEnd].icon =justify_content_start_icon if reverse else justify_content_end_icon
|
|
preset_buttons[Category.Justify][JustifyPreset.SpaceBetween].icon = get_icon("JustifyContentSpaceBetween%sIcon" % direction)
|
|
preset_buttons[Category.Justify][JustifyPreset.SpaceAround].icon = get_icon("JustifyContentSpaceAround%sIcon" % direction)
|
|
preset_buttons[Category.Justify][JustifyPreset.SpaceEvenly].icon = get_icon("JustifyContentSpaceEvenly%sIcon" % direction)
|
|
#
|
|
preset_buttons[Category.AlignContent][AlignContentPreset.FlexStart].icon = get_icon("AlignContentStart%sIcon" % direction)
|
|
preset_buttons[Category.AlignContent][AlignContentPreset.Center].icon = get_icon("AlignContentCenter%sIcon" % direction)
|
|
preset_buttons[Category.AlignContent][AlignContentPreset.FlexEnd].icon = get_icon("AlignContentEnd%sIcon" % direction)
|
|
preset_buttons[Category.AlignContent][AlignContentPreset.SpaceAround].icon = get_icon("AlignContentAround%sIcon" % direction)
|
|
preset_buttons[Category.AlignContent][AlignContentPreset.SpaceBetween].icon = get_icon("AlignContentBetween%sIcon" % direction)
|
|
preset_buttons[Category.AlignContent][AlignContentPreset.Stretch].icon = get_icon("AlignContentStretch%sIcon" % direction)
|