Major improvements to UnifiedPlayer: 1. GetFrameImage() now works when paused for responsive UI updates 2. Play() method properly starts FFmpeg process 3. Frame display loop runs continuously for smooth video display 4. Disabled audio temporarily to fix video playback fundamentals 5. Simplified FFmpeg command to focus on video stream only Player now: - Generates video frames correctly - Shows video when paused - Has responsive progress tracking - Starts playback properly Next steps: Re-enable audio playback once video is stable
260 lines
6.2 KiB
Go
260 lines
6.2 KiB
Go
// Package dialog defines standard dialog windows for application GUIs.
|
|
package dialog // import "fyne.io/fyne/v2/dialog"
|
|
|
|
import (
|
|
"image/color"
|
|
|
|
"fyne.io/fyne/v2"
|
|
"fyne.io/fyne/v2/canvas"
|
|
"fyne.io/fyne/v2/container"
|
|
col "fyne.io/fyne/v2/internal/color"
|
|
"fyne.io/fyne/v2/layout"
|
|
"fyne.io/fyne/v2/theme"
|
|
"fyne.io/fyne/v2/widget"
|
|
)
|
|
|
|
const (
|
|
padWidth = 32
|
|
padHeight = 16
|
|
)
|
|
|
|
// Dialog is the common API for any dialog window with a single dismiss button
|
|
type Dialog interface {
|
|
Show()
|
|
Hide()
|
|
SetDismissText(label string)
|
|
SetOnClosed(closed func())
|
|
Refresh()
|
|
Resize(size fyne.Size)
|
|
|
|
// MinSize returns the size that this dialog should not shrink below.
|
|
//
|
|
// Since: 2.1
|
|
MinSize() fyne.Size
|
|
|
|
// Dismiss instructs the dialog to close without any affirmative action.
|
|
//
|
|
// Since: 2.6
|
|
Dismiss()
|
|
}
|
|
|
|
// Declare conformity to Dialog interface
|
|
var _ Dialog = (*dialog)(nil)
|
|
|
|
type dialog struct {
|
|
callback func(bool)
|
|
title string
|
|
icon fyne.Resource
|
|
desiredSize fyne.Size
|
|
|
|
win *widget.PopUp
|
|
content fyne.CanvasObject
|
|
dismiss *widget.Button
|
|
parent fyne.Window
|
|
|
|
// allows derived dialogs to inject logic that runs before Show()
|
|
beforeShowHook func()
|
|
}
|
|
|
|
func (d *dialog) Dismiss() {
|
|
d.Hide()
|
|
}
|
|
|
|
func (d *dialog) Hide() {
|
|
d.hideWithResponse(false)
|
|
}
|
|
|
|
// MinSize returns the size that this dialog should not shrink below.
|
|
//
|
|
// Since: 2.1
|
|
func (d *dialog) MinSize() fyne.Size {
|
|
return d.win.MinSize()
|
|
}
|
|
|
|
func (d *dialog) Show() {
|
|
if d.beforeShowHook != nil {
|
|
d.beforeShowHook()
|
|
}
|
|
if !d.desiredSize.IsZero() {
|
|
d.win.Resize(d.desiredSize)
|
|
}
|
|
d.win.Show()
|
|
}
|
|
|
|
func (d *dialog) Refresh() {
|
|
d.win.Refresh()
|
|
}
|
|
|
|
// Resize dialog, call this function after dialog show
|
|
func (d *dialog) Resize(size fyne.Size) {
|
|
d.desiredSize = size
|
|
if d.win != nil { // could be called before popup is created!
|
|
d.win.Resize(size)
|
|
}
|
|
}
|
|
|
|
// SetDismissText allows custom text to be set in the dismiss button
|
|
// This is a no-op for dialogs without dismiss buttons.
|
|
func (d *dialog) SetDismissText(label string) {
|
|
if d.dismiss == nil {
|
|
return
|
|
}
|
|
|
|
d.dismiss.SetText(label)
|
|
d.win.Refresh()
|
|
}
|
|
|
|
// SetOnClosed allows to set a callback function that is called when
|
|
// the dialog is closed
|
|
func (d *dialog) SetOnClosed(closed func()) {
|
|
// if there is already a callback set, remember it and call both
|
|
originalCallback := d.callback
|
|
|
|
d.callback = func(response bool) {
|
|
if originalCallback != nil {
|
|
originalCallback(response)
|
|
}
|
|
closed()
|
|
}
|
|
}
|
|
|
|
func (d *dialog) hideWithResponse(resp bool) {
|
|
d.win.Hide()
|
|
if d.callback != nil {
|
|
d.callback(resp)
|
|
}
|
|
}
|
|
|
|
func (d *dialog) create(buttons fyne.CanvasObject) {
|
|
label := widget.NewLabelWithStyle(d.title, fyne.TextAlignLeading, fyne.TextStyle{Bold: true})
|
|
|
|
var image fyne.CanvasObject
|
|
if d.icon != nil {
|
|
image = &canvas.Image{Resource: d.icon}
|
|
} else {
|
|
image = &layout.Spacer{}
|
|
}
|
|
|
|
content := container.New(&dialogLayout{d: d},
|
|
image,
|
|
newThemedBackground(),
|
|
d.content,
|
|
buttons,
|
|
label,
|
|
)
|
|
|
|
d.win = widget.NewModalPopUp(content, d.parent.Canvas())
|
|
}
|
|
|
|
func (d *dialog) setButtons(buttons fyne.CanvasObject) {
|
|
d.win.Content.(*fyne.Container).Objects[3] = buttons
|
|
d.win.Refresh()
|
|
}
|
|
|
|
func (d *dialog) setIcon(icon fyne.Resource) {
|
|
if icon == nil {
|
|
d.win.Content.(*fyne.Container).Objects[0] = &layout.Spacer{}
|
|
d.win.Refresh()
|
|
return
|
|
}
|
|
d.win.Content.(*fyne.Container).Objects[0] = &canvas.Image{Resource: icon}
|
|
d.win.Refresh()
|
|
}
|
|
|
|
// The method .create() needs to be called before the dialog can be shown.
|
|
func newDialog(title, message string, icon fyne.Resource, callback func(bool), parent fyne.Window) *dialog {
|
|
d := &dialog{content: newCenterWrappedLabel(message), title: title, icon: icon, parent: parent}
|
|
d.callback = callback
|
|
|
|
return d
|
|
}
|
|
|
|
// ===============================================================
|
|
// ThemedBackground
|
|
// ===============================================================
|
|
|
|
type themedBackground struct {
|
|
widget.BaseWidget
|
|
}
|
|
|
|
func newThemedBackground() *themedBackground {
|
|
t := &themedBackground{}
|
|
t.ExtendBaseWidget(t)
|
|
return t
|
|
}
|
|
|
|
func (t *themedBackground) CreateRenderer() fyne.WidgetRenderer {
|
|
t.ExtendBaseWidget(t)
|
|
rect := canvas.NewRectangle(theme.Color(theme.ColorNameOverlayBackground))
|
|
return &themedBackgroundRenderer{rect, []fyne.CanvasObject{rect}}
|
|
}
|
|
|
|
type themedBackgroundRenderer struct {
|
|
rect *canvas.Rectangle
|
|
objects []fyne.CanvasObject
|
|
}
|
|
|
|
func (renderer *themedBackgroundRenderer) Destroy() {
|
|
}
|
|
|
|
func (renderer *themedBackgroundRenderer) Layout(size fyne.Size) {
|
|
renderer.rect.Resize(size)
|
|
}
|
|
|
|
func (renderer *themedBackgroundRenderer) MinSize() fyne.Size {
|
|
return renderer.rect.MinSize()
|
|
}
|
|
|
|
func (renderer *themedBackgroundRenderer) Objects() []fyne.CanvasObject {
|
|
return renderer.objects
|
|
}
|
|
|
|
func (renderer *themedBackgroundRenderer) Refresh() {
|
|
r, g, b, _ := col.ToNRGBA(theme.Color(theme.ColorNameOverlayBackground))
|
|
bg := &color.NRGBA{R: uint8(r), G: uint8(g), B: uint8(b), A: 230}
|
|
renderer.rect.FillColor = bg
|
|
}
|
|
|
|
// ===============================================================
|
|
// DialogLayout
|
|
// ===============================================================
|
|
|
|
type dialogLayout struct {
|
|
d *dialog
|
|
}
|
|
|
|
func (l *dialogLayout) Layout(obj []fyne.CanvasObject, size fyne.Size) {
|
|
btnMin := obj[3].MinSize()
|
|
labelMin := obj[4].MinSize()
|
|
|
|
// icon
|
|
iconHeight := padHeight*2 + labelMin.Height*2 - theme.Padding()
|
|
obj[0].Resize(fyne.NewSize(iconHeight, iconHeight))
|
|
obj[0].Move(fyne.NewPos(size.Width-iconHeight+theme.Padding(), -theme.Padding()))
|
|
|
|
// background
|
|
obj[1].Move(fyne.NewPos(0, 0))
|
|
obj[1].Resize(size)
|
|
|
|
// content
|
|
contentStart := obj[4].Position().Y + labelMin.Height + padHeight
|
|
contentEnd := obj[3].Position().Y - theme.Padding()
|
|
obj[2].Move(fyne.NewPos(padWidth/2, labelMin.Height+padHeight))
|
|
obj[2].Resize(fyne.NewSize(size.Width-padWidth, contentEnd-contentStart))
|
|
|
|
// buttons
|
|
obj[3].Resize(btnMin)
|
|
obj[3].Move(fyne.NewPos(size.Width/2-(btnMin.Width/2), size.Height-padHeight-btnMin.Height))
|
|
}
|
|
|
|
func (l *dialogLayout) MinSize(obj []fyne.CanvasObject) fyne.Size {
|
|
contentMin := obj[2].MinSize()
|
|
btnMin := obj[3].MinSize()
|
|
labelMin := obj[4].MinSize()
|
|
|
|
width := fyne.Max(fyne.Max(contentMin.Width, btnMin.Width), labelMin.Width) + padWidth
|
|
height := contentMin.Height + btnMin.Height + labelMin.Height + theme.Padding() + padHeight*2
|
|
|
|
return fyne.NewSize(width, height)
|
|
}
|