text:
/*************************************************************************/
/*  tl_font_family_edit.cpp                                              */
/*************************************************************************/

#include "tl_font_family_edit.hpp"

void EditorInspectorPluginTLFontFamily::_new_style(Object *p_object, Object *p_ctl) {
	Ref<TLFontFamily> object = Ref<TLFontFamily>(Object::cast_to<TLFontFamily>(p_object));
	LineEdit *ctl = Object::cast_to<LineEdit>(p_ctl);
	if (object.is_valid() && ctl && ctl->get_text() != "")
		object->add_style(ctl->get_text());
}

void EditorInspectorPluginTLFontFamily::_remove_style(Object *p_object, String p_style) {
	Ref<TLFontFamily> object = Ref<TLFontFamily>(Object::cast_to<TLFontFamily>(p_object));
	if (object.is_valid())
		object->remove_style(p_style);
}

void EditorInspectorPluginTLFontFamily::_new_lang(Object *p_object, String p_style, Object *p_ctl) {
	Ref<TLFontFamily> object = Ref<TLFontFamily>(Object::cast_to<TLFontFamily>(p_object));
	LineEdit *ctl = Object::cast_to<LineEdit>(p_ctl);
	if (object.is_valid() && ctl && ctl->get_text() != "")
		object->add_language(p_style, ctl->get_text());
}

void EditorInspectorPluginTLFontFamily::_new_script(Object *p_object, String p_style, Object *p_ctl) {
	Ref<TLFontFamily> object = Ref<TLFontFamily>(Object::cast_to<TLFontFamily>(p_object));
	LineEdit *ctl = Object::cast_to<LineEdit>(p_ctl);
	if (object.is_valid() && ctl && ctl->get_text() != "")
		object->add_script(p_style, ctl->get_text());
}

void EditorInspectorPluginTLFontFamily::_remove_lang(Object *p_object, String p_style, String p_lang) {
	Ref<TLFontFamily> object = Ref<TLFontFamily>(Object::cast_to<TLFontFamily>(p_object));
	if (object.is_valid())
		object->remove_language(p_style, p_lang);
}

void EditorInspectorPluginTLFontFamily::_remove_script(Object *p_object, String p_style, String p_script) {
	Ref<TLFontFamily> object = Ref<TLFontFamily>(Object::cast_to<TLFontFamily>(p_object));
	if (object.is_valid())
		object->remove_script(p_style, p_script);
}

void EditorInspectorPluginTLFontFamily::_clear(Object *p_object) {
	Ref<TLShapedAttributedString> object = Ref<TLShapedAttributedString>(Object::cast_to<TLShapedAttributedString>(p_object));
	if (object.is_valid())
		object->clear_attributes();
}

void EditorInspectorPluginTLFontFamily::_commit(Object *p_object) {
	Ref<TLShapedAttributedString> object = Ref<TLShapedAttributedString>(Object::cast_to<TLShapedAttributedString>(p_object));
	if (object.is_valid())
		object->commit_attribute();
}

void EditorInspectorPluginTLFontFamily::_reject(Object *p_object) {
	Ref<TLShapedAttributedString> object = Ref<TLShapedAttributedString>(Object::cast_to<TLShapedAttributedString>(p_object));
	if (object.is_valid())
		object->reject_attribute();
}

void EditorInspectorPluginTLFontFamily::_bind_methods() {
	ClassDB::bind_method(D_METHOD("_new_style", "object", "ctl"), &EditorInspectorPluginTLFontFamily::_new_style);
	ClassDB::bind_method(D_METHOD("_remove_style", "object", "style"), &EditorInspectorPluginTLFontFamily::_remove_style);
	ClassDB::bind_method(D_METHOD("_new_lang", "object", "style", "ctl"), &EditorInspectorPluginTLFontFamily::_new_lang);
	ClassDB::bind_method(D_METHOD("_new_script", "object", "style", "ctl"), &EditorInspectorPluginTLFontFamily::_new_script);
	ClassDB::bind_method(D_METHOD("_remove_lang", "object", "style", "lang"), &EditorInspectorPluginTLFontFamily::_remove_lang);
	ClassDB::bind_method(D_METHOD("_remove_script", "object", "style", "script"), &EditorInspectorPluginTLFontFamily::_remove_script);
	ClassDB::bind_method(D_METHOD("_clear"), &EditorInspectorPluginTLFontFamily::_clear);
	ClassDB::bind_method(D_METHOD("_commit"), &EditorInspectorPluginTLFontFamily::_commit);
	ClassDB::bind_method(D_METHOD("_reject"), &EditorInspectorPluginTLFontFamily::_reject);
}

bool EditorInspectorPluginTLFontFamily::can_handle(Object *p_object) {
	return (Object::cast_to<TLFontFamily>(p_object) != NULL) || (Object::cast_to<TLShapedAttributedString>(p_object) != NULL);
}

void EditorInspectorPluginTLFontFamily::parse_begin(Object *p_object) {
	//NOP
}

bool EditorInspectorPluginTLFontFamily::parse_property(Object *p_object, Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, int p_usage) {
	if (p_path == "attribute/_commit") {
		HBoxContainer *hbox = memnew(HBoxContainer);
		Button *rem_btn = memnew(Button);
		rem_btn->set_h_size_flags(Control::SIZE_EXPAND_FILL);
		rem_btn->connect("pressed", this, "_clear", varray(p_object));
		rem_btn->set_text("Clear");
		hbox->add_child(rem_btn);
		Button *cln_btn = memnew(Button);
		cln_btn->set_h_size_flags(Control::SIZE_EXPAND_FILL);
		cln_btn->connect("pressed", this, "_reject", varray(p_object));
		cln_btn->set_text("Remove");
		hbox->add_child(cln_btn);
		Button *new_btn = memnew(Button);
		new_btn->set_h_size_flags(Control::SIZE_EXPAND_FILL);
		new_btn->connect("pressed", this, "_commit", varray(p_object));
		new_btn->set_text("Add");
		hbox->add_child(new_btn);
		add_custom_control(hbox);
		return true;
	}
	if (p_path == "_new_style") {
		HBoxContainer *hbox = memnew(HBoxContainer);
		LineEdit *new_name = memnew(LineEdit);
		new_name->set_h_size_flags(Control::SIZE_EXPAND_FILL);
		new_name->set_placeholder("Style name");
		hbox->add_child(new_name);
		Button *new_btn = memnew(Button);
		new_btn->set_h_size_flags(Control::SIZE_EXPAND_FILL);
		new_btn->connect("pressed", this, "_new_style", varray(p_object, new_name));
		new_btn->set_text("Add style");
		hbox->add_child(new_btn);
		add_custom_control(hbox);
		return true;
	}
	Vector<String> tokens = p_path.split("/");
	if (tokens.size() == 2) {
		if (tokens[1] == "_prev_style") {
			TLFontFamilyPreview *prev = memnew(TLFontFamilyPreview);
			Ref<TLFontFamily> object = Ref<TLFontFamily>(Object::cast_to<TLFontFamily>(p_object));
			prev->set_ff(object, tokens[0]);
			add_custom_control(prev);
			return true;
		} else if (tokens[1] == "_remove_style") {
			Button *rem_btn = memnew(Button);
			rem_btn->set_text("Remove \"" + tokens[0] + "\" style");
			rem_btn->connect("pressed", this, "_remove_style", varray(p_object, tokens[0]));
			add_custom_control(rem_btn);
			return true;
		} else if (tokens[1] == "_add_lang") {
			HBoxContainer *hbox = memnew(HBoxContainer);
			LineEdit *new_name = memnew(LineEdit);
			new_name->set_h_size_flags(Control::SIZE_EXPAND_FILL);
			new_name->set_max_length(4);
			new_name->set_placeholder("ISO language code");
			hbox->add_child(new_name);
			Button *new_btn = memnew(Button);
			new_btn->set_h_size_flags(Control::SIZE_EXPAND_FILL);
			new_btn->connect("pressed", this, "_new_lang", varray(p_object, tokens[0], new_name));
			new_btn->set_text("Add language");
			hbox->add_child(new_btn);
			add_custom_control(hbox);
			return true;
		} else if (tokens[1] == "_add_script") {
			HBoxContainer *hbox = memnew(HBoxContainer);
			LineEdit *new_name = memnew(LineEdit);
			new_name->set_h_size_flags(Control::SIZE_EXPAND_FILL);
			new_name->set_max_length(4);
			new_name->set_placeholder("ISO script code");
			hbox->add_child(new_name);
			Button *new_btn = memnew(Button);
			new_btn->set_h_size_flags(Control::SIZE_EXPAND_FILL);
			new_btn->connect("pressed", this, "_new_script", varray(p_object, tokens[0], new_name));
			new_btn->set_text("Add script");
			hbox->add_child(new_btn);
			add_custom_control(hbox);
			return true;
		}
	} else if (tokens.size() == 4) {
		if (tokens[3] == "_remove_script" && tokens[1] == "script") {
			Button *rem_btn = memnew(Button);
			rem_btn->set_text("Remove \"" + tokens[2] + "\" script");
			rem_btn->connect("pressed", this, "_remove_script", varray(p_object, tokens[0], tokens[2]));
			add_custom_control(rem_btn);
			return true;
		}
		if (tokens[3] == "_remove_lang" && tokens[1] == "lang") {
			Button *rem_btn = memnew(Button);
			rem_btn->set_text("Remove \"" + tokens[2] + "\" language");
			rem_btn->connect("pressed", this, "_remove_lang", varray(p_object, tokens[0], tokens[2]));
			add_custom_control(rem_btn);
			return true;
		}
	}
	return false; //do not handle
}

void EditorInspectorPluginTLFontFamily::parse_end() {
	//NOP
}

/*************************************************************************/

void TLFontFamilyPreview::_ff_changed(const String &p_text) {
	str->set_text(p_text);
	preview->update();
}

void TLFontFamilyPreview::_redraw() {
	VisualServer::get_singleton()->canvas_item_add_rect(preview->get_canvas_item(), Rect2(Point2(), preview->get_size()), Color(0.8, 0.8, 0.8, 1));
	str->draw(preview->get_canvas_item(), Point2((preview->get_rect().size.x - str->get_width()) / 2, (preview->get_rect().size.y - str->get_height()) / 2 + str->get_ascent()), Color(0, 0, 0, 1));
}

void TLFontFamilyPreview::_bind_methods() {
	ClassDB::bind_method(D_METHOD("_ff_changed", "text"), &TLFontFamilyPreview::_ff_changed);
	ClassDB::bind_method(D_METHOD("_redraw"), &TLFontFamilyPreview::_redraw);
}

void TLFontFamilyPreview::set_ff(const Ref<TLFontFamily> &p_ff, const String &p_style) {
	str->set_base_font(p_ff);
	str->set_base_font_style(p_style);
}

TLFontFamilyPreview::TLFontFamilyPreview() {
	str.instance();
	str->set_base_font_size(18.0);
	str->set_text("Etaoin shrdlu");
	preview = memnew(Control);
	preview->set_custom_minimum_size(Size2(0, 50 * EDSCALE));
	preview->connect("draw", this, "_redraw");
	add_child(preview);
	ctl = memnew(LineEdit);
	ctl->set_text("Etaoin shrdlu");
	ctl->connect("text_changed", this, "_ff_changed");
	add_child(ctl);
}


text:
/*************************************************************************/
/*  tl_editor_node.h                                                     */
/*************************************************************************/

#ifndef TL_EDITOR_NODE_H
#define TL_EDITOR_NODE_H

#include <core/map.h>
#include <core/resource.h>
#include <editor/editor_export.h>
#include <editor/editor_node.h>

#include "tl_core.hpp"

class TLEditorNode : public Node {
	GODOT_SUBCLASS(TLEditorNode, Object)

	EditorNode *editor;

	Map<String, Ref<ImageTexture> > type_icons;

	static TLEditorNode *singleton;

protected:
	void _notification(int p_notification);
	static void _bind_methods();

public:
	_FORCE_INLINE_ static TLEditorNode *get_singleton() { return singleton; }

	TLEditorNode(EditorNode *p_editor);
	~TLEditorNode();
};

#endif //TL_EDITOR_NODE_H

repo_language: C

mime_type: text/x-c


text:
#!/usr/bin/env python

Import('env')
from compat import StringIO

def make_tl_icons_action(target, source, env):

    import os

    dst = target[0].srcnode().abspath
    svg_icons = source

    icons_string = StringIO()

    for f in svg_icons:

        fname = str(f)

        icons_string.write('\t"')

        with open(fname, 'rb') as svgf:
            b = svgf.read(1)
            while(len(b) == 1):
                icons_string.write("\\" + str(hex(ord(b)))[1:])
                b = svgf.read(1)

        icons_string.write('"')
        if fname != svg_icons[-1]:
            icons_string.write(",")
        icons_string.write('\n')

    s = StringIO()
    s.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
    s.write("#ifndef _TL_EDITOR_ICONS_H\n")
    s.write("#define _TL_EDITOR_ICONS_H\n")
    s.write("static const int tl_icons_count = {};\n".format(len(svg_icons)))
    s.write("static const char *tl_icons_sources[] = {\n")
    s.write(icons_string.getvalue())
    s.write('};\n\n')
    s.write("static const char *tl_icons_names[] = {\n")

    # this is used to store the indices of thumbnail icons
    index = 0
    for f in svg_icons:

        fname = str(f)

        icon_name = os.path.basename(fname)[5:-4].title().replace("_", "")
        # some special cases
        if icon_name in ['Int', 'Bool', 'Float']:
            icon_name = icon_name.lower()

        s.write('\t"{0}"'.format(icon_name))

        if fname != svg_icons[-1]:
            s.write(",")
        s.write('\n')

        index += 1

    s.write('};\n')

    s.write("#endif\n")

    with open(dst, "w") as f:
        f.write(s.getvalue())

    s.close()
    icons_string.close()

make_tl_icons_builder = Builder(action=make_tl_icons_action,
                                    suffix='.h',
                                    src_suffix='.svg')
env['BUILDERS']['MakeEditorIconsBuilder'] = make_tl_icons_builder
env.Alias('tl_icons', [env.MakeEditorIconsBuilder('icons.gen.h', Glob("*.svg"))])

Export('env')


text:
# Demos

### Important note

For gdnative demos copy `libgdtl` (with compiled libraries) into `addons` subfolder of each demo.

## `input_builtin` and `input_gdnative`

![input demo screenshot](input_sshot.png)

Rich text input control demo: input, cursor and selection, opening and saving `*.gdrtf` files.

## `disp_builtin` and `disp_gdnative`

![disp demo screenshot](disp_sshot.png)

Shapaed string demo: fonts, string construction, rendering, line breaking and justification.

## `ctrls_builtin` and `ctrls_gdnative`

![ctrls demo screenshot](ctrls_sshot.png)

Ported Godot controls (Label and LineEdit) demo.

## `get_sample_texts_builtin` (module only)

Renders Noto font sample text to `.png` files.


text:
; Engine configuration file.
; It's best edited using the editor UI and not directly,
; since the parameters that go here are not all obvious.
;
; Format:
;   [section] ; section goes between []
;   param=value ; assign values to parameters

config_version=4

_global_script_classes=[  ]
_global_script_class_icons={
}

[application]

config/name="libgdtl rich text input control demo (gdnative)"
run/main_scene="res://main.tscn"
boot_splash/image="res://splash.png"
boot_splash/fullsize=false
config/icon="res://icon.png"

[autoload]

TLConstants="*res://addons/libgdtl/constants.gd"

[display]

window/size/width=1600
window/size/height=800

[editor_plugins]

enabled=PoolStringArray( "libgdtl" )

[rendering]

environment/default_environment="res://default_env.tres"


text:
extends ColorRect

export var gldata = []
var scale = 3

func _draw():
	var x = Vector2(10, rect_size.y / 2)
	if gldata.size() > 0:
		var s = 1.0 / (gldata.size() / 7)
		var n = 75
		for i in range(gldata.size() / 7):
			var face = gldata[i*7 + 0]
			var fsize = gldata[i*7 + 1]
			var asc = gldata[i*7 + 2] * scale
			var dsc = gldata[i*7 + 3] * scale
			var off = gldata[i*7 + 5] * scale

			if (face):
				face.draw_glyph(get_canvas_item(), x + off - Vector2(0, asc), gldata[i*7 + 4], Color(1 - (s*i), 1 - (s*i), 1 - (s*i), 0.5), fsize * scale)

			draw_circle(x + off, 3, Color(1, 0, 0, 0.45))
			draw_line(x + off, x, Color(1, 0, 0))
			draw_line(Vector2(0, rect_size.y / 2 - asc), Vector2(rect_size.x, rect_size.y / 2 - asc), Color(0, 1, 0, 0.2))
			draw_line(Vector2(0, rect_size.y / 2), Vector2(rect_size.x, rect_size.y / 2), Color(0, 1, 0, 0.2))
			draw_line(Vector2(0, rect_size.y / 2 + dsc), Vector2(rect_size.x, rect_size.y / 2 + dsc), Color(0, 1, 0, 0.2))
			draw_circle(x, 3, Color(0, 0, 1, 0.45))
			draw_line(x + gldata[i*7 + 6] * scale, x, Color(0, 0, 1))
			x = x + gldata[i*7 + 6] * scale
			draw_string(get_font("font"), Vector2(10 + n * i, rect_size.y - 34), "%d" % [gldata[i*7 + 4]], Color(1, 1, 1))
			draw_string(get_font("font"), Vector2(10 + n * i, rect_size.y - 22), "%2.1f; %2.1f" % [gldata[i*7 + 6].x, gldata[i*7 + 6].y], Color(0, 0, 1))
			draw_string(get_font("font"), Vector2(10 + n * i, rect_size.y - 10), "%2.1f; %2.1f" % [gldata[i*7 + 5].x, gldata[i*7 + 5].y], Color(1, 0, 0))
			if (face):
				face.draw_glyph(get_canvas_item(), Vector2(10 + n * i, rect_size.y - 80 - dsc / scale), gldata[i*7 + 4], Color(1 - (s*i), 1 - (s*i), 1 - (s*i), 0.5), fsize)

func _on_HSlider_value_changed(value):
	scale = value
	update()


text:
[gd_resource type="Environment" load_steps=2 format=2]

[sub_resource type="ProceduralSky" id=1]

[resource]
background_mode = 2
background_sky = SubResource( 1 )


text:
extends ColorRect

export var point = Vector2()
export var brk = false
export var jst = false

func _draw():
	var tpc = get_parent().get_parent().get_node("TLRichTextEdit")
	tpc.debug_draw(get_canvas_item(), Vector2(70, 35), point, brk, jst)
	tpc.debug_draw_as_hex(get_canvas_item(), Vector2(70, 105), point, brk, jst)
	tpc.debug_draw_logical_as_hex(get_canvas_item(), Vector2(70, 140), point, brk, jst)