From a1cf888b2620e22e46e47769e14bf1b0ead7c6c7 Mon Sep 17 00:00:00 2001 From: Lesterpig Date: Wed, 6 Apr 2016 15:49:21 +0200 Subject: [PATCH 1/6] [d] Add basic draw features - Draw and place clients - Draw arrows - Draw servers - Add icon --- dfssd/gui/application.qrc | 3 + dfssd/gui/clients.go | 90 ++++++++++++++++++++++++++++ dfssd/gui/colors.go | 16 +++++ dfssd/gui/images/node_magnifier.png | Bin 0 -> 2651 bytes dfssd/gui/images/server_connect.png | Bin 0 -> 1684 bytes dfssd/gui/images/server_key.png | Bin 0 -> 1519 bytes dfssd/gui/structures.go | 36 +++++++++++ dfssd/gui/widget.ui | 9 +++ dfssd/gui/window.go | 62 ++++++++++++++++++- dfssd/main.go | 6 +- 10 files changed, 218 insertions(+), 4 deletions(-) create mode 100644 dfssd/gui/clients.go create mode 100644 dfssd/gui/colors.go create mode 100644 dfssd/gui/images/node_magnifier.png create mode 100644 dfssd/gui/images/server_connect.png create mode 100644 dfssd/gui/images/server_key.png create mode 100644 dfssd/gui/structures.go diff --git a/dfssd/gui/application.qrc b/dfssd/gui/application.qrc index 65c5cfc..6fc0032 100644 --- a/dfssd/gui/application.qrc +++ b/dfssd/gui/application.qrc @@ -1,5 +1,8 @@ widget.ui + images/server_key.png + images/server_connect.png + images/node_magnifier.png diff --git a/dfssd/gui/clients.go b/dfssd/gui/clients.go new file mode 100644 index 0000000..bb0ea57 --- /dev/null +++ b/dfssd/gui/clients.go @@ -0,0 +1,90 @@ +package gui + +import ( + "math" + + "github.com/visualfc/goqt/ui" +) + +const ARROW_T = math.Pi / 6 +const ARROW_L = 15 + +func (w *Window) DrawClients() { + scene := w.graphics.Scene() + for i, c := range w.scene.Clients { + x, y := w.GetClientPosition(i) + + // Add ellipse + scene.AddEllipseFWithXYWidthHeightPenBrush(x-10, y-10, 20, 20, pen_black, brush_black) + + // Add text + t := scene.AddSimpleText(c.Name) + r := t.BoundingRect() + t.SetX(x - r.Width()/2) + t.SetY(y + 10) + } +} + +func (w *Window) GetClientPosition(i int) (x, y float64) { + nbClients := float64(len(w.scene.Clients)) + angle := 2 * math.Pi * float64(i) / nbClients + return math.Cos(angle) * (w.circleSize / 2), math.Sin(angle) * (w.circleSize / 2) +} + +func (w *Window) GetServerPosition(platform bool) (x, y float64) { + x = w.circleSize/2 + 150 + y = -16 + if !platform { + x *= -1 + } + return +} + +func (w *Window) DrawServers() { + scene := w.graphics.Scene() + + ttp := scene.AddPixmap(w.pixmaps["ttp"]) + x, y := w.GetServerPosition(false) + ttp.SetPosFWithXY(x, y) + ttp.SetToolTip("TTP") + + platform := scene.AddPixmap(w.pixmaps["platform"]) + platform.SetX(w.circleSize/2 + 150) + platform.SetY(-16) + platform.SetToolTip("Platform") +} + +func (w *Window) DrawArrow(xa, ya, xb, yb float64, rgb uint32) { + scene := w.graphics.Scene() + + path := ui.NewPainterPath() + path.MoveToFWithXY(xa, ya) + path.LineToFWithXY(xb, yb) + + v := ui.NewVector2DWithXposYpos(xa-xb, ya-yb) + l := v.Length() + + // from http://math.stackexchange.com/a/1314050 + xc := xb + ARROW_L/l*(v.X()*math.Cos(ARROW_T)+v.Y()*math.Sin(ARROW_T)) + yc := yb + ARROW_L/l*(v.Y()*math.Cos(ARROW_T)-v.X()*math.Sin(ARROW_T)) + xd := xb + ARROW_L/l*(v.X()*math.Cos(ARROW_T)-v.Y()*math.Sin(ARROW_T)) + yd := yb + ARROW_L/l*(v.Y()*math.Cos(ARROW_T)+v.X()*math.Sin(ARROW_T)) + + path.LineToFWithXY(xc, yc) + path.LineToFWithXY(xd, yd) + path.LineToFWithXY(xb, yb) + path.SetFillRule(ui.Qt_WindingFill) + + color := ui.NewColorWithRgb(rgb) + color.SetAlpha(200) + + pen := ui.NewPenWithColor(color) + pen.SetWidth(3) + pen.SetJoinStyle(ui.Qt_RoundJoin) + + brush := ui.NewBrush() + brush.SetColor(color) + brush.SetStyle(ui.Qt_SolidPattern) + + scene.AddPathWithPathPenBrush(path, pen, brush) +} diff --git a/dfssd/gui/colors.go b/dfssd/gui/colors.go new file mode 100644 index 0000000..4e43cf1 --- /dev/null +++ b/dfssd/gui/colors.go @@ -0,0 +1,16 @@ +package gui + +import "github.com/visualfc/goqt/ui" + +var colors = map[string]uint32{ + "red": 0x00ff0000, + "blue": 0x0000ff00, + "green": 0x000000ff, + "black": 0x00000000, +} + +var pen_black = ui.NewPenWithColor(ui.NewColorWithGlobalcolor(ui.Qt_black)) +var pen_gray = ui.NewPenWithColor(ui.NewColorWithGlobalcolor(ui.Qt_gray)) + +var brush_none = ui.NewBrushWithGlobalcolorBrushstyle(ui.Qt_transparent, ui.Qt_SolidPattern) +var brush_black = ui.NewBrushWithGlobalcolorBrushstyle(ui.Qt_black, ui.Qt_SolidPattern) diff --git a/dfssd/gui/images/node_magnifier.png b/dfssd/gui/images/node_magnifier.png new file mode 100644 index 0000000000000000000000000000000000000000..b19d01b580acfa7344e6e94c937f0c0b96f20186 GIT binary patch literal 2651 zcmaJ@dpwhUA6|}8GbK{7*61M*JIH8r3Y(}V%`l$C+HMRxwB6dsA%{dE6h)6nnN%c7 zl0(R$QWA<-6dkB2QaQvsJ=OF6@%G-I&wc+6pX<85r|XY9!P#jGRC%>B1OkCNIuI$+ z6|wLxR*-%Lp`o9o%PNpW16{bjppec7AT~_y9suFUruzXDfX)ordk3(9KxC0DDh;HO zw-Xp#Hj2K0L5bKrDH{T@uom&?j6eWH>;e2(982Wb%~~Xa#k54aA+F zVo6VyNPiII5zuI%P>2$4L~;3kXe=I&M`Mi9#>PfcgpnYG1JXrC9D&YH1tK6|@L4>N z#pNIt6zO}o!Js8ln(03!uz9~^If5T;k~R!2qVv#L6lS5MpFlGC|3lgAUuXeH0shVR ze+mnzAv^$00R-G&K0`VwhHeT-PR9X<{d+q8@JnO0D#qoe16i3#$H*)svCt-o z4%_%Al_#zbxQm>T_0S=ucztdhmCTHopD0sNg4CC_C$F9n9%TzL~peB z`k4IA6;Cwd=uR|44gaiiyq=z3PDDUObk4O)m)`AhbxmKEKuqjzo@;y6^7wXGF_m|v zqCyl1yu|8gE?uQ(SfAOaNLkhHS61GT zq9Q9oc)ZMA44Ce^ZX;4FwH;pD+?%)rlAQ*T3p;OqF{>8mb?9I(D9OEAvPSgG#EJCm+{7=FiZKs6 zKW|FY&D}vk<}Z2{GVw~X-NkRPFzPg%m=AfRckj6JyMyUt6>ZkMDflq_+Pef*88|3dV`Xn%x!bk4en+#@ zutwpe?j1vIvz$OL_ma7}n(%4rP*Kal&d5#hzP*~67q_O~C|#kJgKB*7#40AgA9HD) zd43U+%bxSP(jat?Ef+qMpx;v8zbj_AGe4+n$lRLF$le3@hdWu$ZSFQDC?dGo#`DB2eX%(Nr7_zUr(jU=Ib!Vi z#>X?ydAMd>tFmIB*OyjZ&nw3tuI>sxnTAt;z*Gz)x)Hv)fY2CNd!vit25>7_q(Wulg)BxDnsXcYBLuRn|@!91>>;@5#O!N(>E2uJ&qGfWdtm zS#K&OSt;>?2z8IanVsRZTng8ow1in{QTNU>V9zSeK6K_R*u5*k=k3V|2QQOI9d#P~ z+R~<@YnF`6_valhWwqy#OnYD%$? zQ(h*G2Fu%3#RCTUHo(d)#Si3GMs;W&_0~`oPo0|nvKHf0ADeiu?!Lylk^3zzkh0Xa zZ4y?EIDp@gud%DwS}E#4kocDGiS4Q~`DcYSlGjntJ#(Y6fup}#_Jg;H zcVJaFZH|5aOT`31aW!gnJQ3QmOnzr(=mDo2ztuxJaFnw-OVR28x}wbgWlDQ?8FJjXR%* z)KYK1pi7@t&CPilf0yAZnn=oCL&I*X?h1RLsGZqS4$Pq1#`V_Pc}yMZp4_Jd5Anw; zh@nj%Gnk$G^Y7_qj8L({6j-=UWZwC6OAB_)SEY$hq1AT!-8XZXNU9C2d05C`>s@y` z-fVP3``KnWrB1ge$yx~#QhrO8sr(mlfes#@x*fj4uj8P79kC~IJMqP&~-0fzJa$D3mOa*Qc@nT5J1!^}UK?)9{C)xyt=dZmfve)o|PjpO|YM zq=25k@Of`(SM!=G_qK7(mq#lq3qvC(aURhr0p;$W;|>p7hy+!2`)B@OdM{5hY1*I# zrd(HBf@(IH-YS!_32Odz^}zyz(PPauwQ`z}^eTVP9{Xtg!tb6V$%$BO>l6JSRhxi9 literal 0 HcmV?d00001 diff --git a/dfssd/gui/images/server_connect.png b/dfssd/gui/images/server_connect.png new file mode 100644 index 0000000000000000000000000000000000000000..faca1bc1c184be44a70bf00431066fb0400375f7 GIT binary patch literal 1684 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 VAwR8YRipp_002ovPDHLkV1kLj<1GLH literal 0 HcmV?d00001 diff --git a/dfssd/gui/structures.go b/dfssd/gui/structures.go new file mode 100644 index 0000000..5615616 --- /dev/null +++ b/dfssd/gui/structures.go @@ -0,0 +1,36 @@ +package gui + +import ( + "time" +) + +// Client represents a DFSSC instance +type Client struct { + Name string +} + +// EventType is used as an enum for event types, to differenciate promises, signatures... +type EventType int + +const ( + PROMISE EventType = iota + SIGNATURE + OTHER +) + +// Event represents a single signature event +type Event struct { + Type EventType + Sender int + Receiver int + Date *time.Time + Duration *time.Duration +} + +// Scene holds the global scene for registered clients and signature events +type Scene struct { + Clients []Client + Events []Event + + currentEvent int +} diff --git a/dfssd/gui/widget.ui b/dfssd/gui/widget.ui index 207beb5..c837232 100644 --- a/dfssd/gui/widget.ui +++ b/dfssd/gui/widget.ui @@ -39,6 +39,15 @@ 300 + + + + 255 + 255 + 255 + + + diff --git a/dfssd/gui/window.go b/dfssd/gui/window.go index a4aa9ae..4c688d5 100644 --- a/dfssd/gui/window.go +++ b/dfssd/gui/window.go @@ -1,6 +1,8 @@ package gui import ( + "math" + "dfss" "github.com/visualfc/goqt/ui" ) @@ -8,7 +10,11 @@ import ( type Window struct { *ui.QMainWindow - logField *ui.QTextEdit + logField *ui.QTextEdit + graphics *ui.QGraphicsView + scene *Scene + circleSize float64 + pixmaps map[string]*ui.QPixmap } func NewWindow() *Window { @@ -23,13 +29,33 @@ func NewWindow() *Window { w := &Window{ QMainWindow: window, + scene: &Scene{}, } + w.InstallEventFilter(w) // Load dynamic elements from driver w.logField = ui.NewTextEditFromDriver(widget.FindChild("logField")) + w.graphics = ui.NewGraphicsViewFromDriver(widget.FindChild("graphicsView")) + + // Load pixmaps + w.pixmaps = map[string]*ui.QPixmap{ + "ttp": ui.NewPixmapWithFilenameFormatFlags(":/images/server_key.png", "", ui.Qt_AutoColor), + "platform": ui.NewPixmapWithFilenameFormatFlags(":/images/server_connect.png", "", ui.Qt_AutoColor), + } + + // Load icon + w.SetWindowIcon(ui.NewIconWithFilename(":/images/node_magnifier.png")) // Add actions w.addActions() + w.initScene() + + // TEST ONLY + w.scene.Clients = []Client{ + Client{"signer1@lesterpig.com"}, + Client{"signer2@insa-rennes.fr"}, + Client{"signer3@dfss.com"}, + } w.StatusBar().ShowMessage("Ready") return w @@ -52,3 +78,37 @@ func (w *Window) addActions() { w.MenuBar().AddAction(openAct) w.MenuBar().AddAction(saveAct) } + +func (w *Window) OnResizeEvent(ev *ui.QResizeEvent) bool { + w.initScene() + return true +} + +func (w *Window) initScene() { + + // Save old scene + oldScene := w.graphics.Scene() + + scene := ui.NewGraphicsScene() + w.graphics.SetScene(scene) + + // Draw base circle + w.circleSize = math.Min(float64(w.graphics.Width()), float64(w.graphics.Height())) - 50 + r := w.circleSize / 2 + scene.AddEllipseFWithXYWidthHeightPenBrush(-r, -r, w.circleSize, w.circleSize, pen_gray, brush_none) + + // Draw clients + w.DrawClients() + w.DrawServers() + + // TEST + xa, ya := w.GetClientPosition(0) + xb, yb := w.GetClientPosition(1) + w.DrawArrow(xa, ya, xb, yb, colors["red"]) + w.DrawArrow(xb, yb, xa, ya, colors["red"]) + + // Purge + if oldScene != nil { + oldScene.Delete() + } +} diff --git a/dfssd/main.go b/dfssd/main.go index 6be4fd8..fa2ce27 100644 --- a/dfssd/main.go +++ b/dfssd/main.go @@ -8,8 +8,8 @@ import ( "strconv" "dfss" - "dfss/dfssd/server" "dfss/dfssd/gui" + "dfss/dfssd/server" "github.com/visualfc/goqt/ui" ) @@ -54,7 +54,7 @@ func main() { lfn := func(str string) { fmt.Println(str) } - err := server.Listen("0.0.0.0:" + strconv.Itoa(port), lfn) + err := server.Listen("0.0.0.0:"+strconv.Itoa(port), lfn) if err != nil { os.Exit(1) } @@ -62,7 +62,7 @@ func main() { ui.Run(func() { window := gui.NewWindow() go func() { - err := server.Listen("0.0.0.0:" + strconv.Itoa(port), window.Log) + err := server.Listen("0.0.0.0:"+strconv.Itoa(port), window.Log) if err != nil { window.Log("!! " + err.Error()) } -- GitLab From 00f0e26afb078130749b288bc67b975e94c9b7f9 Mon Sep 17 00:00:00 2001 From: Lesterpig Date: Wed, 6 Apr 2016 16:26:55 +0200 Subject: [PATCH 2/6] [d] Add import/export feature --- dfssd/gui/save.go | 41 +++++++++++++++++++++++++++++++++++++++++ dfssd/gui/window.go | 12 ++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 dfssd/gui/save.go diff --git a/dfssd/gui/save.go b/dfssd/gui/save.go new file mode 100644 index 0000000..85b0cf7 --- /dev/null +++ b/dfssd/gui/save.go @@ -0,0 +1,41 @@ +package gui + +import ( + "encoding/json" + "io/ioutil" + "strconv" +) + +func (w *Window) Save(filename string) { + data, err := json.Marshal(w.scene) + if err != nil { + w.StatusBar().ShowMessage(err.Error()) + return + } + + err = ioutil.WriteFile(filename, data, 0600) + if err != nil { + w.StatusBar().ShowMessage(err.Error()) + return + } + w.StatusBar().ShowMessage("Saved file as " + filename) +} + +func (w *Window) Open(filename string) { + data, err := ioutil.ReadFile(filename) + if err != nil { + w.StatusBar().ShowMessage(err.Error()) + return + } + + newScene := &Scene{} + err = json.Unmarshal(data, newScene) + if err != nil { + w.StatusBar().ShowMessage(err.Error()) + return + } + + w.scene = newScene + w.StatusBar().ShowMessage("Imported file from " + filename + " (" + strconv.Itoa(len(w.scene.Events)) + " events)") + w.initScene() +} diff --git a/dfssd/gui/window.go b/dfssd/gui/window.go index 4c688d5..b458f1d 100644 --- a/dfssd/gui/window.go +++ b/dfssd/gui/window.go @@ -70,10 +70,22 @@ func (w *Window) addActions() { openAct := ui.NewActionWithTextParent("&Open", w) openAct.SetShortcuts(ui.QKeySequence_Open) openAct.SetStatusTip("Open a demonstration file") + openAct.OnTriggered(func() { + filename := ui.QFileDialogGetOpenFileName() + if filename != "" { + w.Open(filename) + } + }) saveAct := ui.NewActionWithTextParent("&Save", w) saveAct.SetShortcuts(ui.QKeySequence_Save) saveAct.SetStatusTip("Save a demonstration file") + saveAct.OnTriggered(func() { + filename := ui.QFileDialogGetSaveFileName() + if filename != "" { + w.Save(filename) + } + }) w.MenuBar().AddAction(openAct) w.MenuBar().AddAction(saveAct) -- GitLab From 2812ea2de27199808c0016bff447b0c059589b77 Mon Sep 17 00:00:00 2001 From: Lesterpig Date: Fri, 8 Apr 2016 11:43:06 +0200 Subject: [PATCH 3/6] [d] Add basic dynamic view of events --- dfssd/gui/clients.go | 14 +++++++- dfssd/gui/events.go | 74 +++++++++++++++++++++++++++++++++++++++++ dfssd/gui/structures.go | 25 ++++++++++++-- dfssd/gui/widget.ui | 18 +++++++++- dfssd/gui/window.go | 29 ++++++---------- 5 files changed, 137 insertions(+), 23 deletions(-) create mode 100644 dfssd/gui/events.go diff --git a/dfssd/gui/clients.go b/dfssd/gui/clients.go index bb0ea57..da9f561 100644 --- a/dfssd/gui/clients.go +++ b/dfssd/gui/clients.go @@ -86,5 +86,17 @@ func (w *Window) DrawArrow(xa, ya, xb, yb float64, rgb uint32) { brush.SetColor(color) brush.SetStyle(ui.Qt_SolidPattern) - scene.AddPathWithPathPenBrush(path, pen, brush) + arrow := scene.AddPathWithPathPenBrush(path, pen, brush) + w.currentArrows = append(w.currentArrows, arrow) +} + +func (w *Window) RemoveArrows() { + scene := w.graphics.Scene() + + for _, arrow := range w.currentArrows { + scene.RemoveItem(&arrow.QGraphicsItem) + defer arrow.Delete() + } + + w.currentArrows = nil } diff --git a/dfssd/gui/events.go b/dfssd/gui/events.go new file mode 100644 index 0000000..24f55b6 --- /dev/null +++ b/dfssd/gui/events.go @@ -0,0 +1,74 @@ +package gui + +import ( + "fmt" + "time" + "math" +) + +// TEMPORARY +const quantum = 100 // discretization argument for events (ns) +const speed = 500 // duration of a quantum (ms) + +func (w *Window) StartSimulation() { + w.ticker = time.NewTicker(speed * time.Millisecond) + go subroutine(w) +} + +func (w *Window) DrawEvent(e *Event) { + xa, ya := w.GetClientPosition(e.Sender) + xb, yb := w.GetClientPosition(e.Receiver) + w.DrawArrow(xa, ya, xb, yb, colors["red"]) +} + +func (w *Window) PrintQuantumInformation() { + beginning := w.scene.Events[0].Date.UnixNano() + totalDuration := w.scene.Events[len(w.scene.Events) - 1].Date.UnixNano() - beginning + nbQuantum := math.Ceil(float64(totalDuration) / quantum) + durationFromBeginning := w.scene.currentTime.UnixNano() - beginning + currentQuantum := math.Ceil(float64(durationFromBeginning) / quantum)+1 + + w.progress.SetText(fmt.Sprint(currentQuantum, " / ", nbQuantum)) +} + +func subroutine(w *Window) { + for _ = range w.ticker.C { + nbEvents := len(w.scene.Events) + if w.scene.currentEvent >= nbEvents { + // TODO disable looping if needed + w.RemoveArrows() + w.scene.currentEvent = 0 // loop + w.Log("Restarting simulation...") + continue + } + + // Remove arrows from last tick + w.RemoveArrows() + + // Check that we have a least one event to read + if nbEvents == 0 { + continue + } + + // Init first time + if w.scene.currentEvent == 0 { + w.scene.currentTime = w.scene.Events[0].Date + } + + endOfQuantum := w.scene.currentTime.Add(quantum * time.Nanosecond) + + for i := w.scene.currentEvent; i < nbEvents; i++ { + e := w.scene.Events[i] + + if e.Date.After(endOfQuantum) || e.Date.Equal(endOfQuantum) { + break + } + + w.DrawEvent(&e) + w.scene.currentEvent++ + } + + w.PrintQuantumInformation() + w.scene.currentTime = endOfQuantum + } +} diff --git a/dfssd/gui/structures.go b/dfssd/gui/structures.go index 5615616..29dd475 100644 --- a/dfssd/gui/structures.go +++ b/dfssd/gui/structures.go @@ -2,8 +2,27 @@ package gui import ( "time" + + "github.com/visualfc/goqt/ui" ) +// Window contains all information used to make the demonstrator works. +// It extends QMainWindow and cache several graphic informations. +// Do not attempt to instantiante it directly, use `NewWindow` function instead. +type Window struct { + *ui.QMainWindow + + logField *ui.QTextEdit + graphics *ui.QGraphicsView + progress *ui.QLabel + scene *Scene + circleSize float64 + pixmaps map[string]*ui.QPixmap + + currentArrows []*ui.QGraphicsPathItem + ticker *time.Ticker +} + // Client represents a DFSSC instance type Client struct { Name string @@ -23,8 +42,7 @@ type Event struct { Type EventType Sender int Receiver int - Date *time.Time - Duration *time.Duration + Date time.Time } // Scene holds the global scene for registered clients and signature events @@ -32,5 +50,6 @@ type Scene struct { Clients []Client Events []Event - currentEvent int + currentTime time.Time + currentEvent int } diff --git a/dfssd/gui/widget.ui b/dfssd/gui/widget.ui index c837232..d6d39ff 100644 --- a/dfssd/gui/widget.ui +++ b/dfssd/gui/widget.ui @@ -141,7 +141,7 @@ - + 0 0 @@ -157,6 +157,22 @@ + + + + + 80 + 0 + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + diff --git a/dfssd/gui/window.go b/dfssd/gui/window.go index b458f1d..19c54e5 100644 --- a/dfssd/gui/window.go +++ b/dfssd/gui/window.go @@ -2,21 +2,12 @@ package gui import ( "math" + "time" "dfss" "github.com/visualfc/goqt/ui" ) -type Window struct { - *ui.QMainWindow - - logField *ui.QTextEdit - graphics *ui.QGraphicsView - scene *Scene - circleSize float64 - pixmaps map[string]*ui.QPixmap -} - func NewWindow() *Window { file := ui.NewFileWithName(":/widget.ui") loader := ui.NewUiLoader() @@ -36,6 +27,7 @@ func NewWindow() *Window { // Load dynamic elements from driver w.logField = ui.NewTextEditFromDriver(widget.FindChild("logField")) w.graphics = ui.NewGraphicsViewFromDriver(widget.FindChild("graphicsView")) + w.progress = ui.NewLabelFromDriver(widget.FindChild("progressLabel")) // Load pixmaps w.pixmaps = map[string]*ui.QPixmap{ @@ -56,8 +48,15 @@ func NewWindow() *Window { Client{"signer2@insa-rennes.fr"}, Client{"signer3@dfss.com"}, } + w.scene.Events = []Event{ + Event{PROMISE, 0, 1, time.Unix(0, 5)}, + Event{SIGNATURE, 1, 2, time.Unix(0, 15)}, + Event{PROMISE, 1, 0, time.Unix(0, 134)}, + Event{OTHER, 0, 1, time.Unix(0, 402)}, + } w.StatusBar().ShowMessage("Ready") + w.StartSimulation() return w } @@ -97,7 +96,6 @@ func (w *Window) OnResizeEvent(ev *ui.QResizeEvent) bool { } func (w *Window) initScene() { - // Save old scene oldScene := w.graphics.Scene() @@ -113,14 +111,9 @@ func (w *Window) initScene() { w.DrawClients() w.DrawServers() - // TEST - xa, ya := w.GetClientPosition(0) - xb, yb := w.GetClientPosition(1) - w.DrawArrow(xa, ya, xb, yb, colors["red"]) - w.DrawArrow(xb, yb, xa, ya, colors["red"]) - // Purge if oldScene != nil { - oldScene.Delete() + w.RemoveArrows() + defer oldScene.Delete() } } -- GitLab From 1f645003e5ad6a9fa75e73979b479f145cc61fb9 Mon Sep 17 00:00:00 2001 From: Lesterpig Date: Fri, 8 Apr 2016 14:35:31 +0200 Subject: [PATCH 4/6] [d] Improve timer management and add controls --- dfssd/gui/application.qrc | 5 ++ dfssd/gui/events.go | 31 ++++++------ dfssd/gui/{clients.go => graphics.go} | 0 dfssd/gui/images/control_pause.png | Bin 0 -> 1850 bytes dfssd/gui/images/control_pause_blue.png | Bin 0 -> 1962 bytes dfssd/gui/images/control_play.png | Bin 0 -> 1806 bytes dfssd/gui/images/control_play_blue.png | Bin 0 -> 1971 bytes dfssd/gui/images/control_rewind_blue.png | Bin 0 -> 2044 bytes dfssd/gui/structures.go | 5 +- dfssd/gui/widget.ui | 51 +++++++++++++++++--- dfssd/gui/window.go | 59 ++++++++++++++++++++--- 11 files changed, 122 insertions(+), 29 deletions(-) rename dfssd/gui/{clients.go => graphics.go} (100%) create mode 100644 dfssd/gui/images/control_pause.png create mode 100644 dfssd/gui/images/control_pause_blue.png create mode 100644 dfssd/gui/images/control_play.png create mode 100644 dfssd/gui/images/control_play_blue.png create mode 100644 dfssd/gui/images/control_rewind_blue.png diff --git a/dfssd/gui/application.qrc b/dfssd/gui/application.qrc index 6fc0032..d51b0b6 100644 --- a/dfssd/gui/application.qrc +++ b/dfssd/gui/application.qrc @@ -4,5 +4,10 @@ images/server_key.png images/server_connect.png images/node_magnifier.png + images/control_play.png + images/control_play_blue.png + images/control_pause.png + images/control_pause_blue.png + images/control_rewind_blue.png diff --git a/dfssd/gui/events.go b/dfssd/gui/events.go index 24f55b6..d8e204e 100644 --- a/dfssd/gui/events.go +++ b/dfssd/gui/events.go @@ -4,17 +4,14 @@ import ( "fmt" "time" "math" + + "github.com/visualfc/goqt/ui" ) // TEMPORARY const quantum = 100 // discretization argument for events (ns) const speed = 500 // duration of a quantum (ms) -func (w *Window) StartSimulation() { - w.ticker = time.NewTicker(speed * time.Millisecond) - go subroutine(w) -} - func (w *Window) DrawEvent(e *Event) { xa, ya := w.GetClientPosition(e.Sender) xb, yb := w.GetClientPosition(e.Receiver) @@ -22,24 +19,30 @@ func (w *Window) DrawEvent(e *Event) { } func (w *Window) PrintQuantumInformation() { + if len(w.scene.Events) == 0 { + w.progress.SetText("No event") + return + } + beginning := w.scene.Events[0].Date.UnixNano() totalDuration := w.scene.Events[len(w.scene.Events) - 1].Date.UnixNano() - beginning nbQuantum := math.Ceil(float64(totalDuration) / quantum) durationFromBeginning := w.scene.currentTime.UnixNano() - beginning currentQuantum := math.Ceil(float64(durationFromBeginning) / quantum)+1 + if w.scene.currentEvent == 0 { + currentQuantum = 0 + } w.progress.SetText(fmt.Sprint(currentQuantum, " / ", nbQuantum)) } -func subroutine(w *Window) { - for _ = range w.ticker.C { +func (w *Window) initTimer() { + w.timer = ui.NewTimerWithParent(w) + w.timer.OnTimeout(func() { nbEvents := len(w.scene.Events) if w.scene.currentEvent >= nbEvents { - // TODO disable looping if needed - w.RemoveArrows() - w.scene.currentEvent = 0 // loop - w.Log("Restarting simulation...") - continue + w.replayButton.Click() + return } // Remove arrows from last tick @@ -47,7 +50,7 @@ func subroutine(w *Window) { // Check that we have a least one event to read if nbEvents == 0 { - continue + return } // Init first time @@ -70,5 +73,5 @@ func subroutine(w *Window) { w.PrintQuantumInformation() w.scene.currentTime = endOfQuantum - } + }) } diff --git a/dfssd/gui/clients.go b/dfssd/gui/graphics.go similarity index 100% rename from dfssd/gui/clients.go rename to dfssd/gui/graphics.go diff --git a/dfssd/gui/images/control_pause.png b/dfssd/gui/images/control_pause.png new file mode 100644 index 0000000000000000000000000000000000000000..186f361f08b9d67858da54d9decd084f25072f2e GIT binary patch literal 1850 zcmV-A2gUe_P)t79kfVk>AgGWyZ4sc(jwaAq`f`gch2uS-|svw2P^y>KYo05W@hHQ z9LK$l;*ez-Na%ylOz`<%l*?07Q{P^^cyVSWcDbkNPnXaW`Vf~yo&|vM z?Af!!B_$=+g9qOLNtR%AbPOiFUbcb4o#?}^1;4W_7Rb%Dvj3VI8!0klCr_R%z{l{C zQzmkL`t<3cm+I%KbF{Ef5MI+nOgg{Uvrl+T2etsV88}0Z% zq!$$xy@w#a(1XweFkqN2m6n$7dKFJTJmg^p461W>O0;6ooN#o1iw^8xj~okH=xsJzf-8=$nT1a|JIW~BTrk#74ASRhg=^#LZPyiin70JXI>5DJAFahnq*!~j%RS6eWR zDmHC$!r1t@;+W@^&`<=>aBpufeDd)}EOH#?+4nzOhTXe%vo(oywKcWCQK3TN)C{4h zI-OgfqvOvC@_GCA?NI_?sHv$rR#jC63kwV24+Nqo2kkD^XoN#yXm+)#Y*!esRl;~3 zeUm-?$3Hs@S(%xDJOlEH06r%RVoFNNA)Bob0=OVbI+aA4uxf_}%_b8Qo?n?x6J{5` z{efA?x7i>yHRTZbrU;l3ZAE^5K1|Qdu#oEu4SQBkN=}SOI37<&A=Um*rek_p)>kUL z|9L3bumK|^RFH21AkYR8kw>te^SbbZE}iHTMkfl>6~_kMx_F(ImQq}yA)slgsahiw z1g#v?GrN0ABYmx=>rfjHH5{W+VLCgdt|2Ya(do&Sv@RF!Vp*I z^%0QJ7=|w9l+oP@bSwgK_LS%@UW=et&}LbdmTb_jL}I6;d*+o>>H#FsadFqlfMH~? zO-K8npg9T7Db-4nq$L})bc>*l*05TSPIw(*<8^cxUPsdCiE&LR7+OqoiU(Gv{)x$P z5Jgkc2E*G2*Q%+B-6zU`53|`7Y>K}X&V7p@Or(jhgeFDqPQe~V>ke0KxCn2 zr(8ydu~}LRIAx97{SYQ6Ctc*500ggIz4{~7awDRr1zHX>CbMrO6Pp1gmTGiLS*`Qb za1!Ytx_411)kD~rJf0CCpX8h374mpI6F#5M-P6-uR90FB5gaH$sV|O_4e`QS~9qniLt44?bV8x|AKr@1ye3EaCqAzUSy0zx;;lr+@M~|_BghOQv z5$R+~iYeVqk|J1CA}X;G>-2=i*%FBwfv+!Jg68Jt`a5^-{Dpu2r&SVZbaeDdd3kvu zIxnxRtYm2gx>RF^BZ^VwTaK35WIBy_#EZ1FH2C?-PcS^}X=!R|x{TW%Q}RRs&_icu zXBUEabKSa(RBLXoa<^LX&_tnlbl6x{hmj-asaW}LT)zf=eSN-j=gu|Ysxi9%_>qj_ zDdD*EYj$?_0gELgH5Wl}+RMi>sg+2m`-w)8-TQTPe)sNOFHYL^Xl4XuMw<)u0LW8_ z`btMf$2A1;y5Ap2DSoj;Ni8xQR~?fLq%^>YCK1UNgkPF|f!_P~AEEQtaO)7tBTBzy zQ!$~MCm;x-Ehi`2Iyg8~x(e?vZ$naq|AFe< z8~<*Q^u+{aElQ5vZr@m6U;kNFR+g<4Q?#tC46?Ixz+@IPmS&g+kNslV^Q3)9Z~YkTjIlC~Hts)IJh_eRK3aqLOS@bsT=)m(xTMp}3pX oE*igAR>>7q$sAdU(fPx# literal 0 HcmV?d00001 diff --git a/dfssd/gui/images/control_pause_blue.png b/dfssd/gui/images/control_pause_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..3ab8b69db2782806559e5ba9cb057bdf899ea869 GIT binary patch literal 1962 zcmV;b2UYlqP)*DuuOMMXlQpx6u zJClcIxVFAE0pSa9apvO~`U zK$^0t{PuhEin3Nt&x86_75?%D0A+zl%7wmBn*cN^?}@FK?XMEXxv zftU8629FgT=8wsMYj++wbE7ji> z=57~^j3Y0QP;zJ>q`}5RH_;;kcQ<*7EbNOHimF%o@uBQtX%dtaWbFs;O32Q{n)#LQ3$Jwy9C^vx6Fx)%M#NP*oZ8KDD%DEr6ne5Z znj%%8Ls(;IrG#x)j>MUGtZ!Z-Id;@>wE?>@>ZAurbU5H^EWc3O3=T=?sqI)YtP~h# zIx4YBMyA6vcyV$NMY05NvCa$KzB}dg7y$^lkL})9ReKN710-3W^aA-wMWHH_u-0vO zpB2~8b23T96B2m9Aq&v0s5lk<;6A#0AL*tXP}-Yr-1qtX4JWR6^QRTLAVjB+NS&f? z)PTzw#kp{>>A6XB;5H$hXn8ro1N={8fOzia%w>62D` zRK8=~tGrosDZNKHbL7%^CV_+v8y`-)2uSMxPx3T8MfKKOvXy~~duz5I19$oMMc&K5 zSK{^~^E{wE_PV>A1tocpLh^{2#e*P>^{UY*H6YS|l?&H7shVaS%k@5Z#_^3Oo(Kby z1=#pw72I!fAFMsNeJ`>f(m}Nc04rj2u<3IPs+wb5lUW$MGk&Jw0?q6e3 z<$b=GAPqpu%osIeRQ`ewKF!ETA2PMj1tlZ1AV1TI2an!1OhTxYU%k}|=dL%ynH$Z} z-O+a2UGeqC2Q`1zAp4$?bfFh|HABJ(!a$_-q=DIkUY@^hQIe}*u4r@QX?pDI9zPod zAK&Wq)*W~MwyV6$f0ydK1&L0-T`&4-7R{FoAjwGmkW!HB#vF+cUpG>lkz}2Q;?Vzn wIZfmdnFg9MMH9UqhK=%4`m#9w^Pd0%0D9&Azh}>Zm;e9(07*qoM6N<$f;khPF8}}l literal 0 HcmV?d00001 diff --git a/dfssd/gui/images/control_play.png b/dfssd/gui/images/control_play.png new file mode 100644 index 0000000000000000000000000000000000000000..3b64790b971704537cdf56306d98c15f0f7d1c16 GIT binary patch literal 1806 zcmV+p2l4ocP)pI+iFg@iCMHwnE?H)_EStDwW*{c}q5j)~GPC{g$1+TWj1*8|aq2Hw zCS!xl0aBnOD9~cC1$sT*`+hyAwzU_u;mzTk^L^j*y!ZD=V1>Wq$B(C^r>B1)kw}iB z7<@h-kkAkBnc)3DD3|Bv=6-B$Zho?ob0zWK*VotQB_}8Us^GW{6`MAJPOpdj{Ctqh zWFZSZUN4M|jlsCd1b+_hRAs}mNYPz6QC_dWt<}RqH*aSY_ z2iC_{SXi)u!{G>7tWv2UH8lm&)}(<%3eex*54}A-;B>hzH8wVWf=j&5Lx4MT=FDV4 zL4mfm_8{;+9;T-s!mP!@Hjud^{g_+unxR%hR+g4MYj0~K%RFpoXjqT8?q{@&1b+JT z>512?s)w-DiEy9%4CMxxnwnZ=FqCKA zzJ0q(3`~)Lq^_>6NUPQU^zM-(4A^3|222}#Fqv7-aqLQ#A=Mz7HH5tmw1QkNgVM56 z%8<=DIXSHZ0|Qn9mWrm=>2z&7ckX1oW@hICnoEPUp?gj)2Q(wJwEO^=AuJtbQc1|V z@I53ma~9mo!S?Nypx5i$2s1!n>(;GmOrw&G8!IsA=KUrVGz<{}LjuFYBXI1!qj2G3 z3n-LIe8xpyF9>^wIAqm|ip{`rTnS-{1Z0(!mB-4;%E06CfX!}??N`C+2pJG7IBkoIYz@X45GG+00YySW!eO0G4|ZG-$@Jku+IT!Xv|hOiwQnC_?ocUX zyMvueBg zULuZe<`hb?k;$cEIi`E&s~GJ4B4e52<-N@J)B}jfpZ$Nqo;}sjj3g*cBUu6H8Db3`bHl7LWVIZ9s*G|iwE#L z5l{pO6k%j{c3p$dKl>E@>ErevcFoJ-bSmO!f#^g0OHE0EUIhR8tCQd%%@JG@6a$g=lG{wC z2QWK3Yb0zU;OOq|{&|!LV3}opjh6p{kd`=dLGN$9(D2PEaA9ikezjv}5T&{cYmM1F z1%yf1M8IV>n`f+6t7&LxkfoJ0N**(RVT>3I2I%Rz0Zok!sJWXxi>0|#=%SRacklL5 z!7~viVatS^kS#4O{kwYg>cceq(FUH(8RkC_0;jCB6n5-*4cw%89G{Cqozv}cLuaQE zrSr)2^z;~RTNdX59v>_f7Z>ZX8Wxu#0FPA>B9RbhKb~h-$qK-!MkHa`zS8;&Oir3R z+S}VN~%s0IkoOz*6eVPs^)diLzu zIy~|r`9FLlqp_LCap{^yquH-krzK_~35jUp6=)hVIZ@DY3g-742!8M0Jqu3SHF(Sv z$`f%e3?@KGR7Ko(?%cVKBo5eY_JsVG3jAeOXv6XR&8B0@CT!0%GhA)I3jf`|Kab#h zaq9%iJf&Z>shC(fi3pPD%FNVg$HylMsqN;h%Ly61BaP%lRKaSA5B})u1EbLhqa&kT z=gyt`SOB+#e;Y*oFhN;^l389}zM-b3=G%;n3|(Pi5fl{_fku;wyc0EW+}1GA~clmGw#07*qoM6N<$g21I+?f?J) literal 0 HcmV?d00001 diff --git a/dfssd/gui/images/control_play_blue.png b/dfssd/gui/images/control_play_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..a1f7345f3713a730b613faf82026caaa0adb375c GIT binary patch literal 1971 zcmV;k2Tb^hP)FuzPnw&Ga@2NOxDg`J$q# zyMDH*0$W!WL8Ha4>l%7TG>k;`q?i4whyuTa`Ew*l^#AdeAZp(J6tQUZrBl^gpQ0u0 zb_ghy`O6CHT< zz4qRZsyEM{OhTS&d1Lpkdza)rM9Q0cqUauqfy1pxw@w(xB!@^#Zy5cf3U=PJki20O zh(crc>HVAUNF*U8#=LTG-J!b{6>iwGr2^-IQCt~`LniGKnJx;P=@vv$Bv_d*B&<*D zo9|c{j_9}%HL!6-E-qgF%BNOrEa*A;_a-MX9Rk9Noz;sn3QGQ1^VoVyGM(ZbgG_Fe z9Jkw$XhEe7nS5-8!?1EfmFwbhEGZlLO(QlW*SG=N* zbxsf{TDvvd<8ha7q&olNdd#$lW6p_`2-0m@-_jPufydY3=PxwC>yl_qF!v_E@4(5Q z0C{!u>iJLC+=i@{uPDhjlSO1JZUKt`bw7`an)kb~_o21;>GN;G z*fNhxF{D`W&?PVA$+$aS8o<8fn=%_(S@mbetvJeZA9DAnVJCFzu&ZcJ^} zk|89`Mmcd)CKqUek(xk)2cm`u7r9%oW!IKu;<-0I#9#JqqY8q?5WZ>15q} zTs$1=ZaCZ43!fs)q6#bmnkZvlrWbYfC-B#O+vx^mK-aD7SxQ-Akwy*pTzenJLzf#^ zHxmd4{_*nR=C-TkQczc$*$eD5jeHyvDf5s06G!%w^0+>uh0XkB)e{tz}Z1oZdi5)jvZ;j(Q3Aw{K%IT2-C~hkm<|} zYCA_xc0iAgbqh%o2)oGEN$=&a-Ao0XD5$NRm`Fx^*|4 zZX74VM}|cxK@S`~kIuIaK60Zk5FoK}=RTm*!kE9TvgE6ny7-=D^URvojp<47I^PE- zuH`c+Hxp09oHPN?{<#^~dIHDWj{oj861&c+G(mv>={?(cA-?dw2lMA8e zsVTP}yHKs~ff+!abkm&9@Ctab@e*1-4-R~M;Nc&UXdlOa@|BFQ&3f=;?b|(B>+dhj z$@DHR@|$YRHa!bBC*7P#xrb(5x)(Uu(294@c7&RLy=@B}(?b}xjZPxK{*3aRxpJ!Z zonY4bZT-V>&o>v%BP$Z`gSdI`n{MP%Xk65;)2N!p!Ww>g_#Do(b`O&Bt^8R*807Ms z?o#T6BEm$1r)rzVvX|$d>KG}@O!uJTYd&ktCe^hC$(|8R)Z;Se4URQ;;$mZyjnF8@R%C-cR7$@7V2rnkDWlHjy+!Iw6DLNw`rbhHsoO zWGC6EtvL4oewPcJdE4r6-{OF literal 0 HcmV?d00001 diff --git a/dfssd/gui/images/control_rewind_blue.png b/dfssd/gui/images/control_rewind_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..de9fc07b247950c8cb283a10fae0316d2954f35b GIT binary patch literal 2044 zcmVB;%w`(oEWB5{V8L z1Y(-j)3g>UblC*+wa>492A7)cD|dt{eS!a{l52qB~0;CwCUw! zZASKY4Iw{aKopuLVA91Oi7yEdFzSU7`}0uf@*hv_da8FS`%06o-~FREbA>;(!mFzD zmoLe}7xU6^=ND3;%A+6EVBpEr=WXSY?e_b11s`(TVU4QM!_LbkG zTd~hVKq+~)=5kS9TKcwcEQOE-P6xth?v7Zlmd1I|bcMchr+ctymPR@zwwBeBXF3B% zw=K`6<;YYBD0gqIZrN~ee#VA-=HOy?40VAa#K>U5;L^mbT>=IPamM0w4RfZ;cJO{^GbzJF*fWxiGlP8R8l1rqveF$Cs3LalJ zoBwABsrt&%Z4ciTPeP85dCBJTU5oP4OMkq&5VcozT)h#6htOp*T}Yhiwg@3e?97+q z?hmh%$m9a{LT}h0G4a5HRGe+=^^4md%xFEbr^Zc8mw>cz-S)YOx8}U@(v!vL8~~aq z-X7XOcHPcpM*lsutKyL@V#7vHpd-tY<+Yw6gFGnkKw$u=(Z^l@XI}@^&w3e~C3^h~s7A(k~Ze^^HZMX2loCjW2 z#`j;`kDokJgclB8M2g>su+s!((p416%7uw^I4Ok~X%vjHaCRz8k6OUkOu%DOk#gd6 z57>-3UYyAq@!Rx51-5*v7&{MLLUMwSnv97^OgMQWEWM4t`|G$mjOZpPoCX%5F6Hx5 zk2I|+^e_R5e9zvi{>$7ll`Hc9e2*8jQ!Pk(cK z9m@kwF1Zbgxftf~c#=HveN;9jt9IQy;130b!l1%u$j-wiqNZd$z!_w<-idTf3^y_< zZeGOCM&S;Gt{&p-WHoCThJnBQY&CZ5K8z9?znZ2(^AZSI88KxWnBx4_=2a8w*df3u z@kr9B*(_`~N$A(3(3Fv;!T@^2Ab{1_S@t28Qj&T#jl_$XkgXV+#?5sY$p#*2XkNnT z58Ex=B|sT7c;Vm8A@~%#W;tsm$_#@>xE_n)ovmx|r}9I{P4km=8VpIXtrNDpZ>Hn! z=ZZ!c7Xm$COjck5(ZS&5s*~pfNK{}C8iy@k?B=j;qU_lrZ)1Sua=cC@9r*8=p#S!@4;JN70}_bR zAv1o=N^q+~!iti76wk{f9m7h-Np=eGIoGkh_S4)s{zvgAFpQOpZ|EnNA|!RENUD)s^f6UOUi$_Ld8kjK!Go2NLew zvGx;Hr;`?~d@R&wBrKaZlPnR|f_?6H#IbYKy|EIf!*e28lkibP2X_CnA#~#R-~J9Q z1vvg=k7RsoHd+st9nf>{Th-kkO(g|d z+q9DOI!2Eoz%V+`i`K*Mz8}rKe|3FJkMB!!(`mp6+hV6vN^y-PUhLUV - CalculatorForm - + Demonstrator + true @@ -66,10 +66,32 @@ 0 - - Play + + + 40 + 40 + - + + Qt::NoFocus + + + true + + + + + + + + 40 + 40 + + + + Qt::NoFocus + + true @@ -82,8 +104,17 @@ 0 - - Replay + + + 40 + 40 + + + + Qt::NoFocus + + + true @@ -108,6 +139,9 @@ 0 + + Qt::TabFocus + us @@ -146,6 +180,9 @@ 0 + + Qt::TabFocus + Qt::Horizontal diff --git a/dfssd/gui/window.go b/dfssd/gui/window.go index 19c54e5..adbcfcc 100644 --- a/dfssd/gui/window.go +++ b/dfssd/gui/window.go @@ -29,18 +29,23 @@ func NewWindow() *Window { w.graphics = ui.NewGraphicsViewFromDriver(widget.FindChild("graphicsView")) w.progress = ui.NewLabelFromDriver(widget.FindChild("progressLabel")) + w.playButton = ui.NewPushButtonFromDriver(widget.FindChild("playButton")) + w.stopButton = ui.NewPushButtonFromDriver(widget.FindChild("stopButton")) + w.replayButton = ui.NewPushButtonFromDriver(widget.FindChild("replayButton")) + // Load pixmaps w.pixmaps = map[string]*ui.QPixmap{ "ttp": ui.NewPixmapWithFilenameFormatFlags(":/images/server_key.png", "", ui.Qt_AutoColor), "platform": ui.NewPixmapWithFilenameFormatFlags(":/images/server_connect.png", "", ui.Qt_AutoColor), } - // Load icon - w.SetWindowIcon(ui.NewIconWithFilename(":/images/node_magnifier.png")) + // Load icons + w.addIcons() // Add actions w.addActions() w.initScene() + w.initTimer() // TEST ONLY w.scene.Clients = []Client{ @@ -56,16 +61,38 @@ func NewWindow() *Window { } w.StatusBar().ShowMessage("Ready") - w.StartSimulation() + w.PrintQuantumInformation() return w } +func (w *Window) OnResizeEvent(ev *ui.QResizeEvent) bool { + w.initScene() + return true +} + func (w *Window) Log(str string) { w.logField.Append(str) w.logField.EnsureCursorVisible() } +func (w *Window) addIcons() { + w.SetWindowIcon(ui.NewIconWithFilename(":/images/node_magnifier.png")) + + var i *ui.QIcon + i = ui.NewIconWithFilename(":/images/control_play_blue.png") + i.AddFileWithFilenameSizeModeState(":/images/control_play.png", ui.NewSizeWithWidthHeight(32, 32), ui.QIcon_Disabled, ui.QIcon_Off) + w.playButton.SetIcon(i) + + i = ui.NewIconWithFilename(":/images/control_pause_blue.png") + i.AddFileWithFilenameSizeModeState(":/images/control_pause.png", ui.NewSizeWithWidthHeight(32, 32), ui.QIcon_Disabled, ui.QIcon_Off) + w.stopButton.SetIcon(i) + + i = ui.NewIconWithFilename(":/images/control_rewind_blue.png") + w.replayButton.SetIcon(i) +} + func (w *Window) addActions() { + // MENU BAR openAct := ui.NewActionWithTextParent("&Open", w) openAct.SetShortcuts(ui.QKeySequence_Open) openAct.SetStatusTip("Open a demonstration file") @@ -88,11 +115,29 @@ func (w *Window) addActions() { w.MenuBar().AddAction(openAct) w.MenuBar().AddAction(saveAct) -} -func (w *Window) OnResizeEvent(ev *ui.QResizeEvent) bool { - w.initScene() - return true + // SIMULATION CONTROL + w.playButton.OnClicked(func() { + w.playButton.SetDisabled(true) + w.stopButton.SetDisabled(false) + w.timer.StartWithMsec(500) + w.Log("Started simulation") + }) + + w.stopButton.OnClicked(func() { + w.playButton.SetDisabled(false) + w.stopButton.SetDisabled(true) + w.timer.Stop() + w.Log("Paused simulation") + }) + w.stopButton.SetDisabled(true) + + w.replayButton.OnClicked(func() { + w.RemoveArrows() + w.scene.currentEvent = 0 + w.PrintQuantumInformation() + w.Log("Restarting simulation") + }) } func (w *Window) initScene() { -- GitLab From f2c44b6cc0580598c9fce4052579076e27325d0b Mon Sep 17 00:00:00 2001 From: Lesterpig Date: Fri, 8 Apr 2016 15:58:15 +0200 Subject: [PATCH 5/6] [d] Improve event import --- dfssd/gui/colors.go | 4 +- dfssd/gui/events.go | 82 ++++++++++++++++++++++++++++++++++++++--- dfssd/gui/graphics.go | 12 ++++-- dfssd/gui/structures.go | 20 +++++----- dfssd/gui/window.go | 19 +--------- dfssd/main.go | 9 +++-- dfssd/server/server.go | 5 +-- dfssd/server/storage.go | 10 ++--- 8 files changed, 110 insertions(+), 51 deletions(-) diff --git a/dfssd/gui/colors.go b/dfssd/gui/colors.go index 4e43cf1..f4e2a11 100644 --- a/dfssd/gui/colors.go +++ b/dfssd/gui/colors.go @@ -4,8 +4,8 @@ import "github.com/visualfc/goqt/ui" var colors = map[string]uint32{ "red": 0x00ff0000, - "blue": 0x0000ff00, - "green": 0x000000ff, + "green": 0x0000aa00, + "blue": 0x000000ff, "black": 0x00000000, } diff --git a/dfssd/gui/events.go b/dfssd/gui/events.go index d8e204e..215ec90 100644 --- a/dfssd/gui/events.go +++ b/dfssd/gui/events.go @@ -2,20 +2,64 @@ package gui import ( "fmt" - "time" "math" + "time" + "dfss/dfssd/api" "github.com/visualfc/goqt/ui" ) // TEMPORARY const quantum = 100 // discretization argument for events (ns) -const speed = 500 // duration of a quantum (ms) +const speed = 1000 // duration of a quantum (ms) + +// AddEvent interprets an incoming event into a graphic one. +// Expected format: +// +// Timestamp: unix nano timestamp +// Identifier: either "platform", "ttp" or "" +// Log: one of the following +// "sent promise to " +// "sent signature to " +// +// Other messages are currently ignored. +func (w *Window) AddEvent(e *api.Log) { + event := Event{ + Sender: w.scene.identifierToIndex(e.Identifier), + Date: time.Unix(0, e.Timestamp), + } + + w.Log(fmt.Sprint(e.Identifier, " ", e.Log)) + + var receiver string + if n, _ := fmt.Sscanf(e.Log, "sent promise to %s", &receiver); n > 0 { + event.Type = PROMISE + event.Receiver = w.scene.identifierToIndex(receiver) + } else if n, _ := fmt.Sscanf(e.Log, "sent signature to %s", &receiver); n > 0 { + event.Type = SIGNATURE + event.Receiver = w.scene.identifierToIndex(receiver) + } + + if receiver != "" { + w.scene.Events = append(w.scene.Events, event) + } +} func (w *Window) DrawEvent(e *Event) { xa, ya := w.GetClientPosition(e.Sender) xb, yb := w.GetClientPosition(e.Receiver) - w.DrawArrow(xa, ya, xb, yb, colors["red"]) + + var color string + switch e.Type { + case PROMISE: + color = "blue" + case SIGNATURE: + color = "green" + default: + color = "black" + } + + w.DrawArrow(xa, ya, xb, yb, colors[color]) } func (w *Window) PrintQuantumInformation() { @@ -25,10 +69,10 @@ func (w *Window) PrintQuantumInformation() { } beginning := w.scene.Events[0].Date.UnixNano() - totalDuration := w.scene.Events[len(w.scene.Events) - 1].Date.UnixNano() - beginning - nbQuantum := math.Ceil(float64(totalDuration) / quantum) + totalDuration := w.scene.Events[len(w.scene.Events)-1].Date.UnixNano() - beginning + nbQuantum := math.Max(1, math.Ceil(float64(totalDuration)/quantum)) durationFromBeginning := w.scene.currentTime.UnixNano() - beginning - currentQuantum := math.Ceil(float64(durationFromBeginning) / quantum)+1 + currentQuantum := math.Ceil(float64(durationFromBeginning)/quantum) + 1 if w.scene.currentEvent == 0 { currentQuantum = 0 @@ -38,6 +82,9 @@ func (w *Window) PrintQuantumInformation() { func (w *Window) initTimer() { w.timer = ui.NewTimerWithParent(w) + + lastNbOfClients := len(w.scene.Clients) + w.timer.OnTimeout(func() { nbEvents := len(w.scene.Events) if w.scene.currentEvent >= nbEvents { @@ -53,6 +100,11 @@ func (w *Window) initTimer() { return } + // Check if need to redraw everything + if lastNbOfClients != len(w.scene.Clients) { + w.initScene() + } + // Init first time if w.scene.currentEvent == 0 { w.scene.currentTime = w.scene.Events[0].Date @@ -75,3 +127,21 @@ func (w *Window) initTimer() { w.scene.currentTime = endOfQuantum }) } + +func (s *Scene) identifierToIndex(identifier string) int { + if identifier == "platform" { + return -1 + } + if identifier == "ttp" { + return -2 + } + + for i, c := range s.Clients { + if c.Name == identifier { + return i + } + } + + s.Clients = append(s.Clients, Client{Name: identifier}) + return len(s.Clients) - 1 +} diff --git a/dfssd/gui/graphics.go b/dfssd/gui/graphics.go index da9f561..b8fd333 100644 --- a/dfssd/gui/graphics.go +++ b/dfssd/gui/graphics.go @@ -26,6 +26,10 @@ func (w *Window) DrawClients() { } func (w *Window) GetClientPosition(i int) (x, y float64) { + if i < 0 { + return w.GetServerPosition(i == -1) + } + nbClients := float64(len(w.scene.Clients)) angle := 2 * math.Pi * float64(i) / nbClients return math.Cos(angle) * (w.circleSize / 2), math.Sin(angle) * (w.circleSize / 2) @@ -33,7 +37,7 @@ func (w *Window) GetClientPosition(i int) (x, y float64) { func (w *Window) GetServerPosition(platform bool) (x, y float64) { x = w.circleSize/2 + 150 - y = -16 + y = 0 if !platform { x *= -1 } @@ -45,12 +49,12 @@ func (w *Window) DrawServers() { ttp := scene.AddPixmap(w.pixmaps["ttp"]) x, y := w.GetServerPosition(false) - ttp.SetPosFWithXY(x, y) + ttp.SetPosFWithXY(x-32, y-16) ttp.SetToolTip("TTP") platform := scene.AddPixmap(w.pixmaps["platform"]) - platform.SetX(w.circleSize/2 + 150) - platform.SetY(-16) + x, y = w.GetServerPosition(true) + platform.SetPosFWithXY(x, y-16) platform.SetToolTip("Platform") } diff --git a/dfssd/gui/structures.go b/dfssd/gui/structures.go index 72b619b..f646c6a 100644 --- a/dfssd/gui/structures.go +++ b/dfssd/gui/structures.go @@ -12,15 +12,15 @@ import ( type Window struct { *ui.QMainWindow - logField *ui.QTextEdit - graphics *ui.QGraphicsView - progress *ui.QLabel - playButton *ui.QPushButton - stopButton *ui.QPushButton + logField *ui.QTextEdit + graphics *ui.QGraphicsView + progress *ui.QLabel + playButton *ui.QPushButton + stopButton *ui.QPushButton replayButton *ui.QPushButton - scene *Scene - circleSize float64 - pixmaps map[string]*ui.QPixmap + scene *Scene + circleSize float64 + pixmaps map[string]*ui.QPixmap currentArrows []*ui.QGraphicsPathItem timer *ui.QTimer @@ -53,6 +53,6 @@ type Scene struct { Clients []Client Events []Event - currentTime time.Time - currentEvent int + currentTime time.Time + currentEvent int } diff --git a/dfssd/gui/window.go b/dfssd/gui/window.go index adbcfcc..579772f 100644 --- a/dfssd/gui/window.go +++ b/dfssd/gui/window.go @@ -47,19 +47,6 @@ func NewWindow() *Window { w.initScene() w.initTimer() - // TEST ONLY - w.scene.Clients = []Client{ - Client{"signer1@lesterpig.com"}, - Client{"signer2@insa-rennes.fr"}, - Client{"signer3@dfss.com"}, - } - w.scene.Events = []Event{ - Event{PROMISE, 0, 1, time.Unix(0, 5)}, - Event{SIGNATURE, 1, 2, time.Unix(0, 15)}, - Event{PROMISE, 1, 0, time.Unix(0, 134)}, - Event{OTHER, 0, 1, time.Unix(0, 402)}, - } - w.StatusBar().ShowMessage("Ready") w.PrintQuantumInformation() return w @@ -71,6 +58,7 @@ func (w *Window) OnResizeEvent(ev *ui.QResizeEvent) bool { } func (w *Window) Log(str string) { + str = time.Now().Format("[15:04:05.000] ") + str w.logField.Append(str) w.logField.EnsureCursorVisible() } @@ -120,15 +108,13 @@ func (w *Window) addActions() { w.playButton.OnClicked(func() { w.playButton.SetDisabled(true) w.stopButton.SetDisabled(false) - w.timer.StartWithMsec(500) - w.Log("Started simulation") + w.timer.StartWithMsec(speed) }) w.stopButton.OnClicked(func() { w.playButton.SetDisabled(false) w.stopButton.SetDisabled(true) w.timer.Stop() - w.Log("Paused simulation") }) w.stopButton.SetDisabled(true) @@ -136,7 +122,6 @@ func (w *Window) addActions() { w.RemoveArrows() w.scene.currentEvent = 0 w.PrintQuantumInformation() - w.Log("Restarting simulation") }) } diff --git a/dfssd/main.go b/dfssd/main.go index fa2ce27..fc2ede4 100644 --- a/dfssd/main.go +++ b/dfssd/main.go @@ -8,6 +8,7 @@ import ( "strconv" "dfss" + "dfss/dfssd/api" "dfss/dfssd/gui" "dfss/dfssd/server" "github.com/visualfc/goqt/ui" @@ -51,10 +52,10 @@ func main() { case "version": fmt.Println("v"+dfss.Version, runtime.GOOS, runtime.GOARCH) case "nogui": - lfn := func(str string) { - fmt.Println(str) + fn := func(v *api.Log) { + fmt.Printf("[%d] %s: %s\n", v.Timestamp, v.Identifier, v.Log) } - err := server.Listen("0.0.0.0:"+strconv.Itoa(port), lfn) + err := server.Listen("0.0.0.0:"+strconv.Itoa(port), fn) if err != nil { os.Exit(1) } @@ -62,7 +63,7 @@ func main() { ui.Run(func() { window := gui.NewWindow() go func() { - err := server.Listen("0.0.0.0:"+strconv.Itoa(port), window.Log) + err := server.Listen("0.0.0.0:"+strconv.Itoa(port), window.AddEvent) if err != nil { window.Log("!! " + err.Error()) } diff --git a/dfssd/server/server.go b/dfssd/server/server.go index cf0a484..02f2bdc 100644 --- a/dfssd/server/server.go +++ b/dfssd/server/server.go @@ -20,17 +20,16 @@ func (s *Server) SendLog(ctx context.Context, in *api.Log) (*api.Ack, error) { } // Listen with gRPG service -func Listen(addrPort string, lfn func(string)) error { +func Listen(addrPort string, fn func(*api.Log)) error { // open tcp socket lis, err := net.Listen("tcp", addrPort) if err != nil { grpclog.Fatalf("Failed to open tcp socket: %v", err) return err } - lfn("Server listening on " + addrPort) // log display manager - go displayHandler(lfn) + go displayHandler(fn) // bootstrap gRPC service ! grpcServer := grpc.NewServer() diff --git a/dfssd/server/storage.go b/dfssd/server/storage.go index b2e4e0c..d11211f 100644 --- a/dfssd/server/storage.go +++ b/dfssd/server/storage.go @@ -1,7 +1,6 @@ package server import ( - "fmt" "sort" "sync" "time" @@ -23,7 +22,7 @@ func addMessage(msg *api.Log) { } // display logs that are more than since (ms) old -func display(since int64, lfn func(string)) { +func display(since int64, fn func(*api.Log)) { var out []*api.Log // sorted messages to display var recycled []*api.Log // messages too recent to be displayed @@ -45,15 +44,16 @@ func display(since int64, lfn func(string)) { sort.Sort(ByTimestamp(out)) for _, v := range out { - lfn(fmt.Sprintf("[%d] %s:: %s", v.Timestamp, v.Identifier, v.Log)) + //lfn() + fn(v) } } // refresh every second -func displayHandler(lfn func(string)) { +func displayHandler(fn func(*api.Log)) { ticker := time.NewTicker(time.Second) for range ticker.C { - display(1000, lfn) + display(1000, fn) } } -- GitLab From 11dcecc3c180e5255ea80597181bf1957bd27530 Mon Sep 17 00:00:00 2001 From: Lesterpig Date: Fri, 8 Apr 2016 16:12:01 +0200 Subject: [PATCH 6/6] [d] Add some documentation --- dfssd/gui/colors.go | 2 ++ dfssd/gui/events.go | 6 ++++++ dfssd/gui/graphics.go | 15 ++++++++++++--- dfssd/gui/save.go | 2 ++ dfssd/gui/structures.go | 2 ++ dfssd/gui/window.go | 13 +++++++++++++ 6 files changed, 37 insertions(+), 3 deletions(-) diff --git a/dfssd/gui/colors.go b/dfssd/gui/colors.go index f4e2a11..384c1e9 100644 --- a/dfssd/gui/colors.go +++ b/dfssd/gui/colors.go @@ -1,5 +1,7 @@ package gui +// This file stores useful colors + import "github.com/visualfc/goqt/ui" var colors = map[string]uint32{ diff --git a/dfssd/gui/events.go b/dfssd/gui/events.go index 215ec90..e03d81d 100644 --- a/dfssd/gui/events.go +++ b/dfssd/gui/events.go @@ -1,5 +1,7 @@ package gui +// This file handles event timers and imports. + import ( "fmt" "math" @@ -45,6 +47,7 @@ func (w *Window) AddEvent(e *api.Log) { } } +// DrawEvent triggers the appropriate draw action for a spectific event. func (w *Window) DrawEvent(e *Event) { xa, ya := w.GetClientPosition(e.Sender) xb, yb := w.GetClientPosition(e.Receiver) @@ -62,6 +65,7 @@ func (w *Window) DrawEvent(e *Event) { w.DrawArrow(xa, ya, xb, yb, colors[color]) } +// PrintQuantumInformation triggers the update of the "x / y" quantum information. func (w *Window) PrintQuantumInformation() { if len(w.scene.Events) == 0 { w.progress.SetText("No event") @@ -80,6 +84,7 @@ func (w *Window) PrintQuantumInformation() { w.progress.SetText(fmt.Sprint(currentQuantum, " / ", nbQuantum)) } +// initTimer is called during window initialization. It initializes the timeout signal called for each refresh. func (w *Window) initTimer() { w.timer = ui.NewTimerWithParent(w) @@ -128,6 +133,7 @@ func (w *Window) initTimer() { }) } +// identifierToIndex is used to retrieve a client index from its name, inserting a new client if needed. func (s *Scene) identifierToIndex(identifier string) int { if identifier == "platform" { return -1 diff --git a/dfssd/gui/graphics.go b/dfssd/gui/graphics.go index b8fd333..d83d8bd 100644 --- a/dfssd/gui/graphics.go +++ b/dfssd/gui/graphics.go @@ -1,14 +1,18 @@ package gui +// This file handles complex graphic primitives for the demonstrator. + import ( "math" "github.com/visualfc/goqt/ui" ) -const ARROW_T = math.Pi / 6 -const ARROW_L = 15 +// These two constants are used to configure arrows +const ARROW_T = math.Pi / 6 // angle +const ARROW_L = 15 // side length +// DrawClients draws the different clients in a circle. func (w *Window) DrawClients() { scene := w.graphics.Scene() for i, c := range w.scene.Clients { @@ -25,6 +29,7 @@ func (w *Window) DrawClients() { } } +// GetClientPosition translates a client index into its cartesian coordinates. func (w *Window) GetClientPosition(i int) (x, y float64) { if i < 0 { return w.GetServerPosition(i == -1) @@ -35,6 +40,7 @@ func (w *Window) GetClientPosition(i int) (x, y float64) { return math.Cos(angle) * (w.circleSize / 2), math.Sin(angle) * (w.circleSize / 2) } +// GetServerPosition translates a server into its cartesian coordinates. func (w *Window) GetServerPosition(platform bool) (x, y float64) { x = w.circleSize/2 + 150 y = 0 @@ -44,12 +50,13 @@ func (w *Window) GetServerPosition(platform bool) (x, y float64) { return } +// DrawServers draws the DFSS main servers (ttp and platform) func (w *Window) DrawServers() { scene := w.graphics.Scene() ttp := scene.AddPixmap(w.pixmaps["ttp"]) x, y := w.GetServerPosition(false) - ttp.SetPosFWithXY(x-32, y-16) + ttp.SetPosFWithXY(x-32, y-16) // we are shifting here a bit for better arrow display ttp.SetToolTip("TTP") platform := scene.AddPixmap(w.pixmaps["platform"]) @@ -58,6 +65,7 @@ func (w *Window) DrawServers() { platform.SetToolTip("Platform") } +// DrawArrow is the graphic primitive for drawing an arrow between A and B points func (w *Window) DrawArrow(xa, ya, xb, yb float64, rgb uint32) { scene := w.graphics.Scene() @@ -94,6 +102,7 @@ func (w *Window) DrawArrow(xa, ya, xb, yb float64, rgb uint32) { w.currentArrows = append(w.currentArrows, arrow) } +// RemoveArrows remove every arrow present in the graphic area, and delete them for better memory management. func (w *Window) RemoveArrows() { scene := w.graphics.Scene() diff --git a/dfssd/gui/save.go b/dfssd/gui/save.go index 85b0cf7..d230c49 100644 --- a/dfssd/gui/save.go +++ b/dfssd/gui/save.go @@ -1,5 +1,7 @@ package gui +// This file handles open/save feature. + import ( "encoding/json" "io/ioutil" diff --git a/dfssd/gui/structures.go b/dfssd/gui/structures.go index f646c6a..209fd85 100644 --- a/dfssd/gui/structures.go +++ b/dfssd/gui/structures.go @@ -1,5 +1,7 @@ package gui +// This file stores strucutures used in GUI for fast documentation. + import ( "time" diff --git a/dfssd/gui/window.go b/dfssd/gui/window.go index 579772f..8ea71a9 100644 --- a/dfssd/gui/window.go +++ b/dfssd/gui/window.go @@ -1,5 +1,9 @@ +// Package gui is the graphic part of the dfssd program. package gui +// This file is the entry point of the gui package. +// It handles window instantiation and basic operations on it. + import ( "math" "time" @@ -8,6 +12,7 @@ import ( "github.com/visualfc/goqt/ui" ) +// NewWindow creates and initialiaze a new dfssd main window. func NewWindow() *Window { file := ui.NewFileWithName(":/widget.ui") loader := ui.NewUiLoader() @@ -52,17 +57,22 @@ func NewWindow() *Window { return w } +// OnResizeEvent is called by Qt each time an user tries to resize the window. +// We have to redraw the whole scene to adapt. func (w *Window) OnResizeEvent(ev *ui.QResizeEvent) bool { w.initScene() return true } +// Log is used to print a new line in the log area of the window. +// It should be thread-safe. func (w *Window) Log(str string) { str = time.Now().Format("[15:04:05.000] ") + str w.logField.Append(str) w.logField.EnsureCursorVisible() } +// addIcons adds icons to control buttons, since we cannot add them directly in QtCreator. func (w *Window) addIcons() { w.SetWindowIcon(ui.NewIconWithFilename(":/images/node_magnifier.png")) @@ -79,6 +89,7 @@ func (w *Window) addIcons() { w.replayButton.SetIcon(i) } +// addActions adds action listenners to interactive parts of the window. func (w *Window) addActions() { // MENU BAR openAct := ui.NewActionWithTextParent("&Open", w) @@ -125,6 +136,8 @@ func (w *Window) addActions() { }) } +// initScene creates the Qt graphic scene associated to our custom scene. +// It draws the base circle, clients and servers, and do some memory management for us. func (w *Window) initScene() { // Save old scene oldScene := w.graphics.Scene() -- GitLab