for connected embedded systems
PtFileSel
A tree widget for selecting files and directories
Class hierarchy:
PtWidget --> PtBasic --> PtContainer --> PtCompound --> PtGenList --> PtGenTree --> PtFileSel
For more information, see the diagram of the widget hierarchy.
PhAB icon:

Public header:
<photon/PtFileSel.h>
Description:
The PtFileSel widget is a tree where items can be files, directories, links to files or directories, or custom entries.

A PtFileSel widget.
This widget is useful when a program allows users to open or save files or directories. It reads a directory and displays the contents to the user. Users can also use the widget to navigate a filesystem and choose their own file and directory.
The items in the PtFileSel widget are displayed with images to show what type of file they are. Directory items are expandable and can show the files, directories and links under them. To expand and collapse items, you can use the mouse or these keys:
| To: | Press one of: |
|---|---|
| Expand a directory | Enter, -->, or + on the keypad |
| Collapse a directory | Backspace, <--, or - on the keypad |
Each item is stored in a PtFileSelItem_t structure that contains at least:
- PtGenTreeItem_t gen
- Used internally
- short opened
- A value that indicates whether the given directories' children have
already been allocated or not:
- Pt_FS_NEW_DIR-an unallocated directory
- Pt_FS_OLD_DIR-an allocated directory
- short type
- The type of file the item is:
- Pt_FS_DIR_OP-an open directory, one that has visible items
- Pt_FS_DIR_CL-a closed directory, one that doesn't have visible items
- Pt_FS_DLINK_OP-a link to an open directory
- Pt_FS_DLINK_CL-a link to a closed directory
- Pt_FS_FILE-a file
- Pt_FS_FLINK-a link to a file
- Pt_FS_ERROR-a file that had a read error
- short root
- A value that indicates if this is the root item:
- 1-this is the root directory
- 0-this isn't the root directory
- char *fullpath
- The full pathname of the item
- int tag
- Used internally
The widget has two main modes of operation:
- Tree mode (default)
- Items are displayed in a tree structure; opening a directory causes a new branch to be created.
- Single-level mode
-
Items are displayed in a single level or list; the list contains all
the files in the current directory.
When a directory is chosen, the existing items are freed and new ones are
created for the new directory. You can traverse up the filesystem by
using the .. item.
To set the widget to this mode, use the Pt_FS_SINGLE_LEVEL
flag in the Pt_ARG_FS_FLAGS resource.

A single-level file selector.
In this mode, you can also turn on the "key seek" flag, Pt_FS_SEEK_KEY, which lets you use the keyboard to search for a file. In this mode, the widget selects the next file or directory whose name starts with a character that you type. The search is case-sensitive and wraps to the top of the list if the character isn't found. Whenever you press a key, the Pt_CB_FS_SELECTION callback is invoked with a reason_subtype of Pt_LIST_SELECTION_BROWSE.
The widget also has a useful feature in that it will display file information including name, size, date, permissions, owner and group. You can use the Pt_ARG_FS_FORMAT resource to set the amount and order of information displayed. A PtDivider widget is automatically included in the file selector, along with a label for each column you request.
If you want to override the default headers, create a PtDivider of your own, add appropriate PtLabel widgets to it, and make the divider a child of the file selector. The information you requested will be displayed in the proper columns.
For example, if you create a PtDivider with the headings "Filename", "File size", and "Modification time" as a child of a PtFileSel widget and set the Pt_ARG_FS_FORMAT to nsd, the PtFileSel items would contain the name, size, and date information in the proper columns, but your divider would be displayed.
By default, when you expand an item (directory) for the first time, the directory is read and items are allocated. After this, when you collapse and expand the item, the information is stored in memory to remove the delay of reading a directory. You can refresh an item at any time by using the Pt_ARG_FS_REFRESH resource. You can also set the Pt_FS_FREE_ON_COLLAPSE flag to cause a directory to be re-read every time it's expanded. Every time a new root directory is set, all the previous items are freed.
If you plan to add items to the PtFileSel widget yourself by using the PtFSAllocItem(), PtFSAddFirst(), and PtFSAddAfter() convenience functions, you should have a state callback (Pt_CB_FS_STATE, subtype = Pt_FS_STATE_START) that returns Pt_END.
![]() |
If you're in tree mode and you get a state callback that is one of your items
(i.e. not from a filesystem), you should deal with the expansion/collapse and
return Pt_END from the callback
to prevent PtFileSel from trying to find the item in the
filesystem.
If you're in single-level mode and you get a state callback for one of your items (i.e. not from a filesystem), you should deal with the expansion; it's your responsibility to free all the previous items. Return Pt_END from the callback as mentioned above. |
Examples
In the examples below, Pt_FS_ALL_FLAGS is a value containing all the flag bits. It's used for a mask.
To display only directories, in tree mode:
...
PtSetArg(&args[0], Pt_ARG_FS_FLAGS, Pt_FS_SHOW_DIRS,
Pt_FS_ALL_FLAGS);
PtSetArg(&args[1], Pt_ARG_FS_ROOT_DIR, "/", 0);
PtSetArg(&args[2], Pt_ARG_AREA, area, 0);
PtCreateWidget(PtFileSel, NULL, 3, args);
...
To display only files in single-level mode, with keyboard seek on:
...
PtSetArg(&args[0], Pt_ARG_FS_FLAGS,
Pt_FS_SINGLE_LEVEL|Pt_FS_SHOW_FILES| \
Pt_FS_KEY_SEEK, Pt_FS_ALL_FLAGS);
PtSetArg(&args[1], Pt_ARG_FS_ROOT_DIR, "/", 0);
PtSetArg(&args[2], Pt_ARG_AREA, area, 0);
PtCreateWidget(PtFileSel, NULL, 3, args);
...
To display a single level of directories with a ".." to move up levels:
...
PtSetArg(&args[0], Pt_ARG_FS_FLAGS,
Pt_FS_SHOW_DIRS|Pt_FS_SINGLE_LEVEL,
Pt_FS_ALL_FLAGS);
PtSetArg(&args[1], Pt_ARG_FS_ROOT_DIR, "/", 0);
PtSetArg(&args[2], Pt_ARG_AREA, area, 0);
PtCreateWidget(PtFileSel, NULL, 3, args);
...
To display a combination of directories and files in tree mode:
...
PtSetArg(&args[0], Pt_ARG_FS_FLAGS,
Pt_FS_SHOW_DIRS|Pt_FS_SHOW_FILES,
Pt_FS_ALL_FLAGS);
PtSetArg(&args[1], Pt_ARG_FS_ROOT_DIR, "/", 0);
PtSetArg(&args[2], Pt_ARG_AREA, area, 0);
PtCreateWidget(PtFileSel, NULL, 3, args);
...
To show only hidden files (that is, a file whose name begins with a "." and isn't normally displayed):
...
PtSetArg(&args[0], Pt_ARG_FS_FLAGS,
Pt_FS_SHOW_FILES|Pt_FS_SHOW_HIDDEN,
Pt_FS_ALL_FLAGS);
PtSetArg(&args[1], Pt_ARG_FS_ROOT_DIR, "/", 0);
PtSetArg(&args[2], Pt_ARG_AREA, area, 0);
PtCreateWidget(PtFileSel, NULL, 3, args);
...
You can show hidden files or directories by combining the Pt_FS_SHOW_HIDDEN flag with Pt_FS_SHOW_DIRS or Pt_FS_SHOW_FILES.
The PtFileSel widget reads a filesystem, so there could be some delays on large directories. To help you cope with these delays, the widget does the following:
- The Pt_CB_FS_STATE callback is invoked when an item is expanded or collapsed. The expansion may take a long time if the directory is large, so the Pt_CB_FS_STATE callback is actually invoked twice, once at the start of the expansion/collapse (reason = Pt_FS_STATE_START) and once at the end (reason = Pt_FS_STATE_END). This lets you block the widget until the expansion/collapse is done. The code below gives an example of this.
- The Pt_CB_FS_BKGD_HANDLER callback is invoked each time a directory is read. You can use this callback to call something like PtBkgdHandlerProcess(). By doing this, any pending Photon events will be handled and all the screen damage will be fixed. This function should be small; if not, it will slow down the directory reading even further.
Here's a full PtFileSel example:
#include <stdio.h>
#include <Pt.h>
#include <photon/PtFileSel.h>
PtWidget_t *window, *button, *fs;
// quit button callback
int
quit( PtWidget_t *widget, void *data,
PtCallbackInfo_t *info)
{
exit(EXIT_SUCCESS);
return (Pt_CONTINUE);
}
// open button callback
int
file_open( PtWidget_t *widget, void *data,
PtCallbackInfo_t *info)
{
PtFileSelItem_t *item;
char buffer[PATH_MAX+NAME_MAX + 40];
item = PtFSGetCurrent(fs);
if (item == NULL)
return(Pt_CONTINUE);
strcpy(buffer, "The selected file is\n");
strcat(buffer, item->fullpath);
PtAskQuestion(window, "Selected File", buffer, NULL, "Ok",
NULL, NULL, 1);
return (Pt_CONTINUE);
}
// state callback, will use the reason to block the
// widget for large directory opens
int
state_cb( PtWidget_t *widget,
struct fs_dialog_modal *user,
PtCallbackInfo_t *info)
{
PtArg_t args[3];
PtFileSelCallback_t *it;
it = (PtFileSelCallback_t *)(info->cbdata);
if (it->reason == Pt_FS_STATE_START)
{
PtSetArg(&args[0], Pt_ARG_FLAGS, Pt_BLOCKED,
Pt_BLOCKED);
PtSetArg(&args[1], Pt_ARG_CURSOR_TYPE,
Ph_CURSOR_CLOCK, 0);
}
else
{
PtSetArg(&args[0], Pt_ARG_FLAGS, ~Pt_BLOCKED,
Pt_BLOCKED);
PtSetArg(&args[1], Pt_ARG_CURSOR_TYPE,
Ph_CURSOR_INHERIT, 0);
}
PtSetResources(widget, 2, args);
return (Pt_CONTINUE);
}
// function to handle photon draw events and fix screen damage
int
handler_cb(PtWidget_t *widget,
struct fs_dialog_modal *user,
PtCallbackInfo_t *info)
{
PtBkgdHandlerProcess();
return (Pt_CONTINUE);
}
void main(void)
{
PtArg_t args[10];
PtCallback_t cb, cb2;
PhDim_t win_dim = { 300, 300 };
PhArea_t area;
PtFileSelItem_t *item;
// make the main window
PtSetArg( &args[0], Pt_ARG_WINDOW_TITLE,
"PtFileSel Demo", 0 );
PtSetArg( &args[1], Pt_ARG_DIM, &win_dim, 0 );
window = PtAppInit( NULL, NULL, NULL, 2, args );
// make a file selector
area.size.w = 200;
area.size.h = 200;
area.pos.x = 10;
area.pos.y = 10;
cb.event_f = state_cb;
cb2.event_f = handler_cb;
PtSetArg(&args[0], Pt_ARG_AREA, &area, 0 );
PtSetArg(&args[1], Pt_ARG_FS_FLAGS,
Pt_FS_SHOW_DIRS|Pt_FS_SHOW_FILES,
Pt_FS_ALL_FLAGS );
PtSetArg(&args[2], Pt_ARG_FS_ROOT_DIR, "/", 0);
PtSetArg(&args[3], Pt_CB_FS_STATE, &cb, 0);
PtSetArg(&args[4], Pt_CB_FS_BKGD_HANDLER, &cb2, 0);
fs = PtCreateWidget( PtFileSel, window, 5, args );
// make a button for quitting
area.size.w = 60;
area.size.h = 20;
area.pos.x = 230;
area.pos.y = 250;
cb.event_f = quit;
PtSetArg( &args[0], Pt_ARG_AREA, &area, 0 );
PtSetArg( &args[1], Pt_ARG_TEXT_STRING, "Quit", 0);
PtSetArg( &args[2], Pt_CB_ACTIVATE, &cb, 0);
button = PtCreateWidget( PtButton, window, 3, args );
// make a open button
area.size.w = 60;
area.size.h = 20;
area.pos.x = 160;
area.pos.y = 250;
cb.event_f = file_open;
PtSetArg( &args[0], Pt_ARG_AREA, &area, 0 );
PtSetArg( &args[1], Pt_ARG_TEXT_STRING, "Open", 0);
PtSetArg( &args[2], Pt_CB_ACTIVATE, &cb, 0);
PtCreateWidget( PtButton, window, 3, args );
PtRealizeWidget( window );
PtMainLoop();
}
New resources:
| Resource | C type | Pt type | Default |
|---|---|---|---|
| Pt_ARG_FS_FILE_SPEC | char * | String | "*" |
| Pt_ARG_FS_FLAGS | ulong_t | Scalar | Pt_FS_SHOW_DIRS | Pt_FS_SHOW_FILES |
| Pt_ARG_FS_FORMAT | char * | String | NULL |
| Pt_ARG_FS_IMAGES | PhImage_t **, short | Array | PFM-style images (write-only) |
| Pt_ARG_FS_REFRESH | PtFileSelItem_t * | Pointer | NULL |
| Pt_ARG_FS_ROOT_DIR | char * | String | NULL |
| Pt_CB_FS_BKGD_HANDLER | PtCallback_t * | Link | NULL |
| Pt_CB_FS_SELECTION | PtCallback_t * | Link | NULL |
| Pt_CB_FS_STATE | PtCallback_t * | Link | NULL |
Pt_ARG_FS_FILE_SPEC
| C type | Pt type | Default |
|---|---|---|
| char * | String | "*" |
A string used to limit the files listed by specifying a pattern that filenames must match. The default is *, but it can be values such as *.c, *.[ch] and so on. You can specify multiple patterns by separating them with a space or a comma (for example, *.gif, *.jpg).
Pt_ARG_FS_FLAGS
| C type | Pt type | Default |
|---|---|---|
| ulong_t | Scalar | Pt_FS_SHOW_DIRS | Pt_FS_SHOW_FILES |
Flags that control the appearance and behavior of the file selector:
- Pt_FS_SHOW_DIRS
- Show directories.
- Pt_FS_SHOW_FILES
- Show files.
- Pt_FS_SHOW_HIDDEN
- Show hidden files or directories. This flag must be combined with Pt_FS_SHOW_FILES and/or Pt_FS_SHOW_DIRS. A hidden file or directory is one whose name begins with a period (.).
- Pt_FS_SHOW_ERRORS
- Show files that had a read error.
- Pt_FS_FREE_ON_COLLAPSE
- Free items on every collapse. This means that every time an item expands, all its child items are re-read from the disk.
- Pt_FS_SINGLE_LEVEL
- Single-level mode, instead of tree mode. Directories and possibly files are shown in one level with a .. item for moving up directory levels.
- Pt_FS_SEEK_KEY
- Keyboard seek mode, valid only for single-level mode. Type characters to seek an item.
Pt_ARG_FS_FORMAT
| C type | Pt type | Default |
|---|---|---|
| char * | String | NULL |
A string that's used to set the order and amount of file information displayed and optionally the initial size (in pixels) of each column shown. The following information can be displayed for each item in the widget by including the corresponding letter in the Pt_ARG_FS_FORMAT string:
| To display: | Specify: |
|---|---|
| name | n |
| size (in bytes) | s |
| size (in kbytes) | k |
| date | d |
| permissions | p |
| owner | o |
| group | g |
![]() |
These letters must be in lower case. |
The s and k options are mutually exclusive. If you try to set both, the first one found in the string is used and the other is ignored. The maximum number of characters is 6; any extra ones are ignored.
If you wish to display only the filename and no divider at the top, set this resource to NULL. To set the size of the column, specify a number of pixels before the corresponding letter. For example, if you want to have the name (100 pixels wide) and the date (200 pixels wide) displayed, set the Pt_ARG_FS_FORMAT resource as follows:
PtSetArg(&args[0], Pt_ARG_FS_FORMAT, "100n200d", 0);
Pt_ARG_FS_IMAGES (write-only)
| C type | Pt type | Default |
|---|---|---|
| PhImage_t ** | Array | PFM-style images |
A pointer to an array of image pointers (of type PhImage_t - see the Photon Library Reference) to be used for displaying items. The following constants are used to index into this array (the order shown is the order the images appear in the array):
- Pt_FS_DIR_OP-open directories
- Pt_FS_DIR_CL-closed directories
- Pt_FS_DLINK_OP-open directory links
- Pt_FS_DLINK_CL-closed directory links
- Pt_FS_FILE-files
- Pt_FS_FLINK-file links
- Pt_FS_ERROR-errors
If you don't want to change an image, specify NULL for that array element. For example, to change the file image, set the Pt_FS_FILE entry of the array to the image pointer and set all others to NULL.
For example, to change the Pt_FS_DIR_OP and Pt_FS_FILE images:
PhImage_t *images[7];
// assume you fill the below image structures
PhImage_t new_open_image, new_file_image;
...
images[Pt_FS_DIR_OP] = &new_open_image;
images[Pt_FS_DIR_CL] = NULL;
images[Pt_FS_DLINK_OP] = NULL;
images[Pt_FS_DLINK_CL] = NULL;
images[Pt_FS_FILE] = &new_file_image;
images[Pt_FS_FLINK] = NULL;
images[Pt_FS_ERROR] = NULL;
PtSetArg(&args[0], Pt_ARG_FS_IMAGES, images, 7);
...
If you want to save processing time, set the length parameter to PtSetArg() to the index of the last image you changed + 1.
![]() |
Set the flags member of the PhImage_t structures
to:
Ph_RELEASE_IMAGE | Ph_RELEASE_PALETTE |
Ph_RELEASE_TRANSPARENCY_MASK | Ph_RELEASE_GHOST_BITMAP
before providing the images to the widget. If you do this, the memory used for the images is released when the widget is unrealized or destroyed. |
Pt_ARG_FS_REFRESH
| C type | Pt type | Default |
|---|---|---|
| PtFileSelItem_t * | Pointer | NULL |
A pointer to the PtFileSelItem_t structure for an expandable item that's to be refreshed (i.e. reread from the disk). For example, if you have a large directory displayed and someone adds a file, you may wish to refresh the directory item. To do this, set the Pt_ARG_FS_REFRESH resource to point to the root item for that subtree.
Pt_ARG_FS_ROOT_DIR
| C type | Pt type | Default |
|---|---|---|
| char * | String | NULL |
The root directory for the File Selector. The default value is NULL or none.
Pt_CB_FS_BKGD_HANDLER
| C type | Pt type | Default |
|---|---|---|
| PtCallback_t * | Link | NULL |
A list of callbacks invoked each time a directory item is read. For example, if you have 5 files in a directory and expand that directory, this callback is invoked 5 times. It's useful for handling pending Photon events.
Each callback is passed a PtCallbackInfo_t structure that contains at least the following members:
- reason
- Pt_CB_FS_BKGD_HANDLER
- reason_subtype
- One of:
- Pt_FS_NEW_ITEM - a new item is being added to the widget; see below.
- Pt_FS_OLD_ITEM - the PtFileSel widget is doing intensive work and you may want to process events.
- cbdata
- Used only for the Pt_FS_NEW_ITEM subtype of this callback
For the Pt_FS_NEW_ITEM reason subtype, cbdata points to a structure of type PtFileSelBkgdCallback_t, which contains at least:
- char name[]
- The name of the item being added to the widget.
If this callback returns Pt_END, the item isn't added. If you wish to translate an item to another encoding, you should use PxTranslate... functions to do so, copy the new string into name, and return Pt_CONTINUE. You may also wish to process events.
![]() |
Set the Pt_CB_FS_BKGD_HANDLER callback resource before the Pt_ARG_FS_ROOT_DIR resource in order to translate all the filenames. |
Here's an example of this callback:
int
handler_cb( PtWidget_t *widget, void *data,
PtCallbackInfo_t *info)
{
PtArg_t args[1];
PtFileSelBkgdCallback_t *it = (void *) info->cbdata;
int srctaken = 0, dstmade = 0;
char dst[NAME_MAX * 3] = {""};
if (info->reason_subtype != Pt_FS_NEW_ITEM)
return (Pt_END);
// ctrl is a PxTransCtrl structure that was set with a
// call to PxTranslateSet(). The following will convert
// the string and copy it back to the original:
if (PxTranslateToUTF( ctrl, it->name, strlen( it->name),
&srctaken, dst, 0, &dstmade) != -1)
strcpy(it->name, dst);
PtBkgdHandlerProcess();
return(Pt_CONTINUE);
}
Pt_CB_FS_SELECTION
| C type | Pt type | Default |
|---|---|---|
| PtCallback_t * | Link | NULL |
A list of callbacks invoked when the user selects an item. Each callback is passed a PtCallbackInfo_t structure that contains at least the following members:
- reason
- Pt_CB_FS_SELECTION
- reason_subtype
- Depending on the selection mode, this is one of:
- Pt_LIST_SELECTION_FINAL
- Pt_LIST_SELECTION_BROWSE
- Pt_LIST_SELECTION_CANCEL
- cbdata
- A pointer to a PtFileSelCallback_t structure that
contains:
- unsigned sel_mode-the current
selection mode:
- Pt_BROWSE_MODE
- Pt_MULTIPLE_MODE
- Pt_EXTENDED_MODE
- Pt_SINGLE_MODE
- Pt_RANGE_MODE
- PtFileSelItem_t *item-a pointer to the item that has been selected
- unsigned nitems-the number of selected items, which depends on the selection mode
- short reason-not valid for this callback
- unsigned sel_mode-the current
selection mode:
These callbacks should return Pt_CONTINUE.
Pt_CB_FS_STATE
| C type | Pt type | Default |
|---|---|---|
| PtCallback_t * | Link | NULL |
A list of callbacks invoked when an item is expanded or collapsed. Each callback is passed a PtCallbackInfo_t structure that contains at least the following members:
- reason
- Pt_CB_FS_STATE
- reason_subtype
- Pt_TREE_COLLAPSING or Pt_TREE_EXPANDING.
- cbdata
- A pointer to a PtFileSelCallback_t structure that
contains:
- unsigned sel_mode-the current
selection mode:
- Pt_BROWSE_MODE
- Pt_MULTIPLE_MODE
- Pt_EXTENDED_MODE
- Pt_SINGLE_MODE
- Pt_RANGE_MODE
- PtFileSelItem_t *item-if
the reason member is Pt_FS_STATE_START, this
is a pointer to the item being collapsed or expanded; if
the reason member is Pt_FS_STATE_END, this
is NULL.

If the Pt_FS_SINGLE_LEVEL flag is set in the Pt_ARG_FS_FLAGS resource, item is always NULL because all the previous items are destroyed when you select a new directory in single-level mode.
- unsigned nitems-not valid for this callback
- short reason-
- Pt_FS_STATE_START
- The callback is being called before the disk is read (useful for blocking the widget when reading a large directory).
- Pt_FS_STATE_END
- The callback is being called after the disk is read (useful for unblocking the widget).
- unsigned sel_mode-the current
selection mode:
These callbacks should return Pt_CONTINUE.
Inherited resources:
If the widget modifies an inherited resource, the "Default override" column indicates the new value. This modification affects any subclasses of the widget.
Convenience functions:
The PtFileSel widget defines several convenience functions that make it easier to use the file selector once it's been created. Here's a brief overview:
- PtFileSelection()
- Creates a file-selector dialog similar to the AWFileSelect widget. See the Photon Library Reference.
- PtFSAddAfter()
- Inserts an item after the specified item.
- PtFSAddFirst()
- Adds a root item to the widget.
- PtFSAllItems()
- Fills a buffer with pointers to all items.
- PtFSAllocItem()
- Creates an item for a file-selector widget.
- PtFSClearSelection()
- Clears the selection.
- PtFSDamageItem()
- Redraws an item.
- PtFSExpandParents()
- If any ancestors of the given item are collapsed, this function tries to expand them.
- PtFSFolderCollapse()
- Collapses an expandable item (directory).
- PtFSFolderExpand()
- Expands an expandable item (directory).
- PtFSFreeAllItems()
- Unlinks and frees all items.
- PtFSFreeItems()
- Frees an unlinked item.
- PtFSGetCurrent()
- Gets the current item.
- PtFSGetSelIndexes()
- Fills a buffer with indexes.
- PtFSGoto()
- Sets the current item.
- PtFSItemIndex()
- Calculates the index of the specified item.
- PtFSRemoveChildren()
- Unlinks all the children of a given item.
- PtFSRemoveItem()
- Unlinks an item.
- PtFSRemoveList()
- Unlinks the root item.
- PtFSRootItem()
- Returns the first root item of the file selector.
- PtFSSelect()
- Selects the specified item.
- PtFSSelectedItems()
- Fills a buffer with item pointers.
- PtFSSetSelIndexes()
- Sets the selection indexes.
- PtFSShow()
- Sets the position so that the specified item is visible.
- PtFSUnselect()
- Unselects the specified item.
- PtFSUnselectNonBrothers()
- Unselects all items that aren't siblings of the specified item.
