The best way to get to know PhAB is to use it. This chapter provides hands-on sessions to give you a jump start on creating applications:
We'll take a closer look at using PhAB in the chapters that follow.
The first two tutorials cover the basics: creating widgets, changing how widgets look and behave, generating code, running your application, and so on.
The remaining tutorials go beyond the basics to show you how to create working menus, dialogs, and windows. When you've completed these tutorials, you'll be ready to start building almost any Photon application.
Launch PhAB from the Desktop Manager by clicking on its icon:
Before you start the tutorials, take a moment to make yourself familiar with PhAB's user interface:
Overview of PhAB's user interface.
If you wish to identify any icon in the widget bar by name, just pause the mouse pointer on that icon.
If you close the Control Panel, you can redisplay it by selecting Control Panel from the View menu.
In this tutorial you learn how to use PhAB to create and compile a simple application.
PhAB automatically does the following:
The widget now displays "Hello World":
From the File menu, choose Save As to open the Application Selector dialog. Click on the Application Name field, type tut1, then press Enter or click on Save Application.
Now that you've saved your application, you're ready to generate, compile, and execute it.
Wait for the generation process to complete, then click on Done to close the dialog.
Congratulations! You've just created your first Photon application using PhAB.
For more info on compiling, running, and debugging an application, see the section "Making and running your application" in the Generating, Compiling, & Running Code chapter.
This tutorial introduces you to PhAB's resource editors, which let you change how widgets look and behave. You'll find out how to edit virtually any kind of resource a widget may have, including:
In this tutorial, you'll be asked to select various resources in the Control Panel. If you don't see a resource, resize the Control Panel and/or use its scrollbar. |
Let's now edit a numerical resource-the button's border width.
This editor lets you change the value of any numerical widget resource.
Or
Let's change the font of the button's text:
This editor lets you change the text font of any widget that has text.
The button now displays the new font.
Now let's change the button's horizontal text alignment:
This editor serves a dual purpose in PhAB:
Let's now use the flag/option editor to set one of the widget's flags:
A flags resource isn't exclusive, so this time you can use the editor to select multiple options, if desired.
Let's change a color resource-the button's fill color.
This editor lets you edit any color resource. It provides several preset base colors, which should work well with all graphic drivers, and 48 customizable colors for drivers that support 256 or more colors.
If you'd like to experiment with the Hue/Saturation/Brightness (HSB) color model, click on the HSB Model button.
Let's now use the pixmap editor to edit a PtBitmap widget. This editor is called "pixmap" instead of "bitmap" since it lets you edit many types of image resources besides bitmaps.
A PtBitmap widget can be used as a button, or as a static graphic- which is what we'll create here.
If you don't see this widget, add it to the widget bar. To do this, choose the Customize Widget Bar item from the Options menu. You'll see a dialog that lets you add the widget. For more info, see "Widget bar" section in the PhAB Environment chapter. |
Feel free to try the other drawing tools.
Next, we'll edit a multiline text resource-the text of a PtMultiText widget.
Mary hadEnter
aEnter
little lamb.Enter
Let's now create a PtList widget and add text to the widget using the list editor. This editor lets you add and edit text for any widget that provides a list of text items.
If you don't see this widget, add it to the widget bar. To do this, choose the Customize Widget Bar item from the Options menu. You'll see a dialog that lets you add the widget. For more info, see "Widget bar" section in the PhAB Environment chapter. |
Click on Insert After to place this new item after the previous item.
If you wish to save this application, follow the steps from the first tutorial to save the application as tut2. After saving, feel free to generate, make, and run the application.
You now know the basics of editing any widget resource in PhAB. For more information, see the following sections in the Editing Resources and Callbacks in PhAB chapter:
To edit: | See this section: |
---|---|
Bitmaps or images | Pixmap editor |
Colors | Color editor |
Flags | Flag/option editor |
Fonts | Font editor |
Lists of text items | List editor |
Numbers | Number editor or Flag/option editor |
Single-line text strings | Text editor |
Multiline text strings | Multiline text editor |
In this tutorial you'll learn how to set up a link callback, one of the key components of PhAB. To understand what a link callback is, let's start with some background info on widget callbacks.
Almost all widgets support a variety of callbacks. These callbacks enable your application's interface to interact with your application code. For example, let's say you want your application to perform an action when the user clicks on a button. In that case, you would attach a callback function to the button's "Activate" callback.
In a typical windowing environment, you can attach only code functions to widget callbacks. But whenever you use PhAB to create a callback, you can go one step further and attach entire windows, dialogs, menus, and much more. It's this extended functionality that we call a link callback.
PhAB provides two basic types of link callbacks:
To access a widget from your application code, you must first give the widget an instance name. Since all widget instance names reside in the same global namespace, no two widgets within an application can have the same instance name.
We recommend that you start every instance name with a module prefix. For example, if your base window has a PtButton widget that contains the label text "Blue," you could give this widget an instance name of base_blue.
To learn about using link callbacks, let's create two functioning menus-File and Help-that you can later incorporate into your own applications.
In PhAB, menus are built in two pieces:
Using link callbacks, you'll link the menu modules to the File and Help buttons in a menubar. You'll also link a code-type callback to the Quit menu item in the File menu module. This callback will enable the Quit item to close the application.
The menubar grows and shrinks as you change the width of the window, and it always stays at the top of the window. You can see this by clicking in the titlebar of the window, then resizing the window by dragging on one of its resize handles.
If you accidentally click on the Test tab, the window won't resize or accept new widgets. If this happens, just click on the Wind tab. |
By the time you're finished the following steps, the menubar will look like this:
Now that you have menu buttons, you need to create your menu modules. Let's start with the File menu.
You'll see the menu module appear in your work area and the module's name in the module selector's scrolling list.
Let's now add the following menu items to the File menu:
If you click on another module, the menu module will become deselected, which means you won't be able to work on it. To reselect the menu module, click on its titlebar. |
If you look at the Menu Items list, you'll see that the <NEW> item is selected. This special item lets you add new menu items to the menu.
Using what you just learned about creating a menu module, do the following:
If one of your menu modules seems to "disappear" (you may have accidentally closed it or placed it behind another module), it's easy to bring the module back into view. See the " Finding lost modules and icons" in the Working with Modules chapter. |
Let's return to the menu buttons you created earlier and attach link callbacks so that the buttons can pop up your menu modules.
Click on Arm to bring up the callback editor.
You can also select filemenu from a popup list of available modules. To bring up the list, click on the icon to the right of the Name field.
Let's now attach a code-type link callback to the File menu's Quit item so that it can terminate the application.
The function should have a meaningful name. So type quit in the Function field.
You'll now generate the code for your application and edit a generated code stub so that the Quit item will cause your application to exit.
Scroll through the list until you see the quit.c file. This is the generic code template that PhAB generated for your quit() function.
int quit( PtWidget_t *widget, ApInfo_t *apinfo, PtCallbackInfo_t *cbinfo ) { /* eliminate 'unreferenced' warnings */ widget = widget, apinfo = apinfo, cbinfo = cbinfo; exit( EXIT_SUCCESS ); /* This statement won't be reached, but it will keep the compiler happy. */ return( Pt_CONTINUE ); }
For more info on: | See the section: | In the chapter: |
---|---|---|
Widget callbacks | Callbacks | Editing Resources and Callbacks in PhAB |
Editing callbacks | Editing Resources and Callbacks in PhAB | |
Instance names | Instance names | Creating Widgets in PhAB |
Menu modules | Menu modules | Working with Modules |
This tutorial uses the application you created in Tutorial 3. |
This tutorial provides a good example of how you can use setup code to modify a widget's resources before the widget appears onscreen.
In this tutorial, you will:
Dialog modules are designed to let you obtain additional information from the user. Typically, you use this information to carry out a particular command or task.
Since you don't usually need to get the same information twice, dialogs are single-instance modules. That is, you can't realize the same dialog more than once at the same time. If you try create a second instance of a dialog, PhAB simply brings the existing dialog to the front and gives it focus.
If you need to create a window that supports multiple instances, use a window module. You'll learn about window modules in the next tutorial.
To make it easier for you to access widgets from within your application code, PhAB generates a global variable and a manifest. Both of these are based on the widget's instance name.
The global variable, which has the prefix "ABN," represents the widget's name. The manifest, which has the prefix "ABW," represents the widget's instance pointer.
The value of a widget's ABN_... variable is unique only in the module that contains the widget. The variables for widgets in other modules might have the same value. |
For example, let's say you have a widget named about_version. PhAB will use this name to generate a global variable named ABN_about_version and a manifest named ABW_about_version.
In this tutorial you'll learn how to use these generated names.
Using this function, we'll change the content of a label widget within the dialog to display a version number.
Your callback information should now look like this:
You'll see the new dialog in the work area. You'll also see the new callback in the Callbacks list in the callback editor.
Later, you'll fill in the aboutdlg_setup() function so that it changes the blank text of this label to display a version number.
You'll see the Align Widgets dialog.
You'll see that the two labels and the button are now centered horizontally within your dialog.
Your aboutdlg module should now look like this:
Now let's add a callback to the Done button so that the dialog closes when the user clicks on the button.
Selecting the Done code type tells the widget to perform a "Done" operation when the widget is activated. That is, the widget will call the function specified in the Function field (if one is specified) and then close the dialog module.
You'll now modify the generated aboutdlg_setup() function so that it changes the text of the about_version label to show a version number.
Change the code from:
int aboutdlg_setup( PtWidget_t *link_instance, ApInfo_t *apinfo, PtCallbackInfo_t *cbinfo ) { /* eliminate 'unreferenced' warnings */ link_instance = link_instance, apinfo = apinfo, cbinfo = cbinfo; return( Pt_CONTINUE ); }
to the following:
int aboutdlg_setup( PtWidget_t *link_instance, ApInfo_t *apinfo, PtCallbackInfo_t *cbinfo ) { PtArg_t args[1]; /* eliminate 'unreferenced' warnings */ link_instance = link_instance, apinfo = apinfo, cbinfo = cbinfo; PtSetArg(&args[0], Pt_ARG_TEXT_STRING, "1.00", 0); PtSetResources(ABW_about_version, 1, args); return( Pt_CONTINUE ); }
The code is placing the version number (1.00) into the text string resource for the about_version widget. To do this, the code:
We can use this manifest safely since we're dealing with a dialog module-PhAB ensures that only one instance of the dialog will exist at any given time.
You're now ready to compile and run the program:
For more info on: | See the section: | In the chapter: |
---|---|---|
Using dialogs | Dialog modules | Working with Modules |
Instance names | Instance names | Creating Widgets in PhAB |
Variables and manifests | Working with Code | |
Callbacks | Callbacks | Editing Resources and Callbacks in PhAB |
Code-callback functions | Working with Code | |
Generating code | Making and running your application | Generating, Compiling, & Running Code |
This tutorial uses the application you created in Tutorial 4. |
In the previous tutorial, you learned how to handle dialog modules, which support just one instance. In this tutorial you'll learn how to handle window modules, which support multiple instances.
By supporting multiple instances, window modules provide more flexibility than dialogs. But to take advantage of this flexibility, you must keep track of each window's instance pointer. Doing so ensures that you correctly reference the widgets within each instance of a window. You can't safely use the generated global ABW_xxx manifest since it refers only to the last instance created.
To simplify the task of working with multiple instances, PhAB provides API library functions that let you access any widget by means of its global variable name (ABN_xxx).
To start, let's create a window module and attach it to the New menu item in the File menu in tut4. This window will contain buttons that change the color of another widget.
In the previous tutorial, you created a dialog module from within the callback editor. But this time you'll use the module selector to create the module you want. In the future, use whatever method you prefer.
When PhAB prompts you to create the window, click on Yes.
Because a window module supports multiple instances, you have to create code functions that will be called whenever the window opens or closes (i.e. whenever the window is created or destroyed). So let's first set up a callback to detect when the window closes:
Click on Apply, then on Done.
This flag tells the Window Manager to notify your application when the window is closed.
Open the filemenu menu module, then select the Menu Items resource in the Control Panel. You'll see the menu editor.
Let's now add some widgets to the newwin window module. Using these widgets, you'll learn how to update information in the current or other instances of a window module.
Your window should now look something like this:
In the last tutorial, you used the generated ABW_xxx manifest to access a dialog's instance pointer. You can't use this manifest when dealing with multiple instances of a window module since it refers only to the last window created. Instead, you have to add code to the generated window-setup function so that it stores a copy of each window-instance pointer in a global widget array. In this tutorial, you'll need these pointers for the "Change Previous Window Color" button to work.
Open the Build & Run dialog and regenerate the code.
Now let's modify the newwin_setup() function so that it:
Edit the newwin_setup.c file as follows:
int win_ctr = 0; PtWidget_t *win[5]; int newwin_setup( PtWidget_t *link_instance, ApInfo_t *apinfo, PtCallbackInfo_t *cbinfo ) { PtArg_t args[1]; char buffer[40]; /* eliminate 'unreferenced' warnings */ apinfo = apinfo, cbinfo = cbinfo; // Note: Returning Pt_END in a prerealize setup // function will tell PhAB to destroy the // module without realizing it /* allow only 5 windows max */ if ( win_ctr == 5 ) { return( Pt_END ); } /* save window-module instance pointer */ win[win_ctr] = link_instance; sprintf( buffer, "Window %d", win_ctr + 1 ); PtSetArg( &args[0], Pt_ARG_WINDOW_TITLE, buffer, 0 ); PtSetResources( win[win_ctr], 1, args ); win_ctr++; return( Pt_CONTINUE ); }
Now let's modify the color_change() function so that:
If this were a dialog module you could use the ABW_color_rect manifest to update the color of the rectangle. However, because these are window modules, you must use the instance pointer for the window in which the button is being pressed.
To get the instance pointer, you need to call the ApGetWidgetPtr() and ApGetInstance() functions with the instance pointer of the selected widget and the global variable name ABN_color_rect.
If only one instance of the window were guaranteed, the following would work:
PtSetResources( ABW_color_rect, 1, args );
But in this case color_change() has to use:
PtSetResources( ApGetWidgetPtr( ApGetInstance( widget ), ABN_color_rect ), 1, args );
So you need to change color_change.c to look like:
PgColor_t colors[5] = {Pg_BLACK, Pg_YELLOW, Pg_MAGENTA, Pg_CYAN, Pg_DGREEN}; int base_clr = -1; extern int win_ctr; extern PtWidget_t *win[5]; int color_change( PtWidget_t *widget, ApInfo_t *apinfo, PtCallbackInfo_t *cbinfo ) { int i, prev; PtArg_t args[1]; /* eliminate 'unreferenced' warnings */ widget = widget, apinfo = apinfo, cbinfo = cbinfo; if ( ApName( widget ) == ABN_btn_red ) { PtSetArg( &args[0], Pt_ARG_FILL_COLOR, Pg_RED, 0 ); } else if ( ApName( widget ) == ABN_btn_green ) { PtSetArg( &args[0], Pt_ARG_FILL_COLOR, Pg_GREEN, 0 ); } else if ( ApName( widget ) == ABN_btn_blue ) { PtSetArg( &args[0], Pt_ARG_FILL_COLOR, Pg_BLUE, 0 ); } else if ( ApName( widget ) == ABN_btn_prev ) { // Note: Here we use the window-module instance // pointers saved in newwin_setup to update // the window previous to the current window // provided it hasn't been closed. /* determine which window * is previous to this window */ prev = -1; for ( i = 0; i < win_ctr; i++ ) { if ( win[i] == ApGetInstance( widget ) ) { prev = i - 1; break; } } /* if window still exists,update its background color */ if ( prev != -1 && win[prev] ) { base_clr++; if (base_clr >= 5) { base_clr = 0; } PtSetArg( &args[0], Pt_ARG_FILL_COLOR, colors[base_clr], 0 ); PtSetResources( win[prev], 1, args ); } return( Pt_CONTINUE ); } PtSetResources( ApGetWidgetPtr( ApGetInstance( widget ), ABN_color_rect ), 1, args ); return( Pt_CONTINUE ); }
Last of all, you need to modify newwin_close() so that it sets the win array of instance pointers to NULL for a window when it's closed. That way, you can check for NULL in the win array to determine whether the window still exists.
Modify newwin_close.c as follows:
extern int win_ctr; extern PtWidget_t *win[5]; int newwin_close( PtWidget_t *widget, ApInfo_t *apinfo, PtCallbackInfo_t *cbinfo ) { PhWindowEvent_t *we = cbinfo->cbdata; int i; /* eliminate 'unreferenced' warnings */ apinfo = apinfo; /* only process WM close events */ if ( we->event_f != Ph_WM_CLOSE ) { return( Pt_CONTINUE ); } /* okay it's a close so who is it? */ for ( i = 0; i < win_ctr; i++ ) { if ( win[i] == widget ) { win[i] = NULL; break; } } return( Pt_CONTINUE ); }
For more info on: | See the section: | In the chapter: |
---|---|---|
Using windows | Window modules | Working with Modules |
Instance names | Instance names | Creating Widgets in PhAB |
Variables and manifests | Working with Code chapter | |
Callbacks | Callbacks | Editing Resources and Callbacks in PhAB |
Code-callback functions | Working with Code | |
Generating code | Making and running your application | Generating, Compiling, & Running Code |