![]() |
|||
Zune Application Development ManualIntroductionWhat is Zune?Zune is an object-oriented GUI toolkit. It is nearly a clone (at both API and Look&Feel level) of MUI, a well-known Amiga shareware product by Stefan Stuntz. So MUI developers will feel at home here; others will discover the concepts and qualities that Zune shares with MUI.
Zune is based on the BOOPSI system, the framework inherited from AmigaOS for object-oriented programming in C. Zune classes don't derive from existing BOOPSI gadget classes; instead, the Notify class (base class of the Zune hierarchy) derives from the BOOPSI root class. PrerequisitesSome knowledge of OO (object-oriented) programming is more than welcome. If not, Google may help you find good introductory papers on this classic subject. Knowing AROS (or AmigaOS) APIs and concepts like taglists and BOOPSI is essential. Having the Amiga Reference Manuals (aka RKM) is very handy. As Zune is a MUI clone, all the documentation pertaining to MUI is applicable to Zune. In particular, the latest available MUI developer kit can be found here. In this LHA archive, 2 documents are warmly recommended:
Additionally, this archive contains MUI autodocs, which are the reference documentations for all Zune classes. BOOPSI PrimerConceptsClassA class is defined by its name, its parent class and a dispatcher.
BOOPSI type for a class is Class * also known as IClass. ObjectAn object is an instance of class: each object has its specific data, but all objects of the same class share the same behavior. An object has several classes if we count the parents of its true class (the most derived one) up to the rootclass. BOOPSI type for an object is Object *. It has no field you can directly access. AttributeAn attribute is related to the instance data of each object: you can't access these data directly, you can only set or get the attributes provided by an object to modify its internal state. An attribute is implemented as a Tag (ULONG value or'ed with TAG_USER). GetAttr() and SetAttrs() are used to modify an object's attributes. Attributes can be one or more of the following:
MethodA BOOPSI method is a function which receives as parameters an object, a class and a message:
To send a message to an object, use DoMethod(). It will use the true class first. If the class implements this method, it will handle it. Else it will try its parent class, until the message is handled or the rootclass is reached (in this case, the unknown message is silently discarded). ExamplesLet's see basic examples of this OOP framework: Getting an attributeWe'll query a MUI String object for its content:
void f(Object *string)
{
IPTR result;
GetAttr(string, MUIA_String_Contents, &result);
printf("String content is: %s\n", (STRPTR)result);
}
Zune applications use more often the get() and XGET() macros instead: get(string, MUIA_String_Contents, &result); result = XGET(string, MUIA_String_Contents); Setting an attributeLet's change the content of our string: SetAttrs(string, MUIA_String_Contents, (IPTR)"hello", TAG_DONE);
You'll find the set() macro useful: set(string, MUIA_String_Contents, (IPTR)"hello"); But it's only with SetAttrs() that you can set several attributes at once:
SetAttrs(string,
MUIA_Disabled, TRUE,
MUIA_String_Contents, (IPTR)"hmmm...",
TAG_DONE);
Calling a methodLet's see the most called method in a Zune program, the event processing method called in your main loop: result = DoMethod(obj, MUIM_Application_NewInput, (IPTR)&sigs);
Hello world
First things first! I knew you would be all excited. SourceLet's study our first real life example:
// gcc hello.c -lmui
#include <exec/types.h>
#include <libraries/mui.h>
#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/muimaster.h>
#include <clib/alib_protos.h>
int main(void)
{
Object *wnd, *app, *but;
// GUI creation
app = ApplicationObject,
SubWindow, wnd = WindowObject,
MUIA_Window_Title, "Hello world!",
WindowContents, VGroup,
Child, TextObject,
MUIA_Text_Contents, "\33cHello world!\nHow are you?",
End,
Child, but = SimpleButton("_Ok"),
End,
End,
End;
if (app != NULL)
{
ULONG sigs = 0;
// Click Close gadget or hit Escape to quit
DoMethod(wnd, MUIM_Notify, MUIA_Window_CloseRequest, TRUE,
(IPTR)app, 2,
MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit);
// Click the button to quit
DoMethod(but, MUIM_Notify, MUIA_Pressed, FALSE,
(IPTR)app, 2,
MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit);
// Open the window
set(wnd, MUIA_Window_Open, TRUE);
// Check that the window opened
if (XGET(wnd, MUIA_Window_Open))
{
// Main loop
while((LONG)DoMethod(app, MUIM_Application_NewInput, (IPTR)&sigs)
!= MUIV_Application_ReturnID_Quit)
{
if (sigs)
{
sigs = Wait(sigs | SIGBREAKF_CTRL_C);
if (sigs & SIGBREAKF_CTRL_C)
break;
}
}
}
// Destroy our application and all its objects
MUI_DisposeObject(app);
}
return 0;
}
RemarksGeneralWe don't manually open libraries, it's done automatically for us. GUI creationWe use a macro-based language to easily build our GUI. A Zune application has always 1 and only 1 Application object: : app = ApplicationObject, An application can have 0, 1 or more Window objects. Most often a single one: : SubWindow, wnd = WindowObject, Be nice, give a title to the window: : MUIA_Window_Title, "Hello world!", A window must have 1 and only 1 child, usually a group. This one is vertical, that means that its children will be arranged vertically: : WindowContents, VGroup, A group must have at least 1 child, here it's just a text: : Child, TextObject, Zune accepts various escape codes (here, to center the text) and newlines: : MUIA_Text_Contents, "\33cHello world!\nHow are you?", An End macro must match every xxxObject macro (here, TextObject): : End, Let's add a second child to our group, a button! With a keyboard shortcut o indicated by an underscore:
: Child, but = SimpleButton("_Ok"),
Finish the group: : End, Finish the window: : End, Finish the application: : End; So, who still needs a GUI builder? :-) Error handlingIf any of the object in the application tree can't be created, Zune destroys all the objects already created and application creation fails. If not, you have a fully working application:
: if (app != NULL)
: {
: ...
When you're done, just call MUI_DisposeObject() on your application object to destroy all the objects currently in the application, and free all the resources: : ... : MUI_DisposeObject(app); : } NotificationsNotifications are the simplest way to react on events. The principle? We want to be notified when a certain attribute of a certain object is set to a certain value: : DoMethod(wnd, MUIM_Notify, MUIA_Window_CloseRequest, TRUE, Here we'll listen to the MUIA_Window_CloseRequest of our Window object and be notified whenever this attribute is set to TRUE. So what happens when a notification is triggered? A message is sent to an object, here we tell our Application to return MUIV_Application_ReturnID_Quit on the next event loop iteration: : (IPTR)app, 2, : MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit); As we can specify anything we want here, we have to tell the number of extra parameters we are supplying to MUIM_Notify: here, 2 parameters. For the button, we listen to its MUIA_Pressed attribute: it's set to FALSE whenever the button is being released (reacting when it's pressed is bad practice, you may want to release the mouse outside of the button to cancel your action - plus we want to see how it looks when it's pressed). The action is the same as the previous, send a message to the application: : DoMethod(but, MUIM_Notify, MUIA_Pressed, FALSE, : (IPTR)app, 2, : MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit); Opening the windowWindows aren't open until you ask them to: : set(wnd, MUIA_Window_Open, TRUE); If all goes well, your window should be displayed at this point. But it can fail! So don't forget to check by querying the attribute, which should be TRUE: : if (XGET(wnd, MUIA_Window_Open)) Main loopLet me introduce you my lil' friend, the ideal Zune event loop: : ULONG sigs = 0; Don't forget to initialize the signals to 0 ... The test of the loop is the MUIM_Application_NewInput method: : ... : while((LONG) DoMethod(app, MUIM_Application_NewInput, (IPTR)&sigs) : != MUIV_Application_ReturnID_Quit) It takes as input the signals of the events it has to process (result from Wait(), or 0), will modify this value to place the signals Zune is waiting for (for the next Wait()) and will return a value. This return value mechanism was historically the only way to react on events, but it was ugly and has been deprecated in favor of custom classes and object-oriented design. The body of the loop is quite empty, we only wait for signals and handle Ctrl-C to break out of the loop:
: {
: if (sigs)
: {
: sigs = Wait(sigs | SIGBREAKF_CTRL_C);
: if (sigs & SIGBREAKF_CTRL_C)
: break;
: }
: }
ConclusionThis program gets you started with Zune, and allows you to toy with GUI design, but not more. CompilingTo compile this simple program with i386-aros-gcc cross-compiler please use this command: i386-aros-gcc -o hello -D__AROS__ hello.c -lmui Notification actionsAs seen in hello.c, you use MUIM_Notify to call a method if a certain condition happens. If you want your application to react in a specific way to events, you can use one of these schemes:
|
Copyright © 1995-2008, L'équipe de développement AROS. Tous droits réservés. Amiga®, AmigaOS®, Workbench et Intuition sont des marques de Amiga Inc. Les autres marques appartiennent à leur propritaires respectifs. |