A tree widget for selecting files and directories
PtWidget → PtBasic → PtContainer → PtCompound → PtGenList → PtGenTree → PtFileSel
For more information, see the diagram of the widget hierarchy.
<photon/PtFileSel.h>
The PtFileSel widget is a tree where items can be files, directories, links to files or directories, or custom entries.
This widget is useful when a program lets you open or save files or directories. It reads a directory and displays the contents. You can also use the widget to navigate a filesystem and choose your 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 pointer 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:
The widget has two main modes of operation:
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 can also 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 is 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 contain the name, size, and date information in the proper columns, but your divider is 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 reread 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 for 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, 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. |
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, Pt_DEFAULT_PARENT, 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, Pt_DEFAULT_PARENT, 3, args); ...
To display a single level of directories with a “..” item 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, Pt_DEFAULT_PARENT, 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, Pt_DEFAULT_PARENT, 3, args); ...
To show only hidden files (that is, those whose name begins with a “.” and aren'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, Pt_DEFAULT_PARENT, 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:
Here's a full PtFileSel example:
#include <stdio.h> #include <stdlib.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) { PtExit(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]; char const *btns[] = { "&OK" }; item = PtFSGetCurrent(fs); if (item == NULL) return(Pt_CONTINUE); strcpy(buffer, "The selected file is\n"); strcat(buffer, item->fullpath); PtAlert( window, NULL, "Selected File", NULL, buffer, NULL, 1, btns, NULL, 1, 1, Pt_MODAL ); return (Pt_CONTINUE); } /* State callback, will use the reason to block the widget for large directory opens. */ int state_cb( PtWidget_t *widget, void * data, 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, void * data, PtCallbackInfo_t *info) { PtBkgdHandlerProcess(); return (Pt_CONTINUE); } int main(void) { PtArg_t args[10]; PtCallback_t cb, cb2; PhDim_t win_dim = { 300, 300 }; PhArea_t area; if (PtInit(NULL) == -1) exit(EXIT_FAILURE); /* Make the main window. */ PtSetArg( &args[0], Pt_ARG_WINDOW_TITLE, "PtFileSel Demo", 0 ); PtSetArg( &args[1], Pt_ARG_DIM, &win_dim, 0 ); if ((window = PtCreateWidget(PtWindow, Pt_NO_PARENT, 2, args)) == NULL) PtExit(EXIT_FAILURE); /* 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(); return (EXIT_SUCCESS); }
Resource | C type | Pt type | Default |
---|---|---|---|
Pt_ARG_FS_FILE_SPEC | char * | String | "*" |
Pt_ARG_FS_FLAGS | unsigned long | Flags | Pt_FS_SHOW_DIRS | Pt_FS_SHOW_FILES |
Pt_ARG_FS_FORMAT | char * | String | n |
Pt_ARG_FS_IMAGES | PhImage_t *, short | Array | PFM-style images (write-only) |
Pt_ARG_FS_LBL_DATE | char * | String | "Date" |
Pt_ARG_FS_LBL_GROUP | char * | String | "Group" |
Pt_ARG_FS_LBL_NAME | char * | String | "Name" |
Pt_ARG_FS_LBL_OWNER | char * | String | "Owner" |
Pt_ARG_FS_LBL_PERMISSIONS | char * | String | "Permissions" |
Pt_ARG_FS_LBL_SIZE | char * | String | "Size" |
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 |
C type | Pt type | Default |
---|---|---|
char * | String | "*" |
A string that you can use to limit the files listed, by specifying a pattern that the filenames must match. The default is *, but you can use 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).
C type | Pt type | Default |
---|---|---|
unsigned long | Flags | Pt_FS_SHOW_DIRS | Pt_FS_SHOW_FILES |
Flags that control the appearance and behavior of the file selector:
If the Pt_FS_NO_ROOT_DISPLAY and Pt_FS_SINGLE_LEVEL flags are both set, the Pt_FS_NO_ROOT_DISPLAY flag is ignored. |
C type | Pt type | Default |
---|---|---|
char * | String | n |
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);
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):
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]; /* 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. |
C type | Pt type | Default |
---|---|---|
char * | String | "Date" |
The label used for the column that displays the files' modification dates.
C type | Pt type | Default |
---|---|---|
char * | String | "Group" |
The label used for the column that displays the group for the owner of the files.
C type | Pt type | Default |
---|---|---|
char * | String | "Name" |
The label used for the column that displays the names of the files.
C type | Pt type | Default |
---|---|---|
char * | String | "Owner" |
The label used for the column that displays the owners of the files.
C type | Pt type | Default |
---|---|---|
char * | String | "Permissions" |
The label used for the column that displays the permissions for the files.
C type | Pt type | Default |
---|---|---|
char * | String | "Size" |
The label used for the column that displays the sizes of the files.
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.
C type | Pt type | Default |
---|---|---|
char * | String | NULL |
The root directory for the file selector. The default value is NULL or none.
The widget stores the actual path obtained via the realpath() function (see the QNX Neutrino Library Reference). For example, if you set this resource to ///home//fred/.././fred/src, the widget actually sets it to /home/fred/src or /fs/hd0-qnx4/home/fred/src (if home is a link to /fs/hd0-qnx4/home).
Setting Pt_ARG_FS_ROOT_DIR to NULL clears the PtFileSel directory tree, and setting it to "." loads the current working directory.
C type | Pt type | Default |
---|---|---|
PtCallback_t * | Link | NULL |
A list of PtCallback_t structures that define the 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. This gives you a chance to translate any non-UTF-8 filenames into UTF-8 strings. It's also useful for handling pending Photon events.
Each callback is passed a PtCallbackInfo_t structure that contains at least the following members:
For the Pt_FS_NEW_ITEM reason subtype, cbdata points to a structure of type PtFileSelBkgdCallback_t, which contains at least:
If this callback returns Pt_END, the item isn't added. If you want to make sure that the widget correctly displays filenames that aren't encoded in UTF-8, you can use PxTranslate... functions to translate them, 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) { PtFileSelBkgdCallback_t *it = (void *) info->cbdata; if (info->reason_subtype == Pt_FS_NEW_ITEM) { int srctaken = 0, dstmade = 0; char dst[NAME_MAX * 3]; /* 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, sizeof(dst)-1, &dstmade) == 0) { dst[ dstmade ] = '\0'; strcpy(it->name, dst); } else /* Can't translate to UTF-8 -- let's just ignore this file... */ return Pt_END; } PtBkgdHandlerProcess(); return(Pt_CONTINUE); }
C type | Pt type | Default |
---|---|---|
PtCallback_t * | Link | NULL |
A list of PtCallback_t structures that define the callbacks invoked when you select an item. Each callback is passed a PtCallbackInfo_t structure that contains at least the following members:
These callbacks should return Pt_CONTINUE.
C type | Pt type | Default |
---|---|---|
PtCallback_t * | Link | NULL |
A list of PtCallback_t structures that define the callbacks invoked when an item is expanded or collapsed. Each callback is passed a PtCallbackInfo_t structure that contains at least the following members:
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. |
These callbacks should return Pt_CONTINUE.
If the widget modifies an inherited resource, the “Default override” column indicates the new value. This modification affects any subclasses of the widget.
For Pt_CB_DND callbacks for a PtList, the cbinfo->cbdata is a pointer to a PtTreeDndCallback_t structure, containing at least the following members:
The PtFileSel widget defines the following convenience functions that make it easier to use the file selector once it's been created: