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
199 lines
5.1 KiB
Go
199 lines
5.1 KiB
Go
package widget
|
|
|
|
import (
|
|
"image/color"
|
|
"strconv"
|
|
|
|
"fyne.io/fyne/v2"
|
|
"fyne.io/fyne/v2/canvas"
|
|
"fyne.io/fyne/v2/data/binding"
|
|
col "fyne.io/fyne/v2/internal/color"
|
|
"fyne.io/fyne/v2/internal/widget"
|
|
"fyne.io/fyne/v2/theme"
|
|
)
|
|
|
|
type progressRenderer struct {
|
|
widget.BaseRenderer
|
|
background, bar canvas.Rectangle
|
|
label canvas.Text
|
|
ratio float32
|
|
progress *ProgressBar
|
|
}
|
|
|
|
// MinSize calculates the minimum size of a progress bar.
|
|
// This is simply the "100%" label size plus padding.
|
|
func (p *progressRenderer) MinSize() fyne.Size {
|
|
text := "100%"
|
|
if format := p.progress.TextFormatter; format != nil {
|
|
text = format()
|
|
}
|
|
|
|
th := p.progress.Theme()
|
|
padding := th.Size(theme.SizeNameInnerPadding) * 2
|
|
size := fyne.MeasureText(text, p.label.TextSize, p.label.TextStyle)
|
|
return size.AddWidthHeight(padding, padding)
|
|
}
|
|
|
|
func (p *progressRenderer) calculateRatio() {
|
|
if p.progress.Value < p.progress.Min {
|
|
p.progress.Value = p.progress.Min
|
|
}
|
|
if p.progress.Value > p.progress.Max {
|
|
p.progress.Value = p.progress.Max
|
|
}
|
|
|
|
delta := p.progress.Max - p.progress.Min
|
|
p.ratio = float32((p.progress.Value - p.progress.Min) / delta)
|
|
}
|
|
|
|
func (p *progressRenderer) updateBar() {
|
|
p.Layout(p.progress.Size()) // Make sure that bar length updates.
|
|
|
|
// Don't draw rectangles when they can't be seen.
|
|
p.background.Hidden = p.ratio == 1.0
|
|
p.bar.Hidden = p.ratio == 0.0
|
|
|
|
if text := p.progress.TextFormatter; text != nil {
|
|
p.label.Text = text()
|
|
return
|
|
}
|
|
|
|
p.label.Text = strconv.Itoa(int(p.ratio*100)) + "%"
|
|
}
|
|
|
|
// Layout the components of the check widget
|
|
func (p *progressRenderer) Layout(size fyne.Size) {
|
|
p.calculateRatio()
|
|
|
|
p.bar.Resize(fyne.NewSize(size.Width*p.ratio, size.Height))
|
|
p.background.Resize(size)
|
|
p.label.Resize(size)
|
|
}
|
|
|
|
// applyTheme updates the progress bar to match the current theme
|
|
func (p *progressRenderer) applyTheme() {
|
|
th := p.progress.Theme()
|
|
v := fyne.CurrentApp().Settings().ThemeVariant()
|
|
|
|
primaryColor := th.Color(theme.ColorNamePrimary, v)
|
|
inputRadius := th.Size(theme.SizeNameInputRadius)
|
|
|
|
p.background.FillColor = progressBlendColor(primaryColor)
|
|
p.background.CornerRadius = inputRadius
|
|
p.bar.FillColor = primaryColor
|
|
p.bar.CornerRadius = inputRadius
|
|
p.label.Color = th.Color(theme.ColorNameForegroundOnPrimary, v)
|
|
p.label.TextSize = th.Size(theme.SizeNameText)
|
|
}
|
|
|
|
func (p *progressRenderer) Refresh() {
|
|
p.applyTheme()
|
|
p.updateBar()
|
|
p.background.Refresh()
|
|
p.bar.Refresh()
|
|
p.label.Refresh()
|
|
canvas.Refresh(p.progress.super())
|
|
}
|
|
|
|
// ProgressBar widget creates a horizontal panel that indicates progress
|
|
type ProgressBar struct {
|
|
BaseWidget
|
|
|
|
Min, Max, Value float64
|
|
|
|
// TextFormatter can be used to have a custom format of progress text.
|
|
// If set, it overrides the percentage readout and runs each time the value updates.
|
|
//
|
|
// Since: 1.4
|
|
TextFormatter func() string `json:"-"`
|
|
|
|
binder basicBinder
|
|
}
|
|
|
|
// Bind connects the specified data source to this ProgressBar.
|
|
// The current value will be displayed and any changes in the data will cause the widget to update.
|
|
//
|
|
// Since: 2.0
|
|
func (p *ProgressBar) Bind(data binding.Float) {
|
|
p.binder.SetCallback(p.updateFromData)
|
|
p.binder.Bind(data)
|
|
}
|
|
|
|
// SetValue changes the current value of this progress bar (from p.Min to p.Max).
|
|
// The widget will be refreshed to indicate the change.
|
|
func (p *ProgressBar) SetValue(v float64) {
|
|
p.Value = v
|
|
p.Refresh()
|
|
}
|
|
|
|
// MinSize returns the size that this widget should not shrink below
|
|
func (p *ProgressBar) MinSize() fyne.Size {
|
|
p.ExtendBaseWidget(p)
|
|
return p.BaseWidget.MinSize()
|
|
}
|
|
|
|
// CreateRenderer is a private method to Fyne which links this widget to its renderer
|
|
func (p *ProgressBar) CreateRenderer() fyne.WidgetRenderer {
|
|
p.ExtendBaseWidget(p)
|
|
if p.Min == 0 && p.Max == 0 {
|
|
p.Max = 1.0
|
|
}
|
|
|
|
renderer := &progressRenderer{progress: p}
|
|
renderer.label.Alignment = fyne.TextAlignCenter
|
|
renderer.applyTheme()
|
|
renderer.updateBar()
|
|
|
|
renderer.SetObjects([]fyne.CanvasObject{&renderer.background, &renderer.bar, &renderer.label})
|
|
return renderer
|
|
}
|
|
|
|
// Unbind disconnects any configured data source from this ProgressBar.
|
|
// The current value will remain at the last value of the data source.
|
|
//
|
|
// Since: 2.0
|
|
func (p *ProgressBar) Unbind() {
|
|
p.binder.Unbind()
|
|
}
|
|
|
|
// NewProgressBar creates a new progress bar widget.
|
|
// The default Min is 0 and Max is 1, Values set should be between those numbers.
|
|
// The display will convert this to a percentage.
|
|
func NewProgressBar() *ProgressBar {
|
|
bar := &ProgressBar{Min: 0, Max: 1}
|
|
bar.ExtendBaseWidget(bar)
|
|
return bar
|
|
}
|
|
|
|
// NewProgressBarWithData returns a progress bar connected with the specified data source.
|
|
//
|
|
// Since: 2.0
|
|
func NewProgressBarWithData(data binding.Float) *ProgressBar {
|
|
p := NewProgressBar()
|
|
p.Bind(data)
|
|
return p
|
|
}
|
|
|
|
func progressBlendColor(clr color.Color) color.Color {
|
|
r, g, b, a := col.ToNRGBA(clr)
|
|
faded := uint8(a) / 2
|
|
return &color.NRGBA{R: uint8(r), G: uint8(g), B: uint8(b), A: faded}
|
|
}
|
|
|
|
func (p *ProgressBar) updateFromData(data binding.DataItem) {
|
|
if data == nil {
|
|
return
|
|
}
|
|
floatSource, ok := data.(binding.Float)
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
val, err := floatSource.Get()
|
|
if err != nil {
|
|
fyne.LogError("Error getting current data value", err)
|
|
return
|
|
}
|
|
p.SetValue(val)
|
|
}
|