From b8c3d7f856f33ecd18e88c296c4b2c3dd02786ba Mon Sep 17 00:00:00 2001 From: "Marcel M. Otte" Date: Wed, 4 Jan 2023 13:38:16 +0100 Subject: [PATCH] First protocol editor interface prototype working --- internal/app/app.go | 44 ++++++++++++++----- internal/ui/fieldadd.go | 5 ++- internal/ui/fieldeditor.go | 75 +++++++++++++++++++++++++++++++-- internal/ui/protocoleditor.go | 14 ++++-- protocol/field.go | 2 +- protocol/protocol.go | 2 +- protocolctl/protocolctl.go | 34 +++++++++++---- protocolctl/protocolctl_test.go | 2 +- 8 files changed, 148 insertions(+), 30 deletions(-) diff --git a/internal/app/app.go b/internal/app/app.go index e2b2dc9..177be85 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -9,6 +9,7 @@ import ( "fyne.io/fyne/v2/widget" "gitea.mmo.to/ProtocolPacketForger/ppf/internal/ui" + "gitea.mmo.to/ProtocolPacketForger/ppf/protocol" ) var fyneApp fyne.App @@ -17,7 +18,7 @@ var w fyne.Window func Appmain() { fyneApp = app.New() w = fyneApp.NewWindow("ProtocolPacketForger") - w.Resize(fyne.NewSize(800, 600)) + w.Resize(fyne.NewSize(1024, 768)) w.SetContent(CreateApp()) @@ -27,14 +28,14 @@ func Appmain() { type ppfApp struct { // Container for the borderlayout Toolbar fyne.CanvasObject - Metadata *fyne.Container + Metadata *Metadata Extensions *fyne.Container ContextBar *fyne.Container ContentTabs *fyne.Container Workarea *fyne.Container // Once initialized metadata containers for swapping - ProtocolMeta *fyne.Container - PacketMeta *fyne.Container + ProtocolMeta *ProtocolMetadata + PacketMeta *PacketMetadata // Global important stuff Settings map[string]string ProtocolForging bool @@ -45,17 +46,32 @@ type ppfApp struct { var ppf ppfApp +type Metadata struct { + Representation *fyne.Container +} +type PacketMetadata struct { + Metadata +} + +type ProtocolMetadata struct { + Metadata + NameValue *widget.Entry + VersionValue *widget.Entry + ExtendsValue *widget.Entry + DescValue *widget.Entry +} + func CreateApp() *fyne.Container { ppf.Toolbar = CreateToolbar() ppf.Workarea = CreateWorkarea() ppf.Extensions = container.NewCenter() - ppf.Metadata = container.NewCenter() + ppf.ProtocolMeta = CreateMetadataProtocol() ppf.ContextBar = container.NewCenter() return container.NewBorder( ppf.Toolbar, - ppf.Metadata, ppf.ContextBar, + ppf.Metadata.Representation, ppf.Extensions, container.NewVScroll(ppf.Workarea), ) @@ -92,7 +108,8 @@ func CreateWorkarea() *fyne.Container { return ui.GetProtocolEditor().Representation } -func CreateMetadataProtocol() *fyne.Container { +func CreateMetadataProtocol() *ProtocolMetadata { + md := ProtocolMetadata{} vbox := container.NewVBox() vbox.Add(widget.NewLabel("Protocol Metadata")) form := container.New(layout.NewFormLayout()) @@ -107,11 +124,12 @@ func CreateMetadataProtocol() *fyne.Container { multiline := widget.NewMultiLineEntry() multiline.SetMinRowsVisible(3) vbox.Add(multiline) - - return vbox + md.Representation = vbox + return &md } -func CreateMetadataPacket() *fyne.Container { +func CreateMetadataPacket() *PacketMetadata { + md := PacketMetadata{} vbox := container.NewVBox() vbox.Add(widget.NewLabel("Packet Metadata")) form := container.New(layout.NewFormLayout()) @@ -122,5 +140,9 @@ func CreateMetadataPacket() *fyne.Container { multiline := widget.NewMultiLineEntry() multiline.SetMinRowsVisible(3) vbox.Add(multiline) - return vbox + return &md +} + +func UpdateProtocolMetadata(prot *protocol.ProtocolStructure) { + // md := ppfApp.ProtocolMeta } diff --git a/internal/ui/fieldadd.go b/internal/ui/fieldadd.go index a2d998c..7d55af9 100644 --- a/internal/ui/fieldadd.go +++ b/internal/ui/fieldadd.go @@ -2,11 +2,14 @@ package ui import ( "fyne.io/fyne/v2/widget" + "gitea.mmo.to/ProtocolPacketForger/ppf/protocolctl" ) func GetAdder(pEd *ProtocolEditor) *widget.Button { fieldAdder := widget.NewButton("Add Field", func() { - pEd.AddFieldCreator(CreateFieldEditor()) + f := protocolctl.NewEmptyField() + index := protocolctl.AppendField(pEd.Reference, f) + pEd.AddFieldCreator(CreateFieldEditor(pEd, index, f)) }) return fieldAdder } diff --git a/internal/ui/fieldeditor.go b/internal/ui/fieldeditor.go index 34edf89..0034ae0 100644 --- a/internal/ui/fieldeditor.go +++ b/internal/ui/fieldeditor.go @@ -1,11 +1,16 @@ package ui import ( + "fmt" + "strconv" + "fyne.io/fyne/v2" "fyne.io/fyne/v2/container" "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/theme" "fyne.io/fyne/v2/widget" "gitea.mmo.to/ProtocolPacketForger/ppf/protocol" + "gitea.mmo.to/ProtocolPacketForger/ppf/protocolctl" ) type FieldEditor struct { @@ -16,30 +21,72 @@ type FieldEditor struct { SizeLabel *widget.Label SizeValue *widget.Entry SizeInBits bool + OptionalCheck *widget.Check + PayloadCheck *widget.Check // to be filled with needed things Reference *protocol.Field + Index int } -func CreateFieldEditor() *FieldEditor { +func CreateFieldEditor(ed *ProtocolEditor, index int, ref *protocol.Field) *FieldEditor { fc := &FieldEditor{} + fc.Reference = ref + fc.Index = index + setfunc := func(s string) { + bits := 0 + if !fc.SizeInBits { + bits, _ = strconv.Atoi(fc.SizeValue.Text) + bits *= 8 + } else { + bits, _ = strconv.Atoi(fc.SizeValue.Text) + } + protocolctl.UpdateFieldByElement( + ed.Reference, + fc.Index, + protocolctl.NewField( + fc.NameValue.Text, + fc.DescValue.Text, + fc.RegExValue.Text, + bits, + nil, //TODO: implement subfields + fc.OptionalCheck.Checked, + fc.PayloadCheck.Checked, + ), + ) + fmt.Printf("%s", protocolctl.ToJson(ed.Reference)) + } fc.Representation = container.New(layout.NewFormLayout()) - fc.Representation.Add(widget.NewLabel("")) - fc.Representation.Add(widget.NewLabel("Field Values")) + toolbar := widget.NewToolbar() + toolbar.Append(widget.NewToolbarAction(theme.DeleteIcon(), func() { + protocolctl.RemoveFieldByElement(ed.Reference, fc.Index) + ed.Redraw() + })) + fc.Representation.Add(toolbar) + addtool := widget.NewToolbar() + addtool.Append(widget.NewToolbarSpacer()) + addtool.Append(widget.NewToolbarAction(theme.ContentAddIcon(), func() { + protocolctl.AddField(ed.Reference, fc.Index+1, protocolctl.NewEmptyField()) + ed.Redraw() + })) + fc.Representation.Add(container.NewBorder(nil, nil, nil, addtool, widget.NewLabel("Field Values"))) fc.Representation.Add(widget.NewLabel("Name")) fc.NameValue = widget.NewEntry() + fc.NameValue.OnChanged = setfunc fc.Representation.Add(fc.NameValue) fc.Representation.Add(widget.NewLabel("Description")) fc.DescValue = widget.NewEntry() fc.DescValue.MultiLine = true + fc.DescValue.OnChanged = setfunc fc.DescValue.SetMinRowsVisible(3) fc.Representation.Add(fc.DescValue) fc.Representation.Add(widget.NewLabel("RegEx")) fc.RegExValue = widget.NewEntry() + fc.RegExValue.OnChanged = setfunc fc.Representation.Add(fc.RegExValue) fc.SizeLabel = widget.NewLabel("Bytes") @@ -51,9 +98,31 @@ func CreateFieldEditor() *FieldEditor { fc.SizeLabel.SetText("Bits") } fc.SizeInBits = !fc.SizeInBits + setfunc("") // bogus call to reflect the change }) fc.Representation.Add(container.NewHBox(toggleBtn, fc.SizeLabel)) fc.SizeValue = widget.NewEntry() + fc.SizeValue.OnChanged = setfunc fc.Representation.Add(fc.SizeValue) + fc.Representation.Add(widget.NewLabel("Settings")) + fc.OptionalCheck = widget.NewCheck("Optional", func(b bool) { + fc.Reference.Optional = b + setfunc("") + }) + fc.PayloadCheck = widget.NewCheck("Payload", func(b bool) { + fc.Reference.Payload = b + setfunc("") + }) + fc.Representation.Add(container.NewHBox(fc.OptionalCheck, fc.PayloadCheck)) + + fc.NameValue.Text = fc.Reference.Name + fc.DescValue.Text = fc.Reference.Desc + fc.RegExValue.Text = fc.Reference.Regex + fc.SizeValue.Text = strconv.Itoa(fc.Reference.Size) + fc.SizeInBits = true + fc.SizeLabel.SetText("Bits") + fc.OptionalCheck.Checked = fc.Reference.Optional + fc.PayloadCheck.Checked = fc.Reference.Payload + fc.Representation.Refresh() return fc } diff --git a/internal/ui/protocoleditor.go b/internal/ui/protocoleditor.go index 5ab4d1b..4eea51e 100644 --- a/internal/ui/protocoleditor.go +++ b/internal/ui/protocoleditor.go @@ -1,6 +1,8 @@ package ui import ( + "fmt" + "fyne.io/fyne/v2" "fyne.io/fyne/v2/container" "gitea.mmo.to/ProtocolPacketForger/ppf/protocol" @@ -15,7 +17,7 @@ type ProtocolEditor struct { } func GetProtocolEditor() *ProtocolEditor { - container := container.NewGridWrap(fyne.NewSize(300, 300)) + container := container.NewGridWrap(fyne.NewSize(300, 400)) protocolEditor := &ProtocolEditor{container, []*FieldEditor{}, protocolctl.NewProtocolStructure()} container.Add(GetAdder(protocolEditor)) return protocolEditor @@ -27,9 +29,13 @@ func (ed *ProtocolEditor) AddFieldCreator(fieldCreator *FieldEditor) { } func (ed *ProtocolEditor) Redraw() { + json := protocolctl.ToJson(ed.Reference) + fmt.Printf("%s", json) ed.Representation.RemoveAll() - for _, v := range ed.Fields { - ed.Representation.Add(v.Representation) + for i, v := range ed.Reference.Structure { + ed.Representation.Add(CreateFieldEditor(ed, i, v).Representation) + } + if len(ed.Reference.Structure) == 0 { + ed.Representation.Add(GetAdder(ed)) } - ed.Representation.Add(GetAdder(ed)) } diff --git a/protocol/field.go b/protocol/field.go index 70efb1d..586d107 100644 --- a/protocol/field.go +++ b/protocol/field.go @@ -6,7 +6,7 @@ type Field struct { Name string // Name of the Field Desc string // Lengthy description Regex string // Regex to recognize values - Size uint // Size in bits! + Size int // Size in bits! SubFields []Field // Possible sub-fields Optional bool // Is this field required? Payload bool // Is this field the payload or next protocol level? diff --git a/protocol/protocol.go b/protocol/protocol.go index daf92d2..ef0df5b 100644 --- a/protocol/protocol.go +++ b/protocol/protocol.go @@ -2,7 +2,7 @@ package protocol type ProtocolStructure struct { Metadata DOPMeta - Structure []Field + Structure []*Field DefaultValues []DefaultValue JavaScript string } diff --git a/protocolctl/protocolctl.go b/protocolctl/protocolctl.go index ed966f3..d59987c 100644 --- a/protocolctl/protocolctl.go +++ b/protocolctl/protocolctl.go @@ -34,11 +34,16 @@ func UpdateMetaData( prot.Metadata.LowerLayerIdentification = lowerLayerIdent } +func NewEmptyField() *protocol.Field { + f := protocol.Field{} + return &f +} + func NewField( name string, desc string, regex string, - size uint, + size int, subfields []protocol.Field, optional bool, payload bool, @@ -55,8 +60,21 @@ func NewField( return &f } -func AppendField(prot *protocol.ProtocolStructure, field *protocol.Field) { - prot.Structure = append(prot.Structure, *field) +func AppendField(prot *protocol.ProtocolStructure, field *protocol.Field) int { + i := len(prot.Structure) + prot.Structure = append(prot.Structure, field) + return i +} +func AddField(prot *protocol.ProtocolStructure, index int, field *protocol.Field) { + if len(prot.Structure) == index { + AppendField(prot, field) + return + } + ret := make([]*protocol.Field, 0) + ret = append(ret, prot.Structure[:index]...) + ret = append(ret, field) + ret = append(ret, prot.Structure[index:]...) + prot.Structure = ret } func UpdateFieldByName(prot *protocol.ProtocolStructure, name string, field *protocol.Field) { @@ -67,12 +85,12 @@ func UpdateFieldByName(prot *protocol.ProtocolStructure, name string, field *pro } } if fnd != -1 { - prot.Structure[fnd] = *field + prot.Structure[fnd] = field } } func UpdateFieldByElement(prot *protocol.ProtocolStructure, element int, field *protocol.Field) { - prot.Structure[element] = *field + prot.Structure[element] = field } func RemoveFieldByName(prot *protocol.ProtocolStructure, name string) { @@ -89,7 +107,7 @@ func RemoveFieldByName(prot *protocol.ProtocolStructure, name string) { } func RemoveFieldByElement(prot *protocol.ProtocolStructure, field int) { - ret := make([]protocol.Field, 0) + ret := make([]*protocol.Field, 0) ret = append(ret, prot.Structure[:field]...) ret = append(ret, prot.Structure[field+1:]...) prot.Structure = ret @@ -111,7 +129,7 @@ func LoadNew(path string) (*protocol.ProtocolStructure, error) { } func ToJson(prot *protocol.ProtocolStructure) string { - data, err := json.Marshal(*prot) + data, err := json.MarshalIndent(*prot, "", " ") if err != nil { return "" } @@ -119,7 +137,7 @@ func ToJson(prot *protocol.ProtocolStructure) string { } func Save(prot *protocol.ProtocolStructure, path string) error { - data, err := json.Marshal(*prot) + data, err := json.MarshalIndent(*prot, "", " ") if err != nil { return err } diff --git a/protocolctl/protocolctl_test.go b/protocolctl/protocolctl_test.go index 4a14788..5a028e9 100644 --- a/protocolctl/protocolctl_test.go +++ b/protocolctl/protocolctl_test.go @@ -49,7 +49,7 @@ func GenerateFields() []protocol.Field { fmt.Sprintf("testfield%d", i), fmt.Sprintf("Description %d", i), "", - uint(i*8), + int(i*8), nil, false, false,