simonkrauter / NiGui

Cross-platform desktop GUI toolkit written in Nim
MIT License
718 stars 50 forks source link

Is there a way to get mouse over event? #185

Closed harrier77 closed 4 months ago

harrier77 commented 4 months ago

I tried Nigui and I am positive impressed by its simplicity. I found that it is relatively easy to create other controls from the standard controls provided. I was wondering if there is a way to detect the mouse over event on a label or a button to replicate the feedback offered on the web when the cursor becomes a pointer or the link changes its color.

simonkrauter commented 4 months ago

So far mouse move events are not implemented, but I think it would be straight forward to add.

harrier77 commented 4 months ago

Thanks for your answer. I actually did suppose that it was only needed to find a way to link an existing gtk and win32 function to nigui. But how? With some hint I could try to do it myself but I don't even know which gtk object has to be taken as target... I mean: is there a simple mouse over event in GTK?

simonkrauter commented 4 months ago

I have implemented it now, see 4c0ae23. You need to use the git head revision. Feedback is welcome, especially how it affects the application's CPU usage under Windows.

harrier77 commented 4 months ago

That's great, I have tested it and it works on linux/gtk. I simply have added a method like this to a custom widget method handleMouseMoveEvent(control: CustomLabel, event: MouseEvent) = echo "mouse over..." control.backgroundColor=rgb(220,220,220) and every time I move the mouse pointer over the label the backgroud color is changed. For the use I have in mind I need a mouseleave event. I suppose it should be managed by gtk and win32 because I found that there is something similar in wxwidget PS: I will test it on Windows very soon.

harrier77 commented 4 months ago

I found the way wxpython can do what I want to do here: https://stackoverflow.com/questions/74500316/wxpython-is-it-possible-to-manage-the-hover-color-of-a-button It seems that it is needed to bind a wx.EVT_LEAVE_WINDOW to the control, so I think there is a corrisponding gtk event

harrier77 commented 4 months ago

I checked again, maybe I was wrong. I think wx builds EVT_LEAVE and EVT_ENTER on the GdkEventMotion comparing the position of mouse with the rectangle of the control. There is no simple event_leave ready to use in gtk, it must be built. https://github.com/wxWidgets/wxWidgets/blob/e2af669387ebe0c423bc995d8ca3d4c926728456/src/gtk/window.cpp#L1971

harrier77 commented 4 months ago

Here I am again. I tried to implement the onmouse leave event with this: var is_entered:bool=false method handleMouseMoveEvent(control: CustomLabel, event: MouseEvent) = control.backgroundColor=rgb(220,220,220) if (event.x>event.control.width-8 or event.y>event.control.height-8): control.backgroundColor=rgb(255,255,255) is_entered=true It works, but I am not sure if it is the best way to do the trick. Maybe it should be managed better inside Nigui. I will test it in Windows too, and I will check the cpu load.

simonkrauter commented 4 months ago

I have implemented mouse enter/leave events.

My test program:

import nigui

type MyButton = ref object of Button
  isMouseIn: bool

proc newButton(text = ""): Button =
  result = new MyButton
  result.init()
  result.text = text

method handleDrawEvent(control: MyButton, event: DrawEvent) =
  var button = cast[Button](event.control)
  let canvas = event.control.canvas
  if control.isMouseIn:
    canvas.areaColor = rgb(100, 100, 100)
  else:
    canvas.areaColor = rgb(55, 55, 55)
  canvas.textColor = rgb(255, 255, 255)
  canvas.lineColor = rgb(255, 255, 255)
  canvas.drawRectArea(0, 0, button.width, button.height)
  canvas.drawTextCentered(button.text)
  canvas.drawRectOutline(0, 0, button.width, button.height)

method handleMouseEnterEvent(control: MyButton, event: MouseEvent) =
  control.isMouseIn = true
  control.forceRedraw()

method handleMouseLeaveEvent(control: MyButton, event: MouseEvent) =
  control.isMouseIn = false
  control.forceRedraw()

app.init()

var window = newWindow()
window.width = 900
window.height = 800

var box = newLayoutContainer(Layout_Vertical)
window.add(box)

for x in 1..5:
  var box2 = newLayoutContainer(Layout_Horizontal)
  box2.padding = 40
  box2.spacing = 40
  box.add(box2)

  for y in 1..5:
    var button = newButton("Button " & $x & "/" & $y)
    box2.add(button)
    button.width = 120
    button.height = 60

window.show()
app.run()
harrier77 commented 4 months ago

Excellent work, it is very functional and practical. I have just tried your test program and it works in Linux gtk, I will test it in Windows and I will post the result here. Before your new patch I tried to implement the enter/leave events with this but it was not working well because it was depending by the speed of mouse movement:

import nigui
import std/browsers
type CustomButton* = ref object of Button
    miotext: string
type CruButton* = ref object of CustomButton
    hover*:bool
    marg_x*:int
    marg_y*:int
    darker*:Color
    whiter*:Color
method handleDrawEvent(control: CustomButton, event: DrawEvent) = 
    let canvas = event.control.canvas
    canvas.areaColor = control.backgroundColor
    canvas.textColor = rgb(255, 255, 255)
    canvas.lineColor = rgb(255, 255, 255)
    canvas.drawRectArea(0, 0, control.width, control.height)
    canvas.drawTextCentered(control.text)
    canvas.drawRectOutline(0, 0, control.width, control.height)
proc dark_color(color:Color,meno:byte):Color=
    var color1=rgb(color.red-meno,color.green-meno, color.blue-meno,color.alpha)
    return color1
method miosetcolor*(control:CruButton,color:Color) {.base.} =
    control.backgroundColor=color
    control.darker=dark_color(color,10)
    control.whiter=color
    control.hover=true
var listabtn=newSeqOfCap[CruButton](15)
method handleMouseMoveEvent*(control: CruButton, event: MouseEvent) =
    for item, v in listabtn:
        v.backgroundColor=control.whiter
    control.backgroundColor=control.darker
    if (event.x-control.marg_x<=0 or event.y-control.marg_y<=0 or event.x+control.marg_x>event.control.width or event.y+control.marg_y>event.control.height):
        control.backgroundColor=control.whiter
harrier77 commented 4 months ago

I have just tested in Windows, it works exactly as in Linux without any cpu load problem.

simonkrauter commented 4 months ago

Thanks for the feedback :)

harrier77 commented 4 months ago

By the way, windows seems generally slower. I am making a sort of grid in the same way as I do in a browser using table, tr and td. Thanks to Nigui simplicity I loop trough rows using a horizontal container (as a substitute for "tr") and a custom label (as "td"). The same table made in a browser with javascript is very fast, in Nigui/Gtk/Linux is fast and in Windows win32 is slower. But it has nothing to do with your mouse enter/leave events, it is slower the loop which inserts the customlabels in the containers.