aboutsummaryrefslogtreecommitdiff
path: root/gui/internal/ui/rules.go
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-09-16 15:33:23 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-09-16 15:33:23 +0200
commit4363c7ad13d5eae1752ea3c36e1cfe7c13707c0d (patch)
treece20a5be9accc7baf7421dbc675ab4e399652569 /gui/internal/ui/rules.go
parent85d65ebe0adf1b156324a3a4c220e415a79ba9ce (diff)
downloadkrino-4363c7ad13d5eae1752ea3c36e1cfe7c13707c0d.tar.gz
krino-4363c7ad13d5eae1752ea3c36e1cfe7c13707c0d.zip
gui: forms editor - rules and excludes as forms, with add, delete and move
Diffstat (limited to 'gui/internal/ui/rules.go')
-rw-r--r--gui/internal/ui/rules.go58
1 files changed, 56 insertions, 2 deletions
diff --git a/gui/internal/ui/rules.go b/gui/internal/ui/rules.go
index 741f6b1..d582f1e 100644
--- a/gui/internal/ui/rules.go
+++ b/gui/internal/ui/rules.go
@@ -42,9 +42,12 @@ type rulesView struct {
testGo *gtk.Button
out *gtk.TextView
+ sub *gtk.Notebook
+ forms *formsView
rules *model.Rules
pending glib.SourceHandle
quiet bool // set while the view is being filled, so no check is armed
+ inSwap bool // set while a sub-tab switch is being handled
}
func newRulesView(w *Window) *rulesView {
@@ -131,19 +134,37 @@ func newRulesView(w *Window) *rulesView {
right.Append(gtk.NewSeparator(gtk.OrientationHorizontal))
right.Append(outScroll)
+ // Two ways to edit the same file: forms, and the text itself.
+ r.sub = gtk.NewNotebook()
+ r.forms = newFormsView(w, r)
+ r.sub.AppendPage(r.forms.root, gtk.NewLabel("Forms"))
+ r.sub.AppendPage(left, gtk.NewLabel("Text"))
+
panes := gtk.NewPaned(gtk.OrientationHorizontal)
- panes.SetStartChild(left)
+ panes.SetStartChild(r.sub)
panes.SetEndChild(right)
panes.SetResizeStartChild(true)
panes.SetResizeEndChild(false)
panes.SetShrinkEndChild(false)
- panes.SetPosition(620)
+ panes.SetPosition(820)
panes.SetVExpand(true)
r.root.Append(bar)
r.root.Append(gtk.NewSeparator(gtk.OrientationHorizontal))
r.root.Append(panes)
+ // Switching to Forms re-reads the text; text that does not parse keeps
+ // the Text tab until it is fixed (GUI design ยง5.2).
+ r.sub.ConnectSwitchPage(func(_ gtk.Widgetter, page uint) {
+ if page != 0 || r.inSwap || r.rules == nil {
+ return
+ }
+ if err := r.forms.reload(); err != nil {
+ r.setCheck("the text does not parse yet: " + err.Error())
+ r.showText()
+ }
+ })
+
r.buf.ConnectChanged(r.onChanged)
r.diags.ConnectRowSelected(func(row *gtk.ListBoxRow) {
if row != nil {
@@ -166,6 +187,34 @@ func newRulesView(w *Window) *rulesView {
return r
}
+// formsOf is the forms of the text in the editor, for the Forms sub-tab.
+func (r *rulesView) formsOf() ([]model.Form, error) {
+ if r.rules == nil {
+ return nil, fmt.Errorf("no file is open")
+ }
+ r.rules.SetText(r.text())
+ return r.rules.Forms()
+}
+
+// setCheck writes one line in the bar where the check result goes.
+func (r *rulesView) setCheck(text string) { r.check.SetText(escape(text)) }
+
+// showText brings the Text sub-tab forward.
+func (r *rulesView) showText() {
+ r.inSwap = true
+ r.sub.SetCurrentPage(1)
+ r.inSwap = false
+}
+
+// textChangedByForm puts the model's text - just rewritten by a form edit -
+// in the view, and checks it.
+func (r *rulesView) textChangedByForm() {
+ r.quiet = true
+ r.buf.SetText(r.rules.Text)
+ r.quiet = false
+ r.runCheck()
+}
+
// selectedName is the directory the picker names, "" when none is offered.
func (r *rulesView) selectedName() string {
i := int(r.dirs.Selected())
@@ -190,6 +239,11 @@ func (r *rulesView) open(name string) {
}
r.rules = rules
r.setEditable(true)
+ defer func() {
+ if err := r.forms.reload(); err != nil {
+ r.forms.clearEditor("the text does not parse yet: " + err.Error())
+ }
+ }()
if root := r.w.dirRoot(name); root != "" {
r.testPath.SetText(xdg.Abbrev(root) + "/")
}