Skip to content

Commit 7bb649b

Browse files
Replace TabBar with TabPanel for better usability on mobile (#28)
1 parent bf7d698 commit 7bb649b

File tree

17 files changed

+298
-1250
lines changed

17 files changed

+298
-1250
lines changed

assets/icons/TabSwitcher.svg

Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
[remap]
2+
3+
importer="texture"
4+
type="CompressedTexture2D"
5+
uid="uid://8x628rb2bnep"
6+
path="res://.godot/imported/TabSwitcher.svg-2223859299d150806d6ebc1516a3686d.ctex"
7+
metadata={
8+
"vram_texture": false
9+
}
10+
11+
[deps]
12+
13+
source_file="res://assets/icons/TabSwitcher.svg"
14+
dest_files=["res://.godot/imported/TabSwitcher.svg-2223859299d150806d6ebc1516a3686d.ctex"]
15+
16+
[params]
17+
18+
compress/mode=0
19+
compress/high_quality=false
20+
compress/lossy_quality=0.7
21+
compress/hdr_compression=1
22+
compress/normal_map=0
23+
compress/channel_pack=0
24+
mipmaps/generate=false
25+
mipmaps/limit=-1
26+
roughness/mode=0
27+
roughness/src_normal=""
28+
process/fix_alpha_border=true
29+
process/premult_alpha=false
30+
process/normal_map_invert_y=false
31+
process/hdr_as_srgb=false
32+
process/hdr_clamp_exposure=false
33+
process/size_limit=0
34+
detect_3d/compress_to=1
35+
svg/scale=1.0
36+
editor/scale_with_editor_scale=false
37+
editor/convert_colors_with_editor_theme=false

src/autoload/Configs.gd

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ signal active_tab_changed
3030
@warning_ignore("unused_signal")
3131
signal tabs_changed
3232
@warning_ignore("unused_signal")
33+
signal tab_removed
34+
@warning_ignore("unused_signal")
35+
signal tab_selected(index: int)
36+
@warning_ignore("unused_signal")
3337
signal layout_changed
3438

3539
const savedata_path = "user://savedata.tres"

src/autoload/HandlerGUI.gd

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,8 @@ func _ready() -> void:
3131
await get_tree().process_frame # Helps make things more consistent.
3232
update_ui_scale()
3333

34-
if OS.get_name() == "Android":
35-
shortcut_panel = ShortcutPanelScene.instantiate()
36-
get_tree().root.add_child(shortcut_panel)
34+
shortcut_panel = ShortcutPanelScene.instantiate()
35+
get_tree().root.add_child(shortcut_panel)
3736

3837
func _notification(what: int) -> void:
3938
if what == NOTIFICATION_WM_ABOUT:

src/config_classes/SaveData.gd

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -714,7 +714,6 @@ func remove_tab(idx: int) -> void:
714714
_tabs.remove_at(idx)
715715
if idx < _active_tab_index:
716716
new_active_tab_index -= 1
717-
718717
# Clear unnecessary files. This will clear the removed tab too.
719718
var used_file_paths := PackedStringArray()
720719
for tab in _tabs:
@@ -729,11 +728,14 @@ func remove_tab(idx: int) -> void:
729728
if _tabs.is_empty():
730729
_add_new_tab()
731730

732-
emit_changed()
733-
Configs.tabs_changed.emit()
734731
var has_tab_changed := (_active_tab_index == idx)
735732
_active_tab_index = clampi(new_active_tab_index, 0, _tabs.size() - 1)
736733
_tabs[_active_tab_index].activate()
734+
735+
emit_changed()
736+
Configs.tab_removed.emit()
737+
Configs.tabs_changed.emit()
738+
737739
if has_tab_changed:
738740
Configs.active_tab_changed.emit()
739741

src/config_classes/TabData.gd

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const EDITED_FILES_DIR = "user://edited"
88

99
signal status_changed
1010
signal reference_changed
11+
signal data_synced
1112

1213
var presented_name: String:
1314
set(new_value):
@@ -143,7 +144,6 @@ func queue_sync() -> void:
143144
func _sync() -> void:
144145
if not _sync_pending:
145146
return
146-
_sync_pending = false
147147

148148
if is_saved():
149149
# The extension is included in the presented name too.
@@ -163,6 +163,7 @@ func _sync() -> void:
163163
SVGParser.root_to_export_text(edited_text_parse_result.svg)
164164
else:
165165
marked_unsaved = true
166+
166167

167168
elif not FileAccess.file_exists(get_edited_file_path()) or\
168169
SVGParser.text_check_is_root_empty(get_true_svg_text()):
@@ -173,7 +174,9 @@ func _sync() -> void:
173174
empty_unsaved = false
174175
marked_unsaved = false
175176
presented_name = "[ %s ]" % Translator.translate("Unsaved")
176-
177+
178+
_sync_pending = false
179+
data_synced.emit()
177180

178181
func activate() -> void:
179182
active = true

src/ui_parts/display.gd

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
extends VBoxContainer
22

33
const NumberEdit = preload("res://src/ui_widgets/number_edit.gd")
4+
const TabPanel = preload("res://src/ui_parts/tab_panel.tscn")
45

56
@onready var viewport: SubViewport = %Viewport
67
@onready var reference_texture: TextureRect = %Viewport/ReferenceTexture
@@ -14,6 +15,8 @@ const NumberEdit = preload("res://src/ui_widgets/number_edit.gd")
1415
@onready var input_debug_label: Label = %DebugContainer/InputDebugLabel
1516
@onready var toolbar: PanelContainer = $ViewportPanel/VBoxContainer/Toolbar
1617

18+
var tab_panel: PanelContainer
19+
1720
var reference_overlay := false
1821

1922
func _ready() -> void:
@@ -33,7 +36,14 @@ func _ready() -> void:
3336
update_theme()
3437
update_snap_config()
3538
get_window().window_input.connect(_update_input_debug)
36-
39+
40+
tab_panel = TabPanel.instantiate()
41+
var overlay_ref := ColorRect.new()
42+
overlay_ref.color = Color(0, 0, 0, 0.4)
43+
overlay_ref.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
44+
overlay_ref.hide()
45+
get_tree().root.add_child.call_deferred(overlay_ref)
46+
overlay_ref.add_child(tab_panel)
3747

3848
func update_translations() -> void:
3949
%LeftMenu/Visuals.tooltip_text = Translator.translate("Visuals")
@@ -159,3 +169,8 @@ func _update_input_debug(event: InputEvent) -> void:
159169
new_text = new_text.right(-new_text.find("\n") - 1)
160170
new_text += event_text + "\n"
161171
input_debug_label.text = new_text
172+
173+
174+
func _on_tab_switcher_pressed() -> void:
175+
tab_panel.get_parent().show()
176+
tab_panel.animate_in()

src/ui_parts/display.tscn

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@
88
[ext_resource type="PackedScene" uid="uid://dad7fkhmsooc6" path="res://src/ui_widgets/number_edit.tscn" id="7_wrrfr"]
99
[ext_resource type="PackedScene" uid="uid://oltvrf01xrxl" path="res://src/ui_widgets/zoom_menu.tscn" id="8_xtdmn"]
1010
[ext_resource type="Script" uid="uid://b6pmlbnl76wmm" path="res://src/ui_parts/viewport.gd" id="9_4xrk7"]
11-
[ext_resource type="Script" uid="uid://rqrxhe8wa6fn" path="res://src/ui_parts/tab_bar.gd" id="9_rll1m"]
1211
[ext_resource type="Shader" uid="uid://i2y5pyhcgra2" path="res://src/shaders/zoom_shader.gdshader" id="10_x7ybk"]
1312
[ext_resource type="Texture2D" uid="uid://c68og6bsqt0lb" path="res://assets/icons/backgrounds/Checkerboard.svg" id="11_1bm1s"]
1413
[ext_resource type="Script" uid="uid://dtplje5mhdmrj" path="res://src/ui_parts/display_texture.gd" id="12_qi23s"]
1514
[ext_resource type="Script" uid="uid://csqewpxr21ywy" path="res://src/ui_parts/handles_manager.gd" id="13_lwhwy"]
15+
[ext_resource type="Texture2D" uid="uid://8x628rb2bnep" path="res://assets/icons/TabSwitcher.svg" id="14_ryr8t"]
1616
[ext_resource type="Script" uid="uid://cm5033meho5vr" path="res://src/ui_widgets/camera.gd" id="15_hevpa"]
1717

1818
[sub_resource type="ShaderMaterial" id="ShaderMaterial_kqplg"]
@@ -33,13 +33,6 @@ grow_vertical = 2
3333
theme_override_constants/separation = 0
3434
script = ExtResource("1_oib5g")
3535

36-
[node name="TabBar" type="Control" parent="."]
37-
clip_contents = true
38-
custom_minimum_size = Vector2(0, 24)
39-
layout_mode = 2
40-
size_flags_horizontal = 3
41-
script = ExtResource("9_rll1m")
42-
4336
[node name="ViewportPanel" type="PanelContainer" parent="."]
4437
layout_mode = 2
4538
size_flags_vertical = 3
@@ -58,7 +51,7 @@ unique_name_in_owner = true
5851
disable_3d = true
5952
handle_input_locally = false
6053
gui_snap_controls_to_pixels = false
61-
size = Vector2i(720, 1225)
54+
size = Vector2i(720, 1249)
6255
size_2d_override_stretch = true
6356
render_target_update_mode = 4
6457
script = ExtResource("9_4xrk7")
@@ -111,7 +104,6 @@ alignment = 2
111104
[node name="LeftMenu" type="HBoxContainer" parent="ViewportPanel/VBoxContainer/Toolbar/ViewportOptions"]
112105
unique_name_in_owner = true
113106
layout_mode = 2
114-
size_flags_horizontal = 2
115107
theme_override_constants/separation = 5
116108

117109
[node name="Visuals" type="Button" parent="ViewportPanel/VBoxContainer/Toolbar/ViewportOptions/LeftMenu"]
@@ -155,6 +147,22 @@ max_length = 20
155147
min_value = 0.001
156148
allow_lower = false
157149

150+
[node name="spacer" type="Control" parent="ViewportPanel/VBoxContainer/Toolbar/ViewportOptions"]
151+
layout_mode = 2
152+
size_flags_horizontal = 3
153+
154+
[node name="TabSwitcher" type="Button" parent="ViewportPanel/VBoxContainer/Toolbar/ViewportOptions"]
155+
layout_mode = 2
156+
focus_mode = 0
157+
mouse_default_cursor_shape = 2
158+
theme_type_variation = &"IconButton"
159+
icon = ExtResource("14_ryr8t")
160+
icon_alignment = 1
161+
162+
[node name="spacer2" type="Control" parent="ViewportPanel/VBoxContainer/Toolbar/ViewportOptions"]
163+
layout_mode = 2
164+
size_flags_horizontal = 3
165+
158166
[node name="ZoomMenu" parent="ViewportPanel/VBoxContainer/Toolbar/ViewportOptions" instance=ExtResource("8_xtdmn")]
159167
unique_name_in_owner = true
160168
layout_mode = 2
@@ -197,5 +205,6 @@ horizontal_alignment = 2
197205
[connection signal="pressed" from="ViewportPanel/VBoxContainer/Toolbar/ViewportOptions/LeftMenu/Reference" to="." method="_on_reference_pressed"]
198206
[connection signal="toggled" from="ViewportPanel/VBoxContainer/Toolbar/ViewportOptions/LeftMenu/Snapping/SnapButton" to="." method="_on_snap_button_toggled"]
199207
[connection signal="value_changed" from="ViewportPanel/VBoxContainer/Toolbar/ViewportOptions/LeftMenu/Snapping/SnapNumberEdit" to="." method="_on_snap_number_edit_value_changed"]
208+
[connection signal="pressed" from="ViewportPanel/VBoxContainer/Toolbar/ViewportOptions/TabSwitcher" to="." method="_on_tab_switcher_pressed"]
200209
[connection signal="zoom_changed" from="ViewportPanel/VBoxContainer/Toolbar/ViewportOptions/ZoomMenu" to="ViewportPanel/VBoxContainer/ViewportContainer/Viewport" method="_on_zoom_changed"]
201210
[connection signal="zoom_reset_pressed" from="ViewportPanel/VBoxContainer/Toolbar/ViewportOptions/ZoomMenu" to="ViewportPanel/VBoxContainer/ViewportContainer/Viewport" method="center_frame"]

src/ui_parts/editor_scene.gd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ func update_layout() -> void:
4444
top_margin_container.add_theme_constant_override("margin_top", 6)
4545
top_margin_container.add_theme_constant_override("margin_bottom", 6)
4646
top_margin_container.add_theme_constant_override("margin_left", 6)
47+
top_margin_container.add_theme_constant_override("margin_right", 6)
4748
top_margin_container.end_bulk_theme_override()
4849
main_splitter.add_child(top_margin_container)
4950

src/ui_parts/tab_panel.gd

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
extends PanelContainer
2+
3+
const tabItem = preload("res://src/ui_widgets/tab_item.tscn")
4+
5+
@onready var tab_container: VBoxContainer = $VBoxContainer/ScrollContainer/VBoxContainer
6+
7+
func _ready() -> void:
8+
get_parent().gui_input.connect(_on_parent_gui_input)
9+
Configs.tab_removed.connect(refresh_tabs)
10+
Configs.tab_selected.connect(highlight_active_tab)
11+
refresh_tabs()
12+
13+
func animate_in() -> void:
14+
var tween := get_tree().create_tween()
15+
tween.tween_property(self, "position:x", 0, 0.3).from(-200).set_ease(Tween.EASE_IN_OUT)
16+
17+
func animate_out() -> void:
18+
var tween := get_tree().create_tween()
19+
tween.tween_property(self, "position:x", -200, 0.3).set_ease(Tween.EASE_IN_OUT)
20+
await tween.finished
21+
get_parent().hide()
22+
23+
func refresh_tabs() -> void:
24+
print("Refreshing tabs...")
25+
for i in tab_container.get_children():
26+
i.queue_free()
27+
28+
var has_transient_tab := not State.transient_tab_path.is_empty()
29+
var total_tabs := Configs.savedata.get_tab_count()
30+
31+
# If there's a transient tab, we want to draw one more
32+
if has_transient_tab:
33+
total_tabs += 1
34+
35+
for tab_index in total_tabs:
36+
var is_transient := (has_transient_tab and tab_index == total_tabs)
37+
var tab_name := ""
38+
var svg_text := ""
39+
40+
if is_transient:
41+
tab_name = State.transient_tab_path.get_file()
42+
else:
43+
var tab_data = Configs.savedata.get_tab(tab_index)
44+
if tab_data._sync_pending:
45+
await tab_data.data_synced
46+
tab_name = tab_data.presented_name
47+
svg_text = FileAccess.get_file_as_string(TabData.get_edited_file_path_for_id(tab_data.id))
48+
if tab_data.marked_unsaved:
49+
tab_name = "* " + tab_name
50+
51+
var is_active := (
52+
(is_transient and has_transient_tab) or
53+
(not is_transient and tab_index == Configs.savedata.get_active_tab_index())
54+
)
55+
56+
var tab = tabItem.instantiate()
57+
tab_container.add_child(tab)
58+
tab.setup(tab_name, svg_text, is_active)
59+
60+
func highlight_active_tab(new_index: int) -> void:
61+
var active_index = Configs.savedata.get_active_tab_index()
62+
tab_container.get_child(active_index).highlight(false)
63+
Configs.savedata.set_active_tab_index(new_index)
64+
tab_container.get_child(new_index).highlight(true)
65+
66+
func _on_new_tab_pressed() -> void:
67+
Configs.savedata.add_empty_tab()
68+
refresh_tabs()
69+
70+
func _on_parent_gui_input(event: InputEvent) -> void:
71+
if not event is InputEventMouseButton:
72+
return
73+
if event.is_pressed() and event.button_index == MOUSE_BUTTON_LEFT:
74+
animate_out()

0 commit comments

Comments
 (0)