diff --git a/art/custom_icons.svg b/art/custom_icons.svg
new file mode 100644
index 00000000..d890c42e
--- /dev/null
+++ b/art/custom_icons.svg
@@ -0,0 +1,83 @@
+
+
+
diff --git a/art/logo.svg b/art/logo.svg
new file mode 100644
index 00000000..53c33cab
--- /dev/null
+++ b/art/logo.svg
@@ -0,0 +1,13 @@
+
+
+
diff --git a/lorien/Assets/I18n/de.txt b/lorien/Assets/I18n/de.txt
index ba676f7a..32d5dfe4 100644
--- a/lorien/Assets/I18n/de.txt
+++ b/lorien/Assets/I18n/de.txt
@@ -4,15 +4,14 @@ LANGUAGE_NAME Deutsch
# Menu
# --------------------------------------------------------------------------------
-MENU_OPEN Öffnen
+MENU_OPEN Öffnen...
MENU_SAVE Speichern
-MENU_SAVE_AS Speichern als..
+MENU_SAVE_AS Speichern als...
MENU_SETTINGS Einstellungen
MENU_MANUAL Benutzeranleitung
MENU_BUG_TRACKER Bug Tracker
MENU_ABOUT Über
-MENU_EXPORT Exportieren
-MENU_EXPORT_PNG Exportieren als PNG
+MENU_EXPORT Exportieren...
# -----------------------------------------------------------------------------
# Toolbar
diff --git a/lorien/Assets/I18n/en.txt b/lorien/Assets/I18n/en.txt
index 4b654f76..361af844 100644
--- a/lorien/Assets/I18n/en.txt
+++ b/lorien/Assets/I18n/en.txt
@@ -4,15 +4,14 @@ LANGUAGE_NAME English
# Menu strings
# -----------------------------------------------------------------------------
-MENU_OPEN Open
+MENU_OPEN Open...
MENU_SAVE Save
-MENU_SAVE_AS Save as..
+MENU_SAVE_AS Save as...
MENU_SETTINGS Settings
MENU_MANUAL Manual
MENU_BUG_TRACKER Bug Tracker
MENU_ABOUT About
-MENU_EXPORT Export
-MENU_EXPORT_PNG Export Canvas as PNG
+MENU_EXPORT Export...
# -----------------------------------------------------------------------------
# Toolbar
@@ -61,6 +60,7 @@ SETTINGS_TITLE Settings
SETTINGS_GENERAL General
SETTINGS_APPEARANCE Appearance
SETTINGS_RENDERING Rendering
+SETTINGS_KEYBINDINGS Keybindings
SETTINGS_PRESSURE_SENSITIVITY Pressure Sensitivity
SETTINGS_BRUSH_SIZE Default Brush Size
SETTINGS_CANVAS_COLOR Default Canvas Color
@@ -138,3 +138,42 @@ SAVE Save
DISCARD Discard
CANCEL Cancel
DELETE Delete
+
+# -----------------------------------------------------------------------------
+# Action names
+# -----------------------------------------------------------------------------
+
+ACTION_shortcut_save_project Save project
+ACTION_shortcut_new_project New Project
+ACTION_shortcut_open_project Open Project
+ACTION_shortcut_undo Undo
+ACTION_shortcut_redo Redo
+ACTION_shortcut_brush_tool Brush tool
+ACTION_shortcut_line_tool Line tool
+ACTION_shortcut_eraser_tool Eraser tool
+ACTION_shortcut_select_tool Selection tool
+ACTION_shortcut_move_tool Move tool
+ACTION_shortcut_rectangle_tool Rectangle tool
+ACTION_shortcut_circle_tool Circle tool
+ACTION_shortcut_export_project Export project
+ACTION_deselect_all_strokes Deselect all strokes
+ACTION_center_canvas_to_mouse Space
+ACTION_delete_selected_strokes Delete selected strokes
+ACTION_copy_strokes Copy
+ACTION_paste_strokes Paste
+ACTION_duplicate_strokes Duplicate strokes
+ACTION_toggle_distraction_free_mode Toggle distraction free mode
+ACTION_toggle_player EFF TWELVE
+ACTION_toggle_fullscreen Toggle fullscreen
+
+# -----------------------------------------------------------------------------
+# Kebindings dialog messages
+# -----------------------------------------------------------------------------
+
+# Bind key dialog
+KEYBINDING_DIALOG_BIND_WINDOW_NAME Bind key
+KEYBINDING_DIALOG_BIND_ACTION Action: {action}
+
+# Rebind already bound key dialog
+KEYBINDING_DIALOG_REBIND_WINDOW_NAME Rebind key?
+KEYBINDING_DIALOG_REBIND_MESSAGE '{event}' already is bound to {action}.\n\nDo you want to rebind?
diff --git a/lorien/Assets/I18n/es.txt b/lorien/Assets/I18n/es.txt
index e2cf8a62..897f10a8 100644
--- a/lorien/Assets/I18n/es.txt
+++ b/lorien/Assets/I18n/es.txt
@@ -4,17 +4,14 @@ LANGUAGE_NAME Español
# Menu strings
# -----------------------------------------------------------------------------
-MENU_OPEN Abrir
+MENU_OPEN Abrir...
MENU_SAVE Guardar
-MENU_SAVE_AS Guardar como..
+MENU_SAVE_AS Guardar como...
MENU_SETTINGS Configuración
MENU_MANUAL Manual
-# Changed from "Bug tracker" to "Report a bug"
MENU_BUG_TRACKER Reportar un error
-# Changed from "About" to "About Lorien"
MENU_ABOUT Acerca de Lorien
-MENU_EXPORT Exportar
-MENU_EXPORT_PNG Exportar Canvas como PNG
+MENU_EXPORT Exportar...
# -----------------------------------------------------------------------------
# Toolbar
diff --git a/lorien/Assets/I18n/fr.txt b/lorien/Assets/I18n/fr.txt
index 88bcd955..4be2831f 100644
--- a/lorien/Assets/I18n/fr.txt
+++ b/lorien/Assets/I18n/fr.txt
@@ -4,15 +4,14 @@ LANGUAGE_NAME Français
# Menu strings
# -----------------------------------------------------------------------------
-MENU_OPEN Ouvrir
+MENU_OPEN Ouvrir...
MENU_SAVE Enregistrer
MENU_SAVE_AS Enregistrer sous...
MENU_SETTINGS Paramètres
MENU_MANUAL Documentation
MENU_BUG_TRACKER Suivi des bogues
MENU_ABOUT À propos
-MENU_EXPORT Exporter
-MENU_EXPORT_PNG Exporter la zone visible en PNG
+MENU_EXPORT Exporter...
# -----------------------------------------------------------------------------
# Toolbar
diff --git a/lorien/Assets/I18n/it.txt b/lorien/Assets/I18n/it.txt
index 44e2be9b..88d71692 100644
--- a/lorien/Assets/I18n/it.txt
+++ b/lorien/Assets/I18n/it.txt
@@ -4,15 +4,14 @@ LANGUAGE_NAME Italiano
# Menu
# -----------------------------------------------------------------------------
-MENU_OPEN Apri
+MENU_OPEN Apri...
MENU_SAVE Salva
-MENU_SAVE_AS Salva come..
+MENU_SAVE_AS Salva come...
MENU_SETTINGS Impostazioni
MENU_MANUAL Manuale
MENU_BUG_TRACKER Monitoraggio dei bug
MENU_ABOUT Informazioni
-MENU_EXPORT Esporta
-MENU_EXPORT_PNG Esporta Tela come PNG
+MENU_EXPORT Esporta...
# -----------------------------------------------------------------------------
# Toolbar
diff --git a/lorien/Assets/I18n/ko.txt b/lorien/Assets/I18n/ko.txt
index 87b16deb..e31dc912 100644
--- a/lorien/Assets/I18n/ko.txt
+++ b/lorien/Assets/I18n/ko.txt
@@ -4,15 +4,14 @@ LANGUAGE_NAME 한국어
# Menu strings
# -----------------------------------------------------------------------------
-MENU_OPEN 열기
+MENU_OPEN 열기...
MENU_SAVE 저장
-MENU_SAVE_AS 다른 이름으로 저장..
+MENU_SAVE_AS 다른 이름으로 저장...
MENU_SETTINGS 설정
MENU_MANUAL 설명서
MENU_BUG_TRACKER 버그 제보
MENU_ABOUT 정보
-MENU_EXPORT 내보내기
-MENU_EXPORT_PNG PNG 파일로 내보내기
+MENU_EXPORT 내보내기...
# -----------------------------------------------------------------------------
# Toolbar
@@ -94,14 +93,14 @@ ABOUT_DIALOG_EASTEREGG 이스터에그:
# -----------------------------------------------------------------------------
UNSAVED_CHANGES_DIALOG_TITLE 변경사항을 저장할까요?
-UNSAVED_CHANGES_DIALOG_TEXT 파일을 닫기전에 저장할까요?
+UNSAVED_CHANGES_DIALOG_TEXT 파일을 닫기 전에 저장할까요?
# -----------------------------------------------------------------------------
# Exit dialog
# -----------------------------------------------------------------------------
EXIT_DIALOG_TITLE 변경사항을 저장할까요?
-EXIT_DIALOG_TEXT Lorien을 나가지전에 저장할까요?
+EXIT_DIALOG_TEXT Lorien을 나가기 전에 저장할까요?
# -----------------------------------------------------------------------------
# New palette dialog
diff --git a/lorien/Assets/I18n/pt-BR.txt b/lorien/Assets/I18n/pt-BR.txt
index 1f140589..5727c59d 100644
--- a/lorien/Assets/I18n/pt-BR.txt
+++ b/lorien/Assets/I18n/pt-BR.txt
@@ -4,15 +4,14 @@ LANGUAGE_NAME Português Brasil
# Menu strings
# -----------------------------------------------------------------------------
-MENU_OPEN Abrir
+MENU_OPEN Abrir...
MENU_SAVE Salvar
-MENU_SAVE_AS Salvar como..
+MENU_SAVE_AS Salvar como...
MENU_SETTINGS Configuração
MENU_MANUAL Manual
MENU_BUG_TRACKER Reportar um bug
MENU_ABOUT Sobre
-MENU_EXPORT Exportar
-MENU_EXPORT_PNG Exportar Canvas como PNG
+MENU_EXPORT Exportar...
# -----------------------------------------------------------------------------
# Toolbar
diff --git a/lorien/Assets/I18n/ru.txt b/lorien/Assets/I18n/ru.txt
index 43143c66..364f61d6 100644
--- a/lorien/Assets/I18n/ru.txt
+++ b/lorien/Assets/I18n/ru.txt
@@ -4,15 +4,14 @@ LANGUAGE_NAME Русский
# Menu strings
# -----------------------------------------------------------------------------
-MENU_OPEN Open # TODO
+MENU_OPEN Open... # TODO
MENU_SAVE Сохранить
-MENU_SAVE_AS Сохранить как..
+MENU_SAVE_AS Сохранить как...
MENU_SETTINGS Настройки
MENU_MANUAL Руководство
MENU_BUG_TRACKER Баг трекер
MENU_ABOUT О Lorien
-MENU_EXPORT Экспортировать
-MENU_EXPORT_PNG Экспортировать холст как PNG
+MENU_EXPORT Экспортировать...
# -----------------------------------------------------------------------------
# Toolbar
diff --git a/lorien/Assets/I18n/tr.txt b/lorien/Assets/I18n/tr.txt
index fca49bc5..25029eb8 100644
--- a/lorien/Assets/I18n/tr.txt
+++ b/lorien/Assets/I18n/tr.txt
@@ -4,15 +4,14 @@ LANGUAGE_NAME Türkçe
# Menu strings
# -----------------------------------------------------------------------------
-MENU_OPEN Aç
+MENU_OPEN ... Aç
MENU_SAVE Kaydet
MENU_SAVE_AS ... Olarak Kaydet
MENU_SETTINGS Ayarlar
MENU_MANUAL Kullanım Kılauzu
MENU_BUG_TRACKER Hata İzleyici
MENU_ABOUT Hakkında
-MENU_EXPORT Dışa Aktar
-MENU_EXPORT_PNG Tuvali PNG Olarak Dışa Aktar
+MENU_EXPORT ... Dışa Aktar
# -----------------------------------------------------------------------------
# Toolbar
diff --git a/lorien/Assets/I18n/zh-CN.txt b/lorien/Assets/I18n/zh-CN.txt
index 8285ddc5..6c0348f5 100644
--- a/lorien/Assets/I18n/zh-CN.txt
+++ b/lorien/Assets/I18n/zh-CN.txt
@@ -4,15 +4,14 @@ LANGUAGE_NAME Simplified Chinese
# Menu strings
# -----------------------------------------------------------------------------
-MENU_OPEN 打开
+MENU_OPEN 打开...
MENU_SAVE 保存
-MENU_SAVE_AS 另存为..
+MENU_SAVE_AS 另存为...
MENU_SETTINGS 设置
MENU_MANUAL 手册
MENU_BUG_TRACKER Bug 追踪器
MENU_ABOUT 关于
-MENU_EXPORT 导出
-MENU_EXPORT_PNG 将画布导出为PNG
+MENU_EXPORT 导出...
# -----------------------------------------------------------------------------
# Toolbar
diff --git a/lorien/Assets/I18n/zh-TW.txt b/lorien/Assets/I18n/zh-TW.txt
index 98a67652..1541428c 100644
--- a/lorien/Assets/I18n/zh-TW.txt
+++ b/lorien/Assets/I18n/zh-TW.txt
@@ -4,15 +4,14 @@ LANGUAGE_NAME Traditional Chinese
# Menu strings
# -----------------------------------------------------------------------------
-MENU_OPEN 開啟
+MENU_OPEN 開啟...
MENU_SAVE 存檔
-MENU_SAVE_AS 另存為..
+MENU_SAVE_AS 另存為...
MENU_SETTINGS 設定
MENU_MANUAL 線上說明
MENU_BUG_TRACKER 問題追蹤
MENU_ABOUT 關於
-MENU_EXPORT 匯出
-MENU_EXPORT_PNG 將畫布匯出成 PNG 圖檔
+MENU_EXPORT 匯出...
# -----------------------------------------------------------------------------
# Toolbar
diff --git a/lorien/InfiniteCanvas/InfiniteCanvas.gd b/lorien/InfiniteCanvas/InfiniteCanvas.gd
index 65cd2775..1afdf6ca 100644
--- a/lorien/InfiniteCanvas/InfiniteCanvas.gd
+++ b/lorien/InfiniteCanvas/InfiniteCanvas.gd
@@ -46,21 +46,31 @@ func _ready():
_viewport.size = OS.window_size
# -------------------------------------------------------------------------------------------------
-func _input(event: InputEvent) -> void:
+func _unhandled_key_input(event: InputEventKey) -> void:
+ _process_event(event)
+
+# -------------------------------------------------------------------------------------------------
+func _gui_input(event: InputEvent) -> void:
+ _process_event(event)
+
+# -------------------------------------------------------------------------------------------------
+func _process_event(event: InputEvent) -> void:
if event is InputEventMouseMotion:
info.current_pressure = event.pressure
-# -------------------------------------------------------------------------------------------------
-func _process(delta: float) -> void:
- # Deselect selected strokes with shortcut key
- if Input.is_action_just_pressed("deselect_all_strokes"):
+ if event.is_action("deselect_all_strokes"):
if _active_tool == _selection_tool:
_selection_tool.deselect_all_strokes()
-
- # Delete selected strokes with shortcut key
- if Input.is_action_just_pressed("delete_selected_strokes"):
+
+ if event.is_action("delete_selected_strokes"):
if _active_tool == _selection_tool:
_delete_selected_strokes()
+
+ if ! get_tree().is_input_handled():
+ _camera.tool_event(event)
+ if ! get_tree().is_input_handled():
+ if _active_tool.enabled:
+ _active_tool.tool_event(event)
# -------------------------------------------------------------------------------------------------
func center_to_mouse() -> void:
@@ -70,8 +80,8 @@ func center_to_mouse() -> void:
# -------------------------------------------------------------------------------------------------
func use_tool(tool_type: int) -> void:
- _active_tool.enabled = false
var prev_tool := _active_tool
+ var prev_status := prev_tool.enabled
match tool_type:
Types.Tool.BRUSH:
@@ -94,10 +104,12 @@ func use_tool(tool_type: int) -> void:
_use_optimizer = false
if prev_tool != _active_tool:
+ prev_tool.enabled = false
prev_tool.reset()
- _active_tool.enabled = true
+ _active_tool.enabled = prev_status
_active_tool.get_cursor()._on_zoom_changed(_camera.zoom.x)
+
# -------------------------------------------------------------------------------------------------
func set_background_color(color: Color) -> void:
_background_color = color
@@ -337,15 +349,15 @@ func _undo_delete_stroke(stroke: BrushStroke) -> void:
# -------------------------------------------------------------------------------------------------
func _on_window_resized() -> void:
- # Multiplying by scale is needed to fix canvas after changing rect_scale (set_scale() method)
- _viewport.size = get_viewport_rect().size * _scale
+ # Stops viewport from resetting scale when root viewport changes size
+ set_canvas_scale(_scale)
# -------------------------------------------------------------------------------------------------
func set_canvas_scale(scale: float) -> void:
_scale = scale
- _grid.set_grid_scale(_scale)
+ _grid.set_grid_scale(scale)
# Needed to stop stretching of the canvas
- set_scale(Vector2(1 / _scale, 1 / _scale))
+ _viewport.set_size(get_viewport().get_size())
# -------------------------------------------------------------------------------------------------
func get_canvas_scale() -> float:
diff --git a/lorien/InfiniteCanvas/PanZoomCamera.gd b/lorien/InfiniteCanvas/PanZoomCamera.gd
index 146338b8..0c2379de 100644
--- a/lorien/InfiniteCanvas/PanZoomCamera.gd
+++ b/lorien/InfiniteCanvas/PanZoomCamera.gd
@@ -22,13 +22,13 @@ func set_zoom_level(zoom_level: float) -> void:
# -------------------------------------------------------------------------------------------------
func do_center(screen_space_center_point: Vector2) -> void:
- var screen_space_center := get_viewport().size / 2
+ var screen_space_center := get_viewport().get_size() / 2
var delta := screen_space_center - screen_space_center_point
get_viewport().warp_mouse(screen_space_center)
_do_pan(delta)
# -------------------------------------------------------------------------------------------------
-func _input(event: InputEvent) -> void:
+func tool_event(event: InputEvent) -> void:
if _is_input_enabled:
if event is InputEventMouseButton:
diff --git a/lorien/InfiniteCanvas/Tools/BrushTool.gd b/lorien/InfiniteCanvas/Tools/BrushTool.gd
index da07475c..c4757bbf 100644
--- a/lorien/InfiniteCanvas/Tools/BrushTool.gd
+++ b/lorien/InfiniteCanvas/Tools/BrushTool.gd
@@ -15,12 +15,12 @@ var _last_accepted_position: Vector2
var _first_point := false
# -------------------------------------------------------------------------------------------------
-func _input(event: InputEvent) -> void:
+func tool_event(event: InputEvent) -> void:
_cursor.set_pressure(1.0)
if event is InputEventMouseMotion:
_cursor.global_position = xform_vector2(event.global_position)
- _current_position = event.position * _canvas.get_canvas_scale()
+ _current_position = event.position
_current_pressure = event.pressure
if performing_stroke:
_cursor.set_pressure(event.pressure)
diff --git a/lorien/InfiniteCanvas/Tools/CanvasTool.gd b/lorien/InfiniteCanvas/Tools/CanvasTool.gd
index 9dc75643..edb98977 100644
--- a/lorien/InfiniteCanvas/Tools/CanvasTool.gd
+++ b/lorien/InfiniteCanvas/Tools/CanvasTool.gd
@@ -19,6 +19,10 @@ func _ready():
_canvas = get_parent()
set_enabled(false)
+# -------------------------------------------------------------------------------------------------
+func tool_event(event: InputEvent) -> void:
+ pass
+
# -------------------------------------------------------------------------------------------------
func _on_brush_color_changed(color: Color) -> void:
pass
@@ -38,7 +42,7 @@ func set_enabled(e: bool) -> void:
set_process_input(enabled)
_cursor.set_visible(enabled)
if enabled && _canvas:
- _cursor.global_position = xform_vector2(get_viewport().get_mouse_position()) * _canvas.get_canvas_scale()
+ _cursor.global_position = xform_vector2(get_viewport().get_mouse_position())
# -------------------------------------------------------------------------------------------------
func get_enabled() -> bool:
@@ -88,7 +92,7 @@ func end_stroke() -> void:
# -------------------------------------------------------------------------------------------------
func xform_vector2(v: Vector2) -> Vector2:
- return _canvas.get_camera().xform(v)
+ return _canvas.get_camera().xform(v * _canvas.get_canvas_scale())
# -------------------------------------------------------------------------------------------------
func reset() -> void:
diff --git a/lorien/InfiniteCanvas/Tools/CircleTool.gd b/lorien/InfiniteCanvas/Tools/CircleTool.gd
index 0fcbf09f..063d8b41 100644
--- a/lorien/InfiniteCanvas/Tools/CircleTool.gd
+++ b/lorien/InfiniteCanvas/Tools/CircleTool.gd
@@ -22,7 +22,7 @@ func _init():
cos_arr[i] = cos(deg2rad(i))
# -------------------------------------------------------------------------------------------------
-func _input(event: InputEvent) -> void:
+func tool_event(event: InputEvent) -> void:
_cursor.set_pressure(1.0)
var should_draw_circle := Input.is_key_pressed(KEY_SHIFT)
diff --git a/lorien/InfiniteCanvas/Tools/EraserTool.gd b/lorien/InfiniteCanvas/Tools/EraserTool.gd
index 84f89505..2165b635 100644
--- a/lorien/InfiniteCanvas/Tools/EraserTool.gd
+++ b/lorien/InfiniteCanvas/Tools/EraserTool.gd
@@ -11,7 +11,7 @@ var _removed_strokes := [] # BrushStroke -> Vector2
var _bounding_box_cache = {} # BrushStroke -> Rect2
# -------------------------------------------------------------------------------------------------
-func _input(event: InputEvent) -> void:
+func tool_event(event: InputEvent) -> void:
if event is InputEventMouseMotion:
_last_mouse_position = xform_vector2(event.global_position)
_cursor.global_position = _last_mouse_position
diff --git a/lorien/InfiniteCanvas/Tools/LineTool.gd b/lorien/InfiniteCanvas/Tools/LineTool.gd
index 2bf384f5..2d596a95 100644
--- a/lorien/InfiniteCanvas/Tools/LineTool.gd
+++ b/lorien/InfiniteCanvas/Tools/LineTool.gd
@@ -11,7 +11,7 @@ var _head: Vector2
var _tail: Vector2
# -------------------------------------------------------------------------------------------------
-func _input(event: InputEvent) -> void:
+func tool_event(event: InputEvent) -> void:
_cursor.set_pressure(1.0)
# Snap modifier
diff --git a/lorien/InfiniteCanvas/Tools/RectangleTool.gd b/lorien/InfiniteCanvas/Tools/RectangleTool.gd
index 43625d5c..36faf019 100644
--- a/lorien/InfiniteCanvas/Tools/RectangleTool.gd
+++ b/lorien/InfiniteCanvas/Tools/RectangleTool.gd
@@ -9,7 +9,7 @@ export var pressure_curve: Curve
var _start_position_top_left: Vector2
# -------------------------------------------------------------------------------------------------
-func _input(event: InputEvent) -> void:
+func tool_event(event: InputEvent) -> void:
_cursor.set_pressure(1.0)
if event is InputEventMouseMotion:
diff --git a/lorien/InfiniteCanvas/Tools/SelectionTool.gd b/lorien/InfiniteCanvas/Tools/SelectionTool.gd
index cdbad36d..d4397c2f 100644
--- a/lorien/InfiniteCanvas/Tools/SelectionTool.gd
+++ b/lorien/InfiniteCanvas/Tools/SelectionTool.gd
@@ -35,7 +35,26 @@ func _ready():
_selection_rectangle = get_node(selection_rectangle_path)
# ------------------------------------------------------------------------------------------------
-func _input(event: InputEvent) -> void:
+func tool_event(event: InputEvent) -> void:
+ var duplicate_pressed := Utils.event_pressed_bug_workaround("duplicate_strokes", event)
+ var copy_pressed := Utils.event_pressed_bug_workaround("copy_strokes", event)
+ var paste_pressed := Utils.event_pressed_bug_workaround("paste_strokes", event)
+
+ if copy_pressed || duplicate_pressed:
+ var strokes := get_selected_strokes()
+ if strokes.size() > 0:
+ Utils.remove_group_from_all_nodes(GROUP_COPIED_STROKES)
+ for stroke in strokes:
+ stroke.add_to_group(GROUP_COPIED_STROKES)
+ print("Copied %d strokes" % strokes.size())
+
+ if paste_pressed || duplicate_pressed:
+ var strokes := get_tree().get_nodes_in_group(GROUP_COPIED_STROKES)
+ if !strokes.empty():
+ deselect_all_strokes()
+ _cursor.mode = SelectionCursor.Mode.MOVE
+ _paste_strokes(strokes)
+
if event is InputEventMouseButton:
if event.button_index == BUTTON_LEFT:
# LMB down - decide if we should select/multiselect or move the selection
@@ -100,25 +119,6 @@ func _input(event: InputEvent) -> void:
elif get_selected_strokes().size() > 0:
_cursor.mode = SelectionCursor.Mode.MOVE
-# ------------------------------------------------------------------------------------------------
-func _process(delta: float) -> void:
- # Copy selected strokes
- if Input.is_action_just_pressed("copy_strokes") || Input.is_action_just_pressed("duplicate_strokes"):
- var strokes := get_selected_strokes()
- if strokes.size() > 0:
- Utils.remove_group_from_all_nodes(GROUP_COPIED_STROKES)
- for stroke in strokes:
- stroke.add_to_group(GROUP_COPIED_STROKES)
- print("Copied %d strokes" % strokes.size())
-
- # Paste strokes
- if Input.is_action_just_pressed("paste_strokes") || Input.is_action_just_pressed("duplicate_strokes"):
- var strokes := get_tree().get_nodes_in_group(GROUP_COPIED_STROKES)
- if !strokes.empty():
- deselect_all_strokes()
- _cursor.mode = SelectionCursor.Mode.MOVE
- _paste_strokes(strokes)
-
# ------------------------------------------------------------------------------------------------
func compute_selection(start_pos: Vector2, end_pos: Vector2) -> void:
var selection_rect : Rect2 = Utils.calculate_rect(start_pos, end_pos)
diff --git a/lorien/Main.gd b/lorien/Main.gd
index f0eae694..9e04ff4f 100644
--- a/lorien/Main.gd
+++ b/lorien/Main.gd
@@ -114,7 +114,6 @@ func _exit_tree():
# -------------------------------------------------------------------------------------------------
func _process(delta):
- _handle_input_actions()
_statusbar.set_stroke_count(_canvas.info.stroke_count)
_statusbar.set_point_count(_canvas.info.point_count)
_statusbar.set_pressure(_canvas.info.current_pressure)
@@ -128,48 +127,41 @@ func _process(delta):
_menubar.update_tab_title(active_project)
# -------------------------------------------------------------------------------------------------
-func _handle_input_actions() -> void:
- if !is_dialog_open():
- var copy := Input.is_action_just_pressed("copy_strokes")
- var paste := Input.is_action_just_pressed("paste_strokes")
- var duplicate := Input.is_action_just_pressed("duplicate_strokes")
- if copy || paste || duplicate:
- return
-
- if Input.is_action_just_pressed("toggle_player"):
+func _unhandled_input(event):
+ if ! is_dialog_open():
+ if Utils.event_pressed_bug_workaround("toggle_player", event):
_toggle_player()
if !_player_enabled:
-
- if Input.is_action_just_pressed("shortcut_new_project"):
+ if Utils.event_pressed_bug_workaround("shortcut_new_project", event):
_on_create_new_project()
- elif Input.is_action_just_pressed("shortcut_open_project"):
+ elif Utils.event_pressed_bug_workaround("shortcut_open_project", event):
_toolbar._on_OpenFileButton_pressed()
- elif Input.is_action_just_pressed("shortcut_save_project"):
+ elif Utils.event_pressed_bug_workaround("shortcut_save_project", event):
_on_save_project()
- elif Input.is_action_just_pressed("shortcut_export_project"):
+ elif Utils.event_pressed_bug_workaround("shortcut_export_project", event):
_export_svg()
- elif Input.is_action_just_pressed("shortcut_undo"):
+ elif Utils.event_pressed_bug_workaround("shortcut_undo", event):
_on_undo_action()
- elif Input.is_action_just_pressed("shortcut_redo"):
+ elif Utils.event_pressed_bug_workaround("shortcut_redo", event):
_on_redo_action()
- elif Input.is_action_just_pressed("center_canvas_to_mouse"):
+ elif Utils.event_pressed_bug_workaround("center_canvas_to_mouse", event):
_canvas.center_to_mouse()
- elif Input.is_action_just_pressed("shortcut_brush_tool"):
+ elif Utils.event_pressed_bug_workaround("shortcut_brush_tool", event):
_toolbar.enable_tool(Types.Tool.BRUSH)
- elif Input.is_action_just_pressed("shortcut_rectangle_tool"):
+ elif Utils.event_pressed_bug_workaround("shortcut_rectangle_tool", event):
_toolbar.enable_tool(Types.Tool.RECTANGLE)
- elif Input.is_action_just_pressed("shortcut_circle_tool"):
+ elif Utils.event_pressed_bug_workaround("shortcut_circle_tool", event):
_toolbar.enable_tool(Types.Tool.CIRCLE)
- elif Input.is_action_just_pressed("shortcut_line_tool"):
+ elif Utils.event_pressed_bug_workaround("shortcut_line_tool", event):
_toolbar.enable_tool(Types.Tool.LINE)
- elif Input.is_action_just_pressed("shortcut_eraser_tool"):
+ elif Utils.event_pressed_bug_workaround("shortcut_eraser_tool", event):
_toolbar.enable_tool(Types.Tool.ERASER)
- elif Input.is_action_just_pressed("shortcut_select_tool"):
+ elif Utils.event_pressed_bug_workaround("shortcut_select_tool", event):
_toolbar.enable_tool(Types.Tool.SELECT)
- elif Input.is_action_just_pressed("toggle_distraction_free_mode"):
+ elif Utils.event_pressed_bug_workaround("toggle_distraction_free_mode", event):
_toggle_distraction_free_mode()
- elif Input.is_action_just_pressed("toggle_fullscreen"):
+ elif Utils.event_pressed_bug_workaround("toggle_fullscreen", event):
_toggle_fullscreen()
# -------------------------------------------------------------------------------------------------
@@ -541,7 +533,6 @@ func _on_scale_changed() -> void:
Types.UIScale.AUTO: scale = OS.get_screen_size().x / ProjectSettings.get_setting("display/window/size/width")
Types.UIScale.CUSTOM: scale = Settings.get_value(Settings.APPEARANCE_UI_SCALE, Config.DEFAULT_UI_SCALE)
- # Canvas has to be set first to make it the correct scale on startup
_canvas.set_canvas_scale(scale)
get_tree().set_screen_stretch(SceneTree.STRETCH_MODE_DISABLED, SceneTree.STRETCH_ASPECT_IGNORE, Vector2(0,0), scale)
OS.min_window_size = Config.MIN_WINDOW_SIZE * scale
diff --git a/lorien/Main.tscn b/lorien/Main.tscn
index 5b34ac91..2eb60b89 100644
--- a/lorien/Main.tscn
+++ b/lorien/Main.tscn
@@ -39,15 +39,13 @@ __meta__ = {
}
[node name="InfiniteCanvas" parent="." instance=ExtResource( 2 )]
+stretch = true
[node name="Topbar" type="VBoxContainer" parent="."]
anchor_right = 1.0
anchor_bottom = 0.0759259
margin_bottom = -3.99998
custom_constants/separation = 0
-__meta__ = {
-"_edit_use_anchors_": true
-}
[node name="Menubar" parent="Topbar" instance=ExtResource( 4 )]
anchor_right = 0.0
@@ -92,9 +90,6 @@ margin_top = -202.0
margin_right = 154.5
margin_bottom = 202.0
custom_styles/panel = SubResource( 1 )
-__meta__ = {
-"_edit_use_anchors_": false
-}
[node name="ColorPicker" type="ColorPicker" parent="BackgroundColorPickerPopup/PanelContainer"]
margin_left = 24.0
diff --git a/lorien/Misc/DSLParser.gd b/lorien/Misc/DSLParser.gd
index 89d6087d..d5348708 100644
--- a/lorien/Misc/DSLParser.gd
+++ b/lorien/Misc/DSLParser.gd
@@ -89,6 +89,8 @@ class ParsedSymbol:
# -------------------------------------------------------------------------------------------------
class GrammarElement:
+ extends Reference
+
func parse(s: String):
pass
@@ -117,7 +119,7 @@ class GrammarSequence:
var elements: Array
var flatten_same_name := false
- func _init(_name: String, _elements: Array = [], _flatten_same_name = false):
+ func _init(_name: String, _elements: Array = [], _flatten_same_name = false).():
name = _name
elements = _elements
flatten_same_name = _flatten_same_name
@@ -154,7 +156,7 @@ class GrammarLiteral:
var value: String
var ignore_whitespace := true
- func _init(_name: String, _value = null):
+ func _init(_name: String, _value = null).():
if _value == null:
_value = _name
name = _name
@@ -177,7 +179,7 @@ class GrammarRegexMatch:
var regex: RegEx
var ignore_whitespace := true
- func _init(_name: String, pattern: String):
+ func _init(_name: String, pattern: String).():
name = _name
regex = RegEx.new()
regex.compile(pattern)
diff --git a/lorien/Misc/I18nParser.gd b/lorien/Misc/I18nParser.gd
index 0db13250..39a7c942 100644
--- a/lorien/Misc/I18nParser.gd
+++ b/lorien/Misc/I18nParser.gd
@@ -4,8 +4,18 @@ class_name I18nParser
const I18N_FOLDER := "res://Assets/I18n/"
const StringTemplating := preload("res://Misc/StringTemplating.gd")
+# -------------------------------------------------------------------------------------------------
+var _first_load := true
+
+# -------------------------------------------------------------------------------------------------
+func reload_locales() -> ParseResult:
+ TranslationServer.clear()
+ return load_files()
+
# -------------------------------------------------------------------------------------------------
class ParseResult:
+ extends Reference
+
var locales := PoolStringArray()
var language_names := PoolStringArray()
@@ -51,12 +61,15 @@ func load_files() -> ParseResult:
value = value.strip_edges()
value = templater.process_string(value)
+ value = value.replace("\\n", "\n")
translation.add_message(key, value)
else:
printerr("Key not found (make sure to use spaces; not tabs): %s" % line)
TranslationServer.add_translation(translation)
result.append(translation.locale, name)
- print("Loaded i18n file: %s" % f)
+ if _first_load:
+ print("Loaded i18n file: %s" % f)
+ _first_load = false
return result
# -------------------------------------------------------------------------------------------------
diff --git a/lorien/Misc/Settings.gd b/lorien/Misc/Settings.gd
index b4e346d8..f3a30739 100644
--- a/lorien/Misc/Settings.gd
+++ b/lorien/Misc/Settings.gd
@@ -18,6 +18,7 @@ const COLOR_PALETTE_UUID_LAST_USED := "color_palette_uuid_last_used"
# -------------------------------------------------------------------------------------------------
var _config_file := ConfigFile.new()
+var _i18n := I18nParser.new()
var locales: PoolStringArray
var language_names: PoolStringArray
@@ -25,11 +26,13 @@ var language_names: PoolStringArray
func _ready():
_config_file = ConfigFile.new()
_load_settings()
+ reload_locales()
_setup_shortcuts()
_load_shortcuts()
- var i18n := I18nParser.new()
- var parse_result := i18n.load_files()
+# -------------------------------------------------------------------------------------------------
+func reload_locales():
+ var parse_result := _i18n.reload_locales()
TranslationServer.set_locale(get_value(GENERAL_LANGUAGE, "en"))
locales = parse_result.locales
language_names = parse_result.language_names
diff --git a/lorien/Misc/Utils.gd b/lorien/Misc/Utils.gd
index ab4b14c7..dcee392f 100644
--- a/lorien/Misc/Utils.gd
+++ b/lorien/Misc/Utils.gd
@@ -68,3 +68,22 @@ func generate_uuid(length: int) -> String:
s += UUID_ALPHABET[idx]
return s
+# -------------------------------------------------------------------------------------------------
+func translate_action(action_name: String) -> String:
+ return TranslationServer.translate("ACTION_" + action_name)
+
+# -------------------------------------------------------------------------------------------------
+func bindable_actions() -> Array:
+ var result := []
+ for action in InputMap.get_actions():
+ # Suppress default keybindings for using menus etc and EFF TWELVE
+ if action.begins_with("ui_") || action.begins_with("player_"):
+ continue
+ result.append(action)
+ return result
+
+# ------------------------------------------------------------------------------------------------
+# See: https://github.com/mbrlabs/Lorien/pull/168#discussion_r908251372 for details
+# Does an _exact_ match for the given key stroke.
+func event_pressed_bug_workaround(action_name: String, event: InputEvent) -> bool:
+ return InputMap.action_has_event(action_name, event) && event.is_pressed()
diff --git a/lorien/UI/Components/KeyBindingsLine.tscn b/lorien/UI/Components/KeyBindingsLine.tscn
new file mode 100644
index 00000000..ee8075d0
--- /dev/null
+++ b/lorien/UI/Components/KeyBindingsLine.tscn
@@ -0,0 +1,38 @@
+[gd_scene load_steps=4 format=2]
+
+[ext_resource path="res://UI/Components/KeyBindingsLineName.gd" type="Script" id=1]
+[ext_resource path="res://UI/Components/KeyBindingsLineBindings.gd" type="Script" id=2]
+[ext_resource path="res://UI/Components/KeyBindingsLineAddButton.gd" type="Script" id=3]
+
+[node name="KeyBindingsLine" type="GridContainer"]
+anchor_right = 1.0
+anchor_bottom = 1.0
+columns = 3
+__meta__ = {
+"_edit_use_anchors_": false
+}
+
+[node name="Name" type="Label" parent="."]
+margin_top = 3.0
+margin_right = 38.0
+margin_bottom = 17.0
+text = "Name
+"
+valign = 1
+max_lines_visible = 1
+script = ExtResource( 1 )
+
+[node name="Bindings" type="HBoxContainer" parent="."]
+margin_left = 42.0
+margin_right = 42.0
+margin_bottom = 20.0
+script = ExtResource( 2 )
+
+[node name="AddButton" type="Button" parent="."]
+margin_left = 46.0
+margin_right = 66.0
+margin_bottom = 20.0
+text = "+"
+script = ExtResource( 3 )
+
+[connection signal="pressed" from="AddButton" to="AddButton" method="_on_AddButton_pressed"]
diff --git a/lorien/UI/Components/KeyBindingsLineAddButton.gd b/lorien/UI/Components/KeyBindingsLineAddButton.gd
new file mode 100644
index 00000000..d7e169d4
--- /dev/null
+++ b/lorien/UI/Components/KeyBindingsLineAddButton.gd
@@ -0,0 +1,12 @@
+extends Button
+
+# -------------------------------------------------------------------------------------------------
+signal bind_new_key
+
+# -------------------------------------------------------------------------------------------------
+func set_keybindings_data(_bindings_data: Dictionary) -> void:
+ pass
+
+# -------------------------------------------------------------------------------------------------
+func _on_AddButton_pressed() -> void:
+ emit_signal("bind_new_key")
diff --git a/lorien/UI/Components/KeyBindingsLineBindings.gd b/lorien/UI/Components/KeyBindingsLineBindings.gd
new file mode 100644
index 00000000..0a13e757
--- /dev/null
+++ b/lorien/UI/Components/KeyBindingsLineBindings.gd
@@ -0,0 +1,31 @@
+extends HBoxContainer
+
+# -------------------------------------------------------------------------------------------------
+signal modified_binding(bindings_data)
+
+# -------------------------------------------------------------------------------------------------
+var _bindings_data := {}
+var _preloaded_image := preload("res://Assets/Icons/delete.png")
+
+# -------------------------------------------------------------------------------------------------
+# Keybindings data: {"action": "str", "readable_name": "str", "events": [...]}
+func set_keybindings_data(bindings_data: Dictionary) -> void:
+ for child in get_children():
+ remove_child(child)
+
+ _bindings_data = bindings_data
+ for event in bindings_data["events"]:
+ if event is InputEventKey:
+ var remove_button = Button.new()
+ remove_button.text = OS.get_scancode_string(event.get_scancode_with_modifiers())
+ remove_button.icon = _preloaded_image
+
+ remove_button.add_constant_override("hseparation", 6)
+
+ remove_button.connect("pressed", self, "_remove_pressed", [event])
+ add_child(remove_button)
+
+# -------------------------------------------------------------------------------------------------
+func _remove_pressed(event: InputEvent) -> void:
+ _bindings_data["events"].erase(event)
+ emit_signal("modified_binding", _bindings_data)
diff --git a/lorien/UI/Components/KeyBindingsLineName.gd b/lorien/UI/Components/KeyBindingsLineName.gd
new file mode 100644
index 00000000..cc8708d1
--- /dev/null
+++ b/lorien/UI/Components/KeyBindingsLineName.gd
@@ -0,0 +1,9 @@
+extends Label
+
+# -------------------------------------------------------------------------------------------------
+signal modified_binding(bindings_data)
+
+# -------------------------------------------------------------------------------------------------
+# Keybindings data: {"action": "str", "readable_name": "str", "events": [...]}
+func set_keybindings_data(_bindings_data: Dictionary) -> void:
+ text = _bindings_data["readable_name"]
diff --git a/lorien/UI/Dialogs/AddKeyDialog.gd b/lorien/UI/Dialogs/AddKeyDialog.gd
new file mode 100644
index 00000000..69e0a012
--- /dev/null
+++ b/lorien/UI/Dialogs/AddKeyDialog.gd
@@ -0,0 +1,77 @@
+extends WindowDialog
+
+# -------------------------------------------------------------------------------------------------
+const _MODIFIER_KEYS := [KEY_SUPER_L, KEY_SUPER_R, KEY_CONTROL, KEY_SHIFT, KEY_META, KEY_ALT]
+
+# -------------------------------------------------------------------------------------------------
+export var action_name := ""
+export var readable_action_name := "" setget _set_readable_action_name
+
+onready var _confirm_rebind_dialog := $ConfirmRebind
+
+var _pending_bind_event = null
+
+# -------------------------------------------------------------------------------------------------
+func _ready() -> void:
+ _update_event_text()
+ GlobalSignals.connect("language_changed", self, "_update_event_text")
+
+# -------------------------------------------------------------------------------------------------
+func _set_readable_action_name(s: String):
+ readable_action_name = s
+ _update_event_text()
+
+# -------------------------------------------------------------------------------------------------
+func _update_event_text() -> void:
+ $VBoxContainer/EventText.text = tr(
+ "KEYBINDING_DIALOG_BIND_ACTION"
+ ).format({"action": readable_action_name})
+
+# -------------------------------------------------------------------------------------------------
+func _action_for_event(event: InputEvent):
+ for action in Utils.bindable_actions():
+ if InputMap.action_has_event(action, event):
+ return action
+ return null
+
+# -------------------------------------------------------------------------------------------------
+func _input(event: InputEvent) -> void:
+ if ! visible || _confirm_rebind_dialog.visible:
+ return
+ if event is InputEventKey && event.is_pressed():
+ get_tree().set_input_as_handled()
+
+ if event.scancode in _MODIFIER_KEYS:
+ return
+
+ var event_type := InputEventKey.new()
+ event_type.scancode = event.scancode
+ event_type.alt = event.alt
+ event_type.shift = event.shift
+ event_type.control = event.control
+ event_type.meta = event.meta
+ event_type.command = event.command
+
+ var _conflicting_action = _action_for_event(event_type)
+
+ _pending_bind_event = event_type
+ if _conflicting_action is String && _conflicting_action != action_name:
+ _confirm_rebind_dialog.dialog_text = tr("KEYBINDING_DIALOG_REBIND_MESSAGE").format({
+ "event": OS.get_scancode_string(event_type.get_scancode_with_modifiers()),
+ "action": Utils.translate_action(_conflicting_action)
+ })
+ _confirm_rebind_dialog.popup_centered()
+ else:
+ _finish_rebind()
+
+# -------------------------------------------------------------------------------------------------
+func _on_ConfirmRebind_confirmed() -> void:
+ _finish_rebind()
+
+# -------------------------------------------------------------------------------------------------
+func _finish_rebind() -> void:
+ for action in Utils.bindable_actions():
+ if InputMap.action_has_event(action, _pending_bind_event):
+ InputMap.action_erase_event(action, _pending_bind_event)
+ InputMap.action_add_event(action_name, _pending_bind_event)
+ visible = false
diff --git a/lorien/UI/Dialogs/AddKeyDialog.tscn b/lorien/UI/Dialogs/AddKeyDialog.tscn
new file mode 100644
index 00000000..b4b46ec2
--- /dev/null
+++ b/lorien/UI/Dialogs/AddKeyDialog.tscn
@@ -0,0 +1,60 @@
+[gd_scene load_steps=3 format=2]
+
+[ext_resource path="res://UI/Dialogs/AddKeyDialog.gd" type="Script" id=1]
+
+[sub_resource type="StyleBoxLine" id=1]
+color = Color( 0, 0, 0, 0 )
+
+[node name="AddKeyDialog" type="WindowDialog"]
+anchor_left = 0.5
+anchor_top = 0.5
+anchor_right = 0.5
+anchor_bottom = 0.5
+margin_left = -196.0
+margin_top = -128.0
+margin_right = 197.0
+margin_bottom = 15.0
+popup_exclusive = true
+window_title = "Bind key"
+script = ExtResource( 1 )
+__meta__ = {
+"_edit_use_anchors_": false
+}
+
+[node name="VBoxContainer" type="VBoxContainer" parent="."]
+anchor_left = 0.5
+anchor_right = 0.5
+anchor_bottom = 1.0
+margin_left = -105.5
+margin_right = 105.5
+alignment = 1
+__meta__ = {
+"_edit_use_anchors_": false
+}
+
+[node name="EventText" type="Label" parent="VBoxContainer"]
+margin_top = 34.0
+margin_right = 211.0
+margin_bottom = 48.0
+text = "Action: ..."
+align = 1
+__meta__ = {
+"_edit_use_anchors_": false
+}
+
+[node name="Panel" type="HSeparator" parent="VBoxContainer"]
+margin_top = 52.0
+margin_right = 211.0
+margin_bottom = 91.0
+custom_styles/separator = SubResource( 1 )
+custom_constants/separation = 39
+
+[node name="PressKeyMessage" type="Label" parent="VBoxContainer"]
+margin_top = 95.0
+margin_right = 211.0
+margin_bottom = 109.0
+text = "(Press a button to bind)"
+align = 1
+__meta__ = {
+"_edit_use_anchors_": false
+}
diff --git a/lorien/UI/Dialogs/KeyBindingsLine.tscn b/lorien/UI/Dialogs/KeyBindingsLine.tscn
new file mode 100644
index 00000000..0d43f7d4
--- /dev/null
+++ b/lorien/UI/Dialogs/KeyBindingsLine.tscn
@@ -0,0 +1,38 @@
+[gd_scene load_steps=4 format=2]
+
+[ext_resource path="res://UI/Dialogs/KeyBindingsLineName.gd" type="Script" id=1]
+[ext_resource path="res://UI/Dialogs/KeyBindingsLineBindings.gd" type="Script" id=2]
+[ext_resource path="res://UI/Dialogs/KeyBindingsLineAddButton.gd" type="Script" id=3]
+
+[node name="KeyBindingsLine" type="GridContainer"]
+anchor_right = 1.0
+anchor_bottom = 1.0
+columns = 3
+__meta__ = {
+"_edit_use_anchors_": false
+}
+
+[node name="Name" type="Label" parent="."]
+margin_top = 3.0
+margin_right = 38.0
+margin_bottom = 17.0
+text = "Name
+"
+valign = 1
+max_lines_visible = 1
+script = ExtResource( 1 )
+
+[node name="Bindings" type="HBoxContainer" parent="."]
+margin_left = 42.0
+margin_right = 42.0
+margin_bottom = 20.0
+script = ExtResource( 2 )
+
+[node name="AddButton" type="Button" parent="."]
+margin_left = 46.0
+margin_right = 66.0
+margin_bottom = 20.0
+text = "+"
+script = ExtResource( 3 )
+
+[connection signal="pressed" from="AddButton" to="AddButton" method="_on_AddButton_pressed"]
diff --git a/lorien/UI/Dialogs/KeyBindingsList.gd b/lorien/UI/Dialogs/KeyBindingsList.gd
new file mode 100644
index 00000000..2ec189b8
--- /dev/null
+++ b/lorien/UI/Dialogs/KeyBindingsList.gd
@@ -0,0 +1,66 @@
+extends Node
+
+# -------------------------------------------------------------------------------------------------
+const KEYBINDINGS_LINE_SCENE = preload("res://UI/Components/KeyBindingsLine.tscn")
+
+# -------------------------------------------------------------------------------------------------
+onready var _grid := $ScrollContainer/KeyBindingsList
+onready var _add_key_dialog := $AddKeyDialog
+
+# -------------------------------------------------------------------------------------------------
+func _ready() -> void:
+ _populate_input_list()
+ _add_key_dialog.connect("hide", self, "_bind_key_dialog_hidden")
+ GlobalSignals.connect("language_changed", self, "_populate_input_list")
+
+# -------------------------------------------------------------------------------------------------
+func _populate_input_list() -> void:
+ for c in _grid.get_children():
+ _grid.remove_child(c)
+
+ for action in Utils.bindable_actions():
+ var translated_action = Utils.translate_action(action)
+ var shortcuts = []
+ for _event in InputMap.get_action_list(action):
+ if _event is InputEventKey:
+ var event = _event as InputEventKey
+ shortcuts.append(event)
+
+ _new_keybinding_entry(action, translated_action, shortcuts)
+
+# -------------------------------------------------------------------------------------------------
+func _new_keybinding_entry(action_name: String, readable_name: String, events: Array) -> void:
+ var new_line: Node = KEYBINDINGS_LINE_SCENE.instance()
+
+ for child in new_line.get_children():
+ child = child as Node
+
+ child.set_keybindings_data({
+ "action": action_name,
+ "readable_name": readable_name,
+ "events": events,
+ })
+ new_line.remove_child(child)
+ _grid.add_child(child)
+
+ child.connect("modified_binding", self, "_modify_keybinding", [action_name])
+ child.connect("bind_new_key", self, "_bind_new_key", [action_name])
+
+# -------------------------------------------------------------------------------------------------
+func _modify_keybinding(bindings_data: Dictionary, action_name: String) -> void:
+ InputMap.action_erase_events(action_name)
+ for e in bindings_data["events"]:
+ InputMap.action_add_event(action_name, e)
+ _populate_input_list()
+ Settings.reload_locales()
+
+# -------------------------------------------------------------------------------------------------
+func _bind_new_key(action_name: String) -> void:
+ _add_key_dialog.action_name = action_name
+ _add_key_dialog.readable_action_name = Utils.translate_action(action_name)
+ _add_key_dialog.popup_centered()
+
+# -------------------------------------------------------------------------------------------------
+func _bind_key_dialog_hidden() -> void:
+ _populate_input_list()
+ Settings.reload_locales()
diff --git a/lorien/UI/Dialogs/SettingsDialog.gd b/lorien/UI/Dialogs/SettingsDialog.gd
index e024ee59..8a122966 100644
--- a/lorien/UI/Dialogs/SettingsDialog.gd
+++ b/lorien/UI/Dialogs/SettingsDialog.gd
@@ -46,6 +46,7 @@ func _apply_language() -> void:
_tab_container.set_tab_title(0, tr("SETTINGS_GENERAL"))
_tab_container.set_tab_title(1, tr("SETTINGS_APPEARANCE"))
_tab_container.set_tab_title(2, tr("SETTINGS_RENDERING"))
+ _tab_container.set_tab_title(3, tr("SETTINGS_KEYBINDINGS"))
# -------------------------------------------------------------------------------------------------
func _set_values() -> void:
diff --git a/lorien/UI/Dialogs/SettingsDialog.tscn b/lorien/UI/Dialogs/SettingsDialog.tscn
index 277defed..c49c107c 100644
--- a/lorien/UI/Dialogs/SettingsDialog.tscn
+++ b/lorien/UI/Dialogs/SettingsDialog.tscn
@@ -1,8 +1,10 @@
-[gd_scene load_steps=7 format=2]
+[gd_scene load_steps=9 format=2]
[ext_resource path="res://UI/Themes/theme_dark.tres" type="Theme" id=1]
[ext_resource path="res://UI/Dialogs/SettingsDialog.gd" type="Script" id=2]
[ext_resource path="res://UI/Components/DelayedSpinBox.gd" type="Script" id=3]
+[ext_resource path="res://UI/Dialogs/KeyBindingsList.gd" type="Script" id=4]
+[ext_resource path="res://UI/Dialogs/AddKeyDialog.tscn" type="PackedScene" id=5]
[sub_resource type="StyleBoxEmpty" id=1]
@@ -11,6 +13,7 @@
[sub_resource type="StyleBoxEmpty" id=3]
[node name="SettingsDialog" type="WindowDialog"]
+visible = true
margin_right = 520.0
margin_bottom = 250.0
rect_min_size = Vector2( 520, 270 )
@@ -43,6 +46,7 @@ __meta__ = {
}
[node name="General" type="Control" parent="MarginContainer/TabContainer"]
+visible = false
anchor_right = 1.0
anchor_bottom = 1.0
margin_top = 27.0
@@ -311,9 +315,6 @@ margin_top = 27.0
[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer/TabContainer/Rendering"]
anchor_right = 1.0
anchor_bottom = 1.0
-__meta__ = {
-"_edit_use_anchors_": false
-}
[node name="HSeparator3" type="HSeparator" parent="MarginContainer/TabContainer/Rendering/VBoxContainer"]
margin_right = 496.0
@@ -434,6 +435,30 @@ custom_colors/font_color = Color( 1, 0.470588, 0.470588, 1 )
text = "SETTINGS_RESTART_NOTICE"
align = 1
+[node name="Keybindings" type="Control" parent="MarginContainer/TabContainer"]
+anchor_right = 1.0
+anchor_bottom = 1.0
+margin_top = 27.0
+script = ExtResource( 4 )
+
+[node name="ScrollContainer" type="ScrollContainer" parent="MarginContainer/TabContainer/Keybindings"]
+anchor_right = 1.0
+anchor_bottom = 1.0
+margin_top = 12.0
+
+[node name="KeyBindingsList" type="GridContainer" parent="MarginContainer/TabContainer/Keybindings/ScrollContainer"]
+columns = 3
+
+[node name="AddKeyDialog" parent="MarginContainer/TabContainer/Keybindings" instance=ExtResource( 5 )]
+window_title = "KEYBINDING_DIALOG_BIND_WINDOW_NAME"
+
+[node name="ConfirmRebind" type="ConfirmationDialog" parent="MarginContainer/TabContainer/Keybindings/AddKeyDialog"]
+margin_right = 200.0
+margin_bottom = 70.0
+popup_exclusive = true
+window_title = "KEYBINDING_DIALOG_REBIND_WINDOW_NAME"
+dialog_autowrap = true
+
[connection signal="value_changed" from="MarginContainer/TabContainer/General/VBoxContainer/PressureSensitivity/PressureSensitivity" to="." method="_on_PressureSensitivity_value_changed"]
[connection signal="value_changed" from="MarginContainer/TabContainer/General/VBoxContainer/DefaultBrushSize/DefaultBrushSize" to="." method="_on_DefaultBrushSize_value_changed"]
[connection signal="color_changed" from="MarginContainer/TabContainer/General/VBoxContainer/DefaultCanvasColor/DefaultCanvasColor" to="." method="_on_DefaultCanvasColor_color_changed"]
@@ -447,3 +472,4 @@ align = 1
[connection signal="item_selected" from="MarginContainer/TabContainer/Rendering/VBoxContainer/BrushRounding/OptionButton" to="." method="_on_Brush_rounding_item_selected"]
[connection signal="value_changed" from="MarginContainer/TabContainer/Rendering/VBoxContainer/TargetFramerate/TargetFramerate" to="." method="_on_Target_Fps_Foreground_changed"]
[connection signal="value_changed" from="MarginContainer/TabContainer/Rendering/VBoxContainer/BackgroundFramerate/BackgroundFramerate" to="." method="_on_Target_Fps_Background_changed"]
+[connection signal="confirmed" from="MarginContainer/TabContainer/Keybindings/AddKeyDialog/ConfirmRebind" to="MarginContainer/TabContainer/Keybindings/AddKeyDialog" method="_on_ConfirmRebind_confirmed"]
diff --git a/lorien/UI/Themes/theme_dark.tres b/lorien/UI/Themes/theme_dark.tres
index 53025675..e106488e 100644
--- a/lorien/UI/Themes/theme_dark.tres
+++ b/lorien/UI/Themes/theme_dark.tres
@@ -210,7 +210,7 @@ border_width_left = 1
border_width_top = 24
border_width_right = 1
border_width_bottom = 1
-border_color = Color( 0.207843, 0.211765, 0.227451, 1 )
+border_color = Color( 0.329412, 0.329412, 0.329412, 1 )
corner_radius_top_left = 1
corner_radius_top_right = 1
corner_radius_bottom_right = 1
diff --git a/lorien/export_presets.cfg b/lorien/export_presets.cfg
index faf24642..36aaf0fa 100644
--- a/lorien/export_presets.cfg
+++ b/lorien/export_presets.cfg
@@ -91,7 +91,7 @@ application/app_category="Productivity"
application/short_version="0.6.0-dev"
application/version="0.6.0-dev"
application/copyright="mbrlabs"
-display/high_res=false
+display/high_res=true
privacy/camera_usage_description=""
privacy/microphone_usage_description=""
texture_format/s3tc=true
diff --git a/lorien/project.godot b/lorien/project.godot
index c42e21ee..c93244e4 100644
--- a/lorien/project.godot
+++ b/lorien/project.godot
@@ -381,11 +381,6 @@ delete_selected_strokes={
"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777224,"physical_scancode":0,"unicode":0,"echo":false,"script":null)
]
}
-f12={
-"deadzone": 0.5,
-"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777255,"physical_scancode":0,"unicode":0,"echo":false,"script":null)
- ]
-}
copy_strokes={
"deadzone": 0.5,
"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":true,"meta":false,"command":true,"pressed":false,"scancode":67,"physical_scancode":0,"unicode":0,"echo":false,"script":null)