Compare commits

...

5 Commits

5 changed files with 178 additions and 3 deletions

View File

@ -11,6 +11,7 @@ type Application struct {
backend Backend backend Backend
config Config config Config
callbackManager CallbackManager callbackManager CallbackManager
imageManager ImageManager
} }
// Run initializes the application, starts it, and then returns a channel that // Run initializes the application, starts it, and then returns a channel that
@ -120,3 +121,21 @@ func (application *Application) Config () (config *Config) {
config = &application.config config = &application.config
return return
} }
// AddImage adds a new image buffer and returns a pointer to it.
func (application *Application) NewImage () (im *ColorImage) {
cellWidth, cellHeight := application.backend.CellMetrics()
im = &ColorImage {
cellWidth: cellWidth,
cellHeight: cellHeight,
}
application.imageManager.Add(im)
return
}
// Remove removes the specified image buffer, if the application has it. If the
// image was found and removed, removed will be true.
func (application *Application) RemoveImage (im *ColorImage) (removed bool) {
removed = application.imageManager.Remove(im)
return
}

View File

@ -8,11 +8,13 @@ type Backend interface {
SetTitle (title string) (err error) SetTitle (title string) (err error)
SetIcon (icons []image.Image) (err error) SetIcon (icons []image.Image) (err error)
Draw () Draw ()
CellMetrics () (width, height int)
} }
type BackendFactory func ( type BackendFactory func (
application *Application, application *Application,
callbackManager *CallbackManager, callbackManager *CallbackManager,
imageManager *ImageManager,
) ( ) (
backend Backend, backend Backend,
err error, err error,
@ -27,7 +29,10 @@ func RegisterBackend (factory BackendFactory) {
func instantiateBackend (application *Application) (backend Backend, err error) { func instantiateBackend (application *Application) (backend Backend, err error) {
// find a suitable backend // find a suitable backend
for _, factory := range factories { for _, factory := range factories {
backend, err = factory(application, &application.callbackManager) backend, err = factory (
application,
&application.callbackManager,
&application.imageManager)
if err == nil && backend != nil { return } if err == nil && backend != nil { return }
} }

View File

@ -19,8 +19,9 @@ import "github.com/flopp/go-findfont"
// factory instantiates an X backend. // factory instantiates an X backend.
func factory ( func factory (
application *stone.Application, application *stone.Application,
callbackManager *stone.CallbackManager, callbackManager *stone.CallbackManager,
imageManager *stone.ImageManager,
) ( ) (
output stone.Backend, output stone.Backend,
err error, err error,
@ -29,6 +30,7 @@ func factory (
application: application, application: application,
config: application.Config(), config: application.Config(),
callbackManager: callbackManager, callbackManager: callbackManager,
imageManager: imageManager,
} }
// load font // load font

View File

@ -17,6 +17,7 @@ type Backend struct {
application *stone.Application application *stone.Application
config *stone.Config config *stone.Config
callbackManager *stone.CallbackManager callbackManager *stone.CallbackManager
imageManager *stone.ImageManager
connection *xgbutil.XUtil connection *xgbutil.XUtil
window *xwindow.Window window *xwindow.Window
canvas *xgraphics.Image canvas *xgraphics.Image
@ -88,6 +89,12 @@ func (backend *Backend) SetIcon (icons []image.Image) (err error) {
return return
} }
func (backend *Backend) CellMetrics () (width, height int) {
width = backend.metrics.cellWidth
height = backend.metrics.cellHeight
return
}
// calculateWindowSize calculates window bounds based on the internal buffer // calculateWindowSize calculates window bounds based on the internal buffer
// size. // size.
func (backend *Backend) calculateWindowSize () (x, y int) { func (backend *Backend) calculateWindowSize () (x, y int) {

142
image.go Normal file
View File

@ -0,0 +1,142 @@
package stone
import "sync"
import "image"
import "image/color"
type ImageManager struct {
lock sync.RWMutex
images []*ColorImage
}
func (manager *ImageManager) For (callback func (im *ColorImage)) {
manager.lock.RLock()
defer manager.lock.RUnlock()
for _, im := range manager.images {
callback(im)
}
}
func (manager *ImageManager) Add (im *ColorImage) {
manager.lock.Lock()
defer manager.lock.Unlock()
manager.images = append(manager.images, im)
}
func (manager *ImageManager) Size () (size int) {
manager.lock.RLock()
defer manager.lock.RUnlock()
size = len(manager.images)
return
}
func (manager *ImageManager) At (index int) (im *ColorImage) {
manager.lock.RLock()
defer manager.lock.RUnlock()
if index < 0 || index > len(manager.images) { return }
im = manager.images[index]
return
}
func (manager *ImageManager) Remove (im *ColorImage) (removed bool) {
manager.lock.Lock()
defer manager.lock.Unlock()
index := 0
for manager.images[index] != im && index < len(manager.images) {
index ++
}
if index >= len(manager.images) { return }
manager.images = append (
manager.images[:index],
manager.images[index + 1:]...)
removed = true
return
}
type ColorImage struct {
x, y int
width, height int
bufferWidth, bufferHeight int
cellWidth, cellHeight int
buffer []color.RGBA
clean bool
}
func (im *ColorImage) Model () (model color.Model) {
model = color.RGBAModel
return
}
func (im *ColorImage) Bounds () (bounds image.Rectangle) {
bounds.Max.X = im.width
bounds.Max.Y = im.height
return
}
func (im *ColorImage) Size () (width, height int) {
width = im.width
height = im.height
return
}
func (im *ColorImage) SetSize (width, height int) {
im.width = width
im.height = height
im.bufferWidth = im.cellWidth * im.width
im.bufferHeight = im.cellHeight * im.height
im.buffer = make([]color.RGBA, im.bufferWidth * im.bufferHeight)
im.clean = false
}
func (im *ColorImage) At (x, y int) (pixel color.Color) {
if im.outOfBounds(x, y) { return }
pixel = im.buffer[x + y * im.width]
return
}
func (im *ColorImage) AtRGBA (x, y int) (pixel color.RGBA) {
if im.outOfBounds(x, y) { return }
pixel = im.buffer[x + y * im.width]
return
}
func (im *ColorImage) Set (x, y int, pixel color.Color) {
if im.outOfBounds(x, y) { return }
r, g, b, a := pixel.RGBA()
im.buffer[x + y * im.width] = color.RGBA {
R: uint8(r >> 8),
G: uint8(g >> 8),
B: uint8(b >> 8),
A: uint8(a >> 8),
}
im.clean = false
return
}
func (im *ColorImage) SetRGBA (x, y int, pixel color.RGBA) {
if im.outOfBounds(x, y) { return }
im.buffer[x + y * im.width] = pixel
return
}
func (im *ColorImage) MarkClean () {
im.clean = true
}
func (im *ColorImage) outOfBounds (x, y int) (outOfBounds bool) {
outOfBounds =
x >= im.width ||
y >= im.height ||
x < 0 ||
y < 0
return
}