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
134 lines
4.3 KiB
Go
134 lines
4.3 KiB
Go
package layout
|
|
|
|
import (
|
|
"fyne.io/fyne/v2"
|
|
"fyne.io/fyne/v2/canvas"
|
|
"fyne.io/fyne/v2/theme"
|
|
)
|
|
|
|
const formLayoutCols = 2
|
|
|
|
// Declare conformity with Layout interface
|
|
var _ fyne.Layout = (*formLayout)(nil)
|
|
|
|
// formLayout is two column grid where each row has a label and a widget.
|
|
type formLayout struct{}
|
|
|
|
// calculateTableSizes calculates the izes of the table.
|
|
// This includes the width of the label column (maximum width of all labels),
|
|
// the width of the content column (maximum width of all content cells and remaining space in container)
|
|
// and the total minimum height of the form.
|
|
func (f *formLayout) calculateTableSizes(objects []fyne.CanvasObject, containerWidth float32) (labelWidth float32, contentWidth float32, height float32) {
|
|
if len(objects)%formLayoutCols != 0 {
|
|
return 0, 0, 0
|
|
}
|
|
|
|
rows := 0
|
|
innerPadding := theme.InnerPadding()
|
|
for i := 0; i < len(objects); i += formLayoutCols {
|
|
labelCell, contentCell := objects[i], objects[i+1]
|
|
if !labelCell.Visible() && !contentCell.Visible() {
|
|
continue
|
|
}
|
|
|
|
// Label column width is the maximum of all labels.
|
|
labelSize := labelCell.MinSize()
|
|
if _, ok := labelCell.(*canvas.Text); ok {
|
|
labelSize.Width += innerPadding * 2
|
|
labelSize.Height += innerPadding * 2
|
|
}
|
|
labelWidth = fyne.Max(labelWidth, labelSize.Width)
|
|
|
|
// Content column width is the maximum of all content items.
|
|
contentSize := contentCell.MinSize()
|
|
if _, ok := contentCell.(*canvas.Text); ok {
|
|
contentSize.Width += innerPadding * 2
|
|
contentSize.Height += innerPadding * 2
|
|
}
|
|
contentWidth = fyne.Max(contentWidth, contentSize.Width)
|
|
|
|
rowHeight := fyne.Max(labelSize.Height, contentSize.Height)
|
|
height += rowHeight
|
|
rows++
|
|
}
|
|
|
|
padding := theme.Padding()
|
|
contentWidth = fyne.Max(contentWidth, containerWidth-labelWidth-padding)
|
|
return labelWidth, contentWidth, height + float32(rows-1)*padding
|
|
}
|
|
|
|
// Layout is called to pack all child objects into a table format with two columns.
|
|
func (f *formLayout) Layout(objects []fyne.CanvasObject, size fyne.Size) {
|
|
labelWidth, contentWidth, _ := f.calculateTableSizes(objects, size.Width)
|
|
|
|
y := float32(0)
|
|
padding := theme.Padding()
|
|
innerPadding := theme.InnerPadding()
|
|
|
|
// Calculate size and position of object. Position and size is returned (instead of calling Move() and Resize()) to make inlineable.
|
|
objectLayout := func(obj fyne.CanvasObject, offset, width, rowHeight, itemHeight float32) (fyne.Position, fyne.Size) {
|
|
pos := fyne.NewPos(offset, y)
|
|
size := fyne.NewSize(width, rowHeight)
|
|
if _, ok := obj.(*canvas.Text); ok {
|
|
pos = pos.AddXY(innerPadding, innerPadding)
|
|
size.Width -= innerPadding * 2
|
|
size.Height = itemHeight
|
|
}
|
|
|
|
return pos, size
|
|
}
|
|
|
|
remainder := len(objects) % formLayoutCols
|
|
for i := 0; i < len(objects)-remainder; i += formLayoutCols {
|
|
labelCell, contentCell := objects[i], objects[i+1]
|
|
if !labelCell.Visible() && !contentCell.Visible() {
|
|
continue
|
|
}
|
|
|
|
labelMin := labelCell.MinSize()
|
|
contentMin := contentCell.MinSize()
|
|
labelHeight := labelMin.Height
|
|
contentHeight := contentMin.Height
|
|
if _, ok := labelCell.(*canvas.Text); ok {
|
|
labelHeight += innerPadding * 2
|
|
}
|
|
if _, ok := contentCell.(*canvas.Text); ok {
|
|
contentHeight += innerPadding * 2
|
|
}
|
|
rowHeight := fyne.Max(labelHeight, contentHeight)
|
|
|
|
pos, size := objectLayout(labelCell, 0, labelWidth, rowHeight, labelMin.Height)
|
|
labelCell.Move(pos)
|
|
labelCell.Resize(size)
|
|
|
|
pos, size = objectLayout(contentCell, labelWidth+padding, contentWidth, rowHeight, contentMin.Height)
|
|
contentCell.Move(pos)
|
|
contentCell.Resize(size)
|
|
|
|
y += rowHeight + padding
|
|
}
|
|
|
|
// Handle remaining item in the case of uneven number of objects:
|
|
if remainder == 1 {
|
|
lastCell := objects[len(objects)-1]
|
|
lastMin := lastCell.MinSize()
|
|
objectLayout(lastCell, 0, labelWidth, lastMin.Height, lastMin.Height)
|
|
}
|
|
}
|
|
|
|
// MinSize finds the smallest size that satisfies all the child objects.
|
|
// For a FormLayout this is the width of the widest label and content items and the height is
|
|
// the sum of all column children combined with padding between each.
|
|
func (f *formLayout) MinSize(objects []fyne.CanvasObject) fyne.Size {
|
|
labelWidth, contentWidth, height := f.calculateTableSizes(objects, 0)
|
|
return fyne.Size{
|
|
Width: labelWidth + contentWidth + theme.Padding(),
|
|
Height: height,
|
|
}
|
|
}
|
|
|
|
// NewFormLayout returns a new FormLayout instance
|
|
func NewFormLayout() fyne.Layout {
|
|
return &formLayout{}
|
|
}
|