└── addons └── ui_design_tool ├── assets └── icons │ ├── folder_open-white-18dp.svg │ ├── folder_open-white-18dp.svg.import │ ├── format-color-text.png │ ├── format-color-text.png.import │ ├── format_align_center-white-18dp.svg │ ├── format_align_center-white-18dp.svg.import │ ├── format_align_left-white-18dp.svg │ ├── format_align_left-white-18dp.svg.import │ ├── format_align_right-white-18dp.svg │ ├── format_align_right-white-18dp.svg.import │ ├── format_bold-white-18dp.svg │ ├── format_bold-white-18dp.svg.import │ ├── format_clear-white-18dp.svg │ ├── format_clear-white-18dp.svg.import │ ├── format_color_reset-white-18dp.svg │ ├── format_color_reset-white-18dp.svg.import │ ├── format_italic-white-18dp.svg │ ├── format_italic-white-18dp.svg.import │ ├── format_underlined-white-18dp.svg │ ├── format_underlined-white-18dp.svg.import │ ├── marker.png │ ├── marker.png.import │ ├── more_horiz-white-18dp.svg │ ├── more_horiz-white-18dp.svg.import │ ├── more_vert-white-18dp.svg │ ├── more_vert-white-18dp.svg.import │ ├── photo_size_select_small-white-18dp.svg │ ├── photo_size_select_small-white-18dp.svg.import │ ├── refresh-white-18dp.svg │ ├── refresh-white-18dp.svg.import │ ├── vertical_align_bottom-white-18dp.svg │ ├── vertical_align_bottom-white-18dp.svg.import │ ├── vertical_align_center-white-18dp.svg │ ├── vertical_align_center-white-18dp.svg.import │ ├── vertical_align_top-white-18dp.svg │ └── vertical_align_top-white-18dp.svg.import ├── plugin.cfg ├── plugin.gd ├── scenes ├── OverlayTextEdit.gd ├── OverlayTextEdit.tscn ├── Toolbar.gd └── Toolbar.tscn └── scripts ├── FontManager.gd └── Utils.gd /addons/ui_design_tool/assets/icons/folder_open-white-18dp.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /addons/ui_design_tool/assets/icons/folder_open-white-18dp.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://d1uver224k3px" 6 | path="res://.godot/imported/folder_open-white-18dp.svg-b9b09b2c311e4324f6ceb8d836d92307.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://addons/ui_design_tool/assets/icons/folder_open-white-18dp.svg" 14 | dest_files=["res://.godot/imported/folder_open-white-18dp.svg-b9b09b2c311e4324f6ceb8d836d92307.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/lossy_quality=0.7 20 | compress/hdr_compression=1 21 | compress/bptc_ldr=0 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 38 | -------------------------------------------------------------------------------- /addons/ui_design_tool/assets/icons/format-color-text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imjp94/UIDesignTool/0e3bdbbfe966a4ff27ab9b711eff55a049968fd9/addons/ui_design_tool/assets/icons/format-color-text.png -------------------------------------------------------------------------------- /addons/ui_design_tool/assets/icons/format-color-text.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://b3tqua2bt1ix2" 6 | path="res://.godot/imported/format-color-text.png-cb1d0e154a77178073ac1079d1806720.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://addons/ui_design_tool/assets/icons/format-color-text.png" 14 | dest_files=["res://.godot/imported/format-color-text.png-cb1d0e154a77178073ac1079d1806720.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/lossy_quality=0.7 20 | compress/hdr_compression=1 21 | compress/bptc_ldr=0 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 | -------------------------------------------------------------------------------- /addons/ui_design_tool/assets/icons/format_align_center-white-18dp.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /addons/ui_design_tool/assets/icons/format_align_center-white-18dp.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://i11r3de57bc3" 6 | path="res://.godot/imported/format_align_center-white-18dp.svg-223e2eb74ca8e39f9d4bf989291c7829.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://addons/ui_design_tool/assets/icons/format_align_center-white-18dp.svg" 14 | dest_files=["res://.godot/imported/format_align_center-white-18dp.svg-223e2eb74ca8e39f9d4bf989291c7829.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/lossy_quality=0.7 20 | compress/hdr_compression=1 21 | compress/bptc_ldr=0 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 38 | -------------------------------------------------------------------------------- /addons/ui_design_tool/assets/icons/format_align_left-white-18dp.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /addons/ui_design_tool/assets/icons/format_align_left-white-18dp.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://dtsld0omp3fy0" 6 | path="res://.godot/imported/format_align_left-white-18dp.svg-f4e62d6e31b71bc8605b920932857161.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://addons/ui_design_tool/assets/icons/format_align_left-white-18dp.svg" 14 | dest_files=["res://.godot/imported/format_align_left-white-18dp.svg-f4e62d6e31b71bc8605b920932857161.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/lossy_quality=0.7 20 | compress/hdr_compression=1 21 | compress/bptc_ldr=0 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 38 | -------------------------------------------------------------------------------- /addons/ui_design_tool/assets/icons/format_align_right-white-18dp.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /addons/ui_design_tool/assets/icons/format_align_right-white-18dp.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://d0t8qupuaoigg" 6 | path="res://.godot/imported/format_align_right-white-18dp.svg-639ae8d469d29b7a7afdff99480dfa70.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://addons/ui_design_tool/assets/icons/format_align_right-white-18dp.svg" 14 | dest_files=["res://.godot/imported/format_align_right-white-18dp.svg-639ae8d469d29b7a7afdff99480dfa70.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/lossy_quality=0.7 20 | compress/hdr_compression=1 21 | compress/bptc_ldr=0 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 38 | -------------------------------------------------------------------------------- /addons/ui_design_tool/assets/icons/format_bold-white-18dp.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /addons/ui_design_tool/assets/icons/format_bold-white-18dp.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://d3xaf7s36xuqc" 6 | path="res://.godot/imported/format_bold-white-18dp.svg-dd70eba3f014196757627e0aea4304f1.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://addons/ui_design_tool/assets/icons/format_bold-white-18dp.svg" 14 | dest_files=["res://.godot/imported/format_bold-white-18dp.svg-dd70eba3f014196757627e0aea4304f1.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/lossy_quality=0.7 20 | compress/hdr_compression=1 21 | compress/bptc_ldr=0 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 38 | -------------------------------------------------------------------------------- /addons/ui_design_tool/assets/icons/format_clear-white-18dp.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /addons/ui_design_tool/assets/icons/format_clear-white-18dp.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://xnn5xt6piaat" 6 | path="res://.godot/imported/format_clear-white-18dp.svg-47d87e370b9f3dc70b33de4a26f02608.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://addons/ui_design_tool/assets/icons/format_clear-white-18dp.svg" 14 | dest_files=["res://.godot/imported/format_clear-white-18dp.svg-47d87e370b9f3dc70b33de4a26f02608.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/lossy_quality=0.7 20 | compress/hdr_compression=1 21 | compress/bptc_ldr=0 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 38 | -------------------------------------------------------------------------------- /addons/ui_design_tool/assets/icons/format_color_reset-white-18dp.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /addons/ui_design_tool/assets/icons/format_color_reset-white-18dp.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://8qawl7hrofkj" 6 | path="res://.godot/imported/format_color_reset-white-18dp.svg-e433d2e99c38830ed08d7fa1f97f9a11.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://addons/ui_design_tool/assets/icons/format_color_reset-white-18dp.svg" 14 | dest_files=["res://.godot/imported/format_color_reset-white-18dp.svg-e433d2e99c38830ed08d7fa1f97f9a11.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/lossy_quality=0.7 20 | compress/hdr_compression=1 21 | compress/bptc_ldr=0 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 38 | -------------------------------------------------------------------------------- /addons/ui_design_tool/assets/icons/format_italic-white-18dp.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /addons/ui_design_tool/assets/icons/format_italic-white-18dp.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://ck4h5hqubttt7" 6 | path="res://.godot/imported/format_italic-white-18dp.svg-7e46946409e5ba47a73f9c86ddf1ce61.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://addons/ui_design_tool/assets/icons/format_italic-white-18dp.svg" 14 | dest_files=["res://.godot/imported/format_italic-white-18dp.svg-7e46946409e5ba47a73f9c86ddf1ce61.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/lossy_quality=0.7 20 | compress/hdr_compression=1 21 | compress/bptc_ldr=0 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 38 | -------------------------------------------------------------------------------- /addons/ui_design_tool/assets/icons/format_underlined-white-18dp.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /addons/ui_design_tool/assets/icons/format_underlined-white-18dp.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://b44il4qj7cem1" 6 | path="res://.godot/imported/format_underlined-white-18dp.svg-b2765a4e60c3b18727158aebc6b78640.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://addons/ui_design_tool/assets/icons/format_underlined-white-18dp.svg" 14 | dest_files=["res://.godot/imported/format_underlined-white-18dp.svg-b2765a4e60c3b18727158aebc6b78640.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/lossy_quality=0.7 20 | compress/hdr_compression=1 21 | compress/bptc_ldr=0 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 38 | -------------------------------------------------------------------------------- /addons/ui_design_tool/assets/icons/marker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imjp94/UIDesignTool/0e3bdbbfe966a4ff27ab9b711eff55a049968fd9/addons/ui_design_tool/assets/icons/marker.png -------------------------------------------------------------------------------- /addons/ui_design_tool/assets/icons/marker.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://d1rj7h72swjhn" 6 | path="res://.godot/imported/marker.png-3deee63f805205d2092032fd6772df3e.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://addons/ui_design_tool/assets/icons/marker.png" 14 | dest_files=["res://.godot/imported/marker.png-3deee63f805205d2092032fd6772df3e.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/lossy_quality=0.7 20 | compress/hdr_compression=1 21 | compress/bptc_ldr=0 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 | -------------------------------------------------------------------------------- /addons/ui_design_tool/assets/icons/more_horiz-white-18dp.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /addons/ui_design_tool/assets/icons/more_horiz-white-18dp.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://cm5d77b25dgjc" 6 | path="res://.godot/imported/more_horiz-white-18dp.svg-2292c39c5fef87774f0dcabbf9749663.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://addons/ui_design_tool/assets/icons/more_horiz-white-18dp.svg" 14 | dest_files=["res://.godot/imported/more_horiz-white-18dp.svg-2292c39c5fef87774f0dcabbf9749663.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/lossy_quality=0.7 20 | compress/hdr_compression=1 21 | compress/bptc_ldr=0 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 38 | -------------------------------------------------------------------------------- /addons/ui_design_tool/assets/icons/more_vert-white-18dp.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /addons/ui_design_tool/assets/icons/more_vert-white-18dp.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://crte1qj0ftynh" 6 | path="res://.godot/imported/more_vert-white-18dp.svg-f9ce1c1392fbe43035b0f9c38f40fd8c.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://addons/ui_design_tool/assets/icons/more_vert-white-18dp.svg" 14 | dest_files=["res://.godot/imported/more_vert-white-18dp.svg-f9ce1c1392fbe43035b0f9c38f40fd8c.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/lossy_quality=0.7 20 | compress/hdr_compression=1 21 | compress/bptc_ldr=0 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 38 | -------------------------------------------------------------------------------- /addons/ui_design_tool/assets/icons/photo_size_select_small-white-18dp.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /addons/ui_design_tool/assets/icons/photo_size_select_small-white-18dp.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://cqv3uc8bew0am" 6 | path="res://.godot/imported/photo_size_select_small-white-18dp.svg-a132cc84485fb38b8289f82a1cfb4be4.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://addons/ui_design_tool/assets/icons/photo_size_select_small-white-18dp.svg" 14 | dest_files=["res://.godot/imported/photo_size_select_small-white-18dp.svg-a132cc84485fb38b8289f82a1cfb4be4.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/lossy_quality=0.7 20 | compress/hdr_compression=1 21 | compress/bptc_ldr=0 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 38 | -------------------------------------------------------------------------------- /addons/ui_design_tool/assets/icons/refresh-white-18dp.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /addons/ui_design_tool/assets/icons/refresh-white-18dp.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://dn7q7grbfr7kh" 6 | path="res://.godot/imported/refresh-white-18dp.svg-8592ca638cd7e6c945a15796e8610b7c.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://addons/ui_design_tool/assets/icons/refresh-white-18dp.svg" 14 | dest_files=["res://.godot/imported/refresh-white-18dp.svg-8592ca638cd7e6c945a15796e8610b7c.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/lossy_quality=0.7 20 | compress/hdr_compression=1 21 | compress/bptc_ldr=0 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 38 | -------------------------------------------------------------------------------- /addons/ui_design_tool/assets/icons/vertical_align_bottom-white-18dp.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /addons/ui_design_tool/assets/icons/vertical_align_bottom-white-18dp.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://rpjhdv5qake3" 6 | path="res://.godot/imported/vertical_align_bottom-white-18dp.svg-d38142e787fc53732b40c7e09204caed.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://addons/ui_design_tool/assets/icons/vertical_align_bottom-white-18dp.svg" 14 | dest_files=["res://.godot/imported/vertical_align_bottom-white-18dp.svg-d38142e787fc53732b40c7e09204caed.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/lossy_quality=0.7 20 | compress/hdr_compression=1 21 | compress/bptc_ldr=0 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 38 | -------------------------------------------------------------------------------- /addons/ui_design_tool/assets/icons/vertical_align_center-white-18dp.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /addons/ui_design_tool/assets/icons/vertical_align_center-white-18dp.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://ckriw8d4yelu" 6 | path="res://.godot/imported/vertical_align_center-white-18dp.svg-ff9e4504ee166be50beb982105c87414.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://addons/ui_design_tool/assets/icons/vertical_align_center-white-18dp.svg" 14 | dest_files=["res://.godot/imported/vertical_align_center-white-18dp.svg-ff9e4504ee166be50beb982105c87414.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/lossy_quality=0.7 20 | compress/hdr_compression=1 21 | compress/bptc_ldr=0 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 38 | -------------------------------------------------------------------------------- /addons/ui_design_tool/assets/icons/vertical_align_top-white-18dp.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /addons/ui_design_tool/assets/icons/vertical_align_top-white-18dp.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://cjan2dq5nvdvk" 6 | path="res://.godot/imported/vertical_align_top-white-18dp.svg-baa4704503a2c09de95348bc71c911d2.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://addons/ui_design_tool/assets/icons/vertical_align_top-white-18dp.svg" 14 | dest_files=["res://.godot/imported/vertical_align_top-white-18dp.svg-baa4704503a2c09de95348bc71c911d2.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/lossy_quality=0.7 20 | compress/hdr_compression=1 21 | compress/bptc_ldr=0 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 38 | -------------------------------------------------------------------------------- /addons/ui_design_tool/plugin.cfg: -------------------------------------------------------------------------------- 1 | [plugin] 2 | 3 | name="UI Design Tool" 4 | description="" 5 | author="imjp94" 6 | version="0.2.2" 7 | script="plugin.gd" 8 | -------------------------------------------------------------------------------- /addons/ui_design_tool/plugin.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | extends EditorPlugin 3 | const Toolbar = preload("scenes/Toolbar.tscn") 4 | const OverlayTextEdit = preload("scenes/OverlayTextEdit.tscn") 5 | 6 | var toolbar 7 | var overlay_text_edit 8 | 9 | var editor_inspector = get_editor_interface().get_inspector() 10 | var editor_selection = get_editor_interface().get_selection() 11 | 12 | 13 | func _enter_tree(): 14 | toolbar = Toolbar.instantiate() 15 | toolbar.undo_redo = get_undo_redo() 16 | toolbar.connect("property_edited", _on_Toolbar_property_edited) 17 | overlay_text_edit = OverlayTextEdit.instantiate() 18 | overlay_text_edit.undo_redo = get_undo_redo() 19 | overlay_text_edit.connect("property_edited", _on_OverlayTextEdit_property_edited) 20 | 21 | editor_inspector.connect("property_selected", _on_property_selected) 22 | editor_selection.connect("selection_changed", _on_selection_changed) 23 | 24 | add_control_to_container(EditorPlugin.CONTAINER_CANVAS_EDITOR_BOTTOM, toolbar) 25 | add_control_to_container(EditorPlugin.CONTAINER_CANVAS_EDITOR_BOTTOM, overlay_text_edit) 26 | 27 | func _exit_tree(): 28 | if toolbar: 29 | toolbar.queue_free() 30 | if overlay_text_edit: 31 | overlay_text_edit.queue_free() 32 | 33 | func _handles(object): 34 | if object is Control: 35 | _make_visible(true) 36 | return true 37 | _make_visible(false) 38 | return false 39 | 40 | func _forward_canvas_gui_input(event): 41 | if event is InputEventMouseButton: 42 | if event.button_index == MOUSE_BUTTON_LEFT: 43 | if event.double_click: # Always false when selected multiple nodes 44 | if toolbar.focused_objects: 45 | overlay_text_edit.popup() 46 | return true 47 | return false 48 | 49 | func _make_visible(visible): 50 | if toolbar: 51 | toolbar.visible = visible 52 | # overlay_text_edit only visible on double click 53 | 54 | func _on_property_selected(property): 55 | toolbar.focused_property = property 56 | toolbar.focused_inspector = editor_inspector.get_viewport().gui_get_focus_owner() 57 | 58 | func _on_selection_changed(): 59 | var selections = editor_selection.get_selected_nodes() 60 | var is_visible = false 61 | var focused_objects = [] 62 | if selections.size() == 1: 63 | var selection = selections[0] 64 | if selection is Control: 65 | focused_objects = [selection] 66 | is_visible = true 67 | elif selections.size() > 1: 68 | var has_non_control = false 69 | for selection in selections: 70 | if not (selection is Control): 71 | has_non_control = true 72 | break 73 | if not has_non_control: 74 | is_visible = true 75 | focused_objects = selections 76 | 77 | toolbar.visible = is_visible 78 | toolbar.focused_objects = focused_objects 79 | overlay_text_edit.focused_objects = focused_objects 80 | 81 | func _on_Toolbar_property_edited(property): 82 | pass 83 | 84 | func _on_OverlayTextEdit_property_edited(property): 85 | pass 86 | -------------------------------------------------------------------------------- /addons/ui_design_tool/scenes/OverlayTextEdit.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | extends TextEdit 3 | 4 | signal property_edited(property) 5 | 6 | var focused_objects 7 | var undo_redo 8 | 9 | var _object_orig_text = "" 10 | 11 | func _ready(): 12 | set_as_top_level(true) 13 | connect("focus_exited", _on_focused_exited) 14 | connect("text_changed", _on_text_changed) 15 | hide() 16 | 17 | func _on_text_changed(): 18 | if focused_objects: 19 | # TODO: Option to set bbcode_text if is RichTextLabel 20 | focused_objects.back().set("text", text) 21 | 22 | func _on_focused_exited(): 23 | if get_menu().visible: # Support right-click context menu 24 | return 25 | 26 | hide() 27 | # TODO: More efficient way to handle undo/redo of text, right now, whole chunks of string is cached everytime 28 | change_text(focused_objects.back(), text) 29 | 30 | # Popup at mouse position 31 | func popup(): 32 | if focused_objects == null: 33 | return 34 | 35 | var focused_object = focused_objects.back() 36 | if not ("text" in focused_object): 37 | return 38 | 39 | show() 40 | global_position = get_viewport().get_mouse_position() 41 | size = focused_object.size 42 | text = focused_object.text 43 | grab_focus() 44 | 45 | _object_orig_text = focused_object.text 46 | 47 | # Change text with undo/redo 48 | func change_text(object, to): 49 | var from = _object_orig_text 50 | undo_redo.create_action("Change Text") 51 | undo_redo.add_do_method(self, "set_object_text", object, to) 52 | undo_redo.add_undo_method(self, "set_object_text", object, from) 53 | undo_redo.commit_action() 54 | _object_orig_text = "" 55 | 56 | func set_object_text(object, text): 57 | object.set("text", text) 58 | emit_signal("property_edited", "text") 59 | -------------------------------------------------------------------------------- /addons/ui_design_tool/scenes/OverlayTextEdit.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=3 format=2] 2 | 3 | [ext_resource path="res://addons/ui_design_tool/scenes/OverlayTextEdit.gd" type="Script" id=1] 4 | 5 | [sub_resource type="StyleBoxFlat" id=1] 6 | bg_color = Color( 1, 1, 1, 0 ) 7 | 8 | [node name="OverlayTextEdit" type="TextEdit"] 9 | offset_right = 300.0 10 | offset_bottom = 200.0 11 | minimum_size = Vector2( 300, 200 ) 12 | custom_styles/read_only = SubResource( 1 ) 13 | custom_styles/focus = SubResource( 1 ) 14 | custom_styles/normal = SubResource( 1 ) 15 | custom_styles/completion = SubResource( 1 ) 16 | fold_gutter = true 17 | caret_blink = true 18 | script = ExtResource( 1 ) 19 | __meta__ = { 20 | "_edit_use_anchors_": false 21 | } 22 | 23 | [node name="Panel" type="Panel" parent="."] 24 | self_modulate = Color( 1, 1, 1, 0.588235 ) 25 | show_behind_parent = true 26 | anchor_right = 1.0 27 | anchor_bottom = 1.0 28 | mouse_filter = 2 29 | __meta__ = { 30 | "_edit_use_anchors_": false 31 | } 32 | -------------------------------------------------------------------------------- /addons/ui_design_tool/scenes/Toolbar.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | extends Control 3 | const Utils = preload("../scripts/Utils.gd") 4 | const FontManager = preload("../scripts/FontManager.gd") 5 | 6 | signal property_edited(name) # Emitted when property edited, mainly to notify inspector refresh 7 | 8 | # Config file to save user preference 9 | const CONFIG_DIR = "res://addons/ui_design_tool/user_pref.cfg" # Must be abosulte path 10 | const CONFIG_SECTION_META = "path" 11 | const CONFIG_KEY_FONTS_DIR = "fonts_dir" # Directory to fonts resource 12 | # Generic font properties 13 | const PROPERTY_FONT_COLOR = "theme_override_colors/font_color" 14 | const PROPERTY_FONT = "theme_override_fonts/font" 15 | const PROPERTY_FONT_SIZE = "theme_override_font_sizes/font_size" 16 | # RichTextLabel font properties 17 | const PROPERTY_FONT_NORMAL = "theme_override_fonts/normal_font" 18 | const PROPERTY_FONT_BOLD = "theme_override_fonts/bold_font" 19 | const PROPERTY_FONT_ITALIC = "theme_override_fonts/italics_font" 20 | const PROPERTY_FONT_BOLD_ITALIC = "theme_override_fonts/bold_italics_font" 21 | const PROPERTY_FONT_COLOR_DEFAULT = "theme_override_colors/default_color" 22 | # Others generic properties 23 | const PROPERTY_HIGHLIGHT = "theme_override_styles/normal" 24 | const PROPERTY_HIGHLIGHT_PANEL = "theme_override_styles/panel" 25 | const PROPERTY_HORIZONTAL_ALIGNMENT = "horizontal_alignment" 26 | const PROPERTY_VERTICAL_ALIGNMENT = "vertical_alignment" 27 | 28 | const DEFAULT_FONT_SIZE = 16 29 | const FONT_FAMILY_REFERENCE_STRING = "____________" # Reference text to calculate display size of FontFamily 30 | const FONT_FORMATTING_REFERENCE_STRING = "HEADING_1_" # Reference text to calculate display size of FontFormatting 31 | 32 | # Toolbar UI 33 | @onready var FontFamily = $FontFamily 34 | @onready var FontFamilyOptions = $FontFamilyOptions 35 | @onready var FontFamilyOptionsPopupMenu = $FontFamilyOptions/PopupMenu 36 | @onready var FontFamilyFileDialog = $FontFamilyFileDialog 37 | @onready var FontSize = $FontSize 38 | @onready var FontSizePreset = $FontSize/FontSizePreset 39 | @onready var Bold = $Bold 40 | @onready var BoldPopupMenu = $Bold/PopupMenu 41 | @onready var Italic = $Italic 42 | @onready var Underline = $Underline 43 | @onready var FontColor = $FontColor 44 | @onready var FontColorColorRect = $FontColor/ColorRect 45 | @onready var FontColorColorPicker = $FontColor/PopupPanel/ColorPicker 46 | @onready var FontColorPopupPanel = $FontColor/PopupPanel 47 | @onready var Highlight = $Highlight 48 | @onready var HighlightColorRect = $Highlight/ColorRect 49 | @onready var HighlightColorPicker = $Highlight/PopupPanel/ColorPicker 50 | @onready var HighlightPopupPanel = $Highlight/PopupPanel 51 | @onready var HorizontalAlign = $HorizontalAlign 52 | @onready var HorizontalAlignPopupMenu = $HorizontalAlign/PopupMenu 53 | @onready var VerticalAlign = $VerticalAlign 54 | @onready var VerticalAlignPopupMenu = $VerticalAlign/PopupMenu 55 | @onready var FontFormatting = $FontFormatting 56 | @onready var Tools = $Tools 57 | @onready var ToolsPopupMenu = $Tools/PopupMenu 58 | 59 | # Reference passed down from EditorPlugin 60 | var focused_objects = [] : # Editor editing object 61 | set(objs): # focused_objects setter, mainly called from EditorPlugin 62 | var has_changed = false 63 | 64 | if not objs.is_empty(): 65 | if focused_objects.size() == 1 and objs.size() == 1: 66 | # Single selection changed 67 | has_changed = focused_objects.back() != objs.back() 68 | else: 69 | has_changed = true 70 | else: 71 | if not focused_objects.is_empty(): 72 | has_changed = true 73 | 74 | if has_changed: 75 | focused_objects = objs 76 | _on_focused_object_changed(focused_objects) 77 | var focused_property : # Editor editing property 78 | set(prop): # focused_property setter, mainly called from EditorPlugin 79 | if focused_property != prop: 80 | focused_property = prop 81 | _on_focused_property_changed(focused_property) 82 | var focused_inspector : # Editor editing inspector 83 | set(insp): # focused_inspector setter, mainly called from EditorPlugin 84 | if focused_inspector != insp: 85 | focused_inspector = insp 86 | _on_focused_inspector_changed(focused_inspector) 87 | var undo_redo 88 | 89 | var selected_font_root_dir = "res://" 90 | var font_manager = FontManager.new() # Manager of loaded fonts from fonts_dir 91 | var config = ConfigFile.new() # Config file of user preference 92 | 93 | var _is_visible_yet = false # Always True after it has visible once, mainly used to auto load fonts 94 | var _object_orig_font_color = Color.WHITE # Font color of object when FontColor pressed 95 | var _object_orig_highlight # Highlight(StyleBoxFlat) when Highlight pressed 96 | var _object_orig_font_formatting # FontManager.FontFormatting object when FontFormatting item selected 97 | 98 | 99 | func _init(): 100 | var result = config.load(CONFIG_DIR) 101 | if result: 102 | match result: 103 | ERR_FILE_NOT_FOUND: 104 | pass 105 | _: 106 | push_warning("UI Design Tool: An error occurred when trying to access %s, ERROR: %d" % [CONFIG_DIR, result]) 107 | 108 | func _ready(): 109 | hide() 110 | connect("visibility_changed", _on_visibility_changed) 111 | # FontFamily 112 | FontFamily.clip_text = true 113 | FontFamily.custom_minimum_size.x = Utils.get_option_button_display_size(FontFamily, FONT_FAMILY_REFERENCE_STRING).x 114 | FontFamily.connect("item_selected", _on_FontFamily_item_selected) 115 | FontFamilyOptions.connect("pressed", _on_FontFamilyOptions_pressed) 116 | FontFamilyOptionsPopupMenu.connect("id_pressed", _on_FontFamilyOptionsPopupMenu_id_pressed) 117 | FontFamilyFileDialog.connect("dir_selected", _on_FontFamilyFileDialog_dir_selected) 118 | # FontSize 119 | FontSizePreset.connect("item_selected", _on_FontSizePreset_item_selected) 120 | FontSize.connect("text_submitted", _on_FontSize_text_entered) 121 | # Bold 122 | Bold.connect("pressed", _on_Bold_pressed) 123 | BoldPopupMenu.connect("id_pressed", _on_BoldPopupMenu_id_pressed) 124 | # Italic 125 | Italic.connect("pressed", _on_Italic_pressed) 126 | # FontColor 127 | FontColor.connect("pressed", _on_FontColor_pressed) 128 | FontColorColorPicker.connect("color_changed", _on_FontColor_ColorPicker_color_changed) 129 | FontColorPopupPanel.connect("popup_hide", _on_FontColor_PopupPanel_popup_hide) 130 | # Highlight 131 | Highlight.connect("pressed", _on_Highlight_pressed) 132 | HighlightColorPicker.connect("color_changed", _on_Highlight_ColorPicker_color_changed) 133 | HighlightPopupPanel.connect("popup_hide", _on_Highlight_PopupPanel_popup_hide) 134 | # HorizontalAlign 135 | HorizontalAlign.connect("pressed", _on_HorizontalAlign_pressed) 136 | HorizontalAlignPopupMenu.connect("id_pressed", _on_HorizontalAlignPopupMenu_id_pressed) 137 | HorizontalAlignPopupMenu.set_item_metadata(0, HORIZONTAL_ALIGNMENT_LEFT) 138 | HorizontalAlignPopupMenu.set_item_metadata(1, HORIZONTAL_ALIGNMENT_CENTER) 139 | HorizontalAlignPopupMenu.set_item_metadata(2, HORIZONTAL_ALIGNMENT_RIGHT) 140 | # VerticalAlign 141 | VerticalAlign.connect("pressed", _on_VerticalAlign_pressed) 142 | VerticalAlignPopupMenu.connect("id_pressed", _on_VerticalAlignPopupMenu_id_pressed) 143 | VerticalAlignPopupMenu.set_item_metadata(0, VERTICAL_ALIGNMENT_TOP) 144 | VerticalAlignPopupMenu.set_item_metadata(1, VERTICAL_ALIGNMENT_CENTER) 145 | VerticalAlignPopupMenu.set_item_metadata(2, VERTICAL_ALIGNMENT_BOTTOM) 146 | # FontFormatting 147 | FontFormatting.clip_text = true 148 | FontFormatting.custom_minimum_size.x = Utils.get_option_button_display_size(FontFormatting, FONT_FORMATTING_REFERENCE_STRING).x 149 | FontFormatting.connect("item_selected", _on_FontFormatting_item_selected) 150 | # Tools 151 | Tools.connect("pressed", _on_Tools_pressed) 152 | ToolsPopupMenu.connect("id_pressed", _on_ToolsPopupMenu_id_pressed) 153 | 154 | func _on_visibility_changed(): 155 | if not _is_visible_yet and visible: 156 | var fonts_dir = config.get_value(CONFIG_SECTION_META, CONFIG_KEY_FONTS_DIR, "") 157 | if not fonts_dir.is_empty(): 158 | FontFamilyFileDialog.current_path = fonts_dir 159 | _on_FontFamilyFileDialog_dir_selected(fonts_dir) 160 | _is_visible_yet = true 161 | 162 | # Change font object with undo/redo 163 | func change_font(object, to): 164 | var from = object.get(PROPERTY_FONT) 165 | undo_redo.create_action("Change Font") 166 | undo_redo.add_do_method(self, "set_font", object, to if to else false) # Godot bug, varargs ignore null 167 | undo_redo.add_undo_method(self, "set_font", object, from if from else false) 168 | undo_redo.commit_action() 169 | 170 | # Change font data of font object with undo/redo 171 | func change_font_data(object, to): 172 | var from = object.get(PROPERTY_FONT).base_font 173 | undo_redo.create_action("Change Font Data") 174 | undo_redo.add_do_method(self, "set_font_data", object, to if to else false) # Godot bug, varargs ignore null 175 | undo_redo.add_undo_method(self, "set_font_data", object, from if from else false) 176 | undo_redo.commit_action() 177 | 178 | # Change rich text fonts with undo/redo 179 | func change_rich_text_fonts(object, to): 180 | var from = {} 181 | from["regular"] = object.get(PROPERTY_FONT_NORMAL) 182 | from["bold"] = object.get(PROPERTY_FONT_BOLD) 183 | from["regular_italic"] = object.get(PROPERTY_FONT_ITALIC) 184 | from["bold_italic"] = object.get(PROPERTY_FONT_BOLD_ITALIC) 185 | undo_redo.create_action("Change Rich Text Fonts") 186 | undo_redo.add_do_method(self, "set_rich_text_fonts", object, to if to else false) # Godot bug, varargs ignore null 187 | undo_redo.add_undo_method(self, "set_rich_text_fonts", object, from if from else false) 188 | undo_redo.commit_action() 189 | 190 | # Change font size with undo/redo 191 | func change_font_size(object, to): 192 | var from = object.get(PROPERTY_FONT_SIZE) 193 | undo_redo.create_action("Change Font Size") 194 | undo_redo.add_do_method(self, "set_font_size", object, to) 195 | undo_redo.add_undo_method(self, "set_font_size", object, from) 196 | undo_redo.commit_action() 197 | 198 | # Change font color with undo/redo 199 | func change_font_color(object, to): 200 | var from = _object_orig_font_color 201 | undo_redo.create_action("Change Font Color") 202 | undo_redo.add_do_method(self, "set_font_color", object, to if to is Color else false) # Godot bug, varargs ignore null 203 | undo_redo.add_undo_method(self, "set_font_color", object, from if from is Color else false) 204 | undo_redo.commit_action() 205 | 206 | # Change highlight(StyleBoxFlat) with undo/redo 207 | func change_highlight(object, to): 208 | var from = _object_orig_highlight 209 | undo_redo.create_action("Change Highlight") 210 | undo_redo.add_do_method(self, "set_highlight", object, to if to else false) # Godot bug, varargs ignore null 211 | undo_redo.add_undo_method(self, "set_highlight", object, from if from else false) 212 | undo_redo.commit_action() 213 | 214 | # Change horizontal alignment with undo/redo 215 | func change_horizontal_alignment(object, to): 216 | var from = object.get(PROPERTY_HORIZONTAL_ALIGNMENT) 217 | undo_redo.create_action("Change Horizontal Alignment") 218 | undo_redo.add_do_method(self, "set_horizontal_alignment", object, to) 219 | undo_redo.add_undo_method(self, "set_horizontal_alignment", object, from) 220 | undo_redo.commit_action() 221 | 222 | # Change vertical alignment with undo/redo 223 | func change_vertical_alignment(object, to): 224 | var from = object.get(PROPERTY_VERTICAL_ALIGNMENT) 225 | undo_redo.create_action("Change Vertical Alignment") 226 | undo_redo.add_do_method(self, "set_vertical_alignment", object, to) 227 | undo_redo.add_undo_method(self, "set_vertical_alignment", object, from) 228 | undo_redo.commit_action() 229 | 230 | # Change font style(FontManager.FontFormatting) with undo/redo 231 | func change_font_formatting(object, to): 232 | var from = _object_orig_font_formatting 233 | undo_redo.create_action("Change Font Style") 234 | undo_redo.add_do_method(self, "set_font_formatting", object, to if to else false) # Godot bug, varargs ignore null 235 | undo_redo.add_undo_method(self, "set_font_formatting", object, from if from else false) 236 | undo_redo.commit_action() 237 | 238 | # Reflect font name of focused_objects to toolbar 239 | func reflect_font_family_control(): 240 | var obj = focused_objects.back() if focused_objects else null 241 | if not obj: 242 | return 243 | 244 | var font_variation = obj.get(PROPERTY_FONT) if obj else null 245 | if font_variation: 246 | if font_variation.base_font: 247 | var font_face = font_manager.get_font_face(font_variation.base_font) 248 | if font_face: 249 | for i in FontFamily.get_item_count(): 250 | var font_family_name = FontFamily.get_item_text(i) 251 | if font_family_name == font_face.font_family: 252 | FontFamily.tooltip_text = font_family_name 253 | FontFamily.selected = i 254 | reflect_font_weight_control() 255 | return 256 | 257 | FontFamily.tooltip_text = "Font Family" 258 | reset_font_family_control() 259 | 260 | # Reflect font weight of focused_objects to toolbar, always call reflect_font_family_control first 261 | func reflect_font_weight_control(): 262 | var obj = focused_objects.back() if focused_objects else null 263 | if not obj: 264 | return 265 | 266 | var font_variation = obj.get(PROPERTY_FONT) if obj else null 267 | if font_variation: 268 | if font_variation.base_font: 269 | var font_face = font_manager.get_font_face(font_variation.base_font) 270 | if font_face: 271 | var font_weight = font_face.font_weight 272 | 273 | for i in BoldPopupMenu.get_item_count(): 274 | if font_weight.replace("-", "_") == BoldPopupMenu.get_item_text(i).to_lower().replace("-", "_"): 275 | Bold.tooltip_text = BoldPopupMenu.get_item_text(i) 276 | return true 277 | return false 278 | 279 | # Reflect font size of focused_objects to toolbar, always call reflect_font_family_control first 280 | func reflect_font_size_control(): 281 | var obj = focused_objects.back() if focused_objects else null 282 | if not obj: 283 | return 284 | 285 | var has_font_size = PROPERTY_FONT_SIZE in obj 286 | FontSize.mouse_filter = Control.MOUSE_FILTER_IGNORE if not has_font_size else Control.MOUSE_FILTER_STOP 287 | FontSizePreset.disabled = not has_font_size 288 | var font_size_color = Color.WHITE 289 | font_size_color.a = 0.5 if not has_font_size else 1 290 | FontSize.set(PROPERTY_FONT_COLOR, font_size_color) 291 | var font_size = obj.get(PROPERTY_FONT_SIZE) if obj else null 292 | if has_font_size and font_size == null: 293 | font_size = DEFAULT_FONT_SIZE 294 | FontSize.text = str(font_size) if font_size else str(DEFAULT_FONT_SIZE) 295 | 296 | # Reflect bold/italic of focused_objects to toolbar, always call reflect_font_family_control first 297 | func reflect_bold_italic_control(): 298 | var obj = focused_objects.back() if focused_objects else null 299 | if not obj: 300 | return 301 | 302 | if FontFamily.get_item_count(): 303 | var font_family_name = FontFamily.get_item_text(FontFamily.selected) 304 | # TODO: Better way to get current item text from PopupMenu than tooltip_text 305 | var font_weight = Bold.tooltip_text.to_lower().replace("-", "_") 306 | var font_family = font_manager.get_font_family(font_family_name) 307 | 308 | Bold.disabled = font_family == null 309 | var font_variation = obj.get(PROPERTY_FONT) if obj else null 310 | if font_variation: 311 | var font_face = font_manager.get_font_face(font_variation.base_font) 312 | if font_face: 313 | var is_italic = font_face.font_style == FontManager.FONT_STYLE.ITALIC 314 | Italic.button_pressed = is_italic 315 | if not is_italic: 316 | if font_family: 317 | Italic.disabled = not ("italic" in font_family.get(font_weight)) 318 | else: 319 | Italic.disabled = true 320 | else: 321 | Italic.disabled = false 322 | else: 323 | Italic.button_pressed = false 324 | Italic.disabled = true 325 | 326 | var is_none = font_family_name == "None" 327 | var font_weights = FontManager.FONT_WEIGHT.keys() 328 | for i in font_weights.size(): 329 | var font_face = font_family.get(font_weights[i]) if font_family else null 330 | var font_data = font_face.normal if font_face else null 331 | BoldPopupMenu.set_item_disabled(i, true if is_none else font_data == null) 332 | else: 333 | Bold.disabled = true 334 | Italic.disabled = true 335 | Bold.button_pressed = false 336 | Italic.button_pressed = false 337 | 338 | # Reflect font color of focused_objects to toolbar 339 | func reflect_font_color_control(): 340 | var obj = focused_objects.back() if focused_objects else null 341 | if not obj: 342 | return 343 | 344 | var focused_object_font_color = obj.get(PROPERTY_FONT_COLOR) if obj else null 345 | var font_color = Color.WHITE 346 | if focused_object_font_color != null: 347 | font_color = focused_object_font_color 348 | FontColorColorRect.color = font_color 349 | FontColorColorPicker.color = font_color 350 | 351 | # Reflect highlight color of focused_objects to toolbar 352 | func reflect_highlight_control(): 353 | var obj = focused_objects.back() if focused_objects else null 354 | if not obj: 355 | return 356 | 357 | var focused_object_highlight = obj.get(PROPERTY_HIGHLIGHT) if obj else null 358 | if obj is Panel or obj is PanelContainer: 359 | focused_object_highlight = obj.get(PROPERTY_HIGHLIGHT_PANEL) if obj else null 360 | 361 | var highlight_color = Color.WHITE # default modulate color 362 | if focused_object_highlight != null: 363 | if focused_object_highlight is StyleBoxFlat: 364 | highlight_color = focused_object_highlight.bg_color 365 | HighlightColorRect.color = highlight_color 366 | HighlightColorPicker.color = highlight_color 367 | 368 | # Reflect horizontal alignment of focused_objects to toolbar 369 | func reflect_horizontal_alignment_control(): 370 | var obj = focused_objects.back() if focused_objects else null 371 | if not obj: 372 | return 373 | 374 | var h_align = obj.get(PROPERTY_HORIZONTAL_ALIGNMENT) if obj else null 375 | if h_align != null: 376 | var icon 377 | HorizontalAlign.disabled = false 378 | match h_align: 379 | HORIZONTAL_ALIGNMENT_LEFT: 380 | icon = HorizontalAlignPopupMenu.get_item_icon(0) 381 | HORIZONTAL_ALIGNMENT_CENTER: 382 | icon = HorizontalAlignPopupMenu.get_item_icon(1) 383 | HORIZONTAL_ALIGNMENT_RIGHT: 384 | icon = HorizontalAlignPopupMenu.get_item_icon(2) 385 | if icon: 386 | HorizontalAlign.icon = icon 387 | else: 388 | HorizontalAlign.disabled = true 389 | 390 | func reflect_vertical_alignment_control(): 391 | var obj = focused_objects.back() if focused_objects else null 392 | if not obj: 393 | return 394 | 395 | var v_align = obj.get(PROPERTY_VERTICAL_ALIGNMENT) if obj else null 396 | if v_align != null: 397 | var icon 398 | VerticalAlign.disabled = false 399 | match v_align: 400 | VERTICAL_ALIGNMENT_TOP: 401 | icon = VerticalAlignPopupMenu.get_item_icon(0) 402 | VERTICAL_ALIGNMENT_CENTER: 403 | icon = VerticalAlignPopupMenu.get_item_icon(1) 404 | VERTICAL_ALIGNMENT_BOTTOM: 405 | icon = VerticalAlignPopupMenu.get_item_icon(2) 406 | if icon: 407 | VerticalAlign.icon = icon 408 | else: 409 | VerticalAlign.disabled = true 410 | 411 | # Reflect font style of focused_objects to toolbar, it only check if focused_objects can applied with style 412 | func reflect_font_formatting_control(): 413 | var obj = focused_objects.back() if focused_objects else null 414 | if not obj: 415 | return 416 | 417 | # Font Style is not required to be accurate 418 | var font_variation = obj.get(PROPERTY_FONT) if obj else null 419 | FontFormatting.disabled = font_variation == null 420 | 421 | # Reset font name on toolbar 422 | func reset_font_family_control(): 423 | if FontFamily.get_item_count(): 424 | FontFamily.selected = FontFamily.get_item_count() - 1 425 | 426 | func _on_FontFamily_item_selected(index): 427 | if focused_objects == null: 428 | return 429 | 430 | var font_family_name = FontFamily.get_item_text(index) 431 | if font_family_name == "None": 432 | _on_FontClear_pressed() 433 | return 434 | 435 | var font_family = font_manager.get_font_family(font_family_name) 436 | if not font_family: 437 | return 438 | 439 | for obj in focused_objects: 440 | if obj is RichTextLabel: 441 | var to = {} 442 | to["regular"] = create_new_font_obj(font_family.regular.normal.data) if font_family.regular.get("normal") else null 443 | to["bold"] = create_new_font_obj(font_family.bold.normal.data) if font_family.bold.get("normal") else null 444 | to["regular_italic"] = create_new_font_obj(font_family.regular.italic.data) if font_family.regular.get("italic") else null 445 | to["bold_italic"] = create_new_font_obj(font_family.bold.italic.data) if font_family.bold.get("italic") else null 446 | change_rich_text_fonts(obj, to) 447 | else: 448 | var font_variation = obj.get(PROPERTY_FONT) 449 | if not font_variation: 450 | var font_size = FontSizePreset.get_item_text(FontSizePreset.selected).to_int() 451 | font_variation = create_new_font_obj(font_family.regular.normal.data) 452 | change_font(obj, font_variation) 453 | else: 454 | change_font_data(obj, font_family.regular.normal.data) # TODO: Get fallback weight if regular not found 455 | 456 | 457 | func _on_FontFamilyOptions_pressed(): 458 | if focused_objects: 459 | Utils.popup_on_target(FontFamilyOptionsPopupMenu, FontFamilyOptions) 460 | 461 | func _on_FontFamilyOptionsPopupMenu_id_pressed(index): 462 | match index: 463 | 0: 464 | FontFamilyFileDialog.popup_centered(Vector2(600, 400)) 465 | 1: 466 | _on_FontFamilyFileDialog_dir_selected(selected_font_root_dir) 467 | 468 | func _on_FontFamilyFileDialog_dir_selected(dir): 469 | selected_font_root_dir = dir 470 | # Load fonts 471 | if font_manager.load_root_dir(dir): 472 | FontFamily.clear() 473 | for font_family in font_manager.font_families.values(): 474 | FontFamily.add_item(font_family.name) 475 | FontFamily.add_item("None") 476 | 477 | reflect_font_family_control() 478 | config.set_value(CONFIG_SECTION_META, CONFIG_KEY_FONTS_DIR, dir) 479 | config.save(CONFIG_DIR) 480 | else: 481 | print("Failed to load fonts") 482 | 483 | func _on_FontSizePreset_item_selected(index): 484 | if focused_objects == null: 485 | return 486 | 487 | for obj in focused_objects: 488 | var new_font_size_str = FontSizePreset.get_item_text(index) 489 | change_font_size(obj, new_font_size_str.to_int()) 490 | 491 | func _on_FontSize_text_entered(new_text): 492 | if focused_objects == null: 493 | return 494 | 495 | for obj in focused_objects: 496 | change_font_size(obj, FontSize.text.to_int()) 497 | 498 | func _on_Bold_pressed(): 499 | if focused_objects == null: 500 | return 501 | 502 | Utils.popup_on_target(BoldPopupMenu, Bold) 503 | 504 | func _on_BoldPopupMenu_id_pressed(index): 505 | if focused_objects == null: 506 | return 507 | 508 | var font_weight_text = BoldPopupMenu.get_item_text(index) 509 | if font_weight_text == Bold.tooltip_text: 510 | return 511 | 512 | Bold.tooltip_text = font_weight_text 513 | var font_family_name = FontFamily.get_item_text(FontFamily.selected) 514 | var font_weight = Bold.tooltip_text.to_lower().replace("-", "_") 515 | var font_family = font_manager.get_font_family(font_family_name) 516 | 517 | for obj in focused_objects: 518 | if obj is RichTextLabel: 519 | continue 520 | var font_variation = obj.get(PROPERTY_FONT) 521 | if font_variation: 522 | var font_faces = font_family.get(font_weight) 523 | var font_face = font_faces.normal 524 | if Italic.button_pressed: 525 | if font_faces.has("italic"): 526 | font_face = font_faces.italic 527 | var font_data = font_face.data 528 | change_font_data(obj, font_data) 529 | 530 | func _on_Italic_pressed(): 531 | if focused_objects == null: 532 | return 533 | 534 | var font_family_name = FontFamily.get_item_text(FontFamily.selected) 535 | var font_family = font_manager.get_font_family(font_family_name) 536 | if not font_family: 537 | return 538 | 539 | var font_weight = Bold.tooltip_text.to_lower().replace("-", "_") 540 | var font_faces = font_family.get(font_weight) 541 | var font_face = font_faces.get("italic") if Italic.button_pressed else font_faces.normal 542 | 543 | for obj in focused_objects: 544 | change_font_data(obj, font_face.data) 545 | 546 | func _on_FontColor_pressed(): 547 | if focused_objects == null: 548 | return 549 | 550 | Utils.popup_on_target(FontColorPopupPanel, FontColor) 551 | var obj = focused_objects.back() 552 | 553 | if obj is RichTextLabel: 554 | _object_orig_font_color = obj.get(PROPERTY_FONT_COLOR_DEFAULT) 555 | else: 556 | _object_orig_font_color = obj.get(PROPERTY_FONT_COLOR) 557 | 558 | func _on_FontColor_ColorPicker_color_changed(color): 559 | if focused_objects == null: 560 | return 561 | 562 | for obj in focused_objects: 563 | # Preview only, doesn't stack undo/redo as this is called very frequently 564 | if obj is RichTextLabel: 565 | obj.set(PROPERTY_FONT_COLOR_DEFAULT, FontColorColorPicker.color) 566 | else: 567 | obj.set(PROPERTY_FONT_COLOR, FontColorColorPicker.color) 568 | FontColorColorRect.color = FontColorColorPicker.color 569 | 570 | func _on_FontColor_PopupPanel_popup_hide(): 571 | if focused_objects == null: 572 | return 573 | 574 | for obj in focused_objects: 575 | var current_font_color = obj.get(PROPERTY_FONT_COLOR) 576 | var font_color 577 | if current_font_color is Color or _object_orig_font_color is Color: 578 | font_color = FontColorColorPicker.color 579 | # Color selected 580 | change_font_color(obj, font_color) 581 | 582 | func _on_Highlight_pressed(): 583 | if focused_objects == null: 584 | return 585 | 586 | Utils.popup_on_target(HighlightPopupPanel, Highlight) 587 | 588 | for obj in focused_objects: 589 | var style_box_flat = obj.get(PROPERTY_HIGHLIGHT) 590 | if obj is Panel or obj is PanelContainer: 591 | style_box_flat = obj.get(PROPERTY_HIGHLIGHT_PANEL) 592 | if style_box_flat: 593 | _object_orig_highlight = StyleBoxFlat.new() 594 | _object_orig_highlight.bg_color = style_box_flat.bg_color 595 | else: 596 | _object_orig_highlight = null 597 | 598 | func _on_Highlight_ColorPicker_color_changed(color): 599 | if focused_objects == null: 600 | return 601 | 602 | # Preview only, doesn't stack undo/redo as this is called very frequently 603 | HighlightColorRect.color = color 604 | var style_box_flat = StyleBoxFlat.new() 605 | 606 | style_box_flat.bg_color = HighlightColorPicker.color 607 | 608 | for obj in focused_objects: 609 | if obj is Panel or obj is PanelContainer: 610 | obj.set(PROPERTY_HIGHLIGHT_PANEL, style_box_flat) 611 | else: 612 | obj.set(PROPERTY_HIGHLIGHT, style_box_flat) 613 | 614 | func _on_Highlight_PopupPanel_popup_hide(): 615 | if focused_objects == null: 616 | return 617 | 618 | for obj in focused_objects: 619 | var current_highlight 620 | if obj is Panel or obj is PanelContainer: 621 | current_highlight = obj.get(PROPERTY_HIGHLIGHT_PANEL) 622 | else: 623 | current_highlight = obj.get(PROPERTY_HIGHLIGHT) 624 | 625 | # Color selected 626 | var style_box_flat 627 | if current_highlight or _object_orig_highlight: 628 | style_box_flat = StyleBoxFlat.new() 629 | style_box_flat.bg_color = HighlightColorPicker.color 630 | change_highlight(obj, style_box_flat) 631 | 632 | func _on_HorizontalAlign_pressed(): 633 | if focused_objects: 634 | Utils.popup_on_target(HorizontalAlignPopupMenu, HorizontalAlign) 635 | 636 | func _on_HorizontalAlignPopupMenu_id_pressed(index): 637 | if focused_objects == null: 638 | return 639 | 640 | for obj in focused_objects: 641 | HorizontalAlign.icon = HorizontalAlignPopupMenu.get_item_icon(index) 642 | var selected_align = HorizontalAlignPopupMenu.get_item_metadata(index) 643 | var current_align = obj.get(PROPERTY_HORIZONTAL_ALIGNMENT) 644 | if current_align != selected_align: 645 | change_horizontal_alignment(obj, selected_align) 646 | 647 | func _on_VerticalAlign_pressed(): 648 | if focused_objects: 649 | Utils.popup_on_target(VerticalAlignPopupMenu, VerticalAlign) 650 | 651 | func _on_VerticalAlignPopupMenu_id_pressed(index): 652 | if focused_objects == null: 653 | return 654 | 655 | for obj in focused_objects: 656 | VerticalAlign.icon = VerticalAlignPopupMenu.get_item_icon(index) 657 | var selected_v_align = VerticalAlignPopupMenu.get_item_metadata(index) 658 | var current_v_align = obj.get(PROPERTY_VERTICAL_ALIGNMENT) 659 | if current_v_align != selected_v_align: 660 | change_vertical_alignment(obj, selected_v_align) 661 | 662 | func _on_FontFormatting_item_selected(index): 663 | if focused_objects == null: 664 | return 665 | 666 | var font_variation = focused_objects.back().get(PROPERTY_FONT) 667 | if not font_variation: 668 | return 669 | 670 | var font_formatting_name = FontFormatting.get_item_text(index) 671 | var font_formatting = font_manager.FONT_FORMATTINGS[font_formatting_name] 672 | FontFormatting.tooltip_text = font_formatting_name 673 | # TODO: Better way to get current item text from PopupMenu than tooltip_text 674 | _object_orig_font_formatting= FontManager.FontFormatting.new( 675 | Bold.tooltip_text.to_lower().replace("-", "_"), DEFAULT_FONT_SIZE, font_variation.spacing_glyph) 676 | 677 | for obj in focused_objects: 678 | change_font_formatting(obj, font_formatting) 679 | 680 | func _on_Tools_pressed(): 681 | if focused_objects: 682 | Utils.popup_on_target(ToolsPopupMenu, Tools) 683 | 684 | func _on_ToolsPopupMenu_id_pressed(index): 685 | if focused_objects == null: 686 | return 687 | 688 | match index: 689 | 0: # Font Clear 690 | _on_FontClear_pressed() 691 | 1: # Color Clear 692 | _on_ColorClear_pressed() 693 | 2: # Rect Size Refresh 694 | _on_RectSizeRefresh_pressed() 695 | 696 | func _on_FontClear_pressed(): 697 | if focused_objects == null: 698 | return 699 | 700 | for obj in focused_objects: 701 | if obj is RichTextLabel: 702 | var to = { 703 | "regular": null, 704 | "bold": null, 705 | "regular_italic": null, 706 | "bold_italic": null 707 | } 708 | change_rich_text_fonts(obj, to) 709 | else: 710 | change_font(obj, null) 711 | 712 | _on_focused_object_changed(focused_objects) # Update ui default state 713 | 714 | func _on_ColorClear_pressed(): 715 | if focused_objects == null: 716 | return 717 | 718 | for obj in focused_objects: 719 | if obj is RichTextLabel: 720 | _object_orig_font_color = obj.get(PROPERTY_FONT_COLOR_DEFAULT) 721 | else: 722 | _object_orig_font_color = obj.get(PROPERTY_FONT_COLOR) 723 | 724 | if obj is Panel or obj is PanelContainer: 725 | _object_orig_highlight = obj.get(PROPERTY_HIGHLIGHT_PANEL) 726 | else: 727 | _object_orig_highlight = obj.get(PROPERTY_HIGHLIGHT) 728 | change_font_color(obj, null) 729 | change_highlight(obj, null) 730 | 731 | func _on_RectSizeRefresh_pressed(): 732 | if focused_objects: 733 | for obj in focused_objects: 734 | obj.set("size", Vector2.ZERO) 735 | 736 | # focused_objects changed when user select different object in editor 737 | func _on_focused_object_changed(new_focused_object): 738 | reflect_font_family_control() # Font family must be reflected first 739 | reflect_font_size_control() 740 | reflect_font_color_control() 741 | reflect_highlight_control() 742 | reflect_bold_italic_control() 743 | reflect_horizontal_alignment_control() 744 | reflect_vertical_alignment_control() 745 | reflect_font_formatting_control() 746 | 747 | # focused_property changed when user select different property in inspector 748 | func _on_focused_property_changed(new_property): 749 | pass 750 | 751 | # focused_inspector changed when user select different inspector in editor 752 | func _on_focused_inspector_changed(new_inspector): 753 | pass 754 | 755 | # Called from setter method, handle update of font name/font weight in toolbar 756 | func _on_font_data_changed(new_font_data): 757 | var font_face = font_manager.get_font_face(new_font_data) 758 | if font_face: 759 | reflect_font_family_control() 760 | 761 | reflect_bold_italic_control() 762 | emit_signal("property_edited", PROPERTY_FONT) 763 | 764 | # Called from setter method, handle update of font name/font weight in toolbar 765 | func _on_font_changed(new_font): 766 | var font_family_name = FontFamily.get_item_text(FontFamily.selected) 767 | var font_family = font_manager.get_font_family(font_family_name) 768 | if not new_font: 769 | reset_font_family_control() 770 | else: 771 | var font_face = font_manager.get_font_face(new_font.base_font) 772 | if font_face: 773 | reflect_font_family_control() 774 | reflect_font_weight_control() 775 | 776 | reflect_font_size_control() 777 | reflect_bold_italic_control() 778 | reflect_font_formatting_control() 779 | emit_signal("property_edited", PROPERTY_FONT) 780 | 781 | # Called from setter method, handle update of font name/font weight in toolbar 782 | func _on_rich_text_fonts_changed(fonts): 783 | # TODO: Reflect font name of rich text font 784 | emit_signal("property_edited", PROPERTY_FONT) 785 | 786 | # Called from setter method, handle update of font size in toolbar 787 | func _on_font_size_changed(new_font_size): 788 | var new_font_size_str = str(new_font_size) 789 | FontSize.text = new_font_size_str 790 | 791 | emit_signal("property_edited", PROPERTY_FONT_SIZE) 792 | 793 | # Called from setter method, handle update of font color in toolbar 794 | func _on_font_color_changed(new_font_color): 795 | reflect_font_color_control() 796 | 797 | emit_signal("property_edited", PROPERTY_FONT_COLOR) 798 | 799 | # Called from setter method, handle update of highlight in toolbar 800 | func _on_highlight_changed(new_highlight): 801 | reflect_highlight_control() 802 | 803 | if focused_objects is Panel or focused_objects is PanelContainer: 804 | emit_signal("property_edited", PROPERTY_HIGHLIGHT_PANEL) 805 | else: 806 | emit_signal("property_edited", PROPERTY_HIGHLIGHT) 807 | 808 | # Called from setter method, handle update of horizontal alignment in toolbar 809 | func _on_horizontal_alignment_changed(h_align): 810 | reflect_horizontal_alignment_control() 811 | 812 | emit_signal("property_edited", PROPERTY_HORIZONTAL_ALIGNMENT) 813 | 814 | # Called from setter method, handle update of vertical alignment in toolbar 815 | func _on_vertical_alignment_changed(v_align): 816 | reflect_vertical_alignment_control() 817 | 818 | emit_signal("property_edited", PROPERTY_VERTICAL_ALIGNMENT) 819 | 820 | # font data setter, toolbar gets updated after called 821 | func set_font_data(object, font_data): 822 | font_data = font_data if font_data else null # font might be bool false, as Godot ignore null for varargs 823 | object.get(PROPERTY_FONT).base_font = font_data 824 | _on_font_data_changed(font_data) 825 | 826 | # font setter, toolbar gets updated after called 827 | func set_font(object, font): 828 | font = font if font else null 829 | object.set(PROPERTY_FONT, font) 830 | _on_font_changed(font) 831 | 832 | # rich text fonts setter, toolbar gets updated after called 833 | func set_rich_text_fonts(object, fonts): 834 | object.set(PROPERTY_FONT_NORMAL, fonts.regular) 835 | object.set(PROPERTY_FONT_BOLD, fonts.bold) 836 | object.set(PROPERTY_FONT_ITALIC, fonts.regular_italic) 837 | object.set(PROPERTY_FONT_BOLD_ITALIC, fonts.bold_italic) 838 | _on_rich_text_fonts_changed(fonts) 839 | 840 | # font size setter, toolbar gets updated after called 841 | func set_font_size(object, font_size): 842 | object.set(PROPERTY_FONT_SIZE, font_size) 843 | _on_font_size_changed(font_size) 844 | 845 | # font color setter, toolbar gets updated after called 846 | func set_font_color(object, font_color): 847 | font_color = font_color if font_color is Color else null 848 | if object is RichTextLabel: 849 | object.set(PROPERTY_FONT_COLOR_DEFAULT, font_color) 850 | else: 851 | object.set(PROPERTY_FONT_COLOR, font_color) 852 | _on_font_color_changed(font_color) 853 | 854 | # highlight setter, toolbar gets updated after called 855 | func set_highlight(object, highlight): 856 | highlight = highlight if highlight else null 857 | if object is Panel or object is PanelContainer: 858 | object.set(PROPERTY_HIGHLIGHT_PANEL, highlight) 859 | else: 860 | object.set(PROPERTY_HIGHLIGHT, highlight) 861 | _on_highlight_changed(highlight) 862 | 863 | # Horizontal alignment setter, toolbar gets updated after called 864 | func set_horizontal_alignment(object, h_align): 865 | object.set(PROPERTY_HORIZONTAL_ALIGNMENT, h_align) 866 | _on_horizontal_alignment_changed(h_align) 867 | 868 | # Vertical alignment setter, toolbar gets updated after called 869 | func set_vertical_alignment(object, v_align): 870 | object.set(PROPERTY_VERTICAL_ALIGNMENT, v_align) 871 | _on_vertical_alignment_changed(v_align) 872 | 873 | # font style setter, toolbar gets updated after called 874 | func set_font_formatting(object, font_formatting): 875 | if not font_formatting: 876 | return 877 | 878 | var font_family = font_manager.get_font_family(FontFamily.get_item_text(FontFamily.selected)) 879 | var font_face = font_family.get(font_formatting.font_weight).get(FontManager.get_font_style_str(font_formatting.font_style)) 880 | var font_data 881 | if font_face: 882 | font_data = font_face.data 883 | else: 884 | # Use current weight if desired weight not found 885 | font_data = object.get(PROPERTY_FONT).base_font 886 | set_font_data(object, font_data) 887 | set_font_size(object, font_formatting.size) 888 | set_font_extra_spacing_char(object, font_formatting.letter_spacing) 889 | 890 | # font letter spacing setter, toolbar gets updated after called 891 | func set_font_extra_spacing_char(object, new_spacing): 892 | object.get(PROPERTY_FONT).spacing_glyph = new_spacing 893 | # TODO: Add gui for font extra spacing 894 | 895 | # Convenience method to create font object with some default settings 896 | func create_new_font_obj(font_data, size=null): 897 | var font_variation = FontVariation.new() 898 | font_variation.base_font = font_data 899 | return font_variation 900 | -------------------------------------------------------------------------------- /addons/ui_design_tool/scenes/Toolbar.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=20 format=3 uid="uid://nq7vlsvxhv2p"] 2 | 3 | [ext_resource type="Script" path="res://addons/ui_design_tool/scenes/Toolbar.gd" id="1"] 4 | [ext_resource type="Texture2D" uid="uid://d3xaf7s36xuqc" path="res://addons/ui_design_tool/assets/icons/format_bold-white-18dp.svg" id="2"] 5 | [ext_resource type="Texture2D" uid="uid://ck4h5hqubttt7" path="res://addons/ui_design_tool/assets/icons/format_italic-white-18dp.svg" id="3"] 6 | [ext_resource type="Texture2D" uid="uid://b44il4qj7cem1" path="res://addons/ui_design_tool/assets/icons/format_underlined-white-18dp.svg" id="4"] 7 | [ext_resource type="Texture2D" uid="uid://b3tqua2bt1ix2" path="res://addons/ui_design_tool/assets/icons/format-color-text.png" id="5"] 8 | [ext_resource type="Texture2D" uid="uid://8qawl7hrofkj" path="res://addons/ui_design_tool/assets/icons/format_color_reset-white-18dp.svg" id="6"] 9 | [ext_resource type="Texture2D" uid="uid://cqv3uc8bew0am" path="res://addons/ui_design_tool/assets/icons/photo_size_select_small-white-18dp.svg" id="7"] 10 | [ext_resource type="Texture2D" uid="uid://d1uver224k3px" path="res://addons/ui_design_tool/assets/icons/folder_open-white-18dp.svg" id="8"] 11 | [ext_resource type="Texture2D" uid="uid://dn7q7grbfr7kh" path="res://addons/ui_design_tool/assets/icons/refresh-white-18dp.svg" id="9"] 12 | [ext_resource type="Texture2D" uid="uid://d1rj7h72swjhn" path="res://addons/ui_design_tool/assets/icons/marker.png" id="10"] 13 | [ext_resource type="Texture2D" uid="uid://xnn5xt6piaat" path="res://addons/ui_design_tool/assets/icons/format_clear-white-18dp.svg" id="11"] 14 | [ext_resource type="Texture2D" uid="uid://d0t8qupuaoigg" path="res://addons/ui_design_tool/assets/icons/format_align_right-white-18dp.svg" id="12"] 15 | [ext_resource type="Texture2D" uid="uid://i11r3de57bc3" path="res://addons/ui_design_tool/assets/icons/format_align_center-white-18dp.svg" id="13"] 16 | [ext_resource type="Texture2D" uid="uid://dtsld0omp3fy0" path="res://addons/ui_design_tool/assets/icons/format_align_left-white-18dp.svg" id="14"] 17 | [ext_resource type="Texture2D" uid="uid://rpjhdv5qake3" path="res://addons/ui_design_tool/assets/icons/vertical_align_bottom-white-18dp.svg" id="15"] 18 | [ext_resource type="Texture2D" uid="uid://cjan2dq5nvdvk" path="res://addons/ui_design_tool/assets/icons/vertical_align_top-white-18dp.svg" id="16"] 19 | [ext_resource type="Texture2D" uid="uid://ckriw8d4yelu" path="res://addons/ui_design_tool/assets/icons/vertical_align_center-white-18dp.svg" id="17"] 20 | [ext_resource type="Texture2D" uid="uid://crte1qj0ftynh" path="res://addons/ui_design_tool/assets/icons/more_vert-white-18dp.svg" id="18"] 21 | [ext_resource type="Texture2D" uid="uid://cm5d77b25dgjc" path="res://addons/ui_design_tool/assets/icons/more_horiz-white-18dp.svg" id="19"] 22 | 23 | [node name="Toolbar" type="HBoxContainer"] 24 | visible = false 25 | script = ExtResource("1") 26 | 27 | [node name="FontFamily" type="OptionButton" parent="."] 28 | custom_minimum_size = Vector2i(99, 0) 29 | layout_mode = 2 30 | offset_right = 99.0 31 | offset_bottom = 31.0 32 | size_flags_vertical = 4 33 | tooltip_text = "Font Family" 34 | clip_text = true 35 | item_count = 9 36 | selected = 0 37 | popup/item_0/text = "Alata" 38 | popup/item_0/id = 0 39 | popup/item_1/text = "Bungee" 40 | popup/item_1/id = 1 41 | popup/item_2/text = "Concert_One" 42 | popup/item_2/id = 2 43 | popup/item_3/text = "Fredoka_One" 44 | popup/item_3/id = 3 45 | popup/item_4/text = "Neuton" 46 | popup/item_4/id = 4 47 | popup/item_5/text = "Nunito" 48 | popup/item_5/id = 5 49 | popup/item_6/text = "Roboto" 50 | popup/item_6/id = 6 51 | popup/item_7/text = "Space_Mono" 52 | popup/item_7/id = 7 53 | popup/item_8/text = "None" 54 | popup/item_8/id = 8 55 | 56 | [node name="FontFamilyOptions" type="Button" parent="."] 57 | layout_mode = 2 58 | offset_left = 103.0 59 | offset_right = 129.0 60 | offset_bottom = 31.0 61 | tooltip_text = "Font Family Options" 62 | icon = ExtResource("18") 63 | flat = true 64 | 65 | [node name="PopupMenu" type="PopupMenu" parent="FontFamilyOptions"] 66 | item_count = 2 67 | item_0/text = "Load Fonts" 68 | item_0/icon = ExtResource("8") 69 | item_0/id = 0 70 | item_1/text = "Refresh Fonts" 71 | item_1/icon = ExtResource("9") 72 | item_1/id = 1 73 | 74 | [node name="FontFamilyFileDialog" type="FileDialog" parent="."] 75 | title = "Open a Directory" 76 | size = Vector2i(400, 300) 77 | min_size = Vector2i(300, 200) 78 | ok_button_text = "Select This Folder" 79 | file_mode = 2 80 | 81 | [node name="VSeparator" type="VSeparator" parent="."] 82 | layout_mode = 2 83 | offset_left = 133.0 84 | offset_right = 137.0 85 | offset_bottom = 31.0 86 | 87 | [node name="FontSize" type="LineEdit" parent="."] 88 | layout_mode = 2 89 | offset_left = 141.0 90 | offset_right = 208.0 91 | offset_bottom = 31.0 92 | tooltip_text = "Font Size" 93 | 94 | [node name="FontSizePreset" type="OptionButton" parent="FontSize"] 95 | show_behind_parent = true 96 | layout_mode = 1 97 | anchors_preset = 15 98 | anchor_right = 1.0 99 | anchor_bottom = 1.0 100 | offset_left = 27.0 101 | offset_right = 14.0 102 | grow_horizontal = 2 103 | grow_vertical = 2 104 | size_flags_horizontal = 4 105 | size_flags_vertical = 4 106 | tooltip_text = "Font Size Presets" 107 | disabled = true 108 | item_count = 17 109 | popup/item_0/text = "8" 110 | popup/item_0/id = 0 111 | popup/item_1/text = "9" 112 | popup/item_1/id = 1 113 | popup/item_2/text = "10" 114 | popup/item_2/id = 2 115 | popup/item_3/text = "11" 116 | popup/item_3/id = 3 117 | popup/item_4/text = "12" 118 | popup/item_4/id = 4 119 | popup/item_5/text = "14" 120 | popup/item_5/id = 5 121 | popup/item_6/text = "16" 122 | popup/item_6/id = 6 123 | popup/item_7/text = "18" 124 | popup/item_7/id = 7 125 | popup/item_8/text = "24" 126 | popup/item_8/id = 8 127 | popup/item_9/text = "30" 128 | popup/item_9/id = 9 129 | popup/item_10/text = "36" 130 | popup/item_10/id = 10 131 | popup/item_11/text = "48" 132 | popup/item_11/id = 11 133 | popup/item_12/text = "60" 134 | popup/item_12/id = 12 135 | popup/item_13/text = "72" 136 | popup/item_13/id = 13 137 | popup/item_14/text = "96" 138 | popup/item_14/id = 14 139 | popup/item_15/text = "128" 140 | popup/item_15/id = 15 141 | popup/item_16/text = "256" 142 | popup/item_16/id = 16 143 | 144 | [node name="PanelContainer" type="PanelContainer" parent="."] 145 | self_modulate = Color(1, 1, 1, 0) 146 | layout_mode = 2 147 | offset_left = 212.0 148 | offset_right = 212.0 149 | offset_bottom = 31.0 150 | mouse_filter = 2 151 | 152 | [node name="Bold" type="Button" parent="."] 153 | layout_mode = 2 154 | offset_left = 216.0 155 | offset_right = 242.0 156 | offset_bottom = 31.0 157 | tooltip_text = "Bold" 158 | disabled = true 159 | icon = ExtResource("2") 160 | flat = true 161 | 162 | [node name="PopupMenu" type="PopupMenu" parent="Bold"] 163 | item_count = 9 164 | item_0/text = "Thin" 165 | item_0/id = 0 166 | item_1/text = "Extra-Light" 167 | item_1/id = 1 168 | item_2/text = "Light" 169 | item_2/id = 2 170 | item_3/text = "Regular" 171 | item_3/id = 3 172 | item_4/text = "Medium" 173 | item_4/id = 4 174 | item_5/text = "Semi-Bold" 175 | item_5/id = 5 176 | item_6/text = "Bold" 177 | item_6/id = 6 178 | item_7/text = "Extra-Bold" 179 | item_7/id = 7 180 | item_8/text = "Black" 181 | item_8/id = 8 182 | 183 | [node name="Italic" type="Button" parent="."] 184 | layout_mode = 2 185 | offset_left = 246.0 186 | offset_right = 272.0 187 | offset_bottom = 31.0 188 | tooltip_text = "Italic" 189 | disabled = true 190 | toggle_mode = true 191 | icon = ExtResource("3") 192 | flat = true 193 | 194 | [node name="Underline" type="Button" parent="."] 195 | layout_mode = 2 196 | offset_left = 276.0 197 | offset_right = 302.0 198 | offset_bottom = 31.0 199 | tooltip_text = "Underline 200 | *Only supported in RichTextLabel" 201 | disabled = true 202 | toggle_mode = true 203 | icon = ExtResource("4") 204 | flat = true 205 | 206 | [node name="FontColor" type="Button" parent="."] 207 | layout_mode = 2 208 | offset_left = 306.0 209 | offset_right = 332.0 210 | offset_bottom = 31.0 211 | tooltip_text = "Font Color" 212 | icon = ExtResource("5") 213 | flat = true 214 | 215 | [node name="PopupPanel" type="PopupPanel" parent="FontColor"] 216 | size = Vector2i(116, 227) 217 | 218 | [node name="ColorPicker" type="ColorPicker" parent="FontColor/PopupPanel"] 219 | offset_left = 4.0 220 | offset_top = 4.0 221 | offset_right = 294.0 222 | offset_bottom = 511.0 223 | 224 | [node name="ColorRect" type="ColorRect" parent="FontColor"] 225 | layout_mode = 1 226 | anchors_preset = 8 227 | anchor_left = 0.5 228 | anchor_top = 0.5 229 | anchor_right = 0.5 230 | anchor_bottom = 0.5 231 | offset_left = -9.0 232 | offset_top = 8.0 233 | offset_right = 9.0 234 | offset_bottom = 11.0 235 | grow_horizontal = 2 236 | grow_vertical = 2 237 | 238 | [node name="Highlight" type="Button" parent="."] 239 | layout_mode = 2 240 | offset_left = 336.0 241 | offset_right = 362.0 242 | offset_bottom = 31.0 243 | tooltip_text = "Highlight Color" 244 | icon = ExtResource("10") 245 | flat = true 246 | 247 | [node name="PopupPanel" type="PopupPanel" parent="Highlight"] 248 | size = Vector2i(116, 227) 249 | 250 | [node name="ColorPicker" type="ColorPicker" parent="Highlight/PopupPanel"] 251 | offset_left = 4.0 252 | offset_top = 4.0 253 | offset_right = 294.0 254 | offset_bottom = 511.0 255 | 256 | [node name="ColorRect" type="ColorRect" parent="Highlight"] 257 | layout_mode = 1 258 | anchors_preset = 8 259 | anchor_left = 0.5 260 | anchor_top = 0.5 261 | anchor_right = 0.5 262 | anchor_bottom = 0.5 263 | offset_left = -9.0 264 | offset_top = 8.0 265 | offset_right = 9.0 266 | offset_bottom = 11.0 267 | grow_horizontal = 2 268 | grow_vertical = 2 269 | 270 | [node name="VSeparator2" type="VSeparator" parent="."] 271 | layout_mode = 2 272 | offset_left = 366.0 273 | offset_right = 370.0 274 | offset_bottom = 31.0 275 | 276 | [node name="HorizontalAlign" type="Button" parent="."] 277 | layout_mode = 2 278 | offset_left = 374.0 279 | offset_right = 400.0 280 | offset_bottom = 31.0 281 | tooltip_text = "Horizontal Align" 282 | toggle_mode = true 283 | icon = ExtResource("14") 284 | flat = true 285 | 286 | [node name="PopupMenu" type="PopupMenu" parent="HorizontalAlign"] 287 | item_count = 3 288 | item_0/text = "" 289 | item_0/icon = ExtResource("14") 290 | item_0/id = 0 291 | item_1/text = "" 292 | item_1/icon = ExtResource("13") 293 | item_1/id = 1 294 | item_2/text = "" 295 | item_2/icon = ExtResource("12") 296 | item_2/id = 2 297 | 298 | [node name="VerticalAlign" type="Button" parent="."] 299 | layout_mode = 2 300 | offset_left = 404.0 301 | offset_right = 430.0 302 | offset_bottom = 31.0 303 | tooltip_text = "Vertical Align" 304 | toggle_mode = true 305 | icon = ExtResource("16") 306 | flat = true 307 | 308 | [node name="PopupMenu" type="PopupMenu" parent="VerticalAlign"] 309 | item_count = 3 310 | item_0/text = "" 311 | item_0/icon = ExtResource("16") 312 | item_0/id = 0 313 | item_1/text = "" 314 | item_1/icon = ExtResource("17") 315 | item_1/id = 1 316 | item_2/text = "" 317 | item_2/icon = ExtResource("15") 318 | item_2/id = 2 319 | 320 | [node name="VSeparator3" type="VSeparator" parent="."] 321 | layout_mode = 2 322 | offset_left = 434.0 323 | offset_right = 438.0 324 | offset_bottom = 31.0 325 | 326 | [node name="FontFormatting" type="OptionButton" parent="."] 327 | custom_minimum_size = Vector2i(112, 0) 328 | layout_mode = 2 329 | offset_left = 442.0 330 | offset_right = 554.0 331 | offset_bottom = 31.0 332 | size_flags_horizontal = 4 333 | size_flags_vertical = 4 334 | tooltip_text = "Font Formatting" 335 | clip_text = true 336 | item_count = 13 337 | selected = -1 338 | popup/item_0/text = "Heading 1" 339 | popup/item_0/id = 0 340 | popup/item_1/text = "Heading 2" 341 | popup/item_1/id = 1 342 | popup/item_2/text = "Heading 3" 343 | popup/item_2/id = 2 344 | popup/item_3/text = "Heading 4" 345 | popup/item_3/id = 3 346 | popup/item_4/text = "Heading 5" 347 | popup/item_4/id = 4 348 | popup/item_5/text = "Heading 6" 349 | popup/item_5/id = 5 350 | popup/item_6/text = "Subtitle 1" 351 | popup/item_6/id = 6 352 | popup/item_7/text = "Subtitle 2" 353 | popup/item_7/id = 7 354 | popup/item_8/text = "Body 1" 355 | popup/item_8/id = 8 356 | popup/item_9/text = "Body 2" 357 | popup/item_9/id = 9 358 | popup/item_10/text = "Button" 359 | popup/item_10/id = 10 360 | popup/item_11/text = "Caption" 361 | popup/item_11/id = 11 362 | popup/item_12/text = "Overline" 363 | popup/item_12/id = 12 364 | 365 | [node name="Tools" type="Button" parent="."] 366 | layout_mode = 2 367 | offset_left = 558.0 368 | offset_right = 584.0 369 | offset_bottom = 31.0 370 | tooltip_text = "Tools" 371 | icon = ExtResource("19") 372 | flat = true 373 | 374 | [node name="PopupMenu" type="PopupMenu" parent="Tools"] 375 | item_count = 3 376 | item_0/text = "Font Clear" 377 | item_0/icon = ExtResource("11") 378 | item_0/id = 0 379 | item_1/text = "Color Clear" 380 | item_1/icon = ExtResource("6") 381 | item_1/id = 1 382 | item_2/text = "Rect Size Refresh" 383 | item_2/icon = ExtResource("7") 384 | item_2/id = 2 385 | -------------------------------------------------------------------------------- /addons/ui_design_tool/scripts/FontManager.gd: -------------------------------------------------------------------------------- 1 | extends Object 2 | 3 | const FONT_FILE_PATTERN = "\\.ttf$" 4 | const FONT_WEIGHT_PATTERNS = { 5 | "thin": "(?i)(-|_)thin", 6 | "extra_light": "(?i)(-|_)extralight", 7 | "light": "(?i)(-|_)light", 8 | "regular": "(?i)(-|_)regular", 9 | "medium": "(?i)(-|_)medium", 10 | "semi_bold": "(?i)(-|_)semibold", 11 | "bold": "(?i)(-|_)bold", 12 | "extra_bold": "(?i)(-|_)extrabold", 13 | "black": "(?i)(-|_)black", 14 | "extra_black": "(?i)(-|_)extrablack" 15 | } 16 | const FONT_ITALIC_PATTERN = "(?i)italic" 17 | const FONT_ITALIC_ONLY_PATTERN = "(?i)(-|_)italic" 18 | const FONT_VARIABLE_PATTERN = "(?i)(-|_)variable" 19 | var FONT_FORMATTINGS = { 20 | "Heading 1": FontFormatting.new("light", 96, -3), 21 | "Heading 2": FontFormatting.new("light", 60, -2), 22 | "Heading 3": FontFormatting.new("regular", 48), 23 | "Heading 4": FontFormatting.new("regular", 34, 1), 24 | "Heading 5": FontFormatting.new("regular", 24), 25 | "Heading 6": FontFormatting.new("medium", 20, 1), 26 | "Subtitle 1": FontFormatting.new("regular", 16), 27 | "Subtitle 2": FontFormatting.new("medium", 14, 1), 28 | "Body 1": FontFormatting.new("regular", 16, 1), 29 | "Body 2": FontFormatting.new("regular", 14, 1), 30 | "Button": FontFormatting.new("medium", 14, 1), 31 | "Caption": FontFormatting.new("regular", 12, 1), 32 | "Overline": FontFormatting.new("regular", 10) 33 | } # Typography hierarchy presets, see https://material.io/design/typography/the-type-system.html#type-scale 34 | const DIR_FOLDER_PATTERN = "\\w+(?!.*\\w)" 35 | 36 | var font_families = {} 37 | 38 | var _font_file_regex = RegEx.new() 39 | var _font_weight_regexes = { 40 | "thin": RegEx.new(), 41 | "extra_light": RegEx.new(), 42 | "light": RegEx.new(), 43 | "regular": RegEx.new(), 44 | "medium": RegEx.new(), 45 | "semi_bold": RegEx.new(), 46 | "bold": RegEx.new(), 47 | "extra_bold": RegEx.new(), 48 | "black": RegEx.new(), 49 | "extra_black": RegEx.new() 50 | } 51 | var _font_italic_regex = RegEx.new() 52 | var _font_italic_only_regex = RegEx.new() 53 | var _font_variable_regex = RegEx.new() 54 | var _dir_folder_regex = RegEx.new() 55 | 56 | 57 | func _init(): 58 | if _font_file_regex.compile(FONT_FILE_PATTERN): 59 | print("Failed to compile ", FONT_FILE_PATTERN) 60 | 61 | for font_weight in _font_weight_regexes.keys(): 62 | if _font_weight_regexes[font_weight].compile(FONT_WEIGHT_PATTERNS[font_weight]): 63 | print("Failed to compile ", FONT_WEIGHT_PATTERNS[font_weight]) 64 | 65 | if _font_italic_regex.compile(FONT_ITALIC_PATTERN): 66 | print("Failed to compile ", FONT_ITALIC_PATTERN) 67 | 68 | if _font_italic_only_regex.compile(FONT_ITALIC_ONLY_PATTERN): 69 | print("Failed to compile ", FONT_ITALIC_ONLY_PATTERN) 70 | 71 | if _font_variable_regex.compile(FONT_VARIABLE_PATTERN): 72 | print("Failed to compile ", FONT_VARIABLE_PATTERN) 73 | 74 | if _dir_folder_regex.compile(DIR_FOLDER_PATTERN): 75 | print("Failed to compile ", DIR_FOLDER_PATTERN) 76 | 77 | # Load root dir of font resources, check Readme for directory structure 78 | func load_root_dir(root_dir): 79 | var directory = DirAccess.open(root_dir) 80 | var result = DirAccess.get_open_error() 81 | if result == OK: 82 | font_families.clear() 83 | directory.list_dir_begin() # Skip . and .. directory and hidden# TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547 84 | var dir = directory.get_next() 85 | while dir != "": 86 | if not directory.current_is_dir(): 87 | dir = directory.get_next() 88 | continue 89 | 90 | load_fonts(directory.get_current_dir() + "/" + dir) 91 | dir = directory.get_next() 92 | directory.list_dir_end() 93 | else: 94 | push_warning("UI Design Tool: An error occurred when trying to access %s, ERROR: %d" % [root_dir, result]) 95 | return false 96 | 97 | return true 98 | 99 | # Load fonts data from directory, check Readme for filename pattern 100 | func load_fonts(dir): 101 | var directory = DirAccess.open(dir) 102 | var result = DirAccess.get_open_error() 103 | if result == OK: 104 | var font_family_name = _dir_folder_regex.search(dir).get_string() 105 | var font_family = FontFamily.new(font_family_name) 106 | directory.list_dir_begin() 107 | var filename = directory.get_next() 108 | while filename != "": 109 | if directory.current_is_dir(): 110 | filename = directory.get_next() 111 | continue 112 | 113 | if _font_file_regex.search(filename): 114 | for font_weight in _font_weight_regexes.keys(): 115 | if _font_variable_regex.search(filename): # Godot doesn't support variable font 116 | continue 117 | 118 | var abs_dir = directory.get_current_dir() + "/" + filename 119 | if _font_weight_regexes[font_weight].search(filename): 120 | var font_data = load(abs_dir) 121 | 122 | if _font_italic_regex.search(filename): 123 | font_family.set_font_face(FontFace.new(font_family.name, font_weight, font_data, FONT_STYLE.ITALIC)) 124 | else: 125 | font_family.set_font_face(FontFace.new(font_family.name, font_weight, font_data)) 126 | break 127 | else: 128 | # Capture regular italic from {font-name}-italic.ttf 129 | if _font_italic_only_regex.search(filename): 130 | var font_data = load(abs_dir) 131 | font_family.set_font_face(FontFace.new(font_family.name, "regular", font_data, FONT_STYLE.ITALIC)) 132 | break 133 | filename = directory.get_next() 134 | directory.list_dir_end() 135 | 136 | if not font_family.is_empty(): 137 | font_families[font_family.name] = font_family 138 | else: 139 | push_warning("UI Design Tool: Unable to locate usable .ttf files from %s, check README.md for proper directory/filename structure" % dir) 140 | else: 141 | push_warning("UI Design Tool: An error occurred when trying to access %s, ERROR: %d" % [dir, result]) 142 | return false 143 | 144 | return true 145 | 146 | func get_font_face(font_data): 147 | for res in font_families.values(): 148 | for font_weight in FONT_WEIGHT.keys(): 149 | var font_faces = res.get(font_weight) 150 | for font_face in font_faces.values(): 151 | if font_face.data and font_data: 152 | if font_face.data.resource_path == font_data.resource_path: 153 | return font_face 154 | return null 155 | 156 | # Find font resource with font name 157 | func get_font_family(font_family_name): 158 | return font_families.get(font_family_name) 159 | 160 | static func get_font_style_str(font_style): 161 | return FONT_STYLE.keys()[font_style].to_lower() 162 | 163 | # Declaration of font type with font_faces 164 | class FontFamily: 165 | var name = "" 166 | var thin = {} 167 | var extra_light = {} 168 | var light = {} 169 | var regular = {} 170 | var medium = {} 171 | var semi_bold = {} 172 | var bold = {} 173 | var extra_bold = {} 174 | var black = {} 175 | var extra_black = {} 176 | 177 | func _init(n): 178 | name = n 179 | 180 | func set_font_face(font_face): 181 | var font_faces = get(font_face.font_weight.replace('-', '_')) 182 | font_faces[FONT_STYLE.keys()[font_face.font_style].to_lower()] = font_face 183 | 184 | func is_empty(): 185 | for font_weight in FONT_WEIGHT.keys(): 186 | var font_faces = get(font_weight) 187 | if not font_faces.values().is_empty(): 188 | return false 189 | return true 190 | 191 | func get_class(): 192 | return "FontFamily" 193 | 194 | # Font face data, see (https://developer.mozilla.org/my/docs/Web/CSS/@font-face) 195 | class FontFace: 196 | var font_family = "" 197 | var font_weight = "" 198 | var font_style = FONT_STYLE.NORMAL 199 | var data 200 | 201 | func _init(ff, fw, d, fs=FONT_STYLE.NORMAL): 202 | font_family = ff 203 | font_weight = fw 204 | font_style = fs 205 | data = d 206 | 207 | func get_class(): 208 | return "FontFace" 209 | 210 | # Declaration of font style TODO: Custom resource to define font style 211 | class FontFormatting: 212 | var font_weight = "regular" 213 | var font_style = 0 # FONT_STYLE.NORMAL 214 | var size = 16 215 | var letter_spacing = 0 216 | 217 | func _init(fw, s, ls=0): 218 | font_weight = fw 219 | size = s 220 | letter_spacing = ls 221 | 222 | # List of font style, see (https://developer.mozilla.org/my/docs/Web/CSS/font-style) 223 | enum FONT_STYLE { 224 | NORMAL, 225 | ITALIC, 226 | OBLIQUE 227 | } 228 | 229 | # List of font weights, see (https://docs.microsoft.com/en-us/typography/opentype/spec/os2#usweightclass) 230 | const FONT_WEIGHT = { 231 | "thin": 100, 232 | "extra_light": 200, 233 | "light": 300, 234 | "regular": 400, 235 | "medium": 500, 236 | "semi_bold": 600, 237 | "bold": 700, 238 | "extra_bold": 800, 239 | "black": 900 240 | } 241 | -------------------------------------------------------------------------------- /addons/ui_design_tool/scripts/Utils.gd: -------------------------------------------------------------------------------- 1 | static func markup_text_edit_selection(text_edit, start_text, end_text): 2 | if not text_edit.is_selection_active(): 3 | return 4 | 5 | var selection_from_pos = Vector2(text_edit.get_selection_from_column(), text_edit.get_selection_from_line()) 6 | var selection_to_pos = Vector2(text_edit.get_selection_to_column(), text_edit.get_selection_to_line()) 7 | var one_line_selection = selection_from_pos.y == selection_to_pos.y 8 | 9 | text_edit.deselect() 10 | set_text_edit_cursor_pos(text_edit, selection_from_pos.x, selection_from_pos.y) 11 | text_edit.insert_text_at_cursor(start_text) 12 | 13 | if one_line_selection: 14 | selection_to_pos.x += start_text.length() 15 | 16 | set_text_edit_cursor_pos(text_edit, selection_to_pos.x, selection_to_pos.y) 17 | text_edit.insert_text_at_cursor(end_text) 18 | 19 | if one_line_selection: 20 | selection_to_pos.x += end_text.length() 21 | 22 | text_edit.select(selection_from_pos.y, selection_from_pos.x, selection_to_pos.y, selection_to_pos.x) 23 | 24 | static func get_text_edit_cursor_pos(text_edit): 25 | return Vector2(text_edit.get_caret_column(), text_edit.get_caret_line()) 26 | 27 | static func set_text_edit_cursor_pos(text_edit, column, line): 28 | text_edit.set_caret_column(column) 29 | text_edit.set_caret_line(line) 30 | 31 | # Position Popup near to its target while within window, solution from ColorPickerButton source code(https://github.com/godotengine/godot/blob/6d8c14f849376905e1577f9fc3f9512bcffb1e3c/scene/gui/color_picker.cpp#L878) 32 | static func popup_on_target(popup, target): 33 | popup.size = popup.get_contents_minimum_size() 34 | var usable_rect = Rect2(Vector2.ZERO, DisplayServer.window_get_size()) 35 | var cp_rect = Rect2(Vector2.ZERO, popup.get_size()) 36 | for i in 4: 37 | if i > 1: 38 | cp_rect.position.y = target.global_position.y - cp_rect.size.y 39 | else: 40 | cp_rect.position.y = target.global_position.y + target.get_size().y 41 | 42 | if i & 1: 43 | cp_rect.position.x = target.global_position.x 44 | else: 45 | cp_rect.position.x = target.global_position.x - max(0, cp_rect.size.x - target.get_size().x) 46 | 47 | if usable_rect.encloses(cp_rect): 48 | break 49 | popup.set_position(cp_rect.position) 50 | popup.popup() 51 | 52 | # Roughly calculate the display size of option button regarding to the display_text 53 | static func get_option_button_display_size(option_button, display_text): 54 | # TODO: Improve accuracy 55 | # Use default theme if not assingned 56 | var theme = option_button.get_theme() if option_button.get_theme() else Theme.new() 57 | var string_size = theme.get_font("font", "fonts").get_string_size(display_text) 58 | var arrow_icon = theme.get_icon("arrow", "styles") 59 | # Takes arrow icon size into account 60 | string_size.x += arrow_icon.get_width() 61 | return string_size 62 | --------------------------------------------------------------------------------