mirror of
https://github.com/taigrr/wails.git
synced 2026-04-08 08:01:35 -07:00
Compare commits
23 Commits
v2.0.0-alp
...
v2.0.0-alp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
913fe8d184 | ||
|
|
4ce8130cdf | ||
|
|
fe87463b78 | ||
|
|
fe0f0e29e8 | ||
|
|
83d6dac7cf | ||
|
|
02500e0930 | ||
|
|
5e1187f437 | ||
|
|
064ff3b65e | ||
|
|
b5c7019bf0 | ||
|
|
e9d16e77a3 | ||
|
|
2415d4c531 | ||
|
|
3f75213ce3 | ||
|
|
6120ceabf1 | ||
|
|
95a95d1750 | ||
|
|
d923e84456 | ||
|
|
343f573e78 | ||
|
|
c6d87da4f0 | ||
|
|
a9faebe51a | ||
|
|
d436f5d1be | ||
|
|
f40899821f | ||
|
|
2a64ed19a3 | ||
|
|
47bca0be88 | ||
|
|
7ac8cc6b8b |
@@ -26,7 +26,7 @@ export function OpenURL(url) {
|
||||
* Opens the given filename using the system's default file handler
|
||||
*
|
||||
* @export
|
||||
* @param {sting} filename
|
||||
* @param {string} filename
|
||||
* @returns
|
||||
*/
|
||||
export function OpenFile(filename) {
|
||||
|
||||
@@ -62,7 +62,7 @@ if (window.crypto) {
|
||||
export function Call(bindingName, data, timeout) {
|
||||
|
||||
// Timeout infinite by default
|
||||
if (timeout == null || timeout == undefined) {
|
||||
if (timeout == null) {
|
||||
timeout = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ function Invoke(message) {
|
||||
*
|
||||
* @export
|
||||
* @param {string} type
|
||||
* @param {string} payload
|
||||
* @param {Object} payload
|
||||
* @param {string=} callbackID
|
||||
*/
|
||||
export function SendMessage(type, payload, callbackID) {
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
package main
|
||||
|
||||
var version = "v2.0.0-alpha.10"
|
||||
var version = "v2.0.0-alpha.16"
|
||||
|
||||
@@ -2,11 +2,39 @@
|
||||
|
||||
package app
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"github.com/wailsapp/wails/v2/pkg/logger"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Init initialises the application for a debug environment
|
||||
func (a *App) Init() error {
|
||||
// Indicate debug mode
|
||||
a.debug = true
|
||||
// Enable dev tools
|
||||
a.options.DevTools = true
|
||||
|
||||
if a.appType == "desktop" {
|
||||
// Enable dev tools
|
||||
a.options.DevTools = true
|
||||
}
|
||||
|
||||
// Set log levels
|
||||
greeting := flag.String("loglevel", "debug", "Loglevel to use - Trace, Debug, Info, Warning, Error")
|
||||
flag.Parse()
|
||||
if len(*greeting) > 0 {
|
||||
switch strings.ToLower(*greeting) {
|
||||
case "trace":
|
||||
a.logger.SetLogLevel(logger.TRACE)
|
||||
case "info":
|
||||
a.logger.SetLogLevel(logger.INFO)
|
||||
case "warning":
|
||||
a.logger.SetLogLevel(logger.WARNING)
|
||||
case "error":
|
||||
a.logger.SetLogLevel(logger.ERROR)
|
||||
default:
|
||||
a.logger.SetLogLevel(logger.DEBUG)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -8,9 +8,10 @@ package app
|
||||
// will be unknown and the application will not work as expected.
|
||||
|
||||
import (
|
||||
"github.com/wailsapp/wails/v2/internal/logger"
|
||||
"os"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/logger"
|
||||
|
||||
"github.com/wailsapp/wails/v2/pkg/options"
|
||||
)
|
||||
|
||||
@@ -38,7 +39,3 @@ func (a *App) Run() error {
|
||||
os.Exit(1)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Bind the dummy interface
|
||||
func (a *App) Bind(_ interface{}) {
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@ import (
|
||||
|
||||
// App defines a Wails application structure
|
||||
type App struct {
|
||||
appType string
|
||||
|
||||
window *ffenestri.Application
|
||||
servicebus *servicebus.ServiceBus
|
||||
logger *logger.Logger
|
||||
@@ -80,10 +82,11 @@ func CreateApp(appoptions *options.App) (*App, error) {
|
||||
window := ffenestri.NewApplicationWithConfig(appoptions, myLogger, menuManager)
|
||||
|
||||
result := &App{
|
||||
appType: "desktop",
|
||||
window: window,
|
||||
servicebus: servicebus.New(myLogger),
|
||||
logger: myLogger,
|
||||
bindings: binding.NewBindings(myLogger),
|
||||
bindings: binding.NewBindings(myLogger, appoptions.Bind),
|
||||
menuManager: menuManager,
|
||||
startupCallback: appoptions.Startup,
|
||||
shutdownCallback: appoptions.Shutdown,
|
||||
@@ -213,14 +216,3 @@ func (a *App) Run() error {
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Bind a struct to the application by passing in
|
||||
// a pointer to it
|
||||
func (a *App) Bind(structPtr interface{}) {
|
||||
|
||||
// Add the struct to the bindings
|
||||
err := a.bindings.Add(structPtr)
|
||||
if err != nil {
|
||||
a.logger.Fatal("Error during binding: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ func CreateApp(options *Options) *App {
|
||||
webserver: webserver.NewWebServer(myLogger),
|
||||
servicebus: servicebus.New(myLogger),
|
||||
logger: myLogger,
|
||||
bindings: binding.NewBindings(myLogger),
|
||||
bindings: binding.NewBindings(myLogger, options.Bind),
|
||||
}
|
||||
|
||||
// Initialise the app
|
||||
@@ -192,14 +192,3 @@ func (a *App) Run() error {
|
||||
|
||||
return cli.Run()
|
||||
}
|
||||
|
||||
// Bind a struct to the application by passing in
|
||||
// a pointer to it
|
||||
func (a *App) Bind(structPtr interface{}) {
|
||||
|
||||
// Add the struct to the bindings
|
||||
err := a.bindings.Add(structPtr)
|
||||
if err != nil {
|
||||
a.logger.Fatal("Error during binding: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,10 +6,13 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/wailsapp/wails/v2/pkg/options"
|
||||
|
||||
"github.com/leaanthony/clir"
|
||||
"github.com/wailsapp/wails/v2/internal/binding"
|
||||
"github.com/wailsapp/wails/v2/internal/logger"
|
||||
"github.com/wailsapp/wails/v2/internal/messagedispatcher"
|
||||
"github.com/wailsapp/wails/v2/internal/runtime"
|
||||
"github.com/wailsapp/wails/v2/internal/servicebus"
|
||||
"github.com/wailsapp/wails/v2/internal/subsystem"
|
||||
"github.com/wailsapp/wails/v2/internal/webserver"
|
||||
@@ -17,12 +20,16 @@ import (
|
||||
|
||||
// App defines a Wails application structure
|
||||
type App struct {
|
||||
appType string
|
||||
|
||||
binding *subsystem.Binding
|
||||
call *subsystem.Call
|
||||
event *subsystem.Event
|
||||
log *subsystem.Log
|
||||
runtime *subsystem.Runtime
|
||||
|
||||
options *options.App
|
||||
|
||||
bindings *binding.Bindings
|
||||
logger *logger.Logger
|
||||
dispatcher *messagedispatcher.Dispatcher
|
||||
@@ -30,28 +37,40 @@ type App struct {
|
||||
webserver *webserver.WebServer
|
||||
|
||||
debug bool
|
||||
|
||||
// Application Stores
|
||||
loglevelStore *runtime.Store
|
||||
appconfigStore *runtime.Store
|
||||
|
||||
// Startup/Shutdown
|
||||
startupCallback func(*runtime.Runtime)
|
||||
shutdownCallback func()
|
||||
}
|
||||
|
||||
// Create App
|
||||
func CreateApp(options *Options) *App {
|
||||
options.mergeDefaults()
|
||||
// We ignore the inputs (for now)
|
||||
func CreateApp(appoptions *options.App) (*App, error) {
|
||||
|
||||
// TODO: Allow logger output override on CLI
|
||||
myLogger := logger.New(os.Stdout)
|
||||
myLogger.SetLogLevel(logger.TRACE)
|
||||
// Merge default options
|
||||
options.MergeDefaults(appoptions)
|
||||
|
||||
// Set up logger
|
||||
myLogger := logger.New(appoptions.Logger)
|
||||
myLogger.SetLogLevel(appoptions.LogLevel)
|
||||
|
||||
result := &App{
|
||||
bindings: binding.NewBindings(myLogger),
|
||||
logger: myLogger,
|
||||
servicebus: servicebus.New(myLogger),
|
||||
webserver: webserver.NewWebServer(myLogger),
|
||||
appType: "server",
|
||||
bindings: binding.NewBindings(myLogger, options.Bind),
|
||||
logger: myLogger,
|
||||
servicebus: servicebus.New(myLogger),
|
||||
webserver: webserver.NewWebServer(myLogger),
|
||||
startupCallback: appoptions.Startup,
|
||||
shutdownCallback: appoptions.Shutdown,
|
||||
}
|
||||
|
||||
// Initialise app
|
||||
result.Init()
|
||||
|
||||
return result
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Run the application
|
||||
@@ -88,8 +107,21 @@ func (a *App) Run() error {
|
||||
if debugMode {
|
||||
a.servicebus.Debug()
|
||||
}
|
||||
|
||||
// Start the runtime
|
||||
runtime, err := subsystem.NewRuntime(a.servicebus, a.logger, a.startupCallback, a.shutdownCallback)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.runtime = runtime
|
||||
a.runtime.Start()
|
||||
|
||||
// Application Stores
|
||||
a.loglevelStore = a.runtime.GoRuntime().Store.New("wails:loglevel", a.options.LogLevel)
|
||||
a.appconfigStore = a.runtime.GoRuntime().Store.New("wails:appconfig", a.options)
|
||||
|
||||
a.servicebus.Start()
|
||||
log, err := subsystem.NewLog(a.servicebus, a.logger)
|
||||
log, err := subsystem.NewLog(a.servicebus, a.logger, a.loglevelStore)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -102,14 +134,6 @@ func (a *App) Run() error {
|
||||
a.dispatcher = dispatcher
|
||||
a.dispatcher.Start()
|
||||
|
||||
// Start the runtime
|
||||
runtime, err := subsystem.NewRuntime(a.servicebus, a.logger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.runtime = runtime
|
||||
a.runtime.Start()
|
||||
|
||||
// Start the binding subsystem
|
||||
binding, err := subsystem.NewBinding(a.servicebus, a.logger, a.bindings, runtime.GoRuntime())
|
||||
if err != nil {
|
||||
@@ -127,7 +151,7 @@ func (a *App) Run() error {
|
||||
a.event.Start()
|
||||
|
||||
// Start the call subsystem
|
||||
call, err := subsystem.NewCall(a.servicebus, a.logger, a.bindings.DB())
|
||||
call, err := subsystem.NewCall(a.servicebus, a.logger, a.bindings.DB(), a.runtime.GoRuntime())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -147,14 +171,3 @@ func (a *App) Run() error {
|
||||
|
||||
return cli.Run()
|
||||
}
|
||||
|
||||
// Bind a struct to the application by passing in
|
||||
// a pointer to it
|
||||
func (a *App) Bind(structPtr interface{}) {
|
||||
|
||||
// Add the struct to the bindings
|
||||
err := a.bindings.Add(structPtr)
|
||||
if err != nil {
|
||||
a.logger.Fatal("Error during binding: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,11 +13,21 @@ type Bindings struct {
|
||||
}
|
||||
|
||||
// NewBindings returns a new Bindings object
|
||||
func NewBindings(logger *logger.Logger) *Bindings {
|
||||
return &Bindings{
|
||||
func NewBindings(logger *logger.Logger, structPointersToBind []interface{}) *Bindings {
|
||||
result := &Bindings{
|
||||
db: newDB(),
|
||||
logger: logger.CustomLogger("Bindings"),
|
||||
}
|
||||
|
||||
// Add the structs to bind
|
||||
for _, ptr := range structPointersToBind {
|
||||
err := result.Add(ptr)
|
||||
if err != nil {
|
||||
logger.Fatal("Error during binding: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Add the given struct methods to the Bindings
|
||||
|
||||
@@ -86,3 +86,10 @@ bool getJSONInt(JsonNode *item, const char* key, int *result) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JsonNode* mustParseJSON(const char* JSON) {
|
||||
JsonNode* parsedUpdate = json_decode(JSON);
|
||||
if ( parsedUpdate == NULL ) {
|
||||
ABORT("Unable to decode JSON: %s\n", JSON);
|
||||
}
|
||||
return parsedUpdate;
|
||||
}
|
||||
@@ -35,4 +35,6 @@ JsonNode* mustJSONObject(JsonNode *node, const char* key);
|
||||
bool getJSONBool(JsonNode *item, const char* key, bool *result);
|
||||
bool getJSONInt(JsonNode *item, const char* key, int *result);
|
||||
|
||||
JsonNode* mustParseJSON(const char* JSON);
|
||||
|
||||
#endif //ASSETS_C_COMMON_H
|
||||
|
||||
@@ -37,6 +37,7 @@ extern void DarkModeEnabled(struct Application*, char *callbackID);
|
||||
extern void SetApplicationMenu(struct Application*, const char *);
|
||||
extern void AddTrayMenu(struct Application*, const char *menuTrayJSON);
|
||||
extern void SetTrayMenu(struct Application*, const char *menuTrayJSON);
|
||||
extern void UpdateTrayMenuLabel(struct Application*, const char* JSON);
|
||||
extern void AddContextMenu(struct Application*, char *contextMenuJSON);
|
||||
extern void UpdateContextMenu(struct Application*, char *contextMenuJSON);
|
||||
|
||||
|
||||
@@ -192,6 +192,10 @@ func (c *Client) SetTrayMenu(trayMenuJSON string) {
|
||||
C.SetTrayMenu(c.app.app, c.app.string2CString(trayMenuJSON))
|
||||
}
|
||||
|
||||
func (c *Client) UpdateTrayMenuLabel(JSON string) {
|
||||
C.UpdateTrayMenuLabel(c.app.app, c.app.string2CString(JSON))
|
||||
}
|
||||
|
||||
func (c *Client) UpdateContextMenu(contextMenuJSON string) {
|
||||
C.UpdateContextMenu(c.app.app, c.app.string2CString(contextMenuJSON))
|
||||
}
|
||||
|
||||
@@ -150,6 +150,12 @@ void Fatal(struct Application *app, const char *message, ... ) {
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
// Requires NSString input EG lookupStringConstant(str("NSFontAttributeName"))
|
||||
void* lookupStringConstant(id constantName) {
|
||||
void ** dataPtr = CFBundleGetDataPointerForName(CFBundleGetBundleWithIdentifier((CFStringRef)str("com.apple.AppKit")), (CFStringRef) constantName);
|
||||
return (dataPtr ? *dataPtr : nil);
|
||||
}
|
||||
|
||||
bool isRetina(struct Application *app) {
|
||||
CGFloat scale = GET_BACKINGSCALEFACTOR(app->mainWindow);
|
||||
if( (int)scale == 1 ) {
|
||||
@@ -913,7 +919,8 @@ void SetDebug(void *applicationPointer, int flag) {
|
||||
}
|
||||
|
||||
|
||||
// SetContextMenus sets the context menu map for this application
|
||||
|
||||
// AddContextMenu sets the context menu map for this application
|
||||
void AddContextMenu(struct Application *app, const char *contextMenuJSON) {
|
||||
AddContextMenuToStore(app->contextMenuStore, contextMenuJSON);
|
||||
}
|
||||
@@ -932,6 +939,13 @@ void SetTrayMenu(struct Application *app, const char* trayMenuJSON) {
|
||||
);
|
||||
}
|
||||
|
||||
void UpdateTrayMenuLabel(struct Application* app, const char* JSON) {
|
||||
ON_MAIN_THREAD(
|
||||
UpdateTrayMenuLabelInStore(app->trayMenuStore, JSON);
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
void SetBindings(struct Application *app, const char *bindings) {
|
||||
const char* temp = concat("window.wailsbindings = \"", bindings);
|
||||
const char* jscall = concat(temp, "\";");
|
||||
|
||||
@@ -2,7 +2,7 @@ package ffenestri
|
||||
|
||||
/*
|
||||
#cgo darwin CFLAGS: -DFFENESTRI_DARWIN=1
|
||||
#cgo darwin LDFLAGS: -framework WebKit -lobjc
|
||||
#cgo darwin LDFLAGS: -framework WebKit -framework CoreFoundation -lobjc
|
||||
|
||||
#include "ffenestri.h"
|
||||
#include "ffenestri_darwin.h"
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#define OBJC_OLD_DISPATCH_PROTOTYPES 1
|
||||
#include <objc/objc-runtime.h>
|
||||
#include <CoreGraphics/CoreGraphics.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include "json.h"
|
||||
#include "hashmap.h"
|
||||
#include "stdlib.h"
|
||||
@@ -20,7 +21,6 @@
|
||||
#define strunicode(input) msg(c("NSString"), s("stringWithFormat:"), str("%C"), (unsigned short)input)
|
||||
#define cstr(input) (const char *)msg(input, s("UTF8String"))
|
||||
#define url(input) msg(c("NSURL"), s("fileURLWithPath:"), str(input))
|
||||
|
||||
#define ALLOC(classname) msg(c(classname), s("alloc"))
|
||||
#define ALLOC_INIT(classname) msg(msg(c(classname), s("alloc")), s("init"))
|
||||
#define GET_FRAME(receiver) ((CGRect(*)(id, SEL))objc_msgSend_stret)(receiver, s("frame"))
|
||||
@@ -107,7 +107,9 @@ void SetAppearance(struct Application* app, const char *);
|
||||
void WebviewIsTransparent(struct Application* app);
|
||||
void WindowBackgroundIsTranslucent(struct Application* app);
|
||||
void SetTray(struct Application* app, const char *, const char *, const char *);
|
||||
void SetContextMenus(struct Application* app, const char *);
|
||||
//void SetContextMenus(struct Application* app, const char *);
|
||||
void AddTrayMenu(struct Application* app, const char *);
|
||||
|
||||
void* lookupStringConstant(id constantName);
|
||||
|
||||
#endif
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "ffenestri_darwin.h"
|
||||
#include "menu_darwin.h"
|
||||
#include "contextmenus_darwin.h"
|
||||
#include "common.h"
|
||||
|
||||
// NewMenu creates a new Menu struct, saving the given menu structure as JSON
|
||||
Menu* NewMenu(JsonNode *menuData) {
|
||||
@@ -63,8 +64,6 @@ MenuItemCallbackData* CreateMenuItemCallbackData(Menu *menu, id menuItem, const
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void DeleteMenu(Menu *menu) {
|
||||
|
||||
// Free menu item hashmap
|
||||
@@ -99,7 +98,11 @@ void DeleteMenu(Menu *menu) {
|
||||
|
||||
// Creates a JSON message for the given menuItemID and data
|
||||
const char* createMenuClickedMessage(const char *menuItemID, const char *data, enum MenuType menuType, const char *parentID) {
|
||||
|
||||
JsonNode *jsonObject = json_mkobject();
|
||||
if (menuItemID == NULL ) {
|
||||
ABORT("Item ID NULL for menu!!\n");
|
||||
}
|
||||
json_append_member(jsonObject, "menuItemID", json_mkstring(menuItemID));
|
||||
json_append_member(jsonObject, "menuType", json_mkstring(MenuTypeAsString[(int)menuType]));
|
||||
if (data != NULL) {
|
||||
@@ -572,7 +575,7 @@ id processCheckboxMenuItem(Menu *menu, id parentmenu, const char *title, const c
|
||||
return item;
|
||||
}
|
||||
|
||||
id processTextMenuItem(Menu *menu, id parentMenu, const char *title, const char *menuid, bool disabled, const char *acceleratorkey, const char **modifiers) {
|
||||
id processTextMenuItem(Menu *menu, id parentMenu, const char *title, const char *menuid, bool disabled, const char *acceleratorkey, const char **modifiers, const char* tooltip, const char* image, const char* fontName, int fontSize, const char* RGBA) {
|
||||
id item = ALLOC("NSMenuItem");
|
||||
|
||||
// Create a MenuItemCallbackData
|
||||
@@ -585,6 +588,73 @@ id processTextMenuItem(Menu *menu, id parentMenu, const char *title, const char
|
||||
msg(item, s("initWithTitle:action:keyEquivalent:"), str(title),
|
||||
s("menuItemCallback:"), key);
|
||||
|
||||
if( tooltip != NULL ) {
|
||||
msg(item, s("setToolTip:"), str(tooltip));
|
||||
}
|
||||
|
||||
// Process image
|
||||
if( image != NULL && strlen(image) > 0) {
|
||||
id data = ALLOC("NSData");
|
||||
id imageData = msg(data, s("initWithBase64EncodedString:options:"), str(image), 0);
|
||||
id nsimage = ALLOC("NSImage");
|
||||
msg(nsimage, s("initWithData:"), imageData);
|
||||
msg(item, s("setImage:"), nsimage);
|
||||
}
|
||||
|
||||
// Process Menu Item attributes
|
||||
id dictionary = ALLOC_INIT("NSMutableDictionary");
|
||||
|
||||
// Process font
|
||||
id font;
|
||||
CGFloat fontSizeFloat = (CGFloat)fontSize;
|
||||
|
||||
// Check if valid
|
||||
id fontNameAsNSString = str(fontName);
|
||||
id fontsOnSystem = msg(msg(c("NSFontManager"), s("sharedFontManager")), s("availableFonts"));
|
||||
bool valid = msg(fontsOnSystem, s("containsObject:"), fontNameAsNSString);
|
||||
if( valid ) {
|
||||
font = msg(c("NSFont"), s("fontWithName:size:"), fontNameAsNSString, fontSizeFloat);
|
||||
} else {
|
||||
bool supportsMonospacedDigitSystemFont = (bool) msg(c("NSFont"), s("respondsToSelector:"), s("monospacedDigitSystemFontOfSize:weight:"));
|
||||
if( supportsMonospacedDigitSystemFont ) {
|
||||
font = msg(c("NSFont"), s("monospacedDigitSystemFontOfSize:weight:"), fontSizeFloat, NSFontWeightRegular);
|
||||
} else {
|
||||
font = msg(c("NSFont"), s("menuFontOfSize:"), fontSizeFloat);
|
||||
}
|
||||
}
|
||||
|
||||
// Add font to dictionary
|
||||
msg(dictionary, s("setObject:forKey:"), font, lookupStringConstant(str("NSFontAttributeName")));
|
||||
|
||||
// Add offset to dictionary
|
||||
id offset = msg(c("NSNumber"), s("numberWithFloat:"), 0.0);
|
||||
msg(dictionary, s("setObject:forKey:"), offset, lookupStringConstant(str("NSBaselineOffsetAttributeName")));
|
||||
|
||||
// RGBA
|
||||
if( RGBA != NULL && strlen(RGBA) > 0) {
|
||||
unsigned short r, g, b, a;
|
||||
|
||||
// white by default
|
||||
r = g = b = a = 255;
|
||||
int count = sscanf(RGBA, "#%02hx%02hx%02hx%02hx", &r, &g, &b, &a);
|
||||
if (count > 0) {
|
||||
id colour = msg(c("NSColor"), s("colorWithCalibratedRed:green:blue:alpha:"),
|
||||
(float)r / 255.0,
|
||||
(float)g / 255.0,
|
||||
(float)b / 255.0,
|
||||
(float)a / 255.0);
|
||||
msg(dictionary, s("setObject:forKey:"), colour, lookupStringConstant(str("NSForegroundColorAttributeName")));
|
||||
msg(colour, s("release"));
|
||||
}
|
||||
}
|
||||
|
||||
id attributedString = ALLOC("NSMutableAttributedString");
|
||||
msg(attributedString, s("initWithString:attributes:"), str(title), dictionary);
|
||||
msg(dictionary, s("release"));
|
||||
|
||||
msg(item, s("setAttributedTitle:"), attributedString);
|
||||
msg(attributedString, s("autorelease"));
|
||||
|
||||
msg(item, s("setEnabled:"), !disabled);
|
||||
msg(item, s("autorelease"));
|
||||
|
||||
@@ -666,6 +736,13 @@ void processMenuItem(Menu *menu, id parentMenu, JsonNode *item) {
|
||||
const char *acceleratorkey = NULL;
|
||||
const char **modifiers = NULL;
|
||||
|
||||
const char *tooltip = getJSONString(item, "Tooltip");
|
||||
const char *image = getJSONString(item, "Image");
|
||||
const char *fontName = getJSONString(item, "FontName");
|
||||
const char *RGBA = getJSONString(item, "RGBA");
|
||||
int fontSize = 0;
|
||||
getJSONInt(item, "FontSize", &fontSize);
|
||||
|
||||
// If we have an accelerator
|
||||
if( accelerator != NULL ) {
|
||||
// Get the key
|
||||
@@ -698,7 +775,7 @@ void processMenuItem(Menu *menu, id parentMenu, JsonNode *item) {
|
||||
if( type != NULL ) {
|
||||
|
||||
if( STREQ(type->string_, "Text")) {
|
||||
processTextMenuItem(menu, parentMenu, label, menuid, disabled, acceleratorkey, modifiers);
|
||||
processTextMenuItem(menu, parentMenu, label, menuid, disabled, acceleratorkey, modifiers, tooltip, image, fontName, fontSize, RGBA);
|
||||
}
|
||||
else if ( STREQ(type->string_, "Separator")) {
|
||||
addSeparator(parentMenu);
|
||||
|
||||
@@ -14,6 +14,21 @@ static const char *MenuTypeAsString[] = {
|
||||
"ApplicationMenu", "ContextMenu", "TrayMenu",
|
||||
};
|
||||
|
||||
typedef struct _NSRange {
|
||||
unsigned long location;
|
||||
unsigned long length;
|
||||
} NSRange;
|
||||
|
||||
#define NSFontWeightUltraLight -0.8
|
||||
#define NSFontWeightThin -0.6
|
||||
#define NSFontWeightLight -0.4
|
||||
#define NSFontWeightRegular 0
|
||||
#define NSFontWeightMedium 0.23
|
||||
#define NSFontWeightSemibold 0.3
|
||||
#define NSFontWeightBold 0.4
|
||||
#define NSFontWeightHeavy 0.56
|
||||
#define NSFontWeightBlack 0.62
|
||||
|
||||
extern void messageFromWindowCallback(const char *);
|
||||
|
||||
typedef struct {
|
||||
@@ -90,8 +105,7 @@ id processRadioMenuItem(Menu *menu, id parentmenu, const char *title, const char
|
||||
|
||||
id processCheckboxMenuItem(Menu *menu, id parentmenu, const char *title, const char *menuid, bool disabled, bool checked, const char *key);
|
||||
|
||||
id processTextMenuItem(Menu *menu, id parentMenu, const char *title, const char *menuid, bool disabled, const char *acceleratorkey, const char **modifiers);
|
||||
|
||||
id processTextMenuItem(Menu *menu, id parentMenu, const char *title, const char *menuid, bool disabled, const char *acceleratorkey, const char **modifiers, const char* tooltip, const char* image, const char* fontName, int fontSize, const char* RGBA);
|
||||
void processMenuItem(Menu *menu, id parentMenu, JsonNode *item);
|
||||
void processMenuData(Menu *menu, JsonNode *menuData);
|
||||
|
||||
|
||||
@@ -49,42 +49,19 @@ void DumpTrayMenu(TrayMenu* trayMenu) {
|
||||
printf(" ['%s':%p] = { label: '%s', icon: '%s', menu: %p, statusbar: %p }\n", trayMenu->ID, trayMenu, trayMenu->label, trayMenu->icon, trayMenu->menu, trayMenu->statusbaritem );
|
||||
}
|
||||
|
||||
void ShowTrayMenu(TrayMenu* trayMenu) {
|
||||
|
||||
// Create a status bar item if we don't have one
|
||||
if( trayMenu->statusbaritem == NULL ) {
|
||||
id statusBar = msg( c("NSStatusBar"), s("systemStatusBar") );
|
||||
trayMenu->statusbaritem = msg(statusBar, s("statusItemWithLength:"), NSVariableStatusItemLength);
|
||||
msg(trayMenu->statusbaritem, s("retain"));
|
||||
|
||||
}
|
||||
|
||||
id statusBarButton = msg(trayMenu->statusbaritem, s("button"));
|
||||
msg(statusBarButton, s("setImagePosition:"), trayMenu->trayIconPosition);
|
||||
|
||||
// Update the icon if needed
|
||||
UpdateTrayMenuIcon(trayMenu);
|
||||
|
||||
// Update the label if needed
|
||||
UpdateTrayMenuLabel(trayMenu);
|
||||
|
||||
// Update the menu
|
||||
id menu = GetMenu(trayMenu->menu);
|
||||
msg(trayMenu->statusbaritem, s("setMenu:"), menu);
|
||||
}
|
||||
|
||||
void UpdateTrayMenuLabel(TrayMenu *trayMenu) {
|
||||
void UpdateTrayLabel(TrayMenu *trayMenu, const char *label) {
|
||||
|
||||
// Exit early if NULL
|
||||
if( trayMenu->label == NULL ) {
|
||||
return;
|
||||
}
|
||||
// We don't check for a
|
||||
// Update button label
|
||||
id statusBarButton = msg(trayMenu->statusbaritem, s("button"));
|
||||
msg(statusBarButton, s("setTitle:"), str(trayMenu->label));
|
||||
msg(statusBarButton, s("setTitle:"), str(label));
|
||||
}
|
||||
|
||||
void UpdateTrayMenuIcon(TrayMenu *trayMenu) {
|
||||
void UpdateTrayIcon(TrayMenu *trayMenu) {
|
||||
|
||||
// Exit early if NULL
|
||||
if( trayMenu->icon == NULL ) {
|
||||
@@ -105,6 +82,32 @@ void UpdateTrayMenuIcon(TrayMenu *trayMenu) {
|
||||
msg(statusBarButton, s("setImage:"), trayImage);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ShowTrayMenu(TrayMenu* trayMenu) {
|
||||
|
||||
// Create a status bar item if we don't have one
|
||||
if( trayMenu->statusbaritem == NULL ) {
|
||||
id statusBar = msg( c("NSStatusBar"), s("systemStatusBar") );
|
||||
trayMenu->statusbaritem = msg(statusBar, s("statusItemWithLength:"), NSVariableStatusItemLength);
|
||||
msg(trayMenu->statusbaritem, s("retain"));
|
||||
|
||||
}
|
||||
|
||||
id statusBarButton = msg(trayMenu->statusbaritem, s("button"));
|
||||
msg(statusBarButton, s("setImagePosition:"), trayMenu->trayIconPosition);
|
||||
|
||||
// Update the icon if needed
|
||||
UpdateTrayIcon(trayMenu);
|
||||
|
||||
// Update the label if needed
|
||||
UpdateTrayLabel(trayMenu, trayMenu->label);
|
||||
|
||||
// Update the menu
|
||||
id menu = GetMenu(trayMenu->menu);
|
||||
msg(trayMenu->statusbaritem, s("setMenu:"), menu);
|
||||
}
|
||||
|
||||
// UpdateTrayMenuInPlace receives 2 menus. The current menu gets
|
||||
// updated with the data from the new menu.
|
||||
void UpdateTrayMenuInPlace(TrayMenu* currentMenu, TrayMenu* newMenu) {
|
||||
|
||||
@@ -27,8 +27,8 @@ TrayMenu* NewTrayMenu(const char *trayJSON);
|
||||
void DumpTrayMenu(TrayMenu* trayMenu);
|
||||
void ShowTrayMenu(TrayMenu* trayMenu);
|
||||
void UpdateTrayMenuInPlace(TrayMenu* currentMenu, TrayMenu* newMenu);
|
||||
void UpdateTrayMenuIcon(TrayMenu *trayMenu);
|
||||
void UpdateTrayMenuLabel(TrayMenu *trayMenu);
|
||||
void UpdateTrayIcon(TrayMenu *trayMenu);
|
||||
void UpdateTrayLabel(TrayMenu *trayMenu, const char*);
|
||||
|
||||
void LoadTrayIcons();
|
||||
void UnloadTrayIcons();
|
||||
|
||||
@@ -72,15 +72,38 @@ TrayMenu* GetTrayMenuFromStore(TrayMenuStore* store, const char* menuID) {
|
||||
return hashmap_get(&store->trayMenuMap, menuID, strlen(menuID));
|
||||
}
|
||||
|
||||
TrayMenu* MustGetTrayMenuFromStore(TrayMenuStore* store, const char* menuID) {
|
||||
// Get the current menu
|
||||
TrayMenu* result = hashmap_get(&store->trayMenuMap, menuID, strlen(menuID));
|
||||
if (result == NULL ) {
|
||||
ABORT("Unable to find TrayMenu with ID '%s' in the TrayMenuStore!", menuID);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void UpdateTrayMenuLabelInStore(TrayMenuStore* store, const char* JSON) {
|
||||
// Parse the JSON
|
||||
JsonNode *parsedUpdate = mustParseJSON(JSON);
|
||||
|
||||
// Get the data out
|
||||
const char* ID = mustJSONString(parsedUpdate, "ID");
|
||||
const char* Label = mustJSONString(parsedUpdate, "Label");
|
||||
|
||||
// Check we have this menu
|
||||
TrayMenu *menu = MustGetTrayMenuFromStore(store, ID);
|
||||
UpdateTrayLabel(menu, Label);
|
||||
|
||||
}
|
||||
|
||||
void UpdateTrayMenuInStore(TrayMenuStore* store, const char* menuJSON) {
|
||||
TrayMenu* newMenu = NewTrayMenu(menuJSON);
|
||||
// DumpTrayMenu(newMenu);
|
||||
|
||||
// Get the current menu
|
||||
TrayMenu *currentMenu = GetTrayMenuFromStore(store, newMenu->ID);
|
||||
|
||||
// If we don't have a menu, we create one
|
||||
if ( currentMenu == NULL ) {
|
||||
|
||||
// Store the new menu
|
||||
hashmap_put(&store->trayMenuMap, newMenu->ID, strlen(newMenu->ID), newMenu);
|
||||
|
||||
@@ -88,6 +111,7 @@ void UpdateTrayMenuInStore(TrayMenuStore* store, const char* menuJSON) {
|
||||
ShowTrayMenu(newMenu);
|
||||
return;
|
||||
}
|
||||
// DumpTrayMenu(currentMenu);
|
||||
|
||||
// Save the status bar reference
|
||||
newMenu->statusbaritem = currentMenu->statusbaritem;
|
||||
@@ -98,12 +122,6 @@ void UpdateTrayMenuInStore(TrayMenuStore* store, const char* menuJSON) {
|
||||
DeleteMenu(currentMenu->menu);
|
||||
currentMenu->menu = NULL;
|
||||
|
||||
// Free JSON
|
||||
if (currentMenu->processedJSON != NULL ) {
|
||||
json_delete(currentMenu->processedJSON);
|
||||
currentMenu->processedJSON = NULL;
|
||||
}
|
||||
|
||||
// Free the tray menu memory
|
||||
MEMFREE(currentMenu);
|
||||
|
||||
|
||||
@@ -22,4 +22,6 @@ void UpdateTrayMenuInStore(TrayMenuStore* store, const char* menuJSON);
|
||||
void ShowTrayMenusInStore(TrayMenuStore* store);
|
||||
void DeleteTrayMenuStore(TrayMenuStore* store);
|
||||
|
||||
void UpdateTrayMenuLabelInStore(TrayMenuStore* store, const char* JSON);
|
||||
|
||||
#endif //TRAYMENUSTORE_DARWIN_H
|
||||
|
||||
@@ -9,28 +9,35 @@ import (
|
||||
type ProcessedMenuItem struct {
|
||||
ID string
|
||||
// Label is what appears as the menu text
|
||||
Label string
|
||||
Label string `json:",omitempty"`
|
||||
// Role is a predefined menu type
|
||||
Role menu.Role `json:"Role,omitempty"`
|
||||
Role menu.Role `json:",omitempty"`
|
||||
// Accelerator holds a representation of a key binding
|
||||
Accelerator *keys.Accelerator `json:"Accelerator,omitempty"`
|
||||
Accelerator *keys.Accelerator `json:",omitempty"`
|
||||
// Type of MenuItem, EG: Checkbox, Text, Separator, Radio, Submenu
|
||||
Type menu.Type
|
||||
// Disabled makes the item unselectable
|
||||
Disabled bool
|
||||
Disabled bool `json:",omitempty"`
|
||||
// Hidden ensures that the item is not shown in the menu
|
||||
Hidden bool
|
||||
Hidden bool `json:",omitempty"`
|
||||
// Checked indicates if the item is selected (used by Checkbox and Radio types only)
|
||||
Checked bool
|
||||
Checked bool `json:",omitempty"`
|
||||
// Submenu contains a list of menu items that will be shown as a submenu
|
||||
//SubMenu []*MenuItem `json:"SubMenu,omitempty"`
|
||||
SubMenu *ProcessedMenu `json:"SubMenu,omitempty"`
|
||||
SubMenu *ProcessedMenu `json:",omitempty"`
|
||||
|
||||
// Foreground colour in hex RGBA format EG: 0xFF0000FF = #FF0000FF = red
|
||||
Foreground int
|
||||
// Colour
|
||||
RGBA string `json:",omitempty"`
|
||||
|
||||
// Background colour
|
||||
Background int
|
||||
// Font
|
||||
FontSize int `json:",omitempty"`
|
||||
FontName string `json:",omitempty"`
|
||||
|
||||
// Image - base64 image data
|
||||
Image string `json:",omitempty"`
|
||||
|
||||
// Tooltip
|
||||
Tooltip string `json:",omitempty"`
|
||||
}
|
||||
|
||||
func NewProcessedMenuItem(menuItemMap *MenuItemMap, menuItem *menu.MenuItem) *ProcessedMenuItem {
|
||||
@@ -45,8 +52,12 @@ func NewProcessedMenuItem(menuItemMap *MenuItemMap, menuItem *menu.MenuItem) *Pr
|
||||
Disabled: menuItem.Disabled,
|
||||
Hidden: menuItem.Hidden,
|
||||
Checked: menuItem.Checked,
|
||||
Foreground: menuItem.Foreground,
|
||||
Background: menuItem.Background,
|
||||
SubMenu: nil,
|
||||
RGBA: menuItem.RGBA,
|
||||
FontSize: menuItem.FontSize,
|
||||
FontName: menuItem.FontName,
|
||||
Image: menuItem.Image,
|
||||
Tooltip: menuItem.Tooltip,
|
||||
}
|
||||
|
||||
if menuItem.SubMenu != nil {
|
||||
|
||||
@@ -3,6 +3,7 @@ package menumanager
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||
"sync"
|
||||
)
|
||||
@@ -94,6 +95,31 @@ func (m *Manager) GetTrayMenus() ([]string, error) {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (m *Manager) UpdateTrayMenuLabel(trayMenu *menu.TrayMenu) (string, error) {
|
||||
trayID, trayMenuKnown := m.trayMenuPointers[trayMenu]
|
||||
if !trayMenuKnown {
|
||||
return "", fmt.Errorf("[UpdateTrayMenuLabel] unknown tray id for tray %s", trayMenu.Label)
|
||||
}
|
||||
|
||||
type LabelUpdate struct {
|
||||
ID string
|
||||
Label string
|
||||
}
|
||||
|
||||
update := &LabelUpdate{
|
||||
ID: trayID,
|
||||
Label: trayMenu.Label,
|
||||
}
|
||||
|
||||
data, err := json.Marshal(update)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "[UpdateTrayMenuLabel] ")
|
||||
}
|
||||
|
||||
return string(data), nil
|
||||
|
||||
}
|
||||
|
||||
func (m *Manager) GetContextMenus() ([]string, error) {
|
||||
result := []string{}
|
||||
for _, contextMenu := range m.contextMenus {
|
||||
|
||||
@@ -32,6 +32,7 @@ type Client interface {
|
||||
DarkModeEnabled(callbackID string)
|
||||
SetApplicationMenu(menuJSON string)
|
||||
SetTrayMenu(trayMenuJSON string)
|
||||
UpdateTrayMenuLabel(JSON string)
|
||||
UpdateContextMenu(contextMenuJSON string)
|
||||
}
|
||||
|
||||
|
||||
@@ -473,6 +473,20 @@ func (d *Dispatcher) processMenuMessage(result *servicebus.Message) {
|
||||
client.frontend.UpdateContextMenu(updatedContextMenu)
|
||||
}
|
||||
|
||||
case "updatetraymenulabel":
|
||||
updatedTrayMenuLabel, ok := result.Data().(string)
|
||||
if !ok {
|
||||
d.logger.Error("Invalid data for 'menufrontend:updatetraymenulabel' : %#v",
|
||||
result.Data())
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: Work out what we mean in a multi window environment...
|
||||
// For now we will just pick the first one
|
||||
for _, client := range d.clients {
|
||||
client.frontend.UpdateTrayMenuLabel(updatedTrayMenuLabel)
|
||||
}
|
||||
|
||||
default:
|
||||
d.logger.Error("Unknown menufrontend command: %s", command)
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ type Menu interface {
|
||||
UpdateApplicationMenu()
|
||||
UpdateContextMenu(contextMenu *menu.ContextMenu)
|
||||
SetTrayMenu(trayMenu *menu.TrayMenu)
|
||||
UpdateTrayMenuLabel(trayMenu *menu.TrayMenu)
|
||||
}
|
||||
|
||||
type menuRuntime struct {
|
||||
@@ -34,3 +35,7 @@ func (m *menuRuntime) UpdateContextMenu(contextMenu *menu.ContextMenu) {
|
||||
func (m *menuRuntime) SetTrayMenu(trayMenu *menu.TrayMenu) {
|
||||
m.bus.Publish("menu:settraymenu", trayMenu)
|
||||
}
|
||||
|
||||
func (m *menuRuntime) UpdateTrayMenuLabel(trayMenu *menu.TrayMenu) {
|
||||
m.bus.Publish("menu:updatetraymenulabel", trayMenu)
|
||||
}
|
||||
|
||||
@@ -146,9 +146,13 @@ func (s *Store) setupListener() {
|
||||
// Resetting the curent data will resync
|
||||
s.resync()
|
||||
})
|
||||
|
||||
// Do initial resync
|
||||
s.resync()
|
||||
}
|
||||
|
||||
func (s *Store) resync() {
|
||||
|
||||
// Stringify data
|
||||
newdata, err := json.Marshal(s.data.Interface())
|
||||
if err != nil {
|
||||
|
||||
@@ -131,6 +131,17 @@ func (m *Menu) Start() error {
|
||||
// Notify frontend of menu change
|
||||
m.bus.Publish("menufrontend:settraymenu", updatedMenu)
|
||||
|
||||
case "updatetraymenulabel":
|
||||
trayMenu := menuMessage.Data().(*menu.TrayMenu)
|
||||
updatedLabel, err := m.menuManager.UpdateTrayMenuLabel(trayMenu)
|
||||
if err != nil {
|
||||
m.logger.Trace("%s", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Notify frontend of menu change
|
||||
m.bus.Publish("menufrontend:updatetraymenulabel", updatedLabel)
|
||||
|
||||
default:
|
||||
m.logger.Error("unknown menu message: %+v", menuMessage)
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ func (r *Runtime) Start() error {
|
||||
if r.startupCallback != nil {
|
||||
go r.startupCallback(r.runtime)
|
||||
} else {
|
||||
r.logger.Error("no startup callback registered!")
|
||||
r.logger.Warning("no startup callback registered!")
|
||||
}
|
||||
default:
|
||||
r.logger.Error("unknown hook message: %+v", hooksMessage)
|
||||
@@ -131,6 +131,8 @@ func (r *Runtime) GoRuntime() *runtime.Runtime {
|
||||
func (r *Runtime) shutdown() {
|
||||
if r.shutdownCallback != nil {
|
||||
go r.shutdownCallback()
|
||||
} else {
|
||||
r.logger.Warning("no shutdown callback registered!")
|
||||
}
|
||||
r.logger.Trace("Shutdown")
|
||||
}
|
||||
|
||||
@@ -2,14 +2,21 @@ package main
|
||||
|
||||
import (
|
||||
"github.com/wailsapp/wails/v2"
|
||||
"log"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
// Create application with options
|
||||
app := wails.CreateApp("{{.ProjectName}}", 1024, 768)
|
||||
app, err := wails.CreateApp("{{.ProjectName}}", 1024, 768)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
app.Bind(newBasic())
|
||||
|
||||
app.Run()
|
||||
err = app.Run()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,14 @@ type WebClient struct {
|
||||
running bool
|
||||
}
|
||||
|
||||
func (wc *WebClient) SetTrayMenu(trayMenuJSON string) {
|
||||
wc.logger.Info("Not implemented in server build")
|
||||
}
|
||||
|
||||
func (wc *WebClient) UpdateTrayMenuLabel(trayMenuJSON string) {
|
||||
wc.logger.Info("Not implemented in server build")
|
||||
}
|
||||
|
||||
func (wc *WebClient) MessageDialog(dialogOptions *dialog.MessageDialog, callbackID string) {
|
||||
wc.logger.Info("Not implemented in server build")
|
||||
}
|
||||
|
||||
@@ -211,7 +211,6 @@ func (b *BaseBuilder) CompileProject(options *Options) error {
|
||||
options.CompiledBinary = compiledBinary
|
||||
|
||||
// Create the command
|
||||
fmt.Printf("Compile command: %+v", commands.AsSlice())
|
||||
cmd := exec.Command(options.Compiler, commands.AsSlice()...)
|
||||
|
||||
// Set the directory
|
||||
|
||||
@@ -104,7 +104,7 @@ func Build(options *Options) (string, error) {
|
||||
// return "", err
|
||||
// }
|
||||
if !options.IgnoreFrontend {
|
||||
outputLogger.Println(" - Building Wails Frontend")
|
||||
outputLogger.Println(" - Building Project Frontend")
|
||||
err = builder.BuildFrontend(outputLogger)
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
||||
@@ -12,6 +12,14 @@ func (m *Menu) Append(item *MenuItem) {
|
||||
m.Items = append(m.Items, item)
|
||||
}
|
||||
|
||||
// Merge will append the items in the given menu
|
||||
// into this menu
|
||||
func (m *Menu) Merge(menu *Menu) {
|
||||
for _, item := range menu.Items {
|
||||
m.Items = append(m.Items, item)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Menu) Prepend(item *MenuItem) {
|
||||
m.Items = append([]*MenuItem{item}, m.Items...)
|
||||
}
|
||||
|
||||
@@ -28,11 +28,18 @@ type MenuItem struct {
|
||||
// Callback function when menu clicked
|
||||
Click Callback `json:"-"`
|
||||
|
||||
// Foreground colour in hex RGBA format EG: 0xFF0000FF = #FF0000FF = red
|
||||
Foreground int
|
||||
// Colour
|
||||
RGBA string
|
||||
|
||||
// Background colour
|
||||
Background int
|
||||
// Font
|
||||
FontSize int
|
||||
FontName string
|
||||
|
||||
// Image - base64 image data
|
||||
Image string
|
||||
|
||||
// Tooltip
|
||||
Tooltip string
|
||||
|
||||
// This holds the menu item's parent.
|
||||
parent *MenuItem
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
package options
|
||||
|
||||
import (
|
||||
wailsruntime "github.com/wailsapp/wails/v2/internal/runtime"
|
||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||
"log"
|
||||
"runtime"
|
||||
|
||||
wailsruntime "github.com/wailsapp/wails/v2/internal/runtime"
|
||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||
|
||||
"github.com/imdario/mergo"
|
||||
"github.com/wailsapp/wails/v2/pkg/logger"
|
||||
"github.com/wailsapp/wails/v2/pkg/options/mac"
|
||||
@@ -33,6 +34,7 @@ type App struct {
|
||||
LogLevel logger.LogLevel
|
||||
Startup func(*wailsruntime.Runtime) `json:"-"`
|
||||
Shutdown func() `json:"-"`
|
||||
Bind []interface{}
|
||||
}
|
||||
|
||||
// MergeDefaults will set the minimum default values for an application
|
||||
|
||||
10
v2/pkg/str/str.go
Normal file
10
v2/pkg/str/str.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package str
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
func UnixNow() string {
|
||||
return fmt.Sprintf("%+v", time.Now().Unix())
|
||||
}
|
||||
@@ -58,6 +58,7 @@ github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
|
||||
19
v2/wails.go
19
v2/wails.go
@@ -14,19 +14,12 @@ type Runtime = runtime.Runtime
|
||||
// Store is an alias for the Store object
|
||||
type Store = runtime.Store
|
||||
|
||||
// CreateAppWithOptions creates an application based on the given config
|
||||
func CreateAppWithOptions(options *options.App) (*app.App, error) {
|
||||
return app.CreateApp(options)
|
||||
}
|
||||
|
||||
// CreateApp creates an application based on the given title, width and height
|
||||
func CreateApp(title string, width int, height int) (*app.App, error) {
|
||||
|
||||
options := &options.App{
|
||||
Title: title,
|
||||
Width: width,
|
||||
Height: height,
|
||||
// Run creates an application based on the given config and executes it
|
||||
func Run(options *options.App) error {
|
||||
app, err := app.CreateApp(options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return app.CreateApp(options)
|
||||
return app.Run()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user