Skip to content

Commit 009721d

Browse files
committed
Window menu: a list of open images is now displayed...
...at the bottom of the Window menu. This basically duplicates the functionality of the "image tabstrip" PD provides, but for users who disable the tabstrip, they will still have a way to "jump" to any open image. This also mirrors similar functionality in Photoshop and GIMP. Thank you to G Busch for the suggestion!
1 parent a145c20 commit 009721d

File tree

6 files changed

+192
-36
lines changed

6 files changed

+192
-36
lines changed

Classes/pdRecentFiles.cls

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -229,9 +229,9 @@ Friend Sub UpdateUI_NonEmptyList()
229229
End If
230230

231231
'Ensure the special menus at the bottom of the Recent Files list are available
232-
FormMain.MnuRecentSepBar1.Visible = True
233-
FormMain.MnuLoadAllMRU.Visible = True
234-
FormMain.MnuClearMRU.Visible = True
232+
For i = 0 To FormMain.MnuRecentFiles.Count - 1
233+
FormMain.MnuRecentFiles(i).Visible = True
234+
Next i
235235

236236
'Update any relevant thumbnail icons. (TODO: ensure this isn't being called from multiple places.)
237237
IconsAndCursors.ResetMenuIcons
@@ -255,9 +255,10 @@ Friend Sub UpdateUI_EmptyList()
255255
End If
256256

257257
FormMain.MnuRecDocs(0).Enabled = False
258-
FormMain.MnuRecentSepBar1.Visible = False
259-
FormMain.MnuClearMRU.Visible = False
260-
FormMain.MnuLoadAllMRU.Visible = False
258+
259+
For i = 0 To FormMain.MnuRecentFiles.Count - 1
260+
FormMain.MnuRecentFiles(i).Visible = False
261+
Next i
261262

262263
'All icons in this menu need to be manually reset after the list is cleared; the ResetMenuIcons function
263264
' will also call the Menus.UpdateSpecialMenu_RecentFiles() function to set all captions properly.

Forms/MainWindow.frm

Lines changed: 56 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -65,14 +65,17 @@ Begin VB.Form FormMain
6565
Enabled = 0 'False
6666
Index = 0
6767
End
68-
Begin VB.Menu MnuRecentSepBar1
68+
Begin VB.Menu MnuRecentFiles
6969
Caption = "-"
70+
Index = 0
7071
End
71-
Begin VB.Menu MnuLoadAllMRU
72+
Begin VB.Menu MnuRecentFiles
7273
Caption = "Open all recent images"
74+
Index = 1
7375
End
74-
Begin VB.Menu MnuClearMRU
76+
Begin VB.Menu MnuRecentFiles
7577
Caption = "Clear recent image list"
78+
Index = 2
7679
End
7780
End
7881
Begin VB.Menu MnuFile
@@ -1762,6 +1765,17 @@ Begin VB.Form FormMain
17621765
Caption = "Previous image"
17631766
Index = 8
17641767
End
1768+
Begin VB.Menu MnuWindow
1769+
Caption = "-"
1770+
Index = 9
1771+
Visible = 0 'False
1772+
End
1773+
Begin VB.Menu MnuWindowOpen
1774+
Caption = "empty"
1775+
Enabled = 0 'False
1776+
Index = 0
1777+
Visible = 0 'False
1778+
End
17651779
End
17661780
Begin VB.Menu MnuHelpTop
17671781
Caption = "Help"
@@ -2088,6 +2102,33 @@ Private Sub MnuMacroCreate_Click(Index As Integer)
20882102
End Select
20892103
End Sub
20902104

2105+
Private Sub MnuRecentFiles_Click(Index As Integer)
2106+
2107+
Select Case Index
2108+
2109+
Case 0
2110+
'separator
2111+
2112+
'Load all MRU files
2113+
Case 1
2114+
Dim listOfFiles As pdStringStack
2115+
Set listOfFiles = New pdStringStack
2116+
2117+
Dim i As Long
2118+
For i = 0 To g_RecentFiles.GetNumOfItems() - 1
2119+
listOfFiles.AddString g_RecentFiles.GetFullPath(i)
2120+
Next i
2121+
2122+
Loading.LoadMultipleImageFiles listOfFiles, True
2123+
2124+
'Clear MRU
2125+
Case 2
2126+
g_RecentFiles.ClearList
2127+
2128+
End Select
2129+
2130+
End Sub
2131+
20912132
Private Sub MnuRender_Click(Index As Integer)
20922133
Select Case Index
20932134
Case 0
@@ -2724,6 +2765,18 @@ Private Sub MnuView_Click(Index As Integer)
27242765
End Select
27252766
End Sub
27262767

2768+
Private Sub MnuWindowOpen_Click(Index As Integer)
2769+
2770+
'Open the current document corresponding to the index in the menu
2771+
Dim listOfOpenImages As pdStack
2772+
PDImages.GetListOfActiveImageIDs listOfOpenImages
2773+
2774+
If (Index < listOfOpenImages.GetNumOfInts) Then
2775+
If PDImages.IsImageActive(listOfOpenImages.GetInt(Index)) Then CanvasManager.ActivatePDImage listOfOpenImages.GetInt(Index), "window menu"
2776+
End If
2777+
2778+
End Sub
2779+
27272780
Private Sub MnuWindowToolbox_Click(Index As Integer)
27282781

27292782
'Because this is a checkbox-based menu, we handle its commands specially
@@ -3355,10 +3408,6 @@ Private Sub MnuBlur_Click(Index As Integer)
33553408
End Select
33563409
End Sub
33573410

3358-
Private Sub MnuClearMRU_Click()
3359-
g_RecentFiles.ClearList
3360-
End Sub
3361-
33623411
'All Color sub-menu entries are handled here.
33633412
Private Sub MnuColor_Click(Index As Integer)
33643413
Select Case Index
@@ -3723,21 +3772,6 @@ Private Sub MnuLighting_Click(Index As Integer)
37233772
End Select
37243773
End Sub
37253774

3726-
'Load all images in the current "Recent Files" menu
3727-
Private Sub MnuLoadAllMRU_Click()
3728-
3729-
Dim listOfFiles As pdStringStack
3730-
Set listOfFiles = New pdStringStack
3731-
3732-
Dim i As Long
3733-
For i = 0 To g_RecentFiles.GetNumOfItems() - 1
3734-
listOfFiles.AddString g_RecentFiles.GetFullPath(i)
3735-
Next i
3736-
3737-
Loading.LoadMultipleImageFiles listOfFiles, True
3738-
3739-
End Sub
3740-
37413775
'All metadata sub-menu options are handled here
37423776
Private Sub MnuMetadata_Click(Index As Integer)
37433777
Select Case Index

Modules/Interface.bas

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -535,7 +535,10 @@ Private Sub SetUIMode_NoImages()
535535
'With all menus reset to their default values, we can now redraw all associated menu icons.
536536
' (IMPORTANT: this function must be called whenever menu captions change, because icons are associated by caption.)
537537
IconsAndCursors.ResetMenuIcons
538-
538+
539+
'Ensure the Windows menu does not list any open images.
540+
Menus.UpdateSpecialMenu_WindowsOpen
541+
539542
'If no images are currently open, but images were previously opened during this session, release any memory associated
540543
' with those images. This helps minimize PD's memory usage at idle.
541544
If (PDImages.GetNumSessionImages >= 1) Then PDImages.ReleaseAllPDImageResources
@@ -2034,6 +2037,9 @@ Public Sub NotifyNewActiveImage(Optional ByVal newImageIndex As Long = -1)
20342037
'A newly activated image requires a whole swath of UI changes. Ask SyncInterfaceToCurrentImage to handle this for us.
20352038
Interface.SyncInterfaceToCurrentImage
20362039

2040+
'Ensure the list of open windows (on the main form > Window menu) is up-to-date
2041+
Menus.UpdateSpecialMenu_WindowsOpen
2042+
20372043
End Sub
20382044

20392045
'This function should only be used if the entire tabstrip needs to be redrawn due to some massive display-related change

Modules/Menus.bas

Lines changed: 120 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ Attribute VB_Name = "Menus"
1919
'
2020
'***************************************************************************
2121

22-
2322
Option Explicit
2423

2524
Private Type PD_MenuEntry
@@ -922,6 +921,7 @@ Public Sub UpdateAgainstCurrentTheme(Optional ByVal redrawMenuBar As Boolean = T
922921
' (e.g. the "Languages" menu), while others must be handled here.
923922
Menus.UpdateSpecialMenu_RecentFiles
924923
Menus.UpdateSpecialMenu_RecentMacros
924+
Menus.UpdateSpecialMenu_WindowsOpen
925925

926926
If redrawMenuBar Then DrawMenuBar FormMain.hWnd
927927

@@ -3319,15 +3319,129 @@ Public Sub UpdateSpecialMenu_Language(ByVal numOfLanguages As Long, ByRef availa
33193319

33203320
End Sub
33213321

3322+
'The main form's Window menu displays a list of open images. This list must be updated whenever...
3323+
' 1) An image is loaded
3324+
' 2) An image is unloaded
3325+
' 3) A different image is "activated" (e.g. selected for editing)
3326+
' 4) The current image is saved to a different filename
3327+
Public Sub UpdateSpecialMenu_WindowsOpen()
3328+
3329+
Dim i As Long
3330+
3331+
'Quick branch for "no open images" state (it's much easier to handle)
3332+
If (PDImages.GetNumOpenImages > 0) Then
3333+
3334+
'Images are potentially stored non-sequentially. Retrieve a list of active image IDs from the
3335+
' central image manager.
3336+
Dim listOfOpenImages As pdStack
3337+
PDImages.GetListOfActiveImageIDs listOfOpenImages
3338+
3339+
'Ensure the correct number of menus are available. (This may involve freeing existing menus
3340+
' when an image is closed, or adding new menus when an image is opened.)
3341+
3342+
'This limit is effectively arbitrary, but useability of this menu is kind of pointless
3343+
' past a certain point. (Windows may have its own menu count limit as well, idk; I deliberately
3344+
' prefer to stay well beneath that amount.)
3345+
Const MAX_NUM_MENU_ENTRIES As Long = 64
3346+
3347+
Dim numImagesAllowed As Long
3348+
numImagesAllowed = PDMath.Min2Int(MAX_NUM_MENU_ENTRIES, listOfOpenImages.GetNumOfInts)
3349+
3350+
If (FormMain.MnuWindowOpen.Count > numImagesAllowed) Then
3351+
For i = FormMain.MnuWindowOpen.Count - 1 To numImagesAllowed - 1 Step -1
3352+
If (i <> 0) Then Unload FormMain.MnuWindowOpen(i)
3353+
Next i
3354+
End If
3355+
3356+
Dim curMenuCount As Long
3357+
curMenuCount = FormMain.MnuWindowOpen.Count
3358+
If (curMenuCount < numImagesAllowed) Then
3359+
For i = curMenuCount To numImagesAllowed - 1
3360+
Load FormMain.MnuWindowOpen(i)
3361+
Next i
3362+
End If
3363+
3364+
'The correct number of menu entries are now available.
3365+
3366+
'To ensure offsets retrieved from API menu calls are valid, we need to ensure the separator bar
3367+
' above the open window section is visible *before* interacting with items beneath it.
3368+
' (FYI: individual menus start at index 10 (9 is the separator bar above the first open image entry))
3369+
Const MENU_OFFSET As Long = 10
3370+
FormMain.MnuWindow(MENU_OFFSET - 1).Visible = True
3371+
3372+
'We now need to set all menu captions to match the filename of each open image. (As part of setting
3373+
' the correct names, we'll also set visible/enabled/checked state.)
3374+
3375+
'Menu bar itself
3376+
Dim hMenu As Long
3377+
hMenu = GetMenu(FormMain.hWnd)
3378+
3379+
'Window menu
3380+
hMenu = GetSubMenu(hMenu, 9&)
3381+
3382+
'Prepare a MenuItemInfo struct
3383+
Dim tmpMii As Win32_MenuItemInfoW
3384+
tmpMii.cbSize = LenB(tmpMii)
3385+
tmpMii.fMask = MIIM_STRING
3386+
3387+
'Note that we have to use WAPI to do this, because filenames may have Unicode chars.
3388+
For i = 0 To numImagesAllowed - 1
3389+
3390+
'Use VB to set the rest of the parameters; this will also trigger a DrawMenuBar call
3391+
With FormMain.MnuWindowOpen(i)
3392+
.Visible = True
3393+
.Enabled = True
3394+
.Checked = (listOfOpenImages.GetInt(i) = PDImages.GetActiveImageID)
3395+
End With
3396+
3397+
'Retrieve the caption (which should be the location on-disk, unless the image hasn't been saved
3398+
' in which case the loader will have assigned the image a "suggested" filename)
3399+
Dim tmpCaption As String
3400+
If PDImages.GetImageByID(listOfOpenImages.GetInt(i)).ImgStorage.DoesKeyExist("CurrentLocationOnDisk") Then
3401+
tmpCaption = Files.FileGetName(PDImages.GetImageByID(listOfOpenImages.GetInt(i)).ImgStorage.GetEntry_String("CurrentLocationOnDisk"), False)
3402+
End If
3403+
3404+
If (LenB(tmpCaption) = 0) Then
3405+
tmpCaption = Files.FileGetName(PDImages.GetImageByID(listOfOpenImages.GetInt(i)).ImgStorage.GetEntry_String("OriginalFileName"), False)
3406+
End If
3407+
3408+
3409+
Debug.Print "caption?", tmpCaption, hMenu, MENU_OFFSET + i
3410+
'Assign the caption via WAPI to preserve Unicode chars
3411+
tmpMii.dwTypeData = StrPtr(tmpCaption)
3412+
Debug.Print SetMenuItemInfoW(hMenu, MENU_OFFSET + i, 1&, tmpMii), "SetMenuItemInfoW"
3413+
Debug.Print Err.LastDllError
3414+
3415+
Next i
3416+
3417+
'Use the API to trigger a state change for any new captions
3418+
DrawMenuBar FormMain.hWnd
3419+
3420+
'No open images. Unload all menu items and hide the separator bar at the top of this section.
3421+
Else
3422+
3423+
If (FormMain.MnuWindowOpen.Count > 1) Then
3424+
For i = 1 To FormMain.MnuWindowOpen.Count - 1
3425+
Unload FormMain.MnuWindowOpen(i)
3426+
Next i
3427+
End If
3428+
3429+
'Hide the final instance and the separator bar above it
3430+
FormMain.MnuWindow(9).Visible = False
3431+
FormMain.MnuWindowOpen(0).Visible = False
3432+
3433+
End If
3434+
3435+
End Sub
3436+
3437+
'Whenever the "File > Open Recent" menu is modified, we need to modify our internal list of recent file items.
3438+
' (We manually track this menu so we can handle translations correctly for the items at the bottom of the menu,
3439+
' e.g. "Load all" and "Clear list", as well as menu captions for recent files with Unicode filenames.)
33223440
Public Sub UpdateSpecialMenu_RecentFiles()
33233441

3324-
'Whenever the "File > Open Recent" menu is modified, we need to modify our internal list of recent file items.
3325-
' (We manually track this menu so we can handle translations correctly for the items at the bottom of the menu,
3326-
' e.g. "Load all" and "Clear list".)
3327-
33283442
'Start by retrieving a handle to the menu in question
33293443
If (Not g_RecentFiles Is Nothing) Then
3330-
3444+
33313445
Dim hMenu As Long
33323446
hMenu = GetMenu(FormMain.hWnd)
33333447
hMenu = GetSubMenu(hMenu, 0&)

Modules/Saving.bas

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ Public Function PhotoDemon_SaveImage(ByRef srcImage As pdImage, ByVal dstPath As
196196
g_RecentFiles.AddFileToList dstPath, srcImage
197197
Interface.SyncInterfaceToCurrentImage
198198
Interface.NotifyImageChanged PDImages.GetActiveImageID()
199+
Menus.UpdateSpecialMenu_WindowsOpen
199200
End If
200201

201202
'At this point, it's safe to re-enable the main form and restore the default cursor

PhotoDemon.vbp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -478,7 +478,7 @@ Description="PhotoDemon Photo Editor"
478478
CompatibleMode="0"
479479
MajorVer=8
480480
MinorVer=9
481-
RevisionVer=679
481+
RevisionVer=681
482482
AutoIncrementVer=1
483483
ServerSupportFiles=0
484484
VersionComments="Copyright 2000-2021 Tanner Helland - photodemon.org"

0 commit comments

Comments
 (0)