Blitz:Events

From Amiga Coding
Revision as of 12:33, 17 September 2015 by Daedalus (talk | contribs) (Mouse Click)
Jump to: navigation, search

Intuition uses an event system to notify programs of any GUI actions they need to be aware of, such as a gadget being clicked or a menu item being selected. These notifications are passed to programs as a message, which the program then decodes and decides what to do based on the message. Blitz decodes these messages for you and provides some simple commands for figuring out what happened so your program can respond.

Typically, once the interface is set up, the program flow for dealing with events will be something like this:

  • Wait for an event message to arrive
  • Check the event flags
  • Check the individual item that caused the event
  • Carry out the desired action
  • Repeat

Event Flags

Events are identified by special values called IDCMP flags, which are defined by the operating system. Each flag corresponds to a type of event, e.g. menu selected, close gadget clicked, key pressed. All the flags are defined in the Intuition Autodocs, however a window will only report the flags it has been set up to look for. All the common flags are configured for windows in Blitz by default, and the list of flags reported by a window can be modified if required by your program. Many of the Blitz Basic example programs use the actual values of the flags to check for events. The use of constants is advisable however, and will make your code easier to follow later on. The Intuition contents are defined in the amigalibs.res resident file, which can be added to the Resident Files list in the Complier Settings window to include it in your code. Don't forget to add a hash symbol (#) before the constant name from the Autodocs to make it a valid Blitz constant! For example, the C constant IDCMP_MENUPICK becomes #IDCMP_MENUPICK.

Reading Events

Events are entered into a queue automatically by Intuition. Two commands are used to read the first event flag from the queue: Event and WaitEvent. Event checks the queue and returns the flag of the first event waiting. If there are no events waiting (i.e. nothing happened), Event will return 0. WaitEvent works similarly, except program flow will stop until an event does occur.

WaitEvent has the advantage that your program sleeps while it waits and uses no CPU time, and is the preferred method for handling GUI input from the user. The disadvantage is that your program can't do anything else while it waits, so if you need to do something without user interaction (for example animation or enemy movements), use Event instead.

Event flags are long values, so always use a long variable for storing the result of Event or WaitEvent!

Example usage: ev.l = Event If ev

 NPrint "Event flag: ", ev

Else

 NPrint "No event in queue"

End If ev.l = WaitEvent NPrint "Event flag: ", ev


Identifying the Event

Once you see the type of event you want to deal with, you need to decide what to do. For gadgets and menus, you need to identify the individual item that triggered the event since the IDCMP flag just says "a gadget was clicked". This is done differently depending on the type of event.

Gadget Clicked

If the event flag corresponds to a gadget being clicked or released, the GadgetHit function returns the ID code of the gadget affected. For example: gh = GadgetHit Select gh

 Case 0
   NPrint "Cancel gadget clicked!"
 Case 1
   NPrint "Continue gadget clicked!"

End Select

Again, many of the old Blitz examples use "magic numbers" for gadget IDs, but your code will be much more readable if you use constants instead. These should be defined in your code before they're used. Reworking the above example: gh = GadgetHit Select gh

 Case #cancel
   NPrint "Cancel gadget clicked!"
 Case #continue
   NPrint "Continue gadget clicked!"

End Select

Menu Item Selected

If the event flag corresponds to a menu item being selected, the MenuHit, ItemHit and SubHit commands return the ID of the menu, item, and subitem (if relevant) respectively. Since menu positions are defined by their ID number, this means that MenuHit returns 0 for the first menu, 1 for the second and so on. Similarly, ItemHit will return 0 for the first item in the chosen menu, 1 for the second, and the same for SubHit. Constants are still recommended for identifying menu items of course. As well as making your code easier to read, constants will also make it much easier to rearrange the menu items later on without having to search your code to update the values. Example code: Select MenuHit

 Case #menu_project
   Select ItemHit
     Case #menu_about
       Gosub about
     Case #menu_quit
       quit = true
   End Select
 Case #menu_settings
   Select ItemHit
     Case #menu_size
       Select SubHit
         Case #menu_small
           size = 1
         Case #menu_large
           size = 5
       End Select
       Gosub resize
     Case #menu_savesettings
       savesettings{}
   End Select
 End Select

End Select

Mouse Click

The mouse click event will be generated whenever the user clicks on a part of the window that doesn't generate any other event, i.e. isn't a gadget. This event value is #IDCMP_MOUSEBUTTONS, and will be reported whenever the left button is clicked and released. It will also report the middle button if present, and the right button, but only when menus are disabled.

For a mouse click event, the event code generated will reflect the button action that triggered the event, and will be one of the following values:

Event Code Meaning
#SELECTDOWN Left mouse button pressed
#SELECTUP Left mouse button released
#MIDDLEDOWN Middle mouse button pressed
#MIDDLEUP Middle mouse button released
#MENUDOWN Right mouse button pressed
#MENUUP Right mouse button released

Other Event Types

There are a number of other event types that can be detected, some with specific commands for reading the particular properties of the event. They all work in pretty much the same way, so once you understand the events in these examples you should be easily able to implement others. See the Windows section of the Blitz Basic 2 Manual for more details.

Full Event Example

This example code includes the menu example code above, as well as a couple of other IDCMP flags. It also defines the constants required, but the window/GUI setup code, procedures and subroutines are obviously missing. The #IDCMP constants are all included in the amigalibs.res resident file.

Gadget IDs
  1. cancel = 0
  2. continue = 1


Menu constants. These values determine the order of the items in question, starting at 0 for the first.
  1. menu_project = 0 ; First menu title
 #menu_openproject  = 0 ; First item in Project menu
 #menu_about        = 1 ; Second item in Project menu
 #menu_quit         = 2 ; Third item in Project menu
  1. menu_settings = 1 ; Second menu title
 #menu_size         = 0 ; First item in Settings menu
   #menu_small      = 0 ; First sub-item
   #menu_large      = 1 ; Second sub-item
 #menu_opensettings = 1 ; Second item in Settings menu
 #menu_savesettings = 2 ; Third item in Settings menu


Put window and GUI set up code here

Repeat

 ev.l = WaitEvent           ; Long variable required
 NPrint "Event flag: ", ev
 Select ev
   Case #IDCMP_GADGETUP     ; *** Gadget has been clicked (and released)
     gh = GadgetHit
     Select gh
       Case #cancel
         NPrint "Cancel gadget clicked!"
         quit = True
       Case #continue
         NPrint "Continue gadget clicked!"
     End Select


   Case #IDCMP_MENUPICK             ; *** Menu item has been selected
     Select MenuHit
       Case #menu_project           ; Item was in Project menu
         Select ItemHit
           Case #menu_openproject   ; Item was Open Project
             Gosub loadproject
           Case #menu_about         ; Item was About
             Gosub about
           Case #menu_quit          ; Item was Quit
             quit = true
         End Select
       Case #menu_settings          ; Item was in Settings menu
         Select ItemHit
           Case #menu_size          ; Item was in Size submenu
             Select SubHit          ; This menu item has sub items, so check which one was selected
               Case #menu_small     ; Small subitem selected
                 size = 1
               Case #menu_large     ; Large subitem selected
                 size = 5
             End Select
             Gosub resize           ; This subroutine is called regardless of which size was selected
           Case #menu_opensettings  ; Open settings window selected
             Gosub opensettings
           Case #menu_savesettings  ; Save settings selected
             savesettings{}
         End Select
     End Select


   Case #IDCMP_NEWSIZE              ; *** Window has been resized
     Gosub redrawwindow


   Case #IDCMP_CLOSEWINDOW          ; *** Window's close gadget was clicked
     quit = True
 End Select

Until quit End