refactor(browser): use direction and UI string constants throughout workspace
Replaces hardcoded direction strings (left/right/up/down) with DirectionLeft/Right/Up/Down constants and \"New Tab\" with NewTabTitle constant for maintainability.
- commit
- 2e390517bad9747afa50dd84fd0181623bd55fda
- author
- bnema · · 2025-10-23 19:33 UTC
- committer
- bnema · · 2025-10-24 17:33 UTC
- parent
- ca5e83c
- signature
- unsigned
12 files · +71 -65
M internal/app/browser/stacked_panes.go +5 -5
| @@ -430,7 +430,7 @@ func (spm *StackedPaneManager) UpdateStackVisibility(stackNode *paneNode) { | |||
| 430 | 430 | if pane.pane != nil && pane.pane.webView != nil { | |
| 431 | 431 | title := pane.pane.webView.GetTitle() | |
| 432 | 432 | if title == "" { | |
| 433 | - | title = "New Tab" | |
| 433 | + | title = NewTabTitle | |
| 434 | 434 | } | |
| 435 | 435 | spm.updateTitleBarLabel(pane, title) | |
| 436 | 436 | } | |
| @@ -475,12 +475,12 @@ func (spm *StackedPaneManager) NavigateStack(direction string) bool { | |||
| 475 | 475 | // Calculate new index based on direction | |
| 476 | 476 | var newIndex int | |
| 477 | 477 | switch direction { | |
| 478 | - | case "up": | |
| 478 | + | case DirectionUp: | |
| 479 | 479 | newIndex = currentIndex - 1 | |
| 480 | 480 | if newIndex < 0 { | |
| 481 | 481 | newIndex = len(stackNode.stackedPanes) - 1 // Wrap to last | |
| 482 | 482 | } | |
| 483 | - | case "down": | |
| 483 | + | case DirectionDown: | |
| 484 | 484 | newIndex = currentIndex + 1 | |
| 485 | 485 | if newIndex >= len(stackNode.stackedPanes) { | |
| 486 | 486 | newIndex = 0 // Wrap to first | |
| @@ -524,11 +524,11 @@ func (spm *StackedPaneManager) createTitleBar(pane *paneNode) gtk.Widgetter { | |||
| 524 | 524 | if pane.pane != nil && pane.pane.webView != nil { | |
| 525 | 525 | titleText = pane.pane.webView.GetTitle() | |
| 526 | 526 | if titleText == "" { | |
| 527 | - | titleText = "New Tab" // Fallback only when title is actually empty | |
| 527 | + | titleText = NewTabTitle // Fallback only when title is actually empty | |
| 528 | 528 | } | |
| 529 | 529 | pageURL = pane.pane.webView.GetCurrentURL() | |
| 530 | 530 | } else { | |
| 531 | - | titleText = "New Tab" | |
| 531 | + | titleText = NewTabTitle | |
| 532 | 532 | } | |
| 533 | 533 | ||
| 534 | 534 | titleBar := spm.createTitleBarWithTitle(titleText, pageURL) | |
| @@ -430,7 +430,7 @@ func (spm *StackedPaneManager) UpdateStackVisibility(stackNode *paneNode) { | |||||
| 430 | if pane.pane != nil && pane.pane.webView != nil { | 430 | if pane.pane != nil && pane.pane.webView != nil { | ||
| 431 | title := pane.pane.webView.GetTitle() | 431 | title := pane.pane.webView.GetTitle() | ||
| 432 | if title == "" { | 432 | if title == "" { | ||
| 433 | - | title = "New Tab" | 433 | + | title = NewTabTitle |
| 434 | } | 434 | } | ||
| 435 | spm.updateTitleBarLabel(pane, title) | 435 | spm.updateTitleBarLabel(pane, title) | ||
| 436 | } | 436 | } | ||
| @@ -475,12 +475,12 @@ func (spm *StackedPaneManager) NavigateStack(direction string) bool { | |||||
| 475 | // Calculate new index based on direction | 475 | // Calculate new index based on direction | ||
| 476 | var newIndex int | 476 | var newIndex int | ||
| 477 | switch direction { | 477 | switch direction { | ||
| 478 | - | case "up": | 478 | + | case DirectionUp: |
| 479 | newIndex = currentIndex - 1 | 479 | newIndex = currentIndex - 1 | ||
| 480 | if newIndex < 0 { | 480 | if newIndex < 0 { | ||
| 481 | newIndex = len(stackNode.stackedPanes) - 1 // Wrap to last | 481 | newIndex = len(stackNode.stackedPanes) - 1 // Wrap to last | ||
| 482 | } | 482 | } | ||
| 483 | - | case "down": | 483 | + | case DirectionDown: |
| 484 | newIndex = currentIndex + 1 | 484 | newIndex = currentIndex + 1 | ||
| 485 | if newIndex >= len(stackNode.stackedPanes) { | 485 | if newIndex >= len(stackNode.stackedPanes) { | ||
| 486 | newIndex = 0 // Wrap to first | 486 | newIndex = 0 // Wrap to first | ||
| @@ -524,11 +524,11 @@ func (spm *StackedPaneManager) createTitleBar(pane *paneNode) gtk.Widgetter { | |||||
| 524 | if pane.pane != nil && pane.pane.webView != nil { | 524 | if pane.pane != nil && pane.pane.webView != nil { | ||
| 525 | titleText = pane.pane.webView.GetTitle() | 525 | titleText = pane.pane.webView.GetTitle() | ||
| 526 | if titleText == "" { | 526 | if titleText == "" { | ||
| 527 | - | titleText = "New Tab" // Fallback only when title is actually empty | 527 | + | titleText = NewTabTitle // Fallback only when title is actually empty |
| 528 | } | 528 | } | ||
| 529 | pageURL = pane.pane.webView.GetCurrentURL() | 529 | pageURL = pane.pane.webView.GetCurrentURL() | ||
| 530 | } else { | 530 | } else { | ||
| 531 | - | titleText = "New Tab" | 531 | + | titleText = NewTabTitle |
| 532 | } | 532 | } | ||
| 533 | 533 | ||||
| 534 | titleBar := spm.createTitleBarWithTitle(titleText, pageURL) | 534 | titleBar := spm.createTitleBarWithTitle(titleText, pageURL) | ||
M internal/app/browser/window_shortcuts.go +4 -4
| @@ -69,10 +69,10 @@ func (h *WindowShortcutHandler) registerGlobalShortcuts() error { | |||
| 69 | 69 | {"ctrl+minus", h.handleZoomOut, "Zoom out"}, | |
| 70 | 70 | {"ctrl+0", h.handleZoomReset, "Zoom reset"}, | |
| 71 | 71 | // Workspace navigation shortcuts - global level for proper active pane targeting | |
| 72 | - | {"alt+ArrowLeft", func() { h.handleWorkspaceNavigation("left") }, "Navigate left pane"}, | |
| 73 | - | {"alt+ArrowRight", func() { h.handleWorkspaceNavigation("right") }, "Navigate right pane"}, | |
| 74 | - | {"alt+ArrowUp", func() { h.handleWorkspaceNavigation("up") }, "Navigate up pane"}, | |
| 75 | - | {"alt+ArrowDown", func() { h.handleWorkspaceNavigation("down") }, "Navigate down pane"}, | |
| 72 | + | {"alt+ArrowLeft", func() { h.handleWorkspaceNavigation(DirectionLeft) }, "Navigate left pane"}, | |
| 73 | + | {"alt+ArrowRight", func() { h.handleWorkspaceNavigation(DirectionRight) }, "Navigate right pane"}, | |
| 74 | + | {"alt+ArrowUp", func() { h.handleWorkspaceNavigation(DirectionUp) }, "Navigate up pane"}, | |
| 75 | + | {"alt+ArrowDown", func() { h.handleWorkspaceNavigation(DirectionDown) }, "Navigate down pane"}, | |
| 76 | 76 | } | |
| 77 | 77 | ||
| 78 | 78 | for _, shortcut := range shortcuts { | |
| @@ -69,10 +69,10 @@ func (h *WindowShortcutHandler) registerGlobalShortcuts() error { | |||||
| 69 | {"ctrl+minus", h.handleZoomOut, "Zoom out"}, | 69 | {"ctrl+minus", h.handleZoomOut, "Zoom out"}, | ||
| 70 | {"ctrl+0", h.handleZoomReset, "Zoom reset"}, | 70 | {"ctrl+0", h.handleZoomReset, "Zoom reset"}, | ||
| 71 | // Workspace navigation shortcuts - global level for proper active pane targeting | 71 | // Workspace navigation shortcuts - global level for proper active pane targeting | ||
| 72 | - | {"alt+ArrowLeft", func() { h.handleWorkspaceNavigation("left") }, "Navigate left pane"}, | 72 | + | {"alt+ArrowLeft", func() { h.handleWorkspaceNavigation(DirectionLeft) }, "Navigate left pane"}, |
| 73 | - | {"alt+ArrowRight", func() { h.handleWorkspaceNavigation("right") }, "Navigate right pane"}, | 73 | + | {"alt+ArrowRight", func() { h.handleWorkspaceNavigation(DirectionRight) }, "Navigate right pane"}, |
| 74 | - | {"alt+ArrowUp", func() { h.handleWorkspaceNavigation("up") }, "Navigate up pane"}, | 74 | + | {"alt+ArrowUp", func() { h.handleWorkspaceNavigation(DirectionUp) }, "Navigate up pane"}, |
| 75 | - | {"alt+ArrowDown", func() { h.handleWorkspaceNavigation("down") }, "Navigate down pane"}, | 75 | + | {"alt+ArrowDown", func() { h.handleWorkspaceNavigation(DirectionDown) }, "Navigate down pane"}, |
| 76 | } | 76 | } | ||
| 77 | 77 | ||||
| 78 | for _, shortcut := range shortcuts { | 78 | for _, shortcut := range shortcuts { | ||
M internal/app/browser/workspace_css.go +3 -1
| @@ -185,7 +185,9 @@ func (wm *WorkspaceManager) ensureWorkspaceStyles() { | |||
| 185 | 185 | ||
| 186 | 186 | // Only apply CSS if it hasn't been applied globally or if content changed | |
| 187 | 187 | if !globalCSSInitialized || globalCSSContent != workspaceCSS { | |
| 188 | - | webkit.AddCSSProvider(workspaceCSS) | |
| 188 | + | if err := webkit.AddCSSProvider(workspaceCSS); err != nil { | |
| 189 | + | log.Printf("[workspace] WARNING: Failed to add CSS provider: %v", err) | |
| 190 | + | } | |
| 189 | 191 | globalCSSInitialized = true | |
| 190 | 192 | globalCSSContent = workspaceCSS | |
| 191 | 193 | log.Printf("[workspace] Applied workspace CSS styles (%d bytes)", len(workspaceCSS)) | |
| @@ -185,7 +185,9 @@ func (wm *WorkspaceManager) ensureWorkspaceStyles() { | |||||
| 185 | 185 | ||||
| 186 | // Only apply CSS if it hasn't been applied globally or if content changed | 186 | // Only apply CSS if it hasn't been applied globally or if content changed | ||
| 187 | if !globalCSSInitialized || globalCSSContent != workspaceCSS { | 187 | if !globalCSSInitialized || globalCSSContent != workspaceCSS { | ||
| 188 | - | webkit.AddCSSProvider(workspaceCSS) | 188 | + | if err := webkit.AddCSSProvider(workspaceCSS); err != nil { |
| 189 | + | log.Printf("[workspace] WARNING: Failed to add CSS provider: %v", err) | |||
| 190 | + | } | |||
| 189 | globalCSSInitialized = true | 191 | globalCSSInitialized = true | ||
| 190 | globalCSSContent = workspaceCSS | 192 | globalCSSContent = workspaceCSS | ||
| 191 | log.Printf("[workspace] Applied workspace CSS styles (%d bytes)", len(workspaceCSS)) | 193 | log.Printf("[workspace] Applied workspace CSS styles (%d bytes)", len(workspaceCSS)) | ||
M internal/app/browser/workspace_geometry_validator.go +2 -2
| @@ -166,9 +166,9 @@ func (gv *GeometryValidator) ValidateSplit(node *paneNode, direction string) Val | |||
| 166 | 166 | } | |
| 167 | 167 | ||
| 168 | 168 | switch direction { | |
| 169 | - | case "left", "right": | |
| 169 | + | case DirectionLeft, DirectionRight: | |
| 170 | 170 | return gv.ValidateHorizontalSplit(node) | |
| 171 | - | case "up", "down": | |
| 171 | + | case DirectionUp, DirectionDown: | |
| 172 | 172 | return gv.ValidateVerticalSplit(node) | |
| 173 | 173 | default: | |
| 174 | 174 | return ValidationResult{IsValid: false, Reason: fmt.Sprintf("unknown split direction: %s", direction)} | |
| @@ -166,9 +166,9 @@ func (gv *GeometryValidator) ValidateSplit(node *paneNode, direction string) Val | |||||
| 166 | } | 166 | } | ||
| 167 | 167 | ||||
| 168 | switch direction { | 168 | switch direction { | ||
| 169 | - | case "left", "right": | 169 | + | case DirectionLeft, DirectionRight: |
| 170 | return gv.ValidateHorizontalSplit(node) | 170 | return gv.ValidateHorizontalSplit(node) | ||
| 171 | - | case "up", "down": | 171 | + | case DirectionUp, DirectionDown: |
| 172 | return gv.ValidateVerticalSplit(node) | 172 | return gv.ValidateVerticalSplit(node) | ||
| 173 | default: | 173 | default: | ||
| 174 | return ValidationResult{IsValid: false, Reason: fmt.Sprintf("unknown split direction: %s", direction)} | 174 | return ValidationResult{IsValid: false, Reason: fmt.Sprintf("unknown split direction: %s", direction)} | ||
M internal/app/browser/workspace_manager.go +1 -1
| @@ -259,7 +259,7 @@ func (wm *WorkspaceManager) OnWorkspaceMessage(source *webkit.WebView, msg messa | |||
| 259 | 259 | wm.SetActivePane(node, SourceProgrammatic) | |
| 260 | 260 | direction := strings.ToLower(msg.Direction) | |
| 261 | 261 | if direction == "" { | |
| 262 | - | direction = "right" | |
| 262 | + | direction = DirectionRight | |
| 263 | 263 | } | |
| 264 | 264 | ||
| 265 | 265 | if wm.shouldDebounce(source, 200*time.Millisecond) { | |
| @@ -259,7 +259,7 @@ func (wm *WorkspaceManager) OnWorkspaceMessage(source *webkit.WebView, msg messa | |||||
| 259 | wm.SetActivePane(node, SourceProgrammatic) | 259 | wm.SetActivePane(node, SourceProgrammatic) | ||
| 260 | direction := strings.ToLower(msg.Direction) | 260 | direction := strings.ToLower(msg.Direction) | ||
| 261 | if direction == "" { | 261 | if direction == "" { | ||
| 262 | - | direction = "right" | 262 | + | direction = DirectionRight |
| 263 | } | 263 | } | ||
| 264 | 264 | ||||
| 265 | if wm.shouldDebounce(source, 200*time.Millisecond) { | 265 | if wm.shouldDebounce(source, 200*time.Millisecond) { | ||
M internal/app/browser/workspace_navigation.go +23 -23
| @@ -105,21 +105,21 @@ func (wm *WorkspaceManager) detachFocus(node *paneNode) { | |||
| 105 | 105 | } | |
| 106 | 106 | ||
| 107 | 107 | // FocusNeighbor moves focus to the nearest pane in the requested direction using the | |
| 108 | - | // actual widget geometry to determine adjacency. For stacked panes, "up" and "down" | |
| 108 | + | // actual widget geometry to determine adjacency. For stacked panes, DirectionUp and DirectionDown | |
| 109 | 109 | // navigate within the stack. | |
| 110 | 110 | func (wm *WorkspaceManager) FocusNeighbor(direction string) bool { | |
| 111 | 111 | if wm == nil { | |
| 112 | 112 | return false | |
| 113 | 113 | } | |
| 114 | 114 | switch strings.ToLower(direction) { | |
| 115 | - | case "up", "down": | |
| 115 | + | case DirectionUp, DirectionDown: | |
| 116 | 116 | // Check if current pane is part of a stack and handle stack navigation | |
| 117 | 117 | if wm.stackedPaneManager.NavigateStack(strings.ToLower(direction)) { | |
| 118 | 118 | return true | |
| 119 | 119 | } | |
| 120 | 120 | // Fall back to regular adjacency navigation | |
| 121 | 121 | return wm.focusAdjacent(strings.ToLower(direction)) | |
| 122 | - | case "left", "right": | |
| 122 | + | case DirectionLeft, DirectionRight: | |
| 123 | 123 | return wm.focusAdjacent(strings.ToLower(direction)) | |
| 124 | 124 | default: | |
| 125 | 125 | log.Printf("[workspace] invalid focus direction: %s (expected: up, down, left, right)", direction) | |
| @@ -169,12 +169,12 @@ func (wm *WorkspaceManager) navigateStack(direction string) bool { | |||
| 169 | 169 | // Calculate new index based on direction | |
| 170 | 170 | var newIndex int | |
| 171 | 171 | switch direction { | |
| 172 | - | case "up": | |
| 172 | + | case DirectionUp: | |
| 173 | 173 | newIndex = currentIndex - 1 | |
| 174 | 174 | if newIndex < 0 { | |
| 175 | 175 | newIndex = len(stackNode.stackedPanes) - 1 // Wrap to last | |
| 176 | 176 | } | |
| 177 | - | case "down": | |
| 177 | + | case DirectionDown: | |
| 178 | 178 | newIndex = currentIndex + 1 | |
| 179 | 179 | if newIndex >= len(stackNode.stackedPanes) { | |
| 180 | 180 | newIndex = 0 // Wrap to first | |
| @@ -235,29 +235,29 @@ func (wm *WorkspaceManager) focusAdjacent(direction string) bool { | |||
| 235 | 235 | ||
| 236 | 236 | var score float64 | |
| 237 | 237 | switch direction { | |
| 238 | - | case "left": | |
| 238 | + | case DirectionLeft: | |
| 239 | 239 | if dx >= -focusEpsilon { | |
| 240 | 240 | continue | |
| 241 | 241 | } | |
| 242 | 242 | score = math.Abs(dx)*1000 + math.Abs(dy) | |
| 243 | - | case "right": | |
| 243 | + | case DirectionRight: | |
| 244 | 244 | if dx <= focusEpsilon { | |
| 245 | 245 | continue | |
| 246 | 246 | } | |
| 247 | 247 | score = math.Abs(dx)*1000 + math.Abs(dy) | |
| 248 | - | case "up": | |
| 248 | + | case DirectionUp: | |
| 249 | 249 | if dy >= -focusEpsilon { | |
| 250 | 250 | continue | |
| 251 | 251 | } | |
| 252 | 252 | score = math.Abs(dy)*1000 + math.Abs(dx) | |
| 253 | - | case "down": | |
| 253 | + | case DirectionDown: | |
| 254 | 254 | if dy <= focusEpsilon { | |
| 255 | 255 | continue | |
| 256 | 256 | } | |
| 257 | 257 | score = math.Abs(dy)*1000 + math.Abs(dx) | |
| 258 | 258 | } | |
| 259 | 259 | ||
| 260 | - | if direction == "up" || direction == "down" { | |
| 260 | + | if direction == DirectionUp || direction == DirectionDown { | |
| 261 | 261 | debugCandidates = append(debugCandidates, fmt.Sprintf("cand=%p dx=%.2f dy=%.2f score=%.2f", candidate.container, dx, dy, score)) | |
| 262 | 262 | } | |
| 263 | 263 | ||
| @@ -287,29 +287,29 @@ func (wm *WorkspaceManager) structuralNeighbor(node *paneNode, direction string) | |||
| 287 | 287 | refX, refY, refWidth, refHeight := webkit.WidgetGetAllocation(node.container) | |
| 288 | 288 | cx := float64(refX) + float64(refWidth)/2.0 | |
| 289 | 289 | cy := float64(refY) + float64(refHeight)/2.0 | |
| 290 | - | axisVertical := direction == "up" || direction == "down" | |
| 290 | + | axisVertical := direction == DirectionUp || direction == DirectionDown | |
| 291 | 291 | ||
| 292 | 292 | for parent := node.parent; parent != nil; parent = parent.parent { | |
| 293 | 293 | switch direction { | |
| 294 | - | case "up": | |
| 294 | + | case DirectionUp: | |
| 295 | 295 | if axisVertical && parent.orientation == gtk.OrientationVertical && parent.right == node { | |
| 296 | 296 | if leaf := wm.closestLeafFromSubtree(parent.left, cx, cy, direction); leaf != nil { | |
| 297 | 297 | return leaf | |
| 298 | 298 | } | |
| 299 | 299 | } | |
| 300 | - | case "down": | |
| 300 | + | case DirectionDown: | |
| 301 | 301 | if axisVertical && parent.orientation == gtk.OrientationVertical && parent.left == node { | |
| 302 | 302 | if leaf := wm.closestLeafFromSubtree(parent.right, cx, cy, direction); leaf != nil { | |
| 303 | 303 | return leaf | |
| 304 | 304 | } | |
| 305 | 305 | } | |
| 306 | - | case "left": | |
| 306 | + | case DirectionLeft: | |
| 307 | 307 | if !axisVertical && parent.orientation == gtk.OrientationHorizontal && parent.right == node { | |
| 308 | 308 | if leaf := wm.closestLeafFromSubtree(parent.left, cx, cy, direction); leaf != nil { | |
| 309 | 309 | return leaf | |
| 310 | 310 | } | |
| 311 | 311 | } | |
| 312 | - | case "right": | |
| 312 | + | case DirectionRight: | |
| 313 | 313 | if !axisVertical && parent.orientation == gtk.OrientationHorizontal && parent.left == node { | |
| 314 | 314 | if leaf := wm.closestLeafFromSubtree(parent.right, cx, cy, direction); leaf != nil { | |
| 315 | 315 | return leaf | |
| @@ -338,22 +338,22 @@ func (wm *WorkspaceManager) closestLeafFromSubtree(node *paneNode, cx, cy float6 | |||
| 338 | 338 | dy := ty - cy | |
| 339 | 339 | var score float64 | |
| 340 | 340 | switch direction { | |
| 341 | - | case "left": | |
| 341 | + | case DirectionLeft: | |
| 342 | 342 | if dx >= -focusEpsilon { | |
| 343 | 343 | continue | |
| 344 | 344 | } | |
| 345 | 345 | score = math.Abs(dx)*1000 + math.Abs(dy) | |
| 346 | - | case "right": | |
| 346 | + | case DirectionRight: | |
| 347 | 347 | if dx <= focusEpsilon { | |
| 348 | 348 | continue | |
| 349 | 349 | } | |
| 350 | 350 | score = math.Abs(dx)*1000 + math.Abs(dy) | |
| 351 | - | case "up": | |
| 351 | + | case DirectionUp: | |
| 352 | 352 | if dy >= -focusEpsilon { | |
| 353 | 353 | continue | |
| 354 | 354 | } | |
| 355 | 355 | score = math.Abs(dy)*1000 + math.Abs(dx) | |
| 356 | - | case "down": | |
| 356 | + | case DirectionDown: | |
| 357 | 357 | if dy <= focusEpsilon { | |
| 358 | 358 | continue | |
| 359 | 359 | } | |
| @@ -393,22 +393,22 @@ func (wm *WorkspaceManager) boundaryFallbackWithDepth(node *paneNode, direction | |||
| 393 | 393 | return node | |
| 394 | 394 | } | |
| 395 | 395 | switch direction { | |
| 396 | - | case "up": | |
| 396 | + | case DirectionUp: | |
| 397 | 397 | if leaf := wm.boundaryFallbackWithDepth(node.right, direction, depth+1); leaf != nil { | |
| 398 | 398 | return leaf | |
| 399 | 399 | } | |
| 400 | 400 | return wm.boundaryFallbackWithDepth(node.left, direction, depth+1) | |
| 401 | - | case "down": | |
| 401 | + | case DirectionDown: | |
| 402 | 402 | if leaf := wm.boundaryFallbackWithDepth(node.left, direction, depth+1); leaf != nil { | |
| 403 | 403 | return leaf | |
| 404 | 404 | } | |
| 405 | 405 | return wm.boundaryFallbackWithDepth(node.right, direction, depth+1) | |
| 406 | - | case "left": | |
| 406 | + | case DirectionLeft: | |
| 407 | 407 | if leaf := wm.boundaryFallbackWithDepth(node.right, direction, depth+1); leaf != nil { | |
| 408 | 408 | return leaf | |
| 409 | 409 | } | |
| 410 | 410 | return wm.boundaryFallbackWithDepth(node.left, direction, depth+1) | |
| 411 | - | case "right": | |
| 411 | + | case DirectionRight: | |
| 412 | 412 | if leaf := wm.boundaryFallbackWithDepth(node.left, direction, depth+1); leaf != nil { | |
| 413 | 413 | return leaf | |
| 414 | 414 | } | |
| @@ -105,21 +105,21 @@ func (wm *WorkspaceManager) detachFocus(node *paneNode) { | |||||
| 105 | } | 105 | } | ||
| 106 | 106 | ||||
| 107 | // FocusNeighbor moves focus to the nearest pane in the requested direction using the | 107 | // FocusNeighbor moves focus to the nearest pane in the requested direction using the | ||
| 108 | - | // actual widget geometry to determine adjacency. For stacked panes, "up" and "down" | 108 | + | // actual widget geometry to determine adjacency. For stacked panes, DirectionUp and DirectionDown |
| 109 | // navigate within the stack. | 109 | // navigate within the stack. | ||
| 110 | func (wm *WorkspaceManager) FocusNeighbor(direction string) bool { | 110 | func (wm *WorkspaceManager) FocusNeighbor(direction string) bool { | ||
| 111 | if wm == nil { | 111 | if wm == nil { | ||
| 112 | return false | 112 | return false | ||
| 113 | } | 113 | } | ||
| 114 | switch strings.ToLower(direction) { | 114 | switch strings.ToLower(direction) { | ||
| 115 | - | case "up", "down": | 115 | + | case DirectionUp, DirectionDown: |
| 116 | // Check if current pane is part of a stack and handle stack navigation | 116 | // Check if current pane is part of a stack and handle stack navigation | ||
| 117 | if wm.stackedPaneManager.NavigateStack(strings.ToLower(direction)) { | 117 | if wm.stackedPaneManager.NavigateStack(strings.ToLower(direction)) { | ||
| 118 | return true | 118 | return true | ||
| 119 | } | 119 | } | ||
| 120 | // Fall back to regular adjacency navigation | 120 | // Fall back to regular adjacency navigation | ||
| 121 | return wm.focusAdjacent(strings.ToLower(direction)) | 121 | return wm.focusAdjacent(strings.ToLower(direction)) | ||
| 122 | - | case "left", "right": | 122 | + | case DirectionLeft, DirectionRight: |
| 123 | return wm.focusAdjacent(strings.ToLower(direction)) | 123 | return wm.focusAdjacent(strings.ToLower(direction)) | ||
| 124 | default: | 124 | default: | ||
| 125 | log.Printf("[workspace] invalid focus direction: %s (expected: up, down, left, right)", direction) | 125 | log.Printf("[workspace] invalid focus direction: %s (expected: up, down, left, right)", direction) | ||
| @@ -169,12 +169,12 @@ func (wm *WorkspaceManager) navigateStack(direction string) bool { | |||||
| 169 | // Calculate new index based on direction | 169 | // Calculate new index based on direction | ||
| 170 | var newIndex int | 170 | var newIndex int | ||
| 171 | switch direction { | 171 | switch direction { | ||
| 172 | - | case "up": | 172 | + | case DirectionUp: |
| 173 | newIndex = currentIndex - 1 | 173 | newIndex = currentIndex - 1 | ||
| 174 | if newIndex < 0 { | 174 | if newIndex < 0 { | ||
| 175 | newIndex = len(stackNode.stackedPanes) - 1 // Wrap to last | 175 | newIndex = len(stackNode.stackedPanes) - 1 // Wrap to last | ||
| 176 | } | 176 | } | ||
| 177 | - | case "down": | 177 | + | case DirectionDown: |
| 178 | newIndex = currentIndex + 1 | 178 | newIndex = currentIndex + 1 | ||
| 179 | if newIndex >= len(stackNode.stackedPanes) { | 179 | if newIndex >= len(stackNode.stackedPanes) { | ||
| 180 | newIndex = 0 // Wrap to first | 180 | newIndex = 0 // Wrap to first | ||
| @@ -235,29 +235,29 @@ func (wm *WorkspaceManager) focusAdjacent(direction string) bool { | |||||
| 235 | 235 | ||||
| 236 | var score float64 | 236 | var score float64 | ||
| 237 | switch direction { | 237 | switch direction { | ||
| 238 | - | case "left": | 238 | + | case DirectionLeft: |
| 239 | if dx >= -focusEpsilon { | 239 | if dx >= -focusEpsilon { | ||
| 240 | continue | 240 | continue | ||
| 241 | } | 241 | } | ||
| 242 | score = math.Abs(dx)*1000 + math.Abs(dy) | 242 | score = math.Abs(dx)*1000 + math.Abs(dy) | ||
| 243 | - | case "right": | 243 | + | case DirectionRight: |
| 244 | if dx <= focusEpsilon { | 244 | if dx <= focusEpsilon { | ||
| 245 | continue | 245 | continue | ||
| 246 | } | 246 | } | ||
| 247 | score = math.Abs(dx)*1000 + math.Abs(dy) | 247 | score = math.Abs(dx)*1000 + math.Abs(dy) | ||
| 248 | - | case "up": | 248 | + | case DirectionUp: |
| 249 | if dy >= -focusEpsilon { | 249 | if dy >= -focusEpsilon { | ||
| 250 | continue | 250 | continue | ||
| 251 | } | 251 | } | ||
| 252 | score = math.Abs(dy)*1000 + math.Abs(dx) | 252 | score = math.Abs(dy)*1000 + math.Abs(dx) | ||
| 253 | - | case "down": | 253 | + | case DirectionDown: |
| 254 | if dy <= focusEpsilon { | 254 | if dy <= focusEpsilon { | ||
| 255 | continue | 255 | continue | ||
| 256 | } | 256 | } | ||
| 257 | score = math.Abs(dy)*1000 + math.Abs(dx) | 257 | score = math.Abs(dy)*1000 + math.Abs(dx) | ||
| 258 | } | 258 | } | ||
| 259 | 259 | ||||
| 260 | - | if direction == "up" || direction == "down" { | 260 | + | if direction == DirectionUp || direction == DirectionDown { |
| 261 | debugCandidates = append(debugCandidates, fmt.Sprintf("cand=%p dx=%.2f dy=%.2f score=%.2f", candidate.container, dx, dy, score)) | 261 | debugCandidates = append(debugCandidates, fmt.Sprintf("cand=%p dx=%.2f dy=%.2f score=%.2f", candidate.container, dx, dy, score)) | ||
| 262 | } | 262 | } | ||
| 263 | 263 | ||||
| @@ -287,29 +287,29 @@ func (wm *WorkspaceManager) structuralNeighbor(node *paneNode, direction string) | |||||
| 287 | refX, refY, refWidth, refHeight := webkit.WidgetGetAllocation(node.container) | 287 | refX, refY, refWidth, refHeight := webkit.WidgetGetAllocation(node.container) | ||
| 288 | cx := float64(refX) + float64(refWidth)/2.0 | 288 | cx := float64(refX) + float64(refWidth)/2.0 | ||
| 289 | cy := float64(refY) + float64(refHeight)/2.0 | 289 | cy := float64(refY) + float64(refHeight)/2.0 | ||
| 290 | - | axisVertical := direction == "up" || direction == "down" | 290 | + | axisVertical := direction == DirectionUp || direction == DirectionDown |
| 291 | 291 | ||||
| 292 | for parent := node.parent; parent != nil; parent = parent.parent { | 292 | for parent := node.parent; parent != nil; parent = parent.parent { | ||
| 293 | switch direction { | 293 | switch direction { | ||
| 294 | - | case "up": | 294 | + | case DirectionUp: |
| 295 | if axisVertical && parent.orientation == gtk.OrientationVertical && parent.right == node { | 295 | if axisVertical && parent.orientation == gtk.OrientationVertical && parent.right == node { | ||
| 296 | if leaf := wm.closestLeafFromSubtree(parent.left, cx, cy, direction); leaf != nil { | 296 | if leaf := wm.closestLeafFromSubtree(parent.left, cx, cy, direction); leaf != nil { | ||
| 297 | return leaf | 297 | return leaf | ||
| 298 | } | 298 | } | ||
| 299 | } | 299 | } | ||
| 300 | - | case "down": | 300 | + | case DirectionDown: |
| 301 | if axisVertical && parent.orientation == gtk.OrientationVertical && parent.left == node { | 301 | if axisVertical && parent.orientation == gtk.OrientationVertical && parent.left == node { | ||
| 302 | if leaf := wm.closestLeafFromSubtree(parent.right, cx, cy, direction); leaf != nil { | 302 | if leaf := wm.closestLeafFromSubtree(parent.right, cx, cy, direction); leaf != nil { | ||
| 303 | return leaf | 303 | return leaf | ||
| 304 | } | 304 | } | ||
| 305 | } | 305 | } | ||
| 306 | - | case "left": | 306 | + | case DirectionLeft: |
| 307 | if !axisVertical && parent.orientation == gtk.OrientationHorizontal && parent.right == node { | 307 | if !axisVertical && parent.orientation == gtk.OrientationHorizontal && parent.right == node { | ||
| 308 | if leaf := wm.closestLeafFromSubtree(parent.left, cx, cy, direction); leaf != nil { | 308 | if leaf := wm.closestLeafFromSubtree(parent.left, cx, cy, direction); leaf != nil { | ||
| 309 | return leaf | 309 | return leaf | ||
| 310 | } | 310 | } | ||
| 311 | } | 311 | } | ||
| 312 | - | case "right": | 312 | + | case DirectionRight: |
| 313 | if !axisVertical && parent.orientation == gtk.OrientationHorizontal && parent.left == node { | 313 | if !axisVertical && parent.orientation == gtk.OrientationHorizontal && parent.left == node { | ||
| 314 | if leaf := wm.closestLeafFromSubtree(parent.right, cx, cy, direction); leaf != nil { | 314 | if leaf := wm.closestLeafFromSubtree(parent.right, cx, cy, direction); leaf != nil { | ||
| 315 | return leaf | 315 | return leaf | ||
| @@ -338,22 +338,22 @@ func (wm *WorkspaceManager) closestLeafFromSubtree(node *paneNode, cx, cy float6 | |||||
| 338 | dy := ty - cy | 338 | dy := ty - cy | ||
| 339 | var score float64 | 339 | var score float64 | ||
| 340 | switch direction { | 340 | switch direction { | ||
| 341 | - | case "left": | 341 | + | case DirectionLeft: |
| 342 | if dx >= -focusEpsilon { | 342 | if dx >= -focusEpsilon { | ||
| 343 | continue | 343 | continue | ||
| 344 | } | 344 | } | ||
| 345 | score = math.Abs(dx)*1000 + math.Abs(dy) | 345 | score = math.Abs(dx)*1000 + math.Abs(dy) | ||
| 346 | - | case "right": | 346 | + | case DirectionRight: |
| 347 | if dx <= focusEpsilon { | 347 | if dx <= focusEpsilon { | ||
| 348 | continue | 348 | continue | ||
| 349 | } | 349 | } | ||
| 350 | score = math.Abs(dx)*1000 + math.Abs(dy) | 350 | score = math.Abs(dx)*1000 + math.Abs(dy) | ||
| 351 | - | case "up": | 351 | + | case DirectionUp: |
| 352 | if dy >= -focusEpsilon { | 352 | if dy >= -focusEpsilon { | ||
| 353 | continue | 353 | continue | ||
| 354 | } | 354 | } | ||
| 355 | score = math.Abs(dy)*1000 + math.Abs(dx) | 355 | score = math.Abs(dy)*1000 + math.Abs(dx) | ||
| 356 | - | case "down": | 356 | + | case DirectionDown: |
| 357 | if dy <= focusEpsilon { | 357 | if dy <= focusEpsilon { | ||
| 358 | continue | 358 | continue | ||
| 359 | } | 359 | } | ||
| @@ -393,22 +393,22 @@ func (wm *WorkspaceManager) boundaryFallbackWithDepth(node *paneNode, direction | |||||
| 393 | return node | 393 | return node | ||
| 394 | } | 394 | } | ||
| 395 | switch direction { | 395 | switch direction { | ||
| 396 | - | case "up": | 396 | + | case DirectionUp: |
| 397 | if leaf := wm.boundaryFallbackWithDepth(node.right, direction, depth+1); leaf != nil { | 397 | if leaf := wm.boundaryFallbackWithDepth(node.right, direction, depth+1); leaf != nil { | ||
| 398 | return leaf | 398 | return leaf | ||
| 399 | } | 399 | } | ||
| 400 | return wm.boundaryFallbackWithDepth(node.left, direction, depth+1) | 400 | return wm.boundaryFallbackWithDepth(node.left, direction, depth+1) | ||
| 401 | - | case "down": | 401 | + | case DirectionDown: |
| 402 | if leaf := wm.boundaryFallbackWithDepth(node.left, direction, depth+1); leaf != nil { | 402 | if leaf := wm.boundaryFallbackWithDepth(node.left, direction, depth+1); leaf != nil { | ||
| 403 | return leaf | 403 | return leaf | ||
| 404 | } | 404 | } | ||
| 405 | return wm.boundaryFallbackWithDepth(node.right, direction, depth+1) | 405 | return wm.boundaryFallbackWithDepth(node.right, direction, depth+1) | ||
| 406 | - | case "left": | 406 | + | case DirectionLeft: |
| 407 | if leaf := wm.boundaryFallbackWithDepth(node.right, direction, depth+1); leaf != nil { | 407 | if leaf := wm.boundaryFallbackWithDepth(node.right, direction, depth+1); leaf != nil { | ||
| 408 | return leaf | 408 | return leaf | ||
| 409 | } | 409 | } | ||
| 410 | return wm.boundaryFallbackWithDepth(node.left, direction, depth+1) | 410 | return wm.boundaryFallbackWithDepth(node.left, direction, depth+1) | ||
| 411 | - | case "right": | 411 | + | case DirectionRight: |
| 412 | if leaf := wm.boundaryFallbackWithDepth(node.left, direction, depth+1); leaf != nil { | 412 | if leaf := wm.boundaryFallbackWithDepth(node.left, direction, depth+1); leaf != nil { | ||
| 413 | return leaf | 413 | return leaf | ||
| 414 | } | 414 | } | ||
M internal/app/browser/workspace_navigation_test.go +8 -8
| @@ -77,10 +77,10 @@ func TestMapDirection(t *testing.T) { | |||
| 77 | 77 | orientation gtk.Orientation | |
| 78 | 78 | existingFirst bool | |
| 79 | 79 | }{ | |
| 80 | - | {"down", gtk.OrientationVertical, true}, | |
| 81 | - | {"up", gtk.OrientationVertical, false}, | |
| 82 | - | {"right", gtk.OrientationHorizontal, true}, | |
| 83 | - | {"left", gtk.OrientationHorizontal, false}, | |
| 80 | + | {DirectionDown, gtk.OrientationVertical, true}, | |
| 81 | + | {DirectionUp, gtk.OrientationVertical, false}, | |
| 82 | + | {DirectionRight, gtk.OrientationHorizontal, true}, | |
| 83 | + | {DirectionLeft, gtk.OrientationHorizontal, false}, | |
| 84 | 84 | } | |
| 85 | 85 | ||
| 86 | 86 | for _, tt := range tests { | |
| @@ -131,10 +131,10 @@ func TestCaseSensitiveDirections(t *testing.T) { | |||
| 131 | 131 | "Down", | |
| 132 | 132 | "LEFT", | |
| 133 | 133 | "Right", | |
| 134 | - | "up", | |
| 135 | - | "down", | |
| 136 | - | "left", | |
| 137 | - | "right", | |
| 134 | + | DirectionUp, | |
| 135 | + | DirectionDown, | |
| 136 | + | DirectionLeft, | |
| 137 | + | DirectionRight, | |
| 138 | 138 | } | |
| 139 | 139 | ||
| 140 | 140 | for _, direction := range validDirections { | |
| @@ -77,10 +77,10 @@ func TestMapDirection(t *testing.T) { | |||||
| 77 | orientation gtk.Orientation | 77 | orientation gtk.Orientation | ||
| 78 | existingFirst bool | 78 | existingFirst bool | ||
| 79 | }{ | 79 | }{ | ||
| 80 | - | {"down", gtk.OrientationVertical, true}, | 80 | + | {DirectionDown, gtk.OrientationVertical, true}, |
| 81 | - | {"up", gtk.OrientationVertical, false}, | 81 | + | {DirectionUp, gtk.OrientationVertical, false}, |
| 82 | - | {"right", gtk.OrientationHorizontal, true}, | 82 | + | {DirectionRight, gtk.OrientationHorizontal, true}, |
| 83 | - | {"left", gtk.OrientationHorizontal, false}, | 83 | + | {DirectionLeft, gtk.OrientationHorizontal, false}, |
| 84 | } | 84 | } | ||
| 85 | 85 | ||||
| 86 | for _, tt := range tests { | 86 | for _, tt := range tests { | ||
| @@ -131,10 +131,10 @@ func TestCaseSensitiveDirections(t *testing.T) { | |||||
| 131 | "Down", | 131 | "Down", | ||
| 132 | "LEFT", | 132 | "LEFT", | ||
| 133 | "Right", | 133 | "Right", | ||
| 134 | - | "up", | 134 | + | DirectionUp, |
| 135 | - | "down", | 135 | + | DirectionDown, |
| 136 | - | "left", | 136 | + | DirectionLeft, |
| 137 | - | "right", | 137 | + | DirectionRight, |
| 138 | } | 138 | } | ||
| 139 | 139 | ||||
| 140 | for _, direction := range validDirections { | 140 | for _, direction := range validDirections { | ||
M internal/app/browser/workspace_operations.go +4 -4
| @@ -16,10 +16,10 @@ func (wm *WorkspaceManager) SplitPane(target *paneNode, direction string) (*pane | |||
| 16 | 16 | ||
| 17 | 17 | // Validate direction parameter | |
| 18 | 18 | validDirections := map[string]bool{ | |
| 19 | - | "left": true, | |
| 20 | - | "right": true, | |
| 21 | - | "up": true, | |
| 22 | - | "down": true, | |
| 19 | + | DirectionLeft: true, | |
| 20 | + | DirectionRight: true, | |
| 21 | + | DirectionUp: true, | |
| 22 | + | DirectionDown: true, | |
| 23 | 23 | } | |
| 24 | 24 | if !validDirections[direction] { | |
| 25 | 25 | return nil, fmt.Errorf("invalid split direction '%s', expected one of: left, right, up, down", direction) | |
| @@ -16,10 +16,10 @@ func (wm *WorkspaceManager) SplitPane(target *paneNode, direction string) (*pane | |||||
| 16 | 16 | ||||
| 17 | // Validate direction parameter | 17 | // Validate direction parameter | ||
| 18 | validDirections := map[string]bool{ | 18 | validDirections := map[string]bool{ | ||
| 19 | - | "left": true, | 19 | + | DirectionLeft: true, |
| 20 | - | "right": true, | 20 | + | DirectionRight: true, |
| 21 | - | "up": true, | 21 | + | DirectionUp: true, |
| 22 | - | "down": true, | 22 | + | DirectionDown: true, |
| 23 | } | 23 | } | ||
| 24 | if !validDirections[direction] { | 24 | if !validDirections[direction] { | ||
| 25 | return nil, fmt.Errorf("invalid split direction '%s', expected one of: left, right, up, down", direction) | 25 | return nil, fmt.Errorf("invalid split direction '%s', expected one of: left, right, up, down", direction) | ||
M internal/app/browser/workspace_pane_mode.go +5 -5
| @@ -124,17 +124,17 @@ func (wm *WorkspaceManager) handlePaneSplit(node *paneNode, action string) { | |||
| 124 | 124 | return | |
| 125 | 125 | } | |
| 126 | 126 | ||
| 127 | - | // Extract direction from action (e.g., "split-right" -> "right") | |
| 127 | + | // Extract direction from action (e.g., "split-right" -> DirectionRight) | |
| 128 | 128 | var direction string | |
| 129 | 129 | switch action { | |
| 130 | 130 | case "split-right": | |
| 131 | - | direction = "right" | |
| 131 | + | direction = DirectionRight | |
| 132 | 132 | case "split-left": | |
| 133 | - | direction = "left" | |
| 133 | + | direction = DirectionLeft | |
| 134 | 134 | case "split-up": | |
| 135 | - | direction = "up" | |
| 135 | + | direction = DirectionUp | |
| 136 | 136 | case "split-down": | |
| 137 | - | direction = "down" | |
| 137 | + | direction = DirectionDown | |
| 138 | 138 | default: | |
| 139 | 139 | log.Printf("[pane-mode] Invalid split action: %s", action) | |
| 140 | 140 | return | |
| @@ -124,17 +124,17 @@ func (wm *WorkspaceManager) handlePaneSplit(node *paneNode, action string) { | |||||
| 124 | return | 124 | return | ||
| 125 | } | 125 | } | ||
| 126 | 126 | ||||
| 127 | - | // Extract direction from action (e.g., "split-right" -> "right") | 127 | + | // Extract direction from action (e.g., "split-right" -> DirectionRight) |
| 128 | var direction string | 128 | var direction string | ||
| 129 | switch action { | 129 | switch action { | ||
| 130 | case "split-right": | 130 | case "split-right": | ||
| 131 | - | direction = "right" | 131 | + | direction = DirectionRight |
| 132 | case "split-left": | 132 | case "split-left": | ||
| 133 | - | direction = "left" | 133 | + | direction = DirectionLeft |
| 134 | case "split-up": | 134 | case "split-up": | ||
| 135 | - | direction = "up" | 135 | + | direction = DirectionUp |
| 136 | case "split-down": | 136 | case "split-down": | ||
| 137 | - | direction = "down" | 137 | + | direction = DirectionDown |
| 138 | default: | 138 | default: | ||
| 139 | log.Printf("[pane-mode] Invalid split action: %s", action) | 139 | log.Printf("[pane-mode] Invalid split action: %s", action) | ||
| 140 | return | 140 | return | ||
M internal/app/browser/workspace_popup.go +7 -7
| @@ -37,7 +37,7 @@ func (wm *WorkspaceManager) insertIndependentPane(sourceNode *paneNode, webView | |||
| 37 | 37 | } | |
| 38 | 38 | direction := strings.ToLower(wm.app.config.Workspace.Popups.Placement) | |
| 39 | 39 | if direction == "" { | |
| 40 | - | direction = "right" | |
| 40 | + | direction = DirectionRight | |
| 41 | 41 | } | |
| 42 | 42 | // Use splitNode with existing pane instead of insertPopupPane | |
| 43 | 43 | if _, err := wm.splitNode(sourceNode, direction, newPane); err != nil { | |
| @@ -65,7 +65,7 @@ func (wm *WorkspaceManager) configureRelatedPopup(sourceNode *paneNode, webView | |||
| 65 | 65 | } | |
| 66 | 66 | direction := strings.ToLower(wm.app.config.Workspace.Popups.Placement) | |
| 67 | 67 | if direction == "" { | |
| 68 | - | direction = "right" | |
| 68 | + | direction = DirectionRight | |
| 69 | 69 | } | |
| 70 | 70 | // Use splitNode with existing pane instead of insertPopupPane | |
| 71 | 71 | if _, err := wm.splitNode(sourceNode, direction, newPane); err != nil { | |
| @@ -427,7 +427,7 @@ func (wm *WorkspaceManager) handlePopupReadyToShow(popupID uint64) { | |||
| 427 | 427 | // Split pane behavior (default) - use splitNode with existing popup pane | |
| 428 | 428 | direction := strings.ToLower(wm.app.config.Workspace.Popups.Placement) | |
| 429 | 429 | if direction == "" { | |
| 430 | - | direction = "right" | |
| 430 | + | direction = DirectionRight | |
| 431 | 431 | } | |
| 432 | 432 | if _, err := wm.splitNode(info.parentNode, direction, popupPane); err != nil { | |
| 433 | 433 | log.Printf("[workspace] Failed to insert split popup pane: %v", err) | |
| @@ -444,7 +444,7 @@ func (wm *WorkspaceManager) handlePopupReadyToShow(popupID uint64) { | |||
| 444 | 444 | // Insert the popup pane in the same container - use splitNode with existing popup pane | |
| 445 | 445 | direction := strings.ToLower(wm.app.config.Workspace.Popups.Placement) | |
| 446 | 446 | if direction == "" { | |
| 447 | - | direction = "right" | |
| 447 | + | direction = DirectionRight | |
| 448 | 448 | } | |
| 449 | 449 | if _, err := wm.splitNode(info.parentNode, direction, popupPane); err != nil { | |
| 450 | 450 | log.Printf("[workspace] Failed to insert stacked popup pane: %v", err) | |
| @@ -456,7 +456,7 @@ func (wm *WorkspaceManager) handlePopupReadyToShow(popupID uint64) { | |||
| 456 | 456 | log.Printf("[workspace] WARNING: Tabbed popup behavior not yet implemented, falling back to split") | |
| 457 | 457 | direction := strings.ToLower(wm.app.config.Workspace.Popups.Placement) | |
| 458 | 458 | if direction == "" { | |
| 459 | - | direction = "right" | |
| 459 | + | direction = DirectionRight | |
| 460 | 460 | } | |
| 461 | 461 | if _, err := wm.splitNode(info.parentNode, direction, popupPane); err != nil { | |
| 462 | 462 | log.Printf("[workspace] Failed to insert tabbed popup pane: %v", err) | |
| @@ -469,7 +469,7 @@ func (wm *WorkspaceManager) handlePopupReadyToShow(popupID uint64) { | |||
| 469 | 469 | log.Printf("[workspace] WARNING: Windowed popup behavior not yet implemented, falling back to split") | |
| 470 | 470 | direction := strings.ToLower(wm.app.config.Workspace.Popups.Placement) | |
| 471 | 471 | if direction == "" { | |
| 472 | - | direction = "right" | |
| 472 | + | direction = DirectionRight | |
| 473 | 473 | } | |
| 474 | 474 | if _, err := wm.splitNode(info.parentNode, direction, popupPane); err != nil { | |
| 475 | 475 | log.Printf("[workspace] Failed to insert windowed popup pane: %v", err) | |
| @@ -481,7 +481,7 @@ func (wm *WorkspaceManager) handlePopupReadyToShow(popupID uint64) { | |||
| 481 | 481 | log.Printf("[workspace] Unknown popup behavior '%s', falling back to split", behavior) | |
| 482 | 482 | direction := strings.ToLower(wm.app.config.Workspace.Popups.Placement) | |
| 483 | 483 | if direction == "" { | |
| 484 | - | direction = "right" | |
| 484 | + | direction = DirectionRight | |
| 485 | 485 | } | |
| 486 | 486 | if _, err := wm.splitNode(info.parentNode, direction, popupPane); err != nil { | |
| 487 | 487 | log.Printf("[workspace] Failed to insert popup pane: %v", err) | |
| @@ -37,7 +37,7 @@ func (wm *WorkspaceManager) insertIndependentPane(sourceNode *paneNode, webView | |||||
| 37 | } | 37 | } | ||
| 38 | direction := strings.ToLower(wm.app.config.Workspace.Popups.Placement) | 38 | direction := strings.ToLower(wm.app.config.Workspace.Popups.Placement) | ||
| 39 | if direction == "" { | 39 | if direction == "" { | ||
| 40 | - | direction = "right" | 40 | + | direction = DirectionRight |
| 41 | } | 41 | } | ||
| 42 | // Use splitNode with existing pane instead of insertPopupPane | 42 | // Use splitNode with existing pane instead of insertPopupPane | ||
| 43 | if _, err := wm.splitNode(sourceNode, direction, newPane); err != nil { | 43 | if _, err := wm.splitNode(sourceNode, direction, newPane); err != nil { | ||
| @@ -65,7 +65,7 @@ func (wm *WorkspaceManager) configureRelatedPopup(sourceNode *paneNode, webView | |||||
| 65 | } | 65 | } | ||
| 66 | direction := strings.ToLower(wm.app.config.Workspace.Popups.Placement) | 66 | direction := strings.ToLower(wm.app.config.Workspace.Popups.Placement) | ||
| 67 | if direction == "" { | 67 | if direction == "" { | ||
| 68 | - | direction = "right" | 68 | + | direction = DirectionRight |
| 69 | } | 69 | } | ||
| 70 | // Use splitNode with existing pane instead of insertPopupPane | 70 | // Use splitNode with existing pane instead of insertPopupPane | ||
| 71 | if _, err := wm.splitNode(sourceNode, direction, newPane); err != nil { | 71 | if _, err := wm.splitNode(sourceNode, direction, newPane); err != nil { | ||
| @@ -427,7 +427,7 @@ func (wm *WorkspaceManager) handlePopupReadyToShow(popupID uint64) { | |||||
| 427 | // Split pane behavior (default) - use splitNode with existing popup pane | 427 | // Split pane behavior (default) - use splitNode with existing popup pane | ||
| 428 | direction := strings.ToLower(wm.app.config.Workspace.Popups.Placement) | 428 | direction := strings.ToLower(wm.app.config.Workspace.Popups.Placement) | ||
| 429 | if direction == "" { | 429 | if direction == "" { | ||
| 430 | - | direction = "right" | 430 | + | direction = DirectionRight |
| 431 | } | 431 | } | ||
| 432 | if _, err := wm.splitNode(info.parentNode, direction, popupPane); err != nil { | 432 | if _, err := wm.splitNode(info.parentNode, direction, popupPane); err != nil { | ||
| 433 | log.Printf("[workspace] Failed to insert split popup pane: %v", err) | 433 | log.Printf("[workspace] Failed to insert split popup pane: %v", err) | ||
| @@ -444,7 +444,7 @@ func (wm *WorkspaceManager) handlePopupReadyToShow(popupID uint64) { | |||||
| 444 | // Insert the popup pane in the same container - use splitNode with existing popup pane | 444 | // Insert the popup pane in the same container - use splitNode with existing popup pane | ||
| 445 | direction := strings.ToLower(wm.app.config.Workspace.Popups.Placement) | 445 | direction := strings.ToLower(wm.app.config.Workspace.Popups.Placement) | ||
| 446 | if direction == "" { | 446 | if direction == "" { | ||
| 447 | - | direction = "right" | 447 | + | direction = DirectionRight |
| 448 | } | 448 | } | ||
| 449 | if _, err := wm.splitNode(info.parentNode, direction, popupPane); err != nil { | 449 | if _, err := wm.splitNode(info.parentNode, direction, popupPane); err != nil { | ||
| 450 | log.Printf("[workspace] Failed to insert stacked popup pane: %v", err) | 450 | log.Printf("[workspace] Failed to insert stacked popup pane: %v", err) | ||
| @@ -456,7 +456,7 @@ func (wm *WorkspaceManager) handlePopupReadyToShow(popupID uint64) { | |||||
| 456 | log.Printf("[workspace] WARNING: Tabbed popup behavior not yet implemented, falling back to split") | 456 | log.Printf("[workspace] WARNING: Tabbed popup behavior not yet implemented, falling back to split") | ||
| 457 | direction := strings.ToLower(wm.app.config.Workspace.Popups.Placement) | 457 | direction := strings.ToLower(wm.app.config.Workspace.Popups.Placement) | ||
| 458 | if direction == "" { | 458 | if direction == "" { | ||
| 459 | - | direction = "right" | 459 | + | direction = DirectionRight |
| 460 | } | 460 | } | ||
| 461 | if _, err := wm.splitNode(info.parentNode, direction, popupPane); err != nil { | 461 | if _, err := wm.splitNode(info.parentNode, direction, popupPane); err != nil { | ||
| 462 | log.Printf("[workspace] Failed to insert tabbed popup pane: %v", err) | 462 | log.Printf("[workspace] Failed to insert tabbed popup pane: %v", err) | ||
| @@ -469,7 +469,7 @@ func (wm *WorkspaceManager) handlePopupReadyToShow(popupID uint64) { | |||||
| 469 | log.Printf("[workspace] WARNING: Windowed popup behavior not yet implemented, falling back to split") | 469 | log.Printf("[workspace] WARNING: Windowed popup behavior not yet implemented, falling back to split") | ||
| 470 | direction := strings.ToLower(wm.app.config.Workspace.Popups.Placement) | 470 | direction := strings.ToLower(wm.app.config.Workspace.Popups.Placement) | ||
| 471 | if direction == "" { | 471 | if direction == "" { | ||
| 472 | - | direction = "right" | 472 | + | direction = DirectionRight |
| 473 | } | 473 | } | ||
| 474 | if _, err := wm.splitNode(info.parentNode, direction, popupPane); err != nil { | 474 | if _, err := wm.splitNode(info.parentNode, direction, popupPane); err != nil { | ||
| 475 | log.Printf("[workspace] Failed to insert windowed popup pane: %v", err) | 475 | log.Printf("[workspace] Failed to insert windowed popup pane: %v", err) | ||
| @@ -481,7 +481,7 @@ func (wm *WorkspaceManager) handlePopupReadyToShow(popupID uint64) { | |||||
| 481 | log.Printf("[workspace] Unknown popup behavior '%s', falling back to split", behavior) | 481 | log.Printf("[workspace] Unknown popup behavior '%s', falling back to split", behavior) | ||
| 482 | direction := strings.ToLower(wm.app.config.Workspace.Popups.Placement) | 482 | direction := strings.ToLower(wm.app.config.Workspace.Popups.Placement) | ||
| 483 | if direction == "" { | 483 | if direction == "" { | ||
| 484 | - | direction = "right" | 484 | + | direction = DirectionRight |
| 485 | } | 485 | } | ||
| 486 | if _, err := wm.splitNode(info.parentNode, direction, popupPane); err != nil { | 486 | if _, err := wm.splitNode(info.parentNode, direction, popupPane); err != nil { | ||
| 487 | log.Printf("[workspace] Failed to insert popup pane: %v", err) | 487 | log.Printf("[workspace] Failed to insert popup pane: %v", err) | ||
M internal/app/browser/workspace_utils.go +3 -3
| @@ -35,11 +35,11 @@ func (wm *WorkspaceManager) ensureGUIInPane(pane *BrowserPane) { | |||
| 35 | 35 | // mapDirection maps a direction string to GTK orientation and positioning | |
| 36 | 36 | func mapDirection(direction string) (gtk.Orientation, bool) { | |
| 37 | 37 | switch direction { | |
| 38 | - | case "left": | |
| 38 | + | case DirectionLeft: | |
| 39 | 39 | return gtk.OrientationHorizontal, false | |
| 40 | - | case "up": | |
| 40 | + | case DirectionUp: | |
| 41 | 41 | return gtk.OrientationVertical, false | |
| 42 | - | case "down": | |
| 42 | + | case DirectionDown: | |
| 43 | 43 | return gtk.OrientationVertical, true | |
| 44 | 44 | default: | |
| 45 | 45 | return gtk.OrientationHorizontal, true | |
| @@ -35,11 +35,11 @@ func (wm *WorkspaceManager) ensureGUIInPane(pane *BrowserPane) { | |||||
| 35 | // mapDirection maps a direction string to GTK orientation and positioning | 35 | // mapDirection maps a direction string to GTK orientation and positioning | ||
| 36 | func mapDirection(direction string) (gtk.Orientation, bool) { | 36 | func mapDirection(direction string) (gtk.Orientation, bool) { | ||
| 37 | switch direction { | 37 | switch direction { | ||
| 38 | - | case "left": | 38 | + | case DirectionLeft: |
| 39 | return gtk.OrientationHorizontal, false | 39 | return gtk.OrientationHorizontal, false | ||
| 40 | - | case "up": | 40 | + | case DirectionUp: |
| 41 | return gtk.OrientationVertical, false | 41 | return gtk.OrientationVertical, false | ||
| 42 | - | case "down": | 42 | + | case DirectionDown: |
| 43 | return gtk.OrientationVertical, true | 43 | return gtk.OrientationVertical, true | ||
| 44 | default: | 44 | default: | ||
| 45 | return gtk.OrientationHorizontal, true | 45 | return gtk.OrientationHorizontal, true | ||
M internal/app/control/navigation.go +6 -2
| @@ -55,7 +55,9 @@ func (n *NavigationController) NavigateToURL(input string) error { | |||
| 55 | 55 | haveZoom = true | |
| 56 | 56 | if n.webView != nil { | |
| 57 | 57 | if n.webView.UsesDomZoom() { | |
| 58 | - | n.webView.SeedDomZoom(zoomLevel) | |
| 58 | + | if err := n.webView.SeedDomZoom(zoomLevel); err != nil { | |
| 59 | + | log.Printf("Warning: failed to seed DOM zoom for %s: %v", result.URL, err) | |
| 60 | + | } | |
| 59 | 61 | } else { | |
| 60 | 62 | n.webView.RunOnMainThread(func() { | |
| 61 | 63 | if err := n.webView.SetZoom(zoomLevel); err != nil { | |
| @@ -108,7 +110,9 @@ func (n *NavigationController) HandleBrowseCommand() { | |||
| 108 | 110 | zoomLevel = level | |
| 109 | 111 | haveZoom = true | |
| 110 | 112 | if n.webView.UsesDomZoom() { | |
| 111 | - | n.webView.SeedDomZoom(zoomLevel) | |
| 113 | + | if err := n.webView.SeedDomZoom(zoomLevel); err != nil { | |
| 114 | + | log.Printf("Warning: failed to seed DOM zoom for %s: %v", result.URL, err) | |
| 115 | + | } | |
| 112 | 116 | } else { | |
| 113 | 117 | n.webView.RunOnMainThread(func() { | |
| 114 | 118 | if err := n.webView.SetZoom(zoomLevel); err != nil { | |
| @@ -55,7 +55,9 @@ func (n *NavigationController) NavigateToURL(input string) error { | |||||
| 55 | haveZoom = true | 55 | haveZoom = true | ||
| 56 | if n.webView != nil { | 56 | if n.webView != nil { | ||
| 57 | if n.webView.UsesDomZoom() { | 57 | if n.webView.UsesDomZoom() { | ||
| 58 | - | n.webView.SeedDomZoom(zoomLevel) | 58 | + | if err := n.webView.SeedDomZoom(zoomLevel); err != nil { |
| 59 | + | log.Printf("Warning: failed to seed DOM zoom for %s: %v", result.URL, err) | |||
| 60 | + | } | |||
| 59 | } else { | 61 | } else { | ||
| 60 | n.webView.RunOnMainThread(func() { | 62 | n.webView.RunOnMainThread(func() { | ||
| 61 | if err := n.webView.SetZoom(zoomLevel); err != nil { | 63 | if err := n.webView.SetZoom(zoomLevel); err != nil { | ||
| @@ -108,7 +110,9 @@ func (n *NavigationController) HandleBrowseCommand() { | |||||
| 108 | zoomLevel = level | 110 | zoomLevel = level | ||
| 109 | haveZoom = true | 111 | haveZoom = true | ||
| 110 | if n.webView.UsesDomZoom() { | 112 | if n.webView.UsesDomZoom() { | ||
| 111 | - | n.webView.SeedDomZoom(zoomLevel) | 113 | + | if err := n.webView.SeedDomZoom(zoomLevel); err != nil { |
| 114 | + | log.Printf("Warning: failed to seed DOM zoom for %s: %v", result.URL, err) | |||
| 115 | + | } | |||
| 112 | } else { | 116 | } else { | ||
| 113 | n.webView.RunOnMainThread(func() { | 117 | n.webView.RunOnMainThread(func() { | ||
| 114 | if err := n.webView.SetZoom(zoomLevel); err != nil { | 118 | if err := n.webView.SetZoom(zoomLevel); err != nil { | ||