window.go 5.02 KB
Newer Older
Loïck Bonniot's avatar
Loïck Bonniot committed
1
// Package gui is the graphic part of the dfssd program.
2
3
package gui

Loïck Bonniot's avatar
Loïck Bonniot committed
4
5
6
// This file is the entry point of the gui package.
// It handles window instantiation and basic operations on it.

7
import (
Loïck Bonniot's avatar
Loïck Bonniot committed
8
	"math"
9
	"time"
Loïck Bonniot's avatar
Loïck Bonniot committed
10

11
12
13
14
	"dfss"
	"github.com/visualfc/goqt/ui"
)

Loïck Bonniot's avatar
Loïck Bonniot committed
15
// NewWindow creates and initialiaze a new dfssd main window.
16
17
18
19
20
21
22
23
24
25
26
27
func NewWindow() *Window {
	file := ui.NewFileWithName(":/widget.ui")
	loader := ui.NewUiLoader()
	widget := loader.Load(file)

	// Init main window
	window := ui.NewMainWindow()
	window.SetCentralWidget(widget)
	window.SetWindowTitle("DFSS Demonstrator v" + dfss.Version)

	w := &Window{
		QMainWindow: window,
Loïck Bonniot's avatar
Loïck Bonniot committed
28
		scene:       &Scene{},
29
	}
Loïck Bonniot's avatar
Loïck Bonniot committed
30
	w.InstallEventFilter(w)
31
32
33

	// Load dynamic elements from driver
	w.logField = ui.NewTextEditFromDriver(widget.FindChild("logField"))
Loïck Bonniot's avatar
Loïck Bonniot committed
34
	w.graphics = ui.NewGraphicsViewFromDriver(widget.FindChild("graphicsView"))
35
	w.progress = ui.NewLabelFromDriver(widget.FindChild("progressLabel"))
Loïck Bonniot's avatar
Loïck Bonniot committed
36

37
38
39
40
	w.playButton = ui.NewPushButtonFromDriver(widget.FindChild("playButton"))
	w.stopButton = ui.NewPushButtonFromDriver(widget.FindChild("stopButton"))
	w.replayButton = ui.NewPushButtonFromDriver(widget.FindChild("replayButton"))

41
42
43
	w.quantumField = ui.NewSpinBoxFromDriver(widget.FindChild("quantumField"))
	w.speedSlider = ui.NewSliderFromDriver(widget.FindChild("speedSlider"))

Loïck Bonniot's avatar
Loïck Bonniot committed
44
45
46
47
48
49
	// 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),
	}

50
51
	// Load icons
	w.addIcons()
52
53
54

	// Add actions
	w.addActions()
Loïck Bonniot's avatar
Loïck Bonniot committed
55
	w.initScene()
56
	w.initTimer()
Loïck Bonniot's avatar
Loïck Bonniot committed
57

58
	w.StatusBar().ShowMessage("Ready")
59
	w.PrintQuantumInformation()
60
61
62
	return w
}

Loïck Bonniot's avatar
Loïck Bonniot committed
63
64
// OnResizeEvent is called by Qt each time an user tries to resize the window.
// We have to redraw the whole scene to adapt.
65
66
67
68
69
func (w *Window) OnResizeEvent(ev *ui.QResizeEvent) bool {
	w.initScene()
	return true
}

Loïck Bonniot's avatar
Loïck Bonniot committed
70
71
// Log is used to print a new line in the log area of the window.
// It should be thread-safe.
72
func (w *Window) Log(str string) {
Loïck Bonniot's avatar
Loïck Bonniot committed
73
	str = time.Now().Format("[15:04:05.000] ") + str
74
75
76
77
	w.logField.Append(str)
	w.logField.EnsureCursorVisible()
}

Loïck Bonniot's avatar
Loïck Bonniot committed
78
// addIcons adds icons to control buttons, since we cannot add them directly in QtCreator.
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
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)
}

Loïck Bonniot's avatar
Loïck Bonniot committed
95
// addActions adds action listenners to interactive parts of the window.
96
func (w *Window) addActions() {
97
	// MENU BAR
98
99
100
	openAct := ui.NewActionWithTextParent("&Open", w)
	openAct.SetShortcuts(ui.QKeySequence_Open)
	openAct.SetStatusTip("Open a demonstration file")
Loïck Bonniot's avatar
Loïck Bonniot committed
101
102
103
104
105
106
	openAct.OnTriggered(func() {
		filename := ui.QFileDialogGetOpenFileName()
		if filename != "" {
			w.Open(filename)
		}
	})
107
108
109
110

	saveAct := ui.NewActionWithTextParent("&Save", w)
	saveAct.SetShortcuts(ui.QKeySequence_Save)
	saveAct.SetStatusTip("Save a demonstration file")
Loïck Bonniot's avatar
Loïck Bonniot committed
111
112
113
114
115
116
	saveAct.OnTriggered(func() {
		filename := ui.QFileDialogGetSaveFileName()
		if filename != "" {
			w.Save(filename)
		}
	})
117
118
119

	w.MenuBar().AddAction(openAct)
	w.MenuBar().AddAction(saveAct)
Loïck Bonniot's avatar
Loïck Bonniot committed
120

121
122
123
124
	// SIMULATION CONTROL
	w.playButton.OnClicked(func() {
		w.playButton.SetDisabled(true)
		w.stopButton.SetDisabled(false)
125
126
127
128
129
		s := w.speedSlider.Value()
		if s == 0 {
			s = 100 // step-by-step arbitrary speed value
		}
		speed := 2000 / s
Loïck Bonniot's avatar
Loïck Bonniot committed
130
		w.timer.StartWithMsec(speed)
131
132
133
134
135
136
137
138
139
140
141
142
143
144
	})

	w.stopButton.OnClicked(func() {
		w.playButton.SetDisabled(false)
		w.stopButton.SetDisabled(true)
		w.timer.Stop()
	})
	w.stopButton.SetDisabled(true)

	w.replayButton.OnClicked(func() {
		w.RemoveArrows()
		w.scene.currentEvent = 0
		w.PrintQuantumInformation()
	})
145
146
147
148
149
150
151
152
153
154
155

	w.quantumField.OnValueChanged(func(_ string) {
		w.replayButton.Click()
	})

	w.speedSlider.OnValueChanged(func(_ int32) {
		if !w.playButton.IsEnabled() { // playing right now
			w.stopButton.Click()
			w.playButton.Click()
		}
	})
Loïck Bonniot's avatar
Loïck Bonniot committed
156
157
}

Loïck Bonniot's avatar
Loïck Bonniot committed
158
159
// 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.
Loïck Bonniot's avatar
Loïck Bonniot committed
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
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()

	// Purge
	if oldScene != nil {
178
179
		w.RemoveArrows()
		defer oldScene.Delete()
Loïck Bonniot's avatar
Loïck Bonniot committed
180
181
	}
}