From 0a55c373917fc6eb87654a32e869d80e4095d300 Mon Sep 17 00:00:00 2001 From: "Randall C. O'Reilly" Date: Sun, 7 Jun 2026 13:00:44 +0200 Subject: [PATCH 1/3] canvprop: canvas prevent crash on nil props by using SetProperty --- canvas/layers.go | 10 +++++----- canvas/props.go | 2 +- canvas/text.go | 2 +- canvas/tree.go | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/canvas/layers.go b/canvas/layers.go index af34829d..7cd56bff 100644 --- a/canvas/layers.go +++ b/canvas/layers.go @@ -34,13 +34,13 @@ func (l *Layer) ToNode(n tree.Node) { nb := n.AsTree() nb.Name = l.Name if l.Vis { - nb.Properties["style"] = "" - nb.Properties["display"] = "inline" + nb.SetProperty("style", "") + nb.SetProperty("display", "inline") } else { - nb.Properties["style"] = "display:none" - nb.Properties["display"] = "none" + nb.SetProperty("style", "display:none") + nb.SetProperty("display", "none") } - nb.Properties["insensitive"] = l.Lock + nb.SetProperty("insensitive", l.Lock) } // Layers is the list of all layers diff --git a/canvas/props.go b/canvas/props.go index 8dc89dab..05985523 100644 --- a/canvas/props.go +++ b/canvas/props.go @@ -129,7 +129,7 @@ func (sv *SVG) DistributeProps() { } if _, has := nb.Properties[k]; !has { gotSome = true - nb.Properties[k] = v + nb.SetProperty(k, v) } } } diff --git a/canvas/text.go b/canvas/text.go index d069d4c0..7ec36803 100644 --- a/canvas/text.go +++ b/canvas/text.go @@ -68,7 +68,7 @@ func (cv *Canvas) SetTextProperties(tps map[string]any) { cv.setPropsOnSelected("SetTextProperties", "", func(nd svg.Node) { nb := nd.AsNodeBase() for k, v := range tps { - nb.Properties[k] = v + nb.SetProperty(k, v) } }) } diff --git a/canvas/tree.go b/canvas/tree.go index aedf2432..d66dc5c3 100644 --- a/canvas/tree.go +++ b/canvas/tree.go @@ -161,7 +161,7 @@ func (tv *Tree) LayerToggleLock() { //types:add tv.LayerClearCurrent() np = "true" } - sn.AsTree().Properties["insensitive"] = np + sn.AsTree().SetProperty("insensitive", np) cv.UpdateLayers() } @@ -176,7 +176,7 @@ func (tv *Tree) LayerToggleVis() { //types:add } else { np = "display:inline" } - sn.AsTree().Properties["style"] = np + sn.AsTree().SetProperty("style", np) cv.UpdateLayers() } From e2fb2dab317ade4e333854fc20da025ea31e9a69 Mon Sep 17 00:00:00 2001 From: "Randall C. O'Reilly" Date: Tue, 9 Jun 2026 13:30:57 +0200 Subject: [PATCH 2/3] canvprop: update to latest core, lab --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 08ecf194..f639c4b3 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,8 @@ module cogentcore.org/cogent go 1.25.6 require ( - cogentcore.org/core v0.3.34 - cogentcore.org/lab v0.1.12 + cogentcore.org/core v0.3.35 + cogentcore.org/lab v0.1.13 github.com/Knetic/govaluate v3.0.0+incompatible github.com/aandrew-me/tgpt/v2 v2.7.2 github.com/alecthomas/chroma/v2 v2.23.0 diff --git a/go.sum b/go.sum index f84ed9ba..eac92ce6 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,9 @@ codeberg.org/go-pdf/fpdf v0.11.0 h1:n3I8WISQ1cr0S2rvx9DOlE/GypbcimMWqLpel3slHmY= codeberg.org/go-pdf/fpdf v0.11.0/go.mod h1:Y0DGRAdZ0OmnZPvjbMp/1bYxmIPxm0ws4tfoPOc4LjU= -cogentcore.org/core v0.3.34 h1:dOkexm9sP0WD6ova2uenBbkq+V4rhhTa3YSYhJdJZTM= -cogentcore.org/core v0.3.34/go.mod h1:bq1W15L76MTl+Gd+SB2xxdte1hG9HI9rNyAi+Xgv+Wo= -cogentcore.org/lab v0.1.12 h1:6PQP9/3JRpIT/Nd3kI1DbJ5ijXbaomQ2TouiRgt8SAs= -cogentcore.org/lab v0.1.12/go.mod h1:5V7X3dUbQOSj9p1UQZYhw5fmPCP433fhekiLpzgrjEg= +cogentcore.org/core v0.3.35 h1:4MXrFnPT7gz0VwyBeFZLIjiXpFKgz6GiDjxxMn9CV3Q= +cogentcore.org/core v0.3.35/go.mod h1:bq1W15L76MTl+Gd+SB2xxdte1hG9HI9rNyAi+Xgv+Wo= +cogentcore.org/lab v0.1.13 h1:ahFKpqdsC0rcgCFCueDb5EMtYZNE/5DNgusjP9b4i7o= +cogentcore.org/lab v0.1.13/go.mod h1:Ycjrbd2VvHkB4MlcYvyOQ4YJiQZUYN0XqpkadIOJ8eM= git.sr.ht/~sbinet/cmpimg v0.1.0 h1:E0zPRk2muWuCqSKSVZIWsgtU9pjsw3eKHi8VmQeScxo= git.sr.ht/~sbinet/cmpimg v0.1.0/go.mod h1:FU12psLbF4TfNXkKH2ZZQ29crIqoiqTZmeQ7dkp/pxE= github.com/Bios-Marcel/wastebasket/v2 v2.0.3 h1:TkoDPcSqluhLGE+EssHu7UGmLgUEkWg7kNyHyyJ3Q9g= From e64d8a1355e5d99b0157a7357115792d122f22c5 Mon Sep 17 00:00:00 2001 From: "Randall C. O'Reilly" Date: Tue, 9 Jun 2026 13:38:44 +0200 Subject: [PATCH 3/3] canvprop: actually fix api --- canvas/canvas.go | 6 +++--- canvas/svg.go | 3 ++- canvas/tree.go | 3 ++- code/appbar.go | 24 +++++++++++++----------- code/code.go | 3 ++- code/commands.go | 11 ++++++----- code/filetree.go | 3 ++- code/texteditor.go | 4 ++-- 8 files changed, 32 insertions(+), 25 deletions(-) diff --git a/canvas/canvas.go b/canvas/canvas.go index 51fc8af3..7362a87e 100644 --- a/canvas/canvas.go +++ b/canvas/canvas.go @@ -445,14 +445,14 @@ func (cv *Canvas) MakeToolbar(p *tree.Plan) { }) }) tree.Add(p, func(w *core.Button) { - w.SetText("Size").SetIcon(icons.FormatSize).SetMenu(func(m *core.Scene) { + w.SetText("Size").SetIcon(icons.FormatSize).SetMenu(func(m *core.Scene, pos image.Point) { core.NewFuncButton(m).SetFunc(cv.PromptPhysicalSize).SetText("Set size").SetIcon(icons.FormatSize) core.NewFuncButton(m).SetFunc(cv.ResizeToContents).SetIcon(icons.Resize) }) }) tree.Add(p, func(w *core.Button) { - w.SetText("Open recent").SetMenu(func(m *core.Scene) { + w.SetText("Open recent").SetMenu(func(m *core.Scene, pos image.Point) { for _, rp := range RecentPaths { core.NewButton(m).SetText(rp).OnClick(func(e events.Event) { cv.OpenDrawingCheck(core.Filename(rp)) @@ -478,7 +478,7 @@ func (cv *Canvas) MakeToolbar(p *tree.Plan) { }) tree.Add(p, func(w *core.Button) { - w.SetText("Export").SetIcon(icons.ExportNotes).SetMenu(func(m *core.Scene) { + w.SetText("Export").SetIcon(icons.ExportNotes).SetMenu(func(m *core.Scene, pos image.Point) { core.NewFuncButton(m).SetFunc(cv.ExportPNG).SetIcon(icons.Image) core.NewFuncButton(m).SetFunc(cv.ExportPDF).SetIcon(icons.PictureAsPdf) }) diff --git a/canvas/svg.go b/canvas/svg.go index 7a1985ae..5e54de08 100644 --- a/canvas/svg.go +++ b/canvas/svg.go @@ -7,6 +7,7 @@ package canvas import ( "bytes" "fmt" + "image" "strings" "cogentcore.org/cogent/canvas/cicons" @@ -554,7 +555,7 @@ func (sv *SVG) EditNode(n tree.Node) { //types:add d.RunWindowDialog(sv) } -func (sv *SVG) contextMenu(m *core.Scene) { +func (sv *SVG) contextMenu(m *core.Scene, pos image.Point) { es := sv.EditState() itm := es.FirstSelected() if itm != nil { diff --git a/canvas/tree.go b/canvas/tree.go index d66dc5c3..ca547dc0 100644 --- a/canvas/tree.go +++ b/canvas/tree.go @@ -6,6 +6,7 @@ package canvas import ( "fmt" + "image" "cogentcore.org/core/base/fileinfo" "cogentcore.org/core/colors" @@ -180,7 +181,7 @@ func (tv *Tree) LayerToggleVis() { //types:add cv.UpdateLayers() } -func (tv *Tree) contextMenu(m *core.Scene) { +func (tv *Tree) contextMenu(m *core.Scene, pos image.Point) { sn := tv.SyncNode tri := tv.This.(core.Treer) isLay := NodeIsLayer(sn) diff --git a/code/appbar.go b/code/appbar.go index 0b822da4..b70533af 100644 --- a/code/appbar.go +++ b/code/appbar.go @@ -5,6 +5,8 @@ package code import ( + "image" + "cogentcore.org/core/core" "cogentcore.org/core/events" "cogentcore.org/core/filetree" @@ -32,7 +34,7 @@ func (cv *Code) MakeToolbar(p *tree.Plan) { tree.Add(p, func(w *core.Separator) {}) tree.Add(p, func(w *core.Button) { - w.SetText("Open recent").SetMenu(func(m *core.Scene) { + w.SetText("Open recent").SetMenu(func(m *core.Scene, pos image.Point) { for _, rp := range RecentPaths { core.NewButton(m).SetText(rp).OnClick(func(e events.Event) { cv.OpenRecent(core.Filename(rp)) @@ -120,13 +122,13 @@ func (cv *Code) MakeToolbar(p *tree.Plan) { tree.Add(p, func(w *core.Button) { w.SetText("Command").SetShortcut(KeyExecCmd.Chord()) - w.SetMenu(func(m *core.Scene) { + w.SetMenu(func(m *core.Scene, pos image.Point) { ec := ExecCmds(cv) for _, cc := range ec { cc := cc cat := cc[0] icon := CommandIcons[cat] - core.NewButton(m).SetText(cat).SetIcon(icon).SetMenu(func(mm *core.Scene) { + core.NewButton(m).SetText(cat).SetIcon(icon).SetMenu(func(mm *core.Scene, pos image.Point) { nc := len(cc) for i := 1; i < nc; i++ { cm := cc[i] @@ -143,9 +145,9 @@ func (cv *Code) MakeToolbar(p *tree.Plan) { tree.Add(p, func(w *core.Separator) {}) tree.Add(p, func(w *core.Button) { - w.SetText("Splits").SetMenu(func(m *core.Scene) { + w.SetText("Splits").SetMenu(func(m *core.Scene, pos image.Point) { core.NewButton(m).SetText("Set view"). - SetMenu(func(mm *core.Scene) { + SetMenu(func(mm *core.Scene, pos image.Point) { for _, sp := range AvailableSplitNames { sn := SplitName(sp) mb := core.NewButton(mm).SetText(sp) @@ -158,7 +160,7 @@ func (cv *Code) MakeToolbar(p *tree.Plan) { } }) core.NewFuncButton(m).SetFunc(cv.SplitsSaveAs).SetText("Save as").SetIcon(icons.SaveAs) - core.NewButton(m).SetText("Save").SetIcon(icons.Save).SetMenu(func(mm *core.Scene) { + core.NewButton(m).SetText("Save").SetIcon(icons.Save).SetMenu(func(mm *core.Scene, pos image.Point) { for _, sp := range AvailableSplitNames { sn := SplitName(sp) mb := core.NewButton(mm).SetText(sp) @@ -175,8 +177,8 @@ func (cv *Code) MakeToolbar(p *tree.Plan) { }) } -func (cv *Code) OverflowMenu(m *core.Scene) { - core.NewButton(m).SetText("File").SetMenu(func(m *core.Scene) { +func (cv *Code) OverflowMenu(m *core.Scene, pos image.Point) { + core.NewButton(m).SetText("File").SetMenu(func(m *core.Scene, pos image.Point) { core.NewFuncButton(m).SetFunc(cv.NewProject).SetIcon(icons.NewWindow).SetKey(keymap.New) core.NewFuncButton(m).SetFunc(cv.NewFile).SetText("New file").SetIcon(icons.NewWindow) @@ -200,7 +202,7 @@ func (cv *Code) OverflowMenu(m *core.Scene) { }) - core.NewButton(m).SetText("Edit").SetMenu(func(m *core.Scene) { + core.NewButton(m).SetText("Edit").SetMenu(func(m *core.Scene, pos image.Point) { core.NewButton(m).SetText("Paste history").SetIcon(icons.Paste). SetKey(keymap.PasteHist) @@ -244,7 +246,7 @@ func (cv *Code) OverflowMenu(m *core.Scene) { core.NewFuncButton(m).SetFunc(cv.SpacesToTabs).SetIcon(icons.TabMove) }) - core.NewButton(m).SetText("View").SetMenu(func(m *core.Scene) { + core.NewButton(m).SetText("View").SetMenu(func(m *core.Scene, pos image.Point) { core.NewFuncButton(m).SetFunc(cv.FocusPrevPanel).SetText("Focus prev").SetIcon(icons.KeyboardArrowLeft). SetShortcut(KeyPrevPanel.Chord()) core.NewFuncButton(m).SetFunc(cv.FocusNextPanel).SetText("Focus next").SetIcon(icons.KeyboardArrowRight). @@ -259,7 +261,7 @@ func (cv *Code) OverflowMenu(m *core.Scene) { core.NewFuncButton(m).SetFunc(cv.OpenConsoleTab).SetText("Open console").SetIcon(icons.Terminal) }) - core.NewButton(m).SetText("Command").SetMenu(func(m *core.Scene) { + core.NewButton(m).SetText("Command").SetMenu(func(m *core.Scene, pos image.Point) { core.NewFuncButton(m).SetFunc(cv.DebugAttach).SetText("Debug attach").SetIcon(icons.Debug) core.NewFuncButton(m).SetFunc(cv.VCSUpdateAll).SetText("VCS update all").SetIcon(icons.Update) diff --git a/code/code.go b/code/code.go index 89041322..cb462968 100644 --- a/code/code.go +++ b/code/code.go @@ -9,6 +9,7 @@ package code import ( "fmt" + "image" "io/fs" "log" "log/slog" @@ -223,7 +224,7 @@ func (cv *Code) makeTextEditor(p *tree.Plan, i int) { w.Styler(func(s *styles.Style) { s.Grow.Set(1, 0) }) - w.Menu = func(m *core.Scene) { + w.Menu = func(m *core.Scene, pos image.Point) { cv.EditorButtonMenu(i, m) } w.OnClick(func(e events.Event) { diff --git a/code/commands.go b/code/commands.go index 4435d885..79d38bac 100644 --- a/code/commands.go +++ b/code/commands.go @@ -7,6 +7,7 @@ package code import ( "encoding/json" "fmt" + "image" "log" "os" "os/exec" @@ -804,18 +805,18 @@ func (cm *Commands) ViewStandard() { //types:add var CustomCommandsChanged = false // CommandMenuLines returns a menu function for commands for Lines. -func (cv *Code) CommandMenuLines(ln *lines.Lines) func(mm *core.Scene) { +func (cv *Code) CommandMenuLines(ln *lines.Lines) func(mm *core.Scene, pos image.Point) { return cv.CommandMenu(ln.FileInfo().Known, GetVCSRepo(ln), ln.Filename()) } // CommandMenuFileNode returns a menu function for commands for FileNode. -func (cv *Code) CommandMenuFileNode(fn *filetree.Node) func(mm *core.Scene) { +func (cv *Code) CommandMenuFileNode(fn *filetree.Node) func(mm *core.Scene, pos image.Point) { repo, _ := fn.Repo() return cv.CommandMenu(fn.Info.Known, repo, string(fn.Filepath)) } // CommandMenu returns a menu function for commands for given language and vcs name -func (cv *Code) CommandMenu(lang fileinfo.Known, repo vcs.Repo, fname string) func(mm *core.Scene) { +func (cv *Code) CommandMenu(lang fileinfo.Known, repo vcs.Repo, fname string) func(mm *core.Scene, pos image.Point) { vcstype := cv.VersionControl() if repo != nil { vcstype = repo.Type() @@ -826,7 +827,7 @@ func (cv *Code) CommandMenu(lang fileinfo.Known, repo vcs.Repo, fname string) fu if hsz > 0 { lastCmd = string((cv.CmdHistory)[hsz-1]) } - return func(mm *core.Scene) { + return func(mm *core.Scene, pos image.Point) { for _, cc := range cmds { cc := cc n := len(cc) @@ -836,7 +837,7 @@ func (cv *Code) CommandMenu(lang fileinfo.Known, repo vcs.Repo, fname string) fu cmdCat := cc[0] icon := CommandIcons[cmdCat] cb := core.NewButton(mm).SetText(cmdCat).SetType(core.ButtonMenu).SetIcon(icon) - cb.SetMenu(func(m *core.Scene) { + cb.SetMenu(func(m *core.Scene, pos image.Point) { for ii := 1; ii < n; ii++ { it := cc[ii] cmdNm := CommandName(cmdCat, it) diff --git a/code/filetree.go b/code/filetree.go index 0f8a8cf4..134fb59b 100644 --- a/code/filetree.go +++ b/code/filetree.go @@ -5,6 +5,7 @@ package code import ( + "image" "log" "path/filepath" @@ -90,7 +91,7 @@ func (fn *FileNode) ExecCmdNameFile(cmdNm string) { } } -func (fn *FileNode) ContextMenu(m *core.Scene) { +func (fn *FileNode) ContextMenu(m *core.Scene, pos image.Point) { cv, ok := ParentCode(fn.This) if ok { core.NewButton(m).SetText("Exec Cmd").SetIcon(icons.Terminal). diff --git a/code/texteditor.go b/code/texteditor.go index 82cc3200..eb730de3 100644 --- a/code/texteditor.go +++ b/code/texteditor.go @@ -188,7 +188,7 @@ func ConfigOutputTextEditor(ed *textcore.Editor) { } // ContextMenu builds the text editor context menu -func (ed *TextEditor) ContextMenu(m *core.Scene) { +func (ed *TextEditor) ContextMenu(m *core.Scene, pos image.Point) { core.NewButton(m).SetText("Copy").SetIcon(icons.ContentCopy). SetKey(keymap.Copy).SetState(!ed.HasSelection(), states.Disabled). OnClick(func(e events.Event) { @@ -219,7 +219,7 @@ func (ed *TextEditor) ContextMenu(m *core.Scene) { fn := ed.Code.FileNodeForFile(ed.Lines.Filename()) if fn != nil { fn.SelectEvent(events.SelectOne) - fn.VCSContextMenu(m) + fn.VCSContextMenu(m, pos) } if ed.Code.CurDebug() != nil {