toast.go_ raw

   1  package toast
   2  
   3  import (
   4  	"image"
   5  	"image/color"
   6  	
   7  	"github.com/p9c/p9/pkg/gel/gio/f32"
   8  	l "github.com/p9c/p9/pkg/gel/gio/layout"
   9  	"github.com/p9c/p9/pkg/gel/gio/op"
  10  	"github.com/p9c/p9/pkg/gel/gio/op/clip"
  11  	"github.com/p9c/p9/pkg/gel/gio/op/paint"
  12  	"github.com/p9c/p9/pkg/gel/gio/unit"
  13  	icons2 "golang.org/x/exp/shiny/materialdesign/icons"
  14  	
  15  	"github.com/p9c/p9/pkg/gui"
  16  	"github.com/p9c/p9/pkg/gui/shadow"
  17  )
  18  
  19  type Toasts struct {
  20  	toasts             []toast
  21  	layout             *gui.List
  22  	theme              *gui.Theme
  23  	offset             image.Point
  24  	duration           int
  25  	singleSize         image.Point
  26  	singleCornerRadius unit.Value
  27  	singleElevation    unit.Value
  28  }
  29  
  30  type toast struct {
  31  	title, content, level string
  32  	headerBackground      color.NRGBA
  33  	bodyBackground        color.NRGBA
  34  	icon                  *[]byte
  35  	ticker                float32
  36  	close                 gui.Clickable
  37  	cornerRadius          unit.Value
  38  	elevation             unit.Value
  39  }
  40  
  41  func New(th *gui.Theme) *Toasts {
  42  	return &Toasts{
  43  		layout:             th.List(),
  44  		theme:              th,
  45  		duration:           100,
  46  		singleSize:         image.Pt(300, 80),
  47  		singleCornerRadius: unit.Dp(5),
  48  		singleElevation:    unit.Dp(5),
  49  	}
  50  }
  51  func (t *Toasts) AddToast(title, content, level string) {
  52  	ic := &icons2.ActionInfo
  53  	switch level {
  54  	case "Warning":
  55  		ic = &icons2.AlertWarning
  56  	case "Success":
  57  		ic = &icons2.NavigationCheck
  58  	case "Danger":
  59  		ic = &icons2.AlertError
  60  	case "Info":
  61  		ic = &icons2.ActionInfo
  62  	}
  63  	t.toasts = append(
  64  		t.toasts, toast{
  65  			title:            title,
  66  			content:          content,
  67  			level:            level,
  68  			ticker:           0,
  69  			headerBackground: gui.HexNRGB(t.theme.Colors[level]),
  70  			bodyBackground:   gui.HexNRGB(t.theme.Colors["PanelBg"]),
  71  			cornerRadius:     t.singleCornerRadius,
  72  			elevation:        t.singleElevation,
  73  			icon:             ic,
  74  		},
  75  	)
  76  }
  77  
  78  func (t *Toasts) DrawToasts() func(gtx l.Context) {
  79  	return func(gtx l.Context) {
  80  		defer op.Push(gtx.Ops).Pop()
  81  		op.Offset(f32.Pt(float32(gtx.Constraints.Max.X)-310, 0)).Add(gtx.Ops)
  82  		gtx.Constraints.Min = image.Pt(250, gtx.Constraints.Min.Y)
  83  		gtx.Constraints.Max.X = 250
  84  		// paint.Fill(gtx.Ops,  helper.HexARGB("ff559988"))
  85  		t.theme.Inset(
  86  			0,
  87  			t.layout.Vertical().ScrollToEnd().Length(len(t.toasts)).ListElement(t.singleToast).Fn,
  88  		).Fn(gtx)
  89  	}
  90  }
  91  func (t *Toasts) singleToast(gtx l.Context, index int) l.Dimensions {
  92  	if t.toasts[index].ticker < float32(t.duration) {
  93  		t.toasts[index].ticker += 1
  94  		gtx.Constraints.Min = t.singleSize
  95  		// gtx.Constraints.Max = t.singleSize
  96  		gtx.Constraints.Max.X = t.singleSize.X
  97  		sz := gtx.Constraints.Min
  98  		rr := float32(gtx.Px(t.singleCornerRadius))
  99  		
 100  		r := f32.Rect(0, 0, float32(sz.X), float32(sz.Y))
 101  		
 102  		return t.theme.Inset(
 103  			0.05, func(gtx l.Context) l.Dimensions {
 104  				return shadow.Shadow(
 105  					gtx, unit.Dp(3), unit.Dp(1), gui.HexNRGB("ee000000"), t.theme.Flex().Flexed(
 106  						1,
 107  						func(gtx l.Context) l.Dimensions {
 108  							clip.UniformRRect(r, rr).Add(gtx.Ops)
 109  							paint.Fill(gtx.Ops, t.toasts[index].bodyBackground)
 110  							
 111  							return t.theme.Inset(
 112  								0.25,
 113  								t.theme.VFlex().
 114  									Rigid(
 115  										t.theme.Inset(
 116  											0.1,
 117  											t.theme.Fill(t.toasts[index].level, t.theme.Flex().
 118  												Rigid(
 119  													func(gtx l.Context) l.Dimensions {
 120  														return t.theme.Icon().Color("DocText").Scale(1).Src(t.toasts[index].icon).Fn(gtx)
 121  													},
 122  												).
 123  												Flexed(
 124  													1,
 125  													t.theme.H6(t.toasts[index].title).Color("PanelBg").Fn,
 126  												).Fn, l.Center).Fn,
 127  										).Fn,
 128  									).
 129  									Rigid(
 130  										t.theme.Body1(t.toasts[index].content).Color("PanelText").Fn,
 131  									).Fn,
 132  							).Fn(gtx)
 133  						},
 134  					).Fn,
 135  				)
 136  			},
 137  		).Fn(gtx)
 138  	} else {
 139  		t.toasts = remove(t.toasts, index)
 140  		return gui.EmptySpace(0, 0)(gtx)
 141  	}
 142  }
 143  
 144  func remove(slice []toast, s int) []toast {
 145  	return append(slice[:s], slice[s+1:]...)
 146  }
 147