English Amiga Board

English Amiga Board (https://eab.abime.net/index.php)
-   Coders. C/C++ (https://eab.abime.net/forumdisplay.php?f=118)
-   -   Intuition On Click Event? (https://eab.abime.net/showthread.php?t=107774)

Sim085 27 July 2021 20:21

Intuition On Click Event?
 
I have gone through the documentation and cannot understand what I am doing wrong. Hopefully someone can help.

I have a window with a list and a text field. I want the focus to remain always in the text field regardless where the user clicks.

At first I thought of using IDCMP_INTUITICKS event and use ActivateGadget on each tick. However I was never much in love with the idea as this means calling ActivateGadget for the text field even when this is already in focus.

I therefore opted to instead only call ActivateGadget when the list is clicked or when the window is clicked. I thought the easiest way to do this is to listen for the IDCMP_MOUSEBUTTONS event (SELECTDOWN). This does work when clicking on the window, but not when clicking in the window title bar or the list.

So in addition to IDCMP_MOUSEBUTTONS I also listen to IDCMP_GADGETUP. When I receive the event I check if the event is for my list and if so I use ActivateGadget on the text field. This works for this list but ONLY WHEN the list actually has an entry in it. If the list is empty then no IDCMP_GADGETUP event is triggered.

So far I have not found how to capture an on click event on the title bar.

Does anyone have any idea how I can capture an on click event on the title bar and a list (when this is empty)?

thomas 27 July 2021 23:09

Probably the only way to do this is to sub-class STRGCLASS and overload its GM_HANDLEINPUT method. When STRGCLASS decides to let go, change the return value to keep focus.

Thomas Richter 28 July 2021 12:02

In general, I believe it is a bad idea to patronize the user. Thus, if the user decides to click somewhere else, for whatever reason, then the program should rather tolerate that.

Sim085 28 July 2021 16:08

To be honest I only meant to implement this logic in order to save the user from doing some extra clicks.

A clear example is when moving the window. Left as is, the user would move the window and then have to click on the text field to enter some text. What I wanted is that the user would not need to click on the text field after moving the window because he would see the focus is already on this. Same thing as when re-activating a window by clicking anywhere on it, user would need to then need to do another click on the text field to continue using the application.

I know it is sugar candy but thought it would be a nice touch.

Quote:

Originally Posted by Thomas Richter (Post 1498273)
In general, I believe it is a bad idea to patronize the user. Thus, if the user decides to click somewhere else, for whatever reason, then the program should rather tolerate that.


Would I need to use BOOPSI to be able to do this?

Quote:

Originally Posted by thomas (Post 1498204)
Probably the only way to do this is to sub-class STRGCLASS and overload its GM_HANDLEINPUT method. When STRGCLASS decides to let go, change the return value to keep focus.


bebbo 28 July 2021 17:51

Quote:

Originally Posted by Sim085 (Post 1498316)
To be honest I only meant to implement this logic in order to save the user from doing some extra clicks.

A clear example is when moving the window. Left as is, the user would move the window and then have to click on the text field to enter some text. What I wanted is that the user would not need to click on the text field after moving the window because he would see the focus is already on this. Same thing as when re-activating a window by clicking anywhere on it, user would need to then need to do another click on the text field to continue using the application.

I know it is sugar candy but thought it would be a nice touch.

Would I need to use BOOPSI to be able to do this?


As usally - I know nothing - but maybe this helps:


open the input.device
add a handler
that handler checks input events for IECLASS_ACTIVEWINDOW
signal your task or send a msg
...




just guessing^^

Thomas Richter 28 July 2021 18:17

Window activation as IDCMP exists, so there is certainly a possibility to activate a gadget when the user activates the window. That seems to be the most straight-forwared way of doing it. Some care should be taken if there are multiple string gadgets on the same window as then the input focus could potentially change.

A good principle to follow is "principle of least surprise", i.e. don't make any changes that have not been triggered by the user explicitly.

bebbo 28 July 2021 18:26

Quote:

Originally Posted by Thomas Richter (Post 1498337)
Window activation as IDCMP exists, so there is certainly a possibility to activate a gadget when the user activates the window. That seems to be the most straight-forwared way of doing it. Some care should be taken if there are multiple string gadgets on the same window as then the input focus could potentially change.

A good principle to follow is "principle of least surprise", i.e. don't make any changes that have not been triggered by the user explicitly.


maybe someone is able to track the last selected input gadget...

Sim085 30 July 2021 17:17

I managed to achieve that with IDCMP_ACTIVEWINDOW. Now when user focus again on my window it immediately focuses the user on the single text field that I have.

With IDCMP_CHANGEWINDOW I managed to also keep the focus on the single text field when the window is moved. (In the future I should not judge an event by its name, thought this was triggered when user "changed" window).

With the IDCMP_MOUSEBUTTONS I have the click on anywhere on the window not covered by a gadget. Documentation says that this is only issued if not used internally by Intuition so I do not see it as that bad.

The only issue I have is with the list gadget. I cannot understand why when the list has no items it does not trigger the IDCMP_GADGETDOWN even (or IDCMP_GADGETUP).

Quote:

Originally Posted by Thomas Richter (Post 1498337)
Window activation as IDCMP exists, so there is certainly a possibility to activate a gadget when the user activates the window. That seems to be the most straight-forwared way of doing it. Some care should be taken if there are multiple string gadgets on the same window as then the input focus could potentially change.

A good principle to follow is "principle of least surprise", i.e. don't make any changes that have not been triggered by the user explicitly.


bebbo 30 July 2021 18:21

Quote:

Originally Posted by Thomas Richter (Post 1498337)
A good principle to follow is "principle of least surprise"


forward this to the Kickstart developers

Thomas Richter 31 July 2021 09:38

Quote:

Originally Posted by Sim085 (Post 1498645)
The only issue I have is with the list gadget. I cannot understand why when the list has no items it does not trigger the IDCMP_GADGETDOWN even (or IDCMP_GADGETUP).

There is nothing to click on, so why should it register something? IDCMP events are created whenever a gadget changes state, but there is nothing to change here.

Sim085 31 July 2021 13:53

Fair point.

Not sure what I can do to be honest at this point apart from leaving it as is. Other option is to add a dummy entry in the list when it is empty and than handle this case separate as part IDCMP_GADGETUP. Its a hack, but the only thing I can think of :confused

Quote:

Originally Posted by Thomas Richter (Post 1498719)
There is nothing o click on, so why should it register something? IDCMP events are created whenever a gadget changes state, but there is nothing to change here.


bebbo 31 July 2021 15:35

Quote:

Originally Posted by Sim085 (Post 1498735)
Fair point.

Not sure what I can do to be honest at this point apart from leaving it as is. Other option is to add a dummy entry in the list when it is empty and than handle this case separate as part IDCMP_GADGETUP. Its a hack, but the only thing I can think of :confused


try setting the GadgetType to 0 if the list is empty, and restore the type once something is added.

Thomas Richter 31 July 2021 22:55

Quote:

Originally Posted by Sim085 (Post 1498735)
Fair point.

Not sure what I can do to be honest at this point apart from leaving it as is. Other option is to add a dummy entry in the list when it is empty and than handle this case separate as part IDCMP_GADGETUP. Its a hack, but the only thing I can think of :confused


Don't. The problem is that you try to achieve something that is not part of the user interface style the Os offers, so just don't force it. Other programs won't react this way either, so it is not expected to work this way anyhow.

Bruce Abbott 31 July 2021 23:10

Quote:

Originally Posted by Sim085 (Post 1498645)
The only issue I have is with the list gadget. I cannot understand why when the list has no items it does not trigger the IDCMP_GADGETDOWN even (or IDCMP_GADGETUP).

Do you get any messages at all?

Sim085 01 August 2021 00:16

1 Attachment(s)
Hmm.. interesting. I test this by using the following code in the whole loop;
Code:

printf("%x\n", msg->Class);
As expected without touching anything I get the 400000 (IDCMP_INTUITICKS) printed. When I click on the list gadget I get the code f80ad4 printed. However I cannot find any IDCMP event with that code here. I have attached a screenshot.

Quote:

Originally Posted by Bruce Abbott (Post 1498814)
Do you get any messages at all?

I will obviously test how the application feels and if it feels unnatural (or confusing) I would remove this or make it switchable on/off from a configuration file.

Quote:

Originally Posted by Thomas Richter (Post 1498812)
Don't. The problem is that you try to achieve something that is not part of the user interface style the Os offers, so just don't force it. Other programs won't react this way either, so it is not expected to work this way anyhow.


Sim085 01 August 2021 11:02

I did put a condition on event 0x00f80ad4. Works. But not always :(

I am thinking of going to the IDCMP_INTUITICKS path again. However ideally I would like to first check if my search field is already active and only call the ActivateGadget on this field if this is not activated.

But ... :) ... I cannot find any function to do that from here, or a way to achieve this with GT_GetGadgetAttrs as documented here.

bebbo 01 August 2021 15:44

Quote:

Originally Posted by Sim085 (Post 1498861)
I did put a condition on event 0x00f80ad4. Works. But not always :(

I am thinking of going to the IDCMP_INTUITICKS path again. However ideally I would like to first check if my search field is already active and only call the ActivateGadget on this field if this is not activated.

But ... :) ... I cannot find any function to do that from here, or a way to achieve this with GT_GetGadgetAttrs as documented here.


hm:

gad->Flags & GFLG_SELECTED
does not work for you?


You could also call SetGadgetAttrsA with GFLG_SELECTED set...

Thomas Richter 01 August 2021 17:56

Quote:

Originally Posted by Sim085 (Post 1498818)
Code:

printf("%x\n", msg->Class);
As expected without touching anything I get the 400000 (IDCMP_INTUITICKS) printed. When I click on the list gadget I get the code f80ad4 printed.

You are doing something wrong. How exactly do you retreive the message? Note that for gadtools, you need to use GT_GetIMsg(), not GetMsg(). Also, do you check the return code for GetMsg() for NULL? Note that you need to wait for a message to arrive (either Wait() or WaitPort()).

Sim085 01 August 2021 18:44

Yes that worked. I was under the impression that selected would need to be retrieved using GT_GetGadgetAttrs. I see this is a flag however not an attribute.

Quote:

Originally Posted by bebbo (Post 1498920)
hm:
gad->Flags & GFLG_SELECTED
does not work for you?

This is my code;
Code:

/* Main Loop. */   
while(run)    {       

      /* Wait for an event to happen. */       
      int w = Wait(search_onKeyPressSignal | 1L << window->UserPort->mp_SigBit);

      ...

      /* Get message data. */       
      msg = (struct IntuiMessage *)GT_GetIMsg(window->UserPort);

      if(msg->Class == IDCMP_CLOSEWINDOW){ ... }
      ...

      /* Close message. */       
      GT_ReplyIMsg(msg);   
}

I do not check for nulls. I will add that. I suppose without that things might get pretty ugly at some point running the application.

Anything else looks wrong?

The f80ad4 signal is issued multiple times when I hold the mouse left button on the list gadget. But clicking multiple times some times did not trigger an event. Don't know if that helps.

This is why I reverted back to using IDCMP_INTUITICKS. Also something else I noticed is that this event is issued even if I did not register for it.

Quote:

Originally Posted by Thomas Richter (Post 1498946)
You are doing something wrong. How exactly do you retreive the message? Note that for gadtools, you need to use GT_GetIMsg(), not GetMsg(). Also, do you check the return code for GetMsg() for NULL? Note that you need to wait for a message to arrive (either Wait() or WaitPort()).


bebbo 01 August 2021 19:23

Quote:

Originally Posted by Sim085 (Post 1498956)
Yes that worked. I was under the impression that selected would need to be retrieved using GT_GetGadgetAttrs. I see this is a flag however not an attribute.



This is my code;
Code:

/* Main Loop. */   
while(run)    {       

      /* Wait for an event to happen. */       
      int w = Wait(search_onKeyPressSignal | 1L << window->UserPort->mp_SigBit);

      ...

      /* Get message data. */       
      msg = (struct IntuiMessage *)GT_GetIMsg(window->UserPort);

      if(msg->Class == IDCMP_CLOSEWINDOW){ ... }
      ...

      /* Close message. */       
      GT_ReplyIMsg(msg);   
}

I do not check for nulls. I will add that. I suppose without that things might get pretty ugly at some point running the application.

What exactly looks wrong?


looks good.



The most OS friendly way to get a gadget event in empty listviews seems to be setting GTLV_Labels with a one entry list of an empty string.


All times are GMT +2. The time now is 19:35.

Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.

Page generated in 0.08203 seconds with 11 queries