Tutorials

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.

This chapter includes:

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.

Before you start...

If you're developing Photon applications in the IDE, the way you use PhAB there is slightly different than from standalone PhAB. The differences are:

Creating a Photon project and starting PhAB

From the IDE:

To create a new PhAB project, see Creating a QNX Photon Appbuilder project in the Developing Photon Applications chapter of the IDE User's Guide. When you create a new project, the IDE opens PhAB, and you see the New Window Style dialog from which you can select the type of base window for your application.

From standalone PhAB:

You can start PhAB from the Launch menu in the lower-left corner of the screen; choose the Development submenu, and then choose Builder.

You can also start PhAB from a pterm window by typing:

appbuilder

For information about command-line options, see appbuilder in the QNX Neutrino Utilities Reference.

PhAB's Interface

Before you start the tutorials, take a moment to make yourself familiar with PhAB's user interface:


phab at a glance


Overview of PhAB's user interface.

Menubar
Import graphics, create windows and dialogs, generate C and/or C++ code to implement your entire user interface, and more.
Toolbars
Save time with the toolbars—with a couple of mouse clicks you can duplicate, move, align, group, or resize any number of widgets.
Work area
Provides a flexible area where you can work on several application modules all at once.
Widget palette
Makes it easy to add widgets to your application. Just click the widget you want, then click where you want it.
Control panels
Let you fully customize your application's widgets. You can choose text fonts, modify colors, customize bitmaps, and attach callbacks that will pop up dialogs or invoke C and/or C++ code you've supplied.

The widget palette and control panels are initially in the same window, but you can drag any of them into a different window. To switch between panels in a window, click the tab at the top and choose a panel from the menu.

If you close a control panel, you can redisplay it by selecting the appropriate item from the View menu.

Tutorial 1 — Hello, world

In this tutorial you learn how to use PhAB to create and compile a simple application.

Creating the application

  1. Create a new project. See Creating a Photon project and starting PhAB above.
  2. PhAB displays a dialog to let you choose the style for the new application's default base window:

    Choosing the style of the base window

  3. Choose a style and click Done; PhAB creates the base window and displays it.
  4. Whenever you create a new application within standalone PhAB, it's a good idea to save the application and give it a name. (If you're running PhAB from the IDE, you've already saved the application when you created the project).

    From the File menu, choose Save As to open the Application Selector dialog. Click the Application Name field, type tut1, then press Enter or click Save Application.

  5. Look at PhAB's titlebar. It now indicates that the current application is named tut1.
  6. If the widget palette isn't displayed, click the tab at the top of the current control panel and choose Widgets from the menu that appears.
  7. Drag the widget palette away from the other control panels by pointing to the left of its tab, holding down the mouse button, and pointing to PhAB's work area.
  8. If you wish, resize the widget palette and control panels.
  9. Go to the widget palette and click the PtLabel widget icon:

    PtLabel icon

  10. Move the pointer into the application's base window (the pointer changes to a crosshair) and click anywhere near the center of the window.

    PhAB automatically:

  11. Go to the Resources control panel and highlight the text Label beside the Label Text resource.
  12. Change the text to Hello World. As you type, the text in the widget changes:

    Hello World widget

Generating code

Now you're ready to generate, compile, and execute the application. How you perform this step depends on whether you're using PhAB from the IDE or standalone.

From the IDE

When running PhAB from the IDE, PhAB generates the code for your application's user interface, and the IDE compiles and executes the application. You'll notice that only the Generate UI item is available in PhAB's Build menu.

  1. In PhAB, chose Generate UI from the Build menu to generate the user interface code.
  2. Switch to the IDE.
  3. To build the application, follow the instructions in Building projects in the Developing C/C++ Programs chapter of the IDE User's Guide.
  4. To run the application, follow the instructions in Running projects in the Developing C/C++ Programs chapter of the IDE User's Guide.

From standalone PhAB

  1. From the Build menu, choose Build & Run. PhAB displays a dialog for selecting a platform, which is a combination of the operating system, computer, compiler, and endian format. Choose the appropriate platform for your application. For example, if you're using the Neutrino OS on an Intel x86 machine and the gcc compiler, choose X86 (Little Endian).
  2. Click Done once you've made your platform selection. Your application will be generated, compiled and linked. PhAB displays a dialog for entering run arguments. Click OK. Your application runs.

The application will appear in its own window, with the text “Hello World” in the center and the default title “My Application” in the title bar:

Hello World application

Congratulations! You've just created your first Photon application using PhAB.

To quit the application, click the window menu button in its top-left corner, then choose the Close item.

Want more info?

For more info on compiling, running, and debugging an application, see the Generating, Compiling, and Running Code chapter.

Tutorial 2 — editing resources

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:

You'll also learn how to create a template so you can create other instances of an existing widget.

Adding a button widget

  1. Create a new application called tut2. Choose the Plain window style.
  2. Click PtButton in the widget palette:

    PtButton icon

  3. Click near the center of the application's window. You'll see a button widget.
  4. Drag any of the button's resize handles until the button matches the following picture:

    button in window

Changing the bevel width

Let's now edit a numerical resource—the button's bevel width.

  1. Click the Bevel Width resource in the Control Panel. You'll see the number editor:

    Number editor

    This editor lets you change the value of any numerical widget resource.

  2. Change the value to 6. To do this, you can:
  3. To apply the new value and close the editor, press Enter or click Done.

Note: You can also edit this resource (and most resources) right in the Resources control panel. Choose whichever method you like.

Changing the font

Let's change the font of the button's text:

  1. Click the Font resource. You'll see the font editor, which displays the button's current font:

    Font editor

    This editor lets you change the text font of any widget that has text.

  2. Click the Font box or the Size box, select a typeface or size from the displayed list, and click Apply. The button displays the new font.
  3. Click Default. The editor displays the widget's default font, but doesn't apply the font to the widget.
  4. If you want to keep the new font that you selected, click Cancel to ignore the default. If you want to apply the default, click Done. Either way, the editor closes.

Changing the text alignment

Now let's change the button's horizontal text alignment:

  1. Scroll through the Resources control panel to find the Horz Alignment resource, then click it. You'll see the flag/option editor, which displays the widget's current text alignment:

    Flag/option editor

    This editor serves a dual purpose in PhAB:

  2. Click Pt_LEFT or Pt_RIGHT, then click Apply. You'll see the button text move to the left or right edge of the button.
  3. Click Done.

You can also set this resource right in the Resources control panel.

Setting flags

Let's now use the flag/option editor to set one of the widget's flags:

  1. Scroll through the Resources control panel to find the Basic Flags resource, then click it. The flag/option editor reopens, but this time it shows the widget's current PtBasic flag settings:

    Flag/option editor

    The bits in this flag resource aren't mutually exclusive, so this time you can use the editor to select multiple options, if desired.

  2. Set the Pt_TOP_INLINE, Pt_BOTTOM_INLINE, Pt_LEFT_INLINE, and Pt_RIGHT_INLINE flags, then click Done. PhAB draws the button with an inner border:

    Button with inner border

Changing the fill color

Let's change a color resource—the button's fill color.

  1. Click the button's Color: Fill resource. You'll see the color editor, which displays the current fill color:

    Color editor

    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.

  2. Click any color in the Base Colors set, then click on Apply. The button is filled with the color you selected.
  3. Select a color from the Custom Colors set. The sliders will display the color's Red/Green/Blue (RGB) values. Change these values till you get a color you want, then apply your changes.

    If you'd like to experiment with the Hue/Saturation/Brightness (HSB) color model, click the HSB Model button.

  4. Click Done when you've finished experimenting with the editor.

Your button should now look something like this:

Big green button

Don't delete this widget; we'll use it to create a template later on, so that you can create other widgets like it.

Editing a pixmap

Let's now use the pixmap editor to edit a PtLabel widget. This editor is called “pixmap” instead of “bitmap” since it lets you edit many types of image resources besides bitmaps.

A PtLabel widget display text and/or an image.

  1. Click PtLabel in the widget palette:

    PtLabel icon

  2. Move the pointer into the main window and click below the button widget you created. You'll see a PtLabel widget.
  3. Click the Label Type resource in the Resources control panel, and set it to Pt_IMAGE.
  4. Click the Label Image resource in the Resources control panel to bring up the pixmap editor.
  5. Next, bring up the color editor to select a draw color. Just click the following button:

    Color Fill button

  6. Select a color from the pixmap palette. You'll see that the draw color in the pixmap editor changes immediately.

    If you click Edit Color, you'll see the Color Editor, as described earlier.

  7. To draw a simple image, you can:

    Feel free to try the other drawing tools.

  8. When you're done, click the pixmap editor's Done button to apply your changes and close the editor.

Editing multiline text

Next, we'll edit a multiline text resource—the text of a PtMultiText widget.

  1. Click PtMultiText in the widget palette:

    PtMultiText icon

  2. Move the pointer below the label widget you've just created, and drag until the new PtMultiText widget appears big enough to hold a few lines of text.
  3. Click the Text String resource in the Resources control panel to bring up the multiline text editor:

    Multiline text editor

  4. Type a few lines of text. To create a new line, press Enter. For example:

    Mary hadEnter
    aEnter
    little lamb.Enter

  5. Click Done. Your text should appear exactly as you typed it. If it doesn't, try resizing the widget—the widget might not be wide enough or tall enough.
  6. For a different effect, look for the Horz Alignment resource, click the arrow, and change the text alignment to Pt_CENTER. As you can see, each line is now centered individually.
  7. If you haven't already, resize the widget by dragging on one of its resize handles. You'll see the text update automatically to adjust to the new size. For example:

    Multiline text example


Note: You can edit the text right in the control panel, but it displays only the current line of text.

Editing a list of text items

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.

  1. Click PtList in the widget palette:

    PtList icon

  2. Move the pointer into the application's base window, and drag the pointer until the new PtList widget appears big enough to hold a few lines of text.
  3. Click the List of Items resource to bring up the list editor:

    List editor

  4. Click the text box at the bottom of the editor. You'll see the text-input cursor.
  5. Type some text, then click Add After to place the first item in the list.
  6. Now let's create the second item. Click in the text box, and type Ctrl-U to erase the text in the text box, then type some new text.

    Click Add After to place this new item after the previous item.

  7. Repeat the above step as often as you'd like.
  8. Click Apply. The PtList widget should now display the list you've created.
  9. Now try editing the list:
  10. When you're finished experimenting, click on Done to apply your changes and close the editor.

Creating a template

At times, you might want to create many widgets that look and behave alike. You can do this by creating a widget, editing its resources, and then copying and pasting it, but this isn't always very convenient, and doesn't copy certain important elements like callbacks.

PhAB makes it simpler by letting you create a template from an existing widget or widgets. PhAB creates a palette, similar to the widget palette, for your templates.

Let's create a template from the button that you created earlier in this tutorial.

  1. Start by selecting the button.
  2. Click the Widget menu, and then choose Define Template. The Define Template dialog appears.

    Define Template dialog

  3. You need to create a folder in which to store the template, so click on Add Folder. This dialog is displayed:

    Setup Folders dialog

  4. The new folder can be a user folder or a PhAB folder. A user folder is personal and can't be viewed by any other PhAB users logged on to the system. If you choose PhAB folder, the new folder can be shared between users; you must have the necessary permissions to create a PhAB folder.

    Choose User Folder, type My_templates as the folder's name, and click Add. The dialog closes, and the folder's name is displayed in the Define template dialog.

  5. Give the template a name, such as Big green button. This is the name that PhAB uses in the palette.
  6. You can create an icon for the palette entry for the template. If you do not create an icon for the template entry, a default icon is used for it. To create the icon, click the icon Edit button, and then follow the instructions given earlier for editing pixmaps. You should make the icon look something like the widget:

    Green button icon

  7. Optionally, choose the background color for the palette entry by clicking on the Color box. You can use different background colors in a palette to distinguish widgets that are used for different purposes (e.g. buttons and text widgets).
  8. Choose a resize method. This determines whether you drag or just click when you create instances of your template. For this button, choose the dragging method.
  9. The dialog should now look something like this:

    My template

    Click Done.

You've just created a template! Now, let's see how to use it.

  1. Select Window-->Show Templates. On the list of items, select Show My Templates. If the menu item is Hide My Templates, it means that My Templates is already displayed and visible on the screen.
  2. Go to the control panels, and click the top tab. The popup menu now includes My_templates; choose it to display the palette.

    Palette for My_template

  3. Click the icon for your customized button, create an instance of it, and edit it as you wish:

    Template and instance

If you wish, you can save, generate, make, and run the application.

Whenever you start PhAB, it automatically loads the palette for My_templates.

Want more info?

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 or multiline text strings Text editors

For more information on templates, see Templates in the Creating Widgets in PhAB chapter.

Tutorial 3 — creating menus and menubars

This tutorial takes you through the steps required to create menus and menubars.

About link callbacks

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 some windowing environments, 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:

Module-type link callback
Attaches an application module (such as a window, dialog, or menu) to any widget callback. The module opens whenever the callback's conditions are met. In this tutorial, you'll link a menu module to a button's “Arm” callback.
Code-type link callback
Attaches a code function to any widget callback. The widget invokes the function whenever the callback's conditions are met. Note that some code-type link callbacks let you close the parent module automatically. In this tutorial, you'll link a code function to a menu item's callback.

About instance names

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.


Note: Adopting a naming convention for your widgets will make it easier for you to work with large applications.

Creating a menubar

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.

  1. Create a new application named tut3. Choose the Plain window style.
  2. Select the PtMenuBar widget from the widget palette, point at the top left cornet of the main window's canvas, and drag until the menu bar is the width of the window.

    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.


    Note: If you accidentally click the Test button, the window won't resize or accept new widgets. If this happens, you just switched into Test Mode. To go back to Edit Mode, select Project-->Edit mode.

    By the time you're finished the following steps, the menubar will look like this:

    Finished menubar

  3. Place a PtMenuButton widget in the menubar you just created. The menu button is automatically centered vertically in the menubar.
  4. Go to the Resources control panel and click the widget instance name just below the class name. Change the button's instance name to base_file:

    Instance name

  5. Change the button's Label Text resource to File.
  6. Place another PtMenuButton widget next to the first. Change its instance name to base_help and its text to Help.

Creating the File menu module

Now that you have menu buttons, you need to create your menu modules. Let's start with the File menu.

  1. Select Project-->Add Menu. A new menu module appears.
  2. Change the name of the menu from Menu0 to filemenu:

    Changing the menu name

Adding menu items

Let's now add some menu items to the File menu.


Note: If you click another module, the menu module becomes deselected, which means you can't work on it. To reselect the menu module, click its titlebar.

  1. Click the Menu Items resource in the Resources control panel. You'll see the menu editor:

    Menu Items editor

    If you look at the Menu Items list, you'll see that the <New> item is selected. This special item lets you add menu items to the menu.

  2. To add your first menu item—which also happens to be called “New”—click the Item Text field, then type New.
  3. Now give the item an instance name. In the Inst Name field, type file_new.
  4. Click Apply to add the item to the menu. You'll see the item's name in Menu Items list, prefixed by CMD. The CMD means this is a Command item; that is, an item that invokes a PhAB callback.
  5. Repeat the above steps to create the two menu items labeled Save and Save As. Give these items the instance names file_save and file_as.
  6. Up to now, you've added Command-type menu items. You'll now add a Separator item. Just click on the Separator button near the upper-right corner
  7. Click Apply to get the default separator style, which is Etched - in.
  8. Now let's add the Quit item. Click the Command button, then specify Quit as the item text and file_quit as the instance name.
  9. You're finished with this menu module for now, so click Done. The module displays the items you just created:

    Menu module

  10. You'll want to keep this module neatly out of the way while you work on your next task. So click the module's minimize button (the left button at the right side of the title bar), or select the Work menu button (upper-left corner) and choose Minimize.

Creating the Help menu module

Using what you just learned about creating a menu module, do the following:

  1. Create your Help menu module and give it a name of helpmenu.
  2. In this module, place a single command item called About Demo and give the item an instance name of help_about. When you're finished, minimize the module.

Note: 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.

Attaching link callbacks

Let's return to the menu buttons you created earlier and attach link callbacks so that the buttons can pop up your menu modules.

Attaching a module-type link callback

  1. Select the File menu button, then switch to the Callbacks control panel You'll see the File button's callback list:

    Callback list

  2. To have the File menu module pop up when you press the File button, you need to attach an Arm callback to the button. By attaching an Arm callback, you can open the menu using either click-move-click or press-drag-release.

    Click Arm to bring up the callback editor.

  3. The Module Types area of the editor let you choose the type of module you wish to link to. Because you want to link the File button to a menu module, click Menu.
  4. Click the Name list and type filemenu (or select filemenu from the list) which is the name you gave your File menu module. This links the menu button to that module.

    You can also select filemenu from a popup list of available modules. To bring up the list, click the icon to the right of the Name field.

  5. Click Apply to add the link callback, then click Done to close the callback editor.
  6. Repeat the above steps to link the Help menu button to the Help menu module.

Attaching a code-type link callback

Let's now attach a code-type link callback to the File menu's Quit item so that it can terminate the application.

  1. Double-click the iconified filemenu module. This opens and selects the module.
  2. Switch to the Resources control panel, then click the Menu Items resource.
  3. Select the Quit item in the Menu Items list.
  4. Click the icon next to the Callback field to open the callback editor:

    Callback icon

  5. When the editor opens, the default callback type is Code. Since this is the type you want, all you have to do is specify the name of the function you want to call.

    The function should have a meaningful name. So type quit in the Function field.

  6. Click Apply to update the Callbacks list, then click Done to close the editor.
  7. Click Done again to close the menu editor.

Setting up the code

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.

  1. Select Build-->Generate UI. This generates the necessary application files.
  2. After the generation process is complete, open the Browse Files palette window by selection Window-->Show Project.

    Scroll through the list until you see the quit.c file. This is the generic code template that PhAB generated for your quit() function.

  3. You need to make the function exit the program. To do this, select quit.c from the file list, click the Edit button, or double-click quit.c, then change the quit() function to the following:
    int
    quit( PtWidget_t *widget, ApInfo_t *apinfo,
          PtCallbackInfo_t *cbinfo )
    {
    
         /* eliminate 'unreferenced' warnings */
         widget = widget,
         apinfo = apinfo,
         cbinfo = cbinfo;
    
         PtExit( EXIT_SUCCESS );
    
         /* This statement won't be reached, but it
            will keep the compiler happy. */
    
         return( Pt_CONTINUE );
    }

    PtExit() is a function that cleans up the Photon environment and then exits the application. It's described in the Photon Library Reference.


    Note: If you are using the IDE, you can also edit quit.c, or any other source code file, from the IDE editor by double-clicking the file in the project navigator tree.

  4. After you've edited the code, saved your changes, and closed the editor, build and run your application.
  5. Once your application is running, try clicking on the File button to bring up the File menu. Then choose Quit. Your application will immediately terminate and close.

Want more info?

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

Tutorial 4 — creating dialogs

This tutorial describes how to create a dialog. It also provides a good example of how you can use setup code to modify a widget's resources before the widget appears onscreen.


Note: This tutorial uses the application you created in Tutorial 3.

In this tutorial, you'll:

About dialogs

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.

More on instance names

To make it easier for you to access widgets from within your application code, PhAB generates a constant and a manifest. Both of these are based on the widget's instance name.

The constant, which has the prefix ABN_, represents the widget's name. The manifest, which has the prefix ABW_, represents the widget's instance pointer.

For example, let's say you have a widget named about_version. PhAB uses this name to generate a constant named ABN_about_version and a manifest named ABW_about_version.

In this tutorial you'll learn how to use these generated names.


Note: The value of a widget's ABN_... constant is unique in the entire application.

Attaching a dialog module

  1. Make a copy of the tut3 application you created and name it tut4:
  2. Open the Help menu module you created (it may still be iconified).
  3. Click the Menu Items resource in the Resources control panel to open the menu editor.
  4. Select the About Demo item, then click the icon next to the Callback field to open the callback editor:

    Callback icon

  5. When the editor opens, the default callback type is Code. Go to the Module Types group and change the callback type to Dialog.
  6. In the Name field, type aboutdlg as the name of the dialog module you want to link to. (This dialog doesn't exist yet, but PhAB will ask you later to create it.)
  7. In the Setup Function field, type aboutdlg_setup. This is the name we're giving to the setup function that will be called before the dialog is realized.

    Using this function, we'll change the content of a label widget within the dialog to display a version number.

  8. Since you want the aboutdlg_setup function to be called before the dialog is realized, make sure the Prerealize button is enabled.
  9. Click the Location icon to specify where you want the dialog to appear when it gets realized. (The Center Screen location is a good choice.) Click Done.

    Your callback information should now look something like this (depending on the location you chose):

    Callback information

  10. Click on Apply in the Actions group to add the link callback. Since the dialog module you want to link to doesn't exist yet, PhAB asks you to choose a style; select Plain and click Done.

    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.

  11. Click Done to close the callback editor, then click Done again to close the menu editor.

Adding widgets to the dialog

  1. Open the aboutdlg dialog module.
  2. Place two PtLabel widgets in the top half of the dialog, and a PtButton near the bottom:

    Dialog with widgets

  3. Select the top PtLabel widget and change its label text resource to About this Demo. Then change its horizontal alignment to Pt_CENTER.
  4. Select the other PtLabel widget and change its label text to a blank string. Then change its horizontal alignment to Pt_CENTER.

    Later, you'll fill in the aboutdlg_setup() function so that it changes the blank text of this label to display a version number.

  5. You must give this blank PtLabel widget an instance name since you'll be referring to it in code. So change its instance name to about_version.
  6. Select the PtButton widget and change its button text resource to Done. Then change its instance name to about_done.
  7. Let's center the widgets horizontally in the dialog. Select both PtLabel widgets and the PtButton widget, choose Align from the Widget menu, and then choose Alignment Tool from the submenu. You'll see the Align Widgets dialog:

    Alignment dialog

  8. In the Horizontal column, click Align Centers and on Align to Container. Then click the Align button.

    The two labels and the button should now be centered horizontally within your dialog. Your aboutdlg module should now look like this:

    aboutdlg module

Adding a callback to the Done button

Now let's add a callback to the Done button so that the dialog closes when the user clicks on the button.

  1. Select the Done button, then switch to the Callbacks control panel.
  2. Click Activate to add an activate callback. You'll see the callback editor.
  3. Select the Done code type, then click Apply. Don't enter anything in the Function field.

    Selecting the Done code type tells the widget to perform a “Done” operation when the widget is activated. That is, the widget calls the function specified in the Function field (if one is specified) and then closes the dialog module.

  4. Close the editor. The callback list now indicates that you've added an Activate callback called Done:

    Activate callback

Modifying a generated code function

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.

  1. Select Build-->Generate UI. This save yours application and generates the necessary files.
  2. When code generation is complete, choose Window-->Show Project to bring the Browse Files palette window to front. Select aboutdlg_setup.c from the file list, and click Edit, or double-click the filename. If you are using PhAB from the IDE, you can open and edit this file in the IDE.

    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 )
    {
    
        /* eliminate 'unreferenced' warnings */
        link_instance = link_instance, apinfo = apinfo,
                        cbinfo = cbinfo;
    
        PtSetResource( ABW_about_version, Pt_ARG_TEXT_STRING,
                       "1.00", 0);
    
        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 calls PtSetResource() to set the resource for the about_version widget. The code uses the PhAB-generated manifest ABW_about_version, which provides access to the widget's instance pointer.

    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.

  3. Save your changes and exit the text editor.

Compiling and Running

You're now ready to compile and run the program:

  1. Build and run your application. If your program compiles and links without errors (which it should if you edited the function correctly), it will run.
  2. From the running application, open the Help menu and choose About Demo. The dialog will open, and you'll see the version number (1.00) under the label About this Demo. Note that the dialog appears in the location you specified.
  3. Now try to bring up a second instance of the dialog. As you see, it won't work. PhAB always ensures that there is only one instance of a Dialog widget.
  4. Click Done to close the dialog, then quit the application by choosing Quit from its File menu.

Want more info?

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 Generating application code Generating, Compiling, and Running Code

Tutorial 5 — creating windows

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.


Note: This tutorial uses the application you created in Tutorial 4.

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 generated constant name (ABN_xxx).

Creating a window

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 add the window from the Project menu. In the future, use whatever method you prefer.

  1. Make a copy of the tut4 application and call it tut5.
  2. Iconify the aboutdlg dialog module.
  3. From the Project menu, select Add Window. When PhAB prompts you for a window style, choose the Plain style.
  4. Change the new window's instance name from Window0 to newwin, by typing the new name in the instance name field in the control Panel.
  5. The window module should now be the currently selected item.

Attaching callbacks

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:

  1. Switch to the Callbacks control panel, if necessary.
  2. From the list of callbacks, choose Window Manager. You want to use the Window Manager callback since it's invoked when the Photon Window Manager closes the window.
  3. In the Function field, type newwin_close. You don't have to choose a callback type since the default, Code, is the one you want.

    Click Apply, then Done.

  4. Switch to the Resources control panel and select the Flags: Notify resource. Make sure that the Ph_WM_CLOSE flag is set (i.e. highlighted), then click Done. This flag tells the Window Manager to notify your application when the window is closed.
  5. Now let's set up a function that's invoked when the window opens.

    Open the filemenu menu module, then select the Menu Items resource in the Resources control panel. You'll see the menu editor.

  6. Make sure the menu's New item is currently selected in the Menu Items list, then click the Callback icon to open the callback editor.
  7. Choose the Window module type, then click the arrow next to the Name field. You'll see the list of existing window modules.
  8. Choose newwin, which is the window you just created.
  9. In the Setup Function field, enter newwin_setup as the name of the setup function. Later, you'll modify newwin_setup() to handle the window's multiple instances.
  10. Click Apply, then on Done. Click Done again to close the menu editor.

Adding widgets

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.

  1. Add a PtRect widget and four PtButton widgets as follows:

    New window 1

  2. Now modify the left button:
  3. Modify the middle button:
  4. Modify the right button:
  5. Modify the large button:
  6. Last of all, give the rectangle an instance name of color_rect. You need to specify this name so that the color_change() function can change the color of the rectangle.

Your window should now look something like this:

New window 2

Generating and modifying the code

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.

Generating the code

Open the Build menu and select Generate UI.

Modifying the setup function

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 )
{
    char    buffer[40];

    /* eliminate 'unreferenced' warnings */
    link_instance = link_instance, apinfo = apinfo;
    cbinfo = cbinfo;

    /* Note: Returning Pt_END in a prerealize setup
       function tells 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 );
    PtSetResource( win[win_ctr], Pt_ARG_WINDOW_TITLE,
                   buffer, 0 );
    win_ctr++;

    return( Pt_CONTINUE );

}

Modifying the color-change function

Now let's modify the color_change() function so that:


Note: 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 of a widget in the current window, you need to call:

If only one instance of the window were guaranteed, the following would work:

PtSetResource( ABW_color_rect, Pt_ARG_FILL_COLOR,
               buffer, 0 );

But in this case color_change() has to use:

PtSetResource( ApGetWidgetPtr( ApGetInstance( widget ),
               ABN_color_rect ), Pt_ARG_FILL_COLOR,
               buffer, 0 );

So you need to change color_change.c to look like:

PgColor_t          colors[5] = {Pg_BLACK, Pg_YELLOW,
                                Pg_MAGENTA, Pg_CYAN,
                                Pg_GREEN};
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;
  PtWidget_t *this_window;

  /* eliminate 'unreferenced' warnings */
  widget = widget, apinfo = apinfo, cbinfo = cbinfo;

  /* Get a pointer to the current window. */
  this_window = ApGetInstance( widget );

  if ( ApName( widget ) == ABN_btn_red ) {
       PtSetResource(
          ApGetWidgetPtr( this_window, ABN_color_rect ),
          Pt_ARG_FILL_COLOR, Pg_RED, 0 );

  } else if ( ApName( widget ) == ABN_btn_green ) {
       PtSetResource(
          ApGetWidgetPtr( this_window, ABN_color_rect ),
          Pt_ARG_FILL_COLOR, Pg_GREEN, 0 );

  } else if ( ApName( widget ) == ABN_btn_blue ) {
       PtSetResource(
          ApGetWidgetPtr( this_window, ABN_color_rect ),
          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] == this_window ) {
               prev = i - 1;
               break;
           }
       }

       /* If the window still exists, update its background
          color. */

       if ( prev != -1 && win[prev] ) {
           base_clr++;
           if (base_clr >= 5) {
               base_clr = 0;
           }
           PtSetResource( win[prev], Pt_ARG_FILL_COLOR,
                          colors[base_clr], 0 );
       }
   }

   return( Pt_CONTINUE );
}

Modifying the window-close function

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 );
}

Compiling and running

  1. Make and run the application.
  2. From the application's File menu, choose New several times to create multiple windows. You'll see each window's relative number in its titlebar.
  3. Click a color button to make the rectangle change color. Then click the Change Previous Window Color button in any window to change the background color of the previous window.

Want more info?

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 Generating application code Generating, Compiling, and Running Code
Window events Window-management flags Window Management