Skip to content

Commit

Permalink
Fix edit menus on windows and linux
Browse files Browse the repository at this point in the history
  • Loading branch information
leaanthony committed Jan 14, 2025
1 parent c186917 commit 3f78a3a
Show file tree
Hide file tree
Showing 4 changed files with 170 additions and 29 deletions.
3 changes: 3 additions & 0 deletions docs/src/content/docs/changelog.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Fixed
- Fixed Windows+Linux Edit Menu issues by [@leaanthony](https://github.com/leaanthony)

## v3.0.0-alpha.9 - 2025-01-13

### Added
Expand Down
91 changes: 77 additions & 14 deletions v3/pkg/application/menuitem_roles.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,34 +32,77 @@ func NewUnhideMenuItem() *MenuItem {
}

func NewUndoMenuItem() *MenuItem {
return NewMenuItem("Undo").
result := NewMenuItem("Undo").
SetAccelerator("CmdOrCtrl+z")
if runtime.GOOS != "darwin" {
result.OnClick(func(ctx *Context) {
currentWindow := globalApplication.CurrentWindow()
if currentWindow != nil {
currentWindow.undo()
}
})
}
return result
}

// newRedoMenuItem creates a new menu item for redoing the last action
// NewRedoMenuItem creates a new menu item for redoing the last action
func NewRedoMenuItem() *MenuItem {
return NewMenuItem("Redo").
result := NewMenuItem("Redo").
SetAccelerator("CmdOrCtrl+Shift+z")
if runtime.GOOS != "darwin" {
result.OnClick(func(ctx *Context) {
currentWindow := globalApplication.CurrentWindow()
if currentWindow != nil {
currentWindow.redo()
}
})
}
return result
}

func NewCutMenuItem() *MenuItem {
return NewMenuItem("Cut").
SetAccelerator("CmdOrCtrl+x").OnClick(func(ctx *Context) {
currentWindow := globalApplication.CurrentWindow()
if currentWindow != nil {
currentWindow.cut()
}
})
result := NewMenuItem("Cut").
SetAccelerator("CmdOrCtrl+x")

if runtime.GOOS != "darwin" {
result.OnClick(func(ctx *Context) {
currentWindow := globalApplication.CurrentWindow()
if currentWindow != nil {
currentWindow.cut()
}
})
}
return result
}

func NewCopyMenuItem() *MenuItem {
return NewMenuItem("Copy").
result := NewMenuItem("Copy").
SetAccelerator("CmdOrCtrl+c")

if runtime.GOOS != "darwin" {
result.OnClick(func(ctx *Context) {
currentWindow := globalApplication.CurrentWindow()
if currentWindow != nil {
currentWindow.copy()
}
})
}
return result
}

func NewPasteMenuItem() *MenuItem {
return NewMenuItem("Paste").
result := NewMenuItem("Paste").
SetAccelerator("CmdOrCtrl+v")

if runtime.GOOS != "darwin" {
result.OnClick(func(ctx *Context) {
currentWindow := globalApplication.CurrentWindow()
if currentWindow != nil {
currentWindow.paste()
}
})
}
return result
}

func NewPasteAndMatchStyleMenuItem() *MenuItem {
Expand All @@ -68,8 +111,18 @@ func NewPasteAndMatchStyleMenuItem() *MenuItem {
}

func NewDeleteMenuItem() *MenuItem {
return NewMenuItem("Delete").
result := NewMenuItem("Delete").
SetAccelerator("backspace")

if runtime.GOOS != "darwin" {
result.OnClick(func(ctx *Context) {
currentWindow := globalApplication.CurrentWindow()
if currentWindow != nil {
currentWindow.delete()
}
})
}
return result
}

func NewQuitMenuItem() *MenuItem {
Expand All @@ -87,8 +140,18 @@ func NewQuitMenuItem() *MenuItem {
}

func NewSelectAllMenuItem() *MenuItem {
return NewMenuItem("Select All").
result := NewMenuItem("Select All").
SetAccelerator("CmdOrCtrl+a")

if runtime.GOOS != "darwin" {
result.OnClick(func(ctx *Context) {
currentWindow := globalApplication.CurrentWindow()
if currentWindow != nil {
currentWindow.selectAll()
}
})
}
return result
}

func NewAboutMenuItem() *MenuItem {
Expand Down
21 changes: 14 additions & 7 deletions v3/pkg/application/webview_window.go
Original file line number Diff line number Diff line change
Expand Up @@ -1309,42 +1309,49 @@ func (w *WebviewWindow) SetIgnoreMouseEvents(ignore bool) Window {

func (w *WebviewWindow) cut() {
if w.impl == nil || w.isDestroyed() {
w.impl.cut()
return
}
w.impl.cut()
}

func (w *WebviewWindow) copy() {
if w.impl == nil || w.isDestroyed() {
w.impl.copy()
return
}
w.impl.copy()
}

func (w *WebviewWindow) paste() {
if w.impl == nil || w.isDestroyed() {
w.impl.paste()
return
}
w.impl.paste()
}

func (w *WebviewWindow) selectAll() {
if w.impl == nil || w.isDestroyed() {
w.impl.selectAll()
return
}
w.impl.selectAll()
}

func (w *WebviewWindow) undo() {
if w.impl == nil || w.isDestroyed() {
w.impl.undo()
return
}
w.impl.undo()
}

func (w *WebviewWindow) delete() {
if w.impl == nil || w.isDestroyed() {
w.impl.delete()
return
}
w.impl.delete()
}

func (w *WebviewWindow) redo() {
if w.impl == nil || w.isDestroyed() {
w.impl.redo()
return
}
w.impl.redo()
}
84 changes: 76 additions & 8 deletions v3/pkg/application/webview_window_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,30 +74,98 @@ type windowsWebviewWindow struct {
}

func (w *windowsWebviewWindow) cut() {
w32.Cut(w.hwnd)
w.execJS("document.execCommand('cut')")
}

func (w *windowsWebviewWindow) paste() {
w32.Paste(w.hwnd)
w.execJS(`
(async () => {
try {
// Try to read all available formats
const clipboardItems = await navigator.clipboard.read();
for (const clipboardItem of clipboardItems) {
// Check for image types
for (const type of clipboardItem.types) {
if (type.startsWith('image/')) {
const blob = await clipboardItem.getType(type);
const url = URL.createObjectURL(blob);
document.execCommand('insertHTML', false, '<img src="' + url + '">');
return;
}
}
// If no image found, try text
if (clipboardItem.types.includes('text/plain')) {
const text = await navigator.clipboard.readText();
document.execCommand('insertText', false, text);
return;
}
}
} catch(err) {
// Fallback to text-only paste if clipboard access fails
try {
const text = await navigator.clipboard.readText();
document.execCommand('insertText', false, text);
} catch(fallbackErr) {
console.error('Failed to paste:', err, fallbackErr);
}
}
})()
`)
}

func (w *windowsWebviewWindow) copy() {
w32.Copy(w.hwnd)
w.execJS(`
(async () => {
try {
const selection = window.getSelection();
if (!selection.rangeCount) return;
const range = selection.getRangeAt(0);
const container = document.createElement('div');
container.appendChild(range.cloneContents());
// Check if we have any images in the selection
const images = container.getElementsByTagName('img');
if (images.length > 0) {
// Handle image copy
const img = images[0]; // Take the first image
const response = await fetch(img.src);
const blob = await response.blob();
await navigator.clipboard.write([
new ClipboardItem({
[blob.type]: blob
})
]);
} else {
// Handle text copy
const text = selection.toString();
if (text) {
await navigator.clipboard.writeText(text);
}
}
} catch(err) {
console.error('Failed to copy:', err);
}
})()
`)
}

func (w *windowsWebviewWindow) selectAll() {
w32.SelectAll(w.hwnd)
w.execJS("document.execCommand('selectAll')")
}

func (w *windowsWebviewWindow) undo() {
w32.Undo(w.hwnd)
w.execJS("document.execCommand('undo')")
}

func (w *windowsWebviewWindow) delete() {
w32.Delete(w.hwnd)
func (w *windowsWebviewWindow) redo() {
w.execJS("document.execCommand('redo')")
}

func (w *windowsWebviewWindow) redo() {
func (w *windowsWebviewWindow) delete() {
w.execJS("document.execCommand('delete')")
}

func (w *windowsWebviewWindow) handleKeyEvent(_ string) {
Expand Down

0 comments on commit 3f78a3a

Please sign in to comment.