diff --git a/editor/extmarks.go b/editor/extmarks.go new file mode 100644 index 00000000..92cf00fd --- /dev/null +++ b/editor/extmarks.go @@ -0,0 +1,76 @@ +package editor + +import ( + "fmt" + + "github.com/akiyosi/goneovim/util" + "github.com/neovim/go-client/nvim" +) + +// windowExtmarks is +// ["win_extmark", grid, win, ns_id, mark_id, row, col] +// Updates the position of an extmark which is currently visible in a +// window. Only emitted if the mark has the `ui_watched` attribute. +func (ws *Workspace) windowExtmarks(args []interface{}) { + fmt.Println("win_extmark event") + for _, e := range args { + arg := e.([]interface{}) + grid := util.ReflectToInt(arg[0]) + winid := (arg[1]).(nvim.Window) + _ = util.ReflectToInt(arg[2]) + markid := util.ReflectToInt(arg[3]) + row := util.ReflectToInt(arg[4]) + col := util.ReflectToInt(arg[5]) + + win, ok := ws.screen.getWindow(grid) + if !ok { + fmt.Println("debug 21:: continue") + return + } + + var gw *Guiwidget + ws.guiWidgets.Range(func(_, gITF interface{}) bool { + g := gITF.(*Guiwidget) + if g == nil { + return true + } + if markid == g.markID && g.winid == winid { + gw = g + return false + } + return true + }) + if gw == nil { + fmt.Println("debug 22:: continue") + continue + } + + win.storeGuiwidget(gw.id, gw) + cell := win.content[row][col] + if cell != nil { + cell.decal = &Decal{ + exists: true, + markid: markid, + } + } + + win.hasExtmarks = true + // if gw.width == 0 && gw.height == 0 { + // continue + // } + // fmt.Println("debug::", "gridid", win.grid, gw.markID, "text", gw.text, "row,col:", row, col, "width, height:", gw.width, gw.height) + // win.queueRedraw(row, col, gw.width+1, gw.height) + // for i := row; i <= row+gw.height; i++ { + // if i >= len(win.contentMask) { + // continue + // } + // for j := col; j <= col+gw.height; j++ { + // if j >= len(win.contentMask[i]) { + // continue + // } + // win.contentMask[i][j] = true + // } + // } + // win.update() + } +} diff --git a/editor/guiwidget.go b/editor/guiwidget.go new file mode 100644 index 00000000..20f0f360 --- /dev/null +++ b/editor/guiwidget.go @@ -0,0 +1,174 @@ +package editor + +import ( + "fmt" + _ "image/gif" + _ "image/jpeg" + _ "image/png" + "strconv" + "time" + + "github.com/akiyosi/goneovim/util" + "github.com/neovim/go-client/nvim" + "github.com/therecipe/qt/core" +) + +type Guiwidget struct { + Tooltip + + raw string + data *core.QByteArray + mime string + width int + height int + id int + markID int + winid nvim.Window +} + +func newGuiwidget() *Guiwidget { + guiwidget := NewGuiwidget(nil, 0) + guiwidget.data = nil + guiwidget.width = 0 + guiwidget.height = 0 + guiwidget.mime = "" + guiwidget.id = 0 + guiwidget.ConnectPaintEvent(guiwidget.paint) + + return guiwidget +} + +// GuiWidgetPut pushes visual resource data to the front-end +func (w *Workspace) handleRPCGuiwidgetput(updates []interface{}) { + fmt.Println("put guiwidgets") + for _, update := range updates { + a := update.(map[string]interface{}) + + idITF, ok := a["id"] + if !ok { + fmt.Println("debug 7:: continue") + continue + } + id := util.ReflectToInt(idITF) + + var g *Guiwidget + if g, ok = w.getGuiwidgetFromResID(id); !ok { + g = newGuiwidget() + w.storeGuiwidget(id, g) + g.s = w.screen + g.setFont(g.s.font) + } + + g.id = id + + mime, ok := a["mime"] + if ok { + g.mime = mime.(string) + } + + data, ok := a["data"] + if ok { + s := data.(string) + + switch mime { + case "text/plain": + g.updateText(g.s.hlAttrDef[0], s) + + case "image/svg", + "image/svg+xml", + "image/png", + "image/gif", + "image/jpeg", + "image/*": + g.raw = s + default: + } + } + } +} + +// GuiWidgetUpdateView sends a list of "placements". +// A placement associates an extmark with a resource id, and provides +// display options for a widget (width, height, mouse events etc.). +func (w *Workspace) handleRPCGuiwidgetview(updates []interface{}) { + fmt.Println("view guiwidgets") + var markid, resid, width, height int + for _, update := range updates { + a := update.(map[string]interface{}) + + buf, ok := a["buf"] + if !ok { + fmt.Println("debug 10:: continue") + continue + } + + errChan := make(chan error, 60) + var err error + var outstr string + go func() { + outstr, err = w.nvim.CommandOutput( + fmt.Sprintf("echo bufwinid(%d)", util.ReflectToInt(buf)), + ) + errChan <- err + }() + select { + case <-errChan: + case <-time.After(40 * time.Millisecond): + } + + out, _ := strconv.Atoi(outstr) + winid := (nvim.Window)(out) + + widgets, ok := a["widgets"] + if !ok { + fmt.Println("debug 11:: continue") + continue + } + for _, e := range widgets.([]interface{}) { + for k, ee := range e.([]interface{}) { + if k == 0 { + markid = util.ReflectToInt(ee) + } else if k == 1 { + resid = util.ReflectToInt(ee) + } else if k == 2 { + width = util.ReflectToInt(ee) + } else if k == 3 { + height = util.ReflectToInt(ee) + } + if k >= 4 { + } + } + + var g *Guiwidget + if g, ok = w.getGuiwidgetFromResID(resid); !ok { + g = newGuiwidget() + w.storeGuiwidget(resid, g) + g.s = w.screen + g.setFont(g.s.font) + } + + g.winid = winid + g.markID = markid + g.width = width + g.height = height + + switch g.mime { + case "text/plain": + baseFont := g.s.ws.font + g.setFont( + // Set font adjusted to widgets height + initFontNew( + baseFont.fontNew.Family(), + float64(baseFont.height*g.height)*0.7, + 0, + 0, + ), + ) + default: + } + + } + + } + +} diff --git a/editor/imetooltip.go b/editor/imetooltip.go index d971728a..0a3d85c6 100644 --- a/editor/imetooltip.go +++ b/editor/imetooltip.go @@ -149,7 +149,7 @@ func (i *IMETooltip) updateVirtualCursorPos() { i.cursorVisualPos = int(x) return } - x += chunk.width + x += float64(chunk.scale) * i.font.cellwidth k++ } } diff --git a/editor/screen.go b/editor/screen.go index 4dee98ca..3d59256d 100644 --- a/editor/screen.go +++ b/editor/screen.go @@ -1390,6 +1390,8 @@ func (s *Screen) detectCoveredCellInGlobalgrid() { } func (s *Screen) update() { + // shownMarks := []int{} + s.windows.Range(func(grid, winITF interface{}) bool { win := winITF.(*Window) // if grid is dirty, we remove this grid @@ -1414,6 +1416,9 @@ func (s *Screen) update() { win.fill() } win.update() + + // shownMarksWin := win.updateExtMarks() + // shownMarks = append(shownMarks, shownMarksWin...) } return true diff --git a/editor/screen_test.go b/editor/screen_test.go index d79af11f..80d42e17 100644 --- a/editor/screen_test.go +++ b/editor/screen_test.go @@ -229,11 +229,11 @@ func TestWindow_updateLine(t *testing.T) { }, }, []Cell{ - Cell{hldef[7], "~", true, false}, - Cell{hldef[7], " ", true, false}, - Cell{hldef[7], " ", true, false}, - Cell{hldef[7], " ", true, false}, - Cell{hldef[7], " ", true, false}, + Cell{hldef[7], "~", true, false, nil}, + Cell{hldef[7], " ", true, false, nil}, + Cell{hldef[7], " ", true, false, nil}, + Cell{hldef[7], " ", true, false, nil}, + Cell{hldef[7], " ", true, false, nil}, }, }, { @@ -254,11 +254,11 @@ func TestWindow_updateLine(t *testing.T) { }, }, []Cell{ - Cell{hldef[7], "~", true, false}, - Cell{hldef[7], " ", true, false}, - Cell{hldef[7], " ", true, false}, - Cell{hldef[6], "*", true, false}, - Cell{hldef[6], "*", true, false}, + Cell{hldef[7], "~", true, false, nil}, + Cell{hldef[7], " ", true, false, nil}, + Cell{hldef[7], " ", true, false, nil}, + Cell{hldef[6], "*", true, false, nil}, + Cell{hldef[6], "*", true, false, nil}, }, }, { @@ -282,11 +282,11 @@ func TestWindow_updateLine(t *testing.T) { }, }, []Cell{ - Cell{hldef[7], "~", true, false}, - Cell{hldef[6], "@", true, false}, - Cell{hldef[6], "v", true, false}, - Cell{hldef[6], "i", true, false}, - Cell{hldef[6], "m", true, false}, + Cell{hldef[7], "~", true, false, nil}, + Cell{hldef[6], "@", true, false, nil}, + Cell{hldef[6], "v", true, false, nil}, + Cell{hldef[6], "i", true, false, nil}, + Cell{hldef[6], "m", true, false, nil}, }, }, { @@ -308,11 +308,11 @@ func TestWindow_updateLine(t *testing.T) { }, }, []Cell{ - Cell{hldef[7], " ", true, false}, - Cell{hldef[7], " ", true, false}, - Cell{hldef[7], "J", true, false}, - Cell{hldef[6], "i", true, false}, - Cell{hldef[6], "m", true, false}, + Cell{hldef[7], " ", true, false, nil}, + Cell{hldef[7], " ", true, false, nil}, + Cell{hldef[7], "J", true, false, nil}, + Cell{hldef[6], "i", true, false, nil}, + Cell{hldef[6], "m", true, false, nil}, }, }, } diff --git a/editor/tooltip.go b/editor/tooltip.go index ba6b4c4c..86e07d0f 100644 --- a/editor/tooltip.go +++ b/editor/tooltip.go @@ -11,7 +11,7 @@ import ( type ColorStr struct { hl *Highlight str string - width float64 + scale int } // Tooltip is the tooltip @@ -59,15 +59,17 @@ func (t *Tooltip) drawContent(p *gui.QPainter, f func(*gui.QPainter)) { r := []rune(chunk.str) for _, rr := range r { // draw background - p.FillRect4( - core.NewQRectF4( - x, - y, - chunk.width, - height, - ), - bg.QColor(), - ) + if !bg.equals(t.s.ws.background) { + p.FillRect4( + core.NewQRectF4( + x, + y, + float64(chunk.scale)*t.font.cellwidth, + height, + ), + bg.QColor(), + ) + } // set italic if italic { @@ -96,19 +98,25 @@ func (t *Tooltip) drawContent(p *gui.QPainter, f func(*gui.QPainter)) { core.NewQRectF4( x, y+height-underlinePos, - chunk.width, + float64(chunk.scale)*t.font.cellwidth, underlinePos, ), fg.QColor(), ) } - x += chunk.width + x += float64(chunk.scale) * t.font.cellwidth } } } func (t *Tooltip) setQpainterFont(p *gui.QPainter) { + if p == nil { + return + } + if t.font == nil { + return + } p.SetFont(t.font.fontNew) } @@ -143,21 +151,25 @@ func (t *Tooltip) updateText(hl *Highlight, str string) { // rune text r := []rune(str) + var preScale int var preStrWidth float64 var buffer bytes.Buffer for k, rr := range r { // detect char width based cell width w := font.cellwidth + scale := 1 for { cwidth := font.fontMetrics.HorizontalAdvance(string(rr), -1) if cwidth <= w { break } w += font.cellwidth + scale++ } if preStrWidth == 0 { preStrWidth = w + preScale = scale } if preStrWidth == w { @@ -170,9 +182,10 @@ func (t *Tooltip) updateText(hl *Highlight, str string) { if buffer.Len() != 0 { t.text = append(t.text, &ColorStr{ - hl: hl, - str: buffer.String(), - width: preStrWidth, + hl: hl, + str: buffer.String(), + // width: preStrWidth, + scale: preScale, }) buffer.Reset() @@ -180,13 +193,15 @@ func (t *Tooltip) updateText(hl *Highlight, str string) { if preStrWidth != w && k == len(r)-1 { t.text = append(t.text, &ColorStr{ - hl: hl, - str: buffer.String(), - width: w, + hl: hl, + str: buffer.String(), + // width: w, + scale: scale, }) } preStrWidth = w + preScale = scale } } @@ -213,15 +228,24 @@ func (t *Tooltip) update() { for _, chunk := range t.text { r := []rune(chunk.str) for _, _ = range r { - tooltipWidth += chunk.width + tooltipWidth += float64(chunk.scale) * t.font.cellwidth } } + font := t.font + if font == nil { + font = t.s.ws.font + } + // update widget size t.SetFixedSize2( int(tooltipWidth), t.font.lineHeight, ) + t.SetAutoFillBackground(true) + p := gui.NewQPalette() + p.SetColor2(gui.QPalette__Background, t.s.ws.background.QColor()) + t.SetPalette(p) t.Update() } diff --git a/editor/window.go b/editor/window.go index d7fb43a2..00976f54 100644 --- a/editor/window.go +++ b/editor/window.go @@ -18,6 +18,7 @@ import ( "github.com/neovim/go-client/nvim" "github.com/therecipe/qt/core" "github.com/therecipe/qt/gui" + "github.com/therecipe/qt/svg" "github.com/therecipe/qt/widgets" ) @@ -68,12 +69,19 @@ type HlDecoration struct { underdashed bool } +// Decal is +type Decal struct { + exists bool + markid int +} + // Cell is type Cell struct { highlight *Highlight char string normalWidth bool covered bool + decal *Decal } type IntInt [2]int @@ -157,6 +165,8 @@ type Window struct { isMsgGrid bool isGridDirty bool doGetSnapshot bool + hasExtmarks bool + guiWidgets sync.Map } type localWindow struct { @@ -268,6 +278,10 @@ func (w *Window) paint(event *gui.QPaintEvent) { w.drawForeground(p, y, col, cols) } + for y := row; y < row+rows; y++ { + w.drawExtmarks(p, y, col, cols) + } + // Draw scroll snapshot // TODO: If there are wrapped lines in the viewport, the snapshot will be misaligned. w.drawScrollSnapshot(p) @@ -1287,6 +1301,9 @@ func (w *Window) updateLine(row, col int, cells []interface{}) { line[col].char = cell[0].(string) line[col].normalWidth = w.isNormalWidth(line[col].char) + if line[col].decal != nil { + line[col].decal = nil + } if hl != -1 || col == 0 { line[col].highlight = hlAttrDef[hl] @@ -1557,7 +1574,7 @@ func (w *Window) update() { start := w.queueRedrawArea[1] end := w.queueRedrawArea[3] // Update all lines when using the wheel scroll or indent guide feature. - if w.scrollPixels[0] != 0 || w.scrollPixels[1] != 0 || editor.config.Editor.IndentGuide || w.s.name == "minimap" { + if w.scrollPixels[0] != 0 || w.scrollPixels[1] != 0 || editor.config.Editor.IndentGuide || w.s.name == "minimap" || w.hasExtmarks { start = 0 end = w.rows } @@ -1613,6 +1630,12 @@ func (w *Window) update() { drawWithSingleRect = true } } + // If window has extmark + if w.hasExtmarks { + width = w.cols + drawWithSingleRect = true + } + width++ // Create rectangles that require updating. @@ -2570,6 +2593,258 @@ func (w *Window) drawDecoration(p *gui.QPainter, highlight *Highlight, font *Fon } } +func (w *Window) drawExtmarks(p *gui.QPainter, y int, col int, cols int) { + if y >= len(w.content) { + return + } + line := w.content[y] + font := w.getFont() + + // Set smooth scroll offset + scrollPixels := 0 + if w.lastScrollphase != core.Qt__NoScrollPhase { + scrollPixels = w.scrollPixels2 + } + if editor.config.Editor.LineToScroll == 1 { + scrollPixels += w.scrollPixels[1] + } + + for x := 0; x <= col+cols; x++ { + if x >= len(line) { + continue + } + if line[x] == nil { + continue + } + if line[x].decal == nil { + continue + } + if line[x].decal.exists { + + w.guiWidgets.Range(func(_, resITF interface{}) bool { + res := resITF.(*Guiwidget) + if res == nil { + return true + } + + if res.markID == line[x].decal.markid { + width := int(float64(res.width) * font.cellwidth) + height := res.height * font.lineHeight + + if res.mime == "text/plain" { + // res.updateText(w.s.hlAttrDef[0], res.text) + p.FillRect5( + int(float64(x)*font.cellwidth), + y*font.lineHeight+scrollPixels, + width, + height, + w.s.ws.background.QColor(), + ) + } + res.drawExtmark( + int(float64(x)*font.cellwidth), + y*font.lineHeight+scrollPixels, + width, + height, + p, + res.setQpainterFont, + w.devicePixelRatio, + ) + } + + return true + }) + + } + + } +} + +func (g *Guiwidget) drawExtmark(x, y, width, height int, p *gui.QPainter, f func(*gui.QPainter), devicePixelRatio float64) { + f(p) + + p.SetPen2(g.s.ws.foreground.QColor()) + + switch g.mime { + case "text/plain": + g.drawText( + float64(x), + float64(y), + float64(width), + float64(height), + p, g.setQpainterFont) + + case "image/svg": + g.data = core.NewQByteArray2(g.raw, len(g.raw)) + + if g.data == nil { + return + } + renderer := svg.NewQSvgRenderer3( + g.data, + nil, + ) + + image := gui.NewQImage3( + g.width, + g.height, + gui.QImage__Format_ARGB32_Premultiplied, + ) + if image == nil { + return + } + image.SetDevicePixelRatio(devicePixelRatio) + image.Fill3(core.Qt__transparent) + pi := gui.NewQPainter2(image) + + renderer.Render(pi) + + g.drawImage(p, image, x, y, width, height) + + case "image/*", + "image/gif", + "image/jpeg", + "image/png": + g.data = core.NewQByteArray2(g.raw, len(g.raw)) + + image := gui.NewQImage3( + g.width, + g.height, + gui.QImage__Format_ARGB32_Premultiplied, + ) + image.SetDevicePixelRatio(devicePixelRatio) + // image.Fill2(g.s.ws.background.QColor()) + if g.data == nil { + return + } + result := image.LoadFromData2( + g.data, + g.mime, + ) + if !result { + return + } + + g.drawImage(p, image, x, y, width, height) + default: + } +} + +func (g *Guiwidget) drawText(x, y, width, height float64, p *gui.QPainter, f func(*gui.QPainter)) { + f(p) + font := p.Font() + + p.SetPen2(g.s.ws.foreground.QColor()) + + if g.text == nil { + return + } + + for _, chunk := range g.text { + + fg := chunk.hl.fg() + bg := chunk.hl.bg() + // bold := chunk.hl.bold + underline := chunk.hl.underline + // undercurl := chunk.hl.undercurl + // strikethrough := chunk.hl.strikethrough + italic := chunk.hl.italic + + // set foreground color + p.SetPen2(fg.QColor()) + + r := []rune(chunk.str) + for _, rr := range r { + // draw background + if !bg.equals(g.s.ws.background) { + p.FillRect4( + core.NewQRectF4( + x, + y, + float64(chunk.scale)*g.font.cellwidth, + height, + ), + bg.QColor(), + ) + } + + // set italic + if italic { + font.SetItalic(true) + } else { + font.SetItalic(false) + } + + p.DrawText( + core.NewQPointF3( + x, + y+float64(g.font.shift), + ), + string(rr), + ) + + // draw underline + if underline { + var underlinePos float64 = 1 + if g.s.ws.palette.widget.IsVisible() { + underlinePos = 2 + } + + // draw underline + p.FillRect4( + core.NewQRectF4( + x, + y+height-underlinePos, + float64(chunk.scale)*g.font.cellwidth, + underlinePos, + ), + fg.QColor(), + ) + } + + x += float64(chunk.scale) * g.font.cellwidth + } + } +} + +func (g *Guiwidget) drawImage(p *gui.QPainter, image *gui.QImage, x, y, width, height int) { + if image == nil { + return + } + var pixmap *gui.QPixmap + pixmap = pixmap.FromImage2( + image, + core.Qt__AutoColor, + ) + if pixmap == nil { + return + } + + pixmap = pixmap.ScaledToHeight( + height, + core.Qt__SmoothTransformation, + ) + + if pixmap == nil { + return + } + + p.FillRect5( + x, y, + pixmap.Rect().Width(), + height, + g.s.ws.background.QColor(), + ) + + p.DrawPixmap7( + core.NewQPointF3( + float64(x), + float64(y), + ), + pixmap, + ) +} + func (w *Window) getFillpatternAndTransparent(hl *Highlight) (core.Qt__BrushStyle, *RGBA, int) { color := hl.bg() pattern := core.Qt__BrushStyle(1) @@ -3289,3 +3564,51 @@ func (w *Window) layoutExternalWindow(x, y int) { } } + +func (w *Window) getGuiwidgetFromResID(resid int) (*Guiwidget, bool) { + gITF, ok := w.guiWidgets.Load(resid) + if !ok { + return nil, false + } + g := gITF.(*Guiwidget) + if g == nil { + return nil, false + } + + return g, true + // for _, g := range w.guiWidgets { + // if resid == g.id { + // return g + // } + // } + + // return nil +} + +func (w *Window) getGuiwidgetFromMarkID(markid int) *Guiwidget { + + // for _, g := range w.guiWidgets { + // if markid == g.markID { + // return g + // } + // } + + var guiwidget *Guiwidget + w.guiWidgets.Range(func(_, gITF interface{}) bool { + g := gITF.(*Guiwidget) + if g == nil { + return true + } + if markid == g.markID { + guiwidget = g + return true + } + return true + }) + + return guiwidget +} + +func (w *Window) storeGuiwidget(resid int, g *Guiwidget) { + w.guiWidgets.Store(resid, g) +} diff --git a/editor/workspace.go b/editor/workspace.go index 3abea10f..ca3a7c58 100644 --- a/editor/workspace.go +++ b/editor/workspace.go @@ -27,6 +27,8 @@ type workspaceSignal struct { _ func() `signal:"stopSignal"` _ func() `signal:"redrawSignal"` _ func() `signal:"guiSignal"` + _ func() `signal:"guiwidgetputSignal"` + _ func() `signal:"guiwidgetviewSignal"` _ func() `signal:"statuslineSignal"` _ func() `signal:"lintSignal"` @@ -111,6 +113,12 @@ type Workspace struct { isDrawStatusline bool isDrawTabline bool isMouseEnabled bool + + guiwidgetNSID int + guiwidgetputUpdates chan []interface{} + guiwidgetviewUpdates chan []interface{} + // guiWidgets []*Guiwidget + guiWidgets sync.Map } func newWorkspace() *Workspace { @@ -334,8 +342,18 @@ func (ws *Workspace) registerSignal(signal *workspaceSignal, redrawUpdates chan editor.putLog("Received GUI event from neovim") ws.handleGui(updates) }) - ws.signal.ConnectLazyLoadSignal(func() { - if ws.hasLazyUI { + w.signal.ConnectGuiwidgetputSignal(func() { + updates := <-w.guiwidgetputUpdates + editor.putLog("Received GUI event from neovim") + w.handleRPCGuiwidgetput(updates) + }) + w.signal.ConnectGuiwidgetviewSignal(func() { + updates := <-w.guiwidgetviewUpdates + editor.putLog("Received GUI event from neovim") + w.handleRPCGuiwidgetview(updates) + }) + w.signal.ConnectLazyDrawSignal(func() { + if w.hasLazyUI { return } if editor.config.Editor.ExtTabline { @@ -1196,6 +1214,9 @@ func (ws *Workspace) handleRedraw(updates [][]interface{}) { case "win_viewport": ws.windowViewport(args) + case "win_extmark": + w.windowExtmarks(args) + // Popupmenu Events case "popupmenu_show": if ws.cmdline != nil { @@ -1745,6 +1766,7 @@ func (ws *Workspace) handleGui(updates []interface{}) { switch event { case "gonvim_enter": editor.putLog("vim enter") + case "gonvim_uienter": editor.putLog("ui enter") // ws.uiEnterProcess() @@ -2656,6 +2678,40 @@ func (ws *Workspace) toggleIndentguide() { go ws.nvim.Command("doautocmd WinEnter") } +func (w *Workspace) getGuiwidgetFromResID(resid int) (*Guiwidget, bool) { + gITF, ok := w.guiWidgets.Load(resid) + if !ok { + return nil, false + } + g := gITF.(*Guiwidget) + if g == nil { + return nil, false + } + + return g, true +} + +func (w *Workspace) getGuiwidgetFromMarkID(markid int) *Guiwidget { + var guiwidget *Guiwidget + w.guiWidgets.Range(func(_, gITF interface{}) bool { + g := gITF.(*Guiwidget) + if g == nil { + return true + } + if markid == g.markID { + guiwidget = g + return true + } + return true + }) + + return guiwidget +} + +func (w *Workspace) storeGuiwidget(resid int, g *Guiwidget) { + w.guiWidgets.Store(resid, g) +} + // WorkspaceSide is type WorkspaceSide struct { widget *widgets.QWidget