Many minor popup improvements, add weather popup
This commit is contained in:
parent
0b8a9d2e01
commit
9d5cf20d28
@ -13,7 +13,8 @@ Or for a binary that includes embedded static files:
|
||||
|
||||
`packr2 get github.com/onodera-punpun/melonbar`
|
||||
|
||||
`melonbar` depends on Go 1.9 or newer and [packr2](https://github.com/gobuffalo/packr/tree/master/v2).
|
||||
`melonbar` depends on Go 1.9 or newer, gnuplot, and
|
||||
[packr2](https://github.com/gobuffalo/packr/tree/master/v2).
|
||||
|
||||
|
||||
## USAGE
|
||||
|
1
TODO.md
1
TODO.md
@ -2,3 +2,4 @@
|
||||
* Fix weird `'` characters.
|
||||
* Fix `?` character.
|
||||
* Fix `\n` character.
|
||||
* Fix and add `º` character.
|
||||
|
34
bar.go
34
bar.go
@ -30,6 +30,9 @@ type Bar struct {
|
||||
// right of the last block.
|
||||
xsum int
|
||||
|
||||
// Text drawer.
|
||||
drawer *font.Drawer
|
||||
|
||||
// A map with information about the block, see the `Block` type.
|
||||
blocks *sync.Map
|
||||
|
||||
@ -90,6 +93,11 @@ func initBar(x, y, w, h int) (*Bar, error) {
|
||||
bar.w = w
|
||||
bar.h = h
|
||||
|
||||
bar.drawer = &font.Drawer{
|
||||
Dst: bar.img,
|
||||
Face: face,
|
||||
}
|
||||
|
||||
bar.blocks = new(sync.Map)
|
||||
bar.redraw = make(chan *Block)
|
||||
|
||||
@ -111,6 +119,17 @@ func initBar(x, y, w, h int) (*Bar, error) {
|
||||
return true
|
||||
}
|
||||
|
||||
// XXX: Hack for clock block.
|
||||
if name == "clock" {
|
||||
tw := bar.drawer.MeasureString(block.txt).Ceil()
|
||||
if ev.EventX >= int16(((bar.w/2)-(tw/2))-13) && ev.
|
||||
EventX < int16(((bar.w/2)+(tw/2))+13) {
|
||||
return false
|
||||
}
|
||||
block = nil
|
||||
return true
|
||||
}
|
||||
|
||||
if ev.EventX >= int16(block.x) && ev.EventX < int16(block.x+block.
|
||||
w) {
|
||||
return false
|
||||
@ -132,15 +151,9 @@ func initBar(x, y, w, h int) (*Bar, error) {
|
||||
}
|
||||
|
||||
func (bar *Bar) draw(block *Block) error {
|
||||
d := &font.Drawer{
|
||||
Dst: block.img,
|
||||
Src: image.NewUniform(hexToBGRA(block.fg)),
|
||||
Face: face,
|
||||
}
|
||||
|
||||
// Calculate the required x coordinate for the different aligments.
|
||||
var x int
|
||||
tw := d.MeasureString(block.txt).Ceil()
|
||||
tw := bar.drawer.MeasureString(block.txt).Ceil()
|
||||
switch block.align {
|
||||
case 'l':
|
||||
x = block.x
|
||||
@ -168,9 +181,12 @@ func (bar *Bar) draw(block *Block) error {
|
||||
return hexToBGRA(block.bg)
|
||||
})
|
||||
|
||||
// Set text color.
|
||||
bar.drawer.Src = image.NewUniform(hexToBGRA(block.fg))
|
||||
|
||||
// Draw the text.
|
||||
d.Dot = fixed.P(x, 18)
|
||||
d.DrawString(block.txt)
|
||||
bar.drawer.Dot = fixed.P(x, 18)
|
||||
bar.drawer.DrawString(block.txt)
|
||||
|
||||
// Redraw the bar.
|
||||
block.img.XDraw()
|
||||
|
30
blocks.go
30
blocks.go
@ -4,6 +4,7 @@ import (
|
||||
"bufio"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"strconv"
|
||||
"time"
|
||||
@ -25,6 +26,23 @@ func (bar *Bar) clock() {
|
||||
// Notify that the next block can be initialized.
|
||||
bar.ready <- true
|
||||
|
||||
// Show popup on clicking the left mouse button.
|
||||
block.actions["button1"] = func() error {
|
||||
if block.popup != nil {
|
||||
block.popup = block.popup.destroy()
|
||||
return nil
|
||||
}
|
||||
|
||||
var err error
|
||||
block.popup, err = initPopup((bar.w/2)-(178/2), 29, 178, 129, "#EEEEEE",
|
||||
"#021B21")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return block.popup.clock()
|
||||
}
|
||||
|
||||
for {
|
||||
// Compose block text.
|
||||
txt := time.Now().Format("Monday, January 2th 03:04 PM")
|
||||
@ -147,6 +165,14 @@ func (bar *Bar) todo() {
|
||||
// Notify that the next block can be initialized.
|
||||
bar.ready <- true
|
||||
|
||||
// Show popup on clicking the left mouse button.
|
||||
block.actions["button1"] = func() error {
|
||||
cmd := exec.Command("st", "micro", "-savecursor", "false", path.Join(
|
||||
basedir.Home, ".todo"))
|
||||
cmd.Stdout = os.Stdout
|
||||
return cmd.Run()
|
||||
}
|
||||
|
||||
// Watch file for events.
|
||||
w, err := fsnotify.NewWatcher()
|
||||
if err != nil {
|
||||
@ -226,9 +252,7 @@ func (bar *Bar) window() {
|
||||
txt = "?"
|
||||
}
|
||||
}
|
||||
if len(txt) > 34 {
|
||||
txt = txt[0:34] + "..."
|
||||
}
|
||||
txt = trim(txt, 34)
|
||||
|
||||
// Redraw block.
|
||||
if block.diff(txt) {
|
||||
|
BIN
box/images/clock-popup-bg.png
Normal file
BIN
box/images/clock-popup-bg.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 241 B |
Binary file not shown.
Before Width: | Height: | Size: 240 B |
4
main.go
4
main.go
@ -73,11 +73,11 @@ func initFont() error {
|
||||
fr := func(name string) ([]byte, error) {
|
||||
return box.Find(path.Join("fonts", name))
|
||||
}
|
||||
font, err := box.Find("fonts/cure.font")
|
||||
fp, err := box.Find("fonts/cure.font")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
face, err = plan9font.ParseFont(font, fr)
|
||||
face, err = plan9font.ParseFont(fp, fr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
25
popup.go
25
popup.go
@ -7,6 +7,7 @@ import (
|
||||
"github.com/BurntSushi/xgbutil/ewmh"
|
||||
"github.com/BurntSushi/xgbutil/xgraphics"
|
||||
"github.com/BurntSushi/xgbutil/xwindow"
|
||||
"golang.org/x/image/font"
|
||||
)
|
||||
|
||||
// Popup is a struct with information about the popup.
|
||||
@ -21,9 +22,8 @@ type Popup struct {
|
||||
// The foreground and background colors in hex.
|
||||
bg, fg string
|
||||
|
||||
// A channel where the popup should be send to to once its ready
|
||||
// to be redrawn.
|
||||
redraw chan *Popup
|
||||
// Text drawer.
|
||||
drawer *font.Drawer
|
||||
}
|
||||
|
||||
func initPopup(x, y, w, h int, bg, fg string) (*Popup, error) {
|
||||
@ -77,16 +77,31 @@ func initPopup(x, y, w, h int, bg, fg string) (*Popup, error) {
|
||||
popup.bg = bg
|
||||
popup.fg = fg
|
||||
|
||||
popup.redraw = make(chan *Popup)
|
||||
popup.drawer = &font.Drawer{
|
||||
Dst: popup.img,
|
||||
Face: face,
|
||||
}
|
||||
|
||||
// Color the background.
|
||||
popup.img.For(func(cx, cy int) xgraphics.BGRA {
|
||||
return hexToBGRA(popup.bg)
|
||||
})
|
||||
|
||||
// Draw the popup.
|
||||
popup.draw()
|
||||
|
||||
return popup, nil
|
||||
}
|
||||
|
||||
func (popup *Popup) draw() {
|
||||
popup.img.XDraw()
|
||||
popup.img.XPaint(popup.win.Id)
|
||||
}
|
||||
|
||||
// TODO: I don't know if this actually frees memory and shit.
|
||||
func (popup *Popup) destroy() *Popup {
|
||||
popup.win.Destroy()
|
||||
popup.img.Destroy()
|
||||
close(popup.redraw)
|
||||
popup = nil
|
||||
|
||||
return popup
|
||||
|
187
popups.go
187
popups.go
@ -1,27 +1,29 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"image"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"strconv"
|
||||
|
||||
"github.com/BurntSushi/xgbutil/xgraphics"
|
||||
"github.com/antchfx/xmlquery"
|
||||
"github.com/fhs/gompd/mpd"
|
||||
"github.com/rkoesters/xdg/userdirs"
|
||||
"golang.org/x/image/font"
|
||||
"golang.org/x/image/math/fixed"
|
||||
)
|
||||
|
||||
// TODO: Make progressbar clickable.
|
||||
// TODO: Make progressbar update every X milliseconds.
|
||||
func (popup *Popup) music(c *mpd.Client) error {
|
||||
d := &font.Drawer{
|
||||
Dst: popup.img,
|
||||
Src: image.NewUniform(hexToBGRA(popup.fg)),
|
||||
Face: face,
|
||||
}
|
||||
|
||||
// Color the background.
|
||||
popup.img.For(func(cx, cy int) xgraphics.BGRA {
|
||||
return hexToBGRA(popup.bg)
|
||||
@ -36,31 +38,47 @@ func (popup *Popup) music(c *mpd.Client) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Draw album info text.
|
||||
d.Dot = fixed.P(10, 20)
|
||||
d.DrawString("Album: " + cur["Album"])
|
||||
d.Dot = fixed.P(10, 20+16)
|
||||
d.DrawString("Artist: " + cur["AlbumArtist"])
|
||||
d.Dot = fixed.P(10, 20+16+16)
|
||||
d.DrawString("Date: " + cur["Date"])
|
||||
// Set text color.
|
||||
popup.drawer.Src = image.NewUniform(hexToBGRA(popup.fg))
|
||||
|
||||
// Find album art.
|
||||
var f interface{}
|
||||
f, err = os.Open(path.Join(userdirs.Music, path.Dir(
|
||||
cur["file"]), "cover_popup.png"))
|
||||
if err != nil {
|
||||
f, err = box.Open("images/cover.png")
|
||||
// Draw album text.
|
||||
album := trim(cur["Album"], 32)
|
||||
popup.drawer.Dot = fixed.P(-(popup.drawer.MeasureString(album).Ceil()/2)+82,
|
||||
48)
|
||||
popup.drawer.DrawString(album)
|
||||
|
||||
// Draw artist text.
|
||||
artist := trim("Artist: "+cur["AlbumArtist"], 32)
|
||||
popup.drawer.Dot = fixed.P(-(popup.drawer.MeasureString(artist).Ceil()/2)+
|
||||
82, 58+16)
|
||||
popup.drawer.DrawString(artist)
|
||||
|
||||
// Draw rlease date text.
|
||||
date := trim("Release date: "+cur["Date"], 32)
|
||||
popup.drawer.Dot = fixed.P(-(popup.drawer.MeasureString(date).Ceil()/2)+82,
|
||||
58+16+16)
|
||||
popup.drawer.DrawString(date)
|
||||
|
||||
// Check if album art file exists.
|
||||
fp := path.Join(userdirs.Music, path.Dir(cur["file"]), "cover_popup.png")
|
||||
if _, err := os.Stat(fp); !os.IsNotExist(err) {
|
||||
f, err := os.Open(fp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
// Draw album art.
|
||||
img, _, err := image.Decode(f.(io.Reader))
|
||||
if err != nil {
|
||||
return err
|
||||
// Draw album art.
|
||||
img, _, err := image.Decode(f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
xgraphics.Blend(popup.img, xgraphics.NewConvert(X, img), image.Point{
|
||||
-166, -10})
|
||||
} else {
|
||||
popup.drawer.Dot = fixed.P(200, 78)
|
||||
popup.drawer.DrawString("No cover found!")
|
||||
}
|
||||
xgraphics.Blend(popup.img, img, image.Point{-166, -10})
|
||||
|
||||
// Calculate progressbar lengths.
|
||||
e, err := strconv.ParseFloat(sts["elapsed"], 32)
|
||||
@ -75,19 +93,120 @@ func (popup *Popup) music(c *mpd.Client) error {
|
||||
pu := 29 - pf
|
||||
|
||||
// Draw progressbar.
|
||||
d.Dot = fixed.P(10, 132)
|
||||
d.Src = image.NewUniform(hexToBGRA("#5394C9"))
|
||||
popup.drawer.Dot = fixed.P(10, 132)
|
||||
for i := 1; i <= pf; i++ {
|
||||
d.DrawString("-")
|
||||
popup.drawer.DrawString("-")
|
||||
}
|
||||
d.Src = image.NewUniform(hexToBGRA(popup.fg))
|
||||
popup.drawer.Src = image.NewUniform(hexToBGRA("#72A7D3"))
|
||||
for i := 1; i <= pu; i++ {
|
||||
d.DrawString("-")
|
||||
popup.drawer.DrawString("-")
|
||||
}
|
||||
|
||||
// Draw the popup.
|
||||
popup.img.XDraw()
|
||||
popup.img.XPaint(popup.win.Id)
|
||||
// Redraw the bar.
|
||||
popup.draw()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (popup *Popup) clock() error {
|
||||
// Color the background.
|
||||
f, err := box.Open("images/clock-popup-bg.png")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
// Draw album art.
|
||||
bg, _, err := image.Decode(f.(io.Reader))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
xgraphics.Blend(popup.img, xgraphics.NewConvert(X, bg), image.Point{0, 0})
|
||||
|
||||
// Redraw the popup.
|
||||
popup.draw()
|
||||
|
||||
// Set location.
|
||||
lat := "52.0646"
|
||||
lon := "5.2065"
|
||||
|
||||
// Get rainfall information.
|
||||
r, err := http.Get("https://gps.buienradar.nl/getrr.php?lat=" + lat +
|
||||
"&lon=" + lon)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer r.Body.Close()
|
||||
|
||||
// Create rainfall tmp files.
|
||||
td, err := ioutil.TempFile(os.TempDir(), "melonbar-rain-*.dat")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer os.Remove(td.Name())
|
||||
ti, err := ioutil.TempFile(os.TempDir(), "melonbar-rain-*.png")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer os.Remove(ti.Name())
|
||||
|
||||
// Compose rainfall data tmp file contents.
|
||||
var d []byte
|
||||
s := bufio.NewScanner(r.Body)
|
||||
for s.Scan() {
|
||||
d = append(d, bytes.Split(s.Bytes(), []byte("|"))[0]...)
|
||||
d = append(d, []byte("\n")...)
|
||||
}
|
||||
|
||||
// Write rainfall data tmp file.
|
||||
if _, err = td.Write(d); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := td.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create rainfall graph.
|
||||
cmd := exec.Command("gnuplot", "-e", `
|
||||
set terminal png transparent size 211,107;
|
||||
set output '`+ti.Name()+`';
|
||||
set yrange [0:255];
|
||||
set noborder;
|
||||
set nolabel;
|
||||
set nokey;
|
||||
set notics;
|
||||
set notitle;
|
||||
set style fill solid border rgb '#5394C9';
|
||||
plot '`+td.Name()+`' smooth csplines with filledcurve x1 lc rgb '#72A7D3'
|
||||
`)
|
||||
if err := cmd.Run(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Draw rainfall graph.
|
||||
img, _, err := image.Decode(ti)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
xgraphics.Blend(popup.img, xgraphics.NewConvert(X, img), image.Point{14, 0})
|
||||
|
||||
// Redraw the popup.
|
||||
popup.draw()
|
||||
|
||||
// Get weather information.
|
||||
x, err := xmlquery.LoadURL("https://xml.buienradar.nl")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w := xmlquery.FindOne(x, "//weerstation[@id=6260]")
|
||||
fmt.Println()
|
||||
popup.drawer.Src = image.NewUniform(hexToBGRA(popup.fg))
|
||||
popup.drawer.Dot = fixed.P(10, 100)
|
||||
popup.drawer.DrawString("Rainfall graph, it's " + w.SelectElement(
|
||||
"temperatuurGC").InnerText() + "ºC")
|
||||
|
||||
// Redraw the popup.
|
||||
popup.draw()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
8
util.go
8
util.go
@ -13,3 +13,11 @@ func hexToBGRA(h string) xgraphics.BGRA {
|
||||
|
||||
return xgraphics.BGRA{B: d[2], G: d[1], R: d[0], A: 0xFF}
|
||||
}
|
||||
|
||||
// TODO: Instead of doing this using rune-count, do this using pixel-count.
|
||||
func trim(txt string, l int) string {
|
||||
if len(txt) > l {
|
||||
return txt[0:l] + "..."
|
||||
}
|
||||
return txt
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user