window.go 4.95 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
		speed := 2000 / w.speedSlider.Value()
Loïck Bonniot's avatar
Loïck Bonniot committed
126
		w.timer.StartWithMsec(speed)
127 128 129 130 131 132 133 134 135 136 137 138 139 140
	})

	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()
	})
141 142 143 144 145 146 147 148 149 150 151

	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
152 153
}

Loïck Bonniot's avatar
Loïck Bonniot committed
154 155
// 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
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
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 {
174 175
		w.RemoveArrows()
		defer oldScene.Delete()
Loïck Bonniot's avatar
Loïck Bonniot committed
176 177
	}
}