Media: components 341-360
This commit is contained in:
111 files changed
+6831
-1
No files matched your search
@@ -0,0 +1,93 @@
|
||||
package mujica
|
||||
|
||||
import (
|
||||
"image"
|
||||
"log/slog"
|
||||
|
||||
"github.com/egoist/mygo/ui"
|
||||
|
||||
"mujicaui/internal"
|
||||
"mujicaui/theme"
|
||||
)
|
||||
|
||||
// CameraFrame is the caller's latest camera picture.
|
||||
type CameraFrame struct {
|
||||
// Image is the frame; nil shows "No signal".
|
||||
Image image.Image
|
||||
// Seq numbers frames; a new number redraws a reused Image.
|
||||
Seq uint64
|
||||
}
|
||||
|
||||
// CameraPreviewOptions configure a CameraPreview.
|
||||
type CameraPreviewOptions struct {
|
||||
// Label names the camera for assistive technology.
|
||||
Label string
|
||||
Disabled bool
|
||||
}
|
||||
|
||||
type cameraCache struct {
|
||||
img image.Image
|
||||
seq uint64
|
||||
mirror bool
|
||||
bmp *ui.Bitmap
|
||||
}
|
||||
|
||||
type cameraKey struct{}
|
||||
|
||||
// CameraPreview shows frame at 16:9, mirrored while *mirror.
|
||||
func CameraPreview(c *ui.Context, frame CameraFrame, mirror *bool, opts CameraPreviewOptions) ChoiceResult {
|
||||
k := Tokens(c)
|
||||
old := *mirror
|
||||
label := opts.Label
|
||||
if label == "" {
|
||||
label = msg(c, "camera_preview.label")
|
||||
}
|
||||
box := ui.Box(c).FillWidth().AspectRatio(16.0 / 9).Background(videoBlack).Radius(theme.CardRadius).Clip().
|
||||
Center().Focusable().Role(ui.RoleImage).Label(label).Disabled(opts.Disabled)
|
||||
internal.Ring(box, k.Focus, theme.CardRadius)
|
||||
cache := ui.Local(box, cameraKey{}, func() cameraCache { return cameraCache{} })
|
||||
box.Children(func() {
|
||||
if frame.Image == nil {
|
||||
box.Description(msg(c, "camera_preview.noSignal"))
|
||||
ui.Column(c).Gap(8).AlignItems(ui.Center).Children(func() {
|
||||
ui.Icon(c, mediaCamera).Size(28, 28).TextColor(ui.Hex("#BCAEAA"))
|
||||
ui.Text(c, msg(c, "camera_preview.noSignal")).TextColor(ui.Hex("#BCAEAA"))
|
||||
})
|
||||
} else {
|
||||
// Copies are made once per frame number, not per paint.
|
||||
if cache.img != frame.Image || cache.seq != frame.Seq || cache.mirror != *mirror || cache.bmp == nil {
|
||||
*cache = cameraCache{frame.Image, frame.Seq, *mirror, cameraBitmap(frame.Image, *mirror)}
|
||||
}
|
||||
ui.Image(c, cache.bmp).Fit(ui.Contain).Fill()
|
||||
}
|
||||
ui.Box(c).Absolute().Top(8).Right(8).Background(ui.RGBA(0, 0, 0, 0.5)).Radius(theme.ControlRadius).Children(func() {
|
||||
b := mediaToggleAction(c, mediaMirror, msg(c, "camera_preview.mirror"), *mirror)
|
||||
if b.Clicked() && !b.IsDisabled() {
|
||||
*mirror = !*mirror
|
||||
}
|
||||
})
|
||||
})
|
||||
if !box.IsDisabled() && box.Shortcut(0, ui.KeyM) {
|
||||
*mirror = !*mirror
|
||||
}
|
||||
changed := *mirror != old
|
||||
if changed {
|
||||
slog.Debug("mujica: camera_preview mirror", "on", *mirror)
|
||||
}
|
||||
return ChoiceResult{Element: box, changed: changed}
|
||||
}
|
||||
|
||||
// cameraBitmap copies img into a bitmap, flipped when mirror.
|
||||
func cameraBitmap(img image.Image, mirror bool) *ui.Bitmap {
|
||||
if !mirror {
|
||||
return ui.NewBitmap(img)
|
||||
}
|
||||
b := img.Bounds()
|
||||
out := image.NewRGBA(image.Rect(0, 0, b.Dx(), b.Dy()))
|
||||
for y := b.Min.Y; y < b.Max.Y; y++ {
|
||||
for x := b.Min.X; x < b.Max.X; x++ {
|
||||
out.Set(b.Max.X-1-x, y-b.Min.Y, img.At(x, y))
|
||||
}
|
||||
}
|
||||
return ui.NewBitmap(out)
|
||||
}
|
||||
Reference in new issue
Block a user