frame

package module
v0.6.10 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 21, 2018 License: BSD-3-Clause Imports: 10 Imported by: 9

README

Frame

Go Report Card

Synopsis

Package frame implements graphical, editable text widgets compatible with Plan 9's libframe(3). Unlike libframe, the text is byte-addressed and preserves NUL terminated strings. The related github.com/as/font package provides a superset of the golang.org/x/font.Face interface and implements additional functionality for working with Go fonts and frames.

paint

Installation

	go get -d -u github.com/as/frame/...

Updates

NOTE: The API has changed since this README.md was updated.

  • The font functionality is no longer embedded in the frame package
  • The frame.New constructor package function has been modified to take a Config struct

Run the provided gofix program under to programatically update your packages:

	go get -u github.com/as/frame/...
	go install github.com/as/frame/framefix
	framefix github.com/as/ui

Description

A Frame is a graphical text container. It draws text on a bitmap, using previously-drawn text as a cache.

Create one using New:

  dst := image.NewRGBA( image.Rect(0,0,100,100), 
  f := frame.New(dst, dst.Bounds(), &Config struct {
		Color: frame.Mono,
        Font : font.NewFace(12), 
   }

Rendering

The most frequent operations are Insert and Delete. Insert renders text at a given offset without overwriting existing text. Delete deletes a range of text and moves existing text after it into its range. Ranges are defined by two integers and behave equivalently to Go slice indices.

Insert and delete are inverses.

f.Insert([]byte("hello world."), 0)
f.Delete(0, 11)

Projection

PointOf projects the index of a character to a 2D image.Point on the image. IndexOf does the opposite, projecting an index to a point.

They are also inverse operations.

	f.InsertString("hello")
	f.IndexOf(f.PointOf(4))	// returns: 4
	f.PointOf(f.IndexOf(image.Pt(25,25))) // returns: (25, 25)

There is no method for extracting the values of characters in the frame. The data structures are designed to be fast write-only containers.

Selection

Frames select a continuous range of text with Select. The currently-selected range is queried with Dot.

	f.InsertString("hello")
	f.Select(0,2)
	f.Dot()	// returns (0,2)

Drawing

Because the bitmap is an arbitrary image and also a living cache of glyphs, drawing on the bitmap between rendering operations persists on the underlying glyphs. There are a few ways to re-render the bitmap or a region of it.

Recolor(pt image.Point, p0, p1 int64, cols Palette)
  Recolor colors the range p0:p1 by redrawing the foreground, background, and font glyphs

Redraw(pt image.Point, p0, p1 int64, issel bool)
  Redraw redraws the characters between p0:p1. It accesses the cache of drawn glyph widths
  to avoid remeasuring strings

RedrawAt(pt image.Point, text, back image.Image)
  RedrawAt refreshes the entire image to the right of the given pt. Everything below is redrawn.

Refresh()
  Refresh recomputes the state of the frame from scratch. This is an expensive operation compared
  to redraw

Paint(pt0, pt1 image.Point, col image.Image)
  Paint paints the color col on the frame at points pt0-pt1. The result is a Z shaped fill
  consisting of at-most 3 rectangles. No text is redrawn.

Examples

Feature Set

  • UTF8
  • ASCII
  • Elastic tabstops
  • Semantic replacement characters

Note

A frame's text is not addressable. Once the characters are written to the frame, there is no mechanism to retrieve value from within the frame. Use a buffer to store text for reading and the range addresses of the frame to access bytes from that buffer.

See github.com/as/ui/win for an example.

See Also

http://doc.cat-v.org/plan_9/4th_edition/papers/sam/

Specifically, the section Data structures in the terminal served as a guide

Documentation

Overview

Package frame provides plan9-like editable text images on a raster display. This implementation preserves NUL bytes, and uses a set of replacement characters for unrenderable text glyphs generated with a smaller sized font (hexadecimal or ascii representation).

A frame's text is not addressable. Once the characters are written to the frame, there is no mechanism to retrieve their position from within the frame. Use a buffer to store text for reading and the range addresses of the frame to access bytes from that buffer.

See github.com/as/ui/win for an example.

A frame is created using the New function

img := image.NewRGBA(image.Rect(0,0,100,100))
fr := frame.New(img, img.Bounds(), frame.NewGoMono(), frame.Mono)

A frame supports these common operations

Insert: Insert text
Delete: Delete text
IndexOf: Index for point
PointOf: Point for index
Select: Select range
Dot: Return selected range

Insert and Delete

Frames supports two operations for rendering text: Insert and Delete. Insert inserts text at the given index and moves existing characters after the index to the right. Delete deletes text in the given range (a range is a pair of indices) and moves existing character after the index to the left.

The two operations are inverses of each other.

fr.Insert([]byte("hello world."), 0)
fr.Delete(0, 11)

Insert and delete return the number of characters inserted or deleted.

To delete the last insertion:

p0 := 0
n := fr.Insert([]byte("123"), p0)
fr.Delete(p0, p0+n)

To execute a traditional "write" operation:

s := []byte("hello")
fr.Delete(0, int64(len(s)))
fr.Insert(s, 0)

Projection

Frames can translate between coordinates of the mouse and character offsets in the frame itself using IndexOf and PointOf.

p0  := fr.IndexOf(image.Pt(0, 0)) // Returns the index under the 2D point (0,0)
pt0 := fr.PointOf(5) // Returns the 2D point over the index

Selection

Frames support selecting ranges of text along with returning those selected ranges.

fr.Select(p0, p1)
fr.Dot()

A more complicated facility exists for making a live selection. See example/basic for an example of how to use it.

fr.Sweep(...)

Drawing

No special operations are needed after a call to Insert, Delete, or Select. The frame's bitmap is updated. However, there are four functions that will redraw the frame on the bitmap if this is necessary.

Recolor(pt image.Point, p0, p1 int64, cols Palette)

Recolor colors the range p0:p1 by redrawing the foreground, background, and font glyphs

Redraw(pt image.Point, p0, p1 int64, issel bool)

Redraw redraws the characters between p0:p1. It accesses the cache of drawn glyph widths
to avoid remeasuring strings

RedrawAt(pt image.Point, text, back image.Image)

RedrawAt refreshes the entire image to the right of the given pt. Everything below is redrawn.

Refresh()

Refresh recomputes the state of the frame from scratch. This is an expensive operation compared
to redraw

Display Sync

After any operation that alters the frame, one can be sure that the changes can be written to the frame's bitmap. However, the same can not be said for the exp/shiny window. There currently exists an optimization (see github.com/as/drawcache) that caches rectangles that need to be redrawn to the screen. This is because shiny (or the native drivers for it) are too slow to refresh the entire window is that window's resolution is very high.

This rendering pipeline is bottlenecked, so an optimization is located between the |*|

insert | frame | shiny buffer |*| shiny window

Index

Constants

View Source
const (
	FrElastic = 1 << iota
	FrUTF8
)
View Source
const (
	TickOff = 0
	TickOn  = 1
)

Variables

View Source
var (
	Yellow = solid(255, 255, 224)
	Green  = solid(0x99, 0xCC, 0x99)
	Red    = solid(0xCC, 0x99, 0x99)
	Gray   = solid(0x12, 0x12, 0x12)
	Mauve  = solid(0x99, 0x99, 0xDD)

	Ozone     = solid(216, 216, 232)
	Strata    = solid(248, 242, 248)
	AntiPeach = solid(0, 12, 24)
	Peach     = solid(255, 248, 232)

	BBody = solid(243, 248, 254)
	BTag  = solid(214, 230, 252)
	GBody = solid(226, 235, 232)
	GTag  = solid(226, 225, 232)
	PTag  = solid(222, 207, 236)
	PBody = solid(252, 232, 252)

	MMauve = solid(0x66, 0x55, 0x88)
	MTagG  = solid(28-10, 31-13, 38-15)
	MTagC  = MTagW
	MTagW  = solid(28, 31, 38)
	MBodyW = solid(43, 50, 59)
	MTextW = solid(255-59, 255-50, 255-43)
)
View Source
var (
	Acme = Color{
		Palette: Palette{Text: Gray, Back: Yellow},
		Hi:      Palette{Text: image.White, Back: Mauve},
	}
	Mono = Color{
		Palette: Palette{Text: image.Black, Back: image.White},
		Hi:      Palette{Text: image.White, Back: image.Black},
	}
	A = Color{
		Palette: Palette{
			Text: AntiPeach,
			Back: Peach,
		},
		Hi: Palette{
			Back: Mauve,
			Text: image.White,
		},
	}
	ATag0 = Color{
		Palette: Palette{
			Text: Gray,
			Back: Ozone,
		},
		Hi: Palette{
			Back: Mauve,
			Text: image.White,
		},
	}
	ATag1 = Color{
		Palette: Palette{
			Text: Gray,
			Back: Strata,
		},
		Hi: Palette{
			Back: Mauve,
			Text: image.White,
		},
	}
)
View Source
var (
	ForceElastic bool
	ForceUTF8    bool
)
View Source
var (
	ErrBadDst = errors.New("bad dst")
)

Functions

func Printable

func Printable(b byte) bool

Types

type Color

type Color struct {
	Palette
	Hi Palette
}

type Config

type Config struct {
	Flag   int
	Scroll func(int)
	Color  Color
	Face   font.Face
	Drawer Drawer
}

type Drawer

type Drawer interface {
	Draw(dst draw.Image, r image.Rectangle, src image.Image, sp image.Point, op draw.Op)

	// StringBG draws a string to dst at point p
	StringBG(dst draw.Image, p image.Point, src image.Image, sp image.Point, ft font.Face, s []byte, bg image.Image, bgp image.Point) int

	// Flush requests that prior calls to the draw and string methods are flushed from an underlying soft-screen. The list of rectangles provide
	// optional residency information. Implementations may refresh a superset of r, or ignore it entirely, as long as the entire region is
	// refreshed
	Flush(r ...image.Rectangle) error
}

Drawer implements the set of methods a frame needs to draw on a draw.Image. The frame's default behavior is to use the native image/draw package and x/exp/font packages to satisfy this interface.

func NewDefaultDrawer

func NewDefaultDrawer() Drawer

type EventPipe

type EventPipe interface {
	Send(e interface{})
	SendFirst(e interface{})
	NextEvent() interface{}
}

type Frame

type Frame struct {
	box.Run

	Face Face
	Color
	Ticked bool
	Scroll func(int)
	Drawer
	// contains filtered or unexported fields
}

Frame is a write-only container for editable text

func New

func New(dst draw.Image, r image.Rectangle, conf *Config) *Frame

func (*Frame) Bounds

func (f *Frame) Bounds() image.Rectangle

Bounds returns the frame's clipping rectangle

func (*Frame) Close

func (f *Frame) Close() error

Close closes the frame

func (*Frame) Config

func (f *Frame) Config() *Config

func (*Frame) Delete

func (f *Frame) Delete(p0, p1 int64) int

Delete deletes the range [p0:p1) and returns the number of characters deleted

func (*Frame) Dirty

func (f *Frame) Dirty() bool

Dirty returns true if the contents of the frame have changes since the last redraw

func (*Frame) Dot

func (f *Frame) Dot() (p0, p1 int64)

Dot returns the range of the selected text

func (*Frame) Draw

func (f *Frame) Draw(dst draw.Image, r image.Rectangle, src image.Image, sp image.Point, op draw.Op)

func (*Frame) Flags

func (f *Frame) Flags() int

Flags returns the flags currently set for the frame

func (*Frame) Full

func (f *Frame) Full() bool

Full returns true if the last line in the frame is full.

func (*Frame) Grid

func (f *Frame) Grid(pt image.Point) image.Point

Grid returns a grid-aligned point on the frame relative to pt

func (*Frame) IndexOf

func (f *Frame) IndexOf(pt image.Point) (p int64)

IndexOf returns the chracter index under the point pt.

func (*Frame) Insert

func (f *Frame) Insert(s []byte, p0 int64) (wrote int)

Insert inserts the contents of s at index p0 in the frame and returns the number of characters written.

func (*Frame) Len

func (f *Frame) Len() int64

Len returns the number of bytes currently in the frame

func (*Frame) Line

func (f *Frame) Line() int

Line returns the number of wrapped lines currently in the frame

func (*Frame) Mark

func (f *Frame) Mark()

Mark marks the frame as dirty

func (*Frame) MaxLine

func (f *Frame) MaxLine() int

Maxline returns the max number of wrapped lines fitting on the frame

func (*Frame) Paint

func (f *Frame) Paint(p0, p1 image.Point, col image.Image)

Paint paints the color col on the frame at points pt0-pt1. The result is a Z shaped fill consisting of at-most 3 rectangles. No text is redrawn.

func (*Frame) PointOf

func (f *Frame) PointOf(p int64) image.Point

PointOf returns the point on the closest to index p.

func (*Frame) RGBA

func (f *Frame) RGBA() *image.RGBA

func (*Frame) Recolor

func (f *Frame) Recolor(pt image.Point, p0, p1 int64, cols Palette)

Recolor redraws the range p0:p1 with the given palette

func (*Frame) Redraw

func (f *Frame) Redraw(pt image.Point, p0, p1 int64, issel bool)

Redraw draws the range [p0:p1] at the given pt.

func (*Frame) RedrawAt

func (f *Frame) RedrawAt(pt image.Point, text, back image.Image)

RedrawAt renders the frame's bitmap starting at pt and working downwards.

func (*Frame) Refresh

func (f *Frame) Refresh()

Refresh renders the entire frame, including the underlying bitmap. Refresh should not be called after insertion and deletion unless the frame's RGBA bitmap was painted over by another draw operation.

func (*Frame) Reset

func (f *Frame) Reset(r image.Rectangle, b *image.RGBA, ft font.Face)

Reset resets the frame to display on image b with bounds r and font ft.

func (*Frame) Select

func (f *Frame) Select(p0, p1 int64)

Select selects the region [p0:p1). The operation highlights the range of text under that region. If p0 = p1, a tick is drawn to indicate a null selection.

func (*Frame) SetDirty

func (f *Frame) SetDirty(dirty bool)

SetDirty alters the frame's internal state

func (*Frame) SetFlags

func (f *Frame) SetFlags(flags int)

Flag sets the flags for the frame. At this time only FrElastic is supported.

func (*Frame) SetFont

func (f *Frame) SetFont(ft font.Face)

func (*Frame) SetOp

func (f *Frame) SetOp(op draw.Op)

func (*Frame) SetTick

func (f *Frame) SetTick(style int)

func (*Frame) Size

func (f *Frame) Size() image.Point

func (*Frame) Sweep

func (f *Frame) Sweep(ep EventPipe, flush func())

Sweep reads a sequence of mouse.Events from the event pipe and uses the flush functions to draw a live selection. Control is transfered back to the caller after a release event is processed.

func (*Frame) Tick

func (f *Frame) Tick()

func (*Frame) Untick

func (f *Frame) Untick()

type Palette

type Palette struct {
	Text, Back image.Image
}

type Projector

type Projector interface {
	PointOf(int64) image.Point
	IndexOf(image.Point) int64
}

type ScrollEvent

type ScrollEvent struct {
}

type Selector

type Selector interface {
	Select(p0, p1 int64)
	Dot() (p0, p1 int64)
}

type Sweeper

type Sweeper interface {
	Projector
	Selector
}

Directories

Path Synopsis
example
Fix finds Go programs that use old APIs and rewrites them to use newer ones.
Fix finds Go programs that use old APIs and rewrites them to use newer ones.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL