[Previous] [Contents] [Index] [Next]

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:

PtFileSel button in PhAB

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.


PtFileSel


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:
short type
The type of file the item is:
short root
A value that indicates if this is the root item:
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.

Single-level file selector


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.


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

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

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

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.


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


Note: 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:
cbdata
A pointer to a PtFileSelCallback_t structure that contains:

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:

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.

Resource Inherited from Default override
Pt_ARG_ANCHOR_FLAGS PtContainer
Pt_ARG_ANCHOR_OFFSETS PtContainer
Pt_ARG_AREA PtWidget
Pt_ARG_BANDWIDTH_THRESHOLD PtBasic Not used by this class.
Pt_ARG_BALLOON_COLOR PtGenList
Pt_ARG_BALLOON_FILL_COLOR PtGenList
Pt_ARG_BITMAP_CURSOR PtWidget
Pt_ARG_BORDER_WIDTH PtWidget
Pt_ARG_BOT_BORDER_COLOR PtBasic
Pt_ARG_COLOR PtBasic
Pt_ARG_CONTAINER_FLAGS PtContainer
Pt_ARG_CURSOR_COLOR PtWidget
Pt_ARG_CURSOR_TYPE PtWidget
Pt_ARG_DATA PtWidget
Pt_ARG_DIM PtWidget
Pt_ARG_EFLAGS PtWidget Pt_CONSUME_EVENTS
Pt_ARG_FILL_COLOR PtBasic
Pt_ARG_FILL_PATTERN PtBasic
Pt_ARG_FLAGS PtWidget
Pt_ARG_HELP_TOPIC PtWidget
Pt_ARG_HIGHLIGHT_ROUNDNESS PtBasic
Pt_ARG_LIST_COLUMN_ATTR PtGenList
Pt_ARG_LIST_COLUMN_POS PtGenList
Pt_ARG_LIST_FLAGS PtGenList
Pt_ARG_LIST_FONT PtGenList
Pt_ARG_LIST_ITEM_COUNT PtGenList
Pt_ARG_LIST_SB_RES PtGenList
Pt_ARG_LIST_SCROLL_RATE PtGenList
Pt_ARG_LIST_SEL_COUNT PtGenList
Pt_ARG_LIST_TOTAL_HEIGHT PtGenList
Pt_ARG_MARGIN_HEIGHT PtBasic
Pt_ARG_MARGIN_WIDTH PtBasic
Pt_ARG_POS PtWidget
Pt_ARG_RESIZE_FLAGS PtWidget
Pt_ARG_SCROLLBAR_WIDTH PtGenList
Pt_ARG_SELECTION_FILL_COLOR PtGenList
Pt_ARG_SELECTION_MODE PtGenList
Pt_ARG_SELECTION_TEXT_COLOR PtGenList
Pt_ARG_TOP_BORDER_COLOR PtBasic
Pt_ARG_TOP_ITEM_POS PtGenList
Pt_ARG_TRANS_PATTERN PtBasic
Pt_ARG_TREE_FLAGS PtGenTree
Pt_ARG_USER_DATA PtWidget
Pt_ARG_VISIBLE_COUNT PtGenList
Pt_CB_ACTIVATE PtBasic
Pt_CB_ARM PtBasic
Pt_CB_BALLOONS PtContainer Not used by this class.
Pt_CB_BLOCKED PtWidget
Pt_CB_DESTROYED PtWidget
Pt_CB_DISARM PtBasic
Pt_CB_FILTER PtContainer
Pt_CB_GEN_TREE_INPUT PtGenTree
Pt_CB_GOT_FOCUS PtBasic
Pt_CB_HOTKEY PtWidget
Pt_CB_LOST_FOCUS PtBasic
Pt_CB_MENU PtBasic
Pt_CB_RAW PtWidget
Pt_CB_REALIZED PtWidget
Pt_CB_REPEAT PtBasic
Pt_CB_RESIZE PtContainer
Pt_CB_SCROLL_MOVE PtGenList
Pt_CB_UNREALIZED PtWidget

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.

[Previous] [Contents] [Index] [Next]