forked from inkyblackness/imgui-go
-
Notifications
You must be signed in to change notification settings - Fork 15
/
imgui_markdown.go
132 lines (112 loc) · 3.75 KB
/
imgui_markdown.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package imgui
// #include "imgui_markdown_wrapper.h"
import "C"
type MarkdownHeaderData struct {
Font Font
HasSeparator bool
}
type MarkdownImageData struct {
TextureID *TextureID
Scale bool
Size Vec2
UseLinkCallback bool
Uv0, Uv1 Vec2
TintColor, BorderColor Vec4
}
// markdownImageCallbackCache stores user-definied image loader
// it is only way to share it with C callback
var markdownImageCallbackCache func(url string) MarkdownImageData
// markdownImageCache stores markdown image data
// TODO: meybe it should be done on client-side?...
var markdownImageCache map[string]*MarkdownImageData
func init() {
markdownImageCache = make(map[string]*MarkdownImageData)
}
// Markdown implements imgui_markdown.h
// NOTE about arguments:
// - data is pointer to markdown text data
// - linkCB is callback called when link is clicked (it should most likely open link in a web browser)
// - imageCB is expected to load an image at `path` and return POINTER to its texture with some other
// stats. BE AWARE that imageCB MUST NOT pause goroutine. It could e.g.:
// - create variable with TextureID = 0
// - invoge a new goroutine and load the texture there and set pointers value
// - return pointer to declared variable
// - headers are headers formatting data. Note, that first index of slice will be applied
// to top-level (H1), second for H2 and so on.
func Markdown(data *string, linkCB func(s string), imageCB func(path string) MarkdownImageData, headers []MarkdownHeaderData) {
// share imageCB with C callback (goMarkdownImageCallback)
markdownImageCallbackCache = imageCB
state := newInputTextState(*data, nil)
defer func() {
*data = state.buf.toGo()
state.release()
}()
// prepare headers for C
cHeaders := []C.iggMarkdownHeaderData{}
if headers != nil {
for _, data := range headers {
cHeaders = append(cHeaders,
C.iggMarkdownHeaderData{
font: data.Font.handle(),
separator: castBool(data.HasSeparator),
},
)
}
}
var cHeadersPtr *C.iggMarkdownHeaderData
if len(cHeaders) > 0 {
// this trick allows to pass go slice into C
// documentation: https://coderwall.com/p/m_ma7q/pass-go-slices-as-c-array-parameters
cHeadersPtr = &cHeaders[0]
}
linkData := C.iggMarkdown(
(*C.char)(state.buf.ptr),
cHeadersPtr, (C.int)(len(cHeaders)),
)
// Read link callback
s := C.GoString(linkData.link)
s = s[:int(linkData.link_len)]
if s != "" {
linkCB(s)
}
}
// goMarkdownImageCallback is exported to C callback for loading markdown images.
// in short, it calls user-definied cached in markdownImageCallbackCache function.
//export goMarkdownImageCallback
func goMarkdownImageCallback(data C.iggMarkdownLinkCallbackData) (result C.iggMarkdownImageData) {
if markdownImageCallbackCache == nil {
return result
}
path := C.GoString(data.link)
path = path[:int(data.link_len)]
// it calls user-definied function only at first time when this is called.
if _, found := markdownImageCache[path]; !found {
markdownImageCache[path] = &MarkdownImageData{}
go func() {
d := markdownImageCallbackCache(path)
*markdownImageCache[path] = d
}()
}
d := markdownImageCache[path]
// check if texture id isn't nil
if d.TextureID == nil {
return result
}
sizeArg, _ := d.Size.wrapped()
uv0, _ := d.Uv0.wrapped()
uv1, _ := d.Uv1.wrapped()
tintColor, _ := d.TintColor.wrapped()
borderColor, _ := d.BorderColor.wrapped()
result = C.iggMarkdownImageData{
texture: d.TextureID.handle(),
shouldScale: castBool(d.Scale),
size: *sizeArg,
useLinkCallback: castBool(d.UseLinkCallback),
uv0: *uv0,
uv1: *uv1,
tintColor: *tintColor,
borderColor: *borderColor,
}
// return to C
return result
}