diff --git a/Makefile b/Makefile index 7845d5c3..176f0797 100644 --- a/Makefile +++ b/Makefile @@ -66,7 +66,7 @@ build-internal: prepare-internal cp ../*.deb /build/; prepare-internal: - dch --create -v $(VERSION)-6 --package $(PACKAGE_NAME) empty; \ + dch --create -v $(VERSION)-9 --package $(PACKAGE_NAME) empty; \ cd $(WORKDIR)/..; \ tar -czf octoscreen_$(VERSION).orig.tar.gz --exclude-vcs OctoScreen diff --git a/styles/z-bolt/images/actions.svg b/styles/z-bolt/images/actions.svg new file mode 100644 index 00000000..fdbc7555 --- /dev/null +++ b/styles/z-bolt/images/actions.svg @@ -0,0 +1,51 @@ + + + + actions + Created with Sketch. + + + + Actions + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/styles/z-bolt/style.css b/styles/z-bolt/style.css index 0dc09271..8bc6fe73 100644 --- a/styles/z-bolt/style.css +++ b/styles/z-bolt/style.css @@ -20,7 +20,7 @@ scrollbar slider { } progress, trough { - min-height: 40px; + min-height: 20px; font-size: 50px; } @@ -31,8 +31,12 @@ progress { } .printing-progress-bar{ - font-size: 70px; - color: #999; + font-size: 60px; + color: #00C9B4; +} + +.printing-state { + opacity: 0.5; } button { @@ -142,25 +146,8 @@ button.keyboard { } .printing-status-label { - margin-top: 10px; - /* font-size: 24px; */ -} - -/* GtkWindow { - background-color: green; - border-width: 3px; - border-color: blue; -} */ - -/* GtkButton { - background-image: none; - background-color:#1010FF; - margin:2px; - border-radius:0; -} */ + padding-top: 5px; + padding-bottom: 3px; -/* button, entry { - color: #ff00ea; - font: 12px "Comic Sans"; - background-color: #1010FF; - } */ \ No newline at end of file + font-size: 24px; +} diff --git a/ui/common.go b/ui/common.go index a1d584cf..30b8c089 100644 --- a/ui/common.go +++ b/ui/common.go @@ -10,6 +10,7 @@ import ( "github.com/gotk3/gotk3/glib" "github.com/gotk3/gotk3/gtk" + "github.com/mcuadros/go-octoprint" ) // Set at compilation time. @@ -89,6 +90,21 @@ func (p *CommonPanel) Scaled(s int) int { return s * p.UI.scaleFactor } +func (m *CommonPanel) arrangeButtons(buttons []gtk.IWidget) { + + row := 4 + + for i, k := range buttons { + m.Grid().Attach(k, (i%row)+1, i/row, 1, 1) + } +} + +func (m *CommonPanel) command(gcode string) error { + cmd := &octoprint.CommandRequest{} + cmd.Commands = []string{gcode} + return cmd.Do(m.UI.Printer) +} + type BackgroundTask struct { close chan bool diff --git a/ui/extrude.go b/ui/extrude.go new file mode 100644 index 00000000..def9a481 --- /dev/null +++ b/ui/extrude.go @@ -0,0 +1,196 @@ +package ui + +import ( + "fmt" + "strings" + "time" + + "github.com/gotk3/gotk3/gtk" + "github.com/mcuadros/go-octoprint" +) + +var extrudePanelInstance *extrudePanel + +type extrudePanel struct { + CommonPanel + + amount *StepButton + tool *StepButton + + box *gtk.Box + labels map[string]*LabelWithImage + previous *octoprint.TemperatureState +} + +func ExtrudePanel(ui *UI, parent Panel) Panel { + if extrudePanelInstance == nil { + m := &extrudePanel{CommonPanel: NewCommonPanel(ui, parent), + labels: map[string]*LabelWithImage{}, + } + m.panelH = 2 + m.b = NewBackgroundTask(time.Second*5, m.updateTemperatures) + m.initialize() + extrudePanelInstance = m + } + + return extrudePanelInstance +} + +func (m *extrudePanel) initialize() { + defer m.Initialize() + + m.Grid().Attach(m.createExtrudeButton("Extrude", "extrude.svg", 1), 1, 0, 1, 1) + m.Grid().Attach(m.createExtrudeButton("Retract", "retract.svg", -1), 4, 0, 1, 1) + + m.box = MustBox(gtk.ORIENTATION_VERTICAL, 5) + m.box.SetVAlign(gtk.ALIGN_CENTER) + m.box.SetHAlign(gtk.ALIGN_CENTER) + m.Grid().Attach(m.box, 2, 0, 2, 1) + + m.amount = MustStepButton("move-step.svg", Step{"1mm", 1}, Step{"5mm", 5}, Step{"10mm", 10}) + m.Grid().Attach(m.amount, 2, 1, 1, 1) + + m.Grid().Attach(m.createToolButton(), 1, 1, 1, 1) + m.Grid().Attach(m.createFlowrateButton(), 3, 1, 1, 1) +} + +func (m *extrudePanel) updateTemperatures() { + s, err := (&octoprint.ToolStateRequest{ + History: true, + Limit: 1, + }).Do(m.UI.Printer) + + if err != nil { + Logger.Error(err) + return + } + + m.loadTemperatureState(s) +} + +func (m *extrudePanel) loadTemperatureState(s *octoprint.TemperatureState) { + for tool, current := range s.Current { + if _, ok := m.labels[tool]; !ok { + m.addNewTool(tool) + } + + m.loadTemperatureData(tool, ¤t) + } + + m.previous = s +} + +func (m *extrudePanel) addNewTool(tool string) { + m.labels[tool] = MustLabelWithImage("extruder.svg", "") + m.box.Add(m.labels[tool]) + m.tool.AddStep(Step{strings.Title(tool), tool}) + + Logger.Infof("New tool detected %s", tool) +} + +func (m *extrudePanel) loadTemperatureData(tool string, d *octoprint.TemperatureData) { + text := fmt.Sprintf("%s: %.1f°C / %.1f°C", strings.Title(tool), d.Actual, d.Target) + + if m.previous != nil && d.Target > 0 { + if p, ok := m.previous.Current[tool]; ok { + text = fmt.Sprintf("%s (%.1f°C)", text, d.Actual-p.Actual) + } + } + + m.labels[tool].Label.SetText(text) + m.labels[tool].ShowAll() +} + +func (m *extrudePanel) createToolButton() *StepButton { + m.tool = MustStepButton("extruder.svg") + m.tool.Callback = func() { + cmd := &octoprint.ToolSelectRequest{} + cmd.Tool = m.tool.Value().(string) + + Logger.Infof("Changing tool to %s", cmd.Tool) + if err := cmd.Do(m.UI.Printer); err != nil { + Logger.Error(err) + return + } + } + + return m.tool +} + +func (m *extrudePanel) createFlowrateButton() *StepButton { + b := MustStepButton("speed-step.svg", Step{"Slow", 75}, Step{"Normal", 100}, Step{"High", 125}) + b.Callback = func() { + cmd := &octoprint.ToolFlowrateRequest{} + cmd.Factor = b.Value().(int) + + Logger.Infof("Changing flowrate to %d%%", cmd.Factor) + if err := cmd.Do(m.UI.Printer); err != nil { + Logger.Error(err) + return + } + } + + return b +} + +func (m *extrudePanel) createLoadButton() gtk.IWidget { + length := 750.0 + + if m.UI.Settings != nil { + length = m.UI.Settings.FilamentInLength + } + + return MustButtonImage("Load", "extrude.svg", func() { + cmd := &octoprint.CommandRequest{} + cmd.Commands = []string{ + "G91", + fmt.Sprintf("G0 E%.1f F5000", length*0.80), + fmt.Sprintf("G0 E%.1f F500", length*0.20), + "G90", + } + + Logger.Info("Sending filament load request") + if err := cmd.Do(m.UI.Printer); err != nil { + Logger.Error(err) + return + } + }) +} + +func (m *extrudePanel) createUnloadButton() gtk.IWidget { + + length := 800.0 + + if m.UI.Settings != nil { + length = m.UI.Settings.FilamentOutLength + } + + return MustButtonImage("Unload", "retract.svg", func() { + cmd := &octoprint.CommandRequest{} + cmd.Commands = []string{ + "G91", + fmt.Sprintf("G0 E-%.1f F5000", length), + "G90", + } + + Logger.Info("Sending filament unload request") + if err := cmd.Do(m.UI.Printer); err != nil { + Logger.Error(err) + return + } + }) +} + +func (m *extrudePanel) createExtrudeButton(label, image string, dir int) gtk.IWidget { + + return MustPressedButton(label, image, func() { + cmd := &octoprint.ToolExtrudeRequest{} + cmd.Amount = m.amount.Value().(int) * dir + + Logger.Infof("Sending extrude request, with amount %d", cmd.Amount) + if err := cmd.Do(m.UI.Printer); err != nil { + Logger.Error(err) + return + } + }, 200) +} diff --git a/ui/filament.go b/ui/filament.go index 8c266dbc..32dd89c1 100644 --- a/ui/filament.go +++ b/ui/filament.go @@ -14,9 +14,6 @@ var filamentPanelInstance *filamentPanel type filamentPanel struct { CommonPanel - amount *StepButton - tool *StepButton - box *gtk.Box labels map[string]*LabelWithImage previous *octoprint.TemperatureState @@ -39,23 +36,22 @@ func FilamentPanel(ui *UI, parent Panel) Panel { func (m *filamentPanel) initialize() { defer m.Initialize() + m.Grid().Attach(m.createChangeToolButton(0), 1, 0, 1, 1) + m.Grid().Attach(m.createChangeToolButton(1), 2, 0, 1, 1) + m.Grid().Attach(m.createChangeToolButton(2), 3, 0, 1, 1) + m.Grid().Attach(m.createChangeToolButton(3), 4, 0, 1, 1) + m.Grid().Attach(m.createLoadButton(), 1, 1, 1, 1) m.Grid().Attach(m.createUnloadButton(), 4, 1, 1, 1) - m.Grid().Attach(m.createExtrudeButton("Extrude", "extrude.svg", 1), 1, 0, 1, 1) - m.Grid().Attach(m.createExtrudeButton("Retract", "retract.svg", -1), 4, 0, 1, 1) + m.Grid().Attach(MustButtonImageStyle("Temperature", "heat-up.svg", "color4", m.showTemperature), 1, 2, 1, 1) m.box = MustBox(gtk.ORIENTATION_VERTICAL, 5) m.box.SetVAlign(gtk.ALIGN_CENTER) m.box.SetHAlign(gtk.ALIGN_CENTER) - m.Grid().Attach(m.box, 2, 0, 2, 2) + m.Grid().Attach(m.box, 2, 1, 2, 2) - m.amount = MustStepButton("move-step.svg", Step{"1mm", 1}, Step{"5mm", 5}, Step{"10mm", 10}) - m.Grid().Attach(m.amount, 2, 2, 1, 1) - - m.Grid().Attach(m.createToolButton(), 1, 2, 1, 1) - m.Grid().Attach(m.createFlowrateButton(), 3, 2, 1, 1) } func (m *filamentPanel) updateTemperatures() { @@ -87,7 +83,6 @@ func (m *filamentPanel) loadTemperatureState(s *octoprint.TemperatureState) { func (m *filamentPanel) addNewTool(tool string) { m.labels[tool] = MustLabelWithImage("extruder.svg", "") m.box.Add(m.labels[tool]) - m.tool.AddStep(Step{strings.Title(tool), tool}) Logger.Infof("New tool detected %s", tool) } @@ -105,38 +100,6 @@ func (m *filamentPanel) loadTemperatureData(tool string, d *octoprint.Temperatur m.labels[tool].ShowAll() } -func (m *filamentPanel) createToolButton() *StepButton { - m.tool = MustStepButton("extruder.svg") - m.tool.Callback = func() { - cmd := &octoprint.ToolSelectRequest{} - cmd.Tool = m.tool.Value().(string) - - Logger.Infof("Changing tool to %s", cmd.Tool) - if err := cmd.Do(m.UI.Printer); err != nil { - Logger.Error(err) - return - } - } - - return m.tool -} - -func (m *filamentPanel) createFlowrateButton() *StepButton { - b := MustStepButton("speed-step.svg", Step{"Slow", 75}, Step{"Normal", 100}, Step{"High", 125}) - b.Callback = func() { - cmd := &octoprint.ToolFlowrateRequest{} - cmd.Factor = b.Value().(int) - - Logger.Infof("Changing flowrate to %d%%", cmd.Factor) - if err := cmd.Do(m.UI.Printer); err != nil { - Logger.Error(err) - return - } - } - - return b -} - func (m *filamentPanel) createLoadButton() gtk.IWidget { length := 750.0 @@ -144,7 +107,7 @@ func (m *filamentPanel) createLoadButton() gtk.IWidget { length = m.UI.Settings.FilamentInLength } - return MustButtonImage("Load", "extrude.svg", func() { + return MustButtonImageStyle("Load", "extrude.svg", "color3", func() { cmd := &octoprint.CommandRequest{} cmd.Commands = []string{ "G91", @@ -162,14 +125,13 @@ func (m *filamentPanel) createLoadButton() gtk.IWidget { } func (m *filamentPanel) createUnloadButton() gtk.IWidget { - length := 800.0 if m.UI.Settings != nil { length = m.UI.Settings.FilamentOutLength } - return MustButtonImage("Unload", "retract.svg", func() { + return MustButtonImageStyle("Unload", "extrude.svg", "color2", func() { cmd := &octoprint.CommandRequest{} cmd.Commands = []string{ "G91", @@ -185,16 +147,15 @@ func (m *filamentPanel) createUnloadButton() gtk.IWidget { }) } -func (m *filamentPanel) createExtrudeButton(label, image string, dir int) gtk.IWidget { - - return MustPressedButton(label, image, func() { - cmd := &octoprint.ToolExtrudeRequest{} - cmd.Amount = m.amount.Value().(int) * dir +func (m *filamentPanel) createChangeToolButton(num int) gtk.IWidget { + style := fmt.Sprintf("color%d", num+1) + name := fmt.Sprintf("Tool%d", num+1) + gcode := fmt.Sprintf("T%d", num) + return MustButtonImageStyle(name, "extruder.svg", style, func() { + m.command(gcode) + }) +} - Logger.Infof("Sending extrude request, with amount %d", cmd.Amount) - if err := cmd.Do(m.UI.Printer); err != nil { - Logger.Error(err) - return - } - }, 200) +func (m *filamentPanel) showTemperature() { + m.UI.Add(TemperaturePanel(m.UI, m)) } diff --git a/ui/idle_action_menu.go b/ui/idle_action_menu.go new file mode 100644 index 00000000..728dc004 --- /dev/null +++ b/ui/idle_action_menu.go @@ -0,0 +1,61 @@ +package ui + +import "github.com/gotk3/gotk3/gtk" + +var idleActionMenuPanelInstance *idleActionMenuPanel + +type idleActionMenuPanel struct { + CommonPanel +} + +func IdleActionMenuPanel(ui *UI, parent Panel) Panel { + if idleActionMenuPanelInstance == nil { + m := &idleActionMenuPanel{CommonPanel: NewCommonPanel(ui, parent)} + m.initialize() + idleActionMenuPanelInstance = m + } + + return idleActionMenuPanelInstance +} + +func (m *idleActionMenuPanel) initialize() { + defer m.Initialize() + + var buttons = []gtk.IWidget{ + MustButtonImageStyle("Move", "move.svg", "color1", m.showMove), + MustButtonImageStyle("Extrude", "filament.svg", "color1", m.showExtrude), + MustButtonImageStyle("Fan", "fan.svg", "color2", m.showFan), + MustButtonImageStyle("Temperature", "heat-up.svg", "color4", m.showTemperature), + MustButtonImageStyle("Control", "control.svg", "color4", m.showControl), + } + + if m.UI.Settings != nil && m.UI.Settings.ToolChanger { + buttons = append(buttons, MustButtonImageStyle("ToolChanger", "toolchanger.svg", "color2", m.showToolchanger)) + } + + m.arrangeButtons(buttons) +} + +func (m *idleActionMenuPanel) showTemperature() { + m.UI.Add(TemperaturePanel(m.UI, m)) +} + +func (m *idleActionMenuPanel) showExtrude() { + m.UI.Add(ExtrudePanel(m.UI, m)) +} + +func (m *idleActionMenuPanel) showControl() { + m.UI.Add(ControlPanel(m.UI, m)) +} + +func (m *idleActionMenuPanel) showToolchanger() { + m.UI.Add(ToolchangerPanel(m.UI, m)) +} + +func (m *idleActionMenuPanel) showMove() { + m.UI.Add(MovePanel(m.UI, m)) +} + +func (m *idleActionMenuPanel) showFan() { + m.UI.Add(FanPanel(m.UI, m)) +} diff --git a/ui/idle_configuration_menu.go b/ui/idle_configuration_menu.go new file mode 100644 index 00000000..7933712e --- /dev/null +++ b/ui/idle_configuration_menu.go @@ -0,0 +1,48 @@ +package ui + +import "github.com/gotk3/gotk3/gtk" + +var idleConfigurationMenuPanelInstance *idleConfigurationMenuPanel + +type idleConfigurationMenuPanel struct { + CommonPanel +} + +func IdleConfigurationMenuPanel(ui *UI, parent Panel) Panel { + if idleConfigurationMenuPanelInstance == nil { + m := &idleConfigurationMenuPanel{CommonPanel: NewCommonPanel(ui, parent)} + m.initialize() + idleConfigurationMenuPanelInstance = m + } + + return idleConfigurationMenuPanelInstance +} + +func (m *idleConfigurationMenuPanel) initialize() { + defer m.Initialize() + + var buttons = []gtk.IWidget{ + MustButtonImageStyle("Bed Level", "bed-level.svg", "color4", m.showCalibrate), + MustButtonImageStyle("ZOffsets", "z-offset-increase.svg", "color2", m.showNozzleCalibration), + MustButtonImageStyle("Network", "network.svg", "color1", m.showNetwork), + MustButtonImageStyle("System", "info.svg", "color3", m.showSystem), + } + + m.arrangeButtons(buttons) +} + +func (m *idleConfigurationMenuPanel) showNetwork() { + m.UI.Add(NetworkPanel(m.UI, m)) +} + +func (m *idleConfigurationMenuPanel) showSystem() { + m.UI.Add(SystemPanel(m.UI, m)) +} + +func (m *idleConfigurationMenuPanel) showCalibrate() { + m.UI.Add(BedLevelPanel(m.UI, m)) +} + +func (m *idleConfigurationMenuPanel) showNozzleCalibration() { + m.UI.Add(NozzleCalibrationPanel(m.UI, m)) +} diff --git a/ui/idle_menu.go b/ui/idle_menu.go index 72b14d97..47f17522 100644 --- a/ui/idle_menu.go +++ b/ui/idle_menu.go @@ -20,12 +20,17 @@ func (m *idleMenuPanel) initialize() { defer m.Initialize() m.Grid().Attach(MustButtonImageStyle("Move", "move.svg", "color1", m.showMove), 1, 0, 1, 1) - m.Grid().Attach(MustButtonImageStyle("ToolChanger", "toolchanger.svg", "color2", m.showToolchanger), 2, 0, 1, 1) + + m.Grid().Attach(MustButtonImageStyle("Fan", "fan.svg", "color2", m.showFan), 2, 0, 1, 1) + m.Grid().Attach(MustButtonImageStyle("Control", "control.svg", "color4", m.showControl), 3, 0, 1, 1) m.Grid().Attach(MustButtonImageStyle("System", "info.svg", "color3", m.showSystem), 4, 0, 1, 1) m.Grid().Attach(MustButtonImageStyle("Temperature", "heat-up.svg", "color4", m.showTemperature), 1, 1, 1, 1) m.Grid().Attach(MustButtonImageStyle("Network", "network.svg", "color1", m.showNetwork), 2, 1, 1, 1) - m.Grid().Attach(MustButtonImageStyle("Fan", "fan.svg", "color2", m.showFan), 3, 1, 1, 1) + + if m.UI.Settings != nil && m.UI.Settings.ToolChanger { + m.Grid().Attach(MustButtonImageStyle("ToolChanger", "toolchanger.svg", "color2", m.showToolchanger), 3, 1, 1, 1) + } } func (m *idleMenuPanel) showTemperature() { diff --git a/ui/idle_status.go b/ui/idle_status.go index 0842c66b..157a3a69 100644 --- a/ui/idle_status.go +++ b/ui/idle_status.go @@ -37,20 +37,20 @@ func (m *idleStatusPanel) initialize() { defer m.Initialize() m.Grid().Attach(MustButtonImageStyle("Home", "home.svg", "color2", m.showHome), 3, 0, 1, 1) - m.Grid().Attach(MustButtonImageStyle("Bed Level", "bed-level.svg", "color4", m.showCalibrate), 4, 0, 1, 1) + m.Grid().Attach(MustButtonImageStyle("Actions", "actions.svg", "color4", m.showActionsMenu), 4, 0, 1, 1) m.Grid().Attach(MustButtonImageStyle("Filament", "filament.svg", "color3", m.showFilament), 3, 1, 1, 1) - m.Grid().Attach(MustButtonImageStyle("Menu", "control.svg", "color1", m.showMenu), 4, 1, 1, 1) + m.Grid().Attach(MustButtonImageStyle("Configuration", "control.svg", "color1", m.showConfigurationMenu), 4, 1, 1, 1) m.Grid().Attach(MustButtonImageStyle("Print", "print.svg", "color2", m.showFiles), 3, 2, 2, 1) m.showTools() } -func (m *idleStatusPanel) showCalibrate() { - m.UI.Add(BedLevelPanel(m.UI, m)) +func (m *idleStatusPanel) showActionsMenu() { + m.UI.Add(IdleActionMenuPanel(m.UI, m)) } -func (m *idleStatusPanel) showMenu() { - m.UI.Add(IdleMenuPanel(m.UI, m)) +func (m *idleStatusPanel) showConfigurationMenu() { + m.UI.Add(IdleConfigurationMenuPanel(m.UI, m)) } func (m *idleStatusPanel) showHome() { diff --git a/ui/nozzle_calibration.go b/ui/nozzle_calibration.go new file mode 100644 index 00000000..d0cbc968 --- /dev/null +++ b/ui/nozzle_calibration.go @@ -0,0 +1,188 @@ +package ui + +import ( + "fmt" + "math" + "time" + + "github.com/gotk3/gotk3/gtk" + "github.com/mcuadros/go-octoprint" +) + +var nozzleCalibrationPanelInstance *nozzleCalibrationPanel + +type pointCoordinates struct { + x float64 + y float64 + z float64 +} + +type nozzleCalibrationPanel struct { + CommonPanel + zCalibrationMode bool + activeTool int + cPoint pointCoordinates + zOffset float64 + labZOffsetLabel *gtk.Label +} + +func NozzleCalibrationPanel(ui *UI, parent Panel) Panel { + if nozzleCalibrationPanelInstance == nil { + m := &nozzleCalibrationPanel{CommonPanel: NewCommonPanel(ui, parent)} + m.panelH = 3 + m.cPoint = pointCoordinates{x: 20, y: 20, z: 0} + m.initialize() + + nozzleCalibrationPanelInstance = m + } + + return nozzleCalibrationPanelInstance +} + +func (m *nozzleCalibrationPanel) initialize() { + defer m.Initialize() + m.Grid().Attach(m.createChangeToolButton(0), 1, 0, 1, 1) + m.Grid().Attach(m.createChangeToolButton(1), 2, 0, 1, 1) + m.Grid().Attach(m.createChangeToolButton(2), 3, 0, 1, 1) + m.Grid().Attach(m.createChangeToolButton(3), 4, 0, 1, 1) + + m.Grid().Attach(m.createIncreaseOffsetButton(), 1, 1, 1, 1) + m.Grid().Attach(m.createZOffsetLabel(), 2, 1, 2, 1) + m.Grid().Attach(m.createDecreaseOffsetButton(), 4, 1, 1, 1) + + m.Grid().Attach(m.createZCalibrationModeButton(), 1, 2, 1, 1) + m.Grid().Attach(m.createAutoZCalibrationButton(), 2, 2, 2, 1) + +} + +func (m *nozzleCalibrationPanel) createZCalibrationModeButton() gtk.IWidget { + b := MustStepButton("z-calibration.svg", Step{"Start Manual\nCalibration", false}, Step{"Stop Manual\nCalibration", true}) + ctx, _ := b.GetStyleContext() + ctx.AddClass("color2") + + b.Callback = func() { + m.zCalibrationMode = b.Value().(bool) + if m.zCalibrationMode == true { + ctx.AddClass("active") + + m.command("G28") + m.command("T0") + time.Sleep(time.Second * 1) + m.command(fmt.Sprintf("G0 X%f Y%f F10000", m.cPoint.x, m.cPoint.y)) + m.command(fmt.Sprintf("G0 Z10 F2000")) + m.command(fmt.Sprintf("G0 Z%f F400", m.cPoint.z)) + + m.activeTool = 0 + m.updateZOffset(0) + } else { + ctx.RemoveClass("active") + m.labZOffsetLabel.SetText("Press \"Z Offset\"\nbutton to start\nZ-Offset calibration") + } + } + + return b +} + +func (m *nozzleCalibrationPanel) createAutoZCalibrationButton() gtk.IWidget { + return MustButtonImageStyle("Auto Z Calibration", "z-calibration.svg", "color3", func() { + if m.zCalibrationMode { + return + } + + cmd := &octoprint.RunZOffsetCalibrationRequest{} + if err := cmd.Do(m.UI.Printer); err != nil { + Logger.Error(err) + } + }) +} + +func (m *nozzleCalibrationPanel) createIncreaseOffsetButton() gtk.IWidget { + return MustButtonImage("Bed Down", "z-offset-increase.svg", func() { + if !m.zCalibrationMode { + return + } + m.updateZOffset(m.zOffset + 0.02) + }) +} + +func (m *nozzleCalibrationPanel) createDecreaseOffsetButton() gtk.IWidget { + return MustButtonImage("Bed Up", "z-offset-decrease.svg", func() { + if !m.zCalibrationMode { + return + } + m.updateZOffset(m.zOffset - 0.02) + }) +} + +func (m *nozzleCalibrationPanel) updateZOffset(v float64) { + m.zOffset = toFixed(v, 4) + + m.labZOffsetLabel.SetText(fmt.Sprintf("Z-Offset: %.2f", m.zOffset)) + + cmd := &octoprint.CommandRequest{} + cmd.Commands = []string{ + fmt.Sprintf("SET_GCODE_OFFSET Z=%f", m.zOffset), + "G0 Z0 F100", + } + if err := cmd.Do(m.UI.Printer); err != nil { + Logger.Error(err) + } + + cmd2 := &octoprint.SetZOffsetRequest{Value: m.zOffset, Tool: m.activeTool} + if err := cmd2.Do(m.UI.Printer); err != nil { + Logger.Error(err) + } +} + +func (m *nozzleCalibrationPanel) createChangeToolButton(num int) gtk.IWidget { + style := fmt.Sprintf("color%d", num+1) + name := fmt.Sprintf("Tool%d", num+1) + gcode := fmt.Sprintf("T%d", num) + return MustButtonImageStyle(name, "extruder.svg", style, func() { + if m.zCalibrationMode { + m.activeTool = num + m.command(fmt.Sprintf("G0 Z%f", 5.0)) + m.command(gcode) + time.Sleep(time.Second * 1) + m.command(fmt.Sprintf("G0 X%f Y%f F10000", m.cPoint.x, m.cPoint.y)) + + cmd := &octoprint.GetZOffsetRequest{Tool: m.activeTool} + response, err := cmd.Do(m.UI.Printer) + + if err != nil { + Logger.Error(err) + return + } + + m.updateZOffset(response.Offset) + + } else { + m.command(gcode) + } + }) +} + +func (m *nozzleCalibrationPanel) createZOffsetLabel() gtk.IWidget { + m.labZOffsetLabel = MustLabel("---") + m.labZOffsetLabel.SetVAlign(gtk.ALIGN_CENTER) + m.labZOffsetLabel.SetHAlign(gtk.ALIGN_CENTER) + m.labZOffsetLabel.SetVExpand(true) + m.labZOffsetLabel.SetHExpand(true) + m.labZOffsetLabel.SetLineWrap(true) + return m.labZOffsetLabel +} + +func (m *nozzleCalibrationPanel) command(gcode string) error { + cmd := &octoprint.CommandRequest{} + cmd.Commands = []string{gcode} + return cmd.Do(m.UI.Printer) +} + +func round(num float64) int { + return int(num + math.Copysign(0.5, num)) +} + +func toFixed(num float64, precision int) float64 { + output := math.Pow(10, float64(precision)) + return float64(round(num*output)) / output +} diff --git a/ui/print_status.go b/ui/print_status.go index d9fcd808..81e39233 100644 --- a/ui/print_status.go +++ b/ui/print_status.go @@ -2,6 +2,7 @@ package ui import ( "fmt" + "strings" "time" "github.com/gotk3/gotk3/gtk" @@ -16,7 +17,7 @@ type printStatusPanel struct { pb *gtk.ProgressBar bed, tool0, tool1, tool2, tool3 *gtk.Button - file, time, time_left *LabelWithImage + file, time, timeLeft *LabelWithImage complete, pause, stop, menu *gtk.Button } @@ -54,7 +55,7 @@ func (m *printStatusPanel) showTools() { m.tool2 = m.createToolButton(2) m.tool3 = m.createToolButton(3) - m.bed = MustButtonImage("", "bed.svg", func() {}) + m.bed = m.createBedButton() switch toolsCount { case 1: @@ -104,9 +105,15 @@ func (m *printStatusPanel) createProgressBar() *gtk.ProgressBar { func (m *printStatusPanel) createInfoBox() *gtk.Box { m.file = MustLabelWithImage("file.svg", "") + ctx, _ := m.file.GetStyleContext() + ctx.AddClass("printing-status-label") + m.time = MustLabelWithImage("speed-step.svg", "") + ctx, _ = m.time.GetStyleContext() + ctx.AddClass("printing-status-label") - ctx, _ := m.time.GetStyleContext() + m.timeLeft = MustLabelWithImage("speed-step.svg", "") + ctx, _ = m.timeLeft.GetStyleContext() ctx.AddClass("printing-status-label") info := MustBox(gtk.ORIENTATION_VERTICAL, 5) @@ -116,6 +123,7 @@ func (m *printStatusPanel) createInfoBox() *gtk.Box { info.SetVAlign(gtk.ALIGN_CENTER) info.Add(m.file) info.Add(m.time) + info.Add(m.timeLeft) return info } @@ -123,6 +131,17 @@ func (m *printStatusPanel) createInfoBox() *gtk.Box { func (m *printStatusPanel) createToolButton(num int) *gtk.Button { name := fmt.Sprintf("extruder-%d.svg", num+1) b := MustButtonImage("", name, func() {}) + + ctx, _ := b.GetStyleContext() + ctx.AddClass("printing-state") + return b +} + +func (m *printStatusPanel) createBedButton() *gtk.Button { + b := MustButtonImage("", "bed.svg", func() {}) + + ctx, _ := b.GetStyleContext() + ctx.AddClass("printing-state") return b } @@ -238,26 +257,32 @@ func (m *printStatusPanel) updateJob() { file := "not-set" if s.Job.File.Name != "" { - file = strEllipsis(s.Job.File.Name) + file = s.Job.File.Name + file = strings.Replace(file, ".gcode", "", -1) + file = strEllipsisLen(file, 35) } m.file.Label.SetLabel(file) m.pb.SetFraction(s.Progress.Completion / 100) - var text string + var timeSpent, timeLeft string switch s.Progress.Completion { case 100: - text = fmt.Sprintf("Completed in %s", time.Duration(int64(s.Job.LastPrintTime)*1e9)) + timeSpent = fmt.Sprintf("Completed in %s", time.Duration(int64(s.Job.LastPrintTime)*1e9)) + timeLeft = "" case 0: - text = "Warming up ..." + timeSpent = "Warming up ..." + timeLeft = "" default: Logger.Info(s.Progress.PrintTime) e := time.Duration(int64(s.Progress.PrintTime) * 1e9) r := time.Duration(int64(s.Progress.PrintTimeLeft) * 1e9) - text = fmt.Sprintf("Time: %s\nTime Left: %s", e, r) + timeSpent = fmt.Sprintf("Time: %s", e) + timeLeft = fmt.Sprintf("Left: %s", r) } - m.time.Label.SetLabel(text) + m.time.Label.SetLabel(timeSpent) + m.timeLeft.Label.SetLabel(timeLeft) } func (m *printStatusPanel) defineToolsCount() int { diff --git a/ui/temperature.go b/ui/temperature.go index 81c8c2ee..2b9a89a5 100644 --- a/ui/temperature.go +++ b/ui/temperature.go @@ -48,13 +48,13 @@ func (m *temperaturePanel) initialize() { m.box.SetVAlign(gtk.ALIGN_CENTER) m.box.SetHAlign(gtk.ALIGN_CENTER) - m.Grid().Attach(m.box, 2, 0, 2, 1) + m.Grid().Attach(m.box, 2, 1, 2, 1) m.Grid().Attach(m.createToolButton(), 1, 1, 1, 1) m.amount = MustStepButton("move-step.svg", Step{"10°C", 10.}, Step{"5°C", 5.}, Step{"1°C", 1.}) - m.Grid().Attach(m.amount, 2, 1, 1, 1) + m.Grid().Attach(m.amount, 2, 0, 1, 1) - m.Grid().Attach(MustButtonImage("More", "heat-up.svg", m.profilePanel), 3, 1, 1, 1) + m.Grid().Attach(MustButtonImage("More", "heat-up.svg", m.profilePanel), 3, 0, 1, 1) } func (m *temperaturePanel) createToolButton() *StepButton { diff --git a/ui/toolchanger.go b/ui/toolchanger.go index 8cba07da..1ecfd1d1 100644 --- a/ui/toolchanger.go +++ b/ui/toolchanger.go @@ -2,7 +2,6 @@ package ui import ( "fmt" - "time" "github.com/gotk3/gotk3/gtk" "github.com/mcuadros/go-octoprint" @@ -10,26 +9,15 @@ import ( var toolchangerPanelInstance *toolchangerPanel -type pointCoordinates struct { - x float64 - y float64 - z float64 -} - type toolchangerPanel struct { CommonPanel - zCalibrationMode bool - activeTool int - cPoint pointCoordinates - zOffset float64 - labZOffsetLabel *gtk.Label + activeTool int } func ToolchangerPanel(ui *UI, parent Panel) Panel { if toolchangerPanelInstance == nil { m := &toolchangerPanel{CommonPanel: NewCommonPanel(ui, parent)} m.panelH = 3 - m.cPoint = pointCoordinates{x: 20, y: 20, z: 0} m.initialize() toolchangerPanelInstance = m @@ -46,39 +34,16 @@ func (m *toolchangerPanel) initialize() { m.Grid().Attach(m.createChangeToolButton(3), 4, 0, 1, 1) m.Grid().Attach(m.createHomeButton(), 1, 1, 1, 1) - m.Grid().Attach(m.createIncreaseOffsetButton(), 2, 1, 1, 1) - m.Grid().Attach(m.createZOffsetLabel(), 3, 1, 1, 1) - m.Grid().Attach(m.createDecreaseOffsetButton(), 4, 1, 1, 1) - m.Grid().Attach(m.createMagnetOnButton(), 1, 2, 1, 1) - m.Grid().Attach(m.createMagnetOffButton(), 2, 2, 1, 1) - m.Grid().Attach(m.createZCalibrationModeButton(), 3, 2, 1, 1) + m.Grid().Attach(m.createMagnetOnButton(), 3, 1, 1, 1) + m.Grid().Attach(m.createMagnetOffButton(), 4, 1, 1, 1) + m.Grid().Attach(m.createZCalibrationButton(), 2, 2, 1, 1) } -func (m *toolchangerPanel) createZCalibrationModeButton() gtk.IWidget { - b := MustStepButton("z-calibration.svg", Step{"Z Offset", false}, Step{"Z Offset", true}) - ctx, _ := b.GetStyleContext() - ctx.AddClass("color2") - - b.Callback = func() { - m.zCalibrationMode = b.Value().(bool) - if m.zCalibrationMode == true { - ctx.AddClass("active") - - m.command("G28") - m.command("T0") - time.Sleep(time.Second * 1) - m.command(fmt.Sprintf("G0 X%f Y%f F10000", m.cPoint.x, m.cPoint.y)) - m.command(fmt.Sprintf("G0 Z10 F2000")) - m.command(fmt.Sprintf("G0 Z%f F400", m.cPoint.z)) - - m.activeTool = 0 - m.updateZOffset(0) - } else { - ctx.RemoveClass("active") - m.labZOffsetLabel.SetText("Press \"Z Offset\"\nbutton to start\nZ-Offset calibration") - } - } +func (m *toolchangerPanel) createZCalibrationButton() gtk.IWidget { + b := MustButtonImageStyle("Z Offsets", "z-calibration.svg", "color2", func() { + m.UI.Add(NozzleCalibrationPanel(m.UI, m)) + }) return b } @@ -97,69 +62,12 @@ func (m *toolchangerPanel) createHomeButton() gtk.IWidget { }) } -func (m *toolchangerPanel) createIncreaseOffsetButton() gtk.IWidget { - return MustButtonImage("Bed Down", "z-offset-increase.svg", func() { - if !m.zCalibrationMode { - return - } - m.updateZOffset(m.zOffset + 0.02) - }) -} - -func (m *toolchangerPanel) createDecreaseOffsetButton() gtk.IWidget { - return MustButtonImage("Bed Up", "z-offset-decrease.svg", func() { - if !m.zCalibrationMode { - return - } - m.updateZOffset(m.zOffset - 0.02) - }) -} - -func (m *toolchangerPanel) updateZOffset(v float64) { - m.zOffset = v - - m.labZOffsetLabel.SetText(fmt.Sprintf("Z-Offset: %.2f", m.zOffset)) - - cmd := &octoprint.CommandRequest{} - cmd.Commands = []string{ - fmt.Sprintf("SET_GCODE_OFFSET Z=%f", m.zOffset), - "G0 Z0 F100", - } - if err := cmd.Do(m.UI.Printer); err != nil { - Logger.Error(err) - } - - cmd2 := &octoprint.SetZOffsetRequest{Value: m.zOffset, Tool: m.activeTool} - if err := cmd2.Do(m.UI.Printer); err != nil { - Logger.Error(err) - } -} - func (m *toolchangerPanel) createChangeToolButton(num int) gtk.IWidget { style := fmt.Sprintf("color%d", num+1) name := fmt.Sprintf("Tool%d", num+1) gcode := fmt.Sprintf("T%d", num) return MustButtonImageStyle(name, "extruder.svg", style, func() { - if m.zCalibrationMode { - m.activeTool = num - m.command(fmt.Sprintf("G0 Z%f", 5.0)) - m.command(gcode) - time.Sleep(time.Second * 1) - m.command(fmt.Sprintf("G0 X%f Y%f F10000", m.cPoint.x, m.cPoint.y)) - - cmd := &octoprint.GetZOffsetRequest{Tool: m.activeTool} - response, err := cmd.Do(m.UI.Printer) - - if err != nil { - Logger.Error(err) - return - } - - m.updateZOffset(response.Offset) - - } else { - m.command(gcode) - } + m.command(gcode) }) } @@ -188,19 +96,3 @@ func (m *toolchangerPanel) createMagnetOffButton() gtk.IWidget { } }) } - -func (m *toolchangerPanel) createZOffsetLabel() gtk.IWidget { - m.labZOffsetLabel = MustLabel("Press \"Z Offset\"\nbutton to start\nZ-Offset calibration") - m.labZOffsetLabel.SetVAlign(gtk.ALIGN_CENTER) - m.labZOffsetLabel.SetHAlign(gtk.ALIGN_CENTER) - m.labZOffsetLabel.SetVExpand(true) - m.labZOffsetLabel.SetHExpand(true) - m.labZOffsetLabel.SetLineWrap(true) - return m.labZOffsetLabel -} - -func (m *toolchangerPanel) command(gcode string) error { - cmd := &octoprint.CommandRequest{} - cmd.Commands = []string{gcode} - return cmd.Do(m.UI.Printer) -} diff --git a/ui/ui.go b/ui/ui.go index 8ff2a327..13bd8901 100644 --- a/ui/ui.go +++ b/ui/ui.go @@ -123,7 +123,7 @@ func (ui *UI) verifyConnection() { ui.sdNotify("WATCHDOG=1") newUiState := "splash" - splashMessage := "Initializing printer..." + splashMessage := "Loading..." s, err := (&octoprint.ConnectionRequest{}).Do(ui.Printer) if err == nil { diff --git a/vendor/github.com/mcuadros/go-octoprint/zbolt.go b/vendor/github.com/mcuadros/go-octoprint/zbolt.go index 0f4abee5..e23bf67f 100644 --- a/vendor/github.com/mcuadros/go-octoprint/zbolt.go +++ b/vendor/github.com/mcuadros/go-octoprint/zbolt.go @@ -8,6 +8,22 @@ import ( const URIZBoltRequest = "/api/plugin/zbolt" const URIZBoltOctoScreenRequest = "/api/plugin/zbolt_octoscreen" +type RunZOffsetCalibrationRequest struct { + Command string `json:"command"` +} + +func (cmd *RunZOffsetCalibrationRequest) Do(c *Client) error { + cmd.Command = "run_zoffset_calibration" + + b := bytes.NewBuffer(nil) + if err := json.NewEncoder(b).Encode(cmd); err != nil { + return err + } + + _, err := c.doJSONRequest("POST", URIZBoltRequest, b, ConnectionErrors) + return err +} + // SettingsRequest retrieves the current configuration of OctoPrint. type SetZOffsetRequest struct { Command string `json:"command"` @@ -94,6 +110,7 @@ type GetSettingsResponse struct { // Job contains information regarding the target of the current print job. FilamentInLength float64 `json:"filament_in_length"` FilamentOutLength float64 `json:"filament_out_length"` + ToolChanger bool `json:"toolchanger"` GCodes struct { AutoBedLevel string `json:"auto_bed_level"` } `json:"gcodes"`