func main() { X, err := xgbutil.NewConn() if err != nil { log.Fatal(err) } // Load some font. You may need to change the path depending upon your // system configuration. fontReader, err := os.Open(fontPath) if err != nil { log.Fatal(err) } // Now parse the font. font, err := xgraphics.ParseFont(fontReader) if err != nil { log.Fatal(err) } // Create some canvas. ximg := xgraphics.New(X, image.Rect(0, 0, canvasWidth, canvasHeight)) ximg.For(func(x, y int) xgraphics.BGRA { return bg }) // Now write the text. _, _, err = ximg.Text(10, 10, fg, size, font, msg) if err != nil { log.Fatal(err) } // Compute extents of first line of text. _, firsth := xgraphics.Extents(font, size, msg) // Now show the image in its own window. win := ximg.XShowExtra("Drawing text using xgraphics", true) // Now draw some more text below the above and demonstrate how to update // only the region we've updated. _, _, err = ximg.Text(10, 10+firsth, fg, size, font, "Some more text.") if err != nil { log.Fatal(err) } // Now compute extents of the second line of text, so we know which region // to update. secw, sech := xgraphics.Extents(font, size, "Some more text.") // Now repaint on the region that we drew text on. Then update the screen. bounds := image.Rect(10, 10+firsth, 10+secw, 10+firsth+sech) ximg.SubImage(bounds).XDraw() ximg.XPaint(win.Id) // All we really need to do is block, which could be achieved using // 'select{}'. Invoking the main event loop however, will emit error // message if anything went seriously wrong above. xevent.Main(X) }
// NewInput constructs Input values. It needs an X connection, a parent window, // the width of the input box, and theme information related for the font // and background. Padding separating the text and the edges of the window // may also be specified. // // While NewInput returns an *Input, a Input value also has an xwindow.Window // value embedded into it. Thus, an Input can also be treated as a normal // window on which you can assign callbacks, close, destroy, etc. // // As with all windows, the Input window should be destroyed when it is no // longer in used. func NewInput(X *xgbutil.XUtil, parent xproto.Window, width int, padding int, font *truetype.Font, fontSize float64, fontColor, bgColor render.Color) *Input { _, height := xgraphics.Extents(font, fontSize, "M") width, height = width+2*padding, height+2*padding img := xgraphics.New(X, image.Rect(0, 0, width, height)) win := xwindow.Must(xwindow.Create(X, parent)) win.Listen(xproto.EventMaskKeyPress) win.Resize(width, height) ti := &Input{ Window: win, img: img, Text: make([]rune, 0, 50), font: font, fontSize: fontSize, fontColor: fontColor, bgColor: bgColor, padding: padding, } ti.Render() return ti }
// DrawText is a convenience function that will create a new image, render // the provided text to it, paint the image to the provided window, and resize // the window to fit the text snugly. // // An error can occur when rendering the text to an image. func DrawText(win *xwindow.Window, font *truetype.Font, size float64, fontClr, bgClr render.Color, text string) error { // BUG(burntsushi): If `text` is zero-length, very bad things happen. if len(text) == 0 { text = " " } // Over estimate the extents. ew, eh := xgraphics.Extents(font, size, text) // Create an image using the over estimated extents. img := xgraphics.New(win.X, image.Rect(0, 0, ew, eh)) xgraphics.BlendBgColor(img, bgClr.ImageColor()) // Now draw the text, grab the (x, y) position advanced by the text, and // check for an error in rendering. _, _, err := img.Text(0, 0, fontClr.ImageColor(), size, font, text) if err != nil { return err } // Resize the window to the geometry determined by (x, y). win.Resize(ew, eh) // Now draw the image to the window and destroy it. img.XSurfaceSet(win.Id) // subimg := img.SubImage(image.Rect(0, 0, ew, eh)) img.XDraw() img.XPaint(win.Id) img.Destroy() return nil }
// NewCycle creates a new prompt. As many prompts as you want can be created, // and they could even technically be shown simultaneously so long as at most // one of them is using a grab. (The grab will fail for the others and they // will not be shown.) // // CycleTheme and CycleConfig values can either use DefaultCycle{Theme,Config} // values found in this package, or custom ones can be created using // composite literals. func NewCycle(X *xgbutil.XUtil, theme *CycleTheme, config CycleConfig) *Cycle { cycle := &Cycle{ X: X, theme: theme, config: config, showing: false, selected: -1, grabMods: 0, } // Create all windows used for the base of the cycle prompt. // This obviously doesn't include the windows representing the items. cwin := func(p xproto.Window) *xwindow.Window { return xwindow.Must(xwindow.Create(X, p)) } cycle.win = cwin(X.RootWin()) cycle.bTop, cycle.bBot = cwin(cycle.win.Id), cwin(cycle.win.Id) cycle.bLft, cycle.bRht = cwin(cycle.win.Id), cwin(cycle.win.Id) // Make the top-level window override redirect so the window manager // doesn't mess with us. cycle.win.Change(xproto.CwOverrideRedirect, 1) // Set the colors of each window. cclr := func(w *xwindow.Window, clr render.Color) { w.Change(xproto.CwBackPixel, uint32(clr.Int())) } cclr(cycle.win, cycle.theme.BgColor) cclr(cycle.bTop, cycle.theme.BorderColor) cclr(cycle.bBot, cycle.theme.BorderColor) cclr(cycle.bLft, cycle.theme.BorderColor) cclr(cycle.bRht, cycle.theme.BorderColor) // Map the sub-windows once. (Real mapping only happens when // cycle.win is mapped.) cycle.bTop.Map() cycle.bBot.Map() cycle.bLft.Map() cycle.bRht.Map() // Connect the key response handler (i.e., the alt-tab'ing, canceling, etc.) cycle.keyResponse().Connect(X, X.Dummy()) // Guess the maximum font height. _, cycle.fontHeight = xgraphics.Extents( cycle.theme.Font, cycle.theme.FontSize, "A") return cycle }
func (c *Clock) Draw() { c.img.For(func(x, y int) xgraphics.BGRA { return c.Background }) now := time.Now().Format(c.Format) w, h := xgraphics.Extents(c.Font, c.FontSize, now) //println("OH MYYYY: ", w, h) c.img.Text((c.Width/2)-(w/2), (c.Height/2)-(h/2), c.Foreground, c.FontSize, c.Font, now) c.img.XDraw() c.img.XPaint(c.window.Id) }
func (f *Full) UpdateTitle() { if f == nil { return } title := f.client.Name() font := f.theme.Font fontSize := f.theme.FontSize aFontColor := f.theme.AFontColor.ImageColor() iFontColor := f.theme.IFontColor.ImageColor() ew, eh := xgraphics.Extents(font, fontSize, title) imgA := render.NewBorder(f.X, 0, render.NoColor, f.theme.ATitleColor, ew, f.theme.TitleSize, render.GradientVert, render.GradientRegular) imgI := render.NewBorder(f.X, 0, render.NoColor, f.theme.ITitleColor, ew, f.theme.TitleSize, render.GradientVert, render.GradientRegular) y := (f.theme.TitleSize - eh) / 2 _, _, err := imgA.Text(0, y, aFontColor, fontSize, font, title) if err != nil { logger.Warning.Printf("Could not draw window title for window %s "+ "because: %v", f.client, err) } _, _, err = imgI.Text(0, y, iFontColor, fontSize, font, title) if err != nil { logger.Warning.Printf("Could not draw window title for window %s "+ "because: %v", f.client, err) } width, height := ew, imgA.Bounds().Max.Y f.titleText.Create( imgA.SubImage(image.Rect(0, 0, width, height)), imgI.SubImage(image.Rect(0, 0, width, height))) f.titleText.MROpt(fW, 0, 0, width, 0) if f.client.State() == Active { f.titleText.Active() } else { f.titleText.Inactive() } }
func (i *Item) update(text string) { if text == i.displayed { return } else if i.displayed == "" { i.displayed = text } width, height := xgraphics.Extents(i.TrueType, i.Size, i.displayed) sub := i.image.SubImage(image.Rect(10, i.offset, 10+width, height+i.offset)) sub.ForExp(func(x, y int) (r, b, g, a uint8) { return 0x00, 0x00, 0x00, 0x00 }) sub.Text(10, i.offset, i.Color, i.Size, i.TrueType, text) sub.XDraw() sub.XExpPaint(i.window.Id, 10, i.offset) i.displayed = text }