Initial commit
BIN
fonts/Vera.ttf
Normal file
7
fonts/VeraLarge.tres
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
[gd_resource type="DynamicFont" load_steps=2 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://addons/de.mewin.gduibasics/fonts/Vera.ttf" type="DynamicFontData" id=1]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
size = 20
|
||||||
|
font_data = ExtResource( 1 )
|
6
fonts/VeraMedium.tres
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
[gd_resource type="DynamicFont" load_steps=2 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://addons/de.mewin.gduibasics/fonts/Vera.ttf" type="DynamicFontData" id=1]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
font_data = ExtResource( 1 )
|
BIN
fonts/VeraMono.ttf
Normal file
7
fonts/VeraMonoLarge.tres
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
[gd_resource type="DynamicFont" load_steps=2 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://addons/de.mewin.gduibasics/fonts/VeraMono.ttf" type="DynamicFontData" id=1]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
size = 20
|
||||||
|
font_data = ExtResource( 1 )
|
6
fonts/VeraMonoMedium.tres
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
[gd_resource type="DynamicFont" load_steps=2 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://addons/de.mewin.gduibasics/fonts/VeraMono.ttf" type="DynamicFontData" id=1]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
font_data = ExtResource( 1 )
|
7
fonts/VeraMonoSmall.tres
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
[gd_resource type="DynamicFont" load_steps=2 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://addons/de.mewin.gduibasics/fonts/VeraMono.ttf" type="DynamicFontData" id=1]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
size = 12
|
||||||
|
font_data = ExtResource( 1 )
|
7
fonts/VeraSmall.tres
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
[gd_resource type="DynamicFont" load_steps=2 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://addons/de.mewin.gduibasics/fonts/Vera.ttf" type="DynamicFontData" id=1]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
size = 12
|
||||||
|
font_data = ExtResource( 1 )
|
124
fonts/Vera_COPYRIGHT.TXT
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
Bitstream Vera Fonts Copyright
|
||||||
|
|
||||||
|
The fonts have a generous copyright, allowing derivative works (as
|
||||||
|
long as "Bitstream" or "Vera" are not in the names), and full
|
||||||
|
redistribution (so long as they are not *sold* by themselves). They
|
||||||
|
can be be bundled, redistributed and sold with any software.
|
||||||
|
|
||||||
|
The fonts are distributed under the following copyright:
|
||||||
|
|
||||||
|
Copyright
|
||||||
|
=========
|
||||||
|
|
||||||
|
Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream
|
||||||
|
Vera is a trademark of Bitstream, Inc.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of the fonts accompanying this license ("Fonts") and associated
|
||||||
|
documentation files (the "Font Software"), to reproduce and distribute
|
||||||
|
the Font Software, including without limitation the rights to use,
|
||||||
|
copy, merge, publish, distribute, and/or sell copies of the Font
|
||||||
|
Software, and to permit persons to whom the Font Software is furnished
|
||||||
|
to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright and trademark notices and this permission notice
|
||||||
|
shall be included in all copies of one or more of the Font Software
|
||||||
|
typefaces.
|
||||||
|
|
||||||
|
The Font Software may be modified, altered, or added to, and in
|
||||||
|
particular the designs of glyphs or characters in the Fonts may be
|
||||||
|
modified and additional glyphs or characters may be added to the
|
||||||
|
Fonts, only if the fonts are renamed to names not containing either
|
||||||
|
the words "Bitstream" or the word "Vera".
|
||||||
|
|
||||||
|
This License becomes null and void to the extent applicable to Fonts
|
||||||
|
or Font Software that has been modified and is distributed under the
|
||||||
|
"Bitstream Vera" names.
|
||||||
|
|
||||||
|
The Font Software may be sold as part of a larger software package but
|
||||||
|
no copy of one or more of the Font Software typefaces may be sold by
|
||||||
|
itself.
|
||||||
|
|
||||||
|
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||||
|
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL
|
||||||
|
BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||||
|
OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL,
|
||||||
|
OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||||
|
OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT
|
||||||
|
SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||||
|
|
||||||
|
Except as contained in this notice, the names of Gnome, the Gnome
|
||||||
|
Foundation, and Bitstream Inc., shall not be used in advertising or
|
||||||
|
otherwise to promote the sale, use or other dealings in this Font
|
||||||
|
Software without prior written authorization from the Gnome Foundation
|
||||||
|
or Bitstream Inc., respectively. For further information, contact:
|
||||||
|
fonts at gnome dot org.
|
||||||
|
|
||||||
|
Copyright FAQ
|
||||||
|
=============
|
||||||
|
|
||||||
|
1. I don't understand the resale restriction... What gives?
|
||||||
|
|
||||||
|
Bitstream is giving away these fonts, but wishes to ensure its
|
||||||
|
competitors can't just drop the fonts as is into a font sale system
|
||||||
|
and sell them as is. It seems fair that if Bitstream can't make money
|
||||||
|
from the Bitstream Vera fonts, their competitors should not be able to
|
||||||
|
do so either. You can sell the fonts as part of any software package,
|
||||||
|
however.
|
||||||
|
|
||||||
|
2. I want to package these fonts separately for distribution and
|
||||||
|
sale as part of a larger software package or system. Can I do so?
|
||||||
|
|
||||||
|
Yes. A RPM or Debian package is a "larger software package" to begin
|
||||||
|
with, and you aren't selling them independently by themselves.
|
||||||
|
See 1. above.
|
||||||
|
|
||||||
|
3. Are derivative works allowed?
|
||||||
|
Yes!
|
||||||
|
|
||||||
|
4. Can I change or add to the font(s)?
|
||||||
|
Yes, but you must change the name(s) of the font(s).
|
||||||
|
|
||||||
|
5. Under what terms are derivative works allowed?
|
||||||
|
|
||||||
|
You must change the name(s) of the fonts. This is to ensure the
|
||||||
|
quality of the fonts, both to protect Bitstream and Gnome. We want to
|
||||||
|
ensure that if an application has opened a font specifically of these
|
||||||
|
names, it gets what it expects (though of course, using fontconfig,
|
||||||
|
substitutions could still could have occurred during font
|
||||||
|
opening). You must include the Bitstream copyright. Additional
|
||||||
|
copyrights can be added, as per copyright law. Happy Font Hacking!
|
||||||
|
|
||||||
|
6. If I have improvements for Bitstream Vera, is it possible they might get
|
||||||
|
adopted in future versions?
|
||||||
|
|
||||||
|
Yes. The contract between the Gnome Foundation and Bitstream has
|
||||||
|
provisions for working with Bitstream to ensure quality additions to
|
||||||
|
the Bitstream Vera font family. Please contact us if you have such
|
||||||
|
additions. Note, that in general, we will want such additions for the
|
||||||
|
entire family, not just a single font, and that you'll have to keep
|
||||||
|
both Gnome and Jim Lyles, Vera's designer, happy! To make sense to add
|
||||||
|
glyphs to the font, they must be stylistically in keeping with Vera's
|
||||||
|
design. Vera cannot become a "ransom note" font. Jim Lyles will be
|
||||||
|
providing a document describing the design elements used in Vera, as a
|
||||||
|
guide and aid for people interested in contributing to Vera.
|
||||||
|
|
||||||
|
7. I want to sell a software package that uses these fonts: Can I do so?
|
||||||
|
|
||||||
|
Sure. Bundle the fonts with your software and sell your software
|
||||||
|
with the fonts. That is the intent of the copyright.
|
||||||
|
|
||||||
|
8. If applications have built the names "Bitstream Vera" into them,
|
||||||
|
can I override this somehow to use fonts of my choosing?
|
||||||
|
|
||||||
|
This depends on exact details of the software. Most open source
|
||||||
|
systems and software (e.g., Gnome, KDE, etc.) are now converting to
|
||||||
|
use fontconfig (see www.fontconfig.org) to handle font configuration,
|
||||||
|
selection and substitution; it has provisions for overriding font
|
||||||
|
names and subsituting alternatives. An example is provided by the
|
||||||
|
supplied local.conf file, which chooses the family Bitstream Vera for
|
||||||
|
"sans", "serif" and "monospace". Other software (e.g., the XFree86
|
||||||
|
core server) has other mechanisms for font substitution.
|
||||||
|
|
75
images/action.svg
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 4.2333332 4.2333335"
|
||||||
|
version="1.1"
|
||||||
|
id="svg8"
|
||||||
|
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
|
||||||
|
sodipodi:docname="action.svg">
|
||||||
|
<defs
|
||||||
|
id="defs2" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="22.4"
|
||||||
|
inkscape:cx="10.477362"
|
||||||
|
inkscape:cy="2.1937508"
|
||||||
|
inkscape:document-units="mm"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="1858"
|
||||||
|
inkscape:window-height="1057"
|
||||||
|
inkscape:window-x="54"
|
||||||
|
inkscape:window-y="-8"
|
||||||
|
inkscape:window-maximized="1">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid817" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata5">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Ebene 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-292.76665)">
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 1.3229167,293.03123 h 1.5875 l -0.79375,2.11667 z"
|
||||||
|
id="path4526"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccc" />
|
||||||
|
<ellipse
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.26458332;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="path4530"
|
||||||
|
cy="296.20624"
|
||||||
|
cx="2.1166666"
|
||||||
|
rx="0.26458323"
|
||||||
|
ry="0.26458779" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.3 KiB |
34
images/action.svg.import
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="StreamTexture"
|
||||||
|
path="res://.import/action.svg-b508461e00794f206592b7f3abb0bf50.stex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://addons/de.mewin.gduibasics/images/action.svg"
|
||||||
|
dest_files=[ "res://.import/action.svg-b508461e00794f206592b7f3abb0bf50.stex" ]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_mode=0
|
||||||
|
compress/bptc_ldr=0
|
||||||
|
compress/normal_map=0
|
||||||
|
flags/repeat=0
|
||||||
|
flags/filter=true
|
||||||
|
flags/mipmaps=false
|
||||||
|
flags/anisotropic=false
|
||||||
|
flags/srgb=2
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/HDR_as_SRGB=false
|
||||||
|
process/invert_color=false
|
||||||
|
stream=false
|
||||||
|
size_limit=0
|
||||||
|
detect_3d=true
|
||||||
|
svg/scale=1.0
|
68
images/close.svg
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 4.2333332 4.2333335"
|
||||||
|
version="1.1"
|
||||||
|
id="svg8"
|
||||||
|
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
|
||||||
|
sodipodi:docname="close.svg">
|
||||||
|
<defs
|
||||||
|
id="defs2" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="22.4"
|
||||||
|
inkscape:cx="-0.93119331"
|
||||||
|
inkscape:cy="10.469104"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="1858"
|
||||||
|
inkscape:window-height="1057"
|
||||||
|
inkscape:window-x="54"
|
||||||
|
inkscape:window-y="-8"
|
||||||
|
inkscape:window-maximized="1" />
|
||||||
|
<metadata
|
||||||
|
id="metadata5">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Ebene 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-292.76665)">
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:#ffffff;stroke-width:0.26458332;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 0.46597373,293.23262 3.30138587,3.30139"
|
||||||
|
id="path1916"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path1918"
|
||||||
|
d="m 3.7673596,293.23262 -3.30138587,3.30139"
|
||||||
|
style="fill:none;stroke:#ffffff;stroke-width:0.26458332;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.2 KiB |
34
images/close.svg.import
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="StreamTexture"
|
||||||
|
path="res://.import/close.svg-4a9c4498aff69d70db99b31f6d40ad26.stex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://addons/de.mewin.gduibasics/images/close.svg"
|
||||||
|
dest_files=[ "res://.import/close.svg-4a9c4498aff69d70db99b31f6d40ad26.stex" ]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_mode=0
|
||||||
|
compress/bptc_ldr=0
|
||||||
|
compress/normal_map=0
|
||||||
|
flags/repeat=0
|
||||||
|
flags/filter=true
|
||||||
|
flags/mipmaps=false
|
||||||
|
flags/anisotropic=false
|
||||||
|
flags/srgb=2
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/HDR_as_SRGB=false
|
||||||
|
process/invert_color=false
|
||||||
|
stream=false
|
||||||
|
size_limit=0
|
||||||
|
detect_3d=true
|
||||||
|
svg/scale=1.0
|
63
images/favourite.svg
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 4.2333332 4.2333335"
|
||||||
|
version="1.1"
|
||||||
|
id="svg8"
|
||||||
|
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
|
||||||
|
sodipodi:docname="favourite.svg">
|
||||||
|
<defs
|
||||||
|
id="defs2" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="44.8"
|
||||||
|
inkscape:cx="5.510791"
|
||||||
|
inkscape:cy="9.1171212"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="1858"
|
||||||
|
inkscape:window-height="1057"
|
||||||
|
inkscape:window-x="54"
|
||||||
|
inkscape:window-y="-8"
|
||||||
|
inkscape:window-maximized="1" />
|
||||||
|
<metadata
|
||||||
|
id="metadata5">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Ebene 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-292.76665)">
|
||||||
|
<path
|
||||||
|
style="fill:#ffb700;fill-opacity:1;stroke:none;stroke-width:0.40976673px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 0.98483543,296.65544 1.15770177,-0.58209 1.1577019,0.6209 -0.200496,-1.30646 0.9184004,-0.92486 -1.3064568,-0.22638 -0.5885522,-1.16416 -0.5626821,1.19003 -1.34526253,0.18756 0.94427083,0.91194 z"
|
||||||
|
id="path6774"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.0 KiB |
34
images/favourite.svg.import
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="StreamTexture"
|
||||||
|
path="res://.import/favourite.svg-e7f3ad202c86f3b36183a480a4c15217.stex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://addons/de.mewin.gduibasics/images/favourite.svg"
|
||||||
|
dest_files=[ "res://.import/favourite.svg-e7f3ad202c86f3b36183a480a4c15217.stex" ]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_mode=0
|
||||||
|
compress/bptc_ldr=0
|
||||||
|
compress/normal_map=0
|
||||||
|
flags/repeat=0
|
||||||
|
flags/filter=true
|
||||||
|
flags/mipmaps=false
|
||||||
|
flags/anisotropic=false
|
||||||
|
flags/srgb=2
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/HDR_as_SRGB=false
|
||||||
|
process/invert_color=false
|
||||||
|
stream=false
|
||||||
|
size_limit=0
|
||||||
|
detect_3d=true
|
||||||
|
svg/scale=1.0
|
63
images/favourite32.svg
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="32"
|
||||||
|
height="32"
|
||||||
|
viewBox="0 0 8.4666664 8.466667"
|
||||||
|
version="1.1"
|
||||||
|
id="svg8"
|
||||||
|
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
|
||||||
|
sodipodi:docname="favourite32.svg">
|
||||||
|
<defs
|
||||||
|
id="defs2" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="22.4"
|
||||||
|
inkscape:cx="1.2576623"
|
||||||
|
inkscape:cy="7.0007595"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="1858"
|
||||||
|
inkscape:window-height="1057"
|
||||||
|
inkscape:window-x="54"
|
||||||
|
inkscape:window-y="-8"
|
||||||
|
inkscape:window-maximized="1" />
|
||||||
|
<metadata
|
||||||
|
id="metadata5">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Ebene 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-288.53332)">
|
||||||
|
<path
|
||||||
|
style="fill:#ffb700;fill-opacity:1;stroke:none;stroke-width:0.81953347px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 1.9696708,296.31089 2.3154035,-1.16418 2.3154038,1.2418 -0.400992,-2.61292 1.8368008,-1.84972 -2.6129136,-0.45276 -1.1771044,-2.32832 -1.1253642,2.38006 -2.69052493,0.37512 1.88854163,1.82388 z"
|
||||||
|
id="path6774"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.0 KiB |
34
images/favourite32.svg.import
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="StreamTexture"
|
||||||
|
path="res://.import/favourite32.svg-c47e3f97bb8ca7f215e11bab06aac90a.stex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://addons/de.mewin.gduibasics/images/favourite32.svg"
|
||||||
|
dest_files=[ "res://.import/favourite32.svg-c47e3f97bb8ca7f215e11bab06aac90a.stex" ]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_mode=0
|
||||||
|
compress/bptc_ldr=0
|
||||||
|
compress/normal_map=0
|
||||||
|
flags/repeat=0
|
||||||
|
flags/filter=true
|
||||||
|
flags/mipmaps=false
|
||||||
|
flags/anisotropic=false
|
||||||
|
flags/srgb=2
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/HDR_as_SRGB=false
|
||||||
|
process/invert_color=false
|
||||||
|
stream=false
|
||||||
|
size_limit=0
|
||||||
|
detect_3d=true
|
||||||
|
svg/scale=1.0
|
63
images/favourite_inactive.svg
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 4.2333332 4.2333335"
|
||||||
|
version="1.1"
|
||||||
|
id="svg8"
|
||||||
|
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
|
||||||
|
sodipodi:docname="favourite_inactive.svg">
|
||||||
|
<defs
|
||||||
|
id="defs2" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="44.8"
|
||||||
|
inkscape:cx="5.510791"
|
||||||
|
inkscape:cy="9.1171212"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="1858"
|
||||||
|
inkscape:window-height="1057"
|
||||||
|
inkscape:window-x="54"
|
||||||
|
inkscape:window-y="-8"
|
||||||
|
inkscape:window-maximized="1" />
|
||||||
|
<metadata
|
||||||
|
id="metadata5">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Ebene 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-292.76665)">
|
||||||
|
<path
|
||||||
|
style="fill:#808080;fill-opacity:1;stroke:none;stroke-width:0.40976673px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 0.98483543,296.65544 1.15770177,-0.58209 1.1577019,0.6209 -0.200496,-1.30646 0.9184004,-0.92486 -1.3064568,-0.22638 -0.5885522,-1.16416 -0.5626821,1.19003 -1.34526253,0.18756 0.94427083,0.91194 z"
|
||||||
|
id="path6774"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.0 KiB |
34
images/favourite_inactive.svg.import
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="StreamTexture"
|
||||||
|
path="res://.import/favourite_inactive.svg-0714561913ff7c32510529fe22e8eec7.stex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://addons/de.mewin.gduibasics/images/favourite_inactive.svg"
|
||||||
|
dest_files=[ "res://.import/favourite_inactive.svg-0714561913ff7c32510529fe22e8eec7.stex" ]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_mode=0
|
||||||
|
compress/bptc_ldr=0
|
||||||
|
compress/normal_map=0
|
||||||
|
flags/repeat=0
|
||||||
|
flags/filter=true
|
||||||
|
flags/mipmaps=false
|
||||||
|
flags/anisotropic=false
|
||||||
|
flags/srgb=2
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/HDR_as_SRGB=false
|
||||||
|
process/invert_color=false
|
||||||
|
stream=false
|
||||||
|
size_limit=0
|
||||||
|
detect_3d=true
|
||||||
|
svg/scale=1.0
|
65
images/file.svg
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 4.2333332 4.2333335"
|
||||||
|
version="1.1"
|
||||||
|
id="svg1968"
|
||||||
|
sodipodi:docname="file.svg"
|
||||||
|
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
|
||||||
|
<defs
|
||||||
|
id="defs1962" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="11.313709"
|
||||||
|
inkscape:cx="5.1268212"
|
||||||
|
inkscape:cy="11.655659"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
units="px"
|
||||||
|
showguides="true"
|
||||||
|
inkscape:guide-bbox="true"
|
||||||
|
inkscape:window-width="1858"
|
||||||
|
inkscape:window-height="1057"
|
||||||
|
inkscape:window-x="54"
|
||||||
|
inkscape:window-y="-8"
|
||||||
|
inkscape:window-maximized="1" />
|
||||||
|
<metadata
|
||||||
|
id="metadata1965">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Ebene 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-292.76665)">
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.00157475;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="M 3.1875 1.4160156 L 3.1875 14.169922 L 12.753906 14.169922 L 12.753906 6.0429688 L 8.8046875 6.0429688 L 8.1582031 6.0429688 L 8.1582031 1.4160156 L 3.1875 1.4160156 z M 8.8046875 1.4160156 L 8.8046875 5.3945312 L 12.753906 5.3945312 L 8.8046875 1.4160156 z "
|
||||||
|
transform="matrix(0.26458333,0,0,0.26458333,0,292.76665)"
|
||||||
|
id="rect2533" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.2 KiB |
34
images/file.svg.import
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="StreamTexture"
|
||||||
|
path="res://.import/file.svg-4e6b8b924038da5cf70f0f5467754065.stex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://addons/de.mewin.gduibasics/images/file.svg"
|
||||||
|
dest_files=[ "res://.import/file.svg-4e6b8b924038da5cf70f0f5467754065.stex" ]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_mode=0
|
||||||
|
compress/bptc_ldr=0
|
||||||
|
compress/normal_map=0
|
||||||
|
flags/repeat=0
|
||||||
|
flags/filter=true
|
||||||
|
flags/mipmaps=false
|
||||||
|
flags/anisotropic=false
|
||||||
|
flags/srgb=2
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/HDR_as_SRGB=false
|
||||||
|
process/invert_color=false
|
||||||
|
stream=false
|
||||||
|
size_limit=0
|
||||||
|
detect_3d=true
|
||||||
|
svg/scale=1.0
|
66
images/folder.svg
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 4.2333332 4.2333335"
|
||||||
|
version="1.1"
|
||||||
|
id="svg882"
|
||||||
|
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
|
||||||
|
sodipodi:docname="folder.svg">
|
||||||
|
<defs
|
||||||
|
id="defs876" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="44.8"
|
||||||
|
inkscape:cx="3.6511197"
|
||||||
|
inkscape:cy="9.7572085"
|
||||||
|
inkscape:document-units="mm"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
units="px"
|
||||||
|
showguides="true"
|
||||||
|
inkscape:guide-bbox="true"
|
||||||
|
inkscape:window-width="1858"
|
||||||
|
inkscape:window-height="1057"
|
||||||
|
inkscape:window-x="54"
|
||||||
|
inkscape:window-y="-8"
|
||||||
|
inkscape:window-maximized="1" />
|
||||||
|
<metadata
|
||||||
|
id="metadata879">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Ebene 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-292.76665)">
|
||||||
|
<path
|
||||||
|
style="fill:#c9c9c9;fill-opacity:1;stroke:none;stroke-width:0.30309412px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 3.9399672,293.94715 v 2.19117 H 0.29336612 v -2.51 H 1.6261685 l 0.3231055,0.31883 z"
|
||||||
|
id="path1479"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccccc" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.0 KiB |
34
images/folder.svg.import
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="StreamTexture"
|
||||||
|
path="res://.import/folder.svg-7e8d363eac08897a3ba3577c7fe476ba.stex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://addons/de.mewin.gduibasics/images/folder.svg"
|
||||||
|
dest_files=[ "res://.import/folder.svg-7e8d363eac08897a3ba3577c7fe476ba.stex" ]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_mode=0
|
||||||
|
compress/bptc_ldr=0
|
||||||
|
compress/normal_map=0
|
||||||
|
flags/repeat=0
|
||||||
|
flags/filter=true
|
||||||
|
flags/mipmaps=false
|
||||||
|
flags/anisotropic=false
|
||||||
|
flags/srgb=2
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/HDR_as_SRGB=false
|
||||||
|
process/invert_color=false
|
||||||
|
stream=false
|
||||||
|
size_limit=0
|
||||||
|
detect_3d=true
|
||||||
|
svg/scale=1.0
|
66
images/folder32.svg
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="32"
|
||||||
|
height="32"
|
||||||
|
viewBox="0 0 8.4666664 8.466667"
|
||||||
|
version="1.1"
|
||||||
|
id="svg882"
|
||||||
|
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
|
||||||
|
sodipodi:docname="folder32.svg">
|
||||||
|
<defs
|
||||||
|
id="defs876" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="15.839192"
|
||||||
|
inkscape:cx="1.6150387"
|
||||||
|
inkscape:cy="3.5488619"
|
||||||
|
inkscape:document-units="mm"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
units="px"
|
||||||
|
showguides="true"
|
||||||
|
inkscape:guide-bbox="true"
|
||||||
|
inkscape:window-width="1858"
|
||||||
|
inkscape:window-height="1057"
|
||||||
|
inkscape:window-x="54"
|
||||||
|
inkscape:window-y="-8"
|
||||||
|
inkscape:window-maximized="1" />
|
||||||
|
<metadata
|
||||||
|
id="metadata879">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Ebene 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-288.53332)">
|
||||||
|
<path
|
||||||
|
style="fill:#c9c9c9;fill-opacity:1;stroke:none;stroke-width:0.60618824px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 7.8799344,290.89431 v 4.38234 H 0.58673228 v -5.02 H 3.252337 l 0.646211,0.63766 z"
|
||||||
|
id="path1479"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccccc" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.0 KiB |
34
images/folder32.svg.import
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="StreamTexture"
|
||||||
|
path="res://.import/folder32.svg-c88050110add556743258a22e5552a5f.stex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://addons/de.mewin.gduibasics/images/folder32.svg"
|
||||||
|
dest_files=[ "res://.import/folder32.svg-c88050110add556743258a22e5552a5f.stex" ]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_mode=0
|
||||||
|
compress/bptc_ldr=0
|
||||||
|
compress/normal_map=0
|
||||||
|
flags/repeat=0
|
||||||
|
flags/filter=true
|
||||||
|
flags/mipmaps=false
|
||||||
|
flags/anisotropic=false
|
||||||
|
flags/srgb=2
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/HDR_as_SRGB=false
|
||||||
|
process/invert_color=false
|
||||||
|
stream=false
|
||||||
|
size_limit=0
|
||||||
|
detect_3d=true
|
||||||
|
svg/scale=1.0
|
66
images/home32.svg
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="32"
|
||||||
|
height="32"
|
||||||
|
viewBox="0 0 8.4666665 8.466667"
|
||||||
|
version="1.1"
|
||||||
|
id="svg8"
|
||||||
|
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
|
||||||
|
sodipodi:docname="home32.svg">
|
||||||
|
<defs
|
||||||
|
id="defs2" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="4"
|
||||||
|
inkscape:cx="-20.16699"
|
||||||
|
inkscape:cy="-11.362214"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="1858"
|
||||||
|
inkscape:window-height="1057"
|
||||||
|
inkscape:window-x="54"
|
||||||
|
inkscape:window-y="-8"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
showguides="true"
|
||||||
|
inkscape:guide-bbox="true" />
|
||||||
|
<metadata
|
||||||
|
id="metadata5">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Ebene 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-288.53332)">
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.52916664px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 4.9524559,294.56066 v 1.89222 H 6.741491 v -3.74176 h 0.695736 l -3.2038933,-3.6307 -3.2038939,3.6307 H 1.725176 v 3.74176 h 1.7890355 v -1.89222 z"
|
||||||
|
id="path822"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccccccccccc" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.1 KiB |
34
images/home32.svg.import
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="StreamTexture"
|
||||||
|
path="res://.import/home32.svg-6a061fc9d14c6834c99c31a441f002f7.stex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://addons/de.mewin.gduibasics/images/home32.svg"
|
||||||
|
dest_files=[ "res://.import/home32.svg-6a061fc9d14c6834c99c31a441f002f7.stex" ]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_mode=0
|
||||||
|
compress/bptc_ldr=0
|
||||||
|
compress/normal_map=0
|
||||||
|
flags/repeat=0
|
||||||
|
flags/filter=true
|
||||||
|
flags/mipmaps=false
|
||||||
|
flags/anisotropic=false
|
||||||
|
flags/srgb=2
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/HDR_as_SRGB=false
|
||||||
|
process/invert_color=false
|
||||||
|
stream=false
|
||||||
|
size_limit=0
|
||||||
|
detect_3d=true
|
||||||
|
svg/scale=1.0
|
63
images/maximize.svg
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 4.2333332 4.2333335"
|
||||||
|
version="1.1"
|
||||||
|
id="svg8"
|
||||||
|
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
|
||||||
|
sodipodi:docname="maximize.svg">
|
||||||
|
<defs
|
||||||
|
id="defs2" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="31.678384"
|
||||||
|
inkscape:cx="3.2079517"
|
||||||
|
inkscape:cy="6.5159633"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="1858"
|
||||||
|
inkscape:window-height="1057"
|
||||||
|
inkscape:window-x="54"
|
||||||
|
inkscape:window-y="-8"
|
||||||
|
inkscape:window-maximized="1" />
|
||||||
|
<metadata
|
||||||
|
id="metadata5">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Ebene 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-292.76665)">
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.00157475;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="M 1.7910156 2.6953125 C 1.4587386 2.6953125 1.1914062 2.964598 1.1914062 3.296875 L 1.1914062 13.390625 C 1.1914062 13.722902 1.4587386 13.990234 1.7910156 13.990234 L 14.208984 13.990234 C 14.541261 13.990234 14.808594 13.722902 14.808594 13.390625 L 14.808594 3.296875 C 14.808594 2.964598 14.541261 2.6953125 14.208984 2.6953125 L 1.7910156 2.6953125 z M 2.484375 3.7675781 L 13.515625 3.7675781 L 13.515625 12.919922 L 2.484375 12.919922 L 2.484375 3.7675781 z "
|
||||||
|
transform="matrix(0.26458333,0,0,0.26458333,0,292.76665)"
|
||||||
|
id="rect814" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.3 KiB |
34
images/maximize.svg.import
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="StreamTexture"
|
||||||
|
path="res://.import/maximize.svg-3fa9bb18e25e21cc6b72c8baa93b174b.stex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://addons/de.mewin.gduibasics/images/maximize.svg"
|
||||||
|
dest_files=[ "res://.import/maximize.svg-3fa9bb18e25e21cc6b72c8baa93b174b.stex" ]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_mode=0
|
||||||
|
compress/bptc_ldr=0
|
||||||
|
compress/normal_map=0
|
||||||
|
flags/repeat=0
|
||||||
|
flags/filter=true
|
||||||
|
flags/mipmaps=false
|
||||||
|
flags/anisotropic=false
|
||||||
|
flags/srgb=2
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/HDR_as_SRGB=false
|
||||||
|
process/invert_color=false
|
||||||
|
stream=false
|
||||||
|
size_limit=0
|
||||||
|
detect_3d=true
|
||||||
|
svg/scale=1.0
|
67
images/minimize.svg
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 4.2333332 4.2333335"
|
||||||
|
version="1.1"
|
||||||
|
id="svg8"
|
||||||
|
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
|
||||||
|
sodipodi:docname="minimize.svg">
|
||||||
|
<defs
|
||||||
|
id="defs2" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="22.4"
|
||||||
|
inkscape:cx="1.9193787"
|
||||||
|
inkscape:cy="6.0832447"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="1858"
|
||||||
|
inkscape:window-height="1057"
|
||||||
|
inkscape:window-x="54"
|
||||||
|
inkscape:window-y="-8"
|
||||||
|
inkscape:window-maximized="1" />
|
||||||
|
<metadata
|
||||||
|
id="metadata5">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Ebene 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-292.76665)">
|
||||||
|
<rect
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.26499999;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="rect814"
|
||||||
|
width="3.6025856"
|
||||||
|
height="0.72051716"
|
||||||
|
x="0.3153739"
|
||||||
|
y="295.74792"
|
||||||
|
rx="0.15869126"
|
||||||
|
ry="0.15869126" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.9 KiB |
34
images/minimize.svg.import
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="StreamTexture"
|
||||||
|
path="res://.import/minimize.svg-79dc3404e073f085703d8b02fd39b093.stex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://addons/de.mewin.gduibasics/images/minimize.svg"
|
||||||
|
dest_files=[ "res://.import/minimize.svg-79dc3404e073f085703d8b02fd39b093.stex" ]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_mode=0
|
||||||
|
compress/bptc_ldr=0
|
||||||
|
compress/normal_map=0
|
||||||
|
flags/repeat=0
|
||||||
|
flags/filter=true
|
||||||
|
flags/mipmaps=false
|
||||||
|
flags/anisotropic=false
|
||||||
|
flags/srgb=2
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/HDR_as_SRGB=false
|
||||||
|
process/invert_color=false
|
||||||
|
stream=false
|
||||||
|
size_limit=0
|
||||||
|
detect_3d=true
|
||||||
|
svg/scale=1.0
|
7
plugin.cfg
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
[plugin]
|
||||||
|
|
||||||
|
name="GDScript UI Basics"
|
||||||
|
description="Basic and advanced UI elements for Godot. (Requires GDBasics)"
|
||||||
|
author="Patrick Wuttke<mewin@mewin.de>"
|
||||||
|
version="0.1"
|
||||||
|
script="plugin.gd"
|
8
plugin.gd
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
tool
|
||||||
|
extends EditorPlugin
|
||||||
|
|
||||||
|
func _enter_tree():
|
||||||
|
pass
|
||||||
|
|
||||||
|
func _exit_tree():
|
||||||
|
pass
|
22
scenes/dynamic_tabs.tscn
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
[gd_scene load_steps=2 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://addons/de.mewin.gduibasics/scenes/scripts/dynamic_tabs.gd" type="Script" id=1]
|
||||||
|
|
||||||
|
[node name="dynamic_tabs" type="VBoxContainer"]
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
script = ExtResource( 1 )
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="tabs" type="Tabs" parent="."]
|
||||||
|
margin_right = 1024.0
|
||||||
|
margin_bottom = 24.0
|
||||||
|
|
||||||
|
[node name="container" type="TabContainer" parent="."]
|
||||||
|
margin_top = 28.0
|
||||||
|
margin_right = 1024.0
|
||||||
|
margin_bottom = 600.0
|
||||||
|
size_flags_vertical = 3
|
||||||
|
tabs_visible = false
|
32
scenes/editor_file_edit.tscn
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
[gd_scene load_steps=2 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://addons/de.mewin.gduibasics/scenes/scripts/editor_file_edit.gd" type="Script" id=1]
|
||||||
|
|
||||||
|
[node name="editor_file_edit" type="HBoxContainer"]
|
||||||
|
anchor_right = 1.0
|
||||||
|
margin_bottom = 24.0
|
||||||
|
script = ExtResource( 1 )
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="line_edit" type="LineEdit" parent="."]
|
||||||
|
margin_right = 969.0
|
||||||
|
margin_bottom = 24.0
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
size_flags_vertical = 0
|
||||||
|
editable = false
|
||||||
|
|
||||||
|
[node name="button" type="Button" parent="."]
|
||||||
|
margin_left = 973.0
|
||||||
|
margin_right = 1024.0
|
||||||
|
margin_bottom = 24.0
|
||||||
|
text = "Select"
|
||||||
|
|
||||||
|
[node name="file_dialog" type="FileDialog" parent="."]
|
||||||
|
margin_right = 307.0
|
||||||
|
margin_bottom = 130.0
|
||||||
|
window_title = "Open a File"
|
||||||
|
mode = 0
|
||||||
|
[connection signal="pressed" from="button" to="." method="_on_button_pressed"]
|
||||||
|
[connection signal="file_selected" from="file_dialog" to="." method="_on_file_dialog_file_selected"]
|
36
scenes/editor_node_edit.tscn
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
[gd_scene load_steps=3 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://addons/de.mewin.gduibasics/scenes/scripts/editor_node_edit.gd" type="Script" id=1]
|
||||||
|
[ext_resource path="res://addons/de.mewin.gduibasics/scenes/node_selection_dialog.tscn" type="PackedScene" id=2]
|
||||||
|
|
||||||
|
[node name="editor_node_edit" type="HBoxContainer"]
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
margin_bottom = -576.0
|
||||||
|
script = ExtResource( 1 )
|
||||||
|
__meta__ = {
|
||||||
|
"__property_type__": 15,
|
||||||
|
"_edit_use_anchors_": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="line_edit" type="LineEdit" parent="."]
|
||||||
|
margin_right = 969.0
|
||||||
|
margin_bottom = 24.0
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
size_flags_vertical = 0
|
||||||
|
editable = false
|
||||||
|
|
||||||
|
[node name="button" type="Button" parent="."]
|
||||||
|
margin_left = 973.0
|
||||||
|
margin_right = 1024.0
|
||||||
|
margin_bottom = 24.0
|
||||||
|
text = "Select"
|
||||||
|
|
||||||
|
[node name="node_selection_dialog" parent="." instance=ExtResource( 2 )]
|
||||||
|
margin_left = 824.0
|
||||||
|
margin_top = 0.0
|
||||||
|
margin_right = 1024.0
|
||||||
|
margin_bottom = 70.0
|
||||||
|
window_title = "Select a Node ..."
|
||||||
|
[connection signal="pressed" from="button" to="." method="_on_button_pressed"]
|
||||||
|
[connection signal="confirmed" from="node_selection_dialog" to="." method="_on_node_selection_dialog_confirmed"]
|
97
scenes/flexview.tscn
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
[gd_scene load_steps=4 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://addons/de.mewin.gduibasics/scenes/dynamic_tabs.tscn" type="PackedScene" id=1]
|
||||||
|
[ext_resource path="res://addons/de.mewin.gduibasics/scenes/scripts/flexview.gd" type="Script" id=2]
|
||||||
|
|
||||||
|
[sub_resource type="StyleBoxFlat" id=1]
|
||||||
|
bg_color = Color( 0, 0.388235, 1, 0.705882 )
|
||||||
|
border_width_left = 5
|
||||||
|
border_width_top = 5
|
||||||
|
border_width_right = 5
|
||||||
|
border_width_bottom = 5
|
||||||
|
border_color = Color( 0, 0.301961, 0.796078, 0.705882 )
|
||||||
|
border_blend = true
|
||||||
|
|
||||||
|
[node name="flex_view" type="Control"]
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
script = ExtResource( 2 )
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="tabs" parent="." instance=ExtResource( 1 )]
|
||||||
|
drag_to_rearrange_enabled = true
|
||||||
|
drag_out_enabled = true
|
||||||
|
tab_close_display_policy = 2
|
||||||
|
tab_align = 0
|
||||||
|
|
||||||
|
[node name="drop_indicator" type="Control" parent="."]
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
mouse_filter = 2
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="rect_left" type="Control" parent="drop_indicator"]
|
||||||
|
visible = false
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": true
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="rect_right" type="Control" parent="drop_indicator"]
|
||||||
|
visible = false
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_right = 1.00098
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": true
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="rect_top" type="Control" parent="drop_indicator"]
|
||||||
|
visible = false
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": true
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="rect_bottom" type="Control" parent="drop_indicator"]
|
||||||
|
visible = false
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": true
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="rect_center" type="Control" parent="drop_indicator"]
|
||||||
|
visible = false
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
margin_left = 200.0
|
||||||
|
margin_top = 117.0
|
||||||
|
margin_right = -200.0
|
||||||
|
margin_bottom = -117.0
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": true
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="drop_indicator" type="Panel" parent="drop_indicator"]
|
||||||
|
visible = false
|
||||||
|
modulate = Color( 1, 1, 1, 0 )
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
mouse_filter = 2
|
||||||
|
custom_styles/panel = SubResource( 1 )
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="tween" type="Tween" parent="drop_indicator"]
|
||||||
|
|
||||||
|
[connection signal="tab_close" from="tabs" to="." method="_on_tabs_tab_close"]
|
||||||
|
[connection signal="tab_dragged_out" from="tabs" to="." method="_on_tabs_tab_dragged_out"]
|
11
scenes/flexview_hspliter.tscn
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
[gd_scene load_steps=2 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://addons/de.mewin.gduibasics/scenes/scripts/flexview_splitter.gd" type="Script" id=1]
|
||||||
|
|
||||||
|
[node name="flexview_hsplitter" type="HSplitContainer"]
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
script = ExtResource( 1 )
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": false
|
||||||
|
}
|
8
scenes/flexview_vspliter.tscn
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
[gd_scene load_steps=2 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://addons/de.mewin.gduibasics/scenes/scripts/flexview_splitter.gd" type="Script" id=1]
|
||||||
|
|
||||||
|
[node name="flexview_hsplitter" type="VSplitContainer"]
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
script = ExtResource( 1 )
|
21
scenes/flexview_window.tscn
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
[gd_scene load_steps=3 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://addons/de.mewin.gduibasics/scenes/flexview.tscn" type="PackedScene" id=1]
|
||||||
|
[ext_resource path="res://addons/de.mewin.gduibasics/scenes/scripts/flexview_window.gd" type="Script" id=2]
|
||||||
|
|
||||||
|
[node name="flexview_window" type="WindowDialog"]
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
resizable = true
|
||||||
|
script = ExtResource( 2 )
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="flex_view" parent="." instance=ExtResource( 1 )]
|
||||||
|
|
||||||
|
[connection signal="item_rect_changed" from="." to="." method="_on_flexview_window_item_rect_changed"]
|
||||||
|
[connection signal="visibility_changed" from="." to="." method="_on_flexview_window_visibility_changed"]
|
||||||
|
[connection signal="current_view_changed" from="flex_view" to="." method="_on_flex_view_current_view_changed"]
|
||||||
|
[connection signal="view_added" from="flex_view" to="." method="_on_flex_view_view_added"]
|
||||||
|
[connection signal="view_removed" from="flex_view" to="." method="_on_flex_view_view_removed"]
|
27
scenes/line_edit_suggestion_popup.tscn
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
[gd_scene load_steps=2 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://addons/de.mewin.gduibasics/scenes/scripts/line_edit_suggestion_popup.gd" type="Script" id=1]
|
||||||
|
|
||||||
|
|
||||||
|
[node name="line_edit_suggestion_popup" type="Popup"]
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
rect_min_size = Vector2( 0, 100 )
|
||||||
|
script = ExtResource( 1 )
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="panel" type="Panel" parent="."]
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="v_box_container" type="VBoxContainer" parent="panel"]
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": false
|
||||||
|
}
|
51
scenes/line_input_dialog.tscn
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
[gd_scene load_steps=2 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://addons/de.mewin.gduibasics/scenes/scripts/line_input_dialog.gd" type="Script" id=1]
|
||||||
|
|
||||||
|
[node name="line_input_dialog" type="ConfirmationDialog"]
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
margin_right = -524.0
|
||||||
|
margin_bottom = -499.0
|
||||||
|
rect_min_size = Vector2( 500, 90 )
|
||||||
|
window_title = "Enter a text..."
|
||||||
|
dialog_text = "Enter a text:"
|
||||||
|
script = ExtResource( 1 )
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="container" type="VBoxContainer" parent="."]
|
||||||
|
margin_left = 8.0
|
||||||
|
margin_top = 22.0
|
||||||
|
margin_right = 492.0
|
||||||
|
margin_bottom = 79.0
|
||||||
|
mouse_filter = 2
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="control" type="Control" parent="container"]
|
||||||
|
margin_right = 484.0
|
||||||
|
margin_bottom = 5.0
|
||||||
|
rect_min_size = Vector2( 0, 5 )
|
||||||
|
|
||||||
|
[node name="line_edit" type="LineEdit" parent="container"]
|
||||||
|
margin_top = 9.0
|
||||||
|
margin_right = 484.0
|
||||||
|
margin_bottom = 33.0
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="control2" type="Control" parent="container"]
|
||||||
|
margin_top = 37.0
|
||||||
|
margin_right = 484.0
|
||||||
|
margin_bottom = 57.0
|
||||||
|
rect_min_size = Vector2( 0, 20 )
|
||||||
|
mouse_filter = 2
|
||||||
|
[connection signal="about_to_show" from="." to="." method="_on_line_input_dialog_about_to_show"]
|
||||||
|
[connection signal="visibility_changed" from="." to="." method="_on_line_input_dialog_visibility_changed"]
|
||||||
|
[connection signal="text_changed" from="container/line_edit" to="." method="_on_line_edit_text_changed"]
|
||||||
|
[connection signal="text_entered" from="container/line_edit" to="." method="_on_line_edit_text_entered"]
|
26
scenes/node_selection_dialog.tscn
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
[gd_scene load_steps=3 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://addons/de.mewin.gduibasics/scripts/types/controls/editor_node_tree.gd" type="Script" id=1]
|
||||||
|
[ext_resource path="res://addons/de.mewin.gduibasics/scenes/scripts/node_selection_dialog.gd" type="Script" id=2]
|
||||||
|
|
||||||
|
[node name="node_selection_dialog" type="ConfirmationDialog"]
|
||||||
|
margin_left = 233.0
|
||||||
|
margin_top = 45.0
|
||||||
|
margin_right = 843.0
|
||||||
|
margin_bottom = 516.0
|
||||||
|
script = ExtResource( 2 )
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="tree" type="Tree" parent="."]
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
margin_left = 8.0
|
||||||
|
margin_top = 8.0
|
||||||
|
margin_right = -8.0
|
||||||
|
margin_bottom = -36.0
|
||||||
|
script = ExtResource( 1 )
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": false
|
||||||
|
}
|
174
scenes/scripts/dynamic_tabs.gd
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
extends Control
|
||||||
|
|
||||||
|
enum CloseButtonPolicy {
|
||||||
|
SHOW_NEVER = 0,
|
||||||
|
SHOW_ACTIVE_ONLY = 1,
|
||||||
|
SHOW_ALWAYS = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
enum TabAlign {
|
||||||
|
ALIGN_LEFT = 0,
|
||||||
|
ALIGN_CENTER = 1,
|
||||||
|
ALIGN_RIGHT = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
export var current_tab := 0 setget _set_current_tab, _get_current_tab
|
||||||
|
export var drag_to_rearrange_enabled := false setget _set_drag_to_rearrange_enabled
|
||||||
|
export var drag_out_enabled := false
|
||||||
|
export var show_tabs := true setget _set_show_tabs
|
||||||
|
export(CloseButtonPolicy) var tab_close_display_policy := CloseButtonPolicy.SHOW_NEVER setget _set_tab_close_display_policy
|
||||||
|
export(TabAlign) var tab_align := TabAlign.ALIGN_CENTER setget _set_tab_align
|
||||||
|
|
||||||
|
var __mouse_was_inside := false
|
||||||
|
|
||||||
|
#############
|
||||||
|
# overrides #
|
||||||
|
#############
|
||||||
|
func _ready() -> void:
|
||||||
|
$tabs.connect("tab_changed", self, "_on_tabs_tab_changed")
|
||||||
|
$tabs.connect("tab_close", self, "_on_tabs_tab_close")
|
||||||
|
$tabs.connect("reposition_active_tab_request", self, "_on_tabs_reposition_active_tab_request")
|
||||||
|
$tabs.connect("gui_input", self, "_on_tabs_gui_input")
|
||||||
|
|
||||||
|
set_process(false) # only enabled for dragging
|
||||||
|
|
||||||
|
func _process(delta : float) -> void:
|
||||||
|
if !Input.is_mouse_button_pressed(BUTTON_LEFT):
|
||||||
|
__stop_tab_dragging()
|
||||||
|
return
|
||||||
|
var mouse_pos := get_viewport().get_mouse_position()
|
||||||
|
var mouse_is_inside : bool = $tabs.get_global_rect().has_point(mouse_pos)
|
||||||
|
if mouse_is_inside == __mouse_was_inside:
|
||||||
|
return
|
||||||
|
__mouse_was_inside = mouse_is_inside
|
||||||
|
if mouse_is_inside:
|
||||||
|
emit_signal("tab_dragged_in", _get_current_tab(), mouse_pos)
|
||||||
|
else:
|
||||||
|
emit_signal("tab_dragged_out", _get_current_tab(), mouse_pos)
|
||||||
|
|
||||||
|
################
|
||||||
|
# public stuff #
|
||||||
|
################
|
||||||
|
func add_tab(title : String, control : Control, icon : Texture = null) -> int:
|
||||||
|
$tabs.add_tab(title, icon)
|
||||||
|
$container.add_child(control)
|
||||||
|
|
||||||
|
var tab := control.get_position_in_parent()
|
||||||
|
emit_signal("tab_added", tab)
|
||||||
|
return tab
|
||||||
|
|
||||||
|
func move_tab(from : int, to : int) -> void:
|
||||||
|
$tabs.move_tab(from, to)
|
||||||
|
$container.move_child($container.get_child(from), to)
|
||||||
|
|
||||||
|
func remove_tab(tab : int) -> void:
|
||||||
|
if tab == current_tab && __is_tab_dragging():
|
||||||
|
__stop_tab_dragging()
|
||||||
|
|
||||||
|
$tabs.remove_tab(tab)
|
||||||
|
$container.remove_child($container.get_child(tab))
|
||||||
|
emit_signal("tab_removed", tab)
|
||||||
|
|
||||||
|
func find_tab(control : Control) -> int:
|
||||||
|
for tab in range(get_tab_count()):
|
||||||
|
if get_tab_control(tab) == control:
|
||||||
|
return tab
|
||||||
|
return -1
|
||||||
|
|
||||||
|
func remove_all_tabs() -> void:
|
||||||
|
while $tabs.get_tab_count() > 0:
|
||||||
|
$tabs.remove_tab(0)
|
||||||
|
while $container.get_child_count() > 0:
|
||||||
|
$container.remove_child($container.get_child(0))
|
||||||
|
|
||||||
|
func get_tab_control(tab : int) -> Control:
|
||||||
|
return $container.get_tab_control(tab)
|
||||||
|
|
||||||
|
func get_tab_title(tab : int) -> String:
|
||||||
|
return $tabs.get_tab_title(tab)
|
||||||
|
|
||||||
|
func get_tabs() -> Array:
|
||||||
|
return $container.get_children()
|
||||||
|
|
||||||
|
func get_tab_count() -> int:
|
||||||
|
return $container.get_child_count()
|
||||||
|
|
||||||
|
func get_tab_rect(tab : int) -> Rect2:
|
||||||
|
var rect : Rect2 = $tabs.get_tab_rect(tab)
|
||||||
|
return $tabs.get_transform().xform_inv(rect)
|
||||||
|
|
||||||
|
#################
|
||||||
|
# private stuff #
|
||||||
|
#################
|
||||||
|
func __handle_tabs_gui_input(event : InputEvent) -> void:
|
||||||
|
if drag_out_enabled \
|
||||||
|
&& event is InputEventMouseButton \
|
||||||
|
&& event.pressed \
|
||||||
|
&& event.button_index == BUTTON_LEFT:
|
||||||
|
yield(get_tree(), "idle_frame") # wait for the original control to handle the input
|
||||||
|
|
||||||
|
var tab_rect : Rect2 = $tabs.get_tab_rect(_get_current_tab())
|
||||||
|
if tab_rect.has_point(event.position):
|
||||||
|
__start_tab_dragging()
|
||||||
|
|
||||||
|
func __start_tab_dragging() -> void:
|
||||||
|
__mouse_was_inside = true
|
||||||
|
set_process(true)
|
||||||
|
|
||||||
|
func __stop_tab_dragging() -> void:
|
||||||
|
set_process(false)
|
||||||
|
|
||||||
|
func __is_tab_dragging() -> bool:
|
||||||
|
return is_processing()
|
||||||
|
|
||||||
|
###########
|
||||||
|
# setters #
|
||||||
|
###########
|
||||||
|
func _set_current_tab(tab : int) -> void:
|
||||||
|
current_tab = tab
|
||||||
|
$tabs.current_tab = current_tab
|
||||||
|
|
||||||
|
func _get_current_tab() -> int:
|
||||||
|
return $tabs.current_tab
|
||||||
|
|
||||||
|
func _set_drag_to_rearrange_enabled(enabled : bool) -> void:
|
||||||
|
drag_to_rearrange_enabled = enabled
|
||||||
|
$tabs.drag_to_rearrange_enabled = enabled
|
||||||
|
|
||||||
|
func _set_tab_close_display_policy(policy : int) -> void:
|
||||||
|
tab_close_display_policy = policy
|
||||||
|
$tabs.tab_close_display_policy = policy
|
||||||
|
|
||||||
|
func _set_tab_align(align : int) -> void:
|
||||||
|
tab_align = align
|
||||||
|
$tabs.tab_align = align
|
||||||
|
|
||||||
|
func _set_show_tabs(show : bool) -> void:
|
||||||
|
show_tabs = show
|
||||||
|
$tabs.visible = show
|
||||||
|
|
||||||
|
###################
|
||||||
|
# signal handlers #
|
||||||
|
###################
|
||||||
|
func _on_tabs_tab_changed(tab : int) -> void:
|
||||||
|
current_tab = tab
|
||||||
|
$container.current_tab = tab
|
||||||
|
|
||||||
|
func _on_tabs_tab_close(tab : int) -> void:
|
||||||
|
emit_signal("tab_close", tab)
|
||||||
|
|
||||||
|
func _on_tabs_reposition_active_tab_request(to : int) -> void:
|
||||||
|
$container.move_child($container.get_child(_get_current_tab()), to)
|
||||||
|
current_tab = to
|
||||||
|
|
||||||
|
func _on_tabs_gui_input(event : InputEvent) -> void:
|
||||||
|
__handle_tabs_gui_input(event)
|
||||||
|
|
||||||
|
###########
|
||||||
|
# signals #
|
||||||
|
###########
|
||||||
|
signal tab_added(tab)
|
||||||
|
signal tab_removed(tab)
|
||||||
|
signal tab_close(tab)
|
||||||
|
signal tab_dragged_out(tab, position)
|
||||||
|
signal tab_dragged_in(tab, position)
|
31
scenes/scripts/editor_file_edit.gd
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
tool
|
||||||
|
extends Control
|
||||||
|
|
||||||
|
onready var line_edit := $line_edit
|
||||||
|
onready var button := $button
|
||||||
|
onready var file_dialog := $file_dialog
|
||||||
|
|
||||||
|
export(String, FILE) var selected_file setget _set_selected_file
|
||||||
|
var file_filter = ""
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
line_edit.text = selected_file
|
||||||
|
|
||||||
|
func _set_selected_file(value : String):
|
||||||
|
if value != selected_file:
|
||||||
|
selected_file = value
|
||||||
|
if line_edit:
|
||||||
|
line_edit.text = selected_file
|
||||||
|
|
||||||
|
func _on_button_pressed():
|
||||||
|
file_dialog.clear_filters()
|
||||||
|
file_dialog.add_filter(file_filter)
|
||||||
|
file_dialog.filename = selected_file
|
||||||
|
file_dialog.popup_centered_ratio(0.5)
|
||||||
|
|
||||||
|
func _on_file_dialog_file_selected(path : String):
|
||||||
|
if path != selected_file:
|
||||||
|
_set_selected_file(path)
|
||||||
|
emit_signal("selected_file_changed")
|
||||||
|
|
||||||
|
signal selected_file_changed()
|
31
scenes/scripts/editor_node_edit.gd
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
tool
|
||||||
|
extends Control
|
||||||
|
|
||||||
|
onready var line_edit := $line_edit
|
||||||
|
onready var button := $button
|
||||||
|
onready var node_selection_dialog := $node_selection_dialog
|
||||||
|
|
||||||
|
export(NodePath) var selected_node setget _set_selected_node
|
||||||
|
var node_type_filter = Node
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
line_edit.text = str(selected_node)
|
||||||
|
|
||||||
|
func _set_selected_node(value : NodePath):
|
||||||
|
if value != selected_node:
|
||||||
|
selected_node = value
|
||||||
|
if line_edit:
|
||||||
|
line_edit.text = str(selected_node)
|
||||||
|
|
||||||
|
func _on_button_pressed():
|
||||||
|
node_selection_dialog.get_editor_node_tree().node_type_filter = node_type_filter
|
||||||
|
node_selection_dialog.get_editor_node_tree().selected_node = selected_node
|
||||||
|
node_selection_dialog.popup_centered_ratio(0.5)
|
||||||
|
|
||||||
|
func _on_node_selection_dialog_confirmed():
|
||||||
|
var tree = node_selection_dialog.get_editor_node_tree()
|
||||||
|
if tree.selected_node != selected_node:
|
||||||
|
_set_selected_node(tree.selected_node)
|
||||||
|
emit_signal("selected_node_changed")
|
||||||
|
|
||||||
|
signal selected_node_changed()
|
371
scenes/scripts/flexview.gd
Normal file
@ -0,0 +1,371 @@
|
|||||||
|
extends Control
|
||||||
|
|
||||||
|
enum SplitLocation {
|
||||||
|
TOP,
|
||||||
|
BOTTOM,
|
||||||
|
LEFT,
|
||||||
|
RIGHT
|
||||||
|
}
|
||||||
|
enum DropPosition {
|
||||||
|
TOP,
|
||||||
|
BOTTOM,
|
||||||
|
LEFT,
|
||||||
|
RIGHT,
|
||||||
|
CENTER
|
||||||
|
}
|
||||||
|
|
||||||
|
const FlexViewSplitter = preload("res://addons/de.mewin.gduibasics/scenes/scripts/flexview_splitter.gd")
|
||||||
|
|
||||||
|
const META_UNIQUE_TYPE = "__flexview_unique_type__"
|
||||||
|
const META_UNIQUE_KEY = "__flexview_unique_key__"
|
||||||
|
const META_VIEW_TITLE = "__flexview_title__"
|
||||||
|
const META_LAST_DROP_TARGET = "__flexview_last_drop_target__"
|
||||||
|
const GROUP_NAME = "__flexview__"
|
||||||
|
const INDICATOR_ANIM_DURATION = 0.1
|
||||||
|
const __HANDLERS_TO_COPY = ["view_added", "view_removed", "view_closing"]
|
||||||
|
|
||||||
|
onready var _rect_left := $drop_indicator/rect_left
|
||||||
|
onready var _rect_right := $drop_indicator/rect_right
|
||||||
|
onready var _rect_top := $drop_indicator/rect_top
|
||||||
|
onready var _rect_bottom := $drop_indicator/rect_bottom
|
||||||
|
onready var _rect_center := $drop_indicator/rect_center
|
||||||
|
onready var _drop_indicator := $drop_indicator/drop_indicator
|
||||||
|
onready var _tween := $drop_indicator/tween
|
||||||
|
|
||||||
|
var current_view := 0 setget _set_current_view, _get_current_view
|
||||||
|
export var show_tabs := true setget _set_show_tabs
|
||||||
|
|
||||||
|
var __drop_position := -1
|
||||||
|
|
||||||
|
#############
|
||||||
|
# overrides #
|
||||||
|
#############
|
||||||
|
func _ready() -> void:
|
||||||
|
set_process(false) # only used for the drop indicator
|
||||||
|
add_to_group(GROUP_NAME)
|
||||||
|
$tabs.show_tabs = show_tabs
|
||||||
|
|
||||||
|
func _process(delta : float) -> void:
|
||||||
|
var mouse_pos := get_viewport().get_mouse_position()
|
||||||
|
var drop_position : int = DropPosition.CENTER
|
||||||
|
|
||||||
|
if get_view_count() > 0: # only allow splitting if there is at least one view
|
||||||
|
var my_rect := get_global_rect()
|
||||||
|
var distances := [
|
||||||
|
(mouse_pos.y - my_rect.position.y) / my_rect.size.y,
|
||||||
|
(my_rect.position.y + my_rect.size.y - mouse_pos.y) / my_rect.size.y,
|
||||||
|
(mouse_pos.x - my_rect.position.x) / my_rect.size.x,
|
||||||
|
(my_rect.position.x + my_rect.size.x - mouse_pos.x) / my_rect.size.x
|
||||||
|
]
|
||||||
|
var idx := GDBMath.min_element(distances)
|
||||||
|
if distances[idx] < 0.25:
|
||||||
|
drop_position = idx
|
||||||
|
|
||||||
|
if __drop_position == drop_position:
|
||||||
|
return
|
||||||
|
__drop_position = drop_position
|
||||||
|
|
||||||
|
var new_rect := __get_drop_rect(drop_position)
|
||||||
|
_tween.stop(_drop_indicator, "rect_size")
|
||||||
|
_tween.stop(_drop_indicator, "rect_position")
|
||||||
|
_tween.interpolate_property(_drop_indicator, "rect_size", _drop_indicator.rect_size, new_rect.size, INDICATOR_ANIM_DURATION)
|
||||||
|
_tween.interpolate_property(_drop_indicator, "rect_position", _drop_indicator.rect_position, new_rect.position, INDICATOR_ANIM_DURATION)
|
||||||
|
_tween.start()
|
||||||
|
|
||||||
|
################
|
||||||
|
# public stuff #
|
||||||
|
################
|
||||||
|
func add_view(title : String, control : Control, make_current := true) -> int:
|
||||||
|
control.set_meta(META_VIEW_TITLE, title)
|
||||||
|
|
||||||
|
var view : int = $tabs.add_tab(get_view_title_from_control(control), control)
|
||||||
|
emit_signal("view_added", view, self)
|
||||||
|
if make_current:
|
||||||
|
_set_current_view(view)
|
||||||
|
|
||||||
|
# support for control-controlled (lel) titles
|
||||||
|
if control.has_signal("flexview_title_changed"):
|
||||||
|
control.connect("flexview_title_changed", self, "_on_flexview_title_changed")
|
||||||
|
if control.has_signal("flexview_close_me"):
|
||||||
|
control.connect("flexview_close_me", self, "_on_flexview_close_me")
|
||||||
|
|
||||||
|
return view
|
||||||
|
|
||||||
|
func remove_view(view : int) -> void:
|
||||||
|
var control := get_view_control(view)
|
||||||
|
if control:
|
||||||
|
GDBUtility.disconnect_all(control, self)
|
||||||
|
|
||||||
|
$tabs.remove_tab(view)
|
||||||
|
emit_signal("view_removed", view, self)
|
||||||
|
|
||||||
|
if get_view_count() == 0 && get_parent() is FlexViewSplitter:
|
||||||
|
self.queue_free()
|
||||||
|
|
||||||
|
func close_view(view : int) -> void:
|
||||||
|
emit_signal("view_closing", view, self)
|
||||||
|
|
||||||
|
func remove_all_views() -> void:
|
||||||
|
for view in range(get_view_count() - 1, -1, -1):
|
||||||
|
remove_view(view)
|
||||||
|
|
||||||
|
func find_view(control : Control) -> int:
|
||||||
|
return $tabs.find_tab(control)
|
||||||
|
|
||||||
|
func close_all_views() -> void:
|
||||||
|
for view in range(get_view_count() - 1, -1, -1):
|
||||||
|
close_view(view)
|
||||||
|
|
||||||
|
func set_view_title(view : int, title : String) -> void:
|
||||||
|
$tabs.set_tab_title(view, title)
|
||||||
|
|
||||||
|
func get_view_control(view : int) -> Control:
|
||||||
|
return $tabs.get_tab_control(view)
|
||||||
|
|
||||||
|
func get_view_title(view : int) -> String:
|
||||||
|
return $tabs.get_tab_title(view)
|
||||||
|
|
||||||
|
func get_views() -> Array:
|
||||||
|
return $tabs.get_tabs()
|
||||||
|
|
||||||
|
func get_view_count() -> int:
|
||||||
|
return $tabs.get_tab_count()
|
||||||
|
|
||||||
|
func split_view(placement : int, title : String, view : Control) -> Control:
|
||||||
|
var parent := get_parent()
|
||||||
|
var self_first : bool = (placement == SplitLocation.BOTTOM || placement == SplitLocation.RIGHT)
|
||||||
|
|
||||||
|
# add splitter
|
||||||
|
var splitter : SplitContainer
|
||||||
|
if placement == SplitLocation.TOP || placement == SplitLocation.BOTTOM:
|
||||||
|
splitter = preload("res://addons/de.mewin.gduibasics/scenes/flexview_vspliter.tscn").instance()
|
||||||
|
else:
|
||||||
|
splitter = preload("res://addons/de.mewin.gduibasics/scenes/flexview_hspliter.tscn").instance()
|
||||||
|
parent.add_child_below_node(self, splitter)
|
||||||
|
parent.remove_child(self)
|
||||||
|
|
||||||
|
GDBUIUtility.copy_size(splitter, self)
|
||||||
|
|
||||||
|
# add self first (if applicable)
|
||||||
|
if self_first:
|
||||||
|
splitter.add_child(self)
|
||||||
|
|
||||||
|
# create new flex container for other half
|
||||||
|
var new_container : Control = load("res://addons/de.mewin.gduibasics/scenes/flexview.tscn").instance()
|
||||||
|
new_container.add_view(title, view)
|
||||||
|
__copy_signal_handlers(new_container)
|
||||||
|
splitter.add_child(new_container)
|
||||||
|
|
||||||
|
# add self second (if applicable)
|
||||||
|
if !self_first:
|
||||||
|
splitter.add_child(self)
|
||||||
|
|
||||||
|
if placement == SplitLocation.TOP || placement == SplitLocation.BOTTOM:
|
||||||
|
splitter.split_offset = 0.5 * splitter.rect_size.y
|
||||||
|
else:
|
||||||
|
splitter.split_offset = 0.5 * splitter.rect_size.x
|
||||||
|
splitter.clamp_split_offset()
|
||||||
|
return new_container
|
||||||
|
|
||||||
|
################
|
||||||
|
# static stuff #
|
||||||
|
################
|
||||||
|
static func get_view_title_from_control(control : Control) -> String:
|
||||||
|
var prop = control.get("flexview_title")
|
||||||
|
if prop is String:
|
||||||
|
return prop
|
||||||
|
|
||||||
|
var title = control.get_meta(META_VIEW_TITLE)
|
||||||
|
if title is String:
|
||||||
|
return title
|
||||||
|
return control.name
|
||||||
|
|
||||||
|
static func get_all_flex_views() -> Array:
|
||||||
|
return GDBUtility.get_scene_tree().get_nodes_in_group(GROUP_NAME)
|
||||||
|
|
||||||
|
static func get_all_views() -> Array:
|
||||||
|
var views := []
|
||||||
|
for flex_view in get_all_flex_views():
|
||||||
|
views.append_array(flex_view.get_views())
|
||||||
|
return views
|
||||||
|
|
||||||
|
static func get_top_flex_view() -> Control:
|
||||||
|
# can't use GDBUtility.find_node_by_type as we cannot use our own type
|
||||||
|
var all_views := get_all_flex_views()
|
||||||
|
var top_view : Control = null
|
||||||
|
for flex_view in all_views:
|
||||||
|
if top_view == null || top_view.is_greater_than(flex_view):
|
||||||
|
top_view = flex_view
|
||||||
|
return top_view
|
||||||
|
|
||||||
|
static func add_view_anywhere(title : String, view : Control, make_current := true) -> Control:
|
||||||
|
var flex_view := _get_last_drop_target()
|
||||||
|
if flex_view == null:
|
||||||
|
flex_view = get_top_flex_view()
|
||||||
|
if flex_view != null:
|
||||||
|
flex_view.add_view(title, view, make_current)
|
||||||
|
return flex_view
|
||||||
|
|
||||||
|
static func add_unique_view_anywhere(title : String, view : Control, type : String, key, make_current := true) -> Control:
|
||||||
|
var flex_view := add_view_anywhere(title, view, make_current)
|
||||||
|
if flex_view == null: # failed
|
||||||
|
return null
|
||||||
|
view.set_meta(META_UNIQUE_TYPE, type)
|
||||||
|
view.set_meta(META_UNIQUE_KEY, key)
|
||||||
|
return flex_view
|
||||||
|
|
||||||
|
static func remove_all_views_anywhere() -> void:
|
||||||
|
for flex_view in get_all_flex_views():
|
||||||
|
flex_view.remove_all_views()
|
||||||
|
|
||||||
|
static func find_unique_view(type : String, key) -> Control:
|
||||||
|
for view_ctrl in get_all_views():
|
||||||
|
if view_ctrl.has_meta(META_UNIQUE_TYPE) && view_ctrl.has_meta(META_UNIQUE_KEY)\
|
||||||
|
&& view_ctrl.get_meta(META_UNIQUE_TYPE) == type && view_ctrl.get_meta(META_UNIQUE_KEY) == key:
|
||||||
|
return view_ctrl
|
||||||
|
return null
|
||||||
|
|
||||||
|
static func find_flex_view(view_control : Control) -> Control:
|
||||||
|
var my_script : Script = load("res://addons/de.mewin.gduibasics/scripts/types/controls/flexview.gd")
|
||||||
|
return GDBUtility.find_parent_with_type(view_control, my_script) as Control
|
||||||
|
|
||||||
|
static func make_view_current(view_control : Control) -> void:
|
||||||
|
var flex_view := find_flex_view(view_control)
|
||||||
|
if flex_view:
|
||||||
|
flex_view.current_view = view_control.get_position_in_parent()
|
||||||
|
|
||||||
|
static func _set_last_drop_target(flex_view : Control) -> void:
|
||||||
|
flex_view.get_tree().set_meta(META_LAST_DROP_TARGET, flex_view.get_path())
|
||||||
|
|
||||||
|
static func _get_last_drop_target() -> Control:
|
||||||
|
var tree := GDBUtility.get_scene_tree()
|
||||||
|
if tree.has_meta(META_LAST_DROP_TARGET):
|
||||||
|
var flex_view_path := tree.get_meta(META_LAST_DROP_TARGET) as NodePath
|
||||||
|
if flex_view_path:
|
||||||
|
var flex_view := tree.root.get_node_or_null(flex_view_path) as Control
|
||||||
|
return flex_view
|
||||||
|
return null
|
||||||
|
|
||||||
|
#################
|
||||||
|
# private stuff #
|
||||||
|
#################
|
||||||
|
func _start_dropping() -> void:
|
||||||
|
__drop_position = -1
|
||||||
|
_drop_indicator.visible = true
|
||||||
|
_tween.stop_all()
|
||||||
|
_tween.interpolate_property(_drop_indicator, "modulate", Color.transparent, Color.white, INDICATOR_ANIM_DURATION)
|
||||||
|
_tween.start()
|
||||||
|
set_process(true)
|
||||||
|
|
||||||
|
func _stop_dropping() -> void:
|
||||||
|
_tween.stop_all()
|
||||||
|
_tween.interpolate_property(_drop_indicator, "modulate", Color.white, Color.transparent, INDICATOR_ANIM_DURATION)
|
||||||
|
_tween.start()
|
||||||
|
set_process(false)
|
||||||
|
|
||||||
|
yield(get_tree().create_timer(INDICATOR_ANIM_DURATION), "timeout")
|
||||||
|
if !is_processing(): # mOybe we are dragging again
|
||||||
|
_drop_indicator.visible = false
|
||||||
|
|
||||||
|
func _drop(view : Control) -> void:
|
||||||
|
_stop_dropping()
|
||||||
|
|
||||||
|
var title := get_view_title_from_control(view)
|
||||||
|
if __drop_position != DropPosition.CENTER:
|
||||||
|
var new_container := split_view(__drop_position, title, view)
|
||||||
|
_set_last_drop_target(new_container)
|
||||||
|
else:
|
||||||
|
add_view(title, view)
|
||||||
|
_set_last_drop_target(self)
|
||||||
|
|
||||||
|
func __make_floating_tab(tab : int) -> void:
|
||||||
|
var window : WindowDialog = load("res://addons/de.mewin.gduibasics/scenes/flexview_window.tscn").instance()
|
||||||
|
get_tree().root.add_child(window)
|
||||||
|
|
||||||
|
# remove tab
|
||||||
|
var tab_ctrl : Control = $tabs.get_tab_control(tab)
|
||||||
|
remove_view(tab)
|
||||||
|
|
||||||
|
# add to new window
|
||||||
|
var title = get_view_title_from_control(tab_ctrl)
|
||||||
|
window.flex_view.add_view(title, tab_ctrl)
|
||||||
|
__copy_signal_handlers(window.flex_view)
|
||||||
|
|
||||||
|
# place window
|
||||||
|
var vp_size := get_viewport().size
|
||||||
|
var mouse_pos := get_viewport().get_mouse_position()
|
||||||
|
var win_size := vp_size * Vector2(0.5, 0.5)
|
||||||
|
var min_size := window.get_combined_minimum_size()
|
||||||
|
var title_height := window.get_constant("title_height")
|
||||||
|
|
||||||
|
window.rect_size = Vector2(max(win_size.x, min_size.x), max(win_size.y, min_size.y))
|
||||||
|
window.rect_position = mouse_pos - Vector2(0.5 * window.rect_size.x, -0.5 * title_height)
|
||||||
|
window.visible = true
|
||||||
|
|
||||||
|
# emulate mouse down for dragging the window
|
||||||
|
var event := InputEventMouseButton.new()
|
||||||
|
event.button_index = BUTTON_LEFT
|
||||||
|
event.pressed = true
|
||||||
|
event.button_mask = BUTTON_MASK_LEFT
|
||||||
|
event.position = mouse_pos
|
||||||
|
event.global_position = mouse_pos
|
||||||
|
Input.parse_input_event(event)
|
||||||
|
|
||||||
|
func __get_drop_rect(drop_position : int) -> Rect2:
|
||||||
|
var full_rect := Rect2(Vector2(), rect_size)
|
||||||
|
match drop_position:
|
||||||
|
DropPosition.TOP:
|
||||||
|
return full_rect.grow_individual(0.0, 0.0, 0.0, -0.5 * full_rect.size.y)
|
||||||
|
DropPosition.BOTTOM:
|
||||||
|
return full_rect.grow_individual(0.0, -0.5 * full_rect.size.y, 0.0, 0.0)
|
||||||
|
DropPosition.LEFT:
|
||||||
|
return full_rect.grow_individual(0.0, 0.0, -0.5 * full_rect.size.x, 0.0)
|
||||||
|
DropPosition.RIGHT:
|
||||||
|
return full_rect.grow_individual(-0.5 * full_rect.size.x, 0.0, 0.0, 0.0)
|
||||||
|
return full_rect
|
||||||
|
|
||||||
|
func __copy_signal_handlers(other_view : Control) -> void:
|
||||||
|
GDBUtility.copy_all_signal_handlers(other_view, self, __HANDLERS_TO_COPY)
|
||||||
|
|
||||||
|
#####################
|
||||||
|
# setters & getters #
|
||||||
|
#####################
|
||||||
|
func _set_current_view(val : int) -> void:
|
||||||
|
$tabs.current_tab = val
|
||||||
|
emit_signal("current_view_changed", self)
|
||||||
|
|
||||||
|
func _get_current_view() -> int:
|
||||||
|
return $tabs.current_tab
|
||||||
|
|
||||||
|
func _set_show_tabs(show : bool) -> void:
|
||||||
|
show_tabs = show
|
||||||
|
if $tabs:
|
||||||
|
$tabs.show_tabs = show
|
||||||
|
|
||||||
|
###################
|
||||||
|
# signal handlers #
|
||||||
|
###################
|
||||||
|
func _on_tabs_tab_dragged_out(tab : int, position : Vector2) -> void:
|
||||||
|
__make_floating_tab(tab)
|
||||||
|
|
||||||
|
func _on_tabs_tab_close(tab : int):
|
||||||
|
close_view(tab)
|
||||||
|
|
||||||
|
func _on_flexview_title_changed(control : Control) -> void:
|
||||||
|
var view := find_view(control)
|
||||||
|
var title = control.get("flexview_title")
|
||||||
|
if view >= 0 && title is String:
|
||||||
|
set_view_title(view, title)
|
||||||
|
|
||||||
|
func _on_flexview_close_me(control : Control) -> void:
|
||||||
|
var view := find_view(control)
|
||||||
|
if view >= 0:
|
||||||
|
remove_view(view)
|
||||||
|
|
||||||
|
###########
|
||||||
|
# signals #
|
||||||
|
###########
|
||||||
|
signal view_added(view, flex_view)
|
||||||
|
signal view_removed(view, flex_view)
|
||||||
|
signal view_closing(view, flex_view)
|
||||||
|
signal current_view_changed(flex_view)
|
38
scenes/scripts/flexview_splitter.gd
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
extends SplitContainer
|
||||||
|
|
||||||
|
#############
|
||||||
|
# overrides #
|
||||||
|
#############
|
||||||
|
func add_child(child : Node, legible_unique_name := false) -> void:
|
||||||
|
.add_child(child, legible_unique_name)
|
||||||
|
|
||||||
|
child.connect("tree_exited", self, "_on_child_tree_exited")
|
||||||
|
|
||||||
|
#################
|
||||||
|
# private stuff #
|
||||||
|
#################
|
||||||
|
func __try_collapse() -> void:
|
||||||
|
var count := get_child_count()
|
||||||
|
if count == 0: # nothing left? I can go now
|
||||||
|
self.queue_free()
|
||||||
|
return
|
||||||
|
elif count > 1: # more than one? I have to stay
|
||||||
|
return
|
||||||
|
|
||||||
|
# exactly one? replace me with them
|
||||||
|
var child := get_child(0)
|
||||||
|
remove_child(child)
|
||||||
|
|
||||||
|
get_parent().add_child_below_node(self, child)
|
||||||
|
GDBUIUtility.copy_size(child, self)
|
||||||
|
self.queue_free()
|
||||||
|
|
||||||
|
###################
|
||||||
|
# signal handlers #
|
||||||
|
###################
|
||||||
|
func _on_child_tree_exited() -> void:
|
||||||
|
if !get_tree():
|
||||||
|
return
|
||||||
|
|
||||||
|
yield(get_tree(), "idle_frame") # wait until child is actually gone
|
||||||
|
__try_collapse()
|
141
scenes/scripts/flexview_window.gd
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
extends WindowDialog
|
||||||
|
|
||||||
|
const FlexView = preload("res://addons/de.mewin.gduibasics/scenes/scripts/flexview.gd")
|
||||||
|
|
||||||
|
var flex_view : FlexView setget _set_flex_view, _get_flex_view
|
||||||
|
|
||||||
|
var __drop_target : FlexView = null
|
||||||
|
var __is_dragging := false
|
||||||
|
|
||||||
|
#############
|
||||||
|
# overrides #
|
||||||
|
#############
|
||||||
|
func _ready() -> void:
|
||||||
|
set_process(false) # only used to stop dropping when mouse button is lifted
|
||||||
|
__update_title()
|
||||||
|
|
||||||
|
func _process(delta : float) -> void:
|
||||||
|
if !Input.is_mouse_button_pressed(BUTTON_LEFT):
|
||||||
|
__drop()
|
||||||
|
|
||||||
|
func _input(event : InputEvent) -> void:
|
||||||
|
if event is InputEventKey && event.scancode == KEY_SHIFT && __is_dragging:
|
||||||
|
__update_dragging()
|
||||||
|
|
||||||
|
#################
|
||||||
|
# private stuff #
|
||||||
|
#################
|
||||||
|
func __update_view_count() -> void:
|
||||||
|
var child := __get_flex_child()
|
||||||
|
if !(child is FlexView):
|
||||||
|
return
|
||||||
|
|
||||||
|
var count : int = child.get_view_count()
|
||||||
|
if count == 0:
|
||||||
|
self.queue_free()
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
# child.show_tabs = (count > 1)
|
||||||
|
pass
|
||||||
|
|
||||||
|
func __update_dragging() -> void:
|
||||||
|
var child := __get_flex_child()
|
||||||
|
if !(child is FlexView) || child.get_view_count() > 1:
|
||||||
|
set_process(false)
|
||||||
|
__is_dragging = false
|
||||||
|
return
|
||||||
|
|
||||||
|
__is_dragging = true
|
||||||
|
set_process(true)
|
||||||
|
|
||||||
|
# dragging with shift disables dropping
|
||||||
|
if Input.is_key_pressed(KEY_SHIFT):
|
||||||
|
__set_drop_target(null)
|
||||||
|
return
|
||||||
|
|
||||||
|
var mouse_pos := get_viewport().get_mouse_position()
|
||||||
|
var flex_views := get_tree().get_nodes_in_group(FlexView.GROUP_NAME)
|
||||||
|
var views_under_cursor := []
|
||||||
|
|
||||||
|
for view in flex_views:
|
||||||
|
if !self.is_a_parent_of(view) && view.visible && view.get_global_rect().has_point(mouse_pos):
|
||||||
|
views_under_cursor.append(view)
|
||||||
|
|
||||||
|
if views_under_cursor.empty():
|
||||||
|
__set_drop_target(null)
|
||||||
|
return
|
||||||
|
|
||||||
|
# find first in tree
|
||||||
|
var target : FlexView = views_under_cursor[0]
|
||||||
|
for i in range(1, views_under_cursor.size()):
|
||||||
|
var node : FlexView = views_under_cursor[i]
|
||||||
|
if GDBUtility.control_is_in_front_of(node, target):
|
||||||
|
target = node
|
||||||
|
__set_drop_target(target)
|
||||||
|
|
||||||
|
func __set_drop_target(target : FlexView) -> void:
|
||||||
|
if target == __drop_target:
|
||||||
|
return
|
||||||
|
set_process(is_instance_valid(__drop_target)) # process to check if mouse button is lifted
|
||||||
|
|
||||||
|
if is_instance_valid(__drop_target):
|
||||||
|
__drop_target._stop_dropping()
|
||||||
|
__drop_target = target
|
||||||
|
if is_instance_valid(__drop_target):
|
||||||
|
__drop_target._start_dropping()
|
||||||
|
|
||||||
|
func __drop() -> void:
|
||||||
|
var child := __get_flex_child()
|
||||||
|
set_process(false)
|
||||||
|
__is_dragging = false
|
||||||
|
|
||||||
|
if !is_instance_valid(__drop_target) || !(child is FlexView) || child.get_view_count() != 1:
|
||||||
|
return
|
||||||
|
|
||||||
|
var control : Control = child.get_view_control(0)
|
||||||
|
child.remove_view(0)
|
||||||
|
__drop_target._drop(control)
|
||||||
|
self.queue_free()
|
||||||
|
|
||||||
|
func __update_title() -> void:
|
||||||
|
var child := __get_flex_child()
|
||||||
|
if !(child is FlexView):
|
||||||
|
window_title = ""
|
||||||
|
elif child.get_view_count() > 0:
|
||||||
|
window_title = child.get_view_title(child.current_view)
|
||||||
|
|
||||||
|
func __get_flex_child() -> Control:
|
||||||
|
return get_child(1) as Control # TODO: something better (and safer) than a fixed index
|
||||||
|
|
||||||
|
func __close_requested() -> void:
|
||||||
|
for flex_view in GDBUtility.find_nodes_by_type(self, FlexView):
|
||||||
|
flex_view.close_all_views()
|
||||||
|
|
||||||
|
#####################
|
||||||
|
# setters & getters #
|
||||||
|
#####################
|
||||||
|
func _set_flex_view(val) -> void:
|
||||||
|
assert(0, "Cannot set this.")
|
||||||
|
|
||||||
|
func _get_flex_view() -> FlexView:
|
||||||
|
return $flex_view as FlexView
|
||||||
|
|
||||||
|
###################
|
||||||
|
# signal handlers #
|
||||||
|
###################
|
||||||
|
func _on_flex_view_view_added(view : int, flex_view : FlexView) -> void:
|
||||||
|
__update_view_count()
|
||||||
|
|
||||||
|
func _on_flex_view_view_removed(view : int, flex_view : FlexView) -> void:
|
||||||
|
__update_view_count()
|
||||||
|
|
||||||
|
func _on_flexview_window_item_rect_changed() -> void:
|
||||||
|
__update_dragging()
|
||||||
|
|
||||||
|
func _on_flex_view_current_view_changed(flex_view : FlexView):
|
||||||
|
__update_title()
|
||||||
|
|
||||||
|
func _on_flexview_window_visibility_changed():
|
||||||
|
if !visible:
|
||||||
|
__close_requested()
|
||||||
|
visible = true
|
100
scenes/scripts/line_edit_suggestion_popup.gd
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
extends Popup
|
||||||
|
|
||||||
|
enum Position {
|
||||||
|
ABOVE,
|
||||||
|
BELOW
|
||||||
|
}
|
||||||
|
|
||||||
|
var line_edit : LineEdit setget _set_line_edit
|
||||||
|
export(Position) var position = Position.BELOW
|
||||||
|
|
||||||
|
#############
|
||||||
|
# overrides #
|
||||||
|
#############
|
||||||
|
func _ready():
|
||||||
|
call_deferred("__setup")
|
||||||
|
|
||||||
|
#################
|
||||||
|
# private stuff #
|
||||||
|
#################
|
||||||
|
func __setup():
|
||||||
|
__connect()
|
||||||
|
|
||||||
|
func __connect():
|
||||||
|
if !line_edit:
|
||||||
|
return
|
||||||
|
|
||||||
|
line_edit.connect("focus_entered", self, "_on_line_edit_focus_entered")
|
||||||
|
line_edit.connect("focus_exited", self, "_on_line_edit_focus_exited")
|
||||||
|
line_edit.connect("item_rect_changed", self, "_on_line_edit_item_rect_changed")
|
||||||
|
line_edit.connect("resized", self, "_on_line_edit_resized")
|
||||||
|
|
||||||
|
func __disconnect():
|
||||||
|
if !line_edit:
|
||||||
|
return
|
||||||
|
|
||||||
|
line_edit.disconnect("focus_entered", self, "_on_line_edit_focus_entered")
|
||||||
|
line_edit.disconnect("focus_exited", self, "_on_line_edit_focus_exited")
|
||||||
|
line_edit.disconnect("item_rect_changed", self, "_on_line_edit_item_rect_changed")
|
||||||
|
line_edit.disconnect("resized", self, "_on_line_edit_resized")
|
||||||
|
|
||||||
|
func __calc_rect() -> Rect2:
|
||||||
|
var position_ = position
|
||||||
|
var pos := line_edit.rect_global_position
|
||||||
|
var vp_pos = get_viewport_rect().position
|
||||||
|
var vp_size = get_viewport_rect().size
|
||||||
|
var size := rect_min_size
|
||||||
|
var le_size := line_edit.rect_size
|
||||||
|
var max_height : float
|
||||||
|
|
||||||
|
if pos.y + size.y > vp_size.y:
|
||||||
|
position_ = Position.ABOVE
|
||||||
|
elif pos.y < vp_pos.y:
|
||||||
|
position_ = Position.BELOW
|
||||||
|
|
||||||
|
if position_ == Position.ABOVE:
|
||||||
|
max_height = pos.y - vp_pos.y
|
||||||
|
else:
|
||||||
|
max_height = (vp_pos.y + vp_size.y) - (pos.y + size.y)
|
||||||
|
|
||||||
|
var res_size = Vector2(le_size.x, 100.0)
|
||||||
|
if position_ == Position.ABOVE:
|
||||||
|
return Rect2(pos - Vector2(0.0, res_size.y), res_size)
|
||||||
|
else:
|
||||||
|
return Rect2(pos + Vector2(0.0, size.y), res_size)
|
||||||
|
|
||||||
|
func __update():
|
||||||
|
var should_be_visible = line_edit.has_focus()
|
||||||
|
if !should_be_visible:
|
||||||
|
hide()
|
||||||
|
else:
|
||||||
|
var rect := __calc_rect()
|
||||||
|
if visible:
|
||||||
|
rect_position = rect.position
|
||||||
|
rect_size = rect.size
|
||||||
|
else:
|
||||||
|
popup(rect)
|
||||||
|
|
||||||
|
############
|
||||||
|
# handlers #
|
||||||
|
############
|
||||||
|
func _on_line_edit_focus_entered():
|
||||||
|
__update()
|
||||||
|
|
||||||
|
func _on_line_edit_focus_exited():
|
||||||
|
hide()
|
||||||
|
|
||||||
|
func _on_line_edit_item_rect_changed():
|
||||||
|
__update()
|
||||||
|
|
||||||
|
func _on_line_edit_resized():
|
||||||
|
__update()
|
||||||
|
|
||||||
|
###########
|
||||||
|
# setters #
|
||||||
|
###########
|
||||||
|
func _set_line_edit(value : LineEdit):
|
||||||
|
if value != line_edit:
|
||||||
|
__disconnect()
|
||||||
|
line_edit = value
|
||||||
|
__connect()
|
47
scenes/scripts/line_input_dialog.gd
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
tool
|
||||||
|
extends ConfirmationDialog
|
||||||
|
|
||||||
|
export(bool) var allow_empty := true setget _set_allow_empty
|
||||||
|
|
||||||
|
################
|
||||||
|
# public stuff #
|
||||||
|
################
|
||||||
|
func get_line_edit() -> LineEdit:
|
||||||
|
return $container/line_edit as LineEdit
|
||||||
|
|
||||||
|
#################
|
||||||
|
# private stuff #
|
||||||
|
#################
|
||||||
|
func __update():
|
||||||
|
var valid := true
|
||||||
|
if !allow_empty && !$container/line_edit.text:
|
||||||
|
valid = false
|
||||||
|
get_ok().disabled = !valid
|
||||||
|
|
||||||
|
###########
|
||||||
|
# setters #
|
||||||
|
###########
|
||||||
|
func _set_allow_empty(value : bool):
|
||||||
|
if value != allow_empty:
|
||||||
|
allow_empty = value
|
||||||
|
__update()
|
||||||
|
|
||||||
|
############
|
||||||
|
# handlers #
|
||||||
|
############
|
||||||
|
func _on_line_input_dialog_about_to_show():
|
||||||
|
__update()
|
||||||
|
|
||||||
|
func _on_line_edit_text_changed(new_text : String):
|
||||||
|
__update()
|
||||||
|
|
||||||
|
func _on_line_edit_text_entered(new_text):
|
||||||
|
if !get_ok().disabled:
|
||||||
|
visible = false
|
||||||
|
emit_signal("confirmed")
|
||||||
|
|
||||||
|
func _on_line_input_dialog_visibility_changed():
|
||||||
|
if visible:
|
||||||
|
yield(get_tree(), "idle_frame")
|
||||||
|
$container/line_edit.grab_focus()
|
||||||
|
$container/line_edit.caret_position = $container/line_edit.text.length()
|
5
scenes/scripts/node_selection_dialog.gd
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
tool
|
||||||
|
extends ConfirmationDialog
|
||||||
|
|
||||||
|
func get_editor_node_tree() -> UIB_EditorNodeTree:
|
||||||
|
return $tree as UIB_EditorNodeTree
|
174
scenes/scripts/selector_popup.gd
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
extends PopupPanel
|
||||||
|
|
||||||
|
class_name SelectorPopup
|
||||||
|
|
||||||
|
class _Item:
|
||||||
|
var label : String
|
||||||
|
var icon : Texture
|
||||||
|
var metadata
|
||||||
|
var current_list_index := -1
|
||||||
|
|
||||||
|
func _init(label_ : String, icon_ : Texture, metadata_):
|
||||||
|
self.label = label_
|
||||||
|
self.icon = icon_
|
||||||
|
self.metadata = metadata_
|
||||||
|
|
||||||
|
export var match_case := false
|
||||||
|
|
||||||
|
onready var _ledit_search : LineEdit = GDBUtility.find_node_by_name(self, "ledit_search")
|
||||||
|
onready var _ilist_content : ItemList = GDBUtility.find_node_by_name(self, "ilist_content")
|
||||||
|
|
||||||
|
var _items := []
|
||||||
|
var __needs_update := false
|
||||||
|
var __caret := 0
|
||||||
|
var __submitted := false
|
||||||
|
|
||||||
|
################
|
||||||
|
# overridables #
|
||||||
|
################
|
||||||
|
func _should_show(item : _Item) -> bool:
|
||||||
|
var search_text := _ledit_search.text.strip_edges()
|
||||||
|
if search_text == "":
|
||||||
|
return true
|
||||||
|
var item_text := item.label
|
||||||
|
if !match_case:
|
||||||
|
search_text = search_text.to_lower()
|
||||||
|
item_text = item_text.to_lower()
|
||||||
|
return search_text in item_text
|
||||||
|
|
||||||
|
################
|
||||||
|
# public stuff #
|
||||||
|
################
|
||||||
|
func add_item(label : String, icon : Texture = null, metadata = null) -> void:
|
||||||
|
_items.append(_Item.new(label, icon, metadata))
|
||||||
|
invalidate()
|
||||||
|
|
||||||
|
func clear_items() -> void:
|
||||||
|
_items.clear()
|
||||||
|
invalidate()
|
||||||
|
|
||||||
|
func get_item_label(idx : int) -> String:
|
||||||
|
if idx < 0 || idx >= _items.size():
|
||||||
|
return ""
|
||||||
|
return _items[idx].label
|
||||||
|
|
||||||
|
func get_item_metadata(idx : int):
|
||||||
|
if idx < 0 || idx >= _items.size():
|
||||||
|
return null
|
||||||
|
return _items[idx].metadata
|
||||||
|
|
||||||
|
func invalidate() -> void:
|
||||||
|
# only updates once if multiple calls are done in a single frame
|
||||||
|
__needs_update = true
|
||||||
|
yield(get_tree(), "idle_frame")
|
||||||
|
if __needs_update:
|
||||||
|
__needs_update = false
|
||||||
|
__update()
|
||||||
|
|
||||||
|
#################
|
||||||
|
# private stuff #
|
||||||
|
#################
|
||||||
|
func __update() -> void:
|
||||||
|
var idx_increment := 0
|
||||||
|
var insert_index := 0
|
||||||
|
|
||||||
|
for item in self._items:
|
||||||
|
var should_show := self._should_show(item)
|
||||||
|
var is_visible : bool = (item.current_list_index > -1)
|
||||||
|
|
||||||
|
if is_visible:
|
||||||
|
item.current_list_index += idx_increment
|
||||||
|
|
||||||
|
if should_show && !is_visible:
|
||||||
|
self.__add_item(item, insert_index)
|
||||||
|
item.current_list_index = insert_index
|
||||||
|
idx_increment += 1
|
||||||
|
elif !should_show && is_visible:
|
||||||
|
_ilist_content.remove_item(item.current_list_index)
|
||||||
|
item.current_list_index = -1
|
||||||
|
idx_increment -= 1
|
||||||
|
|
||||||
|
if should_show:
|
||||||
|
insert_index += 1
|
||||||
|
|
||||||
|
if !_ilist_content.is_anything_selected() && _ilist_content.get_item_count() > 0:
|
||||||
|
__select(0)
|
||||||
|
|
||||||
|
func __add_item(item : _Item, insert_index : int) -> void:
|
||||||
|
var new_idx := _ilist_content.get_item_count()
|
||||||
|
_ilist_content.add_item(item.label, item.icon)
|
||||||
|
_ilist_content.set_item_metadata(new_idx, item)
|
||||||
|
if insert_index != new_idx:
|
||||||
|
_ilist_content.move_item(new_idx, insert_index)
|
||||||
|
|
||||||
|
func __select(idx : int) -> void:
|
||||||
|
_ilist_content.select(idx)
|
||||||
|
_ilist_content.ensure_current_is_visible()
|
||||||
|
|
||||||
|
func __select_next() -> void:
|
||||||
|
var selected := _ilist_content.get_selected_items()
|
||||||
|
var idx := 0
|
||||||
|
if !selected.empty():
|
||||||
|
idx = selected[0] + 1
|
||||||
|
if idx >= _ilist_content.get_item_count():
|
||||||
|
return
|
||||||
|
__select(idx)
|
||||||
|
|
||||||
|
func __select_prev() -> void:
|
||||||
|
var selected := _ilist_content.get_selected_items()
|
||||||
|
var idx := 0
|
||||||
|
if !selected.empty():
|
||||||
|
idx = selected[0] - 1
|
||||||
|
if idx < 0:
|
||||||
|
return
|
||||||
|
__select(idx)
|
||||||
|
|
||||||
|
func __item_from_list_index(idx : int) -> _Item:
|
||||||
|
return _ilist_content.get_item_metadata(idx) as _Item
|
||||||
|
|
||||||
|
func __item_index(itm : _Item) -> int:
|
||||||
|
return _items.find(itm)
|
||||||
|
|
||||||
|
###################
|
||||||
|
# signal handlers #
|
||||||
|
###################
|
||||||
|
func _on_selector_popup_about_to_show() -> void:
|
||||||
|
__submitted = false
|
||||||
|
_ledit_search.clear()
|
||||||
|
_ledit_search.grab_focus()
|
||||||
|
_ilist_content.unselect_all()
|
||||||
|
__update()
|
||||||
|
|
||||||
|
func _on_ledit_search_text_changed(new_text : String) -> void:
|
||||||
|
__update()
|
||||||
|
|
||||||
|
func _on_ledit_search_gui_input(event : InputEvent) -> void:
|
||||||
|
if !event.is_pressed():
|
||||||
|
return
|
||||||
|
|
||||||
|
if event.is_action("ui_down"):
|
||||||
|
__select_next()
|
||||||
|
elif event.is_action("ui_up"):
|
||||||
|
__select_prev()
|
||||||
|
else:
|
||||||
|
__caret = _ledit_search.caret_position
|
||||||
|
return
|
||||||
|
_ledit_search.caret_position = __caret
|
||||||
|
|
||||||
|
func _on_ledit_search_text_entered(new_text : String) -> void:
|
||||||
|
var selected := _ilist_content.get_selected_items()
|
||||||
|
if selected.empty():
|
||||||
|
return
|
||||||
|
var idx := __item_index(__item_from_list_index(selected[0]))
|
||||||
|
__submitted = true
|
||||||
|
emit_signal("selected", idx)
|
||||||
|
hide()
|
||||||
|
|
||||||
|
func _on_selector_popup_popup_hide() -> void:
|
||||||
|
if !__submitted:
|
||||||
|
emit_signal("selected", -1)
|
||||||
|
|
||||||
|
###########
|
||||||
|
# signals #
|
||||||
|
###########
|
||||||
|
signal selected(index)
|
77
scenes/scripts/variant_editor.gd
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
tool
|
||||||
|
extends Control
|
||||||
|
|
||||||
|
enum Type {
|
||||||
|
STRING,
|
||||||
|
INT,
|
||||||
|
REAL
|
||||||
|
}
|
||||||
|
|
||||||
|
onready var edt_text := $edt_text
|
||||||
|
onready var spin_number := $spin_number
|
||||||
|
|
||||||
|
export var value = "" setget _set_value
|
||||||
|
export(Type) var type = Type.STRING setget _set_type
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
__setup_type()
|
||||||
|
|
||||||
|
func __setup_type():
|
||||||
|
match type:
|
||||||
|
Type.STRING:
|
||||||
|
edt_text.visible = true
|
||||||
|
Type.INT, Type.REAL:
|
||||||
|
spin_number.visible = true
|
||||||
|
_set_value(convert(value, __type_id()))
|
||||||
|
__fill_value()
|
||||||
|
emit_signal("value_changed")
|
||||||
|
|
||||||
|
func __fill_value():
|
||||||
|
match type:
|
||||||
|
Type.STRING:
|
||||||
|
edt_text.text = str(value)
|
||||||
|
Type.INT, Type.REAL:
|
||||||
|
spin_number.value = float(value)
|
||||||
|
|
||||||
|
func __type_id() -> int:
|
||||||
|
match type:
|
||||||
|
Type.STRING:
|
||||||
|
return TYPE_STRING
|
||||||
|
Type.INT:
|
||||||
|
return TYPE_INT
|
||||||
|
Type.REAL:
|
||||||
|
return TYPE_REAL
|
||||||
|
_:
|
||||||
|
assert(false)
|
||||||
|
return TYPE_STRING
|
||||||
|
|
||||||
|
func _set_value(val):
|
||||||
|
val = convert(val, __type_id())
|
||||||
|
if typeof(value) != __type_id() || value != val:
|
||||||
|
value = val
|
||||||
|
__fill_value()
|
||||||
|
|
||||||
|
func _set_type(value : int):
|
||||||
|
if value != type:
|
||||||
|
type = value
|
||||||
|
for child in get_children():
|
||||||
|
child.visible = false
|
||||||
|
__setup_type()
|
||||||
|
|
||||||
|
func _on_edt_text_text_changed(new_text : String):
|
||||||
|
assert(type == Type.STRING)
|
||||||
|
if !value is String || value != new_text:
|
||||||
|
value = new_text
|
||||||
|
emit_signal("value_changed")
|
||||||
|
|
||||||
|
func _on_spin_number_value_changed(value_ : float):
|
||||||
|
assert(type == Type.INT || type == Type.REAL)
|
||||||
|
if type == Type.INT:
|
||||||
|
value_ = int(value_)
|
||||||
|
if typeof(value) != __type_id() || value != value_:
|
||||||
|
value = value_
|
||||||
|
emit_signal("value_changed")
|
||||||
|
|
||||||
|
signal value_changed()
|
||||||
|
|
||||||
|
|
40
scenes/selector_popup.tscn
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
[gd_scene load_steps=2 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://addons/de.mewin.gduibasics/scenes/scripts/selector_popup.gd" type="Script" id=1]
|
||||||
|
|
||||||
|
[node name="selector_popup" type="PopupPanel"]
|
||||||
|
margin_right = 139.0
|
||||||
|
margin_bottom = 198.0
|
||||||
|
script = ExtResource( 1 )
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="vbox_main" type="VBoxContainer" parent="."]
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
margin_left = 5.0
|
||||||
|
margin_top = 5.0
|
||||||
|
margin_right = -5.0
|
||||||
|
margin_bottom = -5.0
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="ledit_search" type="LineEdit" parent="vbox_main"]
|
||||||
|
margin_right = 129.0
|
||||||
|
margin_bottom = 22.0
|
||||||
|
focus_neighbour_top = NodePath(".")
|
||||||
|
focus_neighbour_bottom = NodePath(".")
|
||||||
|
|
||||||
|
[node name="ilist_content" type="ItemList" parent="vbox_main"]
|
||||||
|
margin_top = 26.0
|
||||||
|
margin_right = 129.0
|
||||||
|
margin_bottom = 188.0
|
||||||
|
size_flags_vertical = 3
|
||||||
|
|
||||||
|
[connection signal="about_to_show" from="." to="." method="_on_selector_popup_about_to_show"]
|
||||||
|
[connection signal="popup_hide" from="." to="." method="_on_selector_popup_popup_hide"]
|
||||||
|
[connection signal="gui_input" from="vbox_main/ledit_search" to="." method="_on_ledit_search_gui_input"]
|
||||||
|
[connection signal="text_changed" from="vbox_main/ledit_search" to="." method="_on_ledit_search_text_changed"]
|
||||||
|
[connection signal="text_entered" from="vbox_main/ledit_search" to="." method="_on_ledit_search_text_entered"]
|
34
scenes/variant_editor.tscn
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
[gd_scene load_steps=2 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://addons/de.mewin.gduibasics/scenes/scripts/variant_editor.gd" type="Script" id=1]
|
||||||
|
|
||||||
|
[node name="variant_editor" type="Control"]
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
margin_right = -617.0
|
||||||
|
margin_bottom = -576.0
|
||||||
|
script = ExtResource( 1 )
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="edt_text" type="LineEdit" parent="."]
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
margin_bottom = -24.0
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
caret_blink = true
|
||||||
|
caret_blink_speed = 0.5
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="spin_number" type="SpinBox" parent="."]
|
||||||
|
visible = false
|
||||||
|
anchor_right = 1.0
|
||||||
|
margin_bottom = 24.0
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": false
|
||||||
|
}
|
||||||
|
[connection signal="text_changed" from="edt_text" to="." method="_on_edt_text_text_changed"]
|
||||||
|
[connection signal="value_changed" from="spin_number" to="." method="_on_spin_number_value_changed"]
|
55
scripts/libs/ui_util.gd
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
extends Node
|
||||||
|
|
||||||
|
class_name GDBUIUtility
|
||||||
|
|
||||||
|
static func uncollapse_tree_item(tree_item : TreeItem):
|
||||||
|
while tree_item:
|
||||||
|
tree_item.collapsed = false
|
||||||
|
tree_item = tree_item.get_parent()
|
||||||
|
|
||||||
|
static func find_scene_tree_editor(root : Node = null) -> Node:
|
||||||
|
if not root:
|
||||||
|
root = (Engine.get_main_loop() as SceneTree).root
|
||||||
|
if root.get_class() == "SceneTreeEditor":
|
||||||
|
return root
|
||||||
|
for child in root.get_children():
|
||||||
|
var scene_tree_editor := find_scene_tree_editor(child)
|
||||||
|
if scene_tree_editor:
|
||||||
|
return scene_tree_editor
|
||||||
|
return null
|
||||||
|
|
||||||
|
static func new_item_sorted(tree : Tree, parent : TreeItem, key : String, meta_column := 0) -> TreeItem:
|
||||||
|
var item := parent.get_children()
|
||||||
|
var found_itm : TreeItem
|
||||||
|
var idx := 0
|
||||||
|
while true:
|
||||||
|
if item == null:
|
||||||
|
break
|
||||||
|
|
||||||
|
var itm_key := item.get_metadata(meta_column) as String
|
||||||
|
if itm_key == key:
|
||||||
|
return item
|
||||||
|
elif itm_key > key:
|
||||||
|
break
|
||||||
|
item = item.get_next()
|
||||||
|
idx += 1
|
||||||
|
|
||||||
|
# not found
|
||||||
|
var new_itm : TreeItem = tree.create_item(parent, idx)
|
||||||
|
new_itm.set_metadata(meta_column, key)
|
||||||
|
return new_itm
|
||||||
|
|
||||||
|
static func copy_size(target : Control, source : Control) -> void:
|
||||||
|
target.rect_min_size = source.rect_min_size
|
||||||
|
target.rect_size = source.rect_size
|
||||||
|
target.size_flags_horizontal = source.size_flags_horizontal
|
||||||
|
target.size_flags_vertical = source.size_flags_vertical
|
||||||
|
target.size_flags_stretch_ratio = source.size_flags_stretch_ratio
|
||||||
|
target.anchor_top = source.anchor_top
|
||||||
|
target.anchor_bottom = source.anchor_bottom
|
||||||
|
target.anchor_left = source.anchor_left
|
||||||
|
target.anchor_right = source.anchor_right
|
||||||
|
target.margin_top = source.margin_top
|
||||||
|
target.margin_bottom = source.margin_bottom
|
||||||
|
target.margin_left = source.margin_left
|
||||||
|
target.margin_right = source.margin_right
|
77
scripts/libs/ux.gd
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
# various UX stuff
|
||||||
|
extends Object
|
||||||
|
|
||||||
|
class_name GDBUX
|
||||||
|
|
||||||
|
const __META_STATE = "__gdbui_ux_state__"
|
||||||
|
|
||||||
|
class __State:
|
||||||
|
signal recent_places_changed()
|
||||||
|
signal favourite_places_changed()
|
||||||
|
|
||||||
|
################
|
||||||
|
# public stuff #
|
||||||
|
################
|
||||||
|
static func get_recent_places() -> Array:
|
||||||
|
return GDBSettings.get_value(GDBConstants.SETTING_RECENT_PLACES, [])
|
||||||
|
|
||||||
|
static func add_recent_place(place) -> void:
|
||||||
|
if place is UIB_FileAdapter.FileEntry:
|
||||||
|
add_recent_place(place._get_path())
|
||||||
|
return
|
||||||
|
|
||||||
|
assert(place is String)
|
||||||
|
var recent_places : Array = GDBSettings.get_value(GDBConstants.SETTING_RECENT_PLACES, [])
|
||||||
|
recent_places.erase(place)
|
||||||
|
recent_places.push_front(place)
|
||||||
|
GDBSettings.set_value(GDBConstants.SETTING_RECENT_PLACES, recent_places)
|
||||||
|
|
||||||
|
__get_state().emit_signal("recent_places_changed")
|
||||||
|
|
||||||
|
static func get_favourite_places() -> Array:
|
||||||
|
return GDBSettings.get_value(GDBConstants.SETTING_FAVOURITE_PLACES, [])
|
||||||
|
|
||||||
|
static func is_favourite_place(place) -> bool:
|
||||||
|
if place is UIB_FileAdapter.FileEntry:
|
||||||
|
return is_favourite_place(place._get_path())
|
||||||
|
|
||||||
|
assert(place is String)
|
||||||
|
return GDBSettings.array_has_value(GDBConstants.SETTING_FAVOURITE_PLACES, place)
|
||||||
|
|
||||||
|
static func add_favourite_place(place) -> void:
|
||||||
|
if place is UIB_FileAdapter.FileEntry:
|
||||||
|
add_favourite_place(place._get_path())
|
||||||
|
return
|
||||||
|
|
||||||
|
assert(place is String)
|
||||||
|
var places = GDBSettings.get_value(GDBConstants.SETTING_FAVOURITE_PLACES, [])
|
||||||
|
if !places.has(place):
|
||||||
|
places.append(place)
|
||||||
|
GDBSettings.set_value(GDBConstants.SETTING_FAVOURITE_PLACES, places)
|
||||||
|
|
||||||
|
__get_state().emit_signal("favourite_places_changed")
|
||||||
|
|
||||||
|
static func remove_favourite_place(place) -> void:
|
||||||
|
if place is UIB_FileAdapter.FileEntry:
|
||||||
|
remove_favourite_place(place._get_path())
|
||||||
|
return
|
||||||
|
|
||||||
|
assert(place is String)
|
||||||
|
var places = GDBSettings.get_value(GDBConstants.SETTING_FAVOURITE_PLACES, [])
|
||||||
|
if places.has(place):
|
||||||
|
places.erase(place)
|
||||||
|
GDBSettings.set_value(GDBConstants.SETTING_FAVOURITE_PLACES, places)
|
||||||
|
|
||||||
|
__get_state().emit_signal("favourite_places_changed")
|
||||||
|
|
||||||
|
static func connect_static(sig_name : String, receiver : Object, method : String, binds := []) -> int:
|
||||||
|
return __get_state().connect(sig_name, receiver, method, binds)
|
||||||
|
|
||||||
|
static func disconnect_static(sig_name : String, receiver : Object, method : String) -> void:
|
||||||
|
__get_state().disconnect(sig_name, receiver, method)
|
||||||
|
|
||||||
|
#################
|
||||||
|
# private stuff #
|
||||||
|
#################
|
||||||
|
static func __get_state() -> __State:
|
||||||
|
return GDBUtility.get_state_object(__META_STATE, __State)
|
82
scripts/types/controls/action_button.gd
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
extends Button
|
||||||
|
|
||||||
|
class_name UIB_ActionButton
|
||||||
|
|
||||||
|
var action : UIB_Action setget _set_action
|
||||||
|
|
||||||
|
#############
|
||||||
|
# overrides #
|
||||||
|
#############
|
||||||
|
func _ready():
|
||||||
|
if !action:
|
||||||
|
_set_action(GDBUtility.find_node_by_type(self, UIB_Action))
|
||||||
|
if !action:
|
||||||
|
var action_reference : UIB_ActionReference = GDBUtility.find_node_by_type(self, UIB_ActionReference)
|
||||||
|
if action_reference:
|
||||||
|
_set_action(action_reference.get_action())
|
||||||
|
|
||||||
|
func _pressed():
|
||||||
|
if action:
|
||||||
|
action._apply()
|
||||||
|
|
||||||
|
#################
|
||||||
|
# private stuff #
|
||||||
|
#################
|
||||||
|
func __connect():
|
||||||
|
if !action:
|
||||||
|
return
|
||||||
|
action.connect("disabled_changed", self, "_on_action_disabled_changed")
|
||||||
|
action.connect("toggled_changed", self, "_on_action_toggled_changed")
|
||||||
|
action.connect("text_changed", self, "_on_action_text_changed")
|
||||||
|
action.connect("icon_changed", self, "_on_action_icon_changed")
|
||||||
|
|
||||||
|
func __disconnect():
|
||||||
|
if !action:
|
||||||
|
return
|
||||||
|
action.disconnect("disabled_changed", self, "_on_action_disabled_changed")
|
||||||
|
action.disconnect("toggled_changed", self, "_on_action_toggled_changed")
|
||||||
|
action.disconnect("text_changed", self, "_on_action_text_changed")
|
||||||
|
action.disconnect("icon_changed", self, "_on_action_icon_changed")
|
||||||
|
|
||||||
|
############
|
||||||
|
# handlers #
|
||||||
|
############
|
||||||
|
func _on_action_disabled_changed():
|
||||||
|
disabled = action._is_disabled()
|
||||||
|
|
||||||
|
func _on_action_toggled_changed():
|
||||||
|
toggle_mode = action._is_toggled()
|
||||||
|
pressed = action._is_toggled()
|
||||||
|
|
||||||
|
func _on_action_text_changed():
|
||||||
|
if !icon:
|
||||||
|
text = action._get_text()
|
||||||
|
hint_tooltip = action._get_text()
|
||||||
|
|
||||||
|
func _on_action_icon_changed():
|
||||||
|
icon = action._get_icon()
|
||||||
|
_on_action_text_changed() # update hint/text
|
||||||
|
|
||||||
|
###########
|
||||||
|
# setters #
|
||||||
|
###########
|
||||||
|
func _set_action(value : UIB_Action):
|
||||||
|
if value != action:
|
||||||
|
__disconnect()
|
||||||
|
action = value
|
||||||
|
if action:
|
||||||
|
icon = action._get_icon()
|
||||||
|
if !icon:
|
||||||
|
text = action._get_text()
|
||||||
|
hint_tooltip = action._get_text()
|
||||||
|
disabled = action._is_disabled()
|
||||||
|
toggle_mode = action._is_toggled()
|
||||||
|
pressed = action._is_toggled()
|
||||||
|
__connect()
|
||||||
|
else:
|
||||||
|
icon = null
|
||||||
|
text = ""
|
||||||
|
hint_tooltip = ""
|
||||||
|
disabled = true
|
||||||
|
toggle_mode = false
|
||||||
|
pressed = false
|
57
scripts/types/controls/action_menu_button.gd
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
extends MenuButton
|
||||||
|
|
||||||
|
class_name UIB_ActionMenuButton
|
||||||
|
|
||||||
|
onready var __popup := get_popup()
|
||||||
|
|
||||||
|
#############
|
||||||
|
# overrides #
|
||||||
|
#############
|
||||||
|
func _ready():
|
||||||
|
for child in get_children():
|
||||||
|
if child is UIB_Action:
|
||||||
|
add_action(child)
|
||||||
|
elif child is UIB_Seperator:
|
||||||
|
add_seperator(child)
|
||||||
|
elif child.has_method("get_action"):
|
||||||
|
add_action(child.get_action())
|
||||||
|
|
||||||
|
connect("about_to_show", self, "_on_about_to_show")
|
||||||
|
__popup.connect("index_pressed", self, "_on_popup_index_pressed")
|
||||||
|
|
||||||
|
################
|
||||||
|
# public stuff #
|
||||||
|
################
|
||||||
|
func add_action(action : UIB_Action):
|
||||||
|
if !action:
|
||||||
|
return
|
||||||
|
|
||||||
|
var idx = __popup.get_item_count()
|
||||||
|
__popup.add_item(action._get_text())
|
||||||
|
__popup.set_item_metadata(idx, action)
|
||||||
|
|
||||||
|
func add_seperator(seperator : UIB_Seperator):
|
||||||
|
__popup.add_separator(seperator.text)
|
||||||
|
|
||||||
|
############
|
||||||
|
# handlers #
|
||||||
|
############
|
||||||
|
func _on_about_to_show():
|
||||||
|
for i in range(__popup.get_item_count()):
|
||||||
|
var action := __popup.get_item_metadata(i) as UIB_Action
|
||||||
|
if !action:
|
||||||
|
continue
|
||||||
|
|
||||||
|
action._update()
|
||||||
|
__popup.set_item_text(i, action._get_text())
|
||||||
|
__popup.set_item_icon(i, action._get_icon())
|
||||||
|
__popup.set_item_shortcut(i, action._get_shortcut())
|
||||||
|
__popup.set_item_disabled(i, action._is_disabled())
|
||||||
|
__popup.set_item_as_checkable(i, action._is_toggleable())
|
||||||
|
__popup.set_item_checked(i, action._is_toggled())
|
||||||
|
|
||||||
|
func _on_popup_index_pressed(index : int):
|
||||||
|
var action := __popup.get_item_metadata(index) as UIB_Action
|
||||||
|
if !action:
|
||||||
|
return
|
||||||
|
action._apply()
|
50
scripts/types/controls/action_popup_menu.gd
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
extends PopupMenu
|
||||||
|
|
||||||
|
class_name UIB_ActionPopupMenu
|
||||||
|
|
||||||
|
#############
|
||||||
|
# overrides #
|
||||||
|
#############
|
||||||
|
func _ready():
|
||||||
|
for child in get_children():
|
||||||
|
if child is UIB_Action:
|
||||||
|
add_action(child)
|
||||||
|
elif child.has_method("get_action"):
|
||||||
|
add_action(child.get_action())
|
||||||
|
|
||||||
|
connect("about_to_show", self, "_on_about_to_show")
|
||||||
|
connect("index_pressed", self, "_on_popup_index_pressed")
|
||||||
|
|
||||||
|
################
|
||||||
|
# public stuff #
|
||||||
|
################
|
||||||
|
func add_action(action : UIB_Action):
|
||||||
|
if !action:
|
||||||
|
return
|
||||||
|
|
||||||
|
var idx = get_item_count()
|
||||||
|
add_item(action._get_text())
|
||||||
|
set_item_metadata(idx, action)
|
||||||
|
|
||||||
|
############
|
||||||
|
# handlers #
|
||||||
|
############
|
||||||
|
func _on_about_to_show():
|
||||||
|
for i in range(get_item_count()):
|
||||||
|
var action := get_item_metadata(i) as UIB_Action
|
||||||
|
if !action:
|
||||||
|
continue
|
||||||
|
|
||||||
|
action._update()
|
||||||
|
set_item_text(i, action._get_text())
|
||||||
|
set_item_icon(i, action._get_icon())
|
||||||
|
set_item_shortcut(i, action._get_shortcut())
|
||||||
|
set_item_disabled(i, action._is_disabled())
|
||||||
|
set_item_as_checkable(i, action._is_toggleable())
|
||||||
|
set_item_checked(i, action._is_toggled())
|
||||||
|
|
||||||
|
func _on_popup_index_pressed(index : int):
|
||||||
|
var action := get_item_metadata(index) as UIB_Action
|
||||||
|
if !action:
|
||||||
|
return
|
||||||
|
action._apply()
|
29
scripts/types/controls/action_toolbar.gd
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
extends BoxContainer
|
||||||
|
|
||||||
|
class_name UIB_ActionToolbar
|
||||||
|
|
||||||
|
#############
|
||||||
|
# overrides #
|
||||||
|
#############
|
||||||
|
func _ready():
|
||||||
|
for child in get_children():
|
||||||
|
if child is UIB_Action:
|
||||||
|
add_action(child)
|
||||||
|
elif child.has_method("get_action"):
|
||||||
|
add_action(child.get_action())
|
||||||
|
|
||||||
|
################
|
||||||
|
# public stuff #
|
||||||
|
################
|
||||||
|
func add_action(action : UIB_Action):
|
||||||
|
var btn = ToolButton.new()
|
||||||
|
btn.set_script(preload("res://addons/de.mewin.gduibasics/scripts/types/controls/action_button.gd"))
|
||||||
|
btn.action = action
|
||||||
|
call_deferred("add_child", btn)
|
||||||
|
|
||||||
|
func remove_action(action : UIB_Action):
|
||||||
|
for child in get_children():
|
||||||
|
if child == action || child.get("action") == action \
|
||||||
|
|| (child is UIB_ActionReference && child.get_action() == action):
|
||||||
|
remove_child(child)
|
||||||
|
child.queue_free()
|
250
scripts/types/controls/border_container.gd
Normal file
@ -0,0 +1,250 @@
|
|||||||
|
tool
|
||||||
|
extends MarginContainer
|
||||||
|
|
||||||
|
class_name UIB_BorderContainer
|
||||||
|
|
||||||
|
enum __MouseMode {
|
||||||
|
NONE,
|
||||||
|
MOVING,
|
||||||
|
RESIZE_L,
|
||||||
|
RESIZE_R,
|
||||||
|
RESIZE_T,
|
||||||
|
RESIZE_B,
|
||||||
|
RESIZE_TL,
|
||||||
|
RESIZE_TR,
|
||||||
|
RESIZE_BL,
|
||||||
|
RESIZE_BR
|
||||||
|
}
|
||||||
|
|
||||||
|
export var resizable := true
|
||||||
|
export var show_title := false setget _set_show_title
|
||||||
|
export var title := "" setget _set_title
|
||||||
|
export var grab_everywhere := false
|
||||||
|
export(Texture) var title_image = null
|
||||||
|
export(StyleBox) var style_left setget _set_style_left
|
||||||
|
export(StyleBox) var style_right setget _set_style_right
|
||||||
|
export(StyleBox) var style_top setget _set_style_top
|
||||||
|
export(StyleBox) var style_bottom setget _set_style_bottom
|
||||||
|
|
||||||
|
var __mouse_mode = __MouseMode.NONE
|
||||||
|
var __mouse_down_pos : Vector2
|
||||||
|
|
||||||
|
#############
|
||||||
|
# overrides #
|
||||||
|
#############
|
||||||
|
func _gui_input(event):
|
||||||
|
if event is InputEventMouseButton && event.pressed && event.button_index == BUTTON_LEFT:
|
||||||
|
if resizable:
|
||||||
|
__mouse_mode = __resize_mode(event.position)
|
||||||
|
if __mouse_mode != __MouseMode.NONE:
|
||||||
|
__mouse_down_pos = _win_get_mouse_position() - _win_get_position()
|
||||||
|
if __mouse_mode == __MouseMode.RESIZE_B || __mouse_mode == __MouseMode.RESIZE_BL || __mouse_mode == __MouseMode.RESIZE_BR:
|
||||||
|
__mouse_down_pos.y -= _win_get_size().y
|
||||||
|
if __mouse_mode == __MouseMode.RESIZE_R || __mouse_mode == __MouseMode.RESIZE_TR || __mouse_mode == __MouseMode.RESIZE_BR:
|
||||||
|
__mouse_down_pos.x -= _win_get_size().x
|
||||||
|
set_process(true)
|
||||||
|
return
|
||||||
|
if grab_everywhere || event.position.y < __get_margin("top"):
|
||||||
|
__mouse_mode = __MouseMode.MOVING
|
||||||
|
__mouse_down_pos = _win_get_mouse_position() - _win_get_position()
|
||||||
|
set_process(true)
|
||||||
|
accept_event()
|
||||||
|
elif event is InputEventMouseMotion && resizable:
|
||||||
|
match __resize_mode(event.position):
|
||||||
|
__MouseMode.RESIZE_L, __MouseMode.RESIZE_R:
|
||||||
|
mouse_default_cursor_shape = CURSOR_HSIZE
|
||||||
|
__MouseMode.RESIZE_T, __MouseMode.RESIZE_B:
|
||||||
|
mouse_default_cursor_shape = CURSOR_VSIZE
|
||||||
|
__MouseMode.RESIZE_TL, __MouseMode.RESIZE_BR:
|
||||||
|
mouse_default_cursor_shape = CURSOR_FDIAGSIZE
|
||||||
|
__MouseMode.RESIZE_TR, __MouseMode.RESIZE_BL:
|
||||||
|
mouse_default_cursor_shape = CURSOR_BDIAGSIZE
|
||||||
|
_:
|
||||||
|
mouse_default_cursor_shape = CURSOR_ARROW
|
||||||
|
|
||||||
|
func _process(delta):
|
||||||
|
if !Input.is_mouse_button_pressed(BUTTON_LEFT):
|
||||||
|
__mouse_mode = __MouseMode.NONE
|
||||||
|
|
||||||
|
if __mouse_mode == __MouseMode.NONE:
|
||||||
|
set_process(false)
|
||||||
|
return
|
||||||
|
|
||||||
|
if __mouse_mode == __MouseMode.MOVING:
|
||||||
|
_win_set_position(_win_get_mouse_position() - __mouse_down_pos)
|
||||||
|
return
|
||||||
|
|
||||||
|
var win_pos := _win_get_position()
|
||||||
|
var win_size := _win_get_size()
|
||||||
|
var win_min_size := _win_get_minimum_size()
|
||||||
|
var mouse_pos := _win_get_mouse_position()
|
||||||
|
|
||||||
|
if __mouse_mode == __MouseMode.RESIZE_L || __mouse_mode == __MouseMode.RESIZE_TL || __mouse_mode == __MouseMode.RESIZE_BL:
|
||||||
|
var global_right := win_pos.x + win_size.x
|
||||||
|
var x_pos := mouse_pos.x - __mouse_down_pos.x
|
||||||
|
x_pos = min(x_pos, win_pos.x + win_size.x - win_min_size.x)
|
||||||
|
win_pos.x = x_pos
|
||||||
|
win_size.x = global_right - win_pos.x
|
||||||
|
elif __mouse_mode == __MouseMode.RESIZE_R || __mouse_mode == __MouseMode.RESIZE_TR || __mouse_mode == __MouseMode.RESIZE_BR:
|
||||||
|
var x_pos := mouse_pos.x - __mouse_down_pos.x
|
||||||
|
win_size.x = x_pos - win_pos.x
|
||||||
|
win_size.x = max(win_size.x, win_min_size.x)
|
||||||
|
|
||||||
|
if __mouse_mode == __MouseMode.RESIZE_T || __mouse_mode == __MouseMode.RESIZE_TL || __mouse_mode == __MouseMode.RESIZE_TR:
|
||||||
|
var global_bottom := win_pos.y + win_size.y
|
||||||
|
var y_pos := mouse_pos.y - __mouse_down_pos.y
|
||||||
|
y_pos = min(y_pos, win_pos.y + win_size.y - win_min_size.y)
|
||||||
|
win_pos.y = y_pos
|
||||||
|
win_size.y = global_bottom - win_pos.y
|
||||||
|
elif __mouse_mode == __MouseMode.RESIZE_B || __mouse_mode == __MouseMode.RESIZE_BL || __mouse_mode == __MouseMode.RESIZE_BR:
|
||||||
|
var y_pos := mouse_pos.y - __mouse_down_pos.y
|
||||||
|
win_size.y = y_pos - win_pos.y
|
||||||
|
win_size.y = max(win_size.y, win_min_size.y)
|
||||||
|
|
||||||
|
_win_set_position(win_pos)
|
||||||
|
_win_set_size(win_size)
|
||||||
|
|
||||||
|
func _draw():
|
||||||
|
var marg_left = __get_margin("left")
|
||||||
|
var marg_right = __get_margin("right")
|
||||||
|
var marg_top = __get_margin("top")
|
||||||
|
var marg_bottom = __get_margin("bottom")
|
||||||
|
|
||||||
|
if show_title:
|
||||||
|
var title_height := 0
|
||||||
|
if title_image:
|
||||||
|
# title_height = title_image.get_height()
|
||||||
|
title_height = 0.0
|
||||||
|
else:
|
||||||
|
var font := get_font("font", "Label")
|
||||||
|
title_height = font.get_height() + font.get_descent()
|
||||||
|
if marg_top < title_height:
|
||||||
|
marg_top = title_height
|
||||||
|
set("custom_constants/margin_top", marg_top)
|
||||||
|
|
||||||
|
if style_left:
|
||||||
|
var min_size = style_left.get_minimum_size()
|
||||||
|
min_size.x = max(min_size.x, marg_left)
|
||||||
|
draw_style_box(style_left, Rect2(Vector2(), Vector2(min_size.x, rect_size.y)))
|
||||||
|
|
||||||
|
if style_right:
|
||||||
|
var min_size = style_right.get_minimum_size()
|
||||||
|
min_size.x = max(min_size.x, marg_right)
|
||||||
|
draw_style_box(style_right, Rect2(Vector2(rect_size.x - min_size.x, 0.0), Vector2(min_size.x, rect_size.y)))
|
||||||
|
|
||||||
|
if style_top:
|
||||||
|
var min_size = style_top.get_minimum_size()
|
||||||
|
min_size.y = max(min_size.y, marg_top)
|
||||||
|
draw_style_box(style_top, Rect2(Vector2(), Vector2(rect_size.x, min_size.y)))
|
||||||
|
|
||||||
|
if style_bottom:
|
||||||
|
var min_size = style_bottom.get_minimum_size()
|
||||||
|
min_size.y = max(min_size.y, marg_bottom)
|
||||||
|
draw_style_box(style_bottom, Rect2(Vector2(0.0, rect_size.y - min_size.y), Vector2(rect_size.x, min_size.y)))
|
||||||
|
|
||||||
|
if show_title:
|
||||||
|
if title_image:
|
||||||
|
draw_texture(title_image, Vector2(0.5 * (rect_size.x - title_image.get_width()), 0.0))
|
||||||
|
else:
|
||||||
|
var font := get_font("font", "Label")
|
||||||
|
var string_size := font.get_string_size(title)
|
||||||
|
draw_string(font, Vector2(0.5 * (rect_size.x - string_size.x), string_size.y), title)
|
||||||
|
|
||||||
|
################
|
||||||
|
# overridables #
|
||||||
|
################
|
||||||
|
func _win_get_position() -> Vector2:
|
||||||
|
return get_parent().rect_global_position
|
||||||
|
|
||||||
|
func _win_get_size() -> Vector2:
|
||||||
|
return get_parent().rect_size
|
||||||
|
|
||||||
|
func _win_get_mouse_position() -> Vector2:
|
||||||
|
return get_viewport().get_mouse_position()
|
||||||
|
|
||||||
|
func _win_get_minimum_size() -> Vector2:
|
||||||
|
return get_parent().rect_min_size
|
||||||
|
|
||||||
|
func _win_set_position(pos : Vector2):
|
||||||
|
get_parent().rect_global_position = pos
|
||||||
|
|
||||||
|
func _win_set_size(size : Vector2):
|
||||||
|
get_parent().rect_size = size
|
||||||
|
|
||||||
|
#################
|
||||||
|
# private stuff #
|
||||||
|
#################
|
||||||
|
func __get_margin(what : String) -> int:
|
||||||
|
var marg = get("custom_constants/margin_%s" % what)
|
||||||
|
if !marg:
|
||||||
|
return 0
|
||||||
|
return marg
|
||||||
|
|
||||||
|
func __resize_mode(cursor_pos : Vector2):
|
||||||
|
var resize_left := false
|
||||||
|
var resize_right := false
|
||||||
|
var resize_top := false
|
||||||
|
var resize_bottom := false
|
||||||
|
|
||||||
|
if cursor_pos.y < __get_margin("bottom"):
|
||||||
|
resize_top = true
|
||||||
|
elif cursor_pos.y > rect_size.y - __get_margin("bottom"):
|
||||||
|
resize_bottom = true
|
||||||
|
if cursor_pos.x < __get_margin("left"):
|
||||||
|
resize_left = true
|
||||||
|
elif cursor_pos.x > rect_size.x - __get_margin("right"):
|
||||||
|
resize_right = true
|
||||||
|
|
||||||
|
if resize_top:
|
||||||
|
if resize_left:
|
||||||
|
return __MouseMode.RESIZE_TL
|
||||||
|
elif resize_right:
|
||||||
|
return __MouseMode.RESIZE_TR
|
||||||
|
else:
|
||||||
|
return __MouseMode.RESIZE_T
|
||||||
|
elif resize_bottom:
|
||||||
|
if resize_left:
|
||||||
|
return __MouseMode.RESIZE_BL
|
||||||
|
elif resize_right:
|
||||||
|
return __MouseMode.RESIZE_BR
|
||||||
|
else:
|
||||||
|
return __MouseMode.RESIZE_B
|
||||||
|
elif resize_left:
|
||||||
|
return __MouseMode.RESIZE_L
|
||||||
|
elif resize_right:
|
||||||
|
return __MouseMode.RESIZE_R
|
||||||
|
else:
|
||||||
|
return __MouseMode.NONE
|
||||||
|
|
||||||
|
###########
|
||||||
|
# setters #
|
||||||
|
###########
|
||||||
|
func _set_show_title(val : bool):
|
||||||
|
if val != show_title:
|
||||||
|
show_title = val
|
||||||
|
update()
|
||||||
|
|
||||||
|
func _set_title(val : String):
|
||||||
|
if val != title:
|
||||||
|
title = val
|
||||||
|
update()
|
||||||
|
|
||||||
|
func _set_style_left(val : StyleBox):
|
||||||
|
if val != style_left:
|
||||||
|
style_left = val
|
||||||
|
update()
|
||||||
|
|
||||||
|
func _set_style_right(val : StyleBox):
|
||||||
|
if val != style_right:
|
||||||
|
style_right = val
|
||||||
|
update()
|
||||||
|
|
||||||
|
func _set_style_top(val : StyleBox):
|
||||||
|
if val != style_top:
|
||||||
|
style_top = val
|
||||||
|
update()
|
||||||
|
|
||||||
|
func _set_style_bottom(val : StyleBox):
|
||||||
|
if val != style_bottom:
|
||||||
|
style_bottom = val
|
||||||
|
update()
|
95
scripts/types/controls/dynamic_grid_container.gd
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
tool
|
||||||
|
extends Container
|
||||||
|
|
||||||
|
class_name UIB_DynamicGridContainer
|
||||||
|
|
||||||
|
var __DEFAULT_CONSTRAINTS = UIB_DynamicGridConstraints.new()
|
||||||
|
|
||||||
|
export(int, 1, 100) var columns := 1 setget _set_columns
|
||||||
|
|
||||||
|
func _notification(what):
|
||||||
|
if what == NOTIFICATION_SORT_CHILDREN:
|
||||||
|
__sort_children()
|
||||||
|
|
||||||
|
func __get_constraints(node : Node) -> UIB_DynamicGridConstraints:
|
||||||
|
for child in node.get_children():
|
||||||
|
if child is UIB_DynamicGridConstraints:
|
||||||
|
return child
|
||||||
|
return __DEFAULT_CONSTRAINTS
|
||||||
|
|
||||||
|
func __sort_children():
|
||||||
|
var column_widths := []
|
||||||
|
var column_expand := []
|
||||||
|
|
||||||
|
for i in range(columns):
|
||||||
|
column_widths.append(0)
|
||||||
|
column_expand.append(0.0)
|
||||||
|
|
||||||
|
var rows := [[]]
|
||||||
|
var col := 0
|
||||||
|
var row_width := 0.0
|
||||||
|
|
||||||
|
for child in get_children():
|
||||||
|
if !child is Control || !child.visible:
|
||||||
|
continue
|
||||||
|
var constraints := __get_constraints(child)
|
||||||
|
|
||||||
|
if col + constraints.colspan > columns:
|
||||||
|
col = 0
|
||||||
|
row_width = 0.0
|
||||||
|
rows.append([])
|
||||||
|
|
||||||
|
rows[rows.size() - 1].append(child)
|
||||||
|
|
||||||
|
child.rect_size = child.get_combined_minimum_size()
|
||||||
|
column_widths[col] = max(column_widths[col], child.rect_size.x)
|
||||||
|
|
||||||
|
if child.size_flags_horizontal & Control.SIZE_EXPAND:
|
||||||
|
column_expand[col] = max(column_expand[col], child.size_flags_stretch_ratio)
|
||||||
|
row_width += child.rect_size.x
|
||||||
|
|
||||||
|
col = col + constraints.colspan
|
||||||
|
|
||||||
|
var full_width := 0.0
|
||||||
|
for col_width in column_widths:
|
||||||
|
full_width += col_width
|
||||||
|
var remaining_width := rect_size.x - full_width
|
||||||
|
if remaining_width > 0.0:
|
||||||
|
var combined_expand_ratio := 0.0
|
||||||
|
for expand in column_expand:
|
||||||
|
combined_expand_ratio += expand
|
||||||
|
if combined_expand_ratio > 0.0:
|
||||||
|
for c in range(columns):
|
||||||
|
column_widths[c] += remaining_width * (column_expand[c] / combined_expand_ratio)
|
||||||
|
|
||||||
|
var pos := Vector2()
|
||||||
|
for row in rows:
|
||||||
|
var row_height := 0.0
|
||||||
|
col = 0
|
||||||
|
for child in row:
|
||||||
|
var constraints := __get_constraints(child)
|
||||||
|
child.rect_position = pos
|
||||||
|
|
||||||
|
var width := 0.0
|
||||||
|
for i in range(min(constraints.colspan, columns - col)):
|
||||||
|
width += column_widths[col + i]
|
||||||
|
|
||||||
|
if child.size_flags_horizontal & Control.SIZE_FILL:
|
||||||
|
child.rect_size.x = width
|
||||||
|
pos.x += width
|
||||||
|
|
||||||
|
row_height = max(row_height, child.rect_size.y)
|
||||||
|
col = col + constraints.colspan
|
||||||
|
|
||||||
|
for child in row:
|
||||||
|
if child.size_flags_vertical & Control.SIZE_FILL:
|
||||||
|
child.rect_size.y = row_height
|
||||||
|
|
||||||
|
pos.y += row_height
|
||||||
|
pos.x = 0.0
|
||||||
|
rect_min_size.y = pos.y
|
||||||
|
|
||||||
|
func _set_columns(value : int):
|
||||||
|
if value != columns:
|
||||||
|
columns = value
|
||||||
|
__sort_children()
|
57
scripts/types/controls/editor_inspector_category.gd
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
extends Control
|
||||||
|
|
||||||
|
class_name UIB_EditorInspectorCategory
|
||||||
|
|
||||||
|
var label := "" setget _set_label
|
||||||
|
var icon : Texture setget _set_icon
|
||||||
|
onready var bg_color := get_color("prop_category", "Editor") setget _set_bg_color
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
update()
|
||||||
|
|
||||||
|
func _draw():
|
||||||
|
draw_rect(Rect2(Vector2(), get_size()), bg_color)
|
||||||
|
var font := get_font("font", "Tree")
|
||||||
|
|
||||||
|
var hs := get_constant("hseparation", "Tree")
|
||||||
|
|
||||||
|
var w := font.get_string_size(label).x
|
||||||
|
if icon:
|
||||||
|
w += hs + icon.get_width()
|
||||||
|
|
||||||
|
var ofs := (get_size().x - w) / 2
|
||||||
|
|
||||||
|
if icon:
|
||||||
|
draw_texture(icon, Vector2(ofs, (get_size().y - icon.get_height()) / 2).floor())
|
||||||
|
ofs += hs + icon.get_width()
|
||||||
|
|
||||||
|
var color := get_color("font_color", "Tree");
|
||||||
|
draw_string(font, Vector2(ofs, font.get_ascent() + (get_size().y - font.get_height()) / 2).floor(), label, color, get_size().x)
|
||||||
|
|
||||||
|
func _get_minimum_size() -> Vector2:
|
||||||
|
var ms : Vector2
|
||||||
|
var font := get_font("font", "Tree");
|
||||||
|
|
||||||
|
ms.x = 1
|
||||||
|
ms.y = font.get_height()
|
||||||
|
# if (icon.is_valid()) {
|
||||||
|
# ms.height = MAX(icon->get_height(), ms.height);
|
||||||
|
# }
|
||||||
|
ms.y += get_constant("vseparation", "Tree")
|
||||||
|
|
||||||
|
return ms
|
||||||
|
|
||||||
|
func _set_label(value : String):
|
||||||
|
if value != label:
|
||||||
|
label = value
|
||||||
|
update()
|
||||||
|
|
||||||
|
func _set_icon(value : Texture):
|
||||||
|
if value != icon:
|
||||||
|
icon = value
|
||||||
|
update()
|
||||||
|
|
||||||
|
func _set_bg_color(value : Color):
|
||||||
|
if value != bg_color:
|
||||||
|
bg_color = value
|
||||||
|
update()
|
203
scripts/types/controls/editor_node_tree.gd
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
tool
|
||||||
|
extends Tree
|
||||||
|
|
||||||
|
class_name UIB_EditorNodeTree
|
||||||
|
|
||||||
|
var __tree : Tree
|
||||||
|
var selected_node : NodePath setget _set_selected_node
|
||||||
|
var node_type_filter = Node
|
||||||
|
|
||||||
|
export var show_properties := false
|
||||||
|
export var show_methods := false
|
||||||
|
|
||||||
|
#############
|
||||||
|
# overrides #
|
||||||
|
#############
|
||||||
|
func _ready():
|
||||||
|
assert(Engine.editor_hint)
|
||||||
|
update()
|
||||||
|
connect("visibility_changed", self, "_on_visiblity_changed")
|
||||||
|
connect("item_selected", self, "_on_item_selected")
|
||||||
|
|
||||||
|
################
|
||||||
|
# public stuff #
|
||||||
|
################
|
||||||
|
func update():
|
||||||
|
if !__tree:
|
||||||
|
var scene_tree_editor := GDBUIUtility.find_scene_tree_editor()
|
||||||
|
if !scene_tree_editor:
|
||||||
|
return
|
||||||
|
__tree = __find_tree(scene_tree_editor)
|
||||||
|
if !__tree:
|
||||||
|
return
|
||||||
|
__copy_from(__tree)
|
||||||
|
if !selected_node.is_empty():
|
||||||
|
var full_path := __full_path(selected_node)
|
||||||
|
if !full_path.is_empty():
|
||||||
|
__set_selected_node(full_path, get_root())
|
||||||
|
|
||||||
|
#################
|
||||||
|
# private stuff #
|
||||||
|
#################
|
||||||
|
func __copy_from(tree : Tree):
|
||||||
|
clear()
|
||||||
|
columns = tree.columns
|
||||||
|
__copy_items(tree.get_root())
|
||||||
|
|
||||||
|
func __copy_items(item : TreeItem, parent : TreeItem = null):
|
||||||
|
if !item:
|
||||||
|
return
|
||||||
|
|
||||||
|
var new_item := create_item(parent)
|
||||||
|
for i in range(columns):
|
||||||
|
new_item.set_text(i, item.get_text(i))
|
||||||
|
new_item.set_icon(i, item.get_icon(i))
|
||||||
|
new_item.set_metadata(i, item.get_metadata(i))
|
||||||
|
var meta0 = item.get_metadata(0)
|
||||||
|
if meta0 is NodePath:
|
||||||
|
if show_properties:
|
||||||
|
var prop_item := create_item(new_item)
|
||||||
|
prop_item.set_text(0, tr("Properties"))
|
||||||
|
__fill_node_path_properties(prop_item, meta0)
|
||||||
|
prop_item.collapsed = true
|
||||||
|
prop_item.set_selectable(0, false)
|
||||||
|
if show_methods:
|
||||||
|
var method_item := create_item(new_item)
|
||||||
|
method_item.set_text(0, tr("Methods"))
|
||||||
|
__fill_methods(method_item, meta0)
|
||||||
|
method_item.collapsed = true
|
||||||
|
method_item.set_selectable(0, false)
|
||||||
|
var node : Node = get_node(meta0)
|
||||||
|
if !node is node_type_filter:
|
||||||
|
new_item.set_selectable(0, false)
|
||||||
|
else:
|
||||||
|
new_item.set_selectable(0, false)
|
||||||
|
if !new_item.is_selectable(0):
|
||||||
|
new_item.set_custom_color(0, Color.darkgray)
|
||||||
|
__copy_items(item.get_children(), new_item)
|
||||||
|
__copy_items(item.get_next(), parent)
|
||||||
|
|
||||||
|
func __fill_node_path_properties(parent : TreeItem, node_path : NodePath):
|
||||||
|
assert(node_path.is_absolute())
|
||||||
|
var node := get_node_or_null(node_path)
|
||||||
|
if !node:
|
||||||
|
return
|
||||||
|
__fill_properties(parent, node.get_property_list(), node_path)
|
||||||
|
|
||||||
|
func __fill_properties(parent : TreeItem, properties : Array, parent_path : NodePath):
|
||||||
|
GDBAlgorithm.remove_if(properties, 'return prop.get("usage", PROPERTY_USAGE_EDITOR) & PROPERTY_USAGE_EDITOR == 0', ["prop"])
|
||||||
|
GDBAlgorithm.sort_by(properties, "name")
|
||||||
|
for prop in properties:
|
||||||
|
var prop_item := create_item(parent)
|
||||||
|
var node_path := NodePath(str(parent_path) + ":" + prop["name"])
|
||||||
|
prop_item.set_text(0, "%s : %s" % [prop["name"], GDBUtility.format_type(prop, "any")])
|
||||||
|
prop_item.set_metadata(0, node_path)
|
||||||
|
__fill_properties(prop_item, GDBUtility.get_type_property_list(prop), node_path)
|
||||||
|
prop_item.collapsed = true
|
||||||
|
|
||||||
|
func __fill_methods(parent : TreeItem, node_path : NodePath):
|
||||||
|
assert(node_path.is_absolute())
|
||||||
|
var node := get_node_or_null(node_path)
|
||||||
|
if !node:
|
||||||
|
return
|
||||||
|
var methods := node.get_method_list()
|
||||||
|
GDBAlgorithm.sort_by(methods, "name")
|
||||||
|
for method in methods:
|
||||||
|
var method_item := create_item(parent)
|
||||||
|
method_item.set_text(0, GDBUtility.format_method_signature(method))
|
||||||
|
|
||||||
|
func __find_tree(root : Node) -> Tree:
|
||||||
|
if root is Tree:
|
||||||
|
return root as Tree
|
||||||
|
for child in root.get_children():
|
||||||
|
var tree := __find_tree(child)
|
||||||
|
if tree:
|
||||||
|
return tree
|
||||||
|
return null
|
||||||
|
|
||||||
|
func __set_selected_node(node : NodePath, root : TreeItem):
|
||||||
|
if !root:
|
||||||
|
return false
|
||||||
|
for i in range(columns):
|
||||||
|
if root.get_metadata(i) == node:
|
||||||
|
GDBUIUtility.uncollapse_tree_item(root)
|
||||||
|
root.select(i)
|
||||||
|
return true
|
||||||
|
if __set_selected_node(node, root.get_children()):
|
||||||
|
return true
|
||||||
|
else:
|
||||||
|
return __set_selected_node(node, root.get_next())
|
||||||
|
|
||||||
|
func __full_path(rel_path : NodePath) -> NodePath:
|
||||||
|
assert(!rel_path.is_absolute())
|
||||||
|
var node := get_tree().edited_scene_root.get_node_or_null(rel_path)
|
||||||
|
if !node:
|
||||||
|
# printerr("EditorNodeTree: could not find node: %s" % rel_path)
|
||||||
|
return NodePath()
|
||||||
|
var res_path := node.get_path()
|
||||||
|
if rel_path.get_subname_count() > 0:
|
||||||
|
res_path = NodePath(str(res_path) + ":" + rel_path.get_concatenated_subnames())
|
||||||
|
return res_path
|
||||||
|
|
||||||
|
func __format_tree_item(tree : Tree, item : TreeItem) -> String:
|
||||||
|
var parts := PoolStringArray()
|
||||||
|
for i in range(tree.columns):
|
||||||
|
parts.append("%s[%s]" % [item.get_text(i), item.get_metadata(i)])
|
||||||
|
return parts.join("|")
|
||||||
|
|
||||||
|
func __dump_tree_item(tree : Tree, item : TreeItem, indent := 0):
|
||||||
|
if !item:
|
||||||
|
return
|
||||||
|
print(" ".repeat(indent), __format_tree_item(tree, item))
|
||||||
|
__dump_tree_item(tree, item.get_children(), indent + 2)
|
||||||
|
__dump_tree_item(tree, item.get_next(), indent)
|
||||||
|
|
||||||
|
func _set_selected_node(value : NodePath):
|
||||||
|
if value == selected_node:
|
||||||
|
return
|
||||||
|
if value.is_empty():
|
||||||
|
var selected_item := get_selected()
|
||||||
|
if selected_item:
|
||||||
|
selected_item.deselect(0)
|
||||||
|
return
|
||||||
|
|
||||||
|
if value.is_absolute():
|
||||||
|
printerr("EditorNodeTree: trying to set absolute NodePath, aborting.")
|
||||||
|
return
|
||||||
|
|
||||||
|
var full_path := __full_path(value)
|
||||||
|
if full_path.is_empty():
|
||||||
|
return
|
||||||
|
__set_selected_node(full_path, get_root())
|
||||||
|
selected_node = value
|
||||||
|
|
||||||
|
############
|
||||||
|
# handlers #
|
||||||
|
############
|
||||||
|
func _on_visiblity_changed():
|
||||||
|
if visible:
|
||||||
|
update()
|
||||||
|
|
||||||
|
func _on_item_selected():
|
||||||
|
var item := get_selected()
|
||||||
|
if !item:
|
||||||
|
selected_node = NodePath()
|
||||||
|
emit_signal("selected_node_changed")
|
||||||
|
return
|
||||||
|
for i in range(columns):
|
||||||
|
var meta = item.get_metadata(i)
|
||||||
|
if meta is NodePath:
|
||||||
|
assert(meta.is_absolute())
|
||||||
|
var node : Node = get_node(meta)
|
||||||
|
if !node:
|
||||||
|
printerr("EditorNodeTree contains invalid node path: %s" % meta)
|
||||||
|
return
|
||||||
|
selected_node = NodePath(str(get_tree().edited_scene_root.get_path_to(node)) + ":" + meta.get_concatenated_subnames())
|
||||||
|
emit_signal("selected_node_changed")
|
||||||
|
return
|
||||||
|
printerr("EditorNodeTree: selected node without NodePath?!")
|
||||||
|
|
||||||
|
###########
|
||||||
|
# signals #
|
||||||
|
###########
|
||||||
|
signal selected_node_changed()
|
280
scripts/types/controls/file_list.gd
Normal file
@ -0,0 +1,280 @@
|
|||||||
|
extends Tree
|
||||||
|
|
||||||
|
class_name UIB_FileList
|
||||||
|
|
||||||
|
enum ViewMode {
|
||||||
|
LIST,
|
||||||
|
DETAILS
|
||||||
|
}
|
||||||
|
enum SpecialColumn {
|
||||||
|
CHECKBOX
|
||||||
|
}
|
||||||
|
enum Checkable {
|
||||||
|
NONE,
|
||||||
|
FILES,
|
||||||
|
FOLDERS,
|
||||||
|
BOTH
|
||||||
|
}
|
||||||
|
|
||||||
|
class DetailsColumn:
|
||||||
|
func _get_name() -> String:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
func _get_value(entry) -> String:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
func _get_expand() -> bool:
|
||||||
|
return false
|
||||||
|
|
||||||
|
func _get_min_width() -> float:
|
||||||
|
return 10.0
|
||||||
|
|
||||||
|
func _compare(entry0, entry1) -> bool:
|
||||||
|
return _get_value(entry0) < _get_value(entry1)
|
||||||
|
|
||||||
|
class DetailsColumnName:
|
||||||
|
extends DetailsColumn
|
||||||
|
func _get_name() -> String:
|
||||||
|
return tr("Name")
|
||||||
|
func _get_value(entry) -> String:
|
||||||
|
return entry._get_name()
|
||||||
|
func _get_expand() -> bool:
|
||||||
|
return true
|
||||||
|
|
||||||
|
class DetailsColumnType:
|
||||||
|
extends DetailsColumn
|
||||||
|
func _get_name() -> String:
|
||||||
|
return tr("Type")
|
||||||
|
func _get_value(entry) -> String:
|
||||||
|
if entry._is_folder():
|
||||||
|
return tr("Folder")
|
||||||
|
else:
|
||||||
|
return tr("File")
|
||||||
|
func _get_min_width() -> float:
|
||||||
|
return 100.0
|
||||||
|
|
||||||
|
class DetailsColumnSize:
|
||||||
|
extends DetailsColumn
|
||||||
|
func _get_name() -> String:
|
||||||
|
return tr("Size")
|
||||||
|
func _get_value(entry) -> String:
|
||||||
|
if entry._is_folder():
|
||||||
|
return ""
|
||||||
|
else:
|
||||||
|
return String.humanize_size(entry._get_size())
|
||||||
|
func _get_min_width() -> float:
|
||||||
|
return 100.0
|
||||||
|
func _compare(entry0, entry1) -> bool:
|
||||||
|
return entry0._get_size() < entry1._get_size()
|
||||||
|
|
||||||
|
class DetailsColumnModifiedTime:
|
||||||
|
extends DetailsColumn
|
||||||
|
func _get_name() -> String:
|
||||||
|
return tr("Modified")
|
||||||
|
func _get_value(entry) -> String:
|
||||||
|
if entry._is_folder():
|
||||||
|
return ""
|
||||||
|
else:
|
||||||
|
return GDBFormat.smart_format_unixtime(entry._get_modified_time())
|
||||||
|
func _get_min_width() -> float:
|
||||||
|
return 150.0
|
||||||
|
func _compare(entry0, entry1) -> bool:
|
||||||
|
return entry0._get_modified_time() < entry1._get_modified_time()
|
||||||
|
|
||||||
|
class __ParentFolderEntry:
|
||||||
|
extends UIB_FileAdapter.FileEntry
|
||||||
|
|
||||||
|
var real_entry
|
||||||
|
|
||||||
|
func _init(real_entry_):
|
||||||
|
real_entry = real_entry_
|
||||||
|
|
||||||
|
func _get_name() -> String:
|
||||||
|
return tr("<up>")
|
||||||
|
|
||||||
|
func _is_folder() -> bool:
|
||||||
|
return true
|
||||||
|
|
||||||
|
const CHECKBOX_COLUMN_WIDTH = 25
|
||||||
|
|
||||||
|
export(ViewMode) var view_mode = ViewMode.DETAILS setget _set_view_mode
|
||||||
|
export(Checkable) var checkable = Checkable.NONE setget _set_checkable
|
||||||
|
export var allow_navigation := true
|
||||||
|
export var show_up_entry := true
|
||||||
|
var adapter : UIB_FileAdapter setget _set_adapter
|
||||||
|
var filter : UIB_FileFilter setget _set_filter
|
||||||
|
var current_folder : UIB_FileAdapter.FileEntry setget _set_current_folder
|
||||||
|
var details_columns := [
|
||||||
|
DetailsColumnName.new(),
|
||||||
|
DetailsColumnType.new(),
|
||||||
|
DetailsColumnSize.new(),
|
||||||
|
DetailsColumnModifiedTime.new()
|
||||||
|
]
|
||||||
|
var __special_columns := []
|
||||||
|
var __sort_column := 0
|
||||||
|
var __sort_reverse := false
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
hide_root = true
|
||||||
|
select_mode = Tree.SELECT_ROW
|
||||||
|
|
||||||
|
if adapter == null:
|
||||||
|
adapter = UIB_LocalFileAdapter.new()
|
||||||
|
|
||||||
|
if current_folder == null:
|
||||||
|
current_folder = adapter._get_root()
|
||||||
|
|
||||||
|
__update_entries()
|
||||||
|
|
||||||
|
connect("item_activated", self, "_on_item_activated")
|
||||||
|
connect("item_selected", self, "_on_item_selected")
|
||||||
|
connect("column_title_pressed", self, "_on_column_title_pressed")
|
||||||
|
|
||||||
|
#################
|
||||||
|
# private stuff #
|
||||||
|
#################
|
||||||
|
func __compare_entries(entry0, entry1):
|
||||||
|
if entry0._is_folder() != entry1._is_folder():
|
||||||
|
return entry0._is_folder()
|
||||||
|
var val = details_columns[__sort_column]._compare(entry0, entry1)
|
||||||
|
if __sort_reverse:
|
||||||
|
return !val
|
||||||
|
return val
|
||||||
|
|
||||||
|
func __update_columns():
|
||||||
|
__special_columns.clear()
|
||||||
|
if checkable != Checkable.NONE:
|
||||||
|
__special_columns.append(SpecialColumn.CHECKBOX)
|
||||||
|
|
||||||
|
match view_mode:
|
||||||
|
_: # DETAILS
|
||||||
|
columns = __special_columns.size() + details_columns.size()
|
||||||
|
set_column_titles_visible(true)
|
||||||
|
for i in range(details_columns.size()):
|
||||||
|
set_column_title(__special_columns.size() + i, details_columns[i]._get_name())
|
||||||
|
set_column_expand(i, details_columns[i]._get_expand())
|
||||||
|
set_column_min_width(i, details_columns[i]._get_min_width())
|
||||||
|
|
||||||
|
for i in range(__special_columns.size()):
|
||||||
|
set_column_title(i, "")
|
||||||
|
set_column_expand(i, false)
|
||||||
|
set_column_min_width(i, CHECKBOX_COLUMN_WIDTH)
|
||||||
|
|
||||||
|
func __entry_is_checkable(entry):
|
||||||
|
match checkable:
|
||||||
|
Checkable.BOTH:
|
||||||
|
return true
|
||||||
|
Checkable.FILES:
|
||||||
|
return !entry._is_folder()
|
||||||
|
Checkable.FOLDERS:
|
||||||
|
return entry._is_folder()
|
||||||
|
_:
|
||||||
|
return false
|
||||||
|
|
||||||
|
func __update_entries():
|
||||||
|
if !current_folder:
|
||||||
|
return
|
||||||
|
|
||||||
|
clear()
|
||||||
|
create_item() # root
|
||||||
|
|
||||||
|
__update_columns()
|
||||||
|
if columns < 1:
|
||||||
|
return
|
||||||
|
|
||||||
|
var entries := current_folder._list_files()
|
||||||
|
entries.sort_custom(self, "__compare_entries")
|
||||||
|
|
||||||
|
if allow_navigation && show_up_entry:
|
||||||
|
var parent_folder = current_folder._get_parent()
|
||||||
|
if parent_folder:
|
||||||
|
entries.push_front(__ParentFolderEntry.new(parent_folder))
|
||||||
|
|
||||||
|
for entry in entries:
|
||||||
|
if filter && !entry._is_folder() && !filter._accepts(entry):
|
||||||
|
continue
|
||||||
|
|
||||||
|
var itm = create_item()
|
||||||
|
for i in range(__special_columns.size()):
|
||||||
|
match __special_columns[i]:
|
||||||
|
SpecialColumn.CHECKBOX:
|
||||||
|
if __entry_is_checkable(entry):
|
||||||
|
itm.set_cell_mode(i, TreeItem.CELL_MODE_CHECK)
|
||||||
|
for i in range(details_columns.size()):
|
||||||
|
itm.set_text(__special_columns.size() + i, details_columns[i]._get_value(entry))
|
||||||
|
itm.set_icon(__special_columns.size(), adapter._get_icon(entry))
|
||||||
|
itm.set_metadata(0, entry)
|
||||||
|
|
||||||
|
###########
|
||||||
|
# setters #
|
||||||
|
###########
|
||||||
|
func _set_view_mode(value):
|
||||||
|
if value != view_mode:
|
||||||
|
view_mode = value
|
||||||
|
__update_entries()
|
||||||
|
|
||||||
|
func _set_adapter(value : UIB_FileAdapter):
|
||||||
|
if value != adapter:
|
||||||
|
adapter = value
|
||||||
|
__update_entries()
|
||||||
|
|
||||||
|
func _set_filter(value : UIB_FileFilter):
|
||||||
|
if value != filter:
|
||||||
|
filter = value
|
||||||
|
__update_entries()
|
||||||
|
|
||||||
|
func _set_current_folder(value : UIB_FileAdapter.FileEntry):
|
||||||
|
if value != current_folder:
|
||||||
|
current_folder = value
|
||||||
|
emit_signal("current_folder_changed")
|
||||||
|
__update_entries()
|
||||||
|
|
||||||
|
func _set_checkable(value):
|
||||||
|
if value != checkable:
|
||||||
|
checkable = value
|
||||||
|
__update_entries()
|
||||||
|
|
||||||
|
############
|
||||||
|
# handlers #
|
||||||
|
############
|
||||||
|
func _on_item_activated():
|
||||||
|
var selected := get_selected()
|
||||||
|
if !selected:
|
||||||
|
return
|
||||||
|
var entry = selected.get_metadata(0)
|
||||||
|
if !entry:
|
||||||
|
return
|
||||||
|
if allow_navigation && entry._is_folder():
|
||||||
|
if entry is __ParentFolderEntry:
|
||||||
|
_set_current_folder(entry.real_entry)
|
||||||
|
else:
|
||||||
|
_set_current_folder(entry)
|
||||||
|
else:
|
||||||
|
emit_signal("file_activated", entry)
|
||||||
|
|
||||||
|
func _on_item_selected():
|
||||||
|
var selected := get_selected()
|
||||||
|
if !selected:
|
||||||
|
return
|
||||||
|
var entry = selected.get_metadata(0)
|
||||||
|
if !entry:
|
||||||
|
return
|
||||||
|
emit_signal("file_selected", entry)
|
||||||
|
|
||||||
|
func _on_column_title_pressed(idx : int):
|
||||||
|
var sort_idx := idx - __special_columns.size()
|
||||||
|
if sort_idx >= details_columns.size():
|
||||||
|
return
|
||||||
|
if sort_idx == __sort_column:
|
||||||
|
__sort_reverse = !__sort_reverse
|
||||||
|
else:
|
||||||
|
__sort_column = sort_idx
|
||||||
|
__sort_reverse = false
|
||||||
|
__update_entries()
|
||||||
|
|
||||||
|
###########
|
||||||
|
# signals #
|
||||||
|
###########
|
||||||
|
signal current_folder_changed()
|
||||||
|
signal file_activated(file_entry)
|
||||||
|
signal file_selected(file_entry)
|
43
scripts/types/controls/flow_container.gd
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
tool
|
||||||
|
extends Container
|
||||||
|
|
||||||
|
const SORT_DELAY = 0.02
|
||||||
|
|
||||||
|
class_name UIB_FlowContainer
|
||||||
|
|
||||||
|
export var use_minimum_size := false
|
||||||
|
export var gap := 0.0
|
||||||
|
|
||||||
|
#############
|
||||||
|
# overrides #
|
||||||
|
#############
|
||||||
|
func _notification(what):
|
||||||
|
if what == NOTIFICATION_SORT_CHILDREN:
|
||||||
|
__sort_children()
|
||||||
|
|
||||||
|
#################
|
||||||
|
# private stuff #
|
||||||
|
#################
|
||||||
|
func __sort_children():
|
||||||
|
var pos := Vector2()
|
||||||
|
var row_height := 0.0
|
||||||
|
var vp_rect := get_viewport_rect()
|
||||||
|
|
||||||
|
for child in get_children():
|
||||||
|
if !child.visible || !child is Control:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if use_minimum_size:
|
||||||
|
child.rect_size = child.get_combined_minimum_size()
|
||||||
|
|
||||||
|
if pos.x > 0.0 && pos.x + child.rect_size.x > rect_size.x:
|
||||||
|
pos.x = 0.0
|
||||||
|
pos.y += row_height + gap
|
||||||
|
row_height = 0.0
|
||||||
|
|
||||||
|
child.rect_position = pos
|
||||||
|
|
||||||
|
row_height = max(row_height, child.rect_size.y)
|
||||||
|
pos.x += child.rect_size.x + gap
|
||||||
|
|
||||||
|
rect_min_size.y = pos.y + row_height
|
79
scripts/types/controls/folder_edit.gd
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
extends LineEdit
|
||||||
|
|
||||||
|
class_name UIB_FolderEdit
|
||||||
|
|
||||||
|
var suggestion_popup := UIB_SuggestionPopup.new()
|
||||||
|
var adapter : UIB_FileAdapter
|
||||||
|
var current_folder : UIB_FileAdapter.FileEntry setget _set_current_folder
|
||||||
|
|
||||||
|
#############
|
||||||
|
# overrides #
|
||||||
|
#############
|
||||||
|
func _ready():
|
||||||
|
call_deferred("__setup")
|
||||||
|
connect("text_changed", self, "_on_text_changed")
|
||||||
|
connect("text_entered", self, "_on_text_entered")
|
||||||
|
|
||||||
|
#################
|
||||||
|
# private stuff #
|
||||||
|
#################
|
||||||
|
func __setup():
|
||||||
|
suggestion_popup.connect("suggestion_accepted", self, "_on_suggestion_accepted")
|
||||||
|
add_child(suggestion_popup)
|
||||||
|
|
||||||
|
func __set_suggestions(files : Array):
|
||||||
|
var suggestions := []
|
||||||
|
|
||||||
|
for file in files:
|
||||||
|
if file._is_folder():
|
||||||
|
suggestions.append(file._get_path() + "/")
|
||||||
|
|
||||||
|
suggestion_popup.suggestions = suggestions
|
||||||
|
|
||||||
|
func __update_suggestions():
|
||||||
|
var folder = adapter._get_file(text)
|
||||||
|
|
||||||
|
if folder && folder._is_folder():
|
||||||
|
__set_suggestions(folder._list_files())
|
||||||
|
return
|
||||||
|
var parent_path = text.get_base_dir()
|
||||||
|
|
||||||
|
if parent_path:
|
||||||
|
folder = adapter._get_file(parent_path)
|
||||||
|
if folder && folder._is_folder():
|
||||||
|
__set_suggestions(folder._list_files())
|
||||||
|
return
|
||||||
|
suggestion_popup.suggestions = []
|
||||||
|
|
||||||
|
func __update_current_folder():
|
||||||
|
var new_file = adapter._get_file(text)
|
||||||
|
if new_file:
|
||||||
|
_set_current_folder(new_file)
|
||||||
|
caret_position = text.length()
|
||||||
|
|
||||||
|
###########
|
||||||
|
# setters #
|
||||||
|
###########
|
||||||
|
func _set_current_folder(value):
|
||||||
|
if value != current_folder:
|
||||||
|
current_folder = value
|
||||||
|
text = current_folder._get_path()
|
||||||
|
emit_signal("current_folder_changed")
|
||||||
|
|
||||||
|
############
|
||||||
|
# handlers #
|
||||||
|
############
|
||||||
|
func _on_text_changed(new_text):
|
||||||
|
__update_suggestions()
|
||||||
|
|
||||||
|
func _on_text_entered(new_text):
|
||||||
|
__update_current_folder()
|
||||||
|
|
||||||
|
func _on_suggestion_accepted(suggestion):
|
||||||
|
__update_current_folder()
|
||||||
|
__update_suggestions()
|
||||||
|
|
||||||
|
###########
|
||||||
|
# signals #
|
||||||
|
###########
|
||||||
|
signal current_folder_changed()
|
104
scripts/types/controls/folder_sync.gd
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
extends Node
|
||||||
|
|
||||||
|
class_name UIB_FolderSync
|
||||||
|
|
||||||
|
enum DefaultFolder {
|
||||||
|
HOME,
|
||||||
|
ROOT,
|
||||||
|
CUSTOM
|
||||||
|
}
|
||||||
|
|
||||||
|
export(Array, NodePath) var nodes = []
|
||||||
|
export(DefaultFolder) var default_folder = DefaultFolder.HOME
|
||||||
|
export(NodePath) var folder_up_action
|
||||||
|
export(NodePath) var folder_favourite_action
|
||||||
|
export var custom_default_folder := ""
|
||||||
|
var adapter : UIB_FileAdapter = UIB_LocalFileAdapter.new()
|
||||||
|
|
||||||
|
var current_folder : UIB_FileAdapter.FileEntry setget set_current_folder
|
||||||
|
var __folder_up_action : UIB_SimpleAction
|
||||||
|
var __folder_favourite_action : UIB_SimpleAction
|
||||||
|
var __nodes := []
|
||||||
|
var __locked := false
|
||||||
|
|
||||||
|
#############
|
||||||
|
# overrides #
|
||||||
|
#############
|
||||||
|
func _ready():
|
||||||
|
__folder_up_action = __get_action(folder_up_action)
|
||||||
|
__folder_favourite_action = __get_action(folder_favourite_action)
|
||||||
|
|
||||||
|
if __folder_up_action:
|
||||||
|
__folder_up_action.connect("applied", self, "_on_folder_up_action")
|
||||||
|
|
||||||
|
if __folder_favourite_action:
|
||||||
|
__folder_favourite_action.connect("applied", self, "_on_folder_favourite_action")
|
||||||
|
|
||||||
|
var folder := "/"
|
||||||
|
match default_folder:
|
||||||
|
DefaultFolder.HOME:
|
||||||
|
folder = GDBFsUtil.get_home_folder()
|
||||||
|
DefaultFolder.CUSTOM:
|
||||||
|
folder = custom_default_folder
|
||||||
|
|
||||||
|
for path in nodes:
|
||||||
|
var node := get_node(path)
|
||||||
|
assert(node)
|
||||||
|
if !node:
|
||||||
|
continue
|
||||||
|
node.adapter = adapter
|
||||||
|
node.connect("current_folder_changed", self, "_on_node_current_folder_changed", [node])
|
||||||
|
__nodes.append(node)
|
||||||
|
|
||||||
|
var folder_entry = adapter._get_file(folder)
|
||||||
|
if folder_entry && folder_entry._is_folder():
|
||||||
|
set_current_folder(folder_entry)
|
||||||
|
|
||||||
|
################
|
||||||
|
# public stuff #
|
||||||
|
################
|
||||||
|
func set_current_folder(folder, ignore_node : Node = null):
|
||||||
|
if __locked:
|
||||||
|
return
|
||||||
|
__locked = true
|
||||||
|
|
||||||
|
for node in __nodes:
|
||||||
|
if node != ignore_node:
|
||||||
|
node.current_folder = folder
|
||||||
|
|
||||||
|
__locked = false
|
||||||
|
current_folder = folder
|
||||||
|
|
||||||
|
if __folder_up_action:
|
||||||
|
__folder_up_action.disabled = !folder || !folder._get_parent()
|
||||||
|
if __folder_favourite_action:
|
||||||
|
__folder_favourite_action.toggled = GDBUX.is_favourite_place(current_folder)
|
||||||
|
|
||||||
|
func __get_action(node_path : NodePath) -> UIB_SimpleAction:
|
||||||
|
var action_node = get_node_or_null(node_path)
|
||||||
|
|
||||||
|
if action_node is UIB_SimpleAction:
|
||||||
|
return action_node
|
||||||
|
elif action_node.has_method("get_action"):
|
||||||
|
return action_node.get_action() as UIB_SimpleAction
|
||||||
|
|
||||||
|
return null
|
||||||
|
|
||||||
|
############
|
||||||
|
# handlers #
|
||||||
|
############
|
||||||
|
func _on_node_current_folder_changed(source_node : Node):
|
||||||
|
set_current_folder(source_node.current_folder, source_node)
|
||||||
|
|
||||||
|
func _on_folder_up_action():
|
||||||
|
var parent = current_folder._get_parent()
|
||||||
|
if parent:
|
||||||
|
set_current_folder(parent)
|
||||||
|
|
||||||
|
func _on_folder_favourite_action():
|
||||||
|
if GDBUX.is_favourite_place(current_folder):
|
||||||
|
GDBUX.remove_favourite_place(current_folder)
|
||||||
|
__folder_favourite_action.toggled = false
|
||||||
|
else:
|
||||||
|
GDBUX.add_favourite_place(current_folder)
|
||||||
|
__folder_favourite_action.toggled = true
|
16
scripts/types/controls/named_tab_container.gd
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
extends TabContainer
|
||||||
|
|
||||||
|
class_name UIB_NamedTabContainer
|
||||||
|
|
||||||
|
export(Array, String) var headers := []
|
||||||
|
export(Array, Texture) var icons := []
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
for i in range(headers.size()):
|
||||||
|
if i >= get_child_count():
|
||||||
|
break
|
||||||
|
set_tab_title(i, headers[i])
|
||||||
|
for i in range(icons.size()):
|
||||||
|
if i >= get_child_count():
|
||||||
|
break
|
||||||
|
set_tab_icon(i, icons[i])
|
122
scripts/types/controls/places_list.gd
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
extends ItemList
|
||||||
|
|
||||||
|
class_name UIB_PlacesList
|
||||||
|
|
||||||
|
enum Mode {
|
||||||
|
DEFAULT,
|
||||||
|
# FAVOURITES,
|
||||||
|
CUSTOM
|
||||||
|
}
|
||||||
|
|
||||||
|
class __DefaultItem:
|
||||||
|
var place : String
|
||||||
|
var icon : Texture
|
||||||
|
var label : String
|
||||||
|
|
||||||
|
func _init(place_ : String, icon_ : Texture, label_ : String):
|
||||||
|
place = place_
|
||||||
|
icon = icon_
|
||||||
|
label = label_
|
||||||
|
|
||||||
|
var __DEFAULT_ITEMS := [
|
||||||
|
__DefaultItem.new(GDBFsUtil.get_home_folder(), preload("res://addons/de.mewin.gduibasics/images/home32.svg"), tr("Home"))
|
||||||
|
]
|
||||||
|
|
||||||
|
export(Mode) var mode = Mode.DEFAULT setget _set_mode
|
||||||
|
export(Array, String) var places := [] setget _set_places
|
||||||
|
export(Array, Texture) var icons := []
|
||||||
|
export(Array, String) var names := []
|
||||||
|
|
||||||
|
var adapter : UIB_FileAdapter
|
||||||
|
var current_folder : UIB_FileAdapter.FileEntry setget _set_current_folder
|
||||||
|
|
||||||
|
#############
|
||||||
|
# overrides #
|
||||||
|
#############
|
||||||
|
func _ready():
|
||||||
|
call_deferred("__update_items")
|
||||||
|
|
||||||
|
connect("item_activated", self, "_on_item_activated")
|
||||||
|
GDBUX.connect_static("favourite_places_changed", self, "_on_favourite_places_changed")
|
||||||
|
|
||||||
|
#################
|
||||||
|
# private stuff #
|
||||||
|
#################
|
||||||
|
func __update_items():
|
||||||
|
clear()
|
||||||
|
if !adapter:
|
||||||
|
return
|
||||||
|
|
||||||
|
match mode:
|
||||||
|
Mode.DEFAULT:
|
||||||
|
__add_default_places()
|
||||||
|
_:
|
||||||
|
__add_custom_places()
|
||||||
|
|
||||||
|
func __add_default_places():
|
||||||
|
for default_place in __DEFAULT_ITEMS:
|
||||||
|
var folder := adapter._get_file(default_place.place)
|
||||||
|
if !folder || !folder._is_folder():
|
||||||
|
continue
|
||||||
|
__add_place(folder, default_place.icon, default_place.label)
|
||||||
|
|
||||||
|
for favourite in GDBUX.get_favourite_places():
|
||||||
|
var folder := adapter._get_file(favourite)
|
||||||
|
if !folder || !folder._is_folder():
|
||||||
|
continue
|
||||||
|
__add_place(folder, preload("res://addons/de.mewin.gduibasics/images/favourite32.svg"))
|
||||||
|
|
||||||
|
func __add_custom_places():
|
||||||
|
for i in range(places.size()):
|
||||||
|
var folder = adapter._get_file(places[i])
|
||||||
|
if !folder || !folder._is_folder():
|
||||||
|
continue
|
||||||
|
var label : String = names[i] if i < names.size() else ""
|
||||||
|
var icon : Texture = icons[i] if i < icons.size() else null
|
||||||
|
__add_place(folder, icon, label)
|
||||||
|
|
||||||
|
func __add_place(folder : UIB_FileAdapter.FileEntry, icon : Texture, label := ""):
|
||||||
|
if !icon:
|
||||||
|
icon = preload("res://addons/de.mewin.gduibasics/images/folder32.svg")
|
||||||
|
if !label:
|
||||||
|
label = folder._get_name()
|
||||||
|
var idx = get_item_count()
|
||||||
|
add_item(label, icon)
|
||||||
|
set_item_metadata(idx, folder)
|
||||||
|
|
||||||
|
func __select_current_folder():
|
||||||
|
for i in range(get_item_count()):
|
||||||
|
if get_item_metadata(i)._get_path() == current_folder._get_path():
|
||||||
|
select(i)
|
||||||
|
|
||||||
|
###########
|
||||||
|
# setters #
|
||||||
|
###########
|
||||||
|
func _set_mode(value):
|
||||||
|
if value != mode:
|
||||||
|
mode = value
|
||||||
|
__update_items()
|
||||||
|
|
||||||
|
func _set_places(value):
|
||||||
|
if value != places:
|
||||||
|
places = value
|
||||||
|
__update_items()
|
||||||
|
|
||||||
|
func _set_current_folder(value):
|
||||||
|
if value != current_folder:
|
||||||
|
current_folder = value
|
||||||
|
emit_signal("current_folder_changed")
|
||||||
|
|
||||||
|
############
|
||||||
|
# handlers #
|
||||||
|
############
|
||||||
|
func _on_item_activated(idx):
|
||||||
|
_set_current_folder(get_item_metadata(idx))
|
||||||
|
|
||||||
|
func _on_favourite_places_changed():
|
||||||
|
if mode == Mode.DEFAULT:
|
||||||
|
__update_items()
|
||||||
|
###########
|
||||||
|
# signals #
|
||||||
|
###########
|
||||||
|
signal current_folder_changed()
|
18
scripts/types/controls/recent_places_list.gd
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
extends UIB_PlacesList
|
||||||
|
|
||||||
|
class_name UIB_RecentPlacesList
|
||||||
|
|
||||||
|
#############
|
||||||
|
# overrides #
|
||||||
|
#############
|
||||||
|
func _ready():
|
||||||
|
places = GDBSettings.get_value(GDBConstants.SETTING_RECENT_PLACES, [])
|
||||||
|
|
||||||
|
GDBSettings.connect_static("setting_changed", self, "_on_setting_changed")
|
||||||
|
|
||||||
|
############
|
||||||
|
# handlers #
|
||||||
|
############
|
||||||
|
func _on_setting_changed(setting, value):
|
||||||
|
if setting == GDBConstants.SETTING_RECENT_PLACES:
|
||||||
|
_set_places(value)
|
58
scripts/types/controls/scroll_parallax_bg.gd
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
extends Control
|
||||||
|
|
||||||
|
class_name UIB_ScrollParallaxBackground
|
||||||
|
|
||||||
|
export(Array, Texture) var textures := []
|
||||||
|
export(Array, float) var speeds := []
|
||||||
|
export(NodePath) var scroll_container
|
||||||
|
|
||||||
|
var __scroll_container : ScrollContainer
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
show_behind_parent = true
|
||||||
|
rect_clip_content = true
|
||||||
|
|
||||||
|
if !scroll_container:
|
||||||
|
for child in get_children():
|
||||||
|
if child is ScrollContainer:
|
||||||
|
scroll_container = get_path_to(child)
|
||||||
|
break
|
||||||
|
|
||||||
|
__scroll_container = get_node_or_null(scroll_container) as ScrollContainer
|
||||||
|
|
||||||
|
set_process(false)
|
||||||
|
|
||||||
|
if __scroll_container:
|
||||||
|
# __scroll_container.connect("scroll_started", self, "_on_scroll_started")
|
||||||
|
# __scroll_container.connect("scroll_ended", self, "_on_scroll_ended")
|
||||||
|
__scroll_container.get_h_scrollbar().connect("value_changed", self, "_on_scroll_value_changed")
|
||||||
|
__scroll_container.get_v_scrollbar().connect("value_changed", self, "_on_scroll_value_changed")
|
||||||
|
|
||||||
|
func _draw():
|
||||||
|
if !__scroll_container || __scroll_container.get_child_count() < 1:
|
||||||
|
return
|
||||||
|
var first_child := __scroll_container.get_child(0) as Control
|
||||||
|
if !first_child:
|
||||||
|
return
|
||||||
|
|
||||||
|
for i in range(textures.size()):
|
||||||
|
var texture : Texture = textures[i]
|
||||||
|
var speed : float = speeds[i] if i < speeds.size() else 1.0
|
||||||
|
var rel_scroll := __scroll_container.scroll_vertical / max(first_child.rect_size.y - __scroll_container.rect_size.y, 1.0)
|
||||||
|
var tex_size := rect_size
|
||||||
|
var tex_pos := Vector2()
|
||||||
|
tex_size.y = tex_size.x * (texture.get_height() / texture.get_width())
|
||||||
|
tex_pos.y = speed * -rel_scroll * (tex_size.y - rect_size.y)
|
||||||
|
draw_texture_rect(texture, Rect2(tex_pos, tex_size), false)
|
||||||
|
|
||||||
|
func _process(delta):
|
||||||
|
update()
|
||||||
|
|
||||||
|
func _on_scroll_started():
|
||||||
|
set_process(true)
|
||||||
|
|
||||||
|
func _on_scroll_ended():
|
||||||
|
set_process(false)
|
||||||
|
|
||||||
|
func _on_scroll_value_changed(value : float):
|
||||||
|
update()
|
11
scripts/types/controls/setting_check_box.gd
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
extends CheckBox
|
||||||
|
|
||||||
|
class_name UIB_SettingCheckBox
|
||||||
|
|
||||||
|
export var setting_name = ""
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
pressed = GDBSettings.get_value(setting_name, false)
|
||||||
|
|
||||||
|
func _pressed():
|
||||||
|
GDBSettings.set_value(setting_name, pressed)
|
45
scripts/types/controls/setting_option_button.gd
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
extends OptionButton
|
||||||
|
|
||||||
|
class_name UIB_SettingOptionButton
|
||||||
|
|
||||||
|
export var setting_name := ""
|
||||||
|
export(Array) var values := []
|
||||||
|
export(Array, String) var labels := []
|
||||||
|
export(Array, Texture) var icons := []
|
||||||
|
|
||||||
|
#############
|
||||||
|
# overrides #
|
||||||
|
#############
|
||||||
|
func _ready():
|
||||||
|
__setup()
|
||||||
|
|
||||||
|
connect("item_selected", self, "_on_item_selected")
|
||||||
|
|
||||||
|
#################
|
||||||
|
# private stuff #
|
||||||
|
#################
|
||||||
|
func __setup():
|
||||||
|
clear()
|
||||||
|
|
||||||
|
for i in range(values.size()):
|
||||||
|
var value : String = values[i]
|
||||||
|
var label : String = labels[i] if i < labels.size() else str(value)
|
||||||
|
var icn : Texture = icons[i] if i < icons.size() else null
|
||||||
|
|
||||||
|
add_item(label)
|
||||||
|
set_item_icon(i, icn)
|
||||||
|
|
||||||
|
if !setting_name:
|
||||||
|
return
|
||||||
|
|
||||||
|
var current_value = GDBSettings.get_value(setting_name)
|
||||||
|
var current_idx = values.find(current_value)
|
||||||
|
if current_idx >= 0:
|
||||||
|
select(current_idx)
|
||||||
|
|
||||||
|
############
|
||||||
|
# handlers #
|
||||||
|
############
|
||||||
|
func _on_item_selected(idx : int):
|
||||||
|
if setting_name:
|
||||||
|
GDBSettings.set_value(setting_name, values[idx])
|
231
scripts/types/controls/suggestion_popup.gd
Normal file
@ -0,0 +1,231 @@
|
|||||||
|
extends Popup
|
||||||
|
|
||||||
|
class_name UIB_SuggestionPopup
|
||||||
|
|
||||||
|
export(NodePath) var line_edit_path = ".."
|
||||||
|
export(int, 1, 20) var max_values = 5
|
||||||
|
export(Array, String) var suggestions = [] setget _set_suggestions
|
||||||
|
export(StyleBox) var style_normal = preload("res://addons/de.mewin.gduibasics/styles/suggestion_line_normal.stylebox")
|
||||||
|
export(StyleBox) var style_active = preload("res://addons/de.mewin.gduibasics/styles/suggestion_line_active.stylebox")
|
||||||
|
onready var line_edit : LineEdit = get_node(line_edit_path)
|
||||||
|
|
||||||
|
var __v_box_container := VBoxContainer.new()
|
||||||
|
var __panel := Panel.new()
|
||||||
|
var __labels := []
|
||||||
|
var __filtered_suggestions := []
|
||||||
|
var __filter_text := ""
|
||||||
|
var __active_label := -1
|
||||||
|
var __scroll := 0
|
||||||
|
var __up_direction := false
|
||||||
|
|
||||||
|
#############
|
||||||
|
# overrides #
|
||||||
|
#############
|
||||||
|
func _ready():
|
||||||
|
call_deferred("__initial_setup")
|
||||||
|
|
||||||
|
func _gui_input(event : InputEvent):
|
||||||
|
if !event.is_pressed() || !event is InputEventMouseButton:
|
||||||
|
return
|
||||||
|
|
||||||
|
if event.button_index == BUTTON_LEFT:
|
||||||
|
__accept_suggestion()
|
||||||
|
accept_event()
|
||||||
|
elif event.button_index == BUTTON_WHEEL_DOWN:
|
||||||
|
if !__up_direction:
|
||||||
|
__focus_down()
|
||||||
|
else:
|
||||||
|
__focus_up()
|
||||||
|
elif event.button_index == BUTTON_WHEEL_UP:
|
||||||
|
if !__up_direction:
|
||||||
|
__focus_up()
|
||||||
|
else:
|
||||||
|
__focus_down()
|
||||||
|
|
||||||
|
#################
|
||||||
|
# private stuff #
|
||||||
|
#################
|
||||||
|
func __initial_setup():
|
||||||
|
__panel.show_behind_parent = true
|
||||||
|
add_child(__panel)
|
||||||
|
|
||||||
|
add_child(__v_box_container)
|
||||||
|
|
||||||
|
for i in range(max_values):
|
||||||
|
var label := Label.new()
|
||||||
|
label.size_flags_horizontal |= Control.SIZE_EXPAND
|
||||||
|
label.mouse_filter = Control.MOUSE_FILTER_PASS
|
||||||
|
label.connect("mouse_entered", self, "_on_label_mouse_entered", [i])
|
||||||
|
|
||||||
|
__labels.append(label)
|
||||||
|
__v_box_container.add_child(label)
|
||||||
|
__setup()
|
||||||
|
|
||||||
|
func __setup():
|
||||||
|
if !line_edit:
|
||||||
|
return
|
||||||
|
line_edit.focus_neighbour_top = "."
|
||||||
|
line_edit.focus_neighbour_bottom = "."
|
||||||
|
line_edit.connect("focus_entered", self, "_on_line_edit_focus_entered")
|
||||||
|
line_edit.connect("focus_exited", self, "_on_line_edit_focus_exited")
|
||||||
|
line_edit.connect("text_changed", self, "_on_line_edit_text_changed")
|
||||||
|
line_edit.connect("gui_input", self, "_on_line_edit_gui_input")
|
||||||
|
|
||||||
|
func __calc_rect() -> Rect2:
|
||||||
|
var size := Vector2(line_edit.rect_size.x, __v_box_container.get_combined_minimum_size().y)
|
||||||
|
var lower_rect := Rect2(line_edit.rect_global_position \
|
||||||
|
+ Vector2(0.0, line_edit.rect_size.y), size)
|
||||||
|
if get_viewport_rect().encloses(lower_rect):
|
||||||
|
if __up_direction:
|
||||||
|
__up_direction = false
|
||||||
|
__update_labels(false)
|
||||||
|
return lower_rect
|
||||||
|
else:
|
||||||
|
var upper_rect := Rect2(line_edit.rect_global_position \
|
||||||
|
- Vector2(0.0, size.y), size)
|
||||||
|
if !__up_direction:
|
||||||
|
__up_direction = true
|
||||||
|
__update_labels(false)
|
||||||
|
return upper_rect
|
||||||
|
|
||||||
|
func __get_label(idx : int):
|
||||||
|
assert(idx < __labels.size())
|
||||||
|
if __up_direction:
|
||||||
|
return __labels[__labels.size() - 1 - idx]
|
||||||
|
return __labels[idx]
|
||||||
|
|
||||||
|
func __score_suggestion(suggestion : String) -> float:
|
||||||
|
if suggestion.to_lower().begins_with(__filter_text):
|
||||||
|
return 0.5 + 0.5 * suggestion.similarity(line_edit.text)
|
||||||
|
else:
|
||||||
|
return 0.5 * suggestion.similarity(line_edit.text)
|
||||||
|
|
||||||
|
func __compare_suggestions(sugg0 : String, sugg1 : String):
|
||||||
|
var score0 := __score_suggestion(sugg0)
|
||||||
|
var score1 := __score_suggestion(sugg1)
|
||||||
|
if score0 != score1:
|
||||||
|
return score0 > score1
|
||||||
|
else:
|
||||||
|
return sugg0 < sugg1
|
||||||
|
|
||||||
|
func __filter():
|
||||||
|
__filter_text = line_edit.text.to_lower() # .left(line_edit.caret_position).to_lower()
|
||||||
|
__filtered_suggestions = suggestions.duplicate()
|
||||||
|
__filtered_suggestions.sort_custom(self, "__compare_suggestions")
|
||||||
|
|
||||||
|
func __update_labels(update_size := true):
|
||||||
|
for i in range(__labels.size()):
|
||||||
|
var label : Label = __get_label(i)
|
||||||
|
if i >= __filtered_suggestions.size():
|
||||||
|
label.visible = false
|
||||||
|
else:
|
||||||
|
label.visible = true
|
||||||
|
label.text = __filtered_suggestions[(i + __scroll) % __filtered_suggestions.size()]
|
||||||
|
if i == __active_label:
|
||||||
|
label.add_stylebox_override("normal", style_active)
|
||||||
|
else:
|
||||||
|
label.add_stylebox_override("normal", style_normal)
|
||||||
|
|
||||||
|
if update_size:
|
||||||
|
var rect := __calc_rect()
|
||||||
|
rect_position = rect.position
|
||||||
|
rect_size = rect.size
|
||||||
|
__panel.rect_size = rect_size
|
||||||
|
__v_box_container.rect_size = rect_size
|
||||||
|
|
||||||
|
func __focus_down():
|
||||||
|
if __active_label == __labels.size() - 1:
|
||||||
|
__scroll = min(__scroll + 1, __filtered_suggestions.size() - __labels.size())
|
||||||
|
if __scroll < 0:
|
||||||
|
__scroll = 0
|
||||||
|
else:
|
||||||
|
__active_label += 1
|
||||||
|
__update_labels()
|
||||||
|
line_edit.caret_position = line_edit.text.length()
|
||||||
|
|
||||||
|
func __focus_up():
|
||||||
|
if __active_label < 0:
|
||||||
|
return
|
||||||
|
elif __active_label > 0:
|
||||||
|
__active_label -= 1
|
||||||
|
elif __scroll > 0:
|
||||||
|
__scroll -= 1
|
||||||
|
else:
|
||||||
|
__active_label = -1
|
||||||
|
__update_labels()
|
||||||
|
line_edit.caret_position = line_edit.text.length()
|
||||||
|
|
||||||
|
func __accept_suggestion():
|
||||||
|
if __active_label < 0:
|
||||||
|
return
|
||||||
|
var suggestion = __get_label(__active_label).text
|
||||||
|
line_edit.text = suggestion
|
||||||
|
line_edit.caret_position = suggestion.length()
|
||||||
|
__active_label = -1
|
||||||
|
__scroll = 0
|
||||||
|
__filter()
|
||||||
|
__update_labels()
|
||||||
|
emit_signal("suggestion_accepted", suggestion)
|
||||||
|
|
||||||
|
###########
|
||||||
|
# setters #
|
||||||
|
###########
|
||||||
|
func _set_suggestions(value : Array):
|
||||||
|
suggestions = value
|
||||||
|
if visible:
|
||||||
|
__filter()
|
||||||
|
__update_labels()
|
||||||
|
|
||||||
|
############
|
||||||
|
# handlers #
|
||||||
|
############
|
||||||
|
func _on_line_edit_focus_entered():
|
||||||
|
__filter()
|
||||||
|
__update_labels()
|
||||||
|
|
||||||
|
popup()
|
||||||
|
|
||||||
|
func _on_line_edit_focus_exited():
|
||||||
|
visible = false
|
||||||
|
|
||||||
|
func _on_line_edit_text_changed(new_text : String):
|
||||||
|
if !line_edit || !line_edit.has_focus():
|
||||||
|
return
|
||||||
|
|
||||||
|
__active_label = -1
|
||||||
|
__scroll = 0
|
||||||
|
|
||||||
|
__filter()
|
||||||
|
__update_labels()
|
||||||
|
if !visible:
|
||||||
|
popup()
|
||||||
|
|
||||||
|
func _on_line_edit_gui_input(input_event : InputEvent):
|
||||||
|
if !input_event.is_pressed():
|
||||||
|
return
|
||||||
|
|
||||||
|
if input_event.is_action_pressed("ui_accept"):
|
||||||
|
__accept_suggestion()
|
||||||
|
elif input_event.is_action("ui_down"):
|
||||||
|
if !__up_direction:
|
||||||
|
__focus_down()
|
||||||
|
else:
|
||||||
|
__focus_up()
|
||||||
|
elif input_event.is_action("ui_up"):
|
||||||
|
if !__up_direction:
|
||||||
|
__focus_up()
|
||||||
|
else:
|
||||||
|
__focus_down()
|
||||||
|
|
||||||
|
func _on_label_mouse_entered(index : int):
|
||||||
|
if __up_direction:
|
||||||
|
index = __labels.size() - index - 1
|
||||||
|
|
||||||
|
if __active_label != index:
|
||||||
|
__active_label = index
|
||||||
|
__update_labels()
|
||||||
|
|
||||||
|
###########
|
||||||
|
# signals #
|
||||||
|
###########
|
||||||
|
signal suggestion_accepted(suggestion)
|
41
scripts/types/controls/tabs_item_list.gd
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
extends ItemList
|
||||||
|
|
||||||
|
class_name UIB_TabsItemList
|
||||||
|
|
||||||
|
export(NodePath) var tab_container
|
||||||
|
|
||||||
|
#############
|
||||||
|
# overrides #
|
||||||
|
#############
|
||||||
|
func _ready():
|
||||||
|
call_deferred("__setup")
|
||||||
|
connect("item_selected", self, "_on_item_selected")
|
||||||
|
|
||||||
|
#################
|
||||||
|
# private stuff #
|
||||||
|
#################
|
||||||
|
func __get_tab_container() -> TabContainer:
|
||||||
|
return get_node_or_null(tab_container) as TabContainer
|
||||||
|
|
||||||
|
func __setup():
|
||||||
|
var tab_container_ := __get_tab_container()
|
||||||
|
clear()
|
||||||
|
|
||||||
|
if !tab_container_:
|
||||||
|
return
|
||||||
|
|
||||||
|
for i in range(tab_container_.get_child_count()):
|
||||||
|
var title := tab_container_.get_tab_title(i)
|
||||||
|
var icon := tab_container_.get_tab_icon(i)
|
||||||
|
add_item(title, icon)
|
||||||
|
|
||||||
|
select(tab_container_.current_tab)
|
||||||
|
|
||||||
|
############
|
||||||
|
# handlers #
|
||||||
|
############
|
||||||
|
func _on_item_selected(idx : int):
|
||||||
|
var tab_container_ := __get_tab_container()
|
||||||
|
|
||||||
|
if tab_container_:
|
||||||
|
tab_container_.current_tab = idx
|
77
scripts/types/controls/touch_scroll_container.gd
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
extends ScrollContainer
|
||||||
|
|
||||||
|
class_name UIB_TouchScrollContainer
|
||||||
|
|
||||||
|
export(float) var drag_threshold := 20.0
|
||||||
|
|
||||||
|
var __dragging := false
|
||||||
|
var __drag_start := Vector2()
|
||||||
|
var __drag_start_scroll := Vector2()
|
||||||
|
var __momentum := Vector2()
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
set_process(false)
|
||||||
|
|
||||||
|
get_h_scrollbar().modulate = Color.transparent
|
||||||
|
get_v_scrollbar().modulate = Color.transparent
|
||||||
|
|
||||||
|
func _input(event):
|
||||||
|
if event is InputEventMouseMotion && (event.button_mask & BUTTON_MASK_LEFT) && \
|
||||||
|
(__dragging || get_global_rect().has_point(event.position)):
|
||||||
|
if !__dragging:
|
||||||
|
var dragged = event.position - __drag_start
|
||||||
|
if abs(dragged.x) > drag_threshold \
|
||||||
|
|| abs(dragged.y) > drag_threshold:
|
||||||
|
__dragging = true
|
||||||
|
else:
|
||||||
|
__momentum = event.relative
|
||||||
|
if scroll_horizontal_enabled:
|
||||||
|
scroll_horizontal = __drag_start_scroll.x + __drag_start.x - event.position.x
|
||||||
|
if scroll_vertical_enabled:
|
||||||
|
scroll_vertical = __drag_start_scroll.y + __drag_start.y - event.position.y
|
||||||
|
elif event is InputEventMouseButton && event.button_index == BUTTON_LEFT \
|
||||||
|
&& get_global_rect().has_point(event.position):
|
||||||
|
if !event.pressed:
|
||||||
|
if __dragging:
|
||||||
|
__dragging = false
|
||||||
|
set_process(true) # process momentum
|
||||||
|
else:
|
||||||
|
__emulate_click(event)
|
||||||
|
else:
|
||||||
|
__drag_start = event.position
|
||||||
|
__drag_start_scroll = Vector2(scroll_horizontal, scroll_vertical)
|
||||||
|
get_tree().set_input_as_handled()
|
||||||
|
|
||||||
|
func _process(delta : float):
|
||||||
|
__momentum *= 1.0 - 1.5 * delta
|
||||||
|
if abs(__momentum.x) < 0.01 && abs(__momentum.y) < 0.01:
|
||||||
|
set_process(false)
|
||||||
|
return
|
||||||
|
|
||||||
|
if scroll_horizontal_enabled:
|
||||||
|
scroll_horizontal -= __momentum.x * 50.0 * delta
|
||||||
|
|
||||||
|
if scroll_vertical_enabled:
|
||||||
|
scroll_vertical -= __momentum.y * 50.0 * delta
|
||||||
|
|
||||||
|
func __emulate_click(orig_event : InputEventMouseButton):
|
||||||
|
if get_child_count() < 1:
|
||||||
|
return
|
||||||
|
|
||||||
|
var child = get_child(0) as Control
|
||||||
|
if !child:
|
||||||
|
return
|
||||||
|
|
||||||
|
set_process_input(false)
|
||||||
|
var down_event : InputEventMouseButton = orig_event.duplicate()
|
||||||
|
down_event.position = orig_event.global_position
|
||||||
|
down_event.pressed = true
|
||||||
|
Input.parse_input_event(down_event)
|
||||||
|
|
||||||
|
yield(get_tree(), "idle_frame")
|
||||||
|
|
||||||
|
var up_event : InputEventMouseButton = orig_event.duplicate()
|
||||||
|
up_event.position = orig_event.global_position
|
||||||
|
up_event.pressed = false
|
||||||
|
Input.parse_input_event(up_event)
|
||||||
|
set_process_input(true)
|
28
scripts/types/controls/window_border_container.gd
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
extends UIB_BorderContainer
|
||||||
|
|
||||||
|
class_name UIB_WindowBorderContainer
|
||||||
|
|
||||||
|
export var minimum_size := Vector2(100.0, 100.0)
|
||||||
|
|
||||||
|
#############
|
||||||
|
# overrides #
|
||||||
|
#############
|
||||||
|
func _win_get_position() -> Vector2:
|
||||||
|
return OS.window_position
|
||||||
|
|
||||||
|
func _win_get_size() -> Vector2:
|
||||||
|
return OS.window_size
|
||||||
|
|
||||||
|
func _win_get_mouse_position() -> Vector2:
|
||||||
|
return get_viewport().get_mouse_position() + OS.window_position
|
||||||
|
|
||||||
|
func _win_get_minimum_size() -> Vector2:
|
||||||
|
return minimum_size
|
||||||
|
|
||||||
|
func _win_set_position(pos : Vector2):
|
||||||
|
if pos != OS.window_position:
|
||||||
|
OS.window_position = pos
|
||||||
|
OS.window_maximized = false
|
||||||
|
|
||||||
|
func _win_set_size(size : Vector2):
|
||||||
|
OS.window_size = size
|
8
scripts/types/misc/action_reference.gd
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
extends Node
|
||||||
|
|
||||||
|
class_name UIB_ActionReference
|
||||||
|
|
||||||
|
export(NodePath) var action
|
||||||
|
|
||||||
|
func get_action() -> UIB_Action:
|
||||||
|
return get_node_or_null(action) as UIB_Action
|
25
scripts/types/misc/constraints/dynamic_grid_constraints.gd
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
tool
|
||||||
|
extends Node
|
||||||
|
|
||||||
|
class_name UIB_DynamicGridConstraints
|
||||||
|
|
||||||
|
export(int, 1, 100) var colspan := 1 setget _set_colspan
|
||||||
|
export(int, 1, 100) var rowspan := 1 setget _set_rowspan
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
__trigger_update()
|
||||||
|
|
||||||
|
func __trigger_update():
|
||||||
|
var container := get_node_or_null("../..") as Container # cyclic inclusion, cannot use UIB_DynamicGridContainer
|
||||||
|
if container != null:
|
||||||
|
container.notification(Container.NOTIFICATION_SORT_CHILDREN)
|
||||||
|
|
||||||
|
func _set_colspan(value : int):
|
||||||
|
if value != colspan:
|
||||||
|
colspan = value
|
||||||
|
__trigger_update()
|
||||||
|
|
||||||
|
func _set_rowspan(value : int):
|
||||||
|
if value != rowspan:
|
||||||
|
rowspan = value
|
||||||
|
__trigger_update()
|
50
scripts/types/misc/file_adapter.gd
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
extends Reference
|
||||||
|
|
||||||
|
class_name UIB_FileAdapter
|
||||||
|
|
||||||
|
class FileEntry:
|
||||||
|
func _is_folder() -> bool:
|
||||||
|
return false
|
||||||
|
|
||||||
|
func _is_link() -> bool:
|
||||||
|
return false
|
||||||
|
|
||||||
|
func _list_files() -> Array:
|
||||||
|
return []
|
||||||
|
|
||||||
|
func _get_name() -> String:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
func _get_size() -> int:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
func _get_modified_time() -> int:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
func _get_parent() -> FileEntry:
|
||||||
|
return null
|
||||||
|
|
||||||
|
func _get_path() -> String:
|
||||||
|
var parent := _get_parent()
|
||||||
|
if parent:
|
||||||
|
return parent._get_path().plus_file(_get_name())
|
||||||
|
var name := _get_name()
|
||||||
|
if name == "":
|
||||||
|
return "/"
|
||||||
|
return name
|
||||||
|
|
||||||
|
func _get_root() -> FileEntry:
|
||||||
|
return null
|
||||||
|
|
||||||
|
func _get_file(path : String) -> FileEntry:
|
||||||
|
return null
|
||||||
|
|
||||||
|
func _get_icon(entry) -> Texture:
|
||||||
|
if entry._is_folder():
|
||||||
|
return preload("res://addons/de.mewin.gduibasics/images/folder.svg")
|
||||||
|
else:
|
||||||
|
|
||||||
|
return preload("res://addons/de.mewin.gduibasics/images/file.svg")
|
||||||
|
|
||||||
|
func _get_drives() -> Array:
|
||||||
|
return [""]
|
20
scripts/types/misc/file_extension_filter.gd
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
extends UIB_FileFilter
|
||||||
|
|
||||||
|
class_name UIB_FileExtensionFilter
|
||||||
|
|
||||||
|
var __extensions : PoolStringArray
|
||||||
|
|
||||||
|
func _init(extensions_ : Array):
|
||||||
|
for ext in extensions_:
|
||||||
|
if !ext.begins_with("."):
|
||||||
|
ext = "." + ext
|
||||||
|
__extensions.append(ext)
|
||||||
|
|
||||||
|
func _accepts(entry) -> bool:
|
||||||
|
for ext in __extensions:
|
||||||
|
if entry._get_name().ends_with(ext):
|
||||||
|
return true
|
||||||
|
return false
|
||||||
|
|
||||||
|
func _get_default_name() -> String:
|
||||||
|
return tr("%s-Files") % __extensions.join(", ")
|
16
scripts/types/misc/file_filter.gd
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
extends Reference
|
||||||
|
|
||||||
|
class_name UIB_FileFilter
|
||||||
|
|
||||||
|
var name := ""
|
||||||
|
|
||||||
|
func _accepts(entry) -> bool:
|
||||||
|
return true
|
||||||
|
|
||||||
|
func _get_name() -> String:
|
||||||
|
if name:
|
||||||
|
return name
|
||||||
|
return _get_default_name()
|
||||||
|
|
||||||
|
func _get_default_name() -> String:
|
||||||
|
return ""
|
110
scripts/types/misc/local_file_adapter.gd
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
extends UIB_FileAdapter
|
||||||
|
|
||||||
|
class_name UIB_LocalFileAdapter
|
||||||
|
|
||||||
|
var __dir = Directory.new()
|
||||||
|
|
||||||
|
class LocalFileEntry:
|
||||||
|
extends UIB_FileAdapter.FileEntry
|
||||||
|
|
||||||
|
var path : String
|
||||||
|
var is_link : bool
|
||||||
|
var is_folder : bool
|
||||||
|
var size := -1
|
||||||
|
var modified_time := -1
|
||||||
|
|
||||||
|
func _init(path_ : String, is_link_ : bool, is_folder_ : bool):
|
||||||
|
path = path_
|
||||||
|
is_link = is_link_
|
||||||
|
is_folder = is_folder_
|
||||||
|
if path.ends_with("/") && path != "/":
|
||||||
|
path = path.left(path.length() - 1)
|
||||||
|
|
||||||
|
func _is_folder() -> bool:
|
||||||
|
return is_folder
|
||||||
|
|
||||||
|
func _is_link() -> bool:
|
||||||
|
return is_link
|
||||||
|
|
||||||
|
func _list_files() -> Array:
|
||||||
|
if !is_folder:
|
||||||
|
return []
|
||||||
|
var dir := Directory.new()
|
||||||
|
if dir.open(path + "/") != OK:
|
||||||
|
return []
|
||||||
|
if dir.list_dir_begin(true) != OK:
|
||||||
|
return []
|
||||||
|
var fname := dir.get_next()
|
||||||
|
var files := []
|
||||||
|
while fname:
|
||||||
|
var fpath := path.plus_file(fname)
|
||||||
|
var ffolder := dir.current_is_dir()
|
||||||
|
var flink := false
|
||||||
|
|
||||||
|
files.append(LocalFileEntry.new(fpath, flink, ffolder))
|
||||||
|
|
||||||
|
fname = dir.get_next()
|
||||||
|
return files
|
||||||
|
|
||||||
|
func _get_name() -> String:
|
||||||
|
return path.get_file()
|
||||||
|
|
||||||
|
func _get_size() -> int:
|
||||||
|
if size == -1:
|
||||||
|
size = __calc_size()
|
||||||
|
return size
|
||||||
|
|
||||||
|
func _get_modified_time() -> int:
|
||||||
|
if modified_time == -1:
|
||||||
|
modified_time = __calc_modified_time()
|
||||||
|
return modified_time
|
||||||
|
|
||||||
|
func _get_parent() -> UIB_FileAdapter.FileEntry:
|
||||||
|
var parent_path := path.get_base_dir()
|
||||||
|
if parent_path && parent_path != path:
|
||||||
|
return LocalFileEntry.new(parent_path, false, true)
|
||||||
|
return null
|
||||||
|
|
||||||
|
func __calc_size() -> int:
|
||||||
|
if is_folder:
|
||||||
|
return 0
|
||||||
|
var file := File.new()
|
||||||
|
if file.open(path, File.READ) != OK:
|
||||||
|
return 0
|
||||||
|
return file.get_len()
|
||||||
|
|
||||||
|
func __calc_modified_time() -> int:
|
||||||
|
if is_folder:
|
||||||
|
return 0
|
||||||
|
var file := File.new()
|
||||||
|
return file.get_modified_time(path)
|
||||||
|
|
||||||
|
func _get_file(path : String) -> FileEntry:
|
||||||
|
if OS.has_feature("Windows"): # has "feature"
|
||||||
|
path = path.replace("\\", "/")
|
||||||
|
if path.length() < 2 || path[1] != ":":
|
||||||
|
path = "c:/" + path.lstrip("/")
|
||||||
|
if path.length() == 2: #
|
||||||
|
path += "/"
|
||||||
|
elif !path.begins_with("/"):
|
||||||
|
path = "/" + path # only drive letter, dir_exists() wouldnt work
|
||||||
|
|
||||||
|
var dir := Directory.new()
|
||||||
|
if dir.dir_exists(path):
|
||||||
|
return LocalFileEntry.new(path, false, true)
|
||||||
|
elif dir.file_exists(path):
|
||||||
|
return LocalFileEntry.new(path, false, false)
|
||||||
|
else:
|
||||||
|
return null
|
||||||
|
|
||||||
|
func _get_root() -> UIB_FileAdapter.FileEntry:
|
||||||
|
return _get_file("/")
|
||||||
|
|
||||||
|
func _get_drives() -> Array:
|
||||||
|
var dir := Directory.new()
|
||||||
|
var drives := []
|
||||||
|
|
||||||
|
for i in range(dir.get_drive_count()):
|
||||||
|
drives.append(dir.get_drive(i))
|
||||||
|
|
||||||
|
return drives
|
5
scripts/types/misc/seperator.gd
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
extends Node
|
||||||
|
|
||||||
|
class_name UIB_Seperator
|
||||||
|
|
||||||
|
export(String) var text := ""
|
102
scripts/types/misc/simple_action.gd
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
extends UIB_Action
|
||||||
|
|
||||||
|
class_name UIB_SimpleAction
|
||||||
|
|
||||||
|
export var text := "" setget _set_text
|
||||||
|
export(Texture) var icon setget _set_icon
|
||||||
|
export(Texture) var untoggled_icon setget _set_untoggled_icon
|
||||||
|
export(String) var shortcut_action setget _set_shortcut_action
|
||||||
|
export var disabled := false setget _set_disabled
|
||||||
|
export var toggleable := false setget _set_toggleable
|
||||||
|
export var toggled := false setget _set_toggled
|
||||||
|
|
||||||
|
#############
|
||||||
|
# overrides #
|
||||||
|
#############
|
||||||
|
func _get_text() -> String:
|
||||||
|
return text
|
||||||
|
|
||||||
|
func _get_icon() -> Texture:
|
||||||
|
if untoggled_icon && !toggled:
|
||||||
|
return untoggled_icon
|
||||||
|
return icon
|
||||||
|
|
||||||
|
func _get_shortcut() -> ShortCut:
|
||||||
|
if shortcut_action:
|
||||||
|
var action_list = InputMap.get_action_list(shortcut_action)
|
||||||
|
if !action_list:
|
||||||
|
return null
|
||||||
|
var shortcut := ShortCut.new()
|
||||||
|
shortcut.shortcut = action_list[0]
|
||||||
|
return shortcut
|
||||||
|
return null
|
||||||
|
|
||||||
|
func _is_disabled() -> bool:
|
||||||
|
return disabled
|
||||||
|
|
||||||
|
func _is_toggleable() -> bool:
|
||||||
|
return toggleable
|
||||||
|
|
||||||
|
func _is_toggled() -> bool:
|
||||||
|
return toggled
|
||||||
|
|
||||||
|
func _toggle(value : bool):
|
||||||
|
if toggleable:
|
||||||
|
_set_toggled(value)
|
||||||
|
|
||||||
|
func _apply():
|
||||||
|
emit_signal("applied")
|
||||||
|
|
||||||
|
func _update():
|
||||||
|
emit_signal("update", self)
|
||||||
|
|
||||||
|
###########
|
||||||
|
# setters #
|
||||||
|
###########
|
||||||
|
func _set_text(value : String):
|
||||||
|
if value != text:
|
||||||
|
text = value
|
||||||
|
emit_signal("text_changed")
|
||||||
|
|
||||||
|
func _set_icon(value : Texture):
|
||||||
|
if value != icon:
|
||||||
|
icon = value
|
||||||
|
emit_signal("icon_changed")
|
||||||
|
|
||||||
|
func _set_untoggled_icon(value : Texture):
|
||||||
|
if value != untoggled_icon:
|
||||||
|
untoggled_icon = value
|
||||||
|
emit_signal("icon_changed")
|
||||||
|
|
||||||
|
func _set_shortcut_action(value : String):
|
||||||
|
if value != shortcut_action:
|
||||||
|
shortcut_action = value
|
||||||
|
emit_signal("shortcut_changed")
|
||||||
|
|
||||||
|
func _set_disabled(value : bool):
|
||||||
|
if value != disabled:
|
||||||
|
disabled = value
|
||||||
|
emit_signal("disabled_changed")
|
||||||
|
|
||||||
|
func _set_toggled(value : bool):
|
||||||
|
if value != toggled:
|
||||||
|
toggled = value
|
||||||
|
emit_signal("toggled_changed")
|
||||||
|
if toggled:
|
||||||
|
_set_toggleable(true)
|
||||||
|
if untoggled_icon:
|
||||||
|
emit_signal("icon_changed")
|
||||||
|
|
||||||
|
func _set_toggleable(value : bool):
|
||||||
|
if value != toggleable:
|
||||||
|
toggleable = value
|
||||||
|
emit_signal("toggleable_changed")
|
||||||
|
if !toggleable:
|
||||||
|
_set_toggled(false)
|
||||||
|
|
||||||
|
###########
|
||||||
|
# signals #
|
||||||
|
###########
|
||||||
|
signal applied()
|
||||||
|
signal update(action)
|
||||||
|
signal toggleable_changed()
|
71
scripts/types/misc/ui_action.gd
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
extends Node
|
||||||
|
|
||||||
|
class_name UIB_Action, "res://addons/de.mewin.gduibasics/images/action.svg"
|
||||||
|
|
||||||
|
export var continuous_update = false setget _set_continuous_update
|
||||||
|
|
||||||
|
#############
|
||||||
|
# overrides #
|
||||||
|
#############
|
||||||
|
func _ready():
|
||||||
|
set_process(continuous_update)
|
||||||
|
|
||||||
|
func _process(delta):
|
||||||
|
_update()
|
||||||
|
|
||||||
|
func _unhandled_input(event : InputEvent):
|
||||||
|
if self._is_disabled() || !event.is_pressed():
|
||||||
|
return
|
||||||
|
|
||||||
|
var shortcut := self._get_shortcut()
|
||||||
|
if !shortcut || !shortcut.is_shortcut(event):
|
||||||
|
return
|
||||||
|
|
||||||
|
self._apply()
|
||||||
|
|
||||||
|
################
|
||||||
|
# overridables #
|
||||||
|
################
|
||||||
|
func _get_text() -> String:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
func _get_icon() -> Texture:
|
||||||
|
return null
|
||||||
|
|
||||||
|
func _get_shortcut() -> ShortCut:
|
||||||
|
return null
|
||||||
|
|
||||||
|
func _is_disabled() -> bool:
|
||||||
|
return false
|
||||||
|
|
||||||
|
func _is_toggleable() -> bool:
|
||||||
|
return false
|
||||||
|
|
||||||
|
func _is_toggled() -> bool:
|
||||||
|
return false
|
||||||
|
|
||||||
|
func _toggle(value : bool):
|
||||||
|
pass
|
||||||
|
|
||||||
|
func _apply():
|
||||||
|
_toggle(!_is_toggled())
|
||||||
|
|
||||||
|
func _update():
|
||||||
|
pass
|
||||||
|
|
||||||
|
###########
|
||||||
|
# setters #
|
||||||
|
###########
|
||||||
|
func _set_continuous_update(value):
|
||||||
|
if value != continuous_update:
|
||||||
|
continuous_update = value
|
||||||
|
set_process(continuous_update)
|
||||||
|
|
||||||
|
###########
|
||||||
|
# signals #
|
||||||
|
###########
|
||||||
|
signal text_changed()
|
||||||
|
signal icon_changed()
|
||||||
|
signal shortcut_changed()
|
||||||
|
signal disabled_changed()
|
||||||
|
signal toggled_changed()
|