• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Mouse events & clicking on the UI

Status
Not open for further replies.
Level 6
Joined
Jun 18, 2004
Messages
119
Hey guys,

I'm trying to work with the native Mouse Events, but I've run into a situation where I am unable to differentiate if a click happened on the UI or in the 'world'.

I've tried using the Frame Events, but they don't fire for the big parent UI (only for buttons and portraits, etc).

Has anyone had any luck using
Lua:
TriggerRegisterPlayerEvent(t, Player(i), EVENT_PLAYER_MOUSE_DOWN)
and afterwards checking if the click was on the world/ui?

Cheers,
 
@Tasyen
3uceio-jpg.350780
 
There is not really a clean simple way to do that.

One Idea I had was to place a disabled FRAME above the UI, give it a FRAME as tooltip and check for the tooltip's visiblity. This has some problems: First Tooltips are async, Second There can be a problem with the order and functionality of the tooltip if the other Frames in that section having Tooltips itself.

Another bad one is do the same with Enter / Leave Events they are sync, but again one has the problem of Frame Order and it becomes worese cause now they Frame that handles the enter/Leave event has to be enabled and take the mouse input. That would disable the Frames in the section, that is probably not wanted.

If you UI can not be altered then you could try some PlayableGround 2 Screen transformation math (don't ask me how to do that) and check if the mouse is inside a space that belongs to the UI. Would be simpler; if one has the Mouse On Screen Pos without such transformation. Bad is here that you have to define addtional what coords belong to the UI part.

Maybe don't use the Mouse click event and instead use Order/Selection, both respect when Frames control space on the screen. Most Frames stop orders and selection in the space they own. BUTTON need a setup in fdf to do that.
 
Level 13
Joined
Jun 1, 2008
Messages
360
Thanks alot Tasyen! I was hoping for something easier, but I'll see if I can cook something up with the coordinates. I'm already syncing cameras of players anyway :)
Any luck with this? I noticed that the coordinates are 0,0 on the upper UI, but not on the lower. Seems like a bug/half-way implementation on Bliz side.

I tried with the frames but adding events to existing frames is sysiphus work, not documented and I didn't get it to work (would probably need to spend a whole week on that...). I also didn't get a custom frame to work and even if I would, it would probably introduce other problems.
 
Last edited:
Level 13
Joined
Jun 1, 2008
Messages
360
Sadly, I have just accepted that clicks can happen through the UI. If you manage something, please do share! Otherwise, let's see if blizzard cooks something up!
Hi iNfraNe,
I have experimented around a little more now, using the C# project from Drake (which is really cool btw), and found a solution that is satisfying for me.
The frame stuff still didn't work as expected and has more downsides than advantages for this application, but there is a simple calculation based on the camera height, which solves this.
The following code is in C#, but you can use the same functions in standard triggers.

You probably had something similar already – if you ran into more problems that I don't foresee yet, I'd be glad to get a heads up :)

C#:
public MouseHandler()
{
    //Initialization of trigger events and actions
    var trgDown = CreateTrigger();
    var trgUp = CreateTrigger();
    var trgSyncRead = CreateTrigger();
    foreach (var p in PlayerInfo.Players)
    {
        TriggerRegisterPlayerEvent(trgDown, p.BlzPlayer, EVENT_PLAYER_MOUSE_DOWN);
        TriggerRegisterPlayerEvent(trgUp, p.BlzPlayer, EVENT_PLAYER_MOUSE_UP);
        BlzTriggerRegisterPlayerSyncEvent(trgSyncRead, p.BlzPlayer, "SyncCamX", false);
        BlzTriggerRegisterPlayerSyncEvent(trgSyncRead, p.BlzPlayer, "SyncCamY", false);
        BlzTriggerRegisterPlayerSyncEvent(trgSyncRead, p.BlzPlayer, "SyncCamZ", false);
    }
    TriggerAddAction(trgDown, PlayerMouseDown);
    TriggerAddAction(trgUp, PlayerMouseUp);
    TriggerAddAction(trgSyncRead, SyncCamDataRead);
    TimerStart(CreateTimer(), 0.1f, true, SyncCamDataSend);
}

public void SyncCamDataSend()
{
 
    //This sends the current camera position of each player to the others to sync it
    //Note: I didn't test it in a multiplayer game yet.
    //Thx Tasyen https://www.hiveworkshop.com/threads/target-of-current-camera-desync.316384/#post-3355262
    BlzSendSyncData("SyncCamX", R2S(GetCameraTargetPositionX()));
    BlzSendSyncData("SyncCamY", R2S(GetCameraTargetPositionY()));
    BlzSendSyncData("SyncCamZ", R2S(GetCameraEyePositionZ()));
}

public void SyncCamDataRead()
{
    //This saves the current camera position of each player in float variables (CamXSynced, ...)
    var p = GetTriggerPlayer();
    int pid = GetPlayerId(p);
    string prefix = BlzGetTriggerSyncPrefix();
    if (prefix == "SyncCamX")
    {
        CamXSynced[pid] = S2R(BlzGetTriggerSyncData());
    }
    else if (prefix == "SyncCamY")
    {
        CamYSynced[pid] = S2R(BlzGetTriggerSyncData());
    }
    else if (prefix == "SyncCamZ")
    {
        CamZSynced[pid] = S2R(BlzGetTriggerSyncData());
    }
}

public bool WithinCurrentCamView(int pid, float x, float y)
{
    //This function is called on click. x and y are the coordinates of the mouse click. Returns true if click is in current view.
    //Note: If your top/bottom UI is larger or smaller, you can just change the values 0.317 and 0.5 below.
    float dx = x - CamXSynced[pid];
    float dy = y - CamYSynced[pid];
    //For the default camera angle on a 16:10 screen with cliff level 2, for a camera ...
    //... with height 1000, the y-range is [-317, 445]
    //... with height 2000, the y-range is [-645, 990] - so just linear/proportional.
    //In x-direction the range is the same in both directions, obviously.
    //Let's just use 0.9, which will cover all aspect ratios (except maybe ultra-wide).
    return dx > -0.9f * CamZSynced[pid] && dx < 0.9f * CamZSynced[pid] && dy > -0.317f * CamZSynced[pid] && dy < 0.5f * CamZSynced[pid];
}
 
Last edited:
Status
Not open for further replies.
Top