├── .gitignore ├── .idea ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── libraries │ └── GOPATH__Pipeline_Editor_.xml ├── misc.xml ├── modules.xml ├── vcs.xml └── workspace.xml ├── 2017-01-23 12_04_44-Pipeline Editor.png ├── Pipeline-Editor.iml ├── README.md ├── fmetadata └── fmets.go ├── genxml └── genxml.go ├── gfxcanvas ├── gfxcanvas.go ├── grid.go ├── objects.gon └── util.go ├── gfxinterface └── interface.go ├── gfxobjects ├── line │ └── line.go ├── point │ └── point.go └── rectangle │ └── rectangle.go ├── graph ├── graph.go └── meta.go ├── graphpanel ├── filelist.go ├── graphpanel.go ├── lineedit.go ├── nodelist.go ├── tblargs.go └── valuelist.go ├── images ├── New folder │ └── eraser.png ├── circle.png ├── cursor.png ├── eraser.png ├── grid.png ├── hand.png ├── line.png ├── pen.png ├── sizeall.png ├── square.png ├── square.svg └── type.png ├── janus └── janus.go └── main.go /.gitignore: -------------------------------------------------------------------------------- 1 | .idea* 2 | *.iml 3 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/libraries/GOPATH__Pipeline_Editor_.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 1.8 28 | 29 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/workspace.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 15 | 16 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 39 | 40 | 43 | 44 | 45 | 50 | 51 | 52 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 92 | 93 | 94 | 95 | 98 | 99 | 102 | 103 | 104 | 105 | 108 | 109 | 112 | 113 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 128 | 129 | 136 | 137 | 138 | 151 | 152 | 153 | 154 | 168 | 169 | 170 | 171 | 172 | 173 | 180 | 181 | 182 | 183 | 201 | 208 | 209 | 210 | 213 | 214 | 215 | 217 | 218 | 219 | 220 | 1480698240740 221 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 260 | 263 | 264 | 265 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | -------------------------------------------------------------------------------- /2017-01-23 12_04_44-Pipeline Editor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/5k3105/Pipeline-Editor/3b9fe75d83b6d0df95a70ccc337f105b2f98c8cc/2017-01-23 12_04_44-Pipeline Editor.png -------------------------------------------------------------------------------- /Pipeline-Editor.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /fmetadata/fmets.go: -------------------------------------------------------------------------------- 1 | 2 | package fmets 3 | 4 | //type Flight struct { 5 | // Description string `xml:"Description"` 6 | // Collection_Date string `xml:"Collection_Date"` 7 | // Campaign string `xml:"Campaign"` 8 | // Extraction 9 | // Payload 10 | // Sites_Flown 11 | //} 12 | 13 | //type Extraction struct { 14 | // Software 15 | // Extraction_Date string `xml:"Extraction_Date"` 16 | // Extracted_By string `xml:"Extracted_By"` 17 | // Notes string `xml:"Notes"` 18 | // Disk_Serial_Numbers 19 | //} 20 | 21 | //type Software struct { 22 | // Rev string `xml:"Rev"` 23 | // URL string `xml:"URL"` 24 | // Date string `xml:"Date"` 25 | // LastChangedBy string `xml:"LastChangedBy"` 26 | //} 27 | 28 | //type Disk_Serial_Numbers struct { 29 | // DCC string `xml:"DCC"` 30 | // Camera string `xml:"Camera"` 31 | // GPSIMU string `xml:"GPSIMU"` 32 | // Pony_Express_Backup string `xml:"Pony_Express_Backup"` 33 | //} 34 | 35 | //type Payload struct { 36 | // Spectrometer 37 | // Lidar 38 | // Camera 39 | // GPSIMU 40 | //} 41 | 42 | //type Spectrometer struct { 43 | // Serial_Number string `xml:"Serial_Number"` 44 | // Model string `xml:"Model"` 45 | // Comments string `xml:"Comments"` 46 | // Manufacturer string `xml:"Manufacturer"` 47 | //} 48 | 49 | //type Lidar struct { 50 | // Serial_Number string `xml:"Serial_Number"` 51 | // Model string `xml:"Model"` 52 | // Comments string `xml:"Comments"` 53 | // Manufacturer string `xml:"Manufacturer"` 54 | //} 55 | 56 | //type Camera struct { 57 | // Serial_Number string `xml:"Serial_Number"` 58 | // Model string `xml:"Model"` 59 | // Comments string `xml:"Comments"` 60 | // Manufacturer string `xml:"Manufacturer"` 61 | //} 62 | 63 | //type GPSIMU struct { 64 | // Serial_Number string `xml:"Serial_Number"` 65 | // Model string `xml:"Model"` 66 | // Comments string `xml:"Comments"` 67 | // Manufacturer string `xml:"Manufacturer"` 68 | //} 69 | 70 | //type Sites_Flown struct { 71 | // sites []Site 72 | //} 73 | 74 | //type Site struct { 75 | // SiteID string `xml:"SiteID"` 76 | // DomainName string `xml:"DomainName"` 77 | // Type string `xml:"Type"` 78 | // Northing string `xml:"Northing"` 79 | // Easting string `xml:"Easting"` 80 | // State string `xml:"State"` 81 | // Lat string `xml:"Lat"` 82 | // County string `xml:"County"` 83 | // Long string `xml:"Long"` 84 | // PM_Code string `xml:"PM_Code"` 85 | // Science string `xml:"Science"` 86 | // Domain string `xml:"Domain"` 87 | // Ownership string `xml:"Ownership"` 88 | // Zone string `xml:"Zone"` 89 | //} 90 | -------------------------------------------------------------------------------- /genxml/genxml.go: -------------------------------------------------------------------------------- 1 | package genxml 2 | 3 | import ( 4 | "github.com/5k3105/Pipeline-Editor/gfxcanvas" 5 | "github.com/5k3105/Pipeline-Editor/gfxinterface" 6 | "github.com/5k3105/Pipeline-Editor/graphpanel" 7 | "github.com/5k3105/Pipeline-Editor/janus" 8 | "strconv" 9 | 10 | "github.com/beevik/etree" 11 | "github.com/emirpasic/gods/maps/treemap" 12 | ) 13 | 14 | const Scalefactor = 10 15 | 16 | var w, h float64 = 30 * Scalefactor, 10 * Scalefactor 17 | 18 | func LoadXML(filename string, canvas *gfxcanvas.Canvas, gp *graphpanel.GraphPanel) { //}*janus.Graph { 19 | canvas.Statusbar.ShowMessage(" start loadxml ", 0) 20 | 21 | gp.SetJanusGraph(canvas.JanusGraph) // update pointer to new janusgraph 22 | 23 | doc := etree.NewDocument() 24 | if err := doc.ReadFromFile(filename); err != nil { 25 | panic(err) 26 | } 27 | 28 | graph := doc.SelectElement("graph") 29 | 30 | // update janusgraph 31 | canvas.JanusGraph.GraphName = graph.SelectElement("graphName").Text() 32 | canvas.JanusGraph.DatasetPath = graph.SelectElement("datasetPath").Text() 33 | canvas.JanusGraph.JobID = graph.SelectElement("jobID").Text() 34 | 35 | // update graphpanel 36 | gp.GraphName.SetText(graph.SelectElement("graphName").Text()) 37 | gp.DatasetPath.SetText(graph.SelectElement("datasetPath").Text()) 38 | gp.JobID.SetText(graph.SelectElement("jobID").Text()) 39 | 40 | nodes := graph.SelectElement("nodes") 41 | 42 | // create all nodes 43 | for _, node := range nodes.SelectElements("node") { 44 | 45 | x, _ := strconv.ParseFloat(node.SelectElement("x").Text(), 64) 46 | y, _ := strconv.ParseFloat(node.SelectElement("y").Text(), 64) 47 | i, _ := strconv.Atoi(node.SelectElement("nodeID").Text()) 48 | 49 | canvas.AddRectangleFromFile(i, x, y, w, h, 50 | node.SelectElement("language").Text(), 51 | node.SelectElement("className").Text(), 52 | node.SelectElement("scriptFile").Text()) 53 | } 54 | 55 | // create all edges 56 | for _, node := range nodes.SelectElements("node") { 57 | 58 | sid, _ := strconv.Atoi(node.SelectElement("nodeID").Text()) 59 | s, _ := canvas.Figures.Get(sid) 60 | source := s.(gfxinterface.Figure) 61 | 62 | edges := node.SelectElement("edges") 63 | 64 | for _, edge := range edges.SelectElements("edge") { 65 | //if edge != struct{} { 66 | tid, _ := strconv.Atoi(edge.Text()) 67 | t, _ := canvas.Figures.Get(tid) 68 | target := t.(gfxinterface.Figure) 69 | canvas.AddLineFromFile(source, target) 70 | 71 | } 72 | } 73 | 74 | for _, node := range nodes.SelectElements("node") { 75 | 76 | sid, _ := strconv.Atoi(node.SelectElement("nodeID").Text()) 77 | ji, _ := canvas.JanusGraph.Nodes.Get(sid) 78 | jn := ji.(*janus.Node) 79 | 80 | args := node.SelectElement("args") 81 | 82 | for i, arg := range args.ChildElements() { 83 | 84 | if arg.SelectElement("source").Text() == "" { 85 | return 86 | } 87 | 88 | if len(arg.SelectElements("value")) > 1 { 89 | values := treemap.NewWithIntComparator() 90 | for n, ar := range arg.SelectElements("value") { 91 | values.Put(n, ar.Text()) 92 | } 93 | jn.Args.Put(i, &janus.Arg{Source: arg.SelectElement("source").Text(), 94 | Values: values}) 95 | } else { 96 | jn.Args.Put(i, &janus.Arg{Source: arg.SelectElement("source").Text(), 97 | Value: arg.SelectElement("value").Text(), 98 | Values: treemap.NewWithIntComparator()}) 99 | } 100 | } 101 | 102 | // extra element for args table edit-line 103 | jn.Args.Put(len(args.ChildElements()), &janus.Arg{Source: "", 104 | Value: "", 105 | Values: treemap.NewWithIntComparator()}) 106 | 107 | } 108 | 109 | canvas.Statusbar.ShowMessage(" end loadxml ", 0) 110 | } 111 | 112 | func GenXML(gp *graphpanel.GraphPanel, jg *janus.Graph, filename string) { // gp to get graphname etc 113 | 114 | doc := etree.NewDocument() 115 | doc.CreateProcInst("xml", `version="1.0" encoding="UTF-8"`) 116 | //doc.CreateProcInst("xml-stylesheet", `type="text/xsl" href="style.xsl"`) 117 | 118 | graph := doc.CreateElement("graph") 119 | 120 | jg.GraphName = gp.GraphName.Text() 121 | jg.DatasetPath = gp.DatasetPath.Text() 122 | jg.JobID = gp.JobID.Text() 123 | 124 | graph.CreateElement("graphName").SetText(jg.GraphName) 125 | graph.CreateElement("datasetPath").SetText(jg.DatasetPath) 126 | graph.CreateElement("jobID").SetText(jg.JobID) 127 | 128 | nodes := graph.CreateElement("nodes") 129 | 130 | for _, x := range jg.Nodes.Values() { 131 | nv := x.(*janus.Node) 132 | node := nodes.CreateElement("node") 133 | 134 | node.CreateElement("nodeID").SetText(nv.NodeID) 135 | node.CreateElement("language").SetText(nv.Language) 136 | node.CreateElement("scriptFile").SetText(nv.ScriptFile) 137 | node.CreateElement("className").SetText(nv.ClassName) 138 | 139 | node.CreateElement("x").SetText(FloatToString(nv.X)) 140 | node.CreateElement("y").SetText(FloatToString(nv.Y)) 141 | 142 | args := node.CreateElement("args") 143 | 144 | for i, x := range nv.Args.Values() { 145 | av := x.(*janus.Arg) 146 | if av.Source != "" { 147 | arg := args.CreateElement("arg" + strconv.Itoa(i)) 148 | 149 | arg.CreateElement("source").SetText(av.Source) 150 | //if av.Value != "" { 151 | arg.CreateElement("value").SetText(av.Value) 152 | //} 153 | 154 | if !av.Values.Empty() { 155 | for _, x := range av.Values.Values() { 156 | xs := x.(string) 157 | arg.CreateElement("value").SetText(xs) 158 | } 159 | } 160 | } 161 | } 162 | 163 | edges := node.CreateElement("edges") 164 | 165 | for _, x := range nv.Edges.Values() { 166 | xv := x.(*janus.Edge) 167 | edges.CreateElement("edge").SetText(xv.String) 168 | } 169 | 170 | antiedges := node.CreateElement("antiEdges") 171 | 172 | for _, x := range nv.AntiEdges.Values() { 173 | xv := x.(*janus.Edge) 174 | antiedges.CreateElement("antiEdge").SetText(xv.String) 175 | } 176 | 177 | } 178 | 179 | doc.Indent(2) 180 | doc.WriteToFile(filename) 181 | 182 | } 183 | 184 | func FloatToString(input_num float64) string { 185 | return strconv.FormatFloat(input_num, 'f', 1, 64) 186 | } 187 | -------------------------------------------------------------------------------- /gfxcanvas/gfxcanvas.go: -------------------------------------------------------------------------------- 1 | package gfxcanvas 2 | 3 | import ( 4 | "github.com/5k3105/Pipeline-Editor/gfxinterface" 5 | "github.com/5k3105/Pipeline-Editor/gfxobjects/line" 6 | "github.com/5k3105/Pipeline-Editor/gfxobjects/rectangle" 7 | "github.com/5k3105/Pipeline-Editor/graph" 8 | 9 | "github.com/5k3105/Pipeline-Editor/janus" 10 | "strconv" 11 | 12 | "github.com/emirpasic/gods/maps/treemap" 13 | "github.com/therecipe/qt/core" 14 | "github.com/therecipe/qt/gui" 15 | "github.com/therecipe/qt/widgets" 16 | ) 17 | 18 | const Scalefactor = 10 19 | const MvboxSize int = 100 20 | 21 | var ListNodes func() // circular dependencies 22 | 23 | var w, h float64 = 30 * Scalefactor, 10 * Scalefactor 24 | 25 | type Canvas struct { 26 | Scene *widgets.QGraphicsScene 27 | View *widgets.QGraphicsView 28 | Statusbar *widgets.QStatusBar 29 | Graph *graph.Graph 30 | *Grid 31 | Figures *treemap.Map // gfxinterface.Figure 32 | drag bool 33 | drawingline *line.Line 34 | move bool 35 | movingrect *rectangle.Rectangle 36 | JanusGraph *janus.Graph 37 | } 38 | 39 | type Color struct{ R, G, B, A int } 40 | 41 | func NewCanvas(parent *widgets.QMainWindow, lf func()) *Canvas { 42 | 43 | ListNodes = lf 44 | 45 | var canvas = &Canvas{ 46 | Scene: widgets.NewQGraphicsScene(parent), 47 | View: widgets.NewQGraphicsView(parent), 48 | Figures: treemap.NewWithIntComparator(), 49 | JanusGraph: janus.NewJanusGraph()} 50 | 51 | canvas.Grid = canvas.NewGrid(0, 100, 100, 64, 32, 5*Scalefactor, 160, 160, 160, 120) 52 | 53 | canvas.Scene.ConnectKeyPressEvent(canvas.keyPressEvent) 54 | canvas.Scene.ConnectMousePressEvent(canvas.mousePressEvent) 55 | canvas.Scene.ConnectWheelEvent(canvas.wheelEvent) 56 | canvas.Scene.ConnectMouseMoveEvent(canvas.mouseMoveEvent) 57 | 58 | canvas.Graph = graph.NewGraph() 59 | 60 | canvas.View.Scale(0.8, 0.8) 61 | canvas.View.Scale(0.8, 0.8) 62 | 63 | point := core.NewQPointF3(300, 300) 64 | canvas.View.CenterOn(point) 65 | 66 | canvas.View.SetViewportUpdateMode(0) 67 | 68 | // canvas.View.Scale(1, -1) // flips image 69 | 70 | return canvas 71 | } 72 | func (c *Canvas) Reset() { 73 | c.Scene.Clear() 74 | c.JanusGraph = janus.NewJanusGraph() 75 | c.Graph = graph.NewGraph() 76 | c.Figures.Clear() 77 | c.Grid = c.NewGrid(0, 100, 100, 64, 32, 5*Scalefactor, 160, 160, 160, 120) 78 | point := core.NewQPointF3(300, 300) 79 | c.View.CenterOn(point) 80 | } 81 | 82 | func (c *Canvas) mouseMoveEvent(e *widgets.QGraphicsSceneMouseEvent) { 83 | 84 | if c.move { 85 | var px, py = e.ScenePos().X(), e.ScenePos().Y() 86 | var x, y = float64((int(px) / 50) * 50), float64((int(py) / 50) * 50) // round to nearest fit 87 | 88 | c.movingrect.SetX(x - w + 50.0) // + float64(MvboxSize)) 89 | c.movingrect.SetY(y) 90 | c.movingrect.PrepareGeometryChange() 91 | 92 | } 93 | 94 | if c.drag { 95 | var l = c.drawingline 96 | target := l.Target // Point 97 | target.SetX(e.ScenePos().X()) 98 | target.SetY(e.ScenePos().Y()) 99 | l.PrepareGeometryChange() 100 | 101 | c.Statusbar.ShowMessage(FloatToString(target.GetX())+" "+FloatToString(target.GetY()), 0) 102 | } 103 | 104 | c.Scene.MouseMoveEventDefault(e) 105 | } 106 | 107 | func (c *Canvas) wheelEvent(e *widgets.QGraphicsSceneWheelEvent) { 108 | if e.Modifiers() == core.Qt__ControlModifier { 109 | if e.Delta() > 0 { 110 | c.View.Scale(1.25, 1.25) 111 | } else { 112 | c.View.Scale(0.8, 0.8) 113 | } 114 | } 115 | } 116 | 117 | func (c *Canvas) mousePressEvent(e *widgets.QGraphicsSceneMouseEvent) { 118 | var px, py = e.ScenePos().X(), e.ScenePos().Y() 119 | 120 | switch e.Button() { 121 | case 1: // left button 122 | 123 | if c.move { // stop moving rectangle 124 | t, _ := c.JanusGraph.Nodes.Get(c.movingrect.GetNode().Id) 125 | tn := t.(*janus.Node) 126 | tn.X = c.movingrect.X 127 | tn.Y = c.movingrect.Y // save to jgraph 128 | 129 | c.movingrect.Over2 = false 130 | c.move = false 131 | c.movingrect = nil 132 | // do not DestroyQGraphicsItem() because this is a pointer to the real rectangle 133 | return 134 | } 135 | 136 | var x, y = float64((int(px) / 50) * 50), float64((int(py) / 50) * 50) // round to nearest fit 137 | //float64((int(px) / 5) * 5) 138 | var m = c.FindRectOverlap(x, y) 139 | if m == nil { // no node 140 | 141 | r := c.AddRectangle(x-w+50, y, w, h) 142 | c.Statusbar.ShowMessage(FloatToString(r.X)+" "+FloatToString(r.Y), 0) 143 | 144 | } else { 145 | 146 | var m = c.FindRectBeneath(px, py) 147 | if m != nil { // found node 148 | if c.drawingline == nil { 149 | 150 | r := m.(*rectangle.Rectangle) 151 | if r.FindRectBeneath(px, py) { // if over move box 152 | r.Over2 = true 153 | c.move = true 154 | c.movingrect = r 155 | 156 | } else { 157 | 158 | c.DrawLine(m, px, py) 159 | c.Statusbar.ShowMessage("drag start", 0) 160 | } 161 | } else { 162 | 163 | c.AddLine(c.drawingline.Source, m) 164 | c.Statusbar.ShowMessage("drag end", 0) 165 | 166 | } 167 | } 168 | } 169 | case 2: // right button 170 | 171 | if c.drag { 172 | c.CancelDraw() 173 | } else { 174 | var m = c.FindRectBeneath(px, py) 175 | if m != nil { // found node 176 | c.RemoveRectangle(m) 177 | } 178 | } 179 | 180 | } 181 | 182 | ListNodes() // callback 183 | 184 | c.Scene.MousePressEventDefault(e) 185 | 186 | } 187 | 188 | func (c *Canvas) RemoveRectangle(t gfxinterface.Figure) { 189 | 190 | var target = t.(*rectangle.Rectangle) 191 | c.RemoveEdges(target) 192 | 193 | if target.Scene().Pointer() != nil { 194 | target.DestroyQGraphicsItem() 195 | c.Figures.Remove(target.GetNode().Id) // remove from treemap 196 | 197 | } 198 | 199 | c.JanusGraph.RemoveNode(target.GetNode().Id) 200 | } 201 | 202 | func (c *Canvas) RemoveEdges(r *rectangle.Rectangle) { 203 | 204 | for _, f := range r.IncomingEdges.Values() { // ** 205 | l := f.(*line.Line) 206 | if l.Scene().Pointer() != nil { 207 | l.DestroyQGraphicsPathItem() 208 | } 209 | } 210 | 211 | for _, f := range r.OutgoingEdges.Values() { 212 | l := f.(*line.Line) 213 | if l.Scene().Pointer() != nil { 214 | l.DestroyQGraphicsPathItem() 215 | } 216 | } 217 | 218 | r.IncomingEdges.Clear() 219 | r.OutgoingEdges.Clear() // remove from treemap 220 | 221 | nodeid := strconv.Itoa(r.GetNode().Id) 222 | 223 | // use iterators next 224 | 225 | for _, n := range c.JanusGraph.Nodes.Values() { 226 | for _, ne := range n.(*janus.Node).Edges.Values() { 227 | if ne.(*janus.Edge).String == nodeid { 228 | n.(*janus.Node).Edges.Remove(r.GetNode().Id) 229 | } 230 | } 231 | for _, ne := range n.(*janus.Node).AntiEdges.Values() { 232 | if ne.(*janus.Edge).String == nodeid { 233 | n.(*janus.Node).AntiEdges.Remove(r.GetNode().Id) 234 | } 235 | } 236 | } 237 | 238 | } 239 | 240 | func (c *Canvas) AddRectangle(x, y, w, h float64) *rectangle.Rectangle { 241 | 242 | i, r := rectangle.NewRectangle(x, y, w, h, c.Graph) 243 | c.Figures.Put(i, r) 244 | c.Scene.AddItem(r) 245 | 246 | c.JanusGraph.AddNode(i, x, y) 247 | 248 | return r 249 | } 250 | 251 | func (c *Canvas) AddRectangleFromFile(i int, x, y, w, h float64, language, classname, scriptfile string) *rectangle.Rectangle { 252 | 253 | i, r := rectangle.NewRectangleFromFile(i, x, y, w, h, c.Graph) 254 | c.Figures.Put(i, r) 255 | c.Scene.AddItem(r) 256 | 257 | c.JanusGraph.AddNodeFromFile(i, x, y, language, classname, scriptfile) 258 | 259 | return r 260 | } 261 | 262 | func (c *Canvas) AddLine(source gfxinterface.Figure, target gfxinterface.Figure) { 263 | 264 | l := line.AddLine(c.Graph, source, target) 265 | 266 | l.Source.AddEdgeOutgoing(l) 267 | l.Target.AddEdgeIncoming(l) 268 | 269 | c.Scene.AddItem(l) 270 | 271 | if c.drawingline.Scene().Pointer() != nil { 272 | c.drawingline.DestroyQGraphicsPathItem() 273 | c.drawingline = nil 274 | c.drag = false 275 | 276 | } 277 | 278 | t, _ := c.JanusGraph.Nodes.Get(target.GetNode().Id) 279 | tn := t.(*janus.Node) 280 | 281 | tn.AddEdge(source.GetNode().Id, "Outgoing Edge") 282 | 283 | s, _ := c.JanusGraph.Nodes.Get(source.GetNode().Id) 284 | sn := s.(*janus.Node) 285 | 286 | sn.AddEdge(target.GetNode().Id, "Incoming Edge") 287 | 288 | } 289 | 290 | func (c *Canvas) AddLineFromFile(source gfxinterface.Figure, target gfxinterface.Figure) { 291 | 292 | t, _ := c.JanusGraph.Nodes.Get(target.GetNode().Id) 293 | tn := t.(*janus.Node) 294 | 295 | tn.AddEdge(source.GetNode().Id, "Outgoing Edge") 296 | 297 | // s -> t 298 | s, _ := c.JanusGraph.Nodes.Get(source.GetNode().Id) 299 | sn := s.(*janus.Node) 300 | 301 | sn.AddEdge(target.GetNode().Id, "Incoming Edge") 302 | 303 | l := line.AddLine(c.Graph, source, target) 304 | 305 | c.Scene.AddItem(l) 306 | 307 | l.Source.AddEdgeOutgoing(l) 308 | l.Target.AddEdgeIncoming(l) 309 | 310 | } 311 | 312 | func (c *Canvas) DrawLine(source gfxinterface.Figure, tx, ty float64) { 313 | l := line.DrawLine(source, tx, ty) 314 | c.Scene.AddItem(l) 315 | c.drawingline = l 316 | c.drag = true 317 | } 318 | 319 | func (c *Canvas) keyPressEvent(e *gui.QKeyEvent) { 320 | 321 | if e.Modifiers() == core.Qt__ControlModifier { 322 | switch int32(e.Key()) { 323 | case int32(core.Qt__Key_Equal): 324 | c.View.Scale(1.25, 1.25) 325 | 326 | case int32(core.Qt__Key_Minus): 327 | c.View.Scale(0.8, 0.8) 328 | } 329 | } 330 | 331 | if e.Key() == int(core.Qt__Key_Escape) { 332 | if c.drag { 333 | c.CancelDraw() 334 | } 335 | } 336 | } 337 | 338 | func (c *Canvas) CancelDraw() { 339 | if c.drawingline.Scene().Pointer() != nil { 340 | c.drawingline.DestroyQGraphicsPathItem() 341 | c.drawingline = nil 342 | c.drag = false 343 | 344 | } 345 | } 346 | 347 | func (c *Canvas) ClearScene() { 348 | c.Scene.Clear() 349 | c.View.SetScene(c.Scene) 350 | c.View.Show() 351 | 352 | } 353 | 354 | func (c *Canvas) ShowPic(filepath, filetype string) { 355 | 356 | // string from core.QByteArray like this: (*QByteArray).ConstData() 357 | 358 | ft := core.NewQByteArray2(filetype,len(filetype)) 359 | 360 | ir := gui.NewQImageReader3(filepath, ft) 361 | img := ir.Read() 362 | 363 | pix := gui.QPixmap_FromImage(img, 0) 364 | 365 | c.Scene.Clear() 366 | c.Scene.AddPixmap(pix) 367 | 368 | c.View.SetScene(c.Scene) 369 | c.View.Show() 370 | 371 | } 372 | 373 | func FloatToString(input_num float64) string { 374 | return strconv.FormatFloat(input_num, 'f', 1, 64) 375 | } 376 | -------------------------------------------------------------------------------- /gfxcanvas/grid.go: -------------------------------------------------------------------------------- 1 | package gfxcanvas 2 | 3 | import "github.com/therecipe/qt/gui" 4 | 5 | type Grid struct { 6 | Color 7 | PenWidth int 8 | X, Y float64 9 | Vstep, Hstep, Step float64 10 | } 11 | 12 | func (c *Canvas) NewGrid(penwidth int, x, y, vstep, hstep, step float64, r, g, b, a int) *Grid { 13 | 14 | var inpcolor = Color{r, g, b, a} 15 | 16 | var grid = &Grid{ 17 | Color: inpcolor, 18 | PenWidth: penwidth, 19 | X: x, 20 | Y: y, 21 | Vstep: vstep, 22 | Hstep: hstep, 23 | Step: step} 24 | 25 | var color = gui.NewQColor3(r, g, b, a) 26 | var pen = gui.NewQPen3(color) 27 | pen.SetWidth(penwidth) 28 | 29 | for x := grid.X; x <= hstep*step; x += step { 30 | c.Scene.AddLine2(x, 0, x, vstep*step, pen) 31 | } 32 | 33 | for y := grid.Y; y <= vstep*step; y += step { 34 | c.Scene.AddLine2(0, y, hstep*step, y, pen) 35 | } 36 | 37 | c.View.SetScene(c.Scene) 38 | c.View.Show() 39 | return grid 40 | } 41 | 42 | // vstep := 24.0 43 | // hstep := 64.0 44 | // step := 5.0 45 | -------------------------------------------------------------------------------- /gfxcanvas/objects.gon: -------------------------------------------------------------------------------- 1 | package RoundedRect 2 | 3 | import ( 4 | "github.com/therecipe/qt/core" 5 | "github.com/therecipe/qt/gui" 6 | "github.com/therecipe/qt/widgets" 7 | ) 8 | 9 | type RoundedRect struct { 10 | *widgets.QGraphicsItem 11 | Scene *widgets.QGraphicsScene 12 | X, Y float64 13 | W, H int 14 | } 15 | 16 | func NewRectangle(x, y float64, step, w, h int, s *widgets.QGraphicsScene) *RoundedRect { 17 | i := &RoundedRect{} 18 | i.QGraphicsItem = widgets.NewQGrapicsItem(nil) 19 | i.Scene = s 20 | i.X = x 21 | i.Y = y 22 | i.W = w 23 | i.H = h 24 | 25 | i.SetAcceptHoverEvents(true) 26 | i.ConnectHoverEnterEvent(i.rectHoverEnterEvent) 27 | i.ConnectHoverLeaveEvent(i.rectHoverLeaveEvent) 28 | 29 | i.ConnectBoundingRect(boundingRect) 30 | i.ConnectPaint(paint) 31 | 32 | return i 33 | } 34 | 35 | func (i *widgets.QGraphicsItem) paint(p *gui.QPainter, o *QStyleOptionGraphicsItem, w *QWidget) { 36 | var color = gui.NewQColor2(0, 0, 0, 255) // r,g,b,a 37 | var pen = gui.NewQPen3(color) 38 | pen.SetWidth(1) 39 | var brush = gui.NewQBrush() 40 | 41 | var x, y = float64((int(i.X) / step) * step), float64((int(i.Y) / step) * step) // round to nearest fit 42 | 43 | p.SetRenderHint(1) // Antiailiasing 44 | var path = gui.NewQPainterPath() 45 | path.AddRoundedRect2(x, y, i.W, i.H, 10, 10) 46 | p.SetPen(pen) 47 | color = gui.NewQColor2(0, 0, 0, 100) // r,g,b,a 48 | p.FillPath(path, color) 49 | p.DrawPath(path) 50 | } 51 | 52 | func (i *widgets.QGraphicsItem) boundingRect() *core.QRectF { 53 | return core.QRectF(150, 150, 60, 60) 54 | } 55 | 56 | func (i *widgets.QGraphicsItem) rectHoverEnterEvent(e *widgets.QGraphicsSceneHoverEvent) { 57 | var x, y = e.Pos().X(), e.Pos().Y() 58 | var i = c.Scene.ItemAt3(x, y, nil) 59 | var p = core.NewQPointF() 60 | p = i.ScenePos() 61 | x, y = p.X(), p.Y() 62 | //c.Statusbar.ShowMessage("object is: "+i.Data(0).ToString(), 0) 63 | c.Statusbar.ShowMessage("object is: "+FloatToString(x)+" "+FloatToString(y), 0) 64 | 65 | var color = gui.NewQColor2(0, 0, 0, 255/2) // r,g,b,a 66 | var pen = gui.NewQPen3(color) 67 | pen.SetWidth(0) 68 | var brush = gui.NewQBrush() 69 | r := widgets.NewQGraphicsRectItem3(x+(20/2), y+(10/2), 20/2, 10/2, nil) 70 | r.SetPen(pen) 71 | r.SetBrush(brush) 72 | c.Scene.AddItem(r) 73 | 74 | //c.Statusbar.ShowMessage("hovering: "+FloatToString(e.Pos().X())+", "+FloatToString(e.Pos().Y()), 0) 75 | } 76 | 77 | func (i *widgets.QGraphicsItem) rectHoverLeaveEvent(e *widgets.QGraphicsSceneHoverEvent) { 78 | var x, y = e.Pos().X(), e.Pos().Y() 79 | var i = c.Scene.ItemAt3(x, y, nil) 80 | c.Scene.RemoveItem(i) 81 | 82 | } 83 | -------------------------------------------------------------------------------- /gfxcanvas/util.go: -------------------------------------------------------------------------------- 1 | package gfxcanvas 2 | 3 | import ( 4 | "github.com/5k3105/Pipeline-Editor/gfxinterface" 5 | "github.com/5k3105/Pipeline-Editor/gfxobjects/rectangle" 6 | ) 7 | 8 | func (c *Canvas) FindRectOverlap(x, y float64) gfxinterface.Figure { 9 | // overlap of 2 rectangles 10 | 11 | // detect right and below 12 | // L2x, L2y := x, y 13 | // R2x, R2y := x+300, y+100 14 | 15 | // detect left and below 16 | L2x, L2y := x-300+50, y 17 | R2x, R2y := x, y+100 18 | 19 | for _, f := range c.Figures.Values() { 20 | i := f.(*rectangle.Rectangle) 21 | 22 | L1x, L1y := i.X, i.Y 23 | R1x, R1y := i.X+i.W, i.Y+i.H 24 | 25 | if L2x < R1x && R2x > L1x && L2y < R1y && R2y > L1y { 26 | return i 27 | } 28 | } 29 | 30 | return nil 31 | } 32 | 33 | func (c *Canvas) FindRectBeneath(x, y float64) gfxinterface.Figure { 34 | // point within another rect area 35 | for _, f := range c.Figures.Values() { 36 | i := f.(*rectangle.Rectangle) 37 | 38 | if x >= i.X && x <= i.X+i.W && y >= i.Y && y <= i.Y+i.H { 39 | return i 40 | } 41 | } 42 | 43 | return nil 44 | } 45 | 46 | //func (c *Canvas) FindRectBeneath2(x, y, iX, iY float64) bool { 47 | 48 | // if x >= iX+15 && x <= iX+20 && y >= iY && y <= iY+5 { 49 | // return true 50 | // } else { 51 | // return false 52 | // } 53 | 54 | //} 55 | -------------------------------------------------------------------------------- /gfxinterface/interface.go: -------------------------------------------------------------------------------- 1 | package gfxinterface 2 | 3 | import "github.com/5k3105/Pipeline-Editor/graph" 4 | 5 | type Figure interface { 6 | GetX() float64 7 | SetX(x float64) 8 | GetY() float64 9 | SetY(y float64) 10 | GetW() float64 11 | GetNode() *graph.Node 12 | AddEdgeIncoming(l Link) 13 | AddEdgeOutgoing(l Link) 14 | // RemoveEdge() 15 | } 16 | 17 | type Link interface { 18 | GetEdge() *graph.Edge 19 | } 20 | -------------------------------------------------------------------------------- /gfxobjects/line/line.go: -------------------------------------------------------------------------------- 1 | package line 2 | 3 | import ( 4 | "github.com/5k3105/Pipeline-Editor/gfxinterface" 5 | "github.com/5k3105/Pipeline-Editor/gfxobjects/point" 6 | "github.com/5k3105/Pipeline-Editor/graph" 7 | 8 | "github.com/therecipe/qt/core" 9 | "github.com/therecipe/qt/gui" 10 | "github.com/therecipe/qt/widgets" 11 | ) 12 | 13 | const penwidth int = 5 14 | 15 | type Line struct { 16 | *widgets.QGraphicsPathItem 17 | Edge *graph.Edge // ? 18 | Type string 19 | Source gfxinterface.Figure 20 | Target gfxinterface.Figure 21 | SX, SY float64 // source 22 | TX, TY float64 // target 23 | fgcolor Color 24 | over bool 25 | } 26 | 27 | type Color struct{ R, G, B, A int } 28 | 29 | func AddLine(g *graph.Graph, source gfxinterface.Figure, target gfxinterface.Figure) *Line { 30 | 31 | var s, t = source.GetNode(), target.GetNode() 32 | 33 | var l = &Line{ 34 | QGraphicsPathItem: widgets.NewQGraphicsPathItem(nil), 35 | Type: "Line", 36 | Edge: g.AddEdge(s, t), 37 | Source: source, 38 | Target: target, 39 | SX: source.GetX(), 40 | SY: source.GetY(), 41 | TX: target.GetX(), 42 | TY: target.GetY()} 43 | 44 | l.ConnectBoundingRect(l.boundingRect) 45 | l.ConnectPaint(l.paint) 46 | 47 | return l 48 | } 49 | 50 | //func AddLineFromFile(g *graph.Graph, source gfxinterface.Figure, target gfxinterface.Figure) *Line { 51 | 52 | // var s, t = source.GetNode(), target.GetNode() 53 | 54 | // var l = &Line{ 55 | // QGraphicsPathItem: widgets.NewQGraphicsPathItem(nil), 56 | // Type: "Line", 57 | // Edge: g.AddEdge(s, t), 58 | // Source: source, 59 | // Target: target, 60 | // SX: source.GetX(), 61 | // SY: source.GetY(), 62 | // TX: target.GetX(), 63 | // TY: target.GetY()} 64 | 65 | // l.ConnectBoundingRect(l.boundingRect) 66 | // l.ConnectPaint(l.paint) 67 | 68 | // return l 69 | //} 70 | 71 | func (l *Line) GetEdge() *graph.Edge { return l.Edge } 72 | 73 | func (l *Line) paint(p *gui.QPainter, o *widgets.QStyleOptionGraphicsItem, widget *widgets.QWidget) { 74 | var color = gui.NewQColor3(0, 0, 0, 255) 75 | var brush = gui.NewQBrush3(color, 0) // solid = 1, nobrush = 0 76 | var pen = gui.NewQPen3(color) 77 | pen.SetWidth(penwidth) 78 | 79 | p.SetRenderHint(1, true) // Antiailiasing 80 | p.SetPen(pen) 81 | p.SetBrush(brush) 82 | 83 | path := gui.NewQPainterPath() 84 | 85 | source := l.Source 86 | target := l.Target 87 | 88 | var sx, sy, tx, ty, w = source.GetX(), source.GetY(), target.GetX(), target.GetY(), target.GetW() 89 | sx, sy = sx+(w/2.0), sy+100.0 // bottom center is output node 90 | tx, ty = tx+(w/2.0), ty // top center is input node 91 | path.MoveTo2(sx, sy) 92 | sy = sy + 50.0 // offset by single step 93 | path.LineTo2(sx, sy) 94 | 95 | //var A, B, C int 96 | 97 | // target straight down 98 | if sy < ty && sx == tx { 99 | path.LineTo2(tx, ty) 100 | p.DrawPath(path) 101 | drawArrow(p, tx, ty) 102 | return 103 | } 104 | 105 | // target straight up 106 | if sy > ty && sx == tx { 107 | var offset = (w/2 + 50.0) 108 | sx = sx + offset 109 | path.LineTo2(sx, sy) // A 110 | ty = ty - 50.0 111 | path.LineTo2(sx, ty) // B 112 | path.LineTo2(tx, ty) // C 113 | 114 | ty = ty + 50.0 115 | path.LineTo2(tx, ty) 116 | p.DrawPath(path) 117 | drawArrow(p, tx, ty) 118 | return 119 | } 120 | 121 | // target bottom left 122 | if sx > tx && sy < ty { 123 | path.LineTo2(tx, sy) 124 | path.LineTo2(tx, ty) 125 | p.DrawPath(path) 126 | drawArrow(p, tx, ty) 127 | return 128 | } 129 | 130 | // target bottom right 131 | if sx < tx && sy < ty { 132 | path.LineTo2(tx, sy) 133 | path.LineTo2(tx, ty) 134 | p.DrawPath(path) 135 | drawArrow(p, tx, ty) 136 | return 137 | } 138 | 139 | // target top right 140 | if sx < tx && sy > ty { 141 | var offset = (w/2 + 50.0) 142 | if sx+offset <= tx-offset { // between 143 | sx = sx + offset 144 | path.LineTo2(sx, sy) // A 145 | 146 | ty = ty - 50.0 147 | path.LineTo2(sx, ty) // B 148 | path.LineTo2(tx, ty) // C 149 | 150 | ty = ty + 50.0 151 | path.LineTo2(tx, ty) 152 | p.DrawPath(path) 153 | drawArrow(p, tx, ty) 154 | return 155 | } else { // around 156 | tx = tx + offset 157 | path.LineTo2(tx, sy) // A 158 | 159 | ty = ty - 50.0 160 | path.LineTo2(tx, ty) // B 161 | tx = tx - offset 162 | path.LineTo2(tx, ty) // C 163 | 164 | ty = ty + 50.0 165 | path.LineTo2(tx, ty) 166 | p.DrawPath(path) 167 | drawArrow(p, tx, ty) 168 | return 169 | } 170 | } 171 | 172 | // target top left 173 | if sx > tx && sy > ty { 174 | var offset = (w/2 + 50.0) 175 | if sx-offset >= tx+offset { // between 176 | sx = sx - offset 177 | path.LineTo2(sx, sy) // A 178 | 179 | ty = ty - 50.0 180 | path.LineTo2(sx, ty) // B 181 | path.LineTo2(tx, ty) // C 182 | 183 | ty = ty + 50.0 184 | path.LineTo2(tx, ty) 185 | p.DrawPath(path) 186 | drawArrow(p, tx, ty) 187 | return 188 | } else { // around 189 | tx = tx - offset 190 | path.LineTo2(tx, sy) // A 191 | 192 | ty = ty - 50.0 193 | path.LineTo2(tx, ty) // B 194 | tx = tx + offset 195 | path.LineTo2(tx, ty) // C 196 | 197 | ty = ty + 50.0 198 | path.LineTo2(tx, ty) 199 | p.DrawPath(path) 200 | drawArrow(p, tx, ty) 201 | return 202 | } 203 | } 204 | 205 | } 206 | 207 | func drawArrow(p *gui.QPainter, x, y float64) { 208 | var color = gui.NewQColor3(0, 0, 0, 255) 209 | var brush = gui.NewQBrush3(color, 1) // solid = 1, nobrush = 0 210 | var pen = gui.NewQPen3(color) 211 | pen.SetWidth(0) 212 | 213 | p.SetRenderHint(1, true) // Antiailiasing 214 | p.SetPen(pen) 215 | p.SetBrush(brush) 216 | 217 | path := gui.NewQPainterPath() 218 | 219 | path.MoveTo2(x-10, y-20) 220 | path.LineTo2(x+10, y-20) 221 | path.LineTo2(x, y) 222 | path.LineTo2(x-10, y-20) 223 | 224 | p.DrawPath(path) 225 | } 226 | 227 | func (l *Line) boundingRect() *core.QRectF { 228 | source := l.Source 229 | target := l.Target 230 | return core.NewQRectF4(source.GetX(), source.GetY(), target.GetX(), target.GetY()) 231 | } 232 | 233 | func (l *Line) boundingRectDL() *core.QRectF { 234 | source := l.Source // Rectangle 235 | target := l.Target // Point 236 | return core.NewQRectF4(source.GetX(), source.GetY(), target.GetX(), target.GetY()) 237 | } 238 | 239 | // draw temporary line 240 | func DrawLine(source gfxinterface.Figure, tx, ty float64) *Line { 241 | 242 | var target = &point.Point{X: tx, Y: ty} 243 | 244 | l := &Line{ 245 | QGraphicsPathItem: widgets.NewQGraphicsPathItem(nil), 246 | Type: "Line", 247 | Source: source, 248 | Target: target} 249 | 250 | l.ConnectBoundingRect(l.boundingRectDL) 251 | l.ConnectPaint(l.draw) 252 | 253 | return l 254 | } 255 | 256 | func (l *Line) draw(p *gui.QPainter, o *widgets.QStyleOptionGraphicsItem, widget *widgets.QWidget) { 257 | var color = gui.NewQColor3(0, 0, 0, 255) 258 | var brush = gui.NewQBrush3(color, 0) 259 | var pen = gui.NewQPen3(color) 260 | pen.SetWidth(penwidth) 261 | 262 | p.SetRenderHint(1, true) // Antiailiasing 263 | p.SetPen(pen) 264 | p.SetBrush(brush) 265 | 266 | path := gui.NewQPainterPath() 267 | // center line start, extend to current cursor location 268 | source := l.Source // Rectangle 269 | target := l.Target // Point 270 | path.MoveTo2(source.GetX()+source.GetW()/2, source.GetY()+100/2) // GetH() ?? 271 | path.LineTo2(target.GetX(), target.GetY()) 272 | 273 | p.DrawPath(path) 274 | } 275 | 276 | //func AutoNumber() int64 { 277 | // autonumber += 1 278 | // return autonumber 279 | //} 280 | 281 | //------------------------------------------------------------------------------ 282 | 283 | //type Line struct { 284 | // *widgets.QGraphicsPathItem 285 | // Color 286 | // Id int 287 | // Source Shape 288 | // Target Shape 289 | // // SId, TId int 290 | // // SX, SY float64 // source 291 | // // TX, TY float64 // target 292 | // over bool 293 | //} 294 | 295 | // SX: sx, 296 | // SY: sy, 297 | // TX: tx, 298 | // TY: ty} 299 | 300 | // paint: 301 | // l.SetPath(path) 302 | // l.Scene.AddPath(path, pen, brush) 303 | -------------------------------------------------------------------------------- /gfxobjects/point/point.go: -------------------------------------------------------------------------------- 1 | package point 2 | 3 | import ( 4 | "github.com/5k3105/Pipeline-Editor/gfxinterface" 5 | "github.com/5k3105/Pipeline-Editor/graph" 6 | ) 7 | 8 | type Point struct { 9 | X, Y float64 10 | } 11 | 12 | func (p *Point) GetX() float64 { return p.X } 13 | func (p *Point) SetX(x float64) { p.X = x } 14 | func (p *Point) GetY() float64 { return p.Y } 15 | func (p *Point) SetY(y float64) { p.Y = y } 16 | func (p *Point) GetW() float64 { return 0.0 } 17 | func (p *Point) GetNode() *graph.Node { return nil } 18 | 19 | func (p *Point) AddEdgeIncoming(edge gfxinterface.Link) {} 20 | 21 | func (p *Point) AddEdgeOutgoing(edge gfxinterface.Link) {} 22 | -------------------------------------------------------------------------------- /gfxobjects/rectangle/rectangle.go: -------------------------------------------------------------------------------- 1 | package rectangle 2 | 3 | import ( 4 | "github.com/5k3105/Pipeline-Editor/gfxinterface" 5 | "github.com/5k3105/Pipeline-Editor/graph" 6 | "strconv" 7 | 8 | "github.com/emirpasic/gods/maps/treemap" 9 | "github.com/therecipe/qt/core" 10 | "github.com/therecipe/qt/gui" 11 | "github.com/therecipe/qt/widgets" 12 | ) 13 | 14 | const MvboxSize float64 = 100 15 | const penwidth int = 5 16 | 17 | type Rectangle struct { 18 | *widgets.QGraphicsItem 19 | Type string 20 | Name string 21 | Node *graph.Node 22 | IncomingEdges *treemap.Map //[]gfxinterface.Link 23 | OutgoingEdges *treemap.Map //[]gfxinterface.Link 24 | X, Y float64 25 | W, H float64 26 | over bool 27 | Over2 bool 28 | fgcolor Color 29 | bgcolor Color 30 | } 31 | 32 | type Color struct{ R, G, B, A int } 33 | 34 | func (r *Rectangle) GetX() float64 { return r.X } 35 | func (r *Rectangle) SetX(x float64) { r.X = x } 36 | func (r *Rectangle) GetY() float64 { return r.Y } 37 | func (r *Rectangle) SetY(y float64) { r.Y = y } 38 | func (r *Rectangle) GetW() float64 { return r.W } 39 | func (r *Rectangle) GetNode() *graph.Node { return r.Node } 40 | 41 | func (r *Rectangle) AddEdgeIncoming(l gfxinterface.Link) { 42 | e := l.GetEdge() 43 | r.IncomingEdges.Put(e.Id, l) 44 | } 45 | 46 | func (r *Rectangle) AddEdgeOutgoing(l gfxinterface.Link) { 47 | e := l.GetEdge() 48 | r.OutgoingEdges.Put(e.Id, l) 49 | } 50 | 51 | func NewRectangle(x, y, w, h float64, g *graph.Graph) (int, *Rectangle) { 52 | 53 | r := &Rectangle{ 54 | QGraphicsItem: widgets.NewQGraphicsItem(nil), 55 | Type: "Rectangle", 56 | Node: g.AddNode(), 57 | IncomingEdges: treemap.NewWithIntComparator(), 58 | OutgoingEdges: treemap.NewWithIntComparator(), 59 | X: x, 60 | Y: y, 61 | W: w, 62 | H: h, 63 | fgcolor: Color{0, 0, 0, 255}, 64 | bgcolor: Color{0, 0, 0, 100}, 65 | } 66 | 67 | r.SetAcceptHoverEvents(true) 68 | r.ConnectHoverEnterEvent(r.hoverEnterEvent) 69 | r.ConnectHoverLeaveEvent(r.hoverLeaveEvent) 70 | 71 | r.ConnectBoundingRect(r.boundingRect) 72 | r.ConnectPaint(r.paint) 73 | 74 | return r.Node.Id, r 75 | } 76 | 77 | func NewRectangleFromFile(i int, x, y, w, h float64, g *graph.Graph) (int, *Rectangle) { 78 | 79 | r := &Rectangle{ 80 | QGraphicsItem: widgets.NewQGraphicsItem(nil), 81 | Type: "Rectangle", 82 | Node: g.AddNodeFromFile(i), 83 | IncomingEdges: treemap.NewWithIntComparator(), 84 | OutgoingEdges: treemap.NewWithIntComparator(), 85 | X: x, 86 | Y: y, 87 | W: w, 88 | H: h, 89 | fgcolor: Color{0, 0, 0, 255}, 90 | bgcolor: Color{0, 0, 0, 100}, 91 | } 92 | 93 | r.SetAcceptHoverEvents(true) 94 | r.ConnectHoverEnterEvent(r.hoverEnterEvent) 95 | r.ConnectHoverLeaveEvent(r.hoverLeaveEvent) 96 | 97 | r.ConnectBoundingRect(r.boundingRect) 98 | r.ConnectPaint(r.paint) 99 | 100 | return r.Node.Id, r 101 | } 102 | 103 | func (r *Rectangle) paint(p *gui.QPainter, o *widgets.QStyleOptionGraphicsItem, w *widgets.QWidget) { 104 | 105 | var color = gui.NewQColor3(r.fgcolor.R, r.fgcolor.G, r.fgcolor.B, r.fgcolor.A) // r,g,b,a 106 | 107 | var pen = gui.NewQPen3(color) 108 | pen.SetWidth(penwidth) 109 | 110 | if r.Over2 { 111 | pen.SetStyle(0) 112 | } 113 | 114 | p.SetRenderHint(1, true) // Antiailiasing 115 | var path = gui.NewQPainterPath() 116 | path.AddRoundedRect2(r.X, r.Y, r.W, r.H, 1, 1, 0) // Qt::AbsoluteSize 117 | p.SetPen(pen) 118 | p.DrawPath(path) 119 | 120 | if r.over { 121 | color = gui.NewQColor3(r.bgcolor.R, r.bgcolor.G, r.bgcolor.B, r.bgcolor.A) // r,g,b,a 122 | var brush = gui.NewQBrush3(color, 1) 123 | p.FillPath(path, brush) 124 | 125 | color = gui.NewQColor3(0, 0, 0, 60) // r,g,b,a 126 | var pen2 = gui.NewQPen2(0) // no pen 127 | 128 | var brush2 = gui.NewQBrush3(color, 1) 129 | var path2 = gui.NewQPainterPath() 130 | 131 | p.SetPen(pen2) 132 | path2.AddRoundedRect2(r.X+r.W-MvboxSize, r.Y, MvboxSize, MvboxSize, 1, 1, 0) // moveme box // (r.X+r.W-5, r.Y, 5, 5, 1, 1, 0) 133 | p.FillPath(path2, brush2) 134 | p.DrawPath(path2) 135 | } 136 | 137 | // if selected {} 138 | 139 | var font = gui.NewQFont2("verdana", 20, 1, false) 140 | p.SetFont(font) 141 | 142 | var qpf = core.NewQPointF3(r.X+10.0, r.Y+r.H-10.0) 143 | 144 | if r.Name == "" { 145 | p.DrawText(qpf, "Node "+strconv.Itoa(r.Node.Id)) 146 | } else { 147 | p.DrawText(qpf, r.Name) //+" "+strconv.Itoa(r.Node.Id)) 148 | } 149 | //p.DrawPath(path) 150 | } 151 | 152 | func (r *Rectangle) boundingRect() *core.QRectF { 153 | return core.NewQRectF4(r.X, r.Y, r.W, r.H) 154 | } 155 | 156 | func (r *Rectangle) hoverEnterEvent(e *widgets.QGraphicsSceneHoverEvent) { 157 | r.over = true 158 | r.Update(core.NewQRectF4(r.X, r.Y, r.W, r.H)) 159 | } 160 | 161 | func (r *Rectangle) hoverLeaveEvent(e *widgets.QGraphicsSceneHoverEvent) { 162 | r.over = false 163 | r.Update(core.NewQRectF4(r.X, r.Y, r.W, r.H)) 164 | } 165 | 166 | func (r *Rectangle) FindRectBeneath(x, y float64) bool { 167 | var iX, iY, iW = r.X, r.Y, r.W 168 | //if x >= iX+iW-5 && x <= iX+iW && y >= iY && y <= iY+5 { 169 | if x >= iX+iW-MvboxSize && x <= iX+iW && y >= iY && y <= iY+MvboxSize { 170 | return true 171 | } else { 172 | return false 173 | } 174 | 175 | } 176 | 177 | func FloatToString(input_num float64) string { 178 | return strconv.FormatFloat(input_num, 'f', 6, 64) 179 | } 180 | -------------------------------------------------------------------------------- /graph/graph.go: -------------------------------------------------------------------------------- 1 | package graph 2 | 3 | import ( 4 | "encoding/json" 5 | "os" 6 | ) 7 | 8 | var autonumber int 9 | 10 | type Graph struct { 11 | Id int 12 | Nodes []*Node `json:",omitempty"` 13 | } 14 | 15 | type Node struct { 16 | Id int 17 | IncomingEdges []*Edge 18 | OutgoingEdges []*Edge 19 | } 20 | 21 | type Edge struct { 22 | Id int 23 | Source *Node `json:",omitempty"` 24 | Target *Node `json:",omitempty"` 25 | } 26 | 27 | func NewGraph() *Graph { 28 | var g Graph 29 | g.Id = AutoNumber() 30 | return &g 31 | } 32 | 33 | // Encode to file 34 | func Save(path string, g *Graph) error { 35 | file, err := os.Create(path) 36 | if err == nil { 37 | encoder := json.NewEncoder(file) 38 | encoder.Encode(g) 39 | } 40 | file.Close() 41 | return err 42 | } 43 | 44 | // Decode file 45 | func Load(path string, g *Graph) (error, *Graph) { 46 | file, err := os.Open(path) 47 | if err == nil { 48 | decoder := json.NewDecoder(file) 49 | err = decoder.Decode(g) 50 | } 51 | file.Close() 52 | return err, g 53 | } 54 | 55 | func (g *Graph) AddNode() *Node { 56 | var n Node 57 | 58 | n.Id = AutoNumber() 59 | g.Nodes = append(g.Nodes, &n) 60 | 61 | return &n 62 | } 63 | 64 | func (g *Graph) AddNodeFromFile(i int) *Node { 65 | var n Node 66 | 67 | n.Id = i //AutoNumber() 68 | autonumber = i // hack 69 | g.Nodes = append(g.Nodes, &n) 70 | 71 | return &n 72 | } 73 | 74 | func (g *Graph) AddEdge(source, target *Node) *Edge { 75 | var e Edge 76 | 77 | e.Id = AutoNumber() 78 | e.Source = source 79 | e.Target = target 80 | 81 | s, er := g.NodeFind(source.Id) 82 | Check(er) 83 | 84 | t, er := g.NodeFind(source.Id) 85 | Check(er) 86 | 87 | g.Nodes[s].OutgoingEdges = append(g.Nodes[s].OutgoingEdges, &e) 88 | g.Nodes[t].IncomingEdges = append(g.Nodes[t].IncomingEdges, &e) 89 | 90 | return &e 91 | } 92 | 93 | func (g *Graph) NodeFind(Id int) (i int, err error) { 94 | var s = g.Nodes 95 | 96 | for i, v := range s { 97 | if v.Id == Id { 98 | return i, err 99 | } 100 | } 101 | return 0, err 102 | } 103 | 104 | func AutoNumber() int { 105 | autonumber += 1 106 | return autonumber 107 | } 108 | 109 | func Check(e error) { 110 | if e != nil { 111 | //_, file, line, _ := runtime.Caller(1) 112 | //fmt.Println(line, "\t", file, "\n", e) 113 | //os.Exit(1) 114 | } 115 | } 116 | 117 | //func AutoNumber() Id { 118 | // var i Id 119 | // autonumber += 1 120 | // i = autonumber 121 | // return i 122 | //} 123 | 124 | //func (g *Graph) RemoveNode(n Node) []Node { 125 | // var s = g.Nodes 126 | 127 | // for i, v := range s { 128 | // if v == n { 129 | // g.Nodes = append(s[0:i], s[i+1:]...) 130 | // return g.Nodes 131 | // } 132 | // } 133 | // return s 134 | 135 | //} 136 | 137 | //func (g *Graph) RemoveEdge() { 138 | 139 | //} 140 | 141 | //------------------------------------------------------------------------------ 142 | 143 | //type Node struct { 144 | // Id 145 | // //X, Y float64 `json:",omitempty"` 146 | // //Incoming []Edge `json:",omitempty"` 147 | // //Outgoing []Edge `json:",omitempty"` 148 | //} 149 | 150 | //func (g *Graph) RemoveNode(n *Node) { 151 | 152 | //} 153 | 154 | //func (g *Graph) RemoveEdge() { 155 | 156 | //} 157 | -------------------------------------------------------------------------------- /graph/meta.go: -------------------------------------------------------------------------------- 1 | package graph //meta 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/emirpasic/gods/maps/treemap" 7 | ) 8 | 9 | type Meta struct { 10 | Type *treemap.Map 11 | Data *treemap.Map 12 | } 13 | 14 | type MetaType struct { 15 | Type string 16 | Version string 17 | Author string 18 | Date time.Time 19 | } 20 | 21 | func NewMeta() *Meta { 22 | var m = &Meta{ 23 | Type: treemap.NewWithIntComparator(), 24 | Data: treemap.NewWithIntComparator(), 25 | } 26 | 27 | return m 28 | } 29 | 30 | func (m *Meta) AddMeta(id int, i interface{}, t string, v string, a string, yr, mon, day int) { 31 | 32 | var mt = &MetaType{ 33 | Type: t, 34 | Version: v, 35 | Author: a, 36 | Date: time.Time{}, 37 | } 38 | 39 | mt.Date.AddDate(yr, mon, day) 40 | 41 | m.Type.Put(id, mt) 42 | 43 | m.Data.Put(id, i) 44 | 45 | } 46 | -------------------------------------------------------------------------------- /graphpanel/filelist.go: -------------------------------------------------------------------------------- 1 | package graphpanel 2 | 3 | import ( 4 | "strings" 5 | 6 | "github.com/therecipe/qt/core" 7 | "github.com/therecipe/qt/gui" 8 | "github.com/therecipe/qt/widgets" 9 | ) 10 | 11 | type Filelist struct{ *widgets.QListWidget } 12 | 13 | func (f *Filelist) KeyPressEvent(e *gui.QKeyEvent) { 14 | 15 | if e.Key() == int(core.Qt__Key_Delete) { 16 | f.TakeItem(f.CurrentRow()) 17 | } else { 18 | view.KeyPressEventDefault(e) 19 | } 20 | 21 | } 22 | 23 | func (f *Filelist) CurrentItemChanged(current *widgets.QListWidgetItem, previous *widgets.QListWidgetItem) { 24 | txt := current.Text() 25 | LoadXML(txt) 26 | graphpanel.FileName.SetText(txt) 27 | } 28 | 29 | func (f *Filelist) DragEnterEvent_(e *gui.QDragEnterEvent) { 30 | e.AcceptProposedAction() 31 | } 32 | 33 | func (f *Filelist) DragMoveEvent_(e *gui.QDragMoveEvent) { 34 | e.AcceptProposedAction() 35 | } 36 | 37 | func (f *Filelist) DropEvent_(e *gui.QDropEvent) { 38 | e.SetDropAction(core.Qt__CopyAction) 39 | e.AcceptProposedAction() 40 | e.SetAccepted(true) 41 | 42 | font := gui.NewQFont2("verdana", 13, 1, false) 43 | 44 | for _, j := range strings.Split(e.MimeData().Text(), "\n") { // Urls() 45 | if j[len(j)-4:] == ".xml" { 46 | n := widgets.NewQListWidgetItem2(j[8:], f, 0) 47 | n.SetFont(font) 48 | 49 | } 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /graphpanel/graphpanel.go: -------------------------------------------------------------------------------- 1 | package graphpanel 2 | 3 | import ( 4 | "github.com/5k3105/Pipeline-Editor/janus" 5 | 6 | "github.com/therecipe/qt/gui" 7 | "github.com/therecipe/qt/widgets" 8 | ) 9 | 10 | var ( 11 | LoadXML func(s string) 12 | GenXML func(s string) 13 | CanvasReset func() 14 | graphpanel *GraphPanel 15 | janusgraph *janus.Graph 16 | ) 17 | 18 | type GraphPanel struct { 19 | *widgets.QDockWidget 20 | FileList Filelist 21 | FileName Lineedit 22 | GraphName Lineedit // QLineEdit 23 | JobID Lineedit 24 | DatasetPath Lineedit 25 | NodeID Lineedit 26 | Language Lineedit 27 | ScriptFile Lineedit 28 | ClassName Lineedit 29 | NodeList Nodelist // QListWidget 30 | EdgeIncoming *widgets.QTableWidget 31 | EdgeOutgoing *widgets.QTableWidget 32 | TblArgs *widgets.QTableView 33 | ValueList Valuelist 34 | GenerateXML *widgets.QPushButton 35 | } 36 | 37 | func NewGraphPanel(parent *widgets.QMainWindow, reset func(), lxml func(s string), genxml func(s string)) *GraphPanel { 38 | 39 | LoadXML = lxml 40 | GenXML = genxml 41 | CanvasReset = reset 42 | 43 | graphpanel = &GraphPanel{} 44 | graphpanel.QDockWidget = widgets.NewQDockWidget("Graph Panel", parent, 0) 45 | 46 | var w = widgets.NewQWidget(parent, 0) 47 | w.SetLayout(graphpanel.ui()) 48 | graphpanel.SetWidget(w) 49 | 50 | return graphpanel 51 | } 52 | 53 | func (gp *GraphPanel) Clear() { 54 | gp.FileName.Clear() 55 | gp.GraphName.Clear() 56 | gp.JobID.Clear() 57 | gp.DatasetPath.Clear() 58 | gp.NodeID.Clear() 59 | gp.Language.Clear() 60 | gp.ScriptFile.Clear() 61 | gp.ClassName.Clear() 62 | gp.NodeList.Clear() 63 | gp.EdgeIncoming.Clear() 64 | gp.EdgeOutgoing.Clear() 65 | gp.Tblargs_Clear() 66 | //gp.TblArgs.Clear() 67 | gp.ValueList.Clear() 68 | 69 | } 70 | 71 | func (gp *GraphPanel) ui() *widgets.QVBoxLayout { 72 | 73 | var vlayout0 = widgets.NewQVBoxLayout() 74 | 75 | var lblFileset = widgets.NewQLabel2("File Set: ", nil, 0) 76 | 77 | gp.FileList = Filelist{widgets.NewQListWidget(nil)} 78 | gp.FileList.SetFont(gui.NewQFont2("verdana", 13, 1, false)) 79 | gp.FileList.SetAcceptDrops(true) 80 | //gp.FileList.SetMaximumHeight(200) 81 | 82 | gp.FileList.ConnectDragEnterEvent(gp.FileList.DragEnterEvent_) 83 | gp.FileList.ConnectDragMoveEvent(gp.FileList.DragMoveEvent_) 84 | gp.FileList.ConnectDropEvent(gp.FileList.DropEvent_) 85 | gp.FileList.ConnectKeyPressEvent(gp.FileList.KeyPressEvent) 86 | 87 | gp.FileList.ConnectCurrentItemChanged(gp.FileList.CurrentItemChanged) 88 | 89 | vlayout0.AddWidget(lblFileset, 0, 0) 90 | vlayout0.AddWidget(gp.FileList, 0, 0) 91 | 92 | var hlayoutLine0 = widgets.NewQHBoxLayout() 93 | 94 | var lblFileName = widgets.NewQLabel2(" File Name: ", nil, 0) 95 | lblFileName.SetSizePolicy2(widgets.QSizePolicy__Fixed, widgets.QSizePolicy__Fixed) 96 | 97 | gp.FileName = Lineedit{widgets.NewQLineEdit(nil)} 98 | gp.FileName.SetObjectName("FileName") 99 | gp.FileName.ConnectEditingFinished(gp.FileName.EditingFinished) 100 | 101 | gp.GenerateXML = widgets.NewQPushButton(nil) 102 | gp.GenerateXML.SetText("Save") 103 | gp.GenerateXML.SetMaximumWidth(150) 104 | gp.GenerateXML.ConnectClicked(func(_ bool) { GenXML(gp.FileName.Text()) }) 105 | 106 | hlayoutLine0.AddWidget(lblFileName, 0, 0) 107 | hlayoutLine0.AddWidget(gp.FileName, 0, 0) 108 | hlayoutLine0.AddWidget(gp.GenerateXML, 0, 0) 109 | 110 | var hlayoutLine1 = gp.line1() // graph 111 | var hlayoutLine2 = gp.line2() // node 112 | var vlayoutLine3 = gp.line3() // arg 113 | 114 | var vlayout = widgets.NewQVBoxLayout() 115 | 116 | vlayout.AddLayout(vlayout0, 0) 117 | vlayout.AddLayout(hlayoutLine0, 0) 118 | 119 | vlayout.AddLayout(hlayoutLine1, 0) 120 | vlayout.AddLayout(hlayoutLine2, 0) 121 | vlayout.AddLayout(vlayoutLine3, 0) 122 | 123 | return vlayout 124 | 125 | } 126 | 127 | func (gp *GraphPanel) SetJanusGraph(j *janus.Graph) { 128 | janusgraph = j 129 | } 130 | 131 | func (gp *GraphPanel) line1() *widgets.QHBoxLayout { 132 | var gbGraphProperties = widgets.NewQGroupBox2("Graph Properties", nil) 133 | 134 | var vlayout = widgets.NewQVBoxLayout() 135 | 136 | var hlayoutLine1 = widgets.NewQHBoxLayout() // graphName, jobID 137 | var hlayoutLine2 = widgets.NewQHBoxLayout() // datasetPath 138 | 139 | var lblGraphName = widgets.NewQLabel2(" Graph Name: ", nil, 0) 140 | lblGraphName.SetSizePolicy2(widgets.QSizePolicy__Fixed, widgets.QSizePolicy__Fixed) 141 | 142 | gp.GraphName = Lineedit{widgets.NewQLineEdit(nil)} 143 | gp.GraphName.SetObjectName("GraphName") 144 | gp.GraphName.ConnectEditingFinished(gp.GraphName.EditingFinished) 145 | 146 | var lblJobID = widgets.NewQLabel2(" Job ID: ", nil, 0) 147 | lblJobID.SetSizePolicy2(widgets.QSizePolicy__Fixed, widgets.QSizePolicy__Fixed) 148 | 149 | gp.JobID = Lineedit{widgets.NewQLineEdit(nil)} 150 | gp.JobID.SetObjectName("JobID") 151 | gp.JobID.ConnectEditingFinished(gp.JobID.EditingFinished) 152 | 153 | var btnNewGraph = widgets.NewQPushButton(nil) 154 | btnNewGraph.SetText("New Graph") 155 | //btnScriptFile.SetMaximumWidth(120) 156 | btnNewGraph.ConnectClicked(func(_ bool) { CanvasReset() }) 157 | 158 | var lblDatasetPath = widgets.NewQLabel2(" Dataset Path: ", nil, 0) 159 | lblDatasetPath.SetSizePolicy2(widgets.QSizePolicy__Fixed, widgets.QSizePolicy__Fixed) 160 | 161 | gp.DatasetPath = Lineedit{widgets.NewQLineEdit(nil)} 162 | gp.DatasetPath.SetObjectName("DatasetPath") 163 | gp.DatasetPath.ConnectEditingFinished(gp.DatasetPath.EditingFinished) 164 | 165 | var vlayoutAlign = widgets.NewQVBoxLayout() 166 | var hlayoutAlign = widgets.NewQHBoxLayout() 167 | 168 | vlayoutAlign.AddWidget(lblGraphName, 0, 0) 169 | hlayoutLine1.AddWidget(gp.GraphName, 0, 0) 170 | hlayoutLine1.AddWidget(lblJobID, 0, 0) 171 | hlayoutLine1.AddWidget(gp.JobID, 0, 0) 172 | hlayoutLine1.AddWidget(btnNewGraph, 0, 0) 173 | 174 | vlayoutAlign.AddWidget(lblDatasetPath, 0, 0) 175 | hlayoutLine2.AddWidget(gp.DatasetPath, 0, 0) 176 | 177 | vlayout.AddLayout(hlayoutLine1, 0) 178 | vlayout.AddLayout(hlayoutLine2, 0) 179 | 180 | hlayoutAlign.AddLayout(vlayoutAlign, 0) 181 | hlayoutAlign.AddLayout(vlayout, 0) 182 | 183 | gbGraphProperties.SetLayout(hlayoutAlign) 184 | 185 | var hlayout = widgets.NewQHBoxLayout() 186 | hlayout.AddWidget(gbGraphProperties, 0, 0) 187 | 188 | return hlayout 189 | 190 | } 191 | 192 | func (gp *GraphPanel) line2() *widgets.QHBoxLayout { 193 | 194 | var hlayoutLine1 = widgets.NewQHBoxLayout() // nodeList 195 | var vlayoutLine2 = widgets.NewQVBoxLayout() // Node + Edges 196 | var hlayoutLine3 = widgets.NewQHBoxLayout() // List + Node/Edge 197 | 198 | var hlayoutLine21Node = widgets.NewQHBoxLayout() // Node 199 | var hlayoutLine22Edge = widgets.NewQHBoxLayout() // Edges 200 | 201 | // Node List 202 | gp.NodeList = Nodelist{widgets.NewQListWidget(nil)} 203 | gp.NodeList.ConnectCurrentItemChanged(gp.NodeList.CurrentItemChanged_) 204 | 205 | hlayoutLine1.AddWidget(gp.NodeList, 0, 0) 206 | 207 | //---------- 208 | var gbNodeProperties = widgets.NewQGroupBox2("Node Properties", nil) 209 | 210 | var vlayout = widgets.NewQVBoxLayout() 211 | 212 | var hlayoutNpLine1 = widgets.NewQHBoxLayout() // nodeID, language 213 | var hlayoutNpLine2 = widgets.NewQHBoxLayout() // scriptfile 214 | var hlayoutNpLine3 = widgets.NewQHBoxLayout() // classname 215 | 216 | var lblNodeID = widgets.NewQLabel2(" Node ID: ", nil, 0) 217 | lblNodeID.SetSizePolicy2(widgets.QSizePolicy__Fixed, widgets.QSizePolicy__Fixed) 218 | 219 | gp.NodeID = Lineedit{widgets.NewQLineEdit(nil)} 220 | gp.NodeID.SetObjectName("NodeID") 221 | gp.NodeID.ConnectEditingFinished(gp.NodeID.EditingFinished) 222 | 223 | var lblLanguage = widgets.NewQLabel2(" Language: ", nil, 0) 224 | lblLanguage.SetSizePolicy2(widgets.QSizePolicy__Fixed, widgets.QSizePolicy__Fixed) 225 | 226 | gp.Language = Lineedit{widgets.NewQLineEdit(nil)} 227 | gp.Language.SetObjectName("Language") 228 | gp.Language.ConnectEditingFinished(gp.Language.EditingFinished) 229 | 230 | var lblScriptFile = widgets.NewQLabel2(" Script File: ", nil, 0) 231 | lblScriptFile.SetSizePolicy2(widgets.QSizePolicy__Fixed, widgets.QSizePolicy__Fixed) 232 | 233 | gp.ScriptFile = Lineedit{widgets.NewQLineEdit(nil)} 234 | gp.ScriptFile.SetObjectName("ScriptFile") 235 | gp.ScriptFile.ConnectEditingFinished(gp.ScriptFile.EditingFinished) 236 | 237 | var lblClassName = widgets.NewQLabel2(" Class Name: ", nil, 0) 238 | lblClassName.SetSizePolicy2(widgets.QSizePolicy__Fixed, widgets.QSizePolicy__Fixed) 239 | 240 | gp.ClassName = Lineedit{widgets.NewQLineEdit(nil)} 241 | gp.ClassName.SetObjectName("ClassName") 242 | gp.ClassName.ConnectEditingFinished(gp.ClassName.EditingFinished) 243 | 244 | var btnScriptFile = widgets.NewQPushButton(nil) 245 | btnScriptFile.SetText("+") 246 | btnScriptFile.SetMaximumWidth(35) 247 | btnScriptFile.ConnectClicked(func(_ bool) { 248 | if btnScriptFile.Text() == "+" { 249 | gp.EdgeIncoming.SetVisible(true) 250 | gp.EdgeOutgoing.SetVisible(true) 251 | btnScriptFile.SetText("-") 252 | } else { 253 | gp.EdgeOutgoing.SetVisible(false) 254 | gp.EdgeIncoming.SetVisible(false) 255 | btnScriptFile.SetText("+") 256 | } 257 | 258 | }) 259 | 260 | var vlayoutAlign = widgets.NewQVBoxLayout() 261 | var hlayoutAlign = widgets.NewQHBoxLayout() 262 | 263 | vlayoutAlign.AddWidget(lblNodeID, 0, 0) 264 | hlayoutNpLine1.AddWidget(gp.NodeID, 0, 0) 265 | hlayoutNpLine1.AddWidget(lblLanguage, 0, 0) 266 | hlayoutNpLine1.AddWidget(gp.Language, 0, 0) 267 | 268 | vlayoutAlign.AddWidget(lblScriptFile, 0, 0) 269 | hlayoutNpLine2.AddWidget(gp.ScriptFile, 0, 0) 270 | hlayoutNpLine2.AddWidget(btnScriptFile, 0, 0) 271 | 272 | vlayoutAlign.AddWidget(lblClassName, 0, 0) 273 | hlayoutNpLine3.AddWidget(gp.ClassName, 0, 0) 274 | 275 | vlayout.AddLayout(hlayoutNpLine1, 0) 276 | vlayout.AddLayout(hlayoutNpLine2, 0) 277 | vlayout.AddLayout(hlayoutNpLine3, 0) 278 | 279 | hlayoutAlign.AddLayout(vlayoutAlign, 0) 280 | hlayoutAlign.AddLayout(vlayout, 0) 281 | 282 | gbNodeProperties.SetLayout(hlayoutAlign) 283 | 284 | hlayoutLine21Node.AddWidget(gbNodeProperties, 0, 0) 285 | 286 | // Incoming/Outgoing Edge Tables 287 | gp.EdgeIncoming = widgets.NewQTableWidget2(0, 1, nil) 288 | gp.EdgeOutgoing = widgets.NewQTableWidget2(0, 1, nil) 289 | 290 | gp.EdgeIncoming.SetVisible(false) 291 | gp.EdgeOutgoing.SetVisible(false) 292 | 293 | var strHeaders1 = []string{"Incoming Edge"} 294 | gp.EdgeIncoming.SetHorizontalHeaderLabels(strHeaders1) 295 | gp.EdgeIncoming.HorizontalHeader().SetStretchLastSection(true) 296 | 297 | var strHeaders2 = []string{"Outgoing Edge"} 298 | gp.EdgeOutgoing.SetHorizontalHeaderLabels(strHeaders2) 299 | gp.EdgeOutgoing.HorizontalHeader().SetStretchLastSection(true) 300 | 301 | hlayoutLine22Edge.AddWidget(gp.EdgeIncoming, 0, 0) 302 | hlayoutLine22Edge.AddWidget(gp.EdgeOutgoing, 0, 0) 303 | 304 | vlayoutLine2.AddLayout(hlayoutLine21Node, 0) 305 | vlayoutLine2.AddLayout(hlayoutLine22Edge, 0) 306 | 307 | var w1 = widgets.NewQWidget(nil, 0) 308 | var w2 = widgets.NewQWidget(nil, 0) 309 | var sp = widgets.NewQSplitter(nil) 310 | 311 | w1.SetLayout(hlayoutLine1) 312 | w2.SetLayout(vlayoutLine2) 313 | sp.AddWidget(w1) 314 | sp.AddWidget(w2) 315 | 316 | hlayoutLine3.AddWidget(sp, 0, 0) 317 | 318 | return hlayoutLine3 319 | 320 | } 321 | 322 | func (gp *GraphPanel) line3() *widgets.QVBoxLayout { 323 | 324 | var vlayout = widgets.NewQVBoxLayout() 325 | 326 | gp.TblArgs = NewArgsTable() // Args Table 327 | 328 | gp.ValueList = Valuelist{widgets.NewQListWidget(nil)} 329 | gp.ValueList.SetFont(gui.NewQFont2("verdana", 13, 1, false)) 330 | gp.ValueList.SetAcceptDrops(true) 331 | 332 | gp.ValueList.ConnectDragEnterEvent(gp.ValueList.DragEnterEvent_) 333 | gp.ValueList.ConnectDragMoveEvent(gp.ValueList.DragMoveEvent_) 334 | gp.ValueList.ConnectDropEvent(gp.ValueList.DropEvent_) 335 | 336 | var sp = widgets.NewQSplitter(nil) 337 | sp.SetOrientation(2) 338 | sp.AddWidget(gp.TblArgs) 339 | sp.AddWidget(gp.ValueList) 340 | 341 | vlayout.AddWidget(sp, 0, 0) 342 | 343 | return vlayout 344 | 345 | } 346 | -------------------------------------------------------------------------------- /graphpanel/lineedit.go: -------------------------------------------------------------------------------- 1 | package graphpanel 2 | 3 | import ( 4 | "github.com/5k3105/Pipeline-Editor/janus" 5 | 6 | "github.com/therecipe/qt/core" 7 | "github.com/therecipe/qt/widgets" 8 | ) 9 | 10 | type Lineedit struct{ *widgets.QLineEdit } 11 | 12 | func (l *Lineedit) EditingFinished() { 13 | 14 | var di = graphpanel.NodeList.CurrentItem().Data(int(core.Qt__UserRole)).ToInt(true) 15 | 16 | i, _ := janusgraph.Nodes.Get(di) 17 | jn := i.(*janus.Node) 18 | 19 | switch l.ObjectName() { 20 | 21 | case "GraphName": 22 | janusgraph.GraphName = l.Text() 23 | 24 | case "JobID": 25 | janusgraph.JobID = l.Text() 26 | 27 | case "DatasetPath": 28 | janusgraph.DatasetPath = l.Text() 29 | 30 | case "NodeID": 31 | jn.NodeID = l.Text() 32 | 33 | case "Language": 34 | jn.Language = l.Text() 35 | 36 | case "ScriptFile": 37 | jn.ScriptFile = l.Text() 38 | 39 | case "ClassName": 40 | jn.ClassName = l.Text() 41 | // update canvas and list names 42 | graphpanel.NodeList.CurrentItem().SetText(l.Text()) 43 | // f, _ := canvas.Figures.Get(di) 44 | // r := f.(*rectangle.Rectangle) 45 | // r.Name = l.Text() 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /graphpanel/nodelist.go: -------------------------------------------------------------------------------- 1 | package graphpanel 2 | 3 | import ( 4 | "github.com/5k3105/Pipeline-Editor/janus" 5 | 6 | "github.com/therecipe/qt/core" 7 | "github.com/therecipe/qt/gui" 8 | "github.com/therecipe/qt/widgets" 9 | ) 10 | 11 | type Nodelist struct{ *widgets.QListWidget } 12 | 13 | func (n *Nodelist) CurrentItemChanged_(current *widgets.QListWidgetItem, previous *widgets.QListWidgetItem) { 14 | 15 | var di = current.Data(int(core.Qt__UserRole)).ToInt(true) 16 | jn, _ := janusgraph.Nodes.Get(di) 17 | i := jn.(*janus.Node) 18 | 19 | graphpanel.NodeID.SetText(i.NodeID) 20 | graphpanel.Language.SetText(i.Language) 21 | graphpanel.ScriptFile.SetText(i.ScriptFile) 22 | graphpanel.ClassName.SetText(i.ClassName) 23 | 24 | graphpanel.EdgeIncoming.ClearContents() 25 | graphpanel.EdgeIncoming.SetRowCount(i.AntiEdges.Size()) 26 | graphpanel.EdgeOutgoing.ClearContents() 27 | graphpanel.EdgeOutgoing.SetRowCount(i.Edges.Size()) 28 | 29 | font := gui.NewQFont2("verdana", 13, 1, false) 30 | 31 | for indx, x := range i.Edges.Values() { 32 | xi := x.(*janus.Edge) 33 | var wi = widgets.NewQTableWidgetItem2(xi.String, 0) 34 | wi.SetFont(font) 35 | graphpanel.EdgeOutgoing.SetItem(indx, 0, wi) 36 | } 37 | 38 | for indx, x := range i.AntiEdges.Values() { 39 | xi := x.(*janus.Edge) 40 | var wi = widgets.NewQTableWidgetItem2(xi.String, 0) 41 | wi.SetFont(font) 42 | graphpanel.EdgeIncoming.SetItem(indx, 0, wi) 43 | } 44 | 45 | // ARGS Table 46 | ClearAndSetModel(i) // .(*janus.Node) current 47 | 48 | } 49 | -------------------------------------------------------------------------------- /graphpanel/tblargs.go: -------------------------------------------------------------------------------- 1 | package graphpanel 2 | 3 | import ( 4 | "github.com/5k3105/Pipeline-Editor/janus" 5 | 6 | "strconv" 7 | 8 | "github.com/emirpasic/gods/maps/treemap" 9 | "github.com/therecipe/qt/core" 10 | "github.com/therecipe/qt/gui" 11 | "github.com/therecipe/qt/widgets" 12 | ) 13 | 14 | var ( 15 | model *core.QAbstractTableModel // QAbstractItemModel 16 | view *widgets.QTableView 17 | 18 | textIndex *core.QModelIndex 19 | currentRow int 20 | currentNode *janus.Node 21 | currentArg *janus.Arg 22 | previousRow int //? 23 | ) 24 | 25 | type Delegate struct { 26 | widgets.QStyledItemDelegate //don't use *pointers or it won't work 27 | } 28 | 29 | type Tblargs struct{ *widgets.QTableView } 30 | 31 | func NewArgsTable() *widgets.QTableView { 32 | view = widgets.NewQTableView(nil) // setObjectName 33 | model = core.NewQAbstractTableModel(nil) // NewQAbstractItemModel(nil) 34 | 35 | delegate := InitDelegate() 36 | view.SetItemDelegate(delegate) 37 | //view.SetItemDelegateForColumn(0, delegate) 38 | view.SetFont(gui.NewQFont2("verdana", 13, 1, false)) 39 | 40 | view.SetColumnWidth(1, 250) 41 | view.HorizontalHeader().SetStretchLastSection(true) 42 | 43 | view.SetSelectionBehavior(0) // SelectItems 44 | view.SetSelectionMode(1) // SingleSelection 45 | 46 | view.ConnectKeyPressEvent(view_keypressevent) 47 | //view.ConnectCurrentChanged(view_currentchanged) 48 | view.ConnectSelectionChanged(view_selectionchanged) 49 | 50 | model.ConnectRowCount(model_rowcount) 51 | model.ConnectColumnCount(model_columncount) 52 | model.ConnectData(model_data) 53 | model.ConnectSetData(model_setdata) 54 | model.ConnectInsertRows(model_insertrows) 55 | model.ConnectFlags(model_flags) 56 | model.ConnectRemoveRows(model_removerows) 57 | model.ConnectHeaderData(model_headerdata) 58 | 59 | view.SetModel(model) 60 | 61 | return view 62 | } 63 | 64 | func (gp *GraphPanel) Tblargs_Clear() { 65 | model.BeginResetModel() 66 | //gp.TblArgs = NewArgsTable() //Reset() 67 | model.EndResetModel() 68 | //SetModel() 69 | 70 | graphpanel.ValueList.Clear() 71 | } 72 | 73 | func ClearAndSetModel(jn *janus.Node) { // current Node treemap - called when node in nodelist selected 74 | //model.Clear() 75 | model.BeginResetModel() 76 | model.EndResetModel() 77 | 78 | currentNode = jn 79 | graphpanel.ValueList.Clear() 80 | 81 | currentRow = 0 82 | a, _ := currentNode.Args.Get(currentRow) 83 | currentArg = a.(*janus.Arg) 84 | 85 | // valuelist 86 | font := gui.NewQFont2("verdana", 13, 1, false) 87 | for _, x := range currentArg.Values.Values() { 88 | 89 | xj := x.(string) 90 | n := widgets.NewQListWidgetItem2(xj, graphpanel.ValueList, 0) 91 | n.SetFont(font) 92 | } 93 | 94 | graphpanel.TblArgs.SelectRow(0) 95 | 96 | } 97 | 98 | func view_keypressevent(e *gui.QKeyEvent) { 99 | if e.Key() == int(core.Qt__Key_Delete) { 100 | if view.CurrentIndex().Row() < currentNode.Args.Size()-1 { 101 | // statusbar.ShowMessage("row: "+strconv.Itoa(currentRow)+" list size: "+strconv.Itoa(listv.Size()), 0) 102 | model.RemoveRows(view.CurrentIndex().Row(), 1, core.NewQModelIndex()) 103 | updateValuelist() 104 | } 105 | } else { 106 | view.KeyPressEventDefault(e) 107 | } 108 | } 109 | 110 | //func view_currentchanged(current *core.QModelIndex, previous *core.QModelIndex) { 111 | // previousRow = previous.Row() 112 | // currentRow = current.Row() 113 | //} 114 | 115 | func view_selectionchanged(selected *core.QItemSelection, deselected *core.QItemSelection) { 116 | updateValuelist() 117 | } 118 | 119 | func updateValuelist() { 120 | graphpanel.ValueList.Clear() 121 | // clear and update valuelist w/ jgraph 122 | // current args list row 123 | var r = view.CurrentIndex().Row() 124 | a, _ := currentNode.Args.Get(r) 125 | currentArg := a.(*janus.Arg) 126 | 127 | for _, x := range currentArg.Values.Values() { 128 | xj := x.(string) 129 | widgets.NewQListWidgetItem2(xj, graphpanel.ValueList, 0) 130 | } 131 | } 132 | 133 | func InitDelegate() *Delegate { 134 | item := NewDelegate(nil) //will be generated in moc.go 135 | item.ConnectCreateEditor(delegate_createEditor) 136 | item.ConnectSetEditorData(delegate_setEditorData) 137 | item.ConnectSetModelData(delegate_setModelData) 138 | item.ConnectUpdateEditorGeometry(delegate_updateEditorGeometry) 139 | return item 140 | } 141 | 142 | func delegate_createEditor(parent *widgets.QWidget, option *widgets.QStyleOptionViewItem, index *core.QModelIndex) *widgets.QWidget { 143 | editor := widgets.NewQLineEdit(parent) 144 | textIndex = index //? 145 | 146 | if index.Row() == currentNode.Args.Size()-1 { 147 | model.InsertRow(index.Row(), core.NewQModelIndex()) 148 | } 149 | 150 | //editor.ConnectTextChanged(delegate_textchanged) 151 | 152 | return editor.QWidget_PTR() 153 | } 154 | 155 | // not needed?? 156 | func delegate_textchanged(text string) { 157 | model.SetData(textIndex, core.NewQVariant14(text), 2) // edit role = 2 158 | } 159 | 160 | func delegate_setEditorData(editor *widgets.QWidget, index *core.QModelIndex) { 161 | var value string 162 | 163 | //currentRow = index.Row() // needed? 164 | var argi, exists = currentNode.Args.Get(index.Row()) 165 | 166 | currentArg = argi.(*janus.Arg) // needed?? 167 | 168 | if exists { 169 | //var arg = argi.(*janus.Arg) 170 | switch index.Column() { 171 | case 0: 172 | value = currentArg.Source 173 | case 1: 174 | value = currentArg.Value 175 | } 176 | } 177 | 178 | lineedit := widgets.NewQLineEditFromPointer(editor.Pointer()) 179 | lineedit.SetText(value) //.(string) 180 | } 181 | 182 | func delegate_setModelData(editor *widgets.QWidget, model *core.QAbstractItemModel, index *core.QModelIndex) { 183 | lineedit := widgets.NewQLineEditFromPointer(editor.Pointer()) 184 | text := lineedit.Text() 185 | model.SetData(index, core.NewQVariant14(text), int(core.Qt__EditRole)) 186 | } 187 | 188 | func delegate_updateEditorGeometry(editor *widgets.QWidget, option *widgets.QStyleOptionViewItem, index *core.QModelIndex) { 189 | editor.SetGeometry(option.Rect()) 190 | } 191 | 192 | func model_headerdata(section int, orientation core.Qt__Orientation, role int) *core.QVariant { 193 | if orientation == 1 && role == 0 { // Qt__Horizontal, Qt__DisplayRole 194 | switch section { 195 | case 0: 196 | return core.NewQVariant14("Source") 197 | case 1: 198 | return core.NewQVariant14("Value") 199 | } 200 | 201 | return core.NewQVariant14("column" + strconv.Itoa(section+1)) 202 | } 203 | 204 | if orientation == 2 && role == 0 { 205 | if section < currentNode.Args.Size()-1 { 206 | return core.NewQVariant14(strconv.Itoa(section + 1)) 207 | } else { 208 | return core.NewQVariant14("*") 209 | } 210 | } 211 | return core.NewQVariant() 212 | } 213 | 214 | func model_rowcount(parent *core.QModelIndex) int { 215 | return currentNode.Args.Size() //+ 1 216 | } 217 | 218 | func model_columncount(parent *core.QModelIndex) int { 219 | return 2 220 | } 221 | 222 | func model_data(index *core.QModelIndex, role int) *core.QVariant { // dataset to model/view 223 | 224 | if role == 0 && index.IsValid() { // display role = 0 225 | 226 | var argi, exists = currentNode.Args.Get(index.Row()) 227 | 228 | if exists { 229 | var arg = argi.(*janus.Arg) 230 | switch index.Column() { 231 | case 0: 232 | return core.NewQVariant14(arg.Source) 233 | case 1: 234 | return core.NewQVariant14(arg.Value) 235 | } 236 | } 237 | } 238 | return core.NewQVariant() 239 | 240 | } 241 | 242 | func model_setdata(index *core.QModelIndex, value *core.QVariant, role int) bool { // model/view to dataset 243 | if (role == 2 || role == 0) && index.IsValid() { // edit role = 2 244 | 245 | var argi, exists = currentNode.Args.Get(index.Row()) 246 | 247 | if exists { 248 | var arg = argi.(*janus.Arg) 249 | //if !(arg.Source == "" && arg.Value == "") { 250 | switch index.Column() { 251 | case 0: 252 | currentNode.Args.Put(index.Row(), &janus.Arg{Source: value.ToString(), Value: arg.Value, Values: arg.Values}) 253 | case 1: 254 | currentNode.Args.Put(index.Row(), &janus.Arg{Source: arg.Source, Value: value.ToString(), Values: arg.Values}) 255 | } 256 | return true 257 | } 258 | } 259 | return true 260 | } 261 | 262 | func model_insertrows(row int, count int, parent *core.QModelIndex) bool { 263 | model.BeginInsertRows(core.NewQModelIndex(), row, row) 264 | 265 | currentNode.Args.Put(row+1, &janus.Arg{Source: "", Values: treemap.NewWithIntComparator()}) 266 | 267 | model.EndInsertRows() 268 | view.SelectRow(row) 269 | return true 270 | } 271 | 272 | func model_removerows(row int, count int, parent *core.QModelIndex) bool { 273 | model.BeginRemoveRows(core.NewQModelIndex(), row, row) 274 | 275 | currentNode.Args.Remove(row) 276 | 277 | // reset indexes 278 | for i, x := range currentNode.Args.Keys() { // i always starts from zero 279 | indx := x.(int) // indx does not 280 | 281 | if indx != i { 282 | var ar, _ = currentNode.Args.Get(indx) 283 | var arg = ar.(*janus.Arg) 284 | currentNode.Args.Put(i, &janus.Arg{Source: arg.Source, Value: arg.Value, Values: arg.Values}) 285 | currentNode.Args.Remove(indx) 286 | } 287 | 288 | } 289 | 290 | model.EndRemoveRows() 291 | return true 292 | 293 | } 294 | 295 | func model_flags(index *core.QModelIndex) core.Qt__ItemFlag { 296 | return 35 // 1 || 2 || 32 // ItemIsSelectable || ItemIsEditable || ItemIsEnabled 297 | } 298 | 299 | //func (ta *Tblargs) ItemChanged_(current *widgets.QTableWidgetItem) { 300 | // var di = graphpanel.NodeList.CurrentItem().Data(int(core.Qt__UserRole)).ToInt(true) 301 | // i, _ := janusgraph.Nodes.Get(di) 302 | // jn := i.(*janus.Node) 303 | 304 | // wit := current.Text() 305 | // currentRow := current.Row() 306 | // currentColumn := current.Column() 307 | 308 | // for indx, x := range jn.Args.Values() { 309 | // xi := x.(*janus.Arg) 310 | 311 | // if currentRow == indx { 312 | // switch currentColumn { 313 | // case 1: // Source 314 | // xi.Source = wit 315 | 316 | // case 2: // Value 317 | // xi.Value = wit 318 | 319 | // } 320 | // } 321 | 322 | // } 323 | 324 | //} 325 | 326 | //func (ta *Tblargs) CurrentCellChanged(currentRow int, currentColumn int, previousRow int, previousColumn int) { 327 | // var di = graphpanel.NodeList.CurrentItem().Data(int(core.Qt__UserRole)).ToInt(true) 328 | // i, _ := janusgraph.Nodes.Get(di) 329 | // jn := i.(*janus.Node) 330 | 331 | // wit := ta.Item(currentRow, currentColumn).Text() 332 | 333 | // for indx, x := range jn.Args.Values() { 334 | // xi := x.(*janus.Arg) 335 | 336 | // if currentRow == indx { 337 | // switch currentColumn { 338 | // case 1: // Source 339 | // xi.Source = wit 340 | 341 | // case 2: // Value 342 | // xi.Value = wit 343 | 344 | // } 345 | // } 346 | 347 | // } 348 | 349 | //} 350 | 351 | // var wi = widgets.NewQTableWidgetItem2(xi.Source, 0) 352 | // wi.SetFont(font) 353 | // graphpanel.TblArgs.SetItem(indx, 1, wi) 354 | 355 | // for _, x := range xi.Value.Values() { 356 | // xi := x.(string) 357 | 358 | // if xi != "" { 359 | // n := widgets.NewQListWidgetItem2(xi, graphpanel.ValueList, 0) 360 | // n.SetFont(font) 361 | // } 362 | 363 | // } 364 | 365 | //https://github.com/RustamSafiulin/mnemo_designer/blob/478e34be3564d3c51d8fae7aac9b3c820c6bc12c/propertyeditor/propertytableview.cpp 366 | //void PropertyTableView::init() { 367 | 368 | // resizeColumnsToContents(); 369 | // setColumnWidth(0,150); 370 | // setAlternatingRowColors(true); 371 | // setSelectionMode(QTableView::SingleSelection); 372 | // setSelectionBehavior(QTableView::SelectRows); 373 | // setEditTriggers(QAbstractItemView::CurrentChanged | QAbstractItemView::SelectedClicked); 374 | // verticalHeader()->hide(); 375 | // verticalHeader()->setDefaultSectionSize(25); 376 | // horizontalHeader()->setStretchLastSection(true); 377 | 378 | // delegate = new PropertyDelegate(this); 379 | // setItemDelegate(delegate); 380 | //} 381 | -------------------------------------------------------------------------------- /graphpanel/valuelist.go: -------------------------------------------------------------------------------- 1 | package graphpanel 2 | 3 | import ( 4 | "github.com/5k3105/Pipeline-Editor/janus" 5 | "strings" 6 | 7 | "github.com/therecipe/qt/core" 8 | "github.com/therecipe/qt/gui" 9 | "github.com/therecipe/qt/widgets" 10 | ) 11 | 12 | type Valuelist struct{ *widgets.QListWidget } 13 | 14 | func (v *Valuelist) DragEnterEvent_(e *gui.QDragEnterEvent) { 15 | e.AcceptProposedAction() 16 | } 17 | 18 | func (v *Valuelist) DragMoveEvent_(e *gui.QDragMoveEvent) { 19 | e.AcceptProposedAction() 20 | } 21 | 22 | func (v *Valuelist) DropEvent_(e *gui.QDropEvent) { 23 | e.SetDropAction(core.Qt__CopyAction) 24 | e.AcceptProposedAction() 25 | e.SetAccepted(true) 26 | 27 | font := gui.NewQFont2("verdana", 13, 1, false) 28 | 29 | // current node 30 | var di = graphpanel.NodeList.CurrentItem().Data(int(core.Qt__UserRole)).ToInt(true) 31 | ji, _ := janusgraph.Nodes.Get(di) 32 | jn := ji.(*janus.Node) 33 | 34 | // current args list row 35 | var r = view.CurrentIndex().Row() 36 | a, _ := jn.Args.Get(r) 37 | 38 | ja := a.(*janus.Arg) 39 | ja.Values.Clear() 40 | 41 | // write list items and j.Arg.Values 42 | for indx, j := range strings.Split(e.MimeData().Text(), "\n") { // Urls() 43 | if j != "" { 44 | n := widgets.NewQListWidgetItem2(j[8:], v, 0) 45 | n.SetFont(font) 46 | 47 | ja.Values.Put(indx, j[8:]) 48 | 49 | } 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /images/New folder/eraser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/5k3105/Pipeline-Editor/3b9fe75d83b6d0df95a70ccc337f105b2f98c8cc/images/New folder/eraser.png -------------------------------------------------------------------------------- /images/circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/5k3105/Pipeline-Editor/3b9fe75d83b6d0df95a70ccc337f105b2f98c8cc/images/circle.png -------------------------------------------------------------------------------- /images/cursor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/5k3105/Pipeline-Editor/3b9fe75d83b6d0df95a70ccc337f105b2f98c8cc/images/cursor.png -------------------------------------------------------------------------------- /images/eraser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/5k3105/Pipeline-Editor/3b9fe75d83b6d0df95a70ccc337f105b2f98c8cc/images/eraser.png -------------------------------------------------------------------------------- /images/grid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/5k3105/Pipeline-Editor/3b9fe75d83b6d0df95a70ccc337f105b2f98c8cc/images/grid.png -------------------------------------------------------------------------------- /images/hand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/5k3105/Pipeline-Editor/3b9fe75d83b6d0df95a70ccc337f105b2f98c8cc/images/hand.png -------------------------------------------------------------------------------- /images/line.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/5k3105/Pipeline-Editor/3b9fe75d83b6d0df95a70ccc337f105b2f98c8cc/images/line.png -------------------------------------------------------------------------------- /images/pen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/5k3105/Pipeline-Editor/3b9fe75d83b6d0df95a70ccc337f105b2f98c8cc/images/pen.png -------------------------------------------------------------------------------- /images/sizeall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/5k3105/Pipeline-Editor/3b9fe75d83b6d0df95a70ccc337f105b2f98c8cc/images/sizeall.png -------------------------------------------------------------------------------- /images/square.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/5k3105/Pipeline-Editor/3b9fe75d83b6d0df95a70ccc337f105b2f98c8cc/images/square.png -------------------------------------------------------------------------------- /images/square.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | 24 | 44 | 49 | 50 | 52 | 53 | 55 | image/svg+xml 56 | 58 | 59 | 60 | 61 | 62 | 66 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /images/type.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/5k3105/Pipeline-Editor/3b9fe75d83b6d0df95a70ccc337f105b2f98c8cc/images/type.png -------------------------------------------------------------------------------- /janus/janus.go: -------------------------------------------------------------------------------- 1 | package janus 2 | 3 | import ( 4 | "strconv" 5 | 6 | "github.com/emirpasic/gods/maps/treemap" 7 | ) 8 | 9 | var graph *Graph 10 | 11 | type Graph struct { 12 | GraphName string 13 | DatasetPath string 14 | JobID string 15 | Nodes *treemap.Map 16 | } 17 | 18 | type Node struct { 19 | NodeID string 20 | Language string 21 | ScriptFile string 22 | ClassName string 23 | Args *treemap.Map 24 | Edges *treemap.Map 25 | AntiEdges *treemap.Map 26 | X, Y float64 27 | } 28 | 29 | type Arg struct { 30 | Source string 31 | Value string 32 | Values *treemap.Map 33 | } 34 | 35 | type Edge struct { 36 | String string 37 | } 38 | 39 | func NewJanusGraph() *Graph { 40 | graph = &Graph{Nodes: treemap.NewWithIntComparator()} 41 | return graph 42 | } 43 | 44 | func (jg *Graph) AddNode(i int, x, y float64) { 45 | jg.Nodes.Put(i, &Node{NodeID: strconv.Itoa(i), 46 | Language: "python", 47 | ClassName: "node " + strconv.Itoa(i), 48 | Args: treemap.NewWithIntComparator(), 49 | Edges: treemap.NewWithIntComparator(), 50 | AntiEdges: treemap.NewWithIntComparator(), 51 | X: x, 52 | Y: y}) 53 | 54 | in, _ := jg.Nodes.Get(i) 55 | n := in.(*Node) 56 | n.AddArg(0) 57 | } 58 | 59 | func (jg *Graph) AddNodeFromFile(i int, x, y float64, language, classname, scriptfile string) { 60 | jg.Nodes.Put(i, &Node{ 61 | NodeID: strconv.Itoa(i), 62 | Language: language, 63 | ClassName: classname, 64 | ScriptFile: scriptfile, 65 | Args: treemap.NewWithIntComparator(), 66 | Edges: treemap.NewWithIntComparator(), 67 | AntiEdges: treemap.NewWithIntComparator(), 68 | X: x, 69 | Y: y}) 70 | 71 | in, _ := jg.Nodes.Get(i) 72 | n := in.(*Node) 73 | n.AddArg(0) 74 | } 75 | 76 | func (jg *Graph) RemoveNode(i int) { 77 | jg.Nodes.Remove(i) 78 | 79 | } 80 | 81 | func (n *Node) AddEdge(i int, t string) { 82 | switch t { 83 | case "Incoming Edge": 84 | n.Edges.Put(i, &Edge{String: strconv.Itoa(i)}) // edge is using i as key and value 85 | case "Outgoing Edge": 86 | n.AntiEdges.Put(i, &Edge{String: strconv.Itoa(i)}) 87 | } 88 | 89 | } 90 | 91 | func (n *Node) RemoveEdge(i int, t string) { 92 | switch t { 93 | case "Incoming Edge": 94 | n.Edges.Remove(i) 95 | case "Outgoing Edge": 96 | n.AntiEdges.Remove(i) 97 | } 98 | 99 | } 100 | 101 | func (n *Node) RemoveEdges() { 102 | 103 | // n.Edges.Remove(i) 104 | 105 | // n.AntiEdges.Remove(i) 106 | 107 | } 108 | 109 | func (n *Node) AddArg(i int) { 110 | n.Args.Put(i, &Arg{Source: "", Values: treemap.NewWithIntComparator()}) 111 | } 112 | 113 | func (n *Node) RemoveArg(i int) { 114 | n.Args.Remove(i) 115 | } 116 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/5k3105/Pipeline-Editor/genxml" 5 | "github.com/5k3105/Pipeline-Editor/gfxcanvas" 6 | "github.com/5k3105/Pipeline-Editor/gfxobjects/rectangle" 7 | "github.com/5k3105/Pipeline-Editor/graphpanel" 8 | "github.com/5k3105/Pipeline-Editor/janus" 9 | "os" 10 | 11 | "github.com/therecipe/qt/core" 12 | "github.com/therecipe/qt/gui" 13 | "github.com/therecipe/qt/widgets" 14 | ) 15 | 16 | type Application struct { 17 | *widgets.QApplication 18 | Window *widgets.QMainWindow 19 | Canvas *gfxcanvas.Canvas 20 | GraphPanel *graphpanel.GraphPanel 21 | Statusbar *widgets.QStatusBar 22 | } 23 | 24 | func main() { 25 | var ap = &Application{} 26 | ap.QApplication = widgets.NewQApplication(len(os.Args), os.Args) 27 | 28 | ap.Window = widgets.NewQMainWindow(nil, 0) 29 | ap.Window.SetWindowTitle("Pipeline Editor") 30 | 31 | ap.Statusbar = widgets.NewQStatusBar(ap.Window) 32 | ap.Window.SetStatusBar(ap.Statusbar) 33 | 34 | ap.GraphPanel = graphpanel.NewGraphPanel(ap.Window, ap.CanvasReset, ap.LoadXML, ap.GenXML) 35 | ap.GraphPanel.SetMinimumWidth(320) 36 | 37 | ap.Canvas = gfxcanvas.NewCanvas(ap.Window, ap.ListNodes) 38 | ap.Canvas.Statusbar = ap.Statusbar 39 | 40 | ap.GraphPanel.SetJanusGraph(ap.Canvas.JanusGraph) 41 | 42 | ap.Window.AddDockWidget(core.Qt__LeftDockWidgetArea, ap.GraphPanel) 43 | ap.Window.SetCentralWidget(ap.Canvas.View) 44 | 45 | ap.Statusbar.ShowMessage(core.QCoreApplication_ApplicationDirPath(), 0) 46 | 47 | widgets.QApplication_SetStyle2("fusion") 48 | ap.Window.ShowMaximized() 49 | widgets.QApplication_Exec() 50 | } 51 | 52 | func (ap *Application) CanvasReset() { 53 | ap.Canvas = gfxcanvas.NewCanvas(ap.Window, ap.ListNodes) 54 | ap.Canvas.Statusbar = ap.Statusbar 55 | ap.Window.SetCentralWidget(ap.Canvas.View) 56 | ap.GraphPanel.SetJanusGraph(ap.Canvas.JanusGraph) 57 | 58 | // point := core.NewQPointF3(300, 300) 59 | // ap.Canvas.View.CenterOn(point) 60 | 61 | ap.GraphPanel.Clear() 62 | } 63 | 64 | func (ap *Application) GenXML(filename string) { 65 | genxml.GenXML(ap.GraphPanel, ap.Canvas.JanusGraph, filename) 66 | } 67 | 68 | func (ap *Application) LoadXML(filename string) { 69 | //ap.Canvas.Reset() 70 | ap.CanvasReset() 71 | genxml.LoadXML(filename, ap.Canvas, ap.GraphPanel) 72 | ap.ListNodes() 73 | 74 | // hack 75 | var strHeaders1 = []string{"Incoming Edge"} 76 | ap.GraphPanel.EdgeIncoming.SetHorizontalHeaderLabels(strHeaders1) 77 | ap.GraphPanel.EdgeIncoming.HorizontalHeader().SetStretchLastSection(true) 78 | 79 | var strHeaders2 = []string{"Outgoing Edge"} 80 | ap.GraphPanel.EdgeOutgoing.SetHorizontalHeaderLabels(strHeaders2) 81 | ap.GraphPanel.EdgeOutgoing.HorizontalHeader().SetStretchLastSection(true) 82 | 83 | ap.GraphPanel.NodeList.SetCurrentRow(0) 84 | 85 | // point := core.NewQPointF3(300, 300) 86 | // ap.Canvas.View.CenterOn(point) 87 | } 88 | 89 | func (ap *Application) TextUpdate() { // update text from tblargs to rect font 90 | 91 | } 92 | 93 | func (ap *Application) ListNodes() { 94 | ap.GraphPanel.NodeList.Clear() 95 | 96 | font := gui.NewQFont2("verdana", 13, 1, false) 97 | 98 | for _, f := range ap.Canvas.Figures.Values() { 99 | r := f.(*rectangle.Rectangle) 100 | 101 | ij, _ := ap.Canvas.JanusGraph.Nodes.Get(r.Node.Id) 102 | n := ij.(*janus.Node) 103 | 104 | var txt = n.ClassName 105 | r.Name = n.ClassName 106 | 107 | var li = widgets.NewQListWidgetItem2(txt, ap.GraphPanel.NodeList, 0) 108 | li.SetFont(font) 109 | li.SetData(int(core.Qt__UserRole), core.NewQVariant7(r.Node.Id)) 110 | } 111 | 112 | } 113 | --------------------------------------------------------------------------------