| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210 |
- package glfw
- import (
- "fyne.io/fyne/v2"
- "fyne.io/fyne/v2/canvas"
- "fyne.io/fyne/v2/container"
- "fyne.io/fyne/v2/driver/desktop"
- "fyne.io/fyne/v2/internal/widget"
- "fyne.io/fyne/v2/theme"
- )
- var _ fyne.Widget = (*MenuBar)(nil)
- // MenuBar is a widget for displaying a fyne.MainMenu in a bar.
- type MenuBar struct {
- widget.Base
- Items []fyne.CanvasObject
- active bool
- activeItem *menuBarItem
- canvas fyne.Canvas
- }
- // NewMenuBar creates a menu bar populated with items from the passed main menu structure.
- func NewMenuBar(mainMenu *fyne.MainMenu, canvas fyne.Canvas) *MenuBar {
- items := make([]fyne.CanvasObject, len(mainMenu.Items))
- b := &MenuBar{Items: items, canvas: canvas}
- b.ExtendBaseWidget(b)
- for i, menu := range mainMenu.Items {
- barItem := &menuBarItem{Menu: menu, Parent: b}
- barItem.ExtendBaseWidget(barItem)
- items[i] = barItem
- }
- return b
- }
- // CreateRenderer returns a new renderer for the menu bar.
- //
- // Implements: fyne.Widget
- func (b *MenuBar) CreateRenderer() fyne.WidgetRenderer {
- cont := container.NewHBox(b.Items...)
- background := canvas.NewRectangle(theme.BackgroundColor())
- underlay := &menuBarUnderlay{action: b.deactivate}
- underlay.ExtendBaseWidget(underlay)
- objects := []fyne.CanvasObject{underlay, background, cont}
- for _, item := range b.Items {
- objects = append(objects, item.(*menuBarItem).Child())
- }
- return &menuBarRenderer{
- widget.NewShadowingRenderer(objects, widget.MenuLevel),
- b,
- background,
- underlay,
- cont,
- }
- }
- // IsActive returns whether the menu bar is active or not.
- // An active menu bar shows the current selected menu and should have the focus.
- func (b *MenuBar) IsActive() bool {
- return b.active
- }
- // Toggle changes the activation state of the menu bar.
- // On activation, the first item will become active.
- func (b *MenuBar) Toggle() {
- b.toggle(b.Items[0].(*menuBarItem))
- }
- func (b *MenuBar) activateChild(item *menuBarItem) {
- if !b.active {
- b.active = true
- }
- if item.Child() != nil {
- item.Child().DeactivateChild()
- }
- if b.activeItem == item {
- return
- }
- if b.activeItem != nil {
- if c := b.activeItem.Child(); c != nil {
- c.Hide()
- }
- b.activeItem.Refresh()
- }
- b.activeItem = item
- if item == nil {
- return
- }
- item.Refresh()
- item.Child().Show()
- b.Refresh()
- }
- func (b *MenuBar) deactivate() {
- if !b.active {
- return
- }
- b.active = false
- if b.activeItem != nil {
- if c := b.activeItem.Child(); c != nil {
- defer c.Dismiss()
- c.Hide()
- }
- b.activeItem.Refresh()
- b.activeItem = nil
- }
- b.Refresh()
- }
- func (b *MenuBar) toggle(item *menuBarItem) {
- if b.active {
- b.canvas.Unfocus()
- b.deactivate()
- } else {
- b.activateChild(item)
- b.canvas.Focus(item)
- }
- }
- type menuBarRenderer struct {
- *widget.ShadowingRenderer
- b *MenuBar
- background *canvas.Rectangle
- underlay *menuBarUnderlay
- cont *fyne.Container
- }
- func (r *menuBarRenderer) Layout(size fyne.Size) {
- r.LayoutShadow(size, fyne.NewPos(0, 0))
- minSize := r.MinSize()
- if size.Height != minSize.Height || size.Width < minSize.Width {
- r.b.Resize(fyne.NewSize(fyne.Max(size.Width, minSize.Width), minSize.Height))
- return
- }
- if r.b.active {
- r.underlay.Resize(r.b.canvas.Size())
- } else {
- r.underlay.Resize(fyne.NewSize(0, 0))
- }
- r.cont.Resize(fyne.NewSize(size.Width-2*theme.InnerPadding(), size.Height))
- r.cont.Move(fyne.NewPos(theme.InnerPadding(), 0))
- if item := r.b.activeItem; item != nil {
- if item.Child().Size().IsZero() {
- item.Child().Resize(item.Child().MinSize())
- }
- item.Child().Move(fyne.NewPos(item.Position().X+theme.InnerPadding(), item.Size().Height))
- }
- r.background.Resize(size)
- }
- func (r *menuBarRenderer) MinSize() fyne.Size {
- return r.cont.MinSize().Add(fyne.NewSize(theme.InnerPadding()*2, 0))
- }
- func (r *menuBarRenderer) Refresh() {
- r.Layout(r.b.Size())
- r.background.FillColor = theme.BackgroundColor()
- r.background.Refresh()
- r.ShadowingRenderer.RefreshShadow()
- canvas.Refresh(r.b)
- }
- // Transparent underlay shown as soon as menu is active.
- // It catches mouse events outside the menu's objects.
- type menuBarUnderlay struct {
- widget.Base
- action func()
- }
- var _ fyne.Widget = (*menuBarUnderlay)(nil)
- var _ fyne.Tappable = (*menuBarUnderlay)(nil) // deactivate menu on click outside
- var _ desktop.Hoverable = (*menuBarUnderlay)(nil) // block hover events on main content
- func (u *menuBarUnderlay) CreateRenderer() fyne.WidgetRenderer {
- return &menuUnderlayRenderer{}
- }
- func (u *menuBarUnderlay) MouseIn(*desktop.MouseEvent) {
- }
- func (u *menuBarUnderlay) MouseOut() {
- }
- func (u *menuBarUnderlay) MouseMoved(*desktop.MouseEvent) {
- }
- func (u *menuBarUnderlay) Tapped(*fyne.PointEvent) {
- u.action()
- }
- type menuUnderlayRenderer struct {
- widget.BaseRenderer
- }
- var _ fyne.WidgetRenderer = (*menuUnderlayRenderer)(nil)
- func (r *menuUnderlayRenderer) Layout(fyne.Size) {
- }
- func (r *menuUnderlayRenderer) MinSize() fyne.Size {
- return fyne.NewSize(0, 0)
- }
- func (r *menuUnderlayRenderer) Refresh() {
- }
|