| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132 |
- 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
- }
|