Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

*.Box,SetMouseCapture() captures all mouse-events, not only those within the Box #926

Open
FJuedesOrcl opened this issue Dec 5, 2023 · 1 comment

Comments

@FJuedesOrcl
Copy link

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

@digitallyserviced
Copy link
Contributor

@FJuedesOrcl

// SetMouseCapture sets a function which captures mouse events (consisting of
// the original tcell mouse event and the semantic mouse action) before they are
// forwarded to the primitive's default mouse event handler. This function can
// then choose to forward that event (or a different one) by returning it or
// returning a nil mouse event, in which case the default handler will not be
// called.

So this is how it works. The comment doc even states that it is meant to be a handler to choose whether or not the mouse event should be passed on to the primitives default mouse event handler, which is the one that is built into the TreeView primitive.

If you want to be able to handle more events then what the default primitive is capable of handling, then you need to think about creating a new primtive, or subclassing/embedding the treeview widget.

The wiki describes how to create your own primitive. THen you would be utilizing 'WrapMouseHandler' and 'WrapInputHandler' instead of the global Capture handler that is on the Box primitive.

Also what if you want to make a modal dialog box, and have the MouseCapture force all events to the modal, so it can detect if any clicks were made outside of it to dismiss it? It is just another feature, albeit probably not what you are looking for in this use case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants