5
0
mirror of https://github.com/wailsapp/wails.git synced 2025-05-02 21:10:54 +08:00

InsertBefore/InsertAfter supported

This commit is contained in:
Lea Anthony 2020-12-05 14:14:46 +11:00
parent e8bb950e06
commit 7e42052da0
No known key found for this signature in database
GPG Key ID: 33DAF7BB90A58405
5 changed files with 287 additions and 60 deletions

View File

@ -7,25 +7,25 @@ import (
// CustomLogger defines what a user can do with a logger
type CustomLogger interface {
// Writeln writes directly to the output with no log level plus line ending
Writeln(message string) error
Writeln(message string)
// Write writes directly to the output with no log level
Write(message string) error
Write(message string)
// Trace level logging. Works like Sprintf.
Trace(format string, args ...interface{}) error
Trace(format string, args ...interface{})
// Debug level logging. Works like Sprintf.
Debug(format string, args ...interface{}) error
Debug(format string, args ...interface{})
// Info level logging. Works like Sprintf.
Info(format string, args ...interface{}) error
Info(format string, args ...interface{})
// Warning level logging. Works like Sprintf.
Warning(format string, args ...interface{}) error
Warning(format string, args ...interface{})
// Error level logging. Works like Sprintf.
Error(format string, args ...interface{}) error
Error(format string, args ...interface{})
// Fatal level logging. Works like Sprintf.
Fatal(format string, args ...interface{})
@ -49,43 +49,43 @@ func newcustomLogger(logger *Logger, name string) *customLogger {
// Writeln writes directly to the output with no log level
// Appends a carriage return to the message
func (l *customLogger) Writeln(message string) error {
return l.logger.Writeln(message)
func (l *customLogger) Writeln(message string) {
l.logger.Writeln(message)
}
// Write writes directly to the output with no log level
func (l *customLogger) Write(message string) error {
return l.logger.Write(message)
func (l *customLogger) Write(message string) {
l.logger.Write(message)
}
// Trace level logging. Works like Sprintf.
func (l *customLogger) Trace(format string, args ...interface{}) error {
func (l *customLogger) Trace(format string, args ...interface{}) {
format = fmt.Sprintf("%s | %s", l.name, format)
return l.logger.Trace(format, args...)
l.logger.Trace(format, args...)
}
// Debug level logging. Works like Sprintf.
func (l *customLogger) Debug(format string, args ...interface{}) error {
func (l *customLogger) Debug(format string, args ...interface{}) {
format = fmt.Sprintf("%s | %s", l.name, format)
return l.logger.Debug(format, args...)
l.logger.Debug(format, args...)
}
// Info level logging. Works like Sprintf.
func (l *customLogger) Info(format string, args ...interface{}) error {
func (l *customLogger) Info(format string, args ...interface{}) {
format = fmt.Sprintf("%s | %s", l.name, format)
return l.logger.Info(format, args...)
l.logger.Info(format, args...)
}
// Warning level logging. Works like Sprintf.
func (l *customLogger) Warning(format string, args ...interface{}) error {
func (l *customLogger) Warning(format string, args ...interface{}) {
format = fmt.Sprintf("%s | %s", l.name, format)
return l.logger.Warning(format, args...)
l.logger.Warning(format, args...)
}
// Error level logging. Works like Sprintf.
func (l *customLogger) Error(format string, args ...interface{}) error {
func (l *customLogger) Error(format string, args ...interface{}) {
format = fmt.Sprintf("%s | %s", l.name, format)
return l.logger.Error(format, args...)
l.logger.Error(format, args...)
}

View File

@ -46,67 +46,60 @@ func (l *Logger) SetLogLevel(level LogLevel) {
// Writeln writes directly to the output with no log level
// Appends a carriage return to the message
func (l *Logger) Writeln(message string) error {
return l.output.Print(message)
func (l *Logger) Writeln(message string) {
l.output.Print(message)
}
// Write writes directly to the output with no log level
func (l *Logger) Write(message string) error {
return l.output.Print(message)
func (l *Logger) Write(message string) {
l.output.Print(message)
}
// Print writes directly to the output with no log level
// Appends a carriage return to the message
func (l *Logger) Print(message string) error {
return l.Write(message)
func (l *Logger) Print(message string) {
l.Write(message)
}
// Trace level logging. Works like Sprintf.
func (l *Logger) Trace(format string, args ...interface{}) error {
func (l *Logger) Trace(format string, args ...interface{}) {
if l.logLevel <= logger.TRACE {
return l.output.Trace(fmt.Sprintf(format, args...))
l.output.Trace(fmt.Sprintf(format, args...))
}
return nil
}
// Debug level logging. Works like Sprintf.
func (l *Logger) Debug(format string, args ...interface{}) error {
func (l *Logger) Debug(format string, args ...interface{}) {
if l.logLevel <= logger.DEBUG {
return l.output.Debug(fmt.Sprintf(format, args...))
l.output.Debug(fmt.Sprintf(format, args...))
}
return nil
}
// Info level logging. Works like Sprintf.
func (l *Logger) Info(format string, args ...interface{}) error {
func (l *Logger) Info(format string, args ...interface{}) {
if l.logLevel <= logger.INFO {
return l.output.Info(fmt.Sprintf(format, args...))
l.output.Info(fmt.Sprintf(format, args...))
}
return nil
}
// Warning level logging. Works like Sprintf.
func (l *Logger) Warning(format string, args ...interface{}) error {
func (l *Logger) Warning(format string, args ...interface{}) {
if l.logLevel <= logger.WARNING {
return l.output.Warning(fmt.Sprintf(format, args...))
l.output.Warning(fmt.Sprintf(format, args...))
}
return nil
}
// Error level logging. Works like Sprintf.
func (l *Logger) Error(format string, args ...interface{}) error {
func (l *Logger) Error(format string, args ...interface{}) {
if l.logLevel <= logger.ERROR {
return l.output.Error(fmt.Sprintf(format, args...))
l.output.Error(fmt.Sprintf(format, args...))
}
return nil
}
// Fatal level logging. Works like Sprintf.
func (l *Logger) Fatal(format string, args ...interface{}) {
err := l.output.Fatal(fmt.Sprintf(format, args...))
// Not much we can do but print it out before exiting
if err != nil {
println(err.Error())
}
l.output.Fatal(fmt.Sprintf(format, args...))
os.Exit(1)
}

View File

@ -168,25 +168,24 @@ func (s *ServiceBus) Subscribe(topic string) (<-chan *Message, error) {
}
// Publish sends the given message on the service bus
func (s *ServiceBus) Publish(topic string, data interface{}) error {
func (s *ServiceBus) Publish(topic string, data interface{}) {
// Prevent publish when closed
if s.closed {
return fmt.Errorf("cannot call publish on closed servicebus")
s.logger.Fatal("cannot call publish on closed servicebus")
return
}
message := NewMessage(topic, data)
s.messageQueue <- message
return nil
}
// PublishForTarget sends the given message on the service bus for the given target
func (s *ServiceBus) PublishForTarget(topic string, data interface{}, target string) error {
func (s *ServiceBus) PublishForTarget(topic string, data interface{}, target string) {
// Prevent publish when closed
if s.closed {
return fmt.Errorf("cannot call publish on closed servicebus")
s.logger.Fatal("cannot call publish on closed servicebus")
return
}
message := NewMessageForTarget(topic, data, target)
s.messageQueue <- message
return nil
}

View File

@ -36,9 +36,10 @@ func (m *MenuItem) Parent() *MenuItem {
// submenu, then this method will not add the item and
// simply return false.
func (m *MenuItem) Append(item *MenuItem) bool {
if m.Type != SubmenuType {
if !m.isSubMenu() {
return false
}
item.parent = m
m.SubMenu = append(m.SubMenu, item)
return true
}
@ -48,9 +49,10 @@ func (m *MenuItem) Append(item *MenuItem) bool {
// submenu, then this method will not add the item and
// simply return false.
func (m *MenuItem) Prepend(item *MenuItem) bool {
if m.Type != SubmenuType {
if !m.isSubMenu() {
return false
}
item.parent = m
m.SubMenu = append([]*MenuItem{item}, m.SubMenu...)
return true
}
@ -80,7 +82,7 @@ func (m *MenuItem) removeByID(id string) bool {
m.SubMenu = append(m.SubMenu[:index], m.SubMenu[index+1:]...)
return true
}
if item.Type == SubmenuType {
if item.isSubMenu() {
result := item.removeByID(id)
if result == true {
return result
@ -90,6 +92,120 @@ func (m *MenuItem) removeByID(id string) bool {
return false
}
// InsertAfter attempts to add the given item after this item in the parent
// menu. If there is no parent menu (we are a top level menu) then false is
// returned
func (m *MenuItem) InsertAfter(item *MenuItem) bool {
// We need to find my parent
if m.parent == nil {
return false
}
// Get my parent to insert the item
return m.parent.insertNewItemAfterGivenItem(m, item)
}
// InsertBefore attempts to add the given item before this item in the parent
// menu. If there is no parent menu (we are a top level menu) then false is
// returned
func (m *MenuItem) InsertBefore(item *MenuItem) bool {
// We need to find my parent
if m.parent == nil {
return false
}
// Get my parent to insert the item
return m.parent.insertNewItemBeforeGivenItem(m, item)
}
// insertNewItemAfterGivenItem will insert the given item after the given target
// in this item's submenu. If we are not a submenu,
// then something bad has happened :/
func (m *MenuItem) insertNewItemAfterGivenItem(target *MenuItem,
newItem *MenuItem) bool {
if !m.isSubMenu() {
return false
}
// Find the index of the target
targetIndex := m.getItemIndex(target)
if targetIndex == -1 {
return false
}
// Insert element into slice
return m.insertItemAtIndex(targetIndex+1, newItem)
}
// insertNewItemBeforeGivenItem will insert the given item before the given
// target in this item's submenu. If we are not a submenu, then something bad
// has happened :/
func (m *MenuItem) insertNewItemBeforeGivenItem(target *MenuItem,
newItem *MenuItem) bool {
if !m.isSubMenu() {
return false
}
// Find the index of the target
targetIndex := m.getItemIndex(target)
if targetIndex == -1 {
return false
}
// Insert element into slice
return m.insertItemAtIndex(targetIndex, newItem)
}
func (m *MenuItem) isSubMenu() bool {
return m.Type == SubmenuType
}
// getItemIndex returns the index of the given target relative to this menu
func (m *MenuItem) getItemIndex(target *MenuItem) int {
// This should only be called on submenus
if !m.isSubMenu() {
return -1
}
// hunt down that bad boy
for index, item := range m.SubMenu {
if item == target {
return index
}
}
return -1
}
// insertItemAtIndex attempts to insert the given item into the submenu at
// the given index
// Credit: https://stackoverflow.com/a/61822301
func (m *MenuItem) insertItemAtIndex(index int, target *MenuItem) bool {
// If index is OOB, return false
if index > len(m.SubMenu) {
return false
}
// Save parent reference
target.parent = m
// If index is last item, then just regular append
if index == len(m.SubMenu) {
m.SubMenu = append(m.SubMenu, target)
return true
}
m.SubMenu = append(m.SubMenu[:index+1], m.SubMenu[index:]...)
m.SubMenu[index] = target
return true
}
// Text is a helper to create basic Text menu items
func Text(label string, id string) *MenuItem {
return TextWithAccelerator(label, id, nil)
@ -159,3 +275,20 @@ func SubMenu(label string, items []*MenuItem) *MenuItem {
return result
}
// SubMenuWithID is a helper to create Submenus with an ID
func SubMenuWithID(label string, id string, items []*MenuItem) *MenuItem {
result := &MenuItem{
Label: label,
SubMenu: items,
ID: id,
Type: SubmenuType,
}
// Fix up parent pointers
for _, item := range items {
item.parent = result
}
return result
}

View File

@ -2,6 +2,7 @@ package main
import (
"fmt"
"math/rand"
"strconv"
"sync"
@ -13,8 +14,10 @@ import (
type Menu struct {
runtime *wails.Runtime
dynamicMenuCounter int
lock sync.Mutex
dynamicMenuCounter int
lock sync.Mutex
dynamicMenuItems map[string]*menu.MenuItem
anotherDynamicMenuCounter int
}
// WailsInit is called at application startup
@ -34,6 +37,9 @@ func (m *Menu) WailsInit(runtime *wails.Runtime) error {
fmt.Printf("We can use UTF-8 IDs: %s\n", mi.Label)
})
// Create dynamic menu items 2 submenu
m.createDynamicMenuTwo()
// Setup dynamic menus
m.runtime.Menu.On("Add Menu Item", m.addMenu)
return nil
@ -111,6 +117,102 @@ func (m *Menu) removeMenu(_ *menu.MenuItem) {
m.runtime.Menu.Update()
}
func (m *Menu) createDynamicMenuTwo() {
// Create our submenu
dm2 := menu.SubMenu("Dynamic Menus 2", []*menu.MenuItem{
menu.TextWithAccelerator("Insert Before Random Menu Item",
"Insert Before Random", menu.CmdOrCtrlAccel("]")),
menu.TextWithAccelerator("Insert After Random Menu Item",
"Insert After Random", menu.CmdOrCtrlAccel("[")),
menu.Separator(),
})
m.runtime.Menu.On("Insert Before Random", m.insertBeforeRandom)
m.runtime.Menu.On("Insert After Random", m.insertAfterRandom)
// Initialise out map
m.dynamicMenuItems = make(map[string]*menu.MenuItem)
// Create some random menu items
m.anotherDynamicMenuCounter = 5
for index := 0; index < m.anotherDynamicMenuCounter; index++ {
text := "Other Dynamic Menu Item " + strconv.Itoa(index+1)
item := menu.Text(text, text)
m.dynamicMenuItems[text] = item
dm2.Append(item)
}
// Insert this menu after Dynamic Menu Item 1
dm1 := m.runtime.Menu.GetByID("Dynamic Menus 1")
dm1.InsertAfter(dm2)
m.runtime.Menu.Update()
}
func (m *Menu) insertBeforeRandom(_ *menu.MenuItem) {
// Lock because this method will be called in a goroutine
m.lock.Lock()
defer m.lock.Unlock()
// Pick a random menu
var randomItemID string
var count int
var random = rand.Intn(len(m.dynamicMenuItems))
for randomItemID = range m.dynamicMenuItems {
if count == random {
break
}
count++
}
m.anotherDynamicMenuCounter++
text := "Other Dynamic Menu Item " + strconv.Itoa(
m.anotherDynamicMenuCounter+1)
newItem := menu.Text(text, text)
m.dynamicMenuItems[text] = newItem
item := m.runtime.Menu.GetByID(randomItemID)
m.runtime.Log.Info(fmt.Sprintf(
"Inserting menu item '%s' before menu item '%s'", newItem.Label,
item.Label))
item.InsertBefore(newItem)
m.runtime.Menu.Update()
}
func (m *Menu) insertAfterRandom(_ *menu.MenuItem) {
// Lock because this method will be called in a goroutine
m.lock.Lock()
defer m.lock.Unlock()
// Pick a random menu
var randomItemID string
var count int
var random = rand.Intn(len(m.dynamicMenuItems))
for randomItemID = range m.dynamicMenuItems {
if count == random {
break
}
count++
}
m.anotherDynamicMenuCounter++
text := "Other Dynamic Menu Item " + strconv.Itoa(
m.anotherDynamicMenuCounter+1)
newItem := menu.Text(text, text)
item := m.runtime.Menu.GetByID(randomItemID)
m.dynamicMenuItems[text] = newItem
m.runtime.Log.Info(fmt.Sprintf(
"Inserting menu item '%s' after menu item '%s'", newItem.Label,
item.Label))
item.InsertAfter(newItem)
m.runtime.Menu.Update()
}
func createApplicationMenu() *menu.Menu {
// Create menu
@ -184,7 +286,7 @@ func createApplicationMenu() *menu.Menu {
menu.TextWithAccelerator("Plus", "Plus", menu.Accel("+")),
}),
}),
menu.SubMenu("Dynamic Menus", []*menu.MenuItem{
menu.SubMenuWithID("Dynamic Menus 1", "Dynamic Menus 1", []*menu.MenuItem{
menu.TextWithAccelerator("Add Menu Item", "Add Menu Item", menu.CmdOrCtrlAccel("+")),
menu.Separator(),
}),