UserGuide - Structuring code in Procedures

We're going to revisit the file properties example again. This time to introduce procedures and to address some of the limitations identified in the program in previous items.
  ; The structure for file information as before.
  Structure FILEITEM
    Name.s
    Attributes.i
    Size.q
    DateCreated.i
    DateAccessed.i
    DateModified.i
  EndStructure
  
  ; This is a constant to identify the window.
  Enumeration
    #WindowFiles
  EndEnumeration
  
  ; This is an enumeration to identify controls that will appear on the window.
  Enumeration
    #FolderButton
    #UpdateButton
    #FolderText
    #FilesList
  EndEnumeration
  
  Procedure FilesExamine(Folder.s, List Files.FILEITEM())
    ; Obtains file properties from Folder into Files.
    
    Protected.l Result
    
    ; Clear current contents.
    ClearList(Files())
    
    ; Open the directory to enumerate its contents.
    Result = ExamineDirectory(0, Folder, "*.*")  
    
    ; If this is ok, begin enumeration of entries.
    If Result
      ; Loop through until NextDirectoryEntry(0) becomes zero - indicating that there are no more entries.
      While NextDirectoryEntry(0)
        ; If the directory entry is a file, not a folder.
        If DirectoryEntryType(0) = #PB_DirectoryEntry_File
          ; Add a new element to the list.
          AddElement(Files())
          ; And populate it with the properties of the file.
          Files()\Name = DirectoryEntryName(0)
          Files()\Size = DirectoryEntrySize(0)
          Files()\Attributes = DirectoryEntryAttributes(0)
          Files()\DateCreated = DirectoryEntryDate(0, #PB_Date_Created)
          Files()\DateAccessed = DirectoryEntryDate(0, #PB_Date_Accessed)
          Files()\DateModified = DirectoryEntryDate(0, #PB_Date_Modified)
        EndIf
      Wend
      
      ; Close the directory.
      FinishDirectory(0)
    EndIf
    
    ; Sort the list into ascending alphabetical order of file name.
    SortStructuredList(Files(), #PB_Sort_Ascending, OffsetOf(FILEITEM\Name), #PB_String)
  EndProcedure
  
  Procedure.s FolderSelect(Folder.s)
    ; Displays a path requester and returns the new path, or the old one if the requester is cancelled.
    Protected.s SelectedPath
    
    SelectedPath = PathRequester("Choose a folder.", Folder)
    
    If SelectedPath = ""
      SelectedPath = Folder
    EndIf
    
    ProcedureReturn SelectedPath
  EndProcedure
  
  Procedure LabelUpdate(Folder.s)
    ; Updates the folder label.
    SetGadgetText(#FolderText, Folder)
  EndProcedure
  
  Procedure ListLoad(ListView.l, List Files.FILEITEM())
    ; Load the files properties from list Files() into the list view #FilesList.
    Protected.s Access, Attrib, Create, Folder, Modify, Msg, Num, Size
    
    ; Remove previous contents.
    ClearGadgetItems(ListView)
    
    ForEach Files()
      ; Display the item number and file name.
      Num = StrU(ListIndex(Files()) + 1)
      
      ; These lines convert the three date values to something more familiar.
      Create = FormatDate("%dd/%mm/%yyyy", Files()\DateCreated)
      Access = FormatDate("%dd/%mm/%yyyy", Files()\DateAccessed)
      Modify = FormatDate("%dd/%mm/%yyyy", Files()\DateModified)
      
      ; Convert the file size to a padded string the same as with the index value above,
      ; but allow space for the maximum size of a quad.
      Size = StrU(Files()\Size)
      
      ; Convert the attributes to a string, for now.
      Attrib = StrU(Files()\Attributes)
      
      ; Build a row string.  
      ; The Line Feed character 'Chr(10)' tells the gadget to move to the next column.
      Msg = Num + Chr(10) + Files()\Name + Chr(10) + Create + Chr(10) + Access + Chr(10) + Modify + Chr(10) + Attrib + Chr(10) + Size
      
      ; Add the row to the list view gadget.
      AddGadgetItem(#FilesList, -1, Msg)
    Next Files()
  EndProcedure
  
  Procedure WindowCreate()
    ; Creates the wdwFiles window.
    Protected Flags
    
    ; This line defines a flag for the window attributes by OR-ing together the desired attribute constants.
    Flags = #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget| #PB_Window_TitleBar
    
    ; Open a window.
    OpenWindow(#WindowFiles, 50, 50, 450, 400, "File Properties", Flags)
    ; A button to choose a folder.
    ButtonGadget(#FolderButton, 5, 5, 100, 30, "Select Folder")
    ; A button to update the list.
    ButtonGadget(#UpdateButton, 112, 5, 100, 30, "Update List")
    ; A text gadget to show the name of the folder.
    TextGadget(#FolderText, 5, 40, 400, 25, "")
    ; A list icon gadget to hold the file list and properties.
    ListIconGadget(#FilesList, 5, 70, 400, 326, "#", 35)
    ; Add columns to the ListIconGadget to hold each property.
    AddGadgetColumn(#FilesList, 1, "Name", 200)
    AddGadgetColumn(#FilesList, 2, "Created", 100)
    AddGadgetColumn(#FilesList, 3, "Accessed", 100)
    AddGadgetColumn(#FilesList, 4, "Modified", 100)
    AddGadgetColumn(#FilesList, 5, "Attributes", 150)
    AddGadgetColumn(#FilesList, 6, "Size", 100)
  EndProcedure
  
  Procedure WindowDestroy()
    ; Closes the window.
    ; If necessary, you could do other tidying up jobs here too.
    CloseWindow(#WindowFiles)
  EndProcedure
  
  Procedure WindowResize()
    ; Resizes window gadgets to match the window size.
    ResizeGadget(#FolderText, #PB_Ignore, #PB_Ignore, WindowWidth(#WindowFiles) - 10, #PB_Ignore)
    ResizeGadget(#FilesList, #PB_Ignore, #PB_Ignore, WindowWidth(#WindowFiles) - 10, WindowHeight(#WindowFiles) - 74)
  EndProcedure
  
  ;- Main
  ; Now we define a list of files using the structure previously specified.
  NewList Files.FILEITEM()
  
  ; And some working variables to make things happen.
  Define.s Folder
  Define.l Event, EventWindow, EventGadget, EventType, EventMenu
  
  ; This function gets the home directory for the logged on user.
  Folder = GetHomeDirectory()
  
  ; Create the window and set the initial contents.
  WindowCreate()
  WindowResize()
  LabelUpdate(Folder)
  FilesExamine(Folder, Files())
  ListLoad(#FilesList, Files())
  
  ;- Event Loop
  Repeat
    ; Wait until a new window or gadget event occurs.
    Event = WaitWindowEvent()
    EventWindow = EventWindow()
    EventGadget = EventGadget()
    EventType = EventType()
    
    ; Take some action.
    Select Event
      Case #PB_Event_Gadget
        ; A gadget event occurred.
        If EventGadget = #FolderButton
          ; The folder button was clicked.
          Folder = FolderSelect(Folder)
          LabelUpdate(Folder)
          FilesExamine(Folder, Files())
          ListLoad(#FilesList, Files())
          
        ElseIf EventGadget = #UpdateButton
          ; The update button was clicked.
          FilesExamine(Folder, Files())
          ListLoad(#FilesList, Files())
          
        ElseIf EventGadget = #FolderText
          ; Do nothing here.
          
        ElseIf EventGadget = #FilesList
          ; Do nothing here.
          
        EndIf
        
      Case #PB_Event_SizeWindow
        ; The window was moved or resized.
        If EventWindow = #WindowFiles
          WindowResize()  
        EndIf
        
      Case #PB_Event_CloseWindow
        ; The window was closed.
        If EventWindow = #WindowFiles
          WindowDestroy()
          Break
          
        EndIf
    EndSelect
  ForEver
Previously, we mentioned four limitations to this program. This new version uses procedures to address three of them.

1) You couldn't choose a folder to show.
The "FolderSelect" procedure shows a path requester to allow the user to select a folder. The variable "Folder" is updated with the result of this procedure. The button also calls "LabelUpdate", "FilesExamine" and "ListLoad" to display the contents of the new folder in the window.

2) You can't update the list contents without closing and restarting the program.
Now, when the "Update List" button is clicked, "FilesExamine" and "ListLoad" are called again to update the display.

3) If you resize the window, the gadgets don't resize with it.
The "WindowResize" procedure is called in the event loop to resize the gadgets when the form is resized. Also, although this program didn't really need to, this procedure is called after calling "WindowCreate" to make sure the gadgets are the right size initially.

Notice how several of the procedures are called more than once to perform similar but not identical functions. This improves the efficiency of the program.

We have one final limitation to overcome in a later item.

UserGuide Navigation

< Previous: Displaying graphics output & simple drawing | Overview | Next: Compiler directives >