github.com/AlpineAIO/wails/v2@v2.0.0-beta.32.0.20240505041856-1047a8fa5fef/internal/menumanager/traymenu.go (about) 1 package menumanager 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "strconv" 7 "strings" 8 "sync" 9 10 "github.com/leaanthony/go-ansi-parser" 11 12 "github.com/AlpineAIO/wails/v2/pkg/menu" 13 "github.com/pkg/errors" 14 ) 15 16 var ( 17 trayMenuID int 18 trayMenuIDMutex sync.Mutex 19 ) 20 21 func generateTrayID() string { 22 var idStr string 23 trayMenuIDMutex.Lock() 24 idStr = strconv.Itoa(trayMenuID) 25 trayMenuID++ 26 trayMenuIDMutex.Unlock() 27 return idStr 28 } 29 30 type TrayMenu struct { 31 ID string 32 Label string 33 FontSize int 34 FontName string 35 Disabled bool 36 Tooltip string `json:",omitempty"` 37 Image string 38 MacTemplateImage bool 39 RGBA string 40 menuItemMap *MenuItemMap 41 menu *menu.Menu 42 ProcessedMenu *WailsMenu 43 trayMenu *menu.TrayMenu 44 StyledLabel []*ansi.StyledText `json:",omitempty"` 45 } 46 47 func (t *TrayMenu) AsJSON() (string, error) { 48 data, err := json.Marshal(t) 49 if err != nil { 50 return "", err 51 } 52 return string(data), nil 53 } 54 55 func NewTrayMenu(trayMenu *menu.TrayMenu) *TrayMenu { 56 // Parse ANSI text 57 var styledLabel []*ansi.StyledText 58 tempLabel := trayMenu.Label 59 if strings.Contains(tempLabel, "\033[") { 60 parsedLabel, err := ansi.Parse(tempLabel) 61 if err == nil { 62 styledLabel = parsedLabel 63 } 64 } 65 66 result := &TrayMenu{ 67 Label: trayMenu.Label, 68 FontName: trayMenu.FontName, 69 FontSize: trayMenu.FontSize, 70 Disabled: trayMenu.Disabled, 71 Tooltip: trayMenu.Tooltip, 72 Image: trayMenu.Image, 73 MacTemplateImage: trayMenu.MacTemplateImage, 74 menu: trayMenu.Menu, 75 RGBA: trayMenu.RGBA, 76 menuItemMap: NewMenuItemMap(), 77 trayMenu: trayMenu, 78 StyledLabel: styledLabel, 79 } 80 81 result.menuItemMap.AddMenu(trayMenu.Menu) 82 result.ProcessedMenu = NewWailsMenu(result.menuItemMap, result.menu) 83 84 return result 85 } 86 87 func (m *Manager) OnTrayMenuOpen(id string) { 88 trayMenu, ok := m.trayMenus[id] 89 if !ok { 90 return 91 } 92 if trayMenu.trayMenu.OnOpen == nil { 93 return 94 } 95 go trayMenu.trayMenu.OnOpen() 96 } 97 98 func (m *Manager) OnTrayMenuClose(id string) { 99 trayMenu, ok := m.trayMenus[id] 100 if !ok { 101 return 102 } 103 if trayMenu.trayMenu.OnClose == nil { 104 return 105 } 106 go trayMenu.trayMenu.OnClose() 107 } 108 109 func (m *Manager) AddTrayMenu(trayMenu *menu.TrayMenu) (string, error) { 110 newTrayMenu := NewTrayMenu(trayMenu) 111 112 // Hook up a new ID 113 trayID := generateTrayID() 114 newTrayMenu.ID = trayID 115 116 // Save the references 117 m.trayMenus[trayID] = newTrayMenu 118 m.trayMenuPointers[trayMenu] = trayID 119 120 return newTrayMenu.AsJSON() 121 } 122 123 func (m *Manager) GetTrayID(trayMenu *menu.TrayMenu) (string, error) { 124 trayID, exists := m.trayMenuPointers[trayMenu] 125 if !exists { 126 return "", fmt.Errorf("Unable to find menu ID for tray menu!") 127 } 128 return trayID, nil 129 } 130 131 // SetTrayMenu updates or creates a menu 132 func (m *Manager) SetTrayMenu(trayMenu *menu.TrayMenu) (string, error) { 133 trayID, trayMenuKnown := m.trayMenuPointers[trayMenu] 134 if !trayMenuKnown { 135 return m.AddTrayMenu(trayMenu) 136 } 137 138 // Create the updated tray menu 139 updatedTrayMenu := NewTrayMenu(trayMenu) 140 updatedTrayMenu.ID = trayID 141 142 // Save the reference 143 m.trayMenus[trayID] = updatedTrayMenu 144 145 return updatedTrayMenu.AsJSON() 146 } 147 148 func (m *Manager) GetTrayMenus() ([]string, error) { 149 result := []string{} 150 for _, trayMenu := range m.trayMenus { 151 JSON, err := trayMenu.AsJSON() 152 if err != nil { 153 return nil, err 154 } 155 result = append(result, JSON) 156 } 157 158 return result, nil 159 } 160 161 func (m *Manager) UpdateTrayMenuLabel(trayMenu *menu.TrayMenu) (string, error) { 162 trayID, trayMenuKnown := m.trayMenuPointers[trayMenu] 163 if !trayMenuKnown { 164 return "", fmt.Errorf("[UpdateTrayMenuLabel] unknown tray id for tray %s", trayMenu.Label) 165 } 166 167 type LabelUpdate struct { 168 ID string 169 Label string `json:",omitempty"` 170 FontName string `json:",omitempty"` 171 FontSize int 172 RGBA string `json:",omitempty"` 173 Disabled bool 174 Tooltip string `json:",omitempty"` 175 Image string `json:",omitempty"` 176 MacTemplateImage bool 177 StyledLabel []*ansi.StyledText `json:",omitempty"` 178 } 179 180 // Parse ANSI text 181 var styledLabel []*ansi.StyledText 182 tempLabel := trayMenu.Label 183 if strings.Contains(tempLabel, "\033[") { 184 parsedLabel, err := ansi.Parse(tempLabel) 185 if err == nil { 186 styledLabel = parsedLabel 187 } 188 } 189 190 update := &LabelUpdate{ 191 ID: trayID, 192 Label: trayMenu.Label, 193 FontName: trayMenu.FontName, 194 FontSize: trayMenu.FontSize, 195 Disabled: trayMenu.Disabled, 196 Tooltip: trayMenu.Tooltip, 197 Image: trayMenu.Image, 198 MacTemplateImage: trayMenu.MacTemplateImage, 199 RGBA: trayMenu.RGBA, 200 StyledLabel: styledLabel, 201 } 202 203 data, err := json.Marshal(update) 204 if err != nil { 205 return "", errors.Wrap(err, "[UpdateTrayMenuLabel] ") 206 } 207 208 return string(data), nil 209 } 210 211 func (m *Manager) GetContextMenus() ([]string, error) { 212 result := []string{} 213 for _, contextMenu := range m.contextMenus { 214 JSON, err := contextMenu.AsJSON() 215 if err != nil { 216 return nil, err 217 } 218 result = append(result, JSON) 219 } 220 221 return result, nil 222 }