Skip to content

Commit

Permalink
We are nearly done there. Fix Onclick widget with Size consideration,…
Browse files Browse the repository at this point in the history
… Add Scale operation in imageWidget, implement SurfaceLoaders for easy extension of loading images, change loading image example for advanced drawings and controls, updates URL downloaded images. Last Step: URL With OnError/OnLoading to mimic old behavior with better extension. Linting, Documentation.
  • Loading branch information
cjbrigato committed Sep 25, 2024
1 parent 2713610 commit e8ae07d
Show file tree
Hide file tree
Showing 5 changed files with 212 additions and 85 deletions.
14 changes: 13 additions & 1 deletion ImageWidgets.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ type ImageWidget struct {
texture *Texture
width float32
height float32
scale imgui.Vec2
uv0, uv1 imgui.Vec2
tintColor, borderColor color.Color
onClick func()
Expand All @@ -35,6 +36,7 @@ func Image(texture *Texture) *ImageWidget {
texture: texture,
width: 0,
height: 0,
scale: imgui.Vec2{X: 1, Y: 1},
uv0: imgui.Vec2{X: 0, Y: 0},
uv1: imgui.Vec2{X: 1, Y: 1},
tintColor: color.RGBA{255, 255, 255, 255},
Expand Down Expand Up @@ -74,6 +76,13 @@ func (i *ImageWidget) Size(width, height float32) *ImageWidget {
return i
}

// Scale multiply dimensions after size
func (i *ImageWidget) Scale(scaleX, ScaleY float32) *ImageWidget {
// Size image with DPI scaling
i.scale = imgui.Vec2{scaleX, ScaleY}
return i
}

// Build implements Widget interface.
func (i *ImageWidget) Build() {
if i.width == 0 && i.height == 0 {
Expand All @@ -96,6 +105,9 @@ func (i *ImageWidget) Build() {
size.Y = rect.Y
}

size.X = size.X * i.scale.X
size.Y = size.Y * i.scale.Y

if i.texture == nil || i.texture.tex == nil {
Dummy(size.X, size.Y).Build()
return
Expand All @@ -107,7 +119,7 @@ func (i *ImageWidget) Build() {
mousePos := GetMousePos()

if cursorPos.X <= mousePos.X && cursorPos.Y <= mousePos.Y &&
cursorPos.X+int(i.width) >= mousePos.X && cursorPos.Y+int(i.height) >= mousePos.Y {
cursorPos.X+int(size.X) >= mousePos.X && cursorPos.Y+int(size.Y) >= mousePos.Y {
i.onClick()
}
}
Expand Down
55 changes: 24 additions & 31 deletions ReflectiveBoundTexture.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,19 @@ import (
imgui "github.com/AllenDang/cimgui-go"

Check failure on line 10 in ReflectiveBoundTexture.go

View workflow job for this annotation

GitHub Actions / Lint

could not import github.com/AllenDang/cimgui-go (-: build constraints exclude all Go files in /Users/runner/go/pkg/mod/github.com/!allen!dang/[email protected]) (typecheck)
)

func defaultCanvas() *image.RGBA {
white := color.RGBA{255, 255, 255, 255}
return newImage(800, 600, white)
func defaultSurface() *image.RGBA {
surface, _ := UniformLoader(REFLECTIVE_SURFACE_DEFAULT_WIDTH, REFLECTIVE_SURFACE_DEFAULT_HEIGHT, REFLECTIVE_SURFACE_DEFAULT_COLOR).ServeRGBA()
return surface
}

func newImage(width, height int, bgColor color.Color) *image.RGBA {
img := image.NewRGBA(image.Rect(0, 0, width, height))
for y := 0; y < height; y++ {
for x := 0; x < width; x++ {
img.Set(x, y, bgColor)
}
}
return img
}
const (
REFLECTIVE_SURFACE_DEFAULT_WIDTH = 128
REFLECTIVE_SURFACE_DEFAULT_HEIGHT = 128
)

var (
REFLECTIVE_SURFACE_DEFAULT_COLOR = color.RGBA{255, 255, 255, 255}
)

type ReflectiveBoundTexture struct {
Surface *image.RGBA
Expand All @@ -41,7 +40,7 @@ func (i *ReflectiveBoundTexture) commit() (*ReflectiveBoundTexture, bool) {
i.mu.Lock()
defer i.mu.Unlock()
if i.Surface == nil {
i.Surface = defaultCanvas()
i.Surface = defaultSurface()
}

var has_changed bool
Expand All @@ -54,24 +53,6 @@ func (i *ReflectiveBoundTexture) commit() (*ReflectiveBoundTexture, bool) {
return i, has_changed
}

func (i *ReflectiveBoundTexture) SetSurfaceFn(fn func() *image.RGBA, commit bool) error {
img := fn()
return i.SetSurfaceFromRGBA(img, commit)
}

func (i *ReflectiveBoundTexture) SetSurfaceFromFillRect(width int, height int, c color.Color, commit bool) error {
img := newImage(width, height, c)
return i.SetSurfaceFromRGBA(img, commit)
}

func (i *ReflectiveBoundTexture) SetSurfaceFromFile(path string, commit bool) error {
img, err := LoadImage(path)
if err != nil {
return err
}
return i.SetSurfaceFromRGBA(img, commit)
}

func (i *ReflectiveBoundTexture) SetSurfaceFromRGBA(img *image.RGBA, commit bool) error {
if img != nil {
i.Surface = img
Expand Down Expand Up @@ -164,6 +145,18 @@ func (i *ReflectiveBoundTexture) bind() {
})
}

func (i *ReflectiveBoundTexture) GetSurfaceWidth() int {
return i.Surface.Bounds().Dx()
}

func (i *ReflectiveBoundTexture) GetSurfaceHeight() int {
return i.Surface.Bounds().Dy()
}

func (i *ReflectiveBoundTexture) GetSurfaceSize() image.Point {
return i.Surface.Bounds().Size()
}

func (i *ReflectiveBoundTexture) Texture() *Texture {
i.commit()
return i.tex
Expand Down
124 changes: 124 additions & 0 deletions SurfaceLoaders.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package giu

import (
go_ctx "context"
"image"
"image/color"
"image/draw"
"net/http"
"time"
)

// SurfaceLoader interface
type SurfaceLoader interface {
ServeRGBA() (*image.RGBA, error)
}
type SurfaceLoaderFunc func() (*image.RGBA, error)

func (i *ReflectiveBoundTexture) LoadSurfaceFunc(fn SurfaceLoaderFunc, commit bool) error {
img, err := fn()
if err != nil {
return err
}
return i.SetSurfaceFromRGBA(img, commit)
}

func (i *ReflectiveBoundTexture) LoadSurface(loader SurfaceLoader, commit bool) error {
img, err := loader.ServeRGBA()
if err != nil {
return err
}
return i.SetSurfaceFromRGBA(img, commit)
}

// FileLoader

type fileLoader struct {
path string
}

func (f *fileLoader) ServeRGBA() (*image.RGBA, error) {
img, err := LoadImage(f.path)
if err != nil {
return nil, err
}
return img, nil
}

func FileLoader(path string) SurfaceLoader {
return &fileLoader{
path: path,
}
}

func (i *ReflectiveBoundTexture) SetSurfaceFromFile(path string, commit bool) error {
return i.LoadSurface(FileLoader(path), commit)
}

// UrlLoader

type urlLoader struct {
url string
timeout time.Duration
}

func (u *urlLoader) ServeRGBA() (*image.RGBA, error) {
client := &http.Client{Timeout: u.timeout}
req, err := http.NewRequestWithContext(go_ctx.Background(), "GET", u.url, http.NoBody)
if err != nil {
//errorFn(err)
return nil, err
}
resp, err := client.Do(req)
if err != nil {
//errorFn(err)
return nil, err
}
defer resp.Body.Close()
/*defer func() {
if closeErr := resp.Body.Close(); closeErr != nil {
errorFn(closeErr)
}
}()*/
img, _, err := image.Decode(resp.Body)
if err != nil {
//errorFn(err)
return nil, err
}
return ImageToRgba(img), nil
}

func URLLoader(url string, timeout time.Duration) SurfaceLoader {
return &urlLoader{
url: url,
timeout: timeout,
}
}

func (i *ReflectiveBoundTexture) SetSurfaceFromURL(url string, timeout time.Duration, commit bool) error {
return i.LoadSurface(URLLoader(url, timeout), commit)
}

// UniformLoader
type uniformLoader struct {
width, height int
color color.Color
}

func (u *uniformLoader) ServeRGBA() (*image.RGBA, error) {
img := image.NewRGBA(image.Rect(0, 0, u.width, u.height))
draw.Draw(img, img.Bounds(), &image.Uniform{u.color}, image.ZP, draw.Src)
return img, nil
}

func UniformLoader(width, height int, color color.Color) SurfaceLoader {
return &uniformLoader{
width: width,
height: height,
color: color,
}
}

func (i *ReflectiveBoundTexture) SetSurfaceUniform(width int, height int, c color.Color, commit bool) error {
return i.LoadSurface(UniformLoader(width, height, c), commit)
}
102 changes: 49 additions & 53 deletions examples/loadimage/loadimage.go
Original file line number Diff line number Diff line change
@@ -1,45 +1,70 @@
package main

import (
"context"
"fmt"
"image"
_ "image/jpeg"
_ "image/png"
"log"
"net/http"
"time"

imgui "github.com/AllenDang/cimgui-go"

Check failure on line 11 in examples/loadimage/loadimage.go

View workflow job for this annotation

GitHub Actions / Lint

could not import github.com/AllenDang/cimgui-go (-: build constraints exclude all Go files in /Users/runner/go/pkg/mod/github.com/!allen!dang/[email protected]) (typecheck)
g "github.com/AllenDang/giu"
)

var (
fallback = &g.ReflectiveBoundTexture{}
gopher = &g.ReflectiveBoundTexture{}
urlWidgetLike = &g.ReflectiveBoundTexture{}
rgba *image.RGBA
fromrgba = &g.ReflectiveBoundTexture{}
fromfile = &g.ReflectiveBoundTexture{}
fromurl = &g.ReflectiveBoundTexture{}
rgba *image.RGBA
sonicOffsetX = int32(1180)
sonicOffsetY = int32(580)
)

func loop() {

urlWidgetLike.SetSurfaceFn(downloadUrlFn("https://static.wikia.nocookie.net/smashbros/images/0/0e/Art_Sonic_TSR.png/revision/latest?cb=20200210122913&path-prefix=fr", time.Second*10), true)
var start_pos image.Point
var window_size imgui.Vec2

Check failure on line 26 in examples/loadimage/loadimage.go

View workflow job for this annotation

GitHub Actions / Lint

declared and not used: window_size (typecheck)
g.SingleWindow().Layout(
g.Label("Display image from texture"),
gopher.ToImageWidget(),
g.Label("Display image from fallback"),
fallback.ToImageWidget().OnClick(func() {
g.Custom(func() {
start_pos = g.GetCursorScreenPos()
window_size = imgui.WindowSize()
}),
g.Label("Display wich has size of contentAvaiable (stretch)"),
fromfile.ToImageWidget().OnClick(func() {
fmt.Println("contentAvailable image was clicked")
}).Size(-1, -1),

g.Label("Display image from preloaded rgba"),
fromrgba.ToImageWidget().OnClick(func() {
fmt.Println("rgba image was clicked")
}).Size(600, 400),
g.Label("Display image from gopher"),
gopher.ToImageWidget().OnClick(func() {
}),

g.Label("Display image from file"),
fromfile.ToImageWidget().OnClick(func() {
fmt.Println("image from file was clicked")
}).Size(860, 561),
}),

// TODO Rewrite via func (i *ReflectiveBoundTexture) SetSurfaceFn(fn func() *image.RGBA, commit bool) error {
g.Label("Display image from url (wait few seconds to download)"),
g.ImageWithURL("https://png.pngitem.com/pimgs/s/3-36108_gopher-golang-hd-png-download.png").OnClick(func() {
g.Label("Display image from url + 0.25 scale"),
fromurl.ToImageWidget().OnClick(func() {
fmt.Println("image from url clicked")
}).Size(300, 200),
}).Scale(0.25, 0.25),

g.Label("Advanced Drawing manipulation"),
g.DragInt("Sonic Offset X", &sonicOffsetX, 0, 1280),
g.DragInt("Sonic Offset Y", &sonicOffsetY, 0, 720),
g.Custom(func() {
size := fromurl.GetSurfaceSize()
sonicOffset := image.Point{int(sonicOffsetX), int(sonicOffsetY)}
pos_with_offset := start_pos.Add(sonicOffset)
computed_posX := (float32(pos_with_offset.X)) + imgui.ScrollX()
computed_posY := (float32(pos_with_offset.Y)) + imgui.ScrollY()
//cur_pos := g.GetCursorPos()
scale := imgui.Vec2{0.10, 0.10}
p_min := imgui.Vec2{computed_posX, computed_posY}
p_max := imgui.Vec2{computed_posX + float32(size.X)*scale.X, computed_posY + float32(size.Y)*scale.Y}
imgui.ForegroundDrawList().AddImage(fromurl.Texture().ID(), p_min, p_max)
}),

/*
g.Label("Display images from url with loading and fallback"),
g.Label("Display image from url without placeholder (no size when loading)"),
Expand Down Expand Up @@ -76,39 +101,10 @@ func main() {
if err != nil {
log.Fatalf("Cannot loadIamge fallback.png")
}
gopher.SetSurfaceFromFile("gopher.png", false)
fallback.SetSurfaceFromRGBA(rgba, false)
fromfile.SetSurfaceFromFile("gopher.png", false)
fromrgba.SetSurfaceFromRGBA(rgba, false)
fromurl.SetSurfaceFromURL("https://static.wikia.nocookie.net/smashbros/images/0/0e/Art_Sonic_TSR.png/revision/latest?cb=20200210122913&path-prefix=fr", time.Second*5, false)

wnd := g.NewMasterWindow("Load Image", 600, 500, g.MasterWindowFlagsNotResizable)
//wnd.SetIcon(rgba)
wnd := g.NewMasterWindow("Load Image", 1280, 720, 0)
wnd.Run(loop)
}

func downloadUrlFn(imgUrl string, timeout time.Duration) func() *image.RGBA {
return func() *image.RGBA {
client := &http.Client{Timeout: timeout}
req, err := http.NewRequestWithContext(context.Background(), "GET", imgUrl, http.NoBody)
if err != nil {
//errorFn(err)
return nil
}
resp, err := client.Do(req)
if err != nil {
//errorFn(err)
return nil
}
defer resp.Body.Close()
/*defer func() {
if closeErr := resp.Body.Close(); closeErr != nil {
errorFn(closeErr)
}
}()*/
img, _, err := image.Decode(resp.Body)
if err != nil {
//errorFn(err)
return nil
}
return g.ImageToRgba(img)

}
}
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,5 @@ require (
golang.org/x/sys v0.5.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)


0 comments on commit e8ae07d

Please sign in to comment.