commit 8a75d4479febaa550d442cb9341c22454bef2d34
parent 1ff925de14c898dee92c272733f4f74e950cc3b4
Author: Jack Mordaunt <jackmordaunt@gmail.com>
Date: Thu, 6 May 2021 17:43:22 +0800
ux: process icon concurrently
Signed-off-by: Jack Mordaunt <jackmordaunt@gmail.com>
Diffstat:
| M | cmd/preview/main.go | | | 84 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------- |
1 file changed, 58 insertions(+), 26 deletions(-)
diff --git a/cmd/preview/main.go b/cmd/preview/main.go
@@ -59,10 +59,20 @@ type UI struct {
OpenBtn widget.Clickable
SideBar layout.List
+
+ ProcessedIcon chan ProcessedIconResult
+ Processing bool
+}
+
+type ProcessedIconResult struct {
+ File string
+ Imgs []image.Image
+ Err error
}
// Loop initializes UI state and starts the render loop.
func (ui *UI) Loop() error {
+ ui.ProcessedIcon = make(chan ProcessedIconResult)
var (
ops op.Ops
events = ui.Window.Events()
@@ -83,24 +93,54 @@ func (ui *UI) Loop() error {
// Update the UI state.
func (ui *UI) Update(gtx C) {
- ui.SideBar.Axis = l.Vertical
+ if ui.Processing {
+ op.InvalidateOp{}.Add(gtx.Ops)
+ }
if ui.OpenBtn.Clicked() {
- if err := func() error {
- file, err := zenity.SelectFile()
- if err != nil {
- return fmt.Errorf("selecting file: %w", err)
- }
- f, err := os.Open(file)
- if err != nil {
- return err
+ ui.Processing = true
+ go func() {
+ imgs, file, err := func() ([]image.Image, string, error) {
+ file, err := zenity.SelectFile(zenity.Title("Select .icns file"))
+ if err != nil {
+ return nil, "", fmt.Errorf("selecting file: %w", err)
+ }
+ file, err = filepath.Abs(file)
+ if err != nil {
+ return nil, "", fmt.Errorf("resolving file path: %w", err)
+ }
+ f, err := os.OpenFile(file, os.O_RDONLY, 0644)
+ if err != nil {
+ return nil, "", err
+ }
+ defer f.Close()
+ imgs, err := icns.DecodeAll(f)
+ if err != nil {
+ return nil, "", fmt.Errorf("decoding: %w", err)
+ }
+ return imgs, file, nil
+ }()
+ ui.ProcessedIcon <- ProcessedIconResult{
+ File: filepath.Base(file),
+ Imgs: imgs,
+ Err: err,
}
- defer f.Close()
- imgs, err := icns.DecodeAll(f)
- if err != nil {
- return fmt.Errorf("decoding: %w", err)
+ }()
+ }
+ for ii := range ui.Icons {
+ for _, event := range gtx.Events(ui.Icons[ii]) {
+ if c, ok := event.(pointer.Event); ok && c.Type == pointer.Release {
+ ui.Preview = &ui.Icons[ii]
}
+ }
+ }
+ select {
+ case r := <-ui.ProcessedIcon:
+ if r.Err != nil {
+ // TODO(jfm): push to dismissable error stack.
+ log.Printf("opening icon: %v", r.Err)
+ } else {
ui.Icons = ui.Icons[:]
- for _, img := range imgs {
+ for _, img := range r.Imgs {
ui.Icons = append(ui.Icons, widget.Image{
Src: paint.NewImageOp(img),
Fit: widget.Contain,
@@ -110,24 +150,16 @@ func (ui *UI) Update(gtx C) {
if len(ui.Icons) > 0 {
ui.Preview = &ui.Icons[0]
}
- ui.FileName = filepath.Base(file)
- return nil
- }(); err != nil {
- // TODO(jfm): Push to dismissable error stack.
- log.Printf("opening icns: %v", err)
- }
- }
- for ii := range ui.Icons {
- for _, event := range gtx.Events(ui.Icons[ii]) {
- if c, ok := event.(pointer.Event); ok && c.Type == pointer.Release {
- ui.Preview = &ui.Icons[ii]
- }
+ ui.FileName = r.File
+ ui.Processing = false
}
+ default:
}
}
// Layout the UI.
func (ui *UI) Layout(gtx C) D {
+ ui.SideBar.Axis = l.Vertical
return l.Flex{
Axis: l.Horizontal,
}.Layout(