Many minor popup improvements, add weather popup

This commit is contained in:
Camille Scholtz 2018-12-30 14:31:30 +01:00
parent 0b8a9d2e01
commit 9d5cf20d28
10 changed files with 238 additions and 54 deletions

@ -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

@ -2,3 +2,4 @@
* Fix weird `'` characters.
* Fix `?` character.
* Fix `\n` character.
* Fix and add `º` character.

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()

@ -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) {

Binary file not shown.

After

Width:  |  Height:  |  Size: 241 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 240 B

@ -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
}

@ -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

@ -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
}

@ -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
}