Skip to content

Commit 02f0aa6

Browse files
committed
Added menu options to load/save/reset panels layout
1 parent c0c36b5 commit 02f0aa6

6 files changed

Lines changed: 254 additions & 0 deletions

File tree

material_maker/doc/user_interface_main_menu.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,10 @@ View menu
103103

104104
* the *Panels* submenu can be used to show or hide all side panels
105105

106+
* the *Presets* submenu can be used to load/save/edit panels presets.
107+
108+
* *Reset panels* Resets panels layout to factory settings.
109+
106110
Tools menu
107111
^^^^^^^^^^
108112

material_maker/main_window.gd

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ const RECENT_FILES_COUNT = 15
4848
const MENU_QUICK_EXPORT : int = 1000
4949
const RECENTS_MENU_CLEAR = 1001
5050

51+
const MENU_SAVE_PRESET : int = 1002
52+
const MENU_MANAGE_PRESETS : int = 1003
53+
5154
const THEMES = ["Default Dark", "Default Light", "Classic"]
5255

5356
const MENU : Array[Dictionary] = [
@@ -100,6 +103,8 @@ const MENU : Array[Dictionary] = [
100103
{ menu="View/-" },
101104
# { menu="View/Show or Hide side panels", command="toggle_side_panels", shortcut="Control+Space" },
102105
{ menu="View/Panels", submenu="show_panels" },
106+
{ menu="View/Presets", submenu="panels_preset" },
107+
{ menu="View/Reset Panels", command="view_reset_panels" },
103108

104109
{ menu="Tools/Create", submenu="create" },
105110
{ menu="Tools/Create group", command="create_subgraph", shortcut="Control+G" },
@@ -648,11 +653,62 @@ func create_menu_show_panels(menu : MMMenuManager.MenuBase) -> void:
648653
menu.set_item_checked(i, layout.is_panel_visible(panels[i]))
649654
menu.connect_id_pressed(self._on_ShowPanels_id_pressed)
650655

656+
func create_menu_panels_preset(menu : MMMenuManager.MenuBase) -> void:
657+
menu.clear()
658+
menu.add_item("Save Preset", MENU_SAVE_PRESET)
659+
menu.add_item("Manage Presets", MENU_MANAGE_PRESETS)
660+
if not layout.presets.is_empty():
661+
menu.add_separator()
662+
for id in layout.presets.size():
663+
menu.add_item(layout.presets[id].name, id)
664+
menu.connect_id_pressed(self._on_PanelsPreset_id_pressed)
665+
651666
func _on_ShowPanels_id_pressed(id) -> void:
652667
var panel : String = layout.get_panel_list()[id]
653668
layout.set_panel_visible(panel, not layout.is_panel_visible(panel))
654669
update_menus()
655670

671+
func _on_PanelsPreset_id_pressed(id : int) -> void:
672+
match id:
673+
MENU_MANAGE_PRESETS:
674+
if get_node_or_null("PanelPresetsDialog"):
675+
return
676+
var dialog : Window = preload("res://material_maker/windows/panels_presets_dialog/panels_presets_dialog.tscn").instantiate()
677+
add_child(dialog)
678+
await dialog.edit_presets(layout.presets)
679+
MENU_SAVE_PRESET:
680+
var dialog : Window = preload("res://material_maker/windows/line_dialog/line_dialog.tscn").instantiate()
681+
add_child(dialog)
682+
var status : Dictionary = await dialog.enter_text("Save Preset",
683+
"Enter a name for the new preset", "")
684+
if status.ok:
685+
var preset_name : String = status.text.strip_edges()
686+
if preset_name.is_empty():
687+
accept_dialog("Preset name cannot be empty.")
688+
else:
689+
var is_unique_preset : bool = true
690+
var existing_preset : Dictionary
691+
if not layout.presets.is_empty():
692+
for preset in layout.presets:
693+
if preset.name.to_lower() == preset_name.to_lower():
694+
is_unique_preset = false
695+
existing_preset = preset
696+
break
697+
if not is_unique_preset:
698+
var replace_status : String = await accept_dialog(
699+
"Preset \"%s\" already exists. Do you want to replace it?" % [preset_name], true)
700+
if replace_status == "ok":
701+
existing_preset.preset = $VBoxContainer/Layout/FlexibleLayout.serialize()
702+
else:
703+
var new_preset : Dictionary = {
704+
"name": preset_name,
705+
"preset": $VBoxContainer/Layout/FlexibleLayout.serialize()
706+
}
707+
layout.presets.push_back(new_preset)
708+
_:
709+
$VBoxContainer/Layout/FlexibleLayout.init(layout.presets[id].preset)
710+
update_menus()
711+
656712
func create_menu_create(menu : MMMenuManager.MenuBase) -> void:
657713
var gens = mm_loader.get_generator_list()
658714
menu.clear()
@@ -1036,6 +1092,9 @@ func view_reset_zoom() -> void:
10361092
var graph_edit : MMGraphEdit = get_current_graph_edit()
10371093
graph_edit.zoom = 1
10381094

1095+
func view_reset_panels() -> void:
1096+
$VBoxContainer/Layout.reset_panels()
1097+
10391098
func toggle_side_panels() -> void:
10401099
$VBoxContainer/Layout.toggle_side_panels()
10411100

material_maker/main_window_layout.gd

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ var previous_width : float
4040
var current_mode : String = "material"
4141
var layout : Dictionary = {}
4242

43+
var presets : Array[Dictionary]
4344

4445
func _ready() -> void:
4546
previous_width = size.x
@@ -67,13 +68,30 @@ func load_panels() -> void:
6768
layout[mode] = default_paint_layout
6869
$FlexibleLayout.init(layout[current_mode] if layout.has(current_mode) else null)
6970

71+
# Restore layout presets
72+
var preset_keys : PackedStringArray
73+
if mm_globals.config.has_section("layout_presets"):
74+
preset_keys = mm_globals.config.get_section_keys("layout_presets")
75+
for preset in preset_keys:
76+
presets.push_back({
77+
"name": preset,
78+
"preset": JSON.parse_string(
79+
mm_globals.config.get_value("layout_presets", preset))
80+
})
7081

7182
func save_config() -> void:
7283
layout[current_mode] = $FlexibleLayout.serialize()
7384
for mode in [ "material", "paint" ]:
7485
if layout.has(mode):
7586
mm_globals.config.set_value("layout", mode, JSON.stringify(layout[mode]))
7687

88+
# Save layout presets
89+
if mm_globals.config.has_section("layout_presets"):
90+
mm_globals.config.erase_section("layout_presets")
91+
for preset in presets:
92+
mm_globals.config.set_value("layout_presets",
93+
preset.name, JSON.stringify(preset.preset))
94+
7795

7896
func get_panel(n) -> Control:
7997
if panels.has(n):
@@ -102,3 +120,10 @@ func change_mode(m : String) -> void:
102120

103121
func _on_tab_changed(_tab):
104122
pass
123+
124+
func reset_panels() -> void:
125+
if current_mode == "material":
126+
$FlexibleLayout.init(default_material_layout)
127+
elif current_mode == "paint":
128+
$FlexibleLayout.init(default_paint_layout)
129+
owner.view_center()
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
extends Window
2+
3+
var layout_presets : Array[Dictionary]
4+
var selected_item : int = -1
5+
6+
func _ready() -> void:
7+
if not get_tree().root.gui_embed_subwindows:
8+
content_scale_factor = get_tree().root.content_scale_factor
9+
size = $MarginContainer.get_combined_minimum_size() * content_scale_factor
10+
min_size = size
11+
12+
func edit_presets(presets : Array[Dictionary]) -> void:
13+
layout_presets = presets
14+
_ready()
15+
hide()
16+
popup_centered()
17+
update_item_list()
18+
await %Buttons/Close.pressed
19+
queue_free()
20+
21+
func update_item_list() -> void:
22+
%ItemList.clear()
23+
if not layout_presets.is_empty():
24+
for preset in layout_presets:
25+
var idx : int = %ItemList.add_item(preset.name)
26+
%ItemList.set_item_tooltip_enabled(idx, false)
27+
else:
28+
enable_buttons(false)
29+
if selected_item != -1 and selected_item < %ItemList.item_count:
30+
%ItemList.select(selected_item)
31+
32+
func enable_buttons(enable : bool) -> void:
33+
for btn in %Buttons.get_children():
34+
if btn.name != "Close":
35+
btn.disabled = not enable
36+
37+
func _on_item_list_item_selected(index : int) -> void:
38+
selected_item = index
39+
40+
func _on_rename_pressed() -> void:
41+
if selected_item == -1:
42+
return
43+
var renamed_item : String = %ItemList.get_item_text(selected_item)
44+
var dialog : Window = preload(
45+
"res://material_maker/windows/line_dialog/line_dialog.tscn").instantiate()
46+
add_child(dialog)
47+
48+
var status : Dictionary = await dialog.enter_text("Rename Preset",
49+
"Enter a new name for this preset", renamed_item)
50+
var renamed_item_id : int = -1
51+
var preset_data : Dictionary
52+
if status.ok and not status.text.strip_edges().is_empty():
53+
for preset in layout_presets.size():
54+
if layout_presets[preset].name == renamed_item:
55+
renamed_item_id = preset
56+
preset_data = layout_presets[preset].duplicate()
57+
break
58+
else:
59+
return
60+
61+
var new_preset_name : String = status.text.strip_edges()
62+
for item_index in %ItemList.item_count:
63+
if %ItemList.get_item_text(item_index) == new_preset_name:
64+
if renamed_item_id != item_index:
65+
mm_globals.main_window.accept_dialog(
66+
"Preset \"%s\" already exists." % [new_preset_name])
67+
return
68+
layout_presets.remove_at(renamed_item_id)
69+
preset_data.name = status.text.strip_edges()
70+
layout_presets.insert(renamed_item_id, preset_data)
71+
update_item_list()
72+
73+
func _on_remove_pressed() -> void:
74+
if selected_item == -1:
75+
return
76+
for preset in layout_presets.size():
77+
if layout_presets[preset].name == %ItemList.get_item_text(selected_item):
78+
layout_presets.remove_at(preset)
79+
break
80+
if layout_presets.is_empty():
81+
enable_buttons(false)
82+
update_item_list()
83+
84+
func _on_apply_pressed() -> void:
85+
if selected_item == -1:
86+
return
87+
var layout : HBoxContainer = mm_globals.main_window.layout
88+
layout.get_node("FlexibleLayout").init(layout_presets[selected_item].preset)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
uid://cbelggpnaih8k
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
[gd_scene format=3 uid="uid://l3a3x237y66n"]
2+
3+
[ext_resource type="Script" uid="uid://cbelggpnaih8k" path="res://material_maker/windows/panels_presets_dialog/panels_presets_dialog.gd" id="1_p4t34"]
4+
5+
[node name="PanelPresetsDialog" type="Window" unique_id=1375078152]
6+
oversampling_override = 1.0
7+
title = "Manage Presets"
8+
position = Vector2i(0, 36)
9+
size = Vector2i(350, 350)
10+
script = ExtResource("1_p4t34")
11+
12+
[node name="MarginContainer" type="MarginContainer" parent="." unique_id=1323210345]
13+
custom_minimum_size = Vector2(350, 350)
14+
anchors_preset = 15
15+
anchor_right = 1.0
16+
anchor_bottom = 1.0
17+
grow_horizontal = 2
18+
grow_vertical = 2
19+
theme_override_constants/margin_left = 4
20+
theme_override_constants/margin_top = 4
21+
theme_override_constants/margin_right = 4
22+
theme_override_constants/margin_bottom = 4
23+
24+
[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer" unique_id=1612899448]
25+
layout_mode = 2
26+
27+
[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/VBoxContainer" unique_id=1214955961]
28+
layout_mode = 2
29+
size_flags_vertical = 3
30+
31+
[node name="ItemList" type="ItemList" parent="MarginContainer/VBoxContainer/HBoxContainer" unique_id=1960428380]
32+
unique_name_in_owner = true
33+
layout_mode = 2
34+
size_flags_horizontal = 3
35+
36+
[node name="MarginContainer" type="MarginContainer" parent="MarginContainer/VBoxContainer/HBoxContainer" unique_id=339801386]
37+
layout_mode = 2
38+
theme_override_constants/margin_left = 4
39+
theme_override_constants/margin_top = 4
40+
theme_override_constants/margin_right = 4
41+
theme_override_constants/margin_bottom = 4
42+
43+
[node name="Buttons" type="VBoxContainer" parent="MarginContainer/VBoxContainer/HBoxContainer/MarginContainer" unique_id=808754394]
44+
unique_name_in_owner = true
45+
custom_minimum_size = Vector2(100, 0)
46+
layout_mode = 2
47+
theme_override_constants/separation = 8
48+
49+
[node name="Apply" type="Button" parent="MarginContainer/VBoxContainer/HBoxContainer/MarginContainer/Buttons" unique_id=1091220633]
50+
custom_minimum_size = Vector2(60, 0)
51+
layout_mode = 2
52+
size_flags_horizontal = 3
53+
text = "Apply"
54+
55+
[node name="Rename" type="Button" parent="MarginContainer/VBoxContainer/HBoxContainer/MarginContainer/Buttons" unique_id=1818598517]
56+
custom_minimum_size = Vector2(60, 0)
57+
layout_mode = 2
58+
size_flags_horizontal = 3
59+
text = "Rename"
60+
61+
[node name="Remove" type="Button" parent="MarginContainer/VBoxContainer/HBoxContainer/MarginContainer/Buttons" unique_id=1180899143]
62+
custom_minimum_size = Vector2(60, 0)
63+
layout_mode = 2
64+
size_flags_horizontal = 3
65+
text = "Remove"
66+
67+
[node name="Close" type="Button" parent="MarginContainer/VBoxContainer/HBoxContainer/MarginContainer/Buttons" unique_id=200813023]
68+
custom_minimum_size = Vector2(60, 0)
69+
layout_mode = 2
70+
size_flags_horizontal = 3
71+
size_flags_vertical = 10
72+
text = "Close"
73+
74+
[connection signal="item_selected" from="MarginContainer/VBoxContainer/HBoxContainer/ItemList" to="." method="_on_item_list_item_selected"]
75+
[connection signal="pressed" from="MarginContainer/VBoxContainer/HBoxContainer/MarginContainer/Buttons/Apply" to="." method="_on_apply_pressed"]
76+
[connection signal="pressed" from="MarginContainer/VBoxContainer/HBoxContainer/MarginContainer/Buttons/Rename" to="." method="_on_rename_pressed"]
77+
[connection signal="pressed" from="MarginContainer/VBoxContainer/HBoxContainer/MarginContainer/Buttons/Remove" to="." method="_on_remove_pressed"]

0 commit comments

Comments
 (0)