^ What's the point?
^ Usage
^ Functions

Download :: Topics on this subject on the Forum :: Top
Skeez

Skeez is an animated list view component for Delphi (Win32, Win64) based on Graphics32 and a native FireMonkey component.
The package includes derived components: filesystem browser, picture list viewer and audio file list viewer.

Features:
  • Animated list view (add, refresh, delete, move)
  • Support for multi-line text with expandable height
  • Hot track, hint, scroll to/select item on keypress, edit item's caption
  • Re-draw existing item (partially) with optional animation
  • Multi-column mode
  • Custom sort the list
  • Built-in animations: XY, Zoom, FadeIn, or implement custom animation with an event
  • Filesystem browser with full support for virtual objects (PIDLs) and shell change notifications
  • Picture (thumbnail) list viewer class, uses FreeImage.dll for loading many formats of picture files and displays their EXIF information if available
  • Audio (tag) list viewer class with support for all the current audio tag standards
  • Fully customizable display with support for variable item height within the same list
  • FMX version supports any kind and number of sub-controls for items, like checkboxes, radio buttons or comboboxes etc.
  • The derived classes support browsing the file system or items can be added manually
  • Multi threaded derived classes

The audio list view component uses Tags Library, the used Delphi tagging libraries are also available separatelly:

ID3v1 and ID3v2 tagging unit: ID3v2 Library
MP4 tagging unit: MP4 Tag Library
APEv2 tagging unit: APEv2 Library
Ogg Vorbis and Opus tagging unit: Ogg Vorbis and Opus Tag Library
Flac tagging unit: Flac Tag Library
WMA tagging unit: WMA Tag Library
WAV tagging unit: WAV Tag Library

If you have any question, please write to: 3delite@3delite.hu



Skeez in shareware and commercial software?

The component is free for use in free software. If you like it and use it in a shareware or commercial (or any other money making - advertising, in app. selling, etc.) product you need one of the licenses.


Requirements

Delphi 2009 and above with Graphics32. There is a Delphi 7 version of the basic TSkeez class in the package too.
The filesystem and it's derived classes require Windows Vista or above.

The FireMonkey version (beta) is completely based on FireMonkey, no Graphics32 is needed at all.
Limitations in the current beta version:
  • 'BackgroundColor' is enabled by default, if you want to use styles disable {$DEFINE USEBACKGROUND} in FMX.Skeez.pas.
  • Drag & drop support for TSkeezFilesystem class (Windows only) supports only dropping items into the component area (and supports dropping into folders too) and droping within the same Skeez component, but dropping files and folders from Skeez to other apps does not work. It seems maybe Delphi FMX implementation is not complete, the DragObject.FileNames variable is populated properly (I think) but other app windows show a no-no for accept. FMX.Skeez.pas line 1870. Suggestions are welcome!
  • TSkeezFilesystem and derived classes TSkeezAudios and TSkeezPicures class requires FreeImage.dll (FMX.TBitmap is no thread safe it seems, and graphic processing is needed in worker threads for a smooth animation in the main thread).

Installation

If Graphics32 is not already installed, it's recommended to install it - although it's not needed to install it for Skeez to compile, it's enough to have the Graphics32 units on the search path. But Graphics32 is a great component you might want to decide to use it.

Extract the .zip archives ('bass24.zip', 'graphics32-code-2197-trunk.zip' and 'KleverComponents.zip') from where you installed/extracted Skeez files to a folder.

Create a new package, menu: File/New/Package - Delphi, save it with a new name, menu: File/Save Project As.... for example 'PackageSkeez.bpl'. On the upper-right corner of the Delphi window right mouse click on the package name you saved as, and click on 'Add' from the pop-up menu and add 'Skeez.pas', 'SkeezFilesystem.pas', 'SkeezPictures.pas' and optionally 'SkeezAudios.pas' and 'MultiThread2.pas' and 'Skeez.dcr' for the icon.
Add the directories to the tagging libraries ('..\Delphi\Tagging Libraries\APEv2 Library\' etc.) and all required .pas files to the search path too - Menu: Project/Options, select 'Delphi compiler', in the upper part of the window select 'All configuration', below click on 'Search path' and add the paths where you installed/extracted Skeez.
Right mouse click again on the package name and select 'Build', if successfull, again right mouse click and select 'Install'.

Note: If you get a package build error, comment out '{$DEFINE COMDRAGDROP}' in SkeezFilesystem.pas when building the package. If the build is successfull save the package and enable this compiler directive again - it should work for a real build.

If everything went smooth the components will show up on the '3delite' tab.

To be able to build the tutorials create a new package, as described above, and this time add 'rkShellPath.pas' and 'rkPathViewer.pas' to the package and use a different package name for example 'Packagerk.bpl'.
Build and install it too.

If everything went smooth the components will show up on the 'rmklever' tab.

To install the FireMonkey version do the same as described above, add 'FMX.Skeez.pas', 'FMX.SkeezFilesystem.pas', 'FMX.SkeezPictures.pas' and optionally 'FMX.SkeezAudios.pas' and 'MultiThread2.pas' and 'FMX.Skeez.dcr' (for the icon) to the new package, just create a different package name. Note that it's not yet supported to install both VCL and FMX versions, so choose only one version.


Properties and methods
  • TSkeez.Items: List containing the TSkeezItem items. When changing this list by code after finished call 'ReIndexItems' and to update the display 'UpdateDisplay(True)'.

  • TSkeez.Selected: The currently selected item. When multiple items are selected, this is the last, recently, selected item.

  • TSkeez.MultiColumnCount: If 'MultiColumn' is True, items are drawn side-by-side if the display width is large enough for multiple columns. For example for 2 multi columns the needed space is HorizontalMargin * 2 + Item's total width for all the columns. Multi columns and item columns are 2 separate things. Columns specify an item's text and picture positions, while multi column specify to allow to draw the items horizontally side-by-side if enough space is available.

  • TSkeez.CurrentListingID: This number is incremented on every 'IncrementListingID' call. It us used to identify a listing, needed when for example navigating folders and icons are extracted in another thread, if the user navigates to another folder Skeez will not add the icons arriving after the navigation because the 'CurrentListingID' is not valid for the icon arriving.

  • TSkeez.ImageList: Array containing images that are meant to be re-used for multiple items. Add TBitmap32 pictures to this list and to use these images in the SkeezItem.AddPicture() calls' 'ImageListIndex' variable:
    				with SkeezItem.AddPicture(nil) do begin
    					Position.X := 0;
    					Position.Y := 0;
    					ImageListIndex := 1;
    				end;
    	
  • TSkeez.ParseInQueue: It's essential to call this procedure periodically. Internally Skeez will parse the added 'TSkeezItem's with 'InQueue.Add(SkeezItem)'. 'InQueue.Add()' is a thread safe function (so it's fine to call it in threads), and in the main thread where this function is called will process (parse) the items added with 'InQueue.Add(SkeezItem)'. 'ItemParseMode' specifies how many items to parse for a single 'ParseInQueue' call. 'sipmOne' means one item on every call, which results linear animation, the items will move one by one with a delay how frequently 'ParseInQueue' is called. 'sipmAll' will process all items in the incomming queue, results faster displaying of the items but items will move together in parallel.

  • TSkeez.UpdateDisplay: Update all the items (advance one frame). You need to call this function to update the display (animate) at at least 33ms intervals (FPS = 1000 / interval). If an item is not changed it will not be updated, to force re-drawing all the items call this function with 'UpdateDisplay(True)' - for example if you change the order of items in the 'TSkeez.Items' list.

  • TSkeez.ItemAtPos: Use this function to get the 'TSkeezItem' at the specified position. X and Y is relative to the TSkeez objects top-left corner.

  • TSkeez.Sort: Sort the items with the specified 'OnItemCompare' event. Use the 'Item.Data' class to perform the comparison. This object will be for example 'TSkeezAudioData(Item.Data).FileName' for the audio lister class, 'TSkeezFileData(Item.Data).FileName' for the file system browser component, or the one you added to 'SkeezItem.Data' when adding the skeez items. You should inherit from these types when using the picture and audio component and add your fields to it - this way Skeez will still be able to use these objects like identifying whether it's a folder or a file.

  • TSkeez.ReIndexItems: If you modify the 'TSkeez.Items' list, call this function to re-index the items, then call 'UpdateDisplay(True)'.

Published properties
  • AllowEdit: Enable possibility of editing the first text item of a Skeez item. Can be invoked from code with Skeez1.Edit(Index) or with middle mouse button clicking on an item. Notification of an edit is available with the OnItemEdit() event.

  • AllowHotTrack: Enable to mark the item below the mouse cursor. Use 'ItemHotTrackOptions' to specify the hot tracking colors and alpha value.

  • AllowKeySelect: If True and the Skeez control has focus, pressing a key on the keyboard scrolls to and selects the first item which matches the character (first text item's first character). If another key is pressed in 2 seconds, the first 2 characters are searched.

  • AllowMultiSelect: More than 1 item can be selected by holding down the Shift or Ctrl key and clicking with the left mouse button on items.

  • AllowSelect: Enable to select the item with the mouse cursor and keyboard cursor keys. Use 'ItemSelectionOptions' to specify the selection colors and alpha value.

  • AnimationExpandCollapseTime: Specify how long does an expand or collapse animation take when expanding multi-line texts.

  • AnimationPictureTime: Specify the picture moving time in milliseconds.

  • AnimationPictureX: Specify the pixel count from where the picture start to move.

  • AnimationTextTime: Specify the text moving time in milliseconds.

  • AnimationTextX: Specify the pixel count from where the text start to move.

  • BackgroundColor: Specify the display's background color.

  • HintHideTime: Specifies how long to display a hint. Implement OnItemHint() event to hide the hint.

  • HintShowTime: Specifies how long the mouse cursor needs hovered above an item to pop-up a hint. Implement OnItemHint() event to show the hint.

  • ItemAudioProperties / ItemFileProperties / ItemPictureProperties: Specify the properties of the items. 'ItemFileProperties' always specifies the file items' properties including when using the picture and audio lister. One of the important values is the 'ItemHeight' variable, which specifies the height of the items. Note that you can always specify a custom (item-by-item different) height when adding the TSkeezItems to the queue. File items and picture/audio items will have the same item width though. Use Icon/Picture/CoverArt to specify these pictures' dimensions on the display.

  • ItemHotTrackOptions: Specify the hot track colors and alpha value ('AllowHotTrack' needs to be 'True').

  • ItemSelectionOptions: Specify the selection colors and alpha value ('AllowSelection' needs to be 'True').

  • ItemParseMode: Specifies how many items to parse for a single 'ParseInQueue' call. 'sipmOne' means one item on every call, which results linear animation, the items will move one by one with a delay how frequently 'ParseInQueue' is called. 'sipmAll' will process all items in the incomming queue, results faster displaying of the items but items will move together in parallel.

  • MarginHorizontal: The padding (space) between the display's left side and the items. Also the margin on the right side of the display.

  • MarginVertical: The padding (space) between the display's top and the items. Also the margin at the bottom of the display below the last item.

  • MultiColumn: If 'MultiColumn' is True, items are drawn side-by-side if the display width is large enough for multiple columns. For example for 2 multi columns the needed space is HorizontalMargin * 2 + Item's total width for all the columns. Multi columns and item columns are 2 separate things. Columns specify an item's text and picture positions, while multi column specify to allow to draw the items horizontally side-by-side if enough space is available.

  • MultiColumnCompact: Only has effect if 'MultiColumn' is True, items in one column are compacted vertically, that is every item appears right under the one above. If this flag is not set every item is lined up with the items on the left and on the right to it. Selecting items with cursor keys and methods 'MoveCursorUp' etc. selects the item explicitly to the left/right/above/below.

  • MultiThreaded: For the derived components, this value specifies to use multi threading for loading of the icon/picture/cover art pictures. If this is 'False' these pictures will be parsed in the main thread, which means if the CPU is not powerfull enough the animation will be jerky, but linear. It is recommended to always use multi-threading, for your implementation too.

  • OnlyFilesystem: When browsing folders display only file system items (folders and files).

  • ItemSpacingX and ItemSpacingY: The empty space between items. Left most item appears only by the 'MarginHorizontal' value, top most items appear only by 'MarginVertical'. These values only specify space between items.

Events
  • OnAddItem: Called when adding an item to the list, usefull for adding any custom text and pictures when using the file system/picture/audio components. You can add a column (about it later) and add custom informatiom. For example:
                with DisplayItem.AddText('My text') do begin
                    Position.X := 5;
                    Position.Y := 5;
                    ColumnIndex := 2;
                end;
    

  • OnCanAdd: Implement this event to filter what files are added to the list in case of the picture and audio component. Set 'Add' to False to not list the file.

  • OnFileSelect: If the user double-clicks an item which is not a folder this event is called.

  • OnFolderChange: Notification on going into a folder.

  • OnGetAudioAttributes: For the audio component implement this event to display the audio file's attributes like sample rate, channel count, etc.

  • OnItemCompare: When calling 'TSkeez.Sort' the items with the specified 'OnItemCompare' event will be sorted. Use the 'Item.Data' class to perform the comparison. This object will be for example 'TSkeezAudioData (Item.Data).FileName' for the audio lister class, 'TSkeezFileData(Item.Data).FileName' for the file system browser component, or the one you added to 'SkeezItem.Data' when adding the skeez items. You should inherit from these types when using the picture and audio component and add your fields to it - this way Skeez will still be able to use these objects like identifying whether it's a folder or a file.

  • OnItemEdit: If AllowEdit is True, after editing an item's first text item when user presses Enter this event is called. Set 'Allow' to False te reject the modification.

  • OnItemFree: Called when freeing an item. Implement clean-up of an item's 'Data' if needed.

  • OnItemHint: This event is called when a hint needs to show (Show = True) or needs to hide (Show = False).

  • OnItemHot: If 'AllowHotTrack' is True get notification when an item becomes hot.

  • OnItemSelect: Happens when the user selects an item with mouse clicking on it, or with the cursor keys (not double-click, that is OnFileSelect).

  • OnLayerDrawAfter / OnLayerDrawBefore: It's possible to draw on the TBitmap32 pictures that Skeez generates from TSkeezItems' text and picture lists with this event.

  • OnNeedDataClass: To extend the standard description object for a file item implement this event. Inherit from default class, in case of the file system list component: 'TSkeezFileData', for the picture list: 'TSkeezPictureData' and for the audio list from 'TSkeezAudioData' and in this event create your class for the 'Data' parameter.
    Example for 'TSkeezFilesystem':
    	type
    	    TMyData = class(TSkeezFileData)
    	        MyField: String;
    	    end;
    
    	procedure TForm1.SkeezListNeedDataClass(Sender: TObject; PIDL: PItemIDList; FileName: string; var Data: TSkeezFileData);
    	begin
    	    Data := TMyData.Create;
    	end;
    
    Now this new data can be accessed from a TSkeezItem, with:
    	    (Item.Data as TMyData).MyField
    
    or everywhere when you get a 'TSkeezFileData' type object:
        (FileData as TMyData).MyField
    

Tips
  • It is a good idea to prepare the item data in separate thread(s) with a lower priority then the main thread and use the main thread just for the UI.
    Load the data in a thread and with Skeez1.InQueue.Add(SkeezItem) send it to Skeez. The main UI thread will process this in the main thread when ParseInQueue is called which results smooth animations.
    One can easily implement multi threading with the included TMultiThread2 class (see the implementation in TSkeezFilesystem, TSkeezPictures or TSkeezAudios).

  • To add custom text or pictures to an item, use the OnAddItem() event, for example:
    with SkeezItem.AddText('My text') do begin
        Font.Size := 10;
        Position.X := 6;
        Position.Y := 6;
        ColumnIndex := 2;
    end;
    
    with SkeezItem.AddPicture(Bitmap32) do begin
        Position.X := 4;
        Position.Y := 6;
        //* This will use the 'Position' values, else the picture will be centered in it's column
        Align := paCustom;
    end;
    
  • By default 2 columns are created: first one for the icon/picture, second for the text. To add columns use:
    var
        Column: TSkeezColumn;
    begin
        //* Basic data
        Column := TSkeezColumn.Create;
        Column.Caption := 'Data';
        Column.Width := 350;
        Skeez1.Columns.Add(Column);
    end;
    
  • To update a text (or picture) of an existing item already in the list, send 'TSkeezItemText', 'TSkeezItemTextMultiLine' or 'TSkeezItemPicture' with 'InQueue.Add()'.
    There are 2 options: if you specify 'Index := - 1' then the object will be added, if you specify an existing object 'Index > - 1' (and exists) the text/picture will be replaced. Parent and ParentGUID are always needed to identify which item is to be updated. If you work in thread NEVER access the 'Work.ParentSkeezItem' fields, it could be freed in the mean time if the user navigated to another folder/list, just use it as identification (the pointer and the GUID) for the item to be updated. Extract from SkeezPictures.pas - PictureLoaderThreadWorkerCallback():
        //* Send the loaded picture to Skeez
        SkeezItemPicture := TSkeezItemPicture.Create;
        //* This needs to be a TSkeezItem which will be updated
        SkeezItemPicture.Parent := Work.ParentSkeezItem;
        //* This needs to be a TSkeezItem's GUID which will be updated
        SkeezItemPicture.ParentGUID := Work.ParentSkeezItemGUID;
        //* Use current ListingID, else this update will be
        //* discarded (list changed in the mean time)
        SkeezItemPicture.ListingID := Work.ListingID;
        SkeezItemPicture.Bitmap := Picture; //* The new picture
        Params.SkeezPictures.InQueue.Add(SkeezItemPicture);
    
        //* Send the original dimensions text to Skeez
        SkeezItemText := TSkeezItemText.Create;
        SkeezItemText.Parent := Work.ParentSkeezItem;
        SkeezItemText.ParentGUID := Work.ParentSkeezItemGUID;
        SkeezItemText.ListingID := Work.ListingID;
        //* The new text
        SkeezItemText.Text := IntToStr(OriginalWidth) + ' x ' + IntToStr(OriginalHeight);
        //* The 'TSkeezItemText' index in TSkeezItem.TextItems[Index] that you want to update
        SkeezItemText.Index := 2;
        //* This means the new text will be animated "in"
        SkeezItemText.AnimState := asStarting;
        Params.SkeezPictures.InQueue.Add(SkeezItemText);
    
  • Columns and column header: There's a TSkeez.Columns[] TList which holds the columns, the order specifies the order in which the columns are displayed. Each TColumn in this list has an 'Index' property which identifies the column, use this index in item's text and graphic items to specify in which column they appear. Make sure to not use the same 'Index' for multiple columns.
    To display a column listed ascending/descending add a unicode "up arrow/down arrow" to it's caption: http://unicode-table.com/hu/sets/arrows-symbols/
    When changing column stuff if there are problems call TSkeez.ColumnHeader.Update to re-draw the column headers.
    Do not set the columns 'MinWidth' too low - it needs to be at least '...' characters' width or the code will go into and endless loop if that doesn't fit.

    To use a background picture use:
        Skeez1.Display.Bitmap.LoadFromFile('C:\Picture.bmp');
    
    To adjust the background picture appearance use:
        Skeez1.Display.ScaleMode := smStretch;
    
    Check the 'ScaleMode' options for more modes.

  • When using Delphi's VCL styles use the following code to adjust the colors on style change (TSkeezFilesystem example):
    Uses
        GR32,
        Vcl.Themes,
        Vcl.Styles;
    
    procedure UpdateSkeezStyle(SkeezFilesystem: TSkeezFilesystem);
    var
        BackgroundColor: TColor;
        ListerFontColor: TColor;
        ColumnHeaderTopColor: TColor;
        ColumnHeaderBottomColor: TColor;
        ColumnHeaderFontColor: TColor;
        ColumnHeaderBrightColor: TColor;
        ColumnHeaderDarkColor: TColor;
        LStyle: TCustomStyleServices;
        Item: TSkeezItem;
        i, k: Integer;
    begin
        //* Style enabled?
        LStyle := StyleServices;
        if LStyle.Enabled
        AND (TStyleManager.ActiveStyle.Name <> 'Windows')
        then begin
            //* Get the current style's colors
            ColumnHeaderTopColor := LStyle.GetStyleColor(scGenericGradientBase);
            ColumnHeaderBottomColor := LStyle.GetStyleColor(scGenericGradientEnd);
            ColumnHeaderBrightColor := ColumnHeaderTopColor;
            ColumnHeaderDarkColor := ColumnHeaderBottomColor;
            ColumnHeaderFontColor := LStyle.GetStyleFontColor(sfHeaderSectionTextNormal);
            BackgroundColor := TStyleManager.ActiveStyle.GetStyleColor(scListView);
            ListerFontColor := TStyleManager.ActiveStyle.GetSystemColor(clWindowText);
        end else begin
            //* Set your default Windows style colors here (white theme used here)
            BackgroundColor := clWindow;
            ListerFontColor := clWindowText;
            ColumnHeaderTopColor := WinColor($FFFDFDFD);
            ColumnHeaderBottomColor := WinColor($FFBBBBBB);
            ColumnHeaderBrightColor := clWhite;
            ColumnHeaderDarkColor := WinColor($FFAAAAAA);
            ColumnHeaderFontColor := clWindowText;
        end;
        //* Set background color
        SkeezFilesystem.BackgroundColor := Color32(BackgroundColor);
        //* Set item text colors
        SkeezFilesystem.ItemFileProperties.FileName.Font.Color := ListerFontColor;
        SkeezFilesystem.ItemFileProperties.Size.Font.Color := ListerFontColor;
        SkeezFilesystem.ItemFileProperties.DateTime.Font.Color := ListerFontColor;
        SkeezFilesystem.ItemFileProperties.Description.Font.Color := ListerFontColor;
        //* Column header
        SkeezFilesystem.ColumnHeader.TopColor := Color32(ColumnHeaderTopColor);
        SkeezFilesystem.ColumnHeader.BottomColor := Color32(ColumnHeaderBottomColor);
        SkeezFilesystem.ColumnHeader.BrightColor := Color32(ColumnHeaderBrightColor);
        SkeezFilesystem.ColumnHeader.DarkColor := Color32(ColumnHeaderDarkColor);
        SkeezFilesystem.ColumnHeader.Font.Color := ColumnHeaderFontColor;
        SkeezFilesystem.DrawColumnHeaders;
        //* Redraw all items with new font color
        if SkeezFilesystem.Items.Count > 0 then begin
            for i := 0 to SkeezFilesystem.Items.Count - 1 do begin
                Item := SkeezFilesystem.Items[i];
                for k := 0 to Item.TextItems.Count - 1 do begin
                    Item.TextItems[k].Font.Color := ListerFontColor;
                end;
                for k := 0 to Item.TextMultiLineItems.Count - 1 do begin
                    Item.TextMultiLineItems[k].Font.Color := ListerFontColor;
                end;
                Item.ReDraw;
            end;
        end;
    end;
    
  • It's possible to modify the multi-line text expander/collapser icons by changing the SkeezIcons.res file. Using XN Resource Editor it's simple to edit the .res file, just use transparent PNG images and the same resource name for them. Or assign the pictures 'IconArrowDown', 'IconArrowUp', 'IconArrowDownHot' and 'IconArrowUpHot'.

  • Skeez supports scaling the whole display with a helper property: 'Scale'. Values is 1.0 by default which is 100%. To double the display use 2.0 for both values.
    Note that column widths are not resized because one might save/load the column widths manually.
    To use the Windows' DPI scaling support you can use the code:
        Skeez1.Scale := Screen.PixelsPerInch / 96;
        Skeez1.ColumnHeader.Font.Size := Trunc(8 * Skeez1.ScaleText);
    
    Picture items are also not resized automaticaly, as there is no copy of the pictures stored by Skeez. You have to give Skees pictures resized for your display.

  • FireMonkey version supports any kind and number of sub-controls for items, like checkboxes, radio buttons or comboboxes as standard by FireMonkey.
    There's a tutorial in the Skeez filesystem demo example on how to implement this.

Useful information


[Top]