mirror of https://github.com/dsrw/enu.git
Better markdown rendering. WIP 3d control
This commit is contained in:
parent
7afa4e7235
commit
1a43e71a54
|
@ -31,23 +31,21 @@ content_margin_left = 20.0
|
|||
content_margin_right = 20.0
|
||||
content_margin_top = 20.0
|
||||
content_margin_bottom = 20.0
|
||||
bg_color = Color( 0.0784314, 0.0117647, 0.113725, 1 )
|
||||
bg_color = Color( 0.0784314, 0.0117647, 0.113725, 0.839216 )
|
||||
|
||||
[sub_resource type="DynamicFont" id=13]
|
||||
font_data = ExtResource( 7 )
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id=3]
|
||||
content_margin_top = 10.0
|
||||
content_margin_bottom = 0.0
|
||||
bg_color = Color( 0, 0, 0, 0.839216 )
|
||||
content_margin_top = 20.0
|
||||
bg_color = Color( 0, 0, 0, 0.729412 )
|
||||
border_width_top = 1
|
||||
border_width_bottom = 1
|
||||
border_color = Color( 1, 0.45098, 0.992157, 1 )
|
||||
|
||||
[node name="MarkdownLabel" type="ScrollContainer"]
|
||||
margin_right = 1920.0
|
||||
margin_bottom = 1080.0
|
||||
scroll_horizontal_enabled = false
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
script = ExtResource( 1 )
|
||||
markdown = ""
|
||||
default_font = SubResource( 7 )
|
||||
|
@ -58,21 +56,26 @@ header_font = SubResource( 11 )
|
|||
mono_font = SubResource( 12 )
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="."]
|
||||
margin_right = 1920.0
|
||||
margin_bottom = 1080.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
custom_constants/separation = 0
|
||||
|
||||
[node name="RichTextLabel" type="RichTextLabel" parent="VBoxContainer"]
|
||||
visible = false
|
||||
margin_right = 1920.0
|
||||
margin_bottom = 69.0
|
||||
rect_min_size = Vector2( 1920, 0 )
|
||||
rect_clip_content = false
|
||||
focus_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
theme = ExtResource( 2 )
|
||||
custom_colors/default_color = Color( 1, 1, 1, 1 )
|
||||
custom_colors/selection_color = Color( 0.207843, 0, 0.321569, 1 )
|
||||
custom_styles/normal = SubResource( 6 )
|
||||
tab_size = 2
|
||||
fit_content_height = true
|
||||
scroll_active = false
|
||||
selection_enabled = true
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
|
@ -80,22 +83,18 @@ __meta__ = {
|
|||
|
||||
[node name="TextEdit" type="TextEdit" parent="VBoxContainer"]
|
||||
visible = false
|
||||
margin_right = 1920.0
|
||||
rect_min_size = Vector2( 1920, 0 )
|
||||
size_flags_vertical = 3
|
||||
custom_colors/selection_color = Color( 0.207843, 0, 0.321569, 1 )
|
||||
custom_colors/executing_line_color = Color( 0.0392157, 0, 0.168627, 1 )
|
||||
custom_colors/font_color_readonly = Color( 0.878431, 0.878431, 0.878431, 1 )
|
||||
custom_fonts/font = SubResource( 13 )
|
||||
custom_styles/read_only = SubResource( 3 )
|
||||
custom_styles/normal = SubResource( 3 )
|
||||
indent_using_spaces = true
|
||||
indent_size = 2
|
||||
readonly = true
|
||||
syntax_highlighting = true
|
||||
show_line_numbers = true
|
||||
smooth_scrolling = true
|
||||
wrap_enabled = true
|
||||
caret_blink = true
|
||||
caret_moving_by_right_click = false
|
||||
__meta__ = {
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
[gd_scene load_steps=14 format=2]
|
||||
[gd_scene load_steps=15 format=2]
|
||||
|
||||
[ext_resource path="res://components/Console.gdns" type="Script" id=1]
|
||||
[ext_resource path="res://components/TextEdit.gdns" type="Script" id=2]
|
||||
[ext_resource path="res://components/ActionButton.tscn" type="PackedScene" id=3]
|
||||
[ext_resource path="res://components/MarkdownLabel.tscn" type="PackedScene" id=4]
|
||||
[ext_resource path="res://textures/reticle.png" type="Texture" id=5]
|
||||
[ext_resource path="res://themes/DarkTheme.tres" type="Theme" id=6]
|
||||
[ext_resource path="res://themes/SF-Mono-Powerline-Bold.otf" type="DynamicFontData" id=8]
|
||||
|
@ -30,9 +31,6 @@ font_data = ExtResource( 8 )
|
|||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
mouse_filter = 2
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="Toolbar" type="HBoxContainer" parent="."]
|
||||
anchor_top = 1.0
|
||||
|
@ -104,24 +102,21 @@ group = SubResource( 1 )
|
|||
icon = null
|
||||
|
||||
[node name="LeftPanel" type="MarginContainer" parent="."]
|
||||
anchor_right = 0.4
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 1.0
|
||||
margin_right = 192.0
|
||||
mouse_filter = 2
|
||||
theme = ExtResource( 6 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="ThemeHolder" type="VBoxContainer" parent="LeftPanel"]
|
||||
margin_right = 960.0
|
||||
margin_right = 1152.0
|
||||
margin_bottom = 1080.0
|
||||
mouse_filter = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="LeftPanel/ThemeHolder"]
|
||||
margin_right = 960.0
|
||||
margin_right = 1152.0
|
||||
margin_bottom = 1080.0
|
||||
mouse_filter = 2
|
||||
size_flags_horizontal = 3
|
||||
|
@ -130,7 +125,7 @@ size_flags_stretch_ratio = 2.0
|
|||
|
||||
[node name="Editor" type="TextEdit" parent="LeftPanel/ThemeHolder/MarginContainer"]
|
||||
visible = false
|
||||
margin_right = 960.0
|
||||
margin_right = 1152.0
|
||||
margin_bottom = 1080.0
|
||||
size_flags_vertical = 3
|
||||
custom_colors/selection_color = Color( 0.184314, 0.0117647, 0.686275, 1 )
|
||||
|
@ -163,6 +158,18 @@ scroll_following = true
|
|||
selection_enabled = true
|
||||
script = ExtResource( 1 )
|
||||
|
||||
[node name="RightPanel" type="MarginContainer" parent="."]
|
||||
visible = false
|
||||
anchor_left = 0.5
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
|
||||
[node name="MarkdownLabel" parent="RightPanel" instance=ExtResource( 4 )]
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_right = 960.0
|
||||
margin_bottom = 1080.0
|
||||
|
||||
[node name="Reticle" type="Control" parent="."]
|
||||
visible = false
|
||||
anchor_left = 0.5
|
||||
|
|
|
@ -1,10 +1,24 @@
|
|||
[gd_scene load_steps=7 format=2]
|
||||
[gd_scene load_steps=11 format=2]
|
||||
|
||||
[ext_resource path="res://components/MarkdownLabel.tscn" type="PackedScene" id=1]
|
||||
[ext_resource path="res://scenes/env.tres" type="Environment" id=2]
|
||||
[ext_resource path="res://materials/default_ground.tres" type="Material" id=3]
|
||||
[ext_resource path="res://components/GroundNode.gdns" type="Script" id=4]
|
||||
[ext_resource path="res://components/Player.tscn" type="PackedScene" id=6]
|
||||
|
||||
[sub_resource type="QuadMesh" id=3]
|
||||
size = Vector2( 2, 2 )
|
||||
|
||||
[sub_resource type="ViewportTexture" id=5]
|
||||
viewport_path = NodePath("Spatial/Viewport")
|
||||
|
||||
[sub_resource type="SpatialMaterial" id=4]
|
||||
resource_local_to_scene = true
|
||||
flags_transparent = true
|
||||
flags_unshaded = true
|
||||
flags_albedo_tex_force_srgb = true
|
||||
albedo_texture = SubResource( 5 )
|
||||
|
||||
[sub_resource type="PlaneMesh" id=1]
|
||||
material = ExtResource( 3 )
|
||||
size = Vector2( 1000, 1000 )
|
||||
|
@ -28,9 +42,195 @@ shadow_enabled = true
|
|||
shadow_color = Color( 0.658824, 0.658824, 0.658824, 1 )
|
||||
directional_shadow_mode = 0
|
||||
|
||||
[node name="Spatial" type="Spatial" parent="."]
|
||||
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2, -1.99 )
|
||||
|
||||
[node name="Viewport" type="Viewport" parent="Spatial"]
|
||||
size = Vector2( 1500, 1500 )
|
||||
msaa = 4
|
||||
fxaa = true
|
||||
hdr = false
|
||||
usage = 0
|
||||
render_target_v_flip = true
|
||||
render_target_update_mode = 3
|
||||
|
||||
[node name="MarkdownLabel" parent="Spatial/Viewport" instance=ExtResource( 1 )]
|
||||
markdown = "# Parts of an Enu Program
|
||||
|
||||
Enu is programmed with a language called [Nim](https://nim-lang.org). This tutorial teach some of the
|
||||
basics of Nim, as well as a few special features that are unique to Enu.
|
||||
|
||||
## Comments
|
||||
|
||||
Comments are a way to leave notes to yourself or other programmers. They can be
|
||||
used for lots of different things, but generally provide more information on how
|
||||
something works or why it was done a certain way. They can also have more
|
||||
general information, such as the author of the code and when it was written.
|
||||
They start with a `#` sign. Everything else on the line is ignored.
|
||||
|
||||
```nim
|
||||
# Copyright Scott Wadden, 2022
|
||||
|
||||
var last_row = false # we only want to change colors on the last row
|
||||
```
|
||||
|
||||
## Types
|
||||
|
||||
Every piece of data in Enu has a type. These are the most common:
|
||||
|
||||
- `bool` - a `true` or `false` value. Example: `drawing = false`
|
||||
|
||||
- `Number` - a number with a decimal, like `1.0`. Numbers without decimals, like
|
||||
`1` will usually auto convert, but if something isn't working, try adding a
|
||||
decimal. Example: `var age = 12.5`
|
||||
|
||||
- `Text` - Any combination of letters, numbers and punctuation, contained inside
|
||||
double quotes. Example: `var name = \"Sackville Coding Club\"`
|
||||
|
||||
- `Color` - Any one of `blue`, `red`, `green`, `black`, `white`, `brown` or
|
||||
`eraser`. Someday more colors will be available. Example `color = green`
|
||||
|
||||
- `Position` - The place of something in the world. Example:
|
||||
`me.position = player.position`
|
||||
|
||||
- `Thing` - Anything that exists in the Enu world. This could be something you
|
||||
build, a robot, or the player.
|
||||
|
||||
<div style=\"page-break-after: always;\"></div>
|
||||
|
||||
## Variables
|
||||
|
||||
A variable is used to store data. The value is usually set when it is created,
|
||||
and can be modified later. A variable must always hold the same type of data.
|
||||
|
||||
```nim
|
||||
# ok:
|
||||
var age = 12
|
||||
if birthday:
|
||||
age = age + 1
|
||||
|
||||
if reset:
|
||||
age = 0
|
||||
|
||||
# not ok. Age must always be a number, not text:
|
||||
var age = 12
|
||||
if birthday:
|
||||
age = \"13 years old\"
|
||||
```
|
||||
|
||||
Usually variables are defined with just a value, but sometimes you need to
|
||||
specify their type as well. This could be because you're not ready to give it a
|
||||
value, or because you want it to contain more than one kind of `Thing`.
|
||||
|
||||
For example:
|
||||
|
||||
```nim
|
||||
# this won't work because `enemy` gets automatically set to the type of
|
||||
# `Player`, so other things won't work:
|
||||
var enemy = player
|
||||
enemy = me
|
||||
|
||||
# it will work if we do it like this, since `player` and `me` are both `Thing`
|
||||
var enemy: Thing
|
||||
enemy = player
|
||||
enemy = me
|
||||
```
|
||||
|
||||
<div style=\"page-break-after: always;\"></div>
|
||||
|
||||
Usually each variable starts with `var`, but you can also indent to define
|
||||
multiple variables with a single `var`.
|
||||
|
||||
```nim
|
||||
var name = \"Scott\"
|
||||
var age = 43
|
||||
var town = \"Sackville\"
|
||||
|
||||
# this is exactly the same as the above
|
||||
|
||||
var
|
||||
name = \"Scott\"
|
||||
age = 43
|
||||
town = \"Sackville\"
|
||||
```
|
||||
|
||||
## Special Variables
|
||||
|
||||
Enu has some built in variables.
|
||||
|
||||
- `me` - the `Thing` that we're working on in the current script.
|
||||
|
||||
- `speed` - a `Number` to get or set our current speed. `1.0` by default.
|
||||
|
||||
- `color` - the current drawing `Color`. `blue` by default.
|
||||
|
||||
- `scale` - a `Number` to grow or shrink a `Thing`. `1.0` by default. Be careful
|
||||
about making this too small. You might lose the `Thing` you're working on.
|
||||
|
||||
- `position` - where a `Thing` is. You can use this to move something
|
||||
immediately. `position = player.position` would teleport `me` to the player.
|
||||
|
||||
- `drawing` - a `bool` that indicates if commands like `forward` or `back` should
|
||||
draw blocks. `true` by default. `drawing = false` would let you move without
|
||||
drawing anything, which could be useful for making a hole or a new object.
|
||||
|
||||
- `glow` - how bright a `Thing` is. Can be used to make something flash, or to
|
||||
highlight it.
|
||||
|
||||
<div style=\"page-break-after: always;\"></div>
|
||||
|
||||
## Blocks
|
||||
|
||||
Blocks start with a `:`, and are then indented by two spaces. Everything that's
|
||||
inside the block is controlled by whatever started it.
|
||||
|
||||
- `if` - an `if` block will only run if the statement is `true`.
|
||||
|
||||
```nim
|
||||
var length = 0
|
||||
...
|
||||
if length == 0:
|
||||
glow = 1
|
||||
echo \"You need to provide a length!\"
|
||||
# both of the above only happen if `length` is 0.
|
||||
```
|
||||
|
||||
- `times` - Make something happen more than once.
|
||||
|
||||
```nim
|
||||
4.times:
|
||||
forward 5
|
||||
turn right
|
||||
# the above each happen 4 times (which draws a square!)
|
||||
|
||||
back 20
|
||||
# this only happens once, since it isn't in a `times` block.
|
||||
|
||||
8.times(side):
|
||||
# It's also possible to see how many times we've already performed
|
||||
# the action by passing `times` an index variable.
|
||||
# This starts from 0. in this example we're storing the counter in
|
||||
# a variable called `side`. Because we're doing this 8 times,
|
||||
# `side` will be set first to 0, then 1, 2, 3, 4, 5, 6, 7.
|
||||
forward 5
|
||||
if side != 4:
|
||||
turn right
|
||||
else:
|
||||
turn left
|
||||
|
||||
echo \"We drew a bow tie!\"
|
||||
echo \"This will only be printed once because it isn't in a times block\"
|
||||
```
|
||||
|
||||
"
|
||||
|
||||
[node name="MeshInstance" type="MeshInstance" parent="Spatial"]
|
||||
transform = Transform( 0.95, 0, 0, 0, 0.95, 0, 0, 0, 0.95, 0, 0, 0 )
|
||||
mesh = SubResource( 3 )
|
||||
material/0 = SubResource( 4 )
|
||||
|
||||
[node name="Ground" type="MeshInstance" parent="."]
|
||||
mesh = SubResource( 1 )
|
||||
material/0 = null
|
||||
script = ExtResource( 4 )
|
||||
|
||||
[node name="StaticBody" type="StaticBody" parent="Ground"]
|
||||
|
|
|
@ -150,11 +150,11 @@ back 20
|
|||
# this only happens once, since it isn't in a `times` block.
|
||||
|
||||
8.times(side):
|
||||
# It's also possible to see how many times we've already performed the action
|
||||
# by passing `times` an index variable.
|
||||
# This starts from 0. in this example we're storing the counter in a variable
|
||||
# called `side`. Because we're doing this 8 times, `side` will be set first to
|
||||
# 0, then 1, 2, 3, 4, 5, 6, 7.
|
||||
# It's also possible to see how many times we've already performed
|
||||
# the action by passing `times` an index variable.
|
||||
# This starts from 0. in this example we're storing the counter in
|
||||
# a variable called `side`. Because we're doing this 8 times,
|
||||
# `side` will be set first to 0, then 1, 2, 3, 4, 5, 6, 7.
|
||||
forward 5
|
||||
if side != 4:
|
||||
turn right
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import std / lists
|
||||
import std / [lists, algorithm]
|
||||
import pkg / [godot, markdown, hmatching, print, model_citizen]
|
||||
import godotapi / [rich_text_label, scroll_container, text_edit, theme,
|
||||
dynamic_font, dynamic_font_data, style_box]
|
||||
|
@ -16,6 +16,7 @@ gdobj MarkdownLabel of ScrollContainer:
|
|||
bold_italic_font* {.gd_export.}: DynamicFont
|
||||
header_font* {.gd_export.}: DynamicFont
|
||||
mono_font* {.gd_export.}: DynamicFont
|
||||
mono_width* {.gd_export.} = 0
|
||||
current_label: RichTextLabel
|
||||
container: Node
|
||||
og_text_edit: TextEdit
|
||||
|
@ -28,22 +29,38 @@ gdobj MarkdownLabel of ScrollContainer:
|
|||
self.current_label.visible = true
|
||||
|
||||
proc set_font_sizes =
|
||||
let config = GameState.active.config
|
||||
self.default_font.size = config.font_size.value
|
||||
self.italic_font.size = config.font_size.value
|
||||
self.bold_font.size = config.font_size.value
|
||||
self.bold_italic_font.size = config.font_size.value
|
||||
self.mono_font.size = config.font_size.value
|
||||
self.header_font.size = config.font_size.value * 2
|
||||
var size = 3
|
||||
if self.mono_width > 0:
|
||||
let size_str = " ".repeat(self.mono_width + 2)
|
||||
self.mono_font.size = size
|
||||
while self.mono_font.get_string_size(size_str).x < self.rect_size.x:
|
||||
inc size
|
||||
self.mono_font.size = size
|
||||
dec size
|
||||
else:
|
||||
size = GameState.active().config.font_size.value
|
||||
|
||||
self.default_font.size = size
|
||||
self.italic_font.size = size
|
||||
self.bold_font.size = size
|
||||
self.bold_italic_font.size = size
|
||||
self.mono_font.size = size
|
||||
self.header_font.size = size * 2
|
||||
var first = true
|
||||
for child in self.container.get_children:
|
||||
var child = child.as_object(Node)
|
||||
|
||||
if child of TextEdit:
|
||||
var child = TextEdit(child)
|
||||
var height = child.get_line_count * child.get_line_height + 18
|
||||
var height = child.get_line_count * child.get_line_height + 24
|
||||
let lines = dup child.text.split_lines.sorted_by_it(it.len)
|
||||
|
||||
var size = child.rect_min_size
|
||||
size.y = float height
|
||||
if lines.len > 0:
|
||||
let str_size =
|
||||
self.mono_font.get_string_size(" ".repeat(lines.len + 2))
|
||||
size.x = str_size.x
|
||||
child.rect_min_size = size
|
||||
child.rect_size = size
|
||||
elif child of RichTextLabel:
|
||||
|
@ -53,7 +70,7 @@ gdobj MarkdownLabel of ScrollContainer:
|
|||
|
||||
if not first:
|
||||
stylebox = self.current_label.get_stylebox("normal")
|
||||
stylebox.content_margin_top = float(config.font_size.value + 4)
|
||||
stylebox.content_margin_top = float(size + 4)
|
||||
self.current_label.add_stylebox_override("normal", stylebox)
|
||||
else:
|
||||
first = false
|
||||
|
@ -64,6 +81,7 @@ gdobj MarkdownLabel of ScrollContainer:
|
|||
result.add_color_region("#[", "]#", comment_color, false)
|
||||
|
||||
method ready() =
|
||||
self.bind_signals(self, "resized")
|
||||
self.container = self.get_node("VBoxContainer")
|
||||
self.og_text_edit = self.container.get_node("TextEdit") as TextEdit
|
||||
self.og_label = self.container.get_node("RichTextLabel") as RichTextLabel
|
||||
|
@ -77,6 +95,9 @@ gdobj MarkdownLabel of ScrollContainer:
|
|||
GameState.active.config.font_size.changes:
|
||||
if added:
|
||||
self.set_font_sizes()
|
||||
|
||||
method on_resized =
|
||||
self.set_font_sizes()
|
||||
|
||||
proc render_markdown(token: Token, list_position = 0, inline_blocks = false) =
|
||||
var list_position = list_position
|
||||
|
@ -91,6 +112,16 @@ gdobj MarkdownLabel of ScrollContainer:
|
|||
self.render_markdown t
|
||||
label.with(pop, pop, newline)
|
||||
self.needs_margin = true
|
||||
|
||||
of of Em():
|
||||
label.push_font self.italic_font
|
||||
self.render_markdown t
|
||||
label.pop
|
||||
|
||||
of of Strong():
|
||||
label.push_font self.bold_font
|
||||
self.render_markdown t
|
||||
label.pop
|
||||
|
||||
of of CodeSpan():
|
||||
label.with(push_font self.mono_font, push_color ir_black[number],
|
||||
|
@ -114,34 +145,27 @@ gdobj MarkdownLabel of ScrollContainer:
|
|||
self.needs_margin = true
|
||||
|
||||
of of OL():
|
||||
label.push_indent 2
|
||||
self.render_markdown(t, 1)
|
||||
label.pop
|
||||
|
||||
of of UL():
|
||||
label.push_indent 2
|
||||
self.render_markdown(t)
|
||||
label.pop
|
||||
|
||||
of of LI():
|
||||
label.push_font self.mono_font
|
||||
label.with(push_table 2, push_cell, push_font self.mono_font)
|
||||
if list_position > 0:
|
||||
label.add_text LI(t).marker & ". "
|
||||
inc list_position
|
||||
else:
|
||||
label.add_text "• "
|
||||
label.pop
|
||||
label.with(pop, pop, push_cell)
|
||||
self.render_markdown(t, inline_blocks = true)
|
||||
label.with(newline)
|
||||
self.needs_margin = true
|
||||
label.with(pop, pop, newline)
|
||||
|
||||
of of Text():
|
||||
label.add_text t.doc
|
||||
|
||||
of of SoftBreak():
|
||||
label.newline
|
||||
if inline_blocks:
|
||||
label.with(push_font self.mono_font, add_text " ", pop)
|
||||
label.add_text " "
|
||||
else:
|
||||
self.render_markdown(t)
|
||||
|
||||
|
|
Loading…
Reference in New Issue