[GH-ISSUE #926] *.Box,SetMouseCapture() captures all mouse-events, not only those within the Box #676

Open
opened 2026-03-04 01:06:58 +03:00 by kerem · 1 comment
Owner

Originally created by @FJuedesOrcl on GitHub (Dec 5, 2023).
Original GitHub issue: https://github.com/rivo/tview/issues/926

Hi Friends,

i am not sure if this is intentional, by mistake or technically unavoidable:

  • I have written a small application for which i want to improve the mouse-functionality, for example a double click on a table-row should open an edit-window.
  • I have created an example program (below) that configures a tview.Grid with a tview.TreeView to the left, a tview.Table to the right and a tview.TextView at the bottom as a status-line for debug-output.
  • I have attached a debug-printing MouseCapture function to the tview.Box element of the tview.TreeView only, but that function receives events from all over the screen.
  • My expectation was that, similar to an Input-Handler (*.SetInputCapture()) the MouseCapture function would only receive events within the boxes borders.

Am i doing something wrong? - Please have a look at the code below.
Another question arose while writing the short experimental code:
How can one map the mouse-event coordinates to a TUI-element?
I am using flexible-grid dimensions, so that the dimensions of the elements are depending on the size of the terminal window.

Any hints and recommendations very welcomed!

Best regards from Charleston (WV),
Frank/2

Here is the sample code:

package main

import (
  "fmt"
  "github.com/gdamore/tcell/v2"
  "github.com/rivo/tview"
)

func main() {
    // Configure a status-line for debug output
    Status := tview.NewTextView().SetText("Statusline")

    // Configure a Mouse-Capture function       
    MouseCapture := func(action tview.MouseAction, event *tcell.EventMouse) (tview.MouseAction, *tcell.EventMouse) {
      // Print the Mouse-Action as a bitmap
      Output := fmt.Sprintf("MouseAction: %%%016b; ",action)
      
      // Print the Mouse Buttons as bitmap
      buttons := event.Buttons()
      Output += fmt.Sprintf("MouseButtons: %%%016b; ",buttons)
      
      // Print the modifiers as bitmap
      modifiers := event.Modifiers()
      Output += fmt.Sprintf("Modifier Keys: %%%016b; ",modifiers)
      
      // Print the event-position
      PosX,PosY := event.Position()
      Output += fmt.Sprintf("PosX: %03d; PosY: %02d",PosX,PosY)
      
      // "print" output into status-line
      Status.SetText(Output)
      
      return action,event
    } // END MouseCapture

    // Configure a table with selectable rows
    Panel := tview.NewTable()
    Panel.SetBorders(true)
    Panel.SetBorderColor(tcell.NewRGBColor(127,127,127))
    Panel.SetSelectable(true,false)
    for row:=0;row<13;row++ {
      for col:=0;col<6;col++ {
        Panel.SetCell(row,col,tview.NewTableCell(fmt.Sprintf("row: %2d; col: %2d",row,col)).SetSelectable(true))
      } // END for col
    } // End for row
    
    // Configure a TreeView based menu
    RootNode := tview.NewTreeNode("ROOT").SetColor(tcell.NewRGBColor(255,15,15)).SetSelectable(true)
    for n:=0;n<10;n++ {
      node := tview.NewTreeNode(fmt.Sprintf("Node: %d",n)).SetColor(tcell.NewRGBColor(15,255,15)).SetSelectable(true)
      RootNode.AddChild(node)
    } // END for n
    
    Tree := tview.NewTreeView().SetRoot(RootNode).SetCurrentNode(RootNode).
                                SetGraphics(true).SetGraphicsColor(tcell.NewRGBColor(15,15,255))
    
    // !!!!!!!!!! We set the MouseCapture for the TreeView.Box only !!!!!!!!!!
    Tree.Box.SetBorder(true).SetMouseCapture(MouseCapture)                            
    
    // Configure a grid with the TreeView to the left, the Table to the right and the status-line at the bottom
    Grid := tview.NewGrid()
    Grid.SetColumns(-1,-3).SetRows(0,1).
         AddItem(Tree,0,0,1,1,0,0,true).
         AddItem(Panel,0,1,1,1,0,0,false).
         AddItem(Status,1,0,1,2,0,0,false)

    // Create and run the application
	app := tview.NewApplication().EnableMouse(true).SetMouseCapture(nil)
	if err := app.SetRoot(Grid, true).Run(); err != nil {
		panic(err)
	} // END if
} // END main

Originally created by @FJuedesOrcl on GitHub (Dec 5, 2023). Original GitHub issue: https://github.com/rivo/tview/issues/926 Hi Friends, i am not sure if this is intentional, by mistake or technically unavoidable: - I have written a small application for which i want to improve the mouse-functionality, for example a double click on a table-row should open an edit-window. - I have created an example program (below) that configures a tview.Grid with a tview.TreeView to the left, a tview.Table to the right and a tview.TextView at the bottom as a status-line for debug-output. - I have attached a debug-printing MouseCapture function to the tview.Box element of the tview.TreeView only, but that function receives events from all over the screen. - My expectation was that, similar to an Input-Handler (*.SetInputCapture()) the MouseCapture function would only receive events within the boxes borders. Am i doing something wrong? - Please have a look at the code below. Another question arose while writing the short experimental code: How can one map the mouse-event coordinates to a TUI-element? I am using flexible-grid dimensions, so that the dimensions of the elements are depending on the size of the terminal window. Any hints and recommendations very welcomed! Best regards from Charleston (WV), Frank/2 Here is the sample code: --- ``` package main import ( "fmt" "github.com/gdamore/tcell/v2" "github.com/rivo/tview" ) func main() { // Configure a status-line for debug output Status := tview.NewTextView().SetText("Statusline") // Configure a Mouse-Capture function MouseCapture := func(action tview.MouseAction, event *tcell.EventMouse) (tview.MouseAction, *tcell.EventMouse) { // Print the Mouse-Action as a bitmap Output := fmt.Sprintf("MouseAction: %%%016b; ",action) // Print the Mouse Buttons as bitmap buttons := event.Buttons() Output += fmt.Sprintf("MouseButtons: %%%016b; ",buttons) // Print the modifiers as bitmap modifiers := event.Modifiers() Output += fmt.Sprintf("Modifier Keys: %%%016b; ",modifiers) // Print the event-position PosX,PosY := event.Position() Output += fmt.Sprintf("PosX: %03d; PosY: %02d",PosX,PosY) // "print" output into status-line Status.SetText(Output) return action,event } // END MouseCapture // Configure a table with selectable rows Panel := tview.NewTable() Panel.SetBorders(true) Panel.SetBorderColor(tcell.NewRGBColor(127,127,127)) Panel.SetSelectable(true,false) for row:=0;row<13;row++ { for col:=0;col<6;col++ { Panel.SetCell(row,col,tview.NewTableCell(fmt.Sprintf("row: %2d; col: %2d",row,col)).SetSelectable(true)) } // END for col } // End for row // Configure a TreeView based menu RootNode := tview.NewTreeNode("ROOT").SetColor(tcell.NewRGBColor(255,15,15)).SetSelectable(true) for n:=0;n<10;n++ { node := tview.NewTreeNode(fmt.Sprintf("Node: %d",n)).SetColor(tcell.NewRGBColor(15,255,15)).SetSelectable(true) RootNode.AddChild(node) } // END for n Tree := tview.NewTreeView().SetRoot(RootNode).SetCurrentNode(RootNode). SetGraphics(true).SetGraphicsColor(tcell.NewRGBColor(15,15,255)) // !!!!!!!!!! We set the MouseCapture for the TreeView.Box only !!!!!!!!!! Tree.Box.SetBorder(true).SetMouseCapture(MouseCapture) // Configure a grid with the TreeView to the left, the Table to the right and the status-line at the bottom Grid := tview.NewGrid() Grid.SetColumns(-1,-3).SetRows(0,1). AddItem(Tree,0,0,1,1,0,0,true). AddItem(Panel,0,1,1,1,0,0,false). AddItem(Status,1,0,1,2,0,0,false) // Create and run the application app := tview.NewApplication().EnableMouse(true).SetMouseCapture(nil) if err := app.SetRoot(Grid, true).Run(); err != nil { panic(err) } // END if } // END main ```
Author
Owner

@yxzzy-wtf commented on GitHub (Nov 30, 2025):

Hi @FJuedesOrcl: sorry for the very-late response to this thread. I discovered the same issue when I was building a grid with several MouseCapture events. I was finding that, given a grid, it seems like all items on the "row" would be triggered in sequence.

For example, what I found was, assuming the following grid where [xC] is clickable:

[1C] [2C] [3C]
[4C] [5C] [6C]

Clicking on 3C will first execute MouseCapture on 1C, then 2C, then 3C.

Clicking on 5C will first execute on 4C, then 5C.

On the off chance that you're still dealing with this (or someone else is dealing with this finds this question), a workaround that fixes it for me is:

square.SetMouseCapture(
	func(action tview.MouseAction, event *tcell.EventMouse) (tview.MouseAction, *tcell.EventMouse) {
		mx, my := event.Position()
		x, y, w, h := square.Box.GetRect()
		if mx >= x && my >= y && mx <= (x+w) && my <= (y+h) {
			// DO ACTION
		}

		return action, event
	})

The above basically checks that the mouseclick is within the Box coordinates before doing the action. At some point I might dig deeper into the logic that triggers MouseCapture to see if there's an actual bug causing a full row trigger.

<!-- gh-comment-id:3592501349 --> @yxzzy-wtf commented on GitHub (Nov 30, 2025): Hi @FJuedesOrcl: sorry for the very-late response to this thread. I discovered the same issue when I was building a grid with several MouseCapture events. I was finding that, given a grid, it seems like all items on the "row" would be triggered in sequence. For example, what I found was, assuming the following grid where [xC] is clickable: ``` [1C] [2C] [3C] [4C] [5C] [6C] ``` Clicking on 3C will first execute MouseCapture on 1C, then 2C, then 3C. Clicking on 5C will first execute on 4C, then 5C. On the off chance that you're still dealing with this (or someone else is dealing with this finds this question), a workaround that fixes it for me is: ``` square.SetMouseCapture( func(action tview.MouseAction, event *tcell.EventMouse) (tview.MouseAction, *tcell.EventMouse) { mx, my := event.Position() x, y, w, h := square.Box.GetRect() if mx >= x && my >= y && mx <= (x+w) && my <= (y+h) { // DO ACTION } return action, event }) ``` The above basically checks that the mouseclick is within the Box coordinates before doing the action. At some point I might dig deeper into the logic that triggers MouseCapture to see if there's an actual bug causing a full row trigger.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/tview#676
No description provided.