'Open Recent' most recently used files MRU menu, all OS

Share your advanced PureBasic knowledge/code with the community.
User avatar
Keya
Addict
Addict
Posts: 1891
Joined: Thu Jun 04, 2015 7:10 am

'Open Recent' most recently used files MRU menu, all OS

Post by Keya »

A simple but seemingly effective MRU menu, all OS. I don't know if there are existing examples of this but i finished it before i started to wonder if anybody else has made one. Probably should search first next time.

Image

Basic properties:
- Opening a new file (not in the MRU list) will insert it at the top of the MRU list.
All other items are therefore moved down the list order.
- If the list is full the last item is dropped off/deleted.
- Clicking on an existing item in the list moves it to the top of the list.
Other items are moved but no item is dropped.
- For unused items, there is no HideMenuItem available but DisableMenuItem still gets the job done.
For this reason the size of the list must be fixed/predefined.
Menus are undisabled as the MRU list 'grows' as new files are added to the list.

Ive just used 5 MRU slots for this demo but its trivial to expand by simply adding more "#mnuRecentFile_n_"'s and ensuring #MRU_LAST is correct.

MRUmenu.pbi

Code: Select all

Enumeration FormMenu
  #mnuRecentFile0
  #mnuRecentFile1
  #mnuRecentFile2
  #mnuRecentFile3
  #mnuRecentFile4 ;To have more slots simply make more #mnuRecentFileN's. Nothing else to do.
  #MRU_LAST
EndEnumeration

Global hMRUMenu
Global NewList MRUList.s()

Declare MRU_cbOpenProc(File$, fromMRU)


Procedure MRU_ResetMenus()
  Protected nextmenu
  ResetList(MRUList())
  For i = #mnuRecentFile0 To #MRU_LAST-1
    If NextElement(MRUList())
      File$ = MRUList()
    Else
      File$ = "<empty>"
    EndIf
    nextmenu+1
    SetMenuItemText(hMRUMenu, i, "#"+Str(nextmenu)+". " + File$)    
  Next i
EndProcedure


Procedure MRU_SelectFile(idx)
  SelectElement(MRUList(), idx)
  File$ = MRUList()
  MoveElement(MRUList(), #PB_List_First)
  MRU_ResetMenus()
  Debug "Open MRU file: " + File$
  MRU_cbOpenProc(File$, 1)
EndProcedure


Procedure MRU_MenuEvent()
  Protected menu = EventMenu()
  MRU_SelectFile(menu - #mnuRecentFile0)
EndProcedure


Procedure MRU_AddMenu(hMenu)  
  hMRUMenu=hMenu
  OpenSubMenu("Recently Used")
  For i = #mnuRecentFile0 To #MRU_LAST-1
  MenuItem(i, "")
  Next i
  CloseSubMenu()
  MRU_ResetMenus()
  For i = #mnuRecentFile0 To #MRU_LAST-1
    DisableMenuItem(hMRUMenu, i, 1)
    BindMenuEvent(hMRUMenu, i, @MRU_MenuEvent())
  Next i
EndProcedure


Procedure MRU_AddFile(File$)
  ;// Check existing
  If ListSize(MRUList())    
    ResetList(MRUList())
    NextElement(MRUList())
    LFile$ = LCase(File$)
    ForEach MRUList()
      If LCase(MRUList()) = LFile$
        Debug "- File already in MRU. Moving to top of list."
        MRU_SelectFile(ListIndex(MRUList()))
        ProcedureReturn 0
      EndIf        
    Next
  EndIf  
  ;// Add new
  If ListSize(MRUList()) = (#MRU_LAST-1 - #mnuRecentFile0) + 1
    Debug "- New file, but MRU list is full. Removing oldest file, inserting newest at top"
    SelectElement(MRUList(), ListSize(MRUList())-1)
    DeleteElement(MRUList())
    SelectElement(MRUList(),0)
    InsertElement(MRUList())
  Else
    Debug "- New file. Inserting at top, moving other files down one to grow the MRU list."
    SelectElement(MRUList(),0)
    InsertElement(MRUList())
    DisableMenuItem(hMRUMenu, #mnuRecentFile0 + ListSize(MRUList())-1, 0)
  EndIf  
  MRUList() = File$
  MRU_ResetMenus()
  MRU_cbOpenProc(File$, 0)
EndProcedure

Demo.pb

Code: Select all

;To use:
;1) add a Callback function: MRU_cbOpenProc(File$, fromMRU)
;2) call MRU_AddMenu() when building your dialog's menu
;3) call MRU_AddFile() to add to MRU list

Enumeration FormWindow
  #Dlg1
EndEnumeration

Enumeration FormMenu
  #mnuOpen
  #mnuExit  
EndEnumeration

XIncludeFile("MRUmenu.pbi")


Procedure MRU_cbOpenProc(File$, fromMRU)  ;<### 1 -----------------
  MessageRequester("Open File",File$+Chr(10)+"Already on MRU: " + Str(fromMRU))
EndProcedure



Procedure OpenDlg1(x = 0, y = 0, width = 400, height = 304)
  OpenWindow(#Dlg1, x, y, width, height, "Recently Used File Menu", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  hMainMenu = CreateMenu(#PB_Any, WindowID(#Dlg1))
  MenuTitle("File")
  MenuItem(#mnuOpen, "Open")
  MenuBar()
  MRU_AddMenu(hMainMenu)                    ;<### 2 -----------------
  MenuBar()
  MenuItem(#mnuExit, "Exit") 
EndProcedure



Procedure mnuOpen(evt)
  ;Normally an OpenFileRequester, but for this demo...
  Static Nextfile
  Nextfile+1
  File$ = "c:\File-"+Str(Nextfile)+".txt"
  Debug "Open file: " + File$
  MRU_AddFile(File$)                       ;<### 3 -----------------
EndProcedure


Procedure Dlg1_Events(event)
  If event = #PB_Event_Menu
    evtmenu = EventMenu()
    Select evtmenu
      Case #mnuOpen
        mnuOpen(evtmenu)          
      Case #mnuExit
        End         
    EndSelect
  EndIf
  ProcedureReturn #True
EndProcedure


OpenDlg1()

Repeat
  Define event.i = WaitWindowEvent()
  Dlg1_Events(event)
Until event = #PB_Event_CloseWindow
End
Last edited by Keya on Sat Mar 11, 2017 10:45 pm, edited 2 times in total.
davido
Addict
Addict
Posts: 1890
Joined: Fri Nov 09, 2012 11:04 pm
Location: Uttoxeter, UK

Re: 'Open Recent' most recently used files MRU menu, all OS

Post by davido »

@Keya,
I haven't seen a solution to 'Recent Menu' before.
You've found a very nice simple solution. 8)
I will find it very useful. Thank you for sharing. :D
DE AA EB
User avatar
Keya
Addict
Addict
Posts: 1891
Joined: Thu Jun 04, 2015 7:10 am

Re: 'Open Recent' most recently used files MRU menu, all OS

Post by Keya »

thanks for encouraging words! :)
Ive just updated it to make it properly modular - the demo and the dialog are now completely separated from the MRU.pbi, as they should be
User avatar
OldSkoolGamer
Enthusiast
Enthusiast
Posts: 148
Joined: Mon Dec 15, 2008 11:15 pm
Location: Nashville, TN
Contact:

Re: 'Open Recent' most recently used files MRU menu, all OS

Post by OldSkoolGamer »

Nice!! I was just in the middle of doing my own solution when I decided to search the forums and found yours. Much more elegant and simple than my monstrosity. Thanks for the code,definitely gonna use it n my project.
Post Reply