diff --git a/.gitignore b/.gitignore
index 31899a0..2642ee7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
build
debian/changelog
+pkg/
diff --git a/Makefile b/Makefile
index f91dbc2..0f574ad 100644
--- a/Makefile
+++ b/Makefile
@@ -15,7 +15,7 @@ WORKDIR := $(shell pwd)
BUILD_PATH := $(WORKDIR)/build
DOCKER_IMAGE_BUILD = mcuadros/octoprint-tft-build
-DEBIAN_PACKAGES = JESSIE STRETCH
+DEBIAN_PACKAGES = STRETCH
STRETCH_NAME := stretch
STRETCH_IMAGE := golang:1.9-stretch
STRETCH_GO_TAGS := gtk_3_22
@@ -26,15 +26,15 @@ JESSIE_GO_TAGS := gtk_3_14
# Build information
-GIT_COMMIT = $(shell git rev-parse HEAD | cut -c1-7)
-DEV_PREFIX := 0.0
-VERSION ?= $(DEV_PREFIX)~git$(GIT_COMMIT)
+#GIT_COMMIT = $(shell git rev-parse HEAD | cut -c1-7)
+#DEV_PREFIX := 1.0
+VERSION := 1.3
BUILD_DATE ?= $(shell date --utc +%Y%m%d-%H:%M:%S)
-BRANCH = $(shell git rev-parse --abbrev-ref HEAD)
+#BRANCH = $(shell git rev-parse --abbrev-ref HEAD)
-ifneq ($(BRANCH), master)
- VERSION := $(shell echo $(BRANCH)| sed -e 's/v//g')
-endif
+#ifneq ($(BRANCH), master)
+# VERSION := $(shell echo $(BRANCH)| sed -e 's/v//g')
+#endif
# Package information
PACKAGE_NAME = octoprint-tft
@@ -66,7 +66,7 @@ build-internal: prepare-internal
cp ../*.deb /build/;
prepare-internal:
- dch --create -v $(VERSION)-1 --package $(PACKAGE_NAME) empty; \
+ dch --create -v $(VERSION) --package $(PACKAGE_NAME) empty; \
cd $(WORKDIR)/..; \
tar -czf octoprint-tft_$(VERSION).orig.tar.gz --exclude-vcs OctoPrint-TFT
diff --git a/README.md b/README.md
index 131387a..693ebe6 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-OctoPrint-TFT [](https://github.com/mcuadros/OctoPrint-TFT/releases) []()
+OctoPrint-TFT [](https://github.com/Z-Bolt/OctoPrint-TFT/releases) []()
=============
_OctoPrint-TFT_, a touch interface for TFT touch modules based on GTK+3.
diff --git a/debian/local/disablescreenblank.sh b/debian/local/disablescreenblank.sh
new file mode 100644
index 0000000..d52f01f
--- /dev/null
+++ b/debian/local/disablescreenblank.sh
@@ -0,0 +1,10 @@
+#!/usr/bin/env bash
+
+screen=${1:-0}
+
+# wait 10s for the display manager service to start and attach to screen
+sleep 10
+
+/usr/bin/xset -display :$screen s off # deactivate screen saver
+/usr/bin/xset -display :$screen -dpms # disable DPMS
+/usr/bin/xset -display :$screen s noblank # disable screen blanking
\ No newline at end of file
diff --git a/debian/local/octoprint-tft-environment b/debian/local/octoprint-tft-environment
index e5c386c..6de059c 100644
--- a/debian/local/octoprint-tft-environment
+++ b/debian/local/octoprint-tft-environment
@@ -19,3 +19,6 @@ OCTOPRINT_TFT_STYLE_PATH=/opt/octoprint-tft/styles/default/
# Resolution of the application, should be configured to the resolution of your
# screen, for example 800x480. By default 480x320.
OCTOPRINT_TFT_RESOLUTION=
+
+# Location of file for logging (Optional)
+OCTOPRINT_TFT_LOG_FILE=
diff --git a/debian/octoprint-tft.install b/debian/octoprint-tft.install
index 615c5c9..0837585 100644
--- a/debian/octoprint-tft.install
+++ b/debian/octoprint-tft.install
@@ -1,2 +1,3 @@
debian/local/octoprint-tft-environment etc
debian/local/insserv.conf.d etc
+debian/local/disablescreenblank.sh etc
\ No newline at end of file
diff --git a/debian/octoprint-tft.postinst b/debian/octoprint-tft.postinst
index 082bb47..669589d 100755
--- a/debian/octoprint-tft.postinst
+++ b/debian/octoprint-tft.postinst
@@ -35,6 +35,7 @@ if [ "$1" = configure ] && [ -d /etc/systemd/system/ ]; then
echo "Display manager service is masked" >&2
elif [ -e "$SERVICE" ]; then
ln -sf "$SERVICE" "$DEFAULT_SERVICE"
+ chmod +x /etc/disablescreenblank.sh
else
echo "WARNING: $SERVICE is the selected default display manager but does not exist" >&2
rm -f "$DEFAULT_SERVICE"
diff --git a/debian/octoprint-tft.service b/debian/octoprint-tft.service
index c4f43fa..c992c47 100644
--- a/debian/octoprint-tft.service
+++ b/debian/octoprint-tft.service
@@ -4,13 +4,14 @@ Conflicts=getty@tty7.service
After=systemd-user-sessions.service getty@tty7.service plymouth-quit.service
[Service]
+Type=notify
+NotifyAccess=all
EnvironmentFile=/etc/octoprint-tft-environment
ExecStart=/usr/bin/xinit /usr/bin/OctoPrint-TFT -- :0 -nolisten tcp -nocursor
+ExecStartPost=/etc/disablescreenblank.sh 0
StandardOutput=journal
Restart=always
-RestartSec=1s
-TimeoutStopSec=5s
-IgnoreSIGPIPE=no
+WatchdogSec=10s
[Install]
WantedBy=graphical.target
diff --git a/main.go b/main.go
index c51de09..742c9d2 100644
--- a/main.go
+++ b/main.go
@@ -9,9 +9,8 @@ import (
"strconv"
"strings"
- "github.com/mcuadros/OctoPrint-TFT/ui"
-
"github.com/gotk3/gotk3/gtk"
+ "github.com/mcuadros/OctoPrint-TFT/ui"
"gopkg.in/yaml.v1"
)
@@ -61,6 +60,7 @@ func main() {
gtk.Init(nil)
settings, _ := gtk.SettingsGetDefault()
+
settings.SetProperty("gtk-application-prefer-dark-theme", true)
width, height := getSize()
diff --git a/styles/default/images/logo-white.svg b/styles/default/images/logo-white.svg
new file mode 100644
index 0000000..1bd4d0b
--- /dev/null
+++ b/styles/default/images/logo-white.svg
@@ -0,0 +1,12 @@
+
+
\ No newline at end of file
diff --git a/styles/default/images/open.svg b/styles/default/images/open.svg
new file mode 100644
index 0000000..7e5b3c8
--- /dev/null
+++ b/styles/default/images/open.svg
@@ -0,0 +1,11 @@
+
+
\ No newline at end of file
diff --git a/styles/default/style.css b/styles/default/style.css
index c847e9e..78643ee 100644
--- a/styles/default/style.css
+++ b/styles/default/style.css
@@ -1,3 +1,4 @@
+
.dialog { border: 2px solid black; }
.notification {
@@ -14,3 +15,47 @@
.error {
background-color:rgba(204, 30, 30, 0.7);
}
+
+scrollbar, scrollbar button {
+ border: none;
+ background-color: #000;
+}
+
+window {
+ background-color: #000;
+}
+
+scrollbar slider {
+ /* -GtkScrollbar-has-backward-stepper: true; */
+ /* -GtkScrollbar-has-forward-stepper: true; */
+ min-width: 52px;
+ border-radius: 8px;
+}
+
+progress, trough {
+ min-height: 20px;
+}
+
+
+
+/* GtkWindow {
+ background-color: green;
+ border-width: 3px;
+ border-color: blue;
+} */
+
+/* GtkButton {
+ background-image: none;
+ background-color:#1010FF;
+ margin:2px;
+ border-radius:0;
+} */
+
+
+/* button, entry {
+ color: #ff00ea;
+ font: 12px "Comic Sans";
+ background-color: #1010FF;
+ } */
+
+
diff --git a/ui/common.go b/ui/common.go
index c0f4dc7..b67e6e2 100644
--- a/ui/common.go
+++ b/ui/common.go
@@ -16,9 +16,6 @@ import (
var Version = "0.1.x"
var Build = "no-set"
-const panelW = 4
-const panelH = 2
-
type Panel interface {
Grid() *gtk.Grid
Show()
@@ -27,10 +24,12 @@ type Panel interface {
}
type CommonPanel struct {
- UI *UI
- g *gtk.Grid
- b *BackgroundTask
- p Panel
+ UI *UI
+ g *gtk.Grid
+ b *BackgroundTask
+ p Panel
+ panelW int
+ panelH int
buttons []gtk.IWidget
}
@@ -40,14 +39,14 @@ func NewCommonPanel(ui *UI, parent Panel) CommonPanel {
g.SetRowHomogeneous(true)
g.SetColumnHomogeneous(true)
- return CommonPanel{UI: ui, g: g, p: parent}
+ return CommonPanel{UI: ui, g: g, p: parent, panelW: 4, panelH: 2}
}
func (p *CommonPanel) Initialize() {
- last := panelW * panelH
+ last := p.panelW * p.panelH
if last < len(p.buttons) {
- cols := math.Ceil(float64(len(p.buttons)) / float64(panelW))
- last = int(cols) * panelW
+ cols := math.Ceil(float64(len(p.buttons)) / float64(p.panelW))
+ last = int(cols) * p.panelW
}
for i := len(p.buttons) + 1; i < last; i++ {
@@ -62,8 +61,8 @@ func (p *CommonPanel) Parent() Panel {
}
func (p *CommonPanel) AddButton(b gtk.IWidget) {
- x := len(p.buttons) % panelW
- y := len(p.buttons) / panelW
+ x := len(p.buttons) % p.panelW
+ y := len(p.buttons) / p.panelW
p.g.Attach(b, x+1, y, 1, 1)
p.buttons = append(p.buttons, b)
}
@@ -160,6 +159,49 @@ type Step struct {
Value interface{}
}
+func MustPressedButton(label, i string, pressed func(), speed time.Duration) *gtk.Button {
+ img := MustImageFromFile(i)
+ released := make(chan bool)
+ var mutex sync.Mutex
+
+ b, err := gtk.ButtonNewWithLabel(label)
+ if err != nil {
+ panic(err)
+ }
+
+ b.SetImage(img)
+ b.SetAlwaysShowImage(true)
+ b.SetImagePosition(gtk.POS_TOP)
+ b.SetVExpand(true)
+ b.SetHExpand(true)
+
+ if pressed != nil {
+ b.Connect("pressed", func() {
+ go func() {
+ for {
+ select {
+ case <-released:
+ return
+ default:
+ mutex.Lock()
+ pressed()
+ time.Sleep(speed * time.Millisecond)
+ mutex.Unlock()
+ }
+ }
+ }()
+ })
+ }
+
+ if released != nil {
+ b.Connect("released", func() {
+ released <- true
+ })
+ }
+
+ return b
+}
+
func MustStepButton(image string, s ...Step) *StepButton {
var l string
if len(s) != 0 {
diff --git a/ui/default.go b/ui/default.go
index 12e3e89..da708cf 100644
--- a/ui/default.go
+++ b/ui/default.go
@@ -21,9 +21,10 @@ func (m *defaultPanel) initialize() {
m.Grid().Attach(MustButtonImage("Heat Up", "heat-up.svg", m.showTemperature), 2, 0, 1, 1)
m.Grid().Attach(MustButtonImage("Move", "move.svg", m.showMove), 3, 0, 1, 1)
m.Grid().Attach(MustButtonImage("Home", "home.svg", m.showHome), 4, 0, 1, 1)
- m.Grid().Attach(MustButtonImage("Filament", "filament.svg", m.showFilament), 1, 1, 1, 1)
- m.Grid().Attach(MustButtonImage("Control", "control.svg", m.showControl), 2, 1, 1, 1)
- m.Grid().Attach(MustButtonImage("Files", "files.svg", m.showFiles), 3, 1, 1, 1)
+
+ m.Grid().Attach(MustButtonImage("Print", "files.svg", m.showFiles), 1, 1, 1, 1)
+ m.Grid().Attach(MustButtonImage("Filament", "filament.svg", m.showFilament), 2, 1, 1, 1)
+ m.Grid().Attach(MustButtonImage("Control", "control.svg", m.showControl), 3, 1, 1, 1)
m.Grid().Attach(MustButtonImage("System", "settings.svg", m.showSystem), 4, 1, 1, 1)
}
diff --git a/ui/filament.go b/ui/filament.go
index b1bc6a1..9c41585 100644
--- a/ui/filament.go
+++ b/ui/filament.go
@@ -27,7 +27,7 @@ func FilamentPanel(ui *UI, parent Panel) Panel {
m := &filamentPanel{CommonPanel: NewCommonPanel(ui, parent),
labels: map[string]*LabelWithImage{},
}
-
+ m.panelH = 3
m.b = NewBackgroundTask(time.Second*5, m.updateTemperatures)
m.initialize()
filamentPanelInstance = m
@@ -39,6 +39,9 @@ func FilamentPanel(ui *UI, parent Panel) Panel {
func (m *filamentPanel) initialize() {
defer m.Initialize()
+ 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)
@@ -46,13 +49,13 @@ func (m *filamentPanel) initialize() {
m.box.SetVAlign(gtk.ALIGN_CENTER)
m.box.SetMarginStart(10)
- m.Grid().Attach(m.box, 2, 0, 2, 1)
+ m.Grid().Attach(m.box, 2, 0, 2, 2)
m.amount = MustStepButton("move-step.svg", Step{"5mm", 5}, Step{"10mm", 10}, Step{"1mm", 1})
- m.Grid().Attach(m.amount, 2, 1, 1, 1)
+ m.Grid().Attach(m.amount, 2, 2, 1, 1)
- m.Grid().Attach(m.createToolButton(), 1, 1, 1, 1)
- m.Grid().Attach(m.createFlowrateButton(), 3, 1, 1, 1)
+ m.Grid().Attach(m.createToolButton(), 1, 2, 1, 1)
+ m.Grid().Attach(m.createFlowrateButton(), 3, 2, 1, 1)
}
func (m *filamentPanel) updateTemperatures() {
@@ -134,8 +137,37 @@ func (m *filamentPanel) createFlowrateButton() *StepButton {
return b
}
+func (m *filamentPanel) createLoadButton() gtk.IWidget {
+
+ return MustButtonImage("Load", "extrude.svg", func() {
+ cmd := &octoprint.CommandRequest{}
+ cmd.Commands = []string{"G92 E0", "G0 E600 F5000", "G92 E0", "G0 E65 F500"}
+
+ Logger.Info("Sending filament load request")
+ if err := cmd.Do(m.UI.Printer); err != nil {
+ Logger.Error(err)
+ return
+ }
+ })
+}
+
+func (m *filamentPanel) createUnloadButton() gtk.IWidget {
+
+ return MustButtonImage("Unload", "retract.svg", func() {
+ cmd := &octoprint.CommandRequest{}
+ cmd.Commands = []string{"G92 E0", "G0 E-800 F5000"}
+
+ Logger.Info("Sending filament unload request")
+ if err := cmd.Do(m.UI.Printer); err != nil {
+ Logger.Error(err)
+ return
+ }
+ })
+}
+
func (m *filamentPanel) createExtrudeButton(label, image string, dir int) gtk.IWidget {
- return MustButtonImage(label, image, func() {
+
+ return MustPressedButton(label, image, func() {
cmd := &octoprint.ToolExtrudeRequest{}
cmd.Amount = m.amount.Value().(int) * dir
@@ -144,5 +176,16 @@ func (m *filamentPanel) createExtrudeButton(label, image string, dir int) gtk.IW
Logger.Error(err)
return
}
- })
+ }, 200)
+
+ // return MustButtonImage(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
+ // }
+ // })
}
diff --git a/ui/files.go b/ui/files.go
index 48baeee..b9fc31d 100644
--- a/ui/files.go
+++ b/ui/files.go
@@ -10,17 +10,44 @@ import (
"github.com/mcuadros/go-octoprint"
)
+type locationHistory struct {
+ locations []octoprint.Location
+}
+
+func (l *locationHistory) current() octoprint.Location {
+ return l.locations[len(l.locations)-1]
+}
+
+func (l *locationHistory) goForward(folder string) {
+ newLocation := string(l.current()) + "/" + folder
+ l.locations = append(l.locations, octoprint.Location(newLocation))
+}
+
+func (l *locationHistory) goBack() {
+ l.locations = l.locations[0 : len(l.locations)-1]
+}
+
+func (l *locationHistory) isRoot() bool {
+ if len(l.locations) > 1 {
+ return false
+ } else {
+ return true
+ }
+}
+
var filesPanelInstance *filesPanel
type filesPanel struct {
CommonPanel
- list *gtk.Box
+ list *gtk.Box
+ location locationHistory
}
func FilesPanel(ui *UI, parent Panel) Panel {
if filesPanelInstance == nil {
- m := &filesPanel{CommonPanel: NewCommonPanel(ui, parent)}
+ l := locationHistory{locations: []octoprint.Location{octoprint.Local}}
+ m := &filesPanel{CommonPanel: NewCommonPanel(ui, parent), location: l}
m.initialize()
filesPanelInstance = m
}
@@ -33,6 +60,7 @@ func (m *filesPanel) initialize() {
m.list.SetVExpand(true)
scroll, _ := gtk.ScrolledWindowNew(nil, nil)
+ scroll.SetProperty("overlay-scrolling", false)
scroll.Add(m.list)
box := MustBox(gtk.ORIENTATION_VERTICAL, 0)
@@ -53,7 +81,7 @@ func (m *filesPanel) createActionBar() gtk.IWidget {
bar.Add(m.createRefreshButton())
bar.Add(m.createInitReleaseSDButton())
- bar.Add(MustButton(MustImageFromFileWithSize("back.svg", 40, 40), m.UI.GoHistory))
+ bar.Add(m.createBackButton())
return bar
}
@@ -62,46 +90,49 @@ func (m *filesPanel) createRefreshButton() gtk.IWidget {
return MustButton(MustImageFromFileWithSize("refresh.svg", 40, 40), m.doLoadFiles)
}
+func (m *filesPanel) createBackButton() gtk.IWidget {
+ return MustButton(MustImageFromFileWithSize("back.svg", 40, 40), func() {
+ if m.location.isRoot() {
+ m.UI.GoHistory()
+ } else {
+ m.location.goBack()
+ m.doLoadFiles()
+ }
+ })
+ // return MustButton(MustImageFromFileWithSize("refresh.svg", 40, 40), m.doLoadFiles)
+}
+
func (m *filesPanel) doLoadFiles() {
- Logger.Info("Refreshing list of files")
- m.doRefreshSD()
+ var files []*octoprint.FileInformation
- local := m.doLoadFilesFromLocation(octoprint.Local)
- sdcard := m.doLoadFilesFromLocation(octoprint.SDCard)
+ Logger.Info("Loading list of files from: ", string(m.location.current()))
- s := byDate(local)
- s = append(s, sdcard...)
+ // m.doRefreshSD()
+ r := &octoprint.FilesRequest{Location: m.location.current(), Recursive: false}
+ folder, err := r.Do(m.UI.Printer)
+ if err != nil {
+ Logger.Error(err)
+ files = []*octoprint.FileInformation{}
+ } else {
+ files = folder.Files
+ }
+
+ s := byDate(files)
+ // s = append(s, sdcard...)
sort.Sort(s)
EmptyContainer(&m.list.Container)
for _, f := range s {
if f.IsFolder() {
- continue
+ m.addFolder(m.list, f)
+ } else {
+ m.addFile(m.list, f)
}
-
- m.addFile(m.list, f)
}
m.list.ShowAll()
}
-func (m *filesPanel) doRefreshSD() {
- if err := (&octoprint.SDRefreshRequest{}).Do(m.UI.Printer); err != nil {
- Logger.Error(err)
- }
-}
-
-func (m *filesPanel) doLoadFilesFromLocation(l octoprint.Location) []*octoprint.FileInformation {
- r := &octoprint.FilesRequest{Location: l, Recursive: true}
- files, err := r.Do(m.UI.Printer)
- if err != nil {
- Logger.Error(err)
- return []*octoprint.FileInformation{}
- }
-
- return files.Files
-}
-
func (m *filesPanel) addFile(b *gtk.Box, f *octoprint.FileInformation) {
frame, _ := gtk.FrameNew("")
@@ -119,7 +150,7 @@ func (m *filesPanel) addFile(b *gtk.Box, f *octoprint.FileInformation) {
labels.Add(info)
actions := MustBox(gtk.ORIENTATION_HORIZONTAL, 5)
- actions.Add(m.createLoadAndPrintButton("load.svg", f, false))
+ // actions.Add(m.createLoadAndPrintButton("load.svg", f, false))
actions.Add(m.createLoadAndPrintButton("status.svg", f, true))
file := MustBox(gtk.ORIENTATION_HORIZONTAL, 5)
@@ -138,6 +169,41 @@ func (m *filesPanel) addFile(b *gtk.Box, f *octoprint.FileInformation) {
b.Add(frame)
}
+func (m *filesPanel) addFolder(b *gtk.Box, f *octoprint.FileInformation) {
+ frame, _ := gtk.FrameNew("")
+
+ name := MustLabel(f.Name)
+ name.SetMarkup(fmt.Sprintf("%s", filenameEllipsis(f.Name)))
+ name.SetHExpand(true)
+
+ info := MustLabel("")
+ info.SetMarkup(fmt.Sprintf("Size: %s",
+ humanize.Bytes(uint64(f.Size)),
+ ))
+
+ labels := MustBox(gtk.ORIENTATION_VERTICAL, 5)
+ labels.Add(name)
+ labels.Add(info)
+
+ actions := MustBox(gtk.ORIENTATION_HORIZONTAL, 5)
+ actions.Add(m.createOpenFolderButton(f))
+
+ file := MustBox(gtk.ORIENTATION_HORIZONTAL, 5)
+ file.SetMarginTop(15)
+ file.SetMarginEnd(15)
+ file.SetMarginStart(15)
+ file.SetMarginBottom(15)
+ file.SetHExpand(true)
+
+ file.Add(MustImageFromFileWithSize("files.svg", 35, 35))
+
+ file.Add(labels)
+ file.Add(actions)
+
+ frame.Add(file)
+ b.Add(frame)
+}
+
func (m *filesPanel) createLoadAndPrintButton(img string, f *octoprint.FileInformation, print bool) gtk.IWidget {
return MustButton(
MustImageFromFileWithSize(img, 30, 30),
@@ -156,6 +222,15 @@ func (m *filesPanel) createLoadAndPrintButton(img string, f *octoprint.FileInfor
)
}
+func (m *filesPanel) createOpenFolderButton(f *octoprint.FileInformation) gtk.IWidget {
+ return MustButton(MustImageFromFileWithSize("open.svg", 30, 30), func() {
+ m.location.goForward(f.Path)
+ // m.currentFolder = octoprint.Location(f.Origin + "/" + string())
+ // m.parentFolder = octoprint.Location(f.Origin)
+ m.doLoadFiles()
+ })
+}
+
func (m *filesPanel) createInitReleaseSDButton() gtk.IWidget {
release := MustImageFromFileWithSize("sd_eject.svg", 40, 40)
init := MustImageFromFileWithSize("sd.svg", 40, 40)
diff --git a/ui/logger.go b/ui/logger.go
index 8d9c705..d6ccc76 100644
--- a/ui/logger.go
+++ b/ui/logger.go
@@ -1,6 +1,7 @@
package ui
import (
+ "os"
"path"
"runtime"
"strings"
@@ -63,7 +64,22 @@ func (h NotificationsHook) Fire(entry *logrus.Entry) error {
var Logger *logrus.Entry
func init() {
- logrus.AddHook(ContextHook{})
- logrus.SetLevel(logrus.DebugLevel)
- Logger = logrus.WithFields(logrus.Fields{})
+ var LogFile = os.Getenv("OCTOPRINT_TFT_LOG_FILE")
+
+ var log = logrus.New()
+ log.AddHook(ContextHook{})
+ log.SetLevel(logrus.DebugLevel)
+
+ if LogFile == "" {
+ log.Out = os.Stdout
+ } else {
+ file, err := os.OpenFile(LogFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
+ if err == nil {
+ log.Out = file
+ } else {
+ log.Info("Failed to log to file, using default stderr")
+ }
+ }
+
+ Logger = log.WithFields(logrus.Fields{})
}
diff --git a/ui/move.go b/ui/move.go
index b199b94..923672d 100644
--- a/ui/move.go
+++ b/ui/move.go
@@ -1,8 +1,6 @@
package ui
import (
- "strings"
-
"github.com/gotk3/gotk3/gtk"
"github.com/mcuadros/go-octoprint"
)
@@ -17,6 +15,8 @@ type movePanel struct {
func MovePanel(ui *UI, parent Panel) Panel {
if movePanelInstance == nil {
m := &movePanel{CommonPanel: NewCommonPanel(ui, parent)}
+ m.panelH = 3
+ m.panelW = 3
m.initialize()
movePanelInstance = m
}
@@ -26,23 +26,24 @@ func MovePanel(ui *UI, parent Panel) Panel {
func (m *movePanel) initialize() {
defer m.Initialize()
+ m.Grid().Attach(m.createMoveButton("X-", "move-x-.svg", octoprint.XAxis, -1), 0, 1, 1, 1)
+ m.Grid().Attach(m.createMoveButton("X+", "move-x+.svg", octoprint.XAxis, 1), 2, 1, 1, 1)
+ m.Grid().Attach(m.createMoveButton("Y+", "move-y+.svg", octoprint.YAxis, 1), 1, 0, 1, 1)
+ m.Grid().Attach(m.createMoveButton("Y-", "move-y-.svg", octoprint.YAxis, -1), 1, 2, 1, 1)
- m.AddButton(m.createMoveButton("X+", "move-x+.svg", octoprint.XAxis, 1))
- m.AddButton(m.createMoveButton("Y+", "move-y+.svg", octoprint.YAxis, 1))
- m.AddButton(m.createMoveButton("Z+", "move-z+.svg", octoprint.ZAxis, 1))
+ m.Grid().Attach(m.createMoveButton("Z+", "move-z+.svg", octoprint.ZAxis, 1), 3, 0, 1, 1)
+ m.Grid().Attach(m.createMoveButton("Z-", "move-z-.svg", octoprint.ZAxis, -1), 3, 1, 1, 1)
m.step = MustStepButton("move-step.svg",
Step{"5mm", 5}, Step{"10mm", 10}, Step{"1mm", 1},
)
- m.AddButton(m.step)
- m.AddButton(m.createMoveButton("X-", "move-x-.svg", octoprint.XAxis, -1))
- m.AddButton(m.createMoveButton("Y-", "move-y-.svg", octoprint.YAxis, -1))
- m.AddButton(m.createMoveButton("Z-", "move-z-.svg", octoprint.ZAxis, -1))
+ m.Grid().Attach(m.step, 2, 2, 1, 1)
}
func (m *movePanel) createMoveButton(label, image string, a octoprint.Axis, dir int) gtk.IWidget {
- return MustButtonImage(label, image, func() {
+
+ return MustPressedButton(label, image, func() {
distance := m.step.Value().(int) * dir
cmd := &octoprint.PrintHeadJogRequest{}
@@ -55,13 +56,14 @@ func (m *movePanel) createMoveButton(label, image string, a octoprint.Axis, dir
cmd.Z = distance
}
- Logger.Warningf("Jogging print head axis %s in %dmm",
- strings.ToUpper(string(a)), distance,
- )
+ // Logger.Warningf("Jogging print head axis %s in %dmm",
+ // strings.ToUpper(string(a)), distance,
+ // )
if err := cmd.Do(m.UI.Printer); err != nil {
Logger.Error(err)
return
}
- })
+
+ }, 200)
}
diff --git a/ui/splash.go b/ui/splash.go
index c421f57..2114547 100644
--- a/ui/splash.go
+++ b/ui/splash.go
@@ -14,8 +14,8 @@ func NewSplashPanel(ui *UI) *SplashPanel {
}
func (m *SplashPanel) initialize() {
- logo := MustImageFromFile("octoprint-logo.png")
- m.Label = MustLabel("Connecting to OctoPrint...")
+ logo := MustImageFromFile("logo-white.svg")
+ m.Label = MustLabel("Initializing printer...")
box := MustBox(gtk.ORIENTATION_VERTICAL, 15)
box.SetVAlign(gtk.ALIGN_CENTER)
diff --git a/ui/status.go b/ui/status.go
index 5e11611..37081c8 100644
--- a/ui/status.go
+++ b/ui/status.go
@@ -16,15 +16,16 @@ type statusPanel struct {
step *StepButton
pb *gtk.ProgressBar
- bed, tool0, tool1 *LabelWithImage
- file, left *LabelWithImage
- print, pause, stop *gtk.Button
+ bed, tool0, tool1, tool2, tool3 *LabelWithImage
+ file, left *LabelWithImage
+ print, pause, stop *gtk.Button
}
func StatusPanel(ui *UI, parent Panel) Panel {
if statusPanelInstance == nil {
m := &statusPanel{CommonPanel: NewCommonPanel(ui, parent)}
- m.b = NewBackgroundTask(time.Second*5, m.update)
+ m.panelH = 3
+ m.b = NewBackgroundTask(time.Second*2, m.update)
m.initialize()
statusPanelInstance = m
@@ -36,10 +37,10 @@ func StatusPanel(ui *UI, parent Panel) Panel {
func (m *statusPanel) initialize() {
defer m.Initialize()
- m.Grid().Attach(m.createMainBox(), 1, 0, 4, 1)
- m.Grid().Attach(m.createPrintButton(), 1, 1, 1, 1)
- m.Grid().Attach(m.createPauseButton(), 2, 1, 1, 1)
- m.Grid().Attach(m.createStopButton(), 3, 1, 1, 1)
+ m.Grid().Attach(m.createMainBox(), 1, 0, 4, 2)
+ m.Grid().Attach(m.createPrintButton(), 1, 2, 1, 1)
+ m.Grid().Attach(m.createPauseButton(), 2, 2, 1, 1)
+ m.Grid().Attach(m.createStopButton(), 3, 2, 1, 1)
}
func (m *statusPanel) createProgressBar() *gtk.ProgressBar {
@@ -86,6 +87,8 @@ func (m *statusPanel) createTemperatureBox() *gtk.Box {
m.bed = MustLabelWithImage("bed.svg", "")
m.tool0 = MustLabelWithImage("extruder.svg", "")
m.tool1 = MustLabelWithImage("extruder.svg", "")
+ m.tool2 = MustLabelWithImage("extruder.svg", "")
+ m.tool3 = MustLabelWithImage("extruder.svg", "")
temp := MustBox(gtk.ORIENTATION_VERTICAL, 5)
temp.SetHAlign(gtk.ALIGN_START)
@@ -94,6 +97,8 @@ func (m *statusPanel) createTemperatureBox() *gtk.Box {
temp.Add(m.bed)
temp.Add(m.tool0)
temp.Add(m.tool1)
+ temp.Add(m.tool2)
+ temp.Add(m.tool3)
return temp
}
@@ -128,16 +133,9 @@ func (m *statusPanel) createPauseButton() gtk.IWidget {
}
func (m *statusPanel) createStopButton() gtk.IWidget {
- m.stop = MustButtonImage("Stop", "stop.svg", func() {
- defer m.updateTemperature()
-
- Logger.Warning("Stopping job")
- if err := (&octoprint.CancelRequest{}).Do(m.UI.Printer); err != nil {
- Logger.Error(err)
- return
- }
- })
-
+ m.stop = MustButtonImage("Stop", "stop.svg",
+ ConfirmStopDialog(m.UI.w, "Are you sure you want to stop current print?", m),
+ )
return m.stop
}
@@ -156,6 +154,9 @@ func (m *statusPanel) updateTemperature() {
m.doUpdateState(&s.State)
m.tool1.Hide()
+ m.tool2.Hide()
+ m.tool3.Hide()
+
for tool, s := range s.Temperature.Current {
text := fmt.Sprintf("%s: %.0f°C / %.0f°C", strings.Title(tool), s.Actual, s.Target)
switch tool {
@@ -166,6 +167,12 @@ func (m *statusPanel) updateTemperature() {
case "tool1":
m.tool1.Label.SetLabel(text)
m.tool1.Show()
+ case "tool2":
+ m.tool2.Label.SetLabel(text)
+ m.tool2.Show()
+ case "tool3":
+ m.tool3.Label.SetLabel(text)
+ m.tool3.Show()
}
}
}
@@ -220,15 +227,19 @@ func (m *statusPanel) updateJob() {
var text string
switch s.Progress.Completion {
case 100:
- text = fmt.Sprintf("Job Completed in %s", time.Duration(int64(s.Job.LastPrintTime)*1e9))
+ text = fmt.Sprintf("Completed in %s", time.Duration(int64(s.Job.LastPrintTime)*1e9))
case 0:
text = "Warming up ..."
default:
+ Logger.Info(s.Progress.PrintTime)
+
e := time.Duration(int64(s.Progress.PrintTime) * 1e9)
l := time.Duration(int64(s.Progress.PrintTimeLeft) * 1e9)
- text = fmt.Sprintf("Elapsed/Left: %s / %s", e, l)
+ // eta := time.Now().Add(l).Format("3:04 PM")
if l == 0 {
- text = fmt.Sprintf("Elapsed: %s", e)
+ text = fmt.Sprintf("Print Time: %s", e)
+ } else {
+ text = fmt.Sprintf("Print Time: %s | Left: %s", e, l)
}
}
@@ -236,9 +247,52 @@ func (m *statusPanel) updateJob() {
}
func filenameEllipsis(name string) string {
- if len(name) > 26 {
- return name[:23] + "..."
+ l := len(name)
+ if l > 32 {
+ return name[:12] + "..." + name[l-17:l]
}
return name
}
+
+func btou(b bool) uint8 {
+ if b {
+ return 1
+ }
+ return 0
+}
+
+func ConfirmStopDialog(parent *gtk.Window, msg string, ma *statusPanel) func() {
+ return func() {
+ win := gtk.MessageDialogNewWithMarkup(
+ parent,
+ gtk.DIALOG_MODAL,
+ gtk.MESSAGE_INFO,
+ gtk.BUTTONS_YES_NO,
+ "",
+ )
+
+ win.SetMarkup(CleanHTML(msg))
+ defer win.Destroy()
+
+ box, _ := win.GetContentArea()
+ box.SetMarginStart(15)
+ box.SetMarginEnd(15)
+ box.SetMarginTop(15)
+ box.SetMarginBottom(15)
+
+ ctx, _ := win.GetStyleContext()
+ ctx.AddClass("dialog")
+
+ ergebnis := win.Run()
+
+ if ergebnis == int(gtk.RESPONSE_YES) {
+
+ Logger.Warning("Stopping job")
+ if err := (&octoprint.CancelRequest{}).Do(ma.UI.Printer); err != nil {
+ Logger.Error(err)
+ return
+ }
+ }
+ }
+}
diff --git a/ui/system.go b/ui/system.go
index 6f51367..7db1b97 100644
--- a/ui/system.go
+++ b/ui/system.go
@@ -1,9 +1,8 @@
package ui
import (
- "bytes"
"fmt"
- "io/ioutil"
+ "net"
"github.com/dustin/go-humanize"
"github.com/gotk3/gotk3/gtk"
@@ -101,20 +100,17 @@ func (m *systemPanel) createInfoBox() gtk.IWidget {
main.SetHExpand(true)
main.SetHAlign(gtk.ALIGN_CENTER)
main.SetVExpand(true)
- main.Add(MustImageFromFileWithSize("octoprint-logo.png", 140, 140))
+
+ img := MustImageFromFileWithSize("logo-white.svg", 140, 112)
+ img.SetMarginTop(35)
+ main.Add(img)
info := MustBox(gtk.ORIENTATION_VERTICAL, 0)
info.SetVExpand(true)
info.SetVAlign(gtk.ALIGN_CENTER)
- m.addOctoPrintTFT(info)
-
- title := MustLabel("Versions Information")
- title.SetMarginTop(15)
- title.SetMarginBottom(5)
- info.Add(title)
+ m.addNetwork(info)
m.addOctoPrint(info)
- m.addOctoPi(info)
m.addSystemInfo(info)
main.Add(info)
@@ -122,35 +118,50 @@ func (m *systemPanel) createInfoBox() gtk.IWidget {
return main
}
-func (m *systemPanel) addOctoPrintTFT(box *gtk.Box) {
- title := MustLabel("OctoPrint-TFT Version")
- title.SetMarginBottom(5)
+// func (m *systemPanel) addOctoPrintTFT(box *gtk.Box) {
+// title := MustLabel("OctoPrint-TFT Version")
+// title.SetMarginTop(15)
+// title.SetMarginBottom(5)
- info := MustBox(gtk.ORIENTATION_VERTICAL, 0)
- box.Add(info)
+// info := MustBox(gtk.ORIENTATION_VERTICAL, 0)
+// box.Add(info)
- info.Add(title)
- info.Add(MustLabel("%s (%s)", Version, Build))
-}
+// info.Add(title)
+// info.Add(MustLabel("%s (%s)", Version, Build))
+// }
-func (m *systemPanel) addOctoPi(box *gtk.Box) {
- v, err := ioutil.ReadFile("/etc/octopi_version")
- if err != nil {
- Logger.Error(err)
- return
- }
+func (m *systemPanel) addNetwork(box *gtk.Box) {
+ title := MustLabel("Network Information")
+ title.SetMarginTop(40)
+ title.SetMarginBottom(5)
+
+ box.Add(title)
+ addrs, _ := net.InterfaceAddrs()
- box.Add(MustLabel("OctoPi Version: %s", bytes.Trim(v, "\n")))
+ for _, address := range addrs {
+ if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
+ if ipnet.IP.To4() != nil {
+ box.Add(MustLabel("IP Address %s", ipnet.IP.String()))
+ }
+ }
+ }
}
func (m *systemPanel) addOctoPrint(box *gtk.Box) {
+ title := MustLabel("Versions Information")
+ title.SetMarginTop(15)
+ title.SetMarginBottom(5)
+ box.Add(title)
+
r, err := (&octoprint.VersionRequest{}).Do(m.UI.Printer)
if err != nil {
Logger.Error(err)
return
}
+ box.Add(MustLabel("UI Version: %s (%s)", Version, Build))
box.Add(MustLabel("OctoPrint Version: %s (%s)", r.Server, r.API))
+
}
func (m *systemPanel) addSystemInfo(box *gtk.Box) {
diff --git a/ui/temperature.go b/ui/temperature.go
index 4f9f617..bb6eff6 100644
--- a/ui/temperature.go
+++ b/ui/temperature.go
@@ -48,10 +48,10 @@ func (m *temperaturePanel) initialize() {
m.Grid().Attach(m.box, 2, 0, 2, 1)
m.Grid().Attach(m.createToolButton(), 1, 1, 1, 1)
- m.amount = MustStepButton("move-step.svg", Step{"5°C", 5.}, Step{"10°C", 10.}, Step{"1°C", 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(MustButtonImage("Profiles", "heat-up.svg", m.profilePanel), 3, 1, 1, 1)
+ m.Grid().Attach(MustButtonImage("More", "heat-up.svg", m.profilePanel), 3, 1, 1, 1)
}
func (m *temperaturePanel) createToolButton() *StepButton {
@@ -69,13 +69,14 @@ func (m *temperaturePanel) createToolButton() *StepButton {
}
func (m *temperaturePanel) createChangeButton(label, image string, value float64) gtk.IWidget {
- return MustButtonImage(label, image, func() {
+
+ return MustPressedButton(label, image, func() {
target := value * m.amount.Value().(float64)
if err := m.increaseTarget(m.tool.Value().(string), target); err != nil {
Logger.Error(err)
return
}
- })
+ }, 100)
}
func (m *temperaturePanel) increaseTarget(tool string, value float64) error {
@@ -153,7 +154,7 @@ func (m *temperaturePanel) addNewTool(tool string) {
m.tool.AddStep(Step{strings.Title(tool), tool})
m.tool.Callback()
- Logger.Infof("New tool detected %s", tool)
+ Logger.Infof("Tool detected %s", tool)
}
func (m *temperaturePanel) loadTemperatureData(tool string, d *octoprint.TemperatureData) {
@@ -211,6 +212,7 @@ func (m *profilesPanel) createProfileButton(img string, p *octoprint.Temperature
if err := m.setProfile(p); err != nil {
Logger.Error(err)
}
+ m.UI.GoHistory()
})
}
diff --git a/ui/ui.go b/ui/ui.go
index e64d518..dd20a60 100644
--- a/ui/ui.go
+++ b/ui/ui.go
@@ -6,6 +6,7 @@ import (
"sync"
"time"
+ "github.com/coreos/go-systemd/daemon"
"github.com/gotk3/gotk3/gdk"
"github.com/gotk3/gotk3/gtk"
"github.com/mcuadros/go-octoprint"
@@ -80,6 +81,8 @@ func (ui *UI) initialize() {
ui.g = MustGrid()
ui.o.Add(ui.g)
ui.o.AddOverlay(ui.Notifications)
+
+ daemon.SdNotify(false, "READY=1")
}
func (ui *UI) loadStyle() {
@@ -97,6 +100,8 @@ func (ui *UI) loadStyle() {
var errMercyPeriod = time.Second * 30
func (ui *UI) verifyConnection() {
+ daemon.SdNotify(false, "WATCHDOG=1")
+
splash := NewSplashPanel(ui)
s, err := (&octoprint.ConnectionRequest{}).Do(ui.Printer)
diff --git a/vendor/github.com/coreos/go-systemd/.travis.yml b/vendor/github.com/coreos/go-systemd/.travis.yml
new file mode 100644
index 0000000..cfea999
--- /dev/null
+++ b/vendor/github.com/coreos/go-systemd/.travis.yml
@@ -0,0 +1,45 @@
+dist: trusty
+sudo: required
+services:
+ - docker
+
+language: go
+go:
+ - "1.10.x"
+ - "1.11.x"
+go_import_path: github.com/coreos/go-systemd
+
+env:
+ global:
+ - IMPORTPATH=github.com/coreos/go-systemd
+ - GOPATH=/opt
+ - DEP_BINDIR=/tmp
+ - BUILD_DIR=/opt/src/github.com/coreos/go-systemd
+ matrix:
+ - DOCKER_BASE=ubuntu:16.04
+ - DOCKER_BASE=ubuntu:18.04
+ - DOCKER_BASE=debian:stretch
+
+before_install:
+ - sudo apt-get -qq update
+ - sudo apt-get install -y libsystemd-journal-dev libsystemd-daemon-dev
+ - curl https://raw.githubusercontent.com/golang/dep/master/install.sh | INSTALL_DIRECTORY=${DEP_BINDIR} sh
+ - ${DEP_BINDIR}/dep ensure -v
+ - docker pull ${DOCKER_BASE}
+ - docker run --privileged -e GOPATH=${GOPATH} --cidfile=/tmp/cidfile ${DOCKER_BASE} /bin/bash -c "apt-get update && apt-get install -y sudo build-essential git golang dbus libsystemd-dev libpam-systemd systemd-container"
+ - docker commit `cat /tmp/cidfile` go-systemd/container-tests
+ - rm -f /tmp/cidfile
+
+install:
+ - docker run --shm-size=2gb -d --cidfile=/tmp/cidfile --privileged -e GOPATH=${GOPATH} -v ${PWD}:${BUILD_DIR} go-systemd/container-tests /bin/systemd --system
+
+script:
+ - ./scripts/travis/pr-test.sh go_fmt
+ - ./scripts/travis/pr-test.sh build_source
+ - ./scripts/travis/pr-test.sh build_tests
+ - docker exec --privileged `cat /tmp/cidfile` /bin/bash -c "cd ${BUILD_DIR} && ./scripts/travis/pr-test.sh run_tests"
+ - ./scripts/travis/pr-test.sh go_vet
+ - ./scripts/travis/pr-test.sh license_check
+
+after_script:
+ - docker kill `cat /tmp/cidfile`
diff --git a/vendor/github.com/coreos/go-systemd/CONTRIBUTING.md b/vendor/github.com/coreos/go-systemd/CONTRIBUTING.md
new file mode 100644
index 0000000..0551ed5
--- /dev/null
+++ b/vendor/github.com/coreos/go-systemd/CONTRIBUTING.md
@@ -0,0 +1,77 @@
+# How to Contribute
+
+CoreOS projects are [Apache 2.0 licensed](LICENSE) and accept contributions via
+GitHub pull requests. This document outlines some of the conventions on
+development workflow, commit message formatting, contact points and other
+resources to make it easier to get your contribution accepted.
+
+# Certificate of Origin
+
+By contributing to this project you agree to the Developer Certificate of
+Origin (DCO). This document was created by the Linux Kernel community and is a
+simple statement that you, as a contributor, have the legal right to make the
+contribution. See the [DCO](DCO) file for details.
+
+# Email and Chat
+
+The project currently uses the general CoreOS email list and IRC channel:
+- Email: [coreos-dev](https://groups.google.com/forum/#!forum/coreos-dev)
+- IRC: #[coreos](irc://irc.freenode.org:6667/#coreos) IRC channel on freenode.org
+
+Please avoid emailing maintainers found in the MAINTAINERS file directly. They
+are very busy and read the mailing lists.
+
+## Getting Started
+
+- Fork the repository on GitHub
+- Read the [README](README.md) for build and test instructions
+- Play with the project, submit bugs, submit patches!
+
+## Contribution Flow
+
+This is a rough outline of what a contributor's workflow looks like:
+
+- Create a topic branch from where you want to base your work (usually master).
+- Make commits of logical units.
+- Make sure your commit messages are in the proper format (see below).
+- Push your changes to a topic branch in your fork of the repository.
+- Make sure the tests pass, and add any new tests as appropriate.
+- Submit a pull request to the original repository.
+
+Thanks for your contributions!
+
+### Coding Style
+
+CoreOS projects written in Go follow a set of style guidelines that we've documented
+[here](https://github.com/coreos/docs/tree/master/golang). Please follow them when
+working on your contributions.
+
+### Format of the Commit Message
+
+We follow a rough convention for commit messages that is designed to answer two
+questions: what changed and why. The subject line should feature the what and
+the body of the commit should describe the why.
+
+```
+scripts: add the test-cluster command
+
+this uses tmux to setup a test cluster that you can easily kill and
+start for debugging.
+
+Fixes #38
+```
+
+The format can be described more formally as follows:
+
+```
+:
+
+
+
+