| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227 |
- package widget
- import (
- "image/color"
- "fyne.io/fyne/v2"
- "fyne.io/fyne/v2/canvas"
- "fyne.io/fyne/v2/driver/desktop"
- "fyne.io/fyne/v2/internal/widget"
- "fyne.io/fyne/v2/theme"
- )
- var _ fyne.Widget = (*radioItem)(nil)
- var _ desktop.Hoverable = (*radioItem)(nil)
- var _ fyne.Tappable = (*radioItem)(nil)
- var _ fyne.Focusable = (*radioItem)(nil)
- func newRadioItem(label string, onTap func(*radioItem)) *radioItem {
- i := &radioItem{Label: label, onTap: onTap}
- i.ExtendBaseWidget(i)
- return i
- }
- // radioItem is a single radio item to be used by RadioGroup.
- type radioItem struct {
- DisableableWidget
- Label string
- Selected bool
- focused bool
- hovered bool
- onTap func(item *radioItem)
- }
- // CreateRenderer is a private method to Fyne which links this widget to its renderer.
- //
- // Implements: fyne.Widget
- func (i *radioItem) CreateRenderer() fyne.WidgetRenderer {
- focusIndicator := canvas.NewCircle(color.Transparent)
- // TODO move to `theme.RadioButtonFillIcon()` when we add it in 2.4
- icon := canvas.NewImageFromResource(fyne.CurrentApp().Settings().Theme().Icon("iconNameRadioButtonFill"))
- over := canvas.NewImageFromResource(theme.NewThemedResource(theme.RadioButtonIcon()))
- label := canvas.NewText(i.Label, theme.ForegroundColor())
- label.Alignment = fyne.TextAlignLeading
- r := &radioItemRenderer{
- BaseRenderer: widget.NewBaseRenderer([]fyne.CanvasObject{focusIndicator, icon, over, label}),
- focusIndicator: focusIndicator,
- icon: icon,
- over: over,
- item: i,
- label: label,
- }
- r.update()
- return r
- }
- // FocusGained is called when this item gained the focus.
- //
- // Implements: fyne.Focusable
- func (i *radioItem) FocusGained() {
- i.focused = true
- i.Refresh()
- }
- // FocusLost is called when this item lost the focus.
- //
- // Implements: fyne.Focusable
- func (i *radioItem) FocusLost() {
- i.focused = false
- i.Refresh()
- }
- // MouseIn is called when a desktop pointer enters the widget.
- //
- // Implements: desktop.Hoverable
- func (i *radioItem) MouseIn(_ *desktop.MouseEvent) {
- if i.Disabled() {
- return
- }
- i.hovered = true
- i.Refresh()
- }
- // MouseMoved is called when a desktop pointer hovers over the widget.
- //
- // Implements: desktop.Hoverable
- func (i *radioItem) MouseMoved(_ *desktop.MouseEvent) {
- }
- // MouseOut is called when a desktop pointer exits the widget
- //
- // Implements: desktop.Hoverable
- func (i *radioItem) MouseOut() {
- if i.Disabled() {
- return
- }
- i.hovered = false
- i.Refresh()
- }
- // SetSelected sets whether this radio item is selected or not.
- func (i *radioItem) SetSelected(selected bool) {
- if i.Disabled() || i.Selected == selected {
- return
- }
- i.Selected = selected
- i.Refresh()
- }
- // Tapped is called when a pointer tapped event is captured and triggers any change handler
- //
- // Implements: fyne.Tappable
- func (i *radioItem) Tapped(_ *fyne.PointEvent) {
- if !i.focused && !fyne.CurrentDevice().IsMobile() {
- impl := i.super()
- if c := fyne.CurrentApp().Driver().CanvasForObject(impl); c != nil {
- c.Focus(impl.(fyne.Focusable))
- }
- }
- i.toggle()
- }
- // TypedKey is called when this item receives a key event.
- //
- // Implements: fyne.Focusable
- func (i *radioItem) TypedKey(_ *fyne.KeyEvent) {
- }
- // TypedRune is called when this item receives a char event.
- //
- // Implements: fyne.Focusable
- func (i *radioItem) TypedRune(r rune) {
- if r == ' ' {
- i.toggle()
- }
- }
- func (i *radioItem) toggle() {
- if i.Disabled() || i.onTap == nil {
- return
- }
- i.onTap(i)
- }
- type radioItemRenderer struct {
- widget.BaseRenderer
- focusIndicator *canvas.Circle
- icon, over *canvas.Image
- item *radioItem
- label *canvas.Text
- }
- func (r *radioItemRenderer) Layout(size fyne.Size) {
- focusIndicatorSize := fyne.NewSquareSize(theme.IconInlineSize() + theme.InnerPadding())
- r.focusIndicator.Resize(focusIndicatorSize)
- r.focusIndicator.Move(fyne.NewPos(theme.InputBorderSize(), (size.Height-focusIndicatorSize.Height)/2))
- labelSize := fyne.NewSize(size.Width, size.Height)
- r.label.Resize(labelSize)
- r.label.Move(fyne.NewPos(focusIndicatorSize.Width+theme.Padding(), 0))
- iconPos := fyne.NewPos(theme.InnerPadding()/2+theme.InputBorderSize(), (size.Height-theme.IconInlineSize())/2)
- iconSize := fyne.NewSquareSize(theme.IconInlineSize())
- r.icon.Resize(iconSize)
- r.icon.Move(iconPos)
- r.over.Resize(iconSize)
- r.over.Move(iconPos)
- }
- func (r *radioItemRenderer) MinSize() fyne.Size {
- inPad := theme.InnerPadding() * 2
- return r.label.MinSize().
- Add(fyne.NewSize(inPad, inPad)).
- Add(fyne.NewSize(theme.IconInlineSize()+theme.Padding(), 0))
- }
- func (r *radioItemRenderer) Refresh() {
- r.update()
- canvas.Refresh(r.item.super())
- }
- func (r *radioItemRenderer) update() {
- r.label.Text = r.item.Label
- r.label.Color = theme.ForegroundColor()
- r.label.TextSize = theme.TextSize()
- if r.item.Disabled() {
- r.label.Color = theme.DisabledColor()
- }
- out := theme.NewThemedResource(theme.RadioButtonIcon())
- out.ColorName = theme.ColorNameInputBorder
- // TODO move to `theme.RadioButtonFillIcon()` when we add it in 2.4
- in := theme.NewThemedResource(fyne.CurrentApp().Settings().Theme().Icon("iconNameRadioButtonFill"))
- in.ColorName = theme.ColorNameInputBackground
- if r.item.Selected {
- in.ColorName = theme.ColorNamePrimary
- out.ColorName = theme.ColorNameForeground
- }
- if r.item.Disabled() {
- if r.item.Selected {
- in.ColorName = theme.ColorNameDisabled
- } else {
- in.ColorName = theme.ColorNameBackground
- }
- out.ColorName = theme.ColorNameDisabled
- }
- r.icon.Resource = in
- r.over.Resource = out
- if r.item.Disabled() {
- r.focusIndicator.FillColor = color.Transparent
- } else if r.item.focused {
- r.focusIndicator.FillColor = theme.FocusColor()
- } else if r.item.hovered {
- r.focusIndicator.FillColor = theme.HoverColor()
- } else {
- r.focusIndicator.FillColor = color.Transparent
- }
- }
|