bar.go (3440B)
1 package main 2 3 import ( 4 "image" 5 "errors" 6 "image/color" 7 8 "hhvn.uk/hbspbar/config" 9 "hhvn.uk/hbspbar/status" 10 "hhvn.uk/hbspbar/bspc" 11 "hhvn.uk/hbspbar/drw" 12 ) 13 14 var bars map[int]*bar = make(map[int]*bar) 15 16 type bar struct { 17 id int 18 w *drw.Window 19 i *image.RGBA 20 } 21 22 var ( 23 ErrNoState = errors.New("attempted to create a bar with uninitialized state") 24 ErrNoSuchBar = errors.New("attempted to destroy non-existant bar") 25 ) 26 27 func (b *bar) init(id int, state *bspc.State) error { 28 b.id = id 29 b.i = nil 30 31 mon, err := b.getmon(state) 32 if err != nil { return err } 33 34 go mon.TopPadding(config.H) 35 36 geom := mon.Rectangle 37 38 b.w, err = drw.WindowCreate(geom.X, geom.Y, geom.Width, config.H) 39 if err != nil { return err } 40 41 rect := image.Rect(0, 0, int(mon.Rectangle.Width), int(config.H)) 42 b.i = image.NewRGBA(rect) 43 44 return nil 45 } 46 47 func (b *bar) destroy(state *bspc.State) { 48 mon, _ := b.getmon(state) 49 if (mon != nil) { 50 mon.TopPadding(0) 51 } 52 } 53 54 func (b bar) getmon(state *bspc.State) (*bspc.Monitor, error) { 55 return state.GetMon(b.id) 56 } 57 58 func (b *bar) drawText(x int, col color.Color, text string) (int, error) { 59 return drw.DrawText(b.i, x, col, text) 60 } 61 62 func (b *bar) drawRect(x, y, w, h int, c color.Color, fill bool) { 63 drw.DrawRect(b.i, x, y, w, h, c, fill) 64 } 65 66 func (b bar) draw(state *bspc.State, blocks []*status.Block) error { 67 var bg color.Color 68 var filled bool 69 70 if blocks == nil { 71 return nil 72 } 73 74 mon, err := b.getmon(state) 75 if err != nil { 76 return err 77 } 78 79 // Dimensions of drawing space 80 cx := 0 81 w := int(mon.Rectangle.Width) 82 h := int(config.H) 83 84 85 // Draw background 86 b.drawRect(0, 0, w, h, config.Bg, true) 87 88 // Monitor 89 montext := mon.Name 90 monw := 6 + drw.TextWidth(montext) + 8 91 92 if mon.Focused { 93 bg = config.Sel 94 } else { 95 bg = config.UnselMon 96 } 97 98 b.drawRect(cx, 0, monw, h, bg, true) 99 b.drawText(cx + 6, config.Fg, montext) 100 cx += monw 101 102 // Desktops 103 boxw := 4 104 ds := len(mon.Desktops) 105 dw := 4 + (4 + boxw + 2 + 3) * ds + 5 106 107 for i := 0; i < ds; i++ { 108 dw += drw.TextWidth(mon.Desktops[i].Name) 109 } 110 111 cx += 4 112 for i := 0; i < ds; i++ { 113 d := mon.Desktops[i] 114 115 cx += 5 116 117 switch { 118 case d.Urgent(): bg = config.Urg 119 case d.Focused: bg = config.Sel 120 default: bg = config.FgDark 121 } 122 123 filled = d.Root != nil 124 125 b.drawRect(cx, 3, boxw, h - 7, bg, filled) 126 cx += boxw + 2 127 ax, _ := b.drawText(cx, config.Fg, d.Name) 128 cx += ax + 2 129 } 130 131 cx = int(mon.Rectangle.Width) 132 for _, s := range blocks { 133 if s != nil { 134 cx -= s.W 135 cx -= config.StatusPad 136 } 137 } 138 139 b.drawRect(cx, 0, int(mon.Rectangle.Width) - cx, int(config.H), 140 config.Status, true) 141 142 cx += config.StatusPad / 2 143 144 for _, s := range blocks { 145 if s != nil { 146 drw.AddImg(b.i, cx, s.W, s.I) 147 148 cx += s.W + config.StatusPad 149 } 150 } 151 152 b.w.Paint(b.i) 153 154 return nil 155 } 156 157 func Create(state *bspc.State, id int) (error) { 158 var b bar 159 160 if state == nil { 161 return ErrNoState 162 } 163 164 if _, ok := bars[id]; ok { 165 // Already created, whatever. 166 return nil 167 } 168 169 if err := b.init(id, state); err != nil { 170 return err 171 } 172 173 bars[b.id] = &b 174 return nil 175 } 176 177 func Redraw(state *bspc.State, blocks []*status.Block) { 178 for _, b := range bars { 179 b.draw(state, blocks) 180 } 181 } 182 183 func Destroy(state *bspc.State, id int) error { 184 b, ok := bars[id] 185 if !ok { 186 return ErrNoSuchBar 187 } 188 189 b.destroy(state) 190 delete(bars, id) 191 192 return nil 193 } 194 195 func Cleanup(state *bspc.State) { 196 if state != nil { 197 for _, b := range bars { 198 b.destroy(state) 199 } 200 } 201 }