DESCRIPTION: The GUI API extension provides you with an easy means to develop complex and dynamic interfaces, advanced event handling, and a completely new way to design and organize your code.
GM VERSION: 8.1 (Possibly compliant with earlier versions, but not sure)
REGISTERED: YES (requires PRO)
FILE TYPE: .zip
FILE LINK: http://www.upurload....7942352cc76.zip
***CREDIT must be given to iam1me if used. However, you are completely free to use, modify, extend, and redistribute (requiring due credit be given to me) this code as you like.***
- A bug was fixed involving the use of sprites
- A small memory leak was fixed
- Labels have been added to the GUI API
For the past couple of weeks I have been working on a GUI API using pure GML. My inspiration for this extension comes both from my programming background, especially with Java, and the fact that I am using GM for a semester long project and so I needed to have a strong, organized, and flexible code base from which to build upon. I suspect that the people who will be most inclined to use this extension are my fellow programmers - and it will also benefit those who want to move from GM to other languages, especially Java.
Now, there are many Widget extensions available that provide you with things like menus, text boxes, fancy buttons, etc. The GUI API, however, is a bit different. This extension (currently) provides the following: panels, layout managers, advanced (& custom) event handling, and essentially a whole new way of designing and organizing your code. Of course, widgets are an essential part of any GUI, and so these will be added in as I have time and if I see that people are interested. I maybe incorporating BBGaming's Game Widgets extension, modified for this API, in a later release. Ultimately, I plan on releasing this as a GEX - but for now at least I will leave it as a Script extension. Unfortunately, when I exported the scripts it removed all of my folders... but its still fairly organized due to a consistent naming convention.
The zip file contains a few different files: GUI_API.gml, GUI_API_CONSTANTS.txt, GA_example.gm81, GA_example.exe, and screen_shot_example.png. The names should be fairly self-explanatory. When using the GUI_API, you must import both the GUI_API.gml file as well as the GUI_API_CONSTANTS.txt file. You must also make sure to call the script include_GUI_API() somewhere in your code BEFORE attempting to use anything else in the extension.
The GUI_Object is the base object for all of the extensions GUI instances. It routes all of the local event handling to appropriate scripts such that each instance is automatically synced with the advanced event handling system provided by the GUI API. The user of this GUI_API should NOT change or add events to the GUI_Object - rather they should use the event handling system which I will describe below. Nor, for that matter should you inherit from this instance - rather create an instance of it and make changes only to the instance.
A new GUI_Object should be created using the script: GA_object_create(x,y,width,height). This script will return the id of a new instance of the GUI_Object. If you would like to specify a draw script, there is a draw_script variable for each GUI_Object which you are free to set - but do NOT clear or add an event script using object_event_add.
If a change is made to your instance which would cause a visual difference and has been added to a panel, call GA_object_invalidate(GUI_Object id) in order to invalidate the object and its parents so that they will be redrawn.
A GUI_Object can very easily be setup to only draw itself in certain views, if views are enabled. Simply call the GA_object_set_views(GUI_Object id, view flags); to specify which views it should draw itself under. By default it will draw itself under view zero. The script accepts an integer, and it uses the first 8 bits to represent each of the 8 views. The constants file contains constants such as VIEW_0, VIEW_1, VIEW_2, etc. Use these as your parameter. If you want to use multiple views for a single GUI_Object, simply OR them together. For instance, if I wanted my GUI_Object called example to be drawn in views 3 & 7, I would write: GA_object_set_views(example, VIEW_3 | VIEW_7). This can be used to easily make a Heads Up Display!!!
LABELS (As of Version 1.05)
Most GUIs require the use of labels, of text. Sometimes a sprite can suffice, but not if that text needs to change throughout the game, like a life/score counter. You can easily create a label by using the GA_label_create(text,font id) command. You can customize a label by settings its various properties: autoresize, color, bgcolor, font, and text. You can set these using commands like GA_label_set_color(label id, color) or GA_label_set_font(label id, font id). Remember that, for font, -1 defaults to 12pt Arial.
A panel is a GUI_Object with some added variables and functionality. A panel is a special GUI_Object which can contain other GUI_Objects, and arrange them using a Layout. To create a new panel use the GA_panel_create() script. Do not place anything apart from GUI_Objects into a panel. You may place panels within panels.
Instances that are inserted into a panel will be clipped in so far as they exceed the visual boundaries of the panel. Instances will also no longer draw themselves, rather the panel will draw them as need be. The GUI_API takes advantage of surfaces in order to limit the amount of drawing done every frame. A panel will only redraw itself and its children if it becomes invalidated. Note: if a child becomes invalidated it will invalidate its parent.
Note: since a panel controls the drawing of its children, only the panels view settings will be taken into account. Thus if the panel is setup to be drawn in view 0, but a child is setup to be drawn in view 1, the child will be drawn in view 0 and nothing will be drawn in view 1.
Panels provide coding organization. When a panel is destroyed, it destroys all of its children. This limits how many instance ids you need to keep track of. Of course, if you don't want one destroyed, you can always remove it from the panel before hand.
To add an item use the GA_panel_child_add(panel id, child id) script, and to remove an item use the GA_panel_child_remove(panel id, child id) script.
More importantly, panels provide visual organization using Layouts. Layouts automatically organize a panels children based upon various settings. Layouts are dynamic: they organize the children of a panel as they are added/removed/etc. The GUI API currently provides two Layouts: the FlowLayout & StackLayout.
To set a layout to a panel, use the GA_panel_set_layout(panel id, layout id) script.
The Flow Layout arranges a panels children on row first basis. By default, the flow layout will arrange children going from left to right, top to bottom, and left aligned. When one row is filled, it goes to the next row. To create a new flow layout, use the GA_layout_flow_create() script.
You can customize the flow layout by using such scripts as GA_layout_flow_set_valign(layout id, valign value) & GA_layout_flow_set_hgap(layout id, horizontal gap in pixels). You can set the following settings: halign, valign, hdir, vdir, hgap, and vgap.
For halign use the constants: LEFT, CENTER, RIGHT. For valign use: TOP, CENTER, BOTTOM. For hdir use : LEFT_TO_RIGHT & RIGHT_TO_LEFT. For vdir use: TOP_TO_BOTTOM & BOTTOM_TO_TOP.
hgap can be any number (should be positive) and represents the # of pixels between any two items horizontally. vgap is very similar but represents the # of pixels between rows vertically.
The Stack Layout is very similar to the Flow Layout, but inversed. The Stack Layout lays out items column first. By default it lays out items going from the top down, left to right, top-left aligned. It has all the same variables and settings as the Flow Layout, though they are implemented slightly differently. To create a new stack layout, use the GA_layout_stack_create() script.
By placing panels inside of panels and giving each panel different layouts, you can achieve many different visual affects.
In the example file included in the .zip, I combine the flow and stack layouts in order to vertically and horizontally center 3 panels of different colors and size.
ADVANCED EVENT HANDLING
This will perhaps be the biggest attraction for my GUI API. The event handling provided by GML is extremely limiting: they aren't dynamic, they must be assigned to objects rather than instances, and only one instance can listen to any given event (apart from global events). You are also extremely limited in writing custom events. My GUI API breaks all of these barriers, and it doesn't use up any of your 15 custom user events.
In order for an instance to fire events, and have other instances listen for these events, it must have a variable called event_listeners which holds the id of a valid ds_map.
In order to add a listener to an event, call GA_event_add_listener(source id, event id, listener id, script id). The Source is the instance that fires the event, the event id is a number that uniquely identifies the event (example: ev_left_button), the listener id is the id of an instance that is responding to the event, and script id is the id of a script to run when the event is fired. When the event is fired, the scope will be set to the listener before running the script. Any number of listeners can be added to any event, though each listener can only have one script per event per source.
While the event id you specify can be any of the built in event constants, it can also be a custom id for a custom event. Just make sure that your event ids don't overlap with the built in event types or the GUI_APIs constants. I suggest starting off custom event ids at 2000.
An event can then be fired using the GA_event_fire(source id, event id, event_args id) script. Event_args should be an instance of the EventArgs Object, which you can create by calling GA_event_args_create(source id, event id). When an event is fired, the event args is put onto a global event stack. This allows listening scripts to grab data about an event. This also allows you to provide as much information as you need about an event, by adding local variables to the event args instance. In order to grab the latest event args instance, use GA_event_get_args(); Make sure that after you call the fire function, that you then delete the event_args instance.
Within the GUI_API, I use this to provide a few different custom events: ev_layout_modified, ev_child_added, and ev_child_removed.
Even if you don't use any of the rest of the GUI_API, you can use this in isolation of the rest.
Please tell me what you think. Will you use it? How would you like to see it improved? Any bugs?
Edited by iam1me, 22 February 2012 - 02:03 PM.