Skip to content

Commit f00f0a8

Browse files
committed
New run-time resource minimizer
I never get tired of having my own UI toolkit for PD. It allows for so many neat tweaks and adjustments that would otherwise be a nightmare (or straight-up impossible) to implement. Case in point: this commit! One of the difficult things with a program like PD is that it needs to expose a *lot* of UI elements, especially on the main window. All the graphics required for the various toolboxes (especially if a complex tool like Advanced Text is active) add up quickly, and despite aggressive optimizations, GDI object count at a cold startup is still some ~250 objects, mostly DIB handles for each control's backbuffer. Recent changes to improve UI responsiveness - like caching toolboxes after they've been used in a session - also cause GDI object count to climb during a session. Images with many layers, especially animated images, are also a challenge. So in this commit, I've implemented a new strategy to help combat the potential for gradual resource climb. First up, PD's central "pdDIB" object - the object that manages all arbitrary raster images - now provides a "Suspend" method. This function uses a compressor of your choosing (lz4 by default) to compress the current pixel buffer to an arbitrary memory stream, after which it will free all GDI objects associated with the image. The pixel data stays suspended until you attempt to access it (directly, or via an associated GDI handle, like a DC), at which point the class automatically recreates all necessary GDI objects and the original pixel buffer in the background. You never need to worry about calling "unsuspend" - it always happens automatically, as needed. Alongside this new feature, I've started adding auto-suspend calls across a swath of UI code. When PD controls lose focus, they now suspend their backbuffer (since they're unlikely to render for awhile). Same for when they're hidden (a tricky one to implement, since Windows doesn't provide this notification automatically - fortunately, PD has a robust system in-place for inter-window communication). Controls that maintain internal spritesheets, like toolbox buttons, will now also free their spritesheets after a successful render event. This imposes no noticeable change to UI fluidity, but resource improvements are significant. On a cold start, PD has gone from ~250 GDI objects to just 148. Cold start memory usage is also down, and even if you open every toolbox in the program during a session, PD can now suspend all UI graphics for inactive toolboxes while still maintaining the windows themselves in the background, ready at a moment's notice. (GDI object requirements are down more than 70% in this scenario!) I'll be adding more suspend triggers in the coming days, which should help to bring resource usage down even more. I love the idea of each new PD release being even *more* lightweight than the previous one - despite many new features - and this commit will help 9.0 reach that goal! (This work was actually inspired by recent animation engine work, since animation frames pose a unique challenge for resource management. This new "suspend/resume" feature will be useful for further improving PD's resource management when working with animations, I think - I just need to do a lot of profiling first to ensure it doesn't affect animation timing accuracy.)
1 parent 06a70c9 commit f00f0a8

16 files changed

+375
-76
lines changed

Classes/pdDIB.cls

Lines changed: 234 additions & 22 deletions
Large diffs are not rendered by default.

Classes/pdLayer.cls

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2019,7 +2019,7 @@ End Function
20192019
' so for small layers, it may use a ton of dead space. This is by design.
20202020
'
20212021
'Note that this specialized function cannot physically make use of the current thumbnail cache, as it
2022-
' requires specialized transforms. As such, its performance will possibly be (much) slower than the
2022+
' requires specialized transforms. As such, its performance will possibly be (much?) slower than the
20232023
' normal thumbnail function.
20242024
'
20252025
'TODO: color-management

Classes/pdUCSupport.cls

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -580,9 +580,9 @@ Friend Sub SetCustomBackcolor(Optional ByVal newBackColor As Long = -1&)
580580
m_BackColor = newBackColor
581581
End Sub
582582

583-
'Want to receive custom window messages? No problem. Register them here, then watch for the CustomMessage event.
584-
' Note, however, that if the message is specific to PD, the caller needs to let us know, as we will need to manually
585-
' handle message marshaling.
583+
'Want to receive custom window messages? No problem. Register them here, then watch for
584+
' the CustomMessage event. Note, however, that if the message is specific to PD, the caller
585+
' needs to let us know, as we will need to manually handle message marshaling.
586586
Friend Sub SubclassCustomMessage(ByVal wMsg As Long, Optional ByVal msgIsInternalToPD As Boolean = False)
587587

588588
If PDMain.IsProgramRunning() Then
@@ -650,9 +650,10 @@ Private Function CacheWindowDimensions() As Boolean
650650

651651
End Function
652652

653-
'The naming of this function is potentially confusing, but it restores the back buffer to the currently specified back color.
654-
' It does not resize the DIB; it just fill it with a single uniform color. Optionally, a specific erase rect can be supplied.
655-
' (If coordinates are *not* supplied, the entire buffer will be wiped.)
653+
'The naming of this function is potentially confusing, but it restores the back buffer to the
654+
' currently specified back color. It does *not* resize the DIB; it just fills it with a single
655+
' uniform color. Optionally, a specific erase rect can be supplied. (If coordinates are *not*
656+
' supplied, the entire buffer will be wiped.)
656657
Private Sub ResetBackBuffer(Optional ByVal newBackColor As Long = -1&, Optional ByVal rpLeft As Single = 0!, Optional ByVal rpTop As Single = 0!, Optional ByVal rpWidth As Single = 0!, Optional ByVal rpHeight As Single = 0!)
657658

658659
'If the caller specifies a background color, we want to use it. If they don't, grab the default window background from
@@ -804,9 +805,14 @@ Private Sub m_FocusDetector_GotFocusReliable()
804805
End Sub
805806

806807
Private Sub m_FocusDetector_LostFocusReliable()
808+
807809
m_MouseButtonState = 0
808810
If m_MouseInsideUC Then TriggerMouseLeave
809811
RaiseEvent LostFocusAPI
812+
813+
'After losing focus, we typically don't expect redraws - so suspend this DIB for now
814+
m_BackBuffer.SuspendDIB
815+
810816
End Sub
811817

812818
Private Sub m_KeyEvents_KeyDownCustom(ByVal Shift As ShiftConstants, ByVal vkCode As Long, markEventHandled As Boolean)
@@ -999,7 +1005,7 @@ Private Sub m_WindowPainter_EraseBkgnd()
9991005
'If backbuffering is active (as it is with most PD controls), copy the relevant portion of the buffer into place.
10001006
Else
10011007
GDI.BitBltWrapper targetDC, 0, 0, Me.GetControlWidth + 1, Me.GetControlHeight + 1, m_BackBuffer.GetDIBDC, 0, 0, vbSrcCopy
1002-
m_BackBuffer.FreeFromDC
1008+
m_BackBuffer.SuspendDIB
10031009
End If
10041010

10051011
End Sub
@@ -1028,7 +1034,7 @@ Private Sub m_WindowPainter_PaintWindow(ByVal winLeft As Long, ByVal winTop As L
10281034
'If backbuffering is active (as it is with most PD controls), copy the relevant portion of the buffer into place.
10291035
Else
10301036
GDI.BitBltWrapper targetDC, winLeft, winTop, winWidth, winHeight, m_BackBuffer.GetDIBDC, winLeft, winTop, vbSrcCopy
1031-
m_BackBuffer.FreeFromDC
1037+
m_BackBuffer.SuspendDIB
10321038
End If
10331039

10341040
End Sub
@@ -1301,11 +1307,11 @@ Friend Sub RequestRepaint(Optional ByVal raiseImmediateDrawEvent As Boolean = Fa
13011307
'When running, rely on the painter to paint the control for us
13021308
If PDMain.IsProgramRunning() Then
13031309

1304-
'In the event that a paint event is not called right away (because the control is invisible, or some
1305-
' other reason), free the back buffer DIB from its DC to free up a bit of resources. If a paint
1306-
' event *is* called right away, this has no ill effects, because the DC is auto-generated as needed.
1310+
'In the event that a paint event is not called right away (because the control is invisible,
1311+
' or some other reason), free the back buffer DIB from its DC to free up a bit of resources.
1312+
' If a paint event *is* called right away, this has no ill effects, because the DC is
1313+
' auto-generated as needed.
13071314
m_BackBuffer.FreeFromDC
1308-
13091315
m_WindowPainter.RequestRepaint raiseImmediateDrawEvent
13101316

13111317
Else
@@ -1484,6 +1490,10 @@ Private Sub StopAllSubclassing()
14841490

14851491
End Sub
14861492

1493+
Private Sub HandleWM_HideChild()
1494+
If (Not m_NoBackBufferMode) Then m_BackBuffer.SuspendDIB
1495+
End Sub
1496+
14871497
Private Function HandleWM_WindowPosChanging(ByVal hWnd As Long, ByVal uiMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
14881498

14891499
Dim initVisibility As Boolean
@@ -1503,8 +1513,10 @@ Private Function HandleWM_WindowPosChanging(ByVal hWnd As Long, ByVal uiMsg As L
15031513

15041514
End If
15051515

1506-
'Finally, notify the parent of the pending visibility change (if any)
1516+
'Finally, notify the parent of the pending visibility change (if any), and suspend our
1517+
' back buffer if the window has been made invisible
15071518
If (initVisibility <> m_Visibility) Then RaiseEvent VisibilityChange(m_Visibility)
1519+
If (Not m_Visibility) Then m_BackBuffer.SuspendDIB
15081520

15091521
End Function
15101522

@@ -1519,8 +1531,10 @@ Private Function HandleWM_ShowWindow(ByVal hWnd As Long, ByVal uiMsg As Long, By
15191531
' one before the control is actually shown.)
15201532
If m_Visibility And (Not initVisibility) And (m_RedrawRequestCount > 0) Then AskForARepaint True, True
15211533

1522-
'Finally, notify the parent of the pending visibility change
1534+
'Finally, notify the parent of the pending visibility change (if any), and suspend our
1535+
' back buffer if the window has been made invisible
15231536
If (initVisibility <> m_Visibility) Then RaiseEvent VisibilityChange(m_Visibility)
1537+
If (Not m_Visibility) Then m_BackBuffer.SuspendDIB
15241538

15251539
End Function
15261540

@@ -1549,9 +1563,16 @@ Private Function ISubclass_WindowMsg(ByVal hWnd As Long, ByVal uiMsg As Long, By
15491563
m_hWnd = 0
15501564
End If
15511565

1566+
'Child windows don't normally receive WM_SHOWWINDOW notifications. In PD, we manually
1567+
' forward these messages so that we can free up various UI-related bits to keep memory
1568+
' as low as humanly possible.
1569+
ElseIf (uiMsg = WM_PD_HIDECHILD) Then
1570+
HandleWM_HideChild
1571+
15521572
Else
15531573

1554-
'See if this message is a message that our parent control wants notification for. If it is, relay it accordingly.
1574+
'See if this message is a message that our parent control wants notification for.
1575+
' If it is, relay it accordingly.
15551576
If (Not m_CustomMessages Is Nothing) Then
15561577
If m_CustomMessages.DoesKeyExist(uiMsg) Then
15571578

Classes/pdVisualThemes.cls

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,12 +73,16 @@ Private m_ThemeAccent As PD_THEME_ACCENT
7373
Private m_MonochromeIcons As Boolean
7474

7575
'Extra API functions for painting form backgrounds
76-
Private Const WM_PAINT As Long = &HF
7776
Private Const WM_ERASEBKGND As Long = &H14
78-
Private Declare Function GetClientRect Lib "user32" (ByVal targetHWnd As Long, ByRef lpRect As RECT) As Long
79-
Private Declare Function EndPaint Lib "user32" (ByVal targetHWnd As Long, ByRef lpPaint As PAINTSTRUCT) As Long
77+
Private Const WM_PAINT As Long = &HF
78+
Private Const WM_SHOWWINDOW As Long = &H18
79+
8080
Private Declare Function BeginPaint Lib "user32" (ByVal targetHWnd As Long, ByRef lpPaint As PAINTSTRUCT) As Long
81+
Private Declare Function EndPaint Lib "user32" (ByVal targetHWnd As Long, ByRef lpPaint As PAINTSTRUCT) As Long
82+
Private Declare Function EnumChildWindows Lib "user32" (ByVal hWndParent As Long, ByVal lpEnumProc As Long, ByVal lParam As Long) As Long
83+
Private Declare Function GetClientRect Lib "user32" (ByVal targetHWnd As Long, ByRef lpRect As RECT) As Long
8184
Private Declare Function GetUpdateRect Lib "user32" (ByVal targetHWnd As Long, ByRef lpRect As RECT, ByVal bErase As Long) As Long
85+
Private Declare Function SendNotifyMessage Lib "user32" Alias "SendNotifyMessageW" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
8286

8387
'As part of the painting process, we're gonna be generating a looot of paint messages. To avoid churn, we'll declare
8488
' a single paint struct and update rect up front.
@@ -859,6 +863,11 @@ Friend Sub BuildThemePackage()
859863

860864
End Sub
861865

866+
Friend Function EnumChildProc(ByVal hWnd As Long) As Long
867+
SendNotifyMessage hWnd, WM_PD_HIDECHILD, 0&, 0&
868+
EnumChildProc = 1
869+
End Function
870+
862871
'Helper for BuildThemePackage(), above. Not intended or designed for any other use.
863872
Private Sub AddThemeFileToPackage(ByRef dstPackager As pdPackageChunky, ByRef srcFilename As String)
864873

@@ -976,6 +985,23 @@ Private Function HandleFormWMEraseBkgnd(ByVal hWnd As Long, ByVal uiMsg As Long,
976985

977986
End Function
978987

988+
Private Function HandleFormWMShowWindow(ByVal hWnd As Long, ByVal uiMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
989+
990+
'For purposes of this sub, we only care about windows getting hidden
991+
If (wParam = 0) Then
992+
993+
'This window is getting hidden. Enumerate its child windows, and notify them of this event.
994+
' (By default, child windows do not receive visibility notification changes, but in PD, we use
995+
' visibility changes to suspend a bunch of UI resources.)
996+
EnumChildWindows hWnd, AddressOf VBHacks.StandInEnumChildWndProc, ObjPtr(Me)
997+
998+
End If
999+
1000+
'We don't actually handle the visibility toggle, so we need to call DefWindowProc
1001+
HandleFormWMShowWindow = VBHacks.DefaultSubclassProc(hWnd, uiMsg, wParam, lParam)
1002+
1003+
End Function
1004+
9791005
Private Function ISubclass_WindowMsg(ByVal hWnd As Long, ByVal uiMsg As Long, ByVal wParam As Long, ByVal lParam As Long, ByVal dwRefData As Long) As Long
9801006

9811007
If (uiMsg = WM_PAINT) Then
@@ -984,6 +1010,9 @@ Private Function ISubclass_WindowMsg(ByVal hWnd As Long, ByVal uiMsg As Long, By
9841010
ElseIf (uiMsg = WM_ERASEBKGND) Then
9851011
ISubclass_WindowMsg = HandleFormWMEraseBkgnd(hWnd, uiMsg, wParam, lParam)
9861012

1013+
ElseIf (uiMsg = WM_SHOWWINDOW) Then
1014+
ISubclass_WindowMsg = HandleFormWMShowWindow(hWnd, uiMsg, wParam, lParam)
1015+
9871016
ElseIf (uiMsg = WM_NCDESTROY) Then
9881017

9891018
m_SubclassedHWnds.DeleteEntry hWnd

Controls/pdButton.ctl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -675,7 +675,7 @@ Private Sub RedrawBackBuffer()
675675
End If
676676

677677
m_Images.AlphaBlendToDCEx bufferDC, btImageCoords.x, btImageCoords.y, m_ImageWidth, m_ImageHeight, 0, pxOffset, m_ImageWidth, m_ImageHeight
678-
m_Images.FreeFromDC
678+
m_Images.SuspendDIB
679679

680680
End If
681681

Controls/pdButtonStrip.ctl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1172,10 +1172,10 @@ Private Sub UpdateColorList()
11721172
.LoadThemeColor BTS_SelectedText, "SelectedText", IDE_WHITE
11731173
.LoadThemeColor BTS_UnselectedText, "UnselectedText", IDE_GRAY
11741174
.LoadThemeColor BTS_Light_Background, "BackgroundLightMode", IDE_WHITE
1175-
.LoadThemeColor BTS_Light_SelectedItemFill, "SelectedItemFillLightMode", IDE_LIGHTBLUE
1175+
.LoadThemeColor BTS_Light_SelectedItemFill, "SelectedItemFillLightMode", IDE_BLUE
11761176
.LoadThemeColor BTS_Light_UnselectedItemFill, "UnselectedItemFillLightMode", IDE_WHITE
1177-
.LoadThemeColor BTS_Light_SelectedItemBorder, "SelectedItemBorderLightMode", IDE_LIGHTBLUE
1178-
.LoadThemeColor BTS_Light_UnselectedItemBorder, "UnselectedItemBorderLightMode", IDE_LIGHTBLUE
1177+
.LoadThemeColor BTS_Light_SelectedItemBorder, "SelectedItemBorderLightMode", IDE_BLUE
1178+
.LoadThemeColor BTS_Light_UnselectedItemBorder, "UnselectedItemBorderLightMode", IDE_BLUE
11791179
.LoadThemeColor BTS_Light_SelectedText, "SelectedTextLightMode", IDE_BLUE
11801180
.LoadThemeColor BTS_Light_UnselectedText, "UnselectedTextLightMode", IDE_GRAY
11811181
End With

Controls/pdSliderStandalone.ctl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -918,7 +918,7 @@ Private Sub RenderTrack(Optional ByVal refreshImmediately As Boolean = False, Op
918918
ElseIf (m_KnobStyle = SquareStyle) Then
919919
m_GradientDIB.AlphaBlendToDC m_SliderBackgroundDIB.GetDIBDC, 255, GetTrackLeft - (m_TrackDiameter \ 2) + 1, 0
920920
End If
921-
m_GradientDIB.FreeFromDC
921+
m_GradientDIB.SuspendDIB
922922

923923
End Select
924924

@@ -1416,8 +1416,8 @@ Private Sub RedrawBackBuffer(Optional ByVal refreshImmediately As Boolean = Fals
14161416
bufferDC = ucSupport.GetBackBufferDC(True, finalBackColor)
14171417
If (bufferDC = 0) Then Exit Sub
14181418

1419-
'Copy the previously assembled track onto the back buffer. (This is faster than AlphaBlending the result, especially because
1420-
' we don't need any blending.)
1419+
'Copy the previously assembled track onto the back buffer.
1420+
' (This is faster than AlphaBlending the result, and we don't need blending.)
14211421
GDI.BitBltWrapper bufferDC, 0, 0, m_SliderAreaWidth, m_SliderAreaHeight, m_SliderBackgroundDIB.GetDIBDC, 0, 0, vbSrcCopy
14221422
m_SliderBackgroundDIB.FreeFromDC
14231423

Controls/pdSpinner.ctl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1325,7 +1325,7 @@ Private Sub UpdateColorList()
13251325
.LoadThemeColor PDS_ButtonArrow, "ButtonArrow", IDE_GRAY
13261326
.LoadThemeColor PDS_ButtonBorder, "ButtonBorder", IDE_BLUE
13271327
.LoadThemeColor PDS_ButtonFill, "ButtonFill", IDE_WHITE
1328-
.LoadThemeColor PDS_ErrorBorder, "ErrorBorder", IDE_RED
1328+
.LoadThemeColor PDS_ErrorBorder, "ErrorBorder", IDE_GRAY
13291329
End With
13301330

13311331
RelayUpdatedColorsToEditBox

Modules/Compression.bas

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -136,24 +136,28 @@ End Sub
136136
'Want to know if a given compression engine is available? Call this function. It will (obviously) return FALSE for
137137
' any engines that weren't initialized properly.
138138
Public Function IsFormatSupported(ByVal cmpFormat As PD_CompressionFormat) As Boolean
139-
Select Case cmpFormat
140-
Case cf_None
141-
IsFormatSupported = m_CompressorAvailable(ce_None)
142-
Case cf_Zlib
143-
IsFormatSupported = m_CompressorAvailable(ce_LibDeflate)
144-
Case cf_Zstd
145-
IsFormatSupported = m_CompressorAvailable(ce_Zstd)
146-
Case cf_Lz4
147-
IsFormatSupported = m_CompressorAvailable(ce_Lz4)
148-
Case cf_Lz4hc
149-
IsFormatSupported = m_CompressorAvailable(ce_Lz4)
150-
Case cf_Deflate
151-
IsFormatSupported = m_CompressorAvailable(ce_LibDeflate)
152-
Case cf_Gzip
153-
IsFormatSupported = m_CompressorAvailable(ce_LibDeflate)
154-
Case Else
155-
IsFormatSupported = False
156-
End Select
139+
If VBHacks.IsArrayInitialized(m_CompressorAvailable) Then
140+
Select Case cmpFormat
141+
Case cf_None
142+
IsFormatSupported = m_CompressorAvailable(ce_None)
143+
Case cf_Zlib
144+
IsFormatSupported = m_CompressorAvailable(ce_LibDeflate)
145+
Case cf_Zstd
146+
IsFormatSupported = m_CompressorAvailable(ce_Zstd)
147+
Case cf_Lz4
148+
IsFormatSupported = m_CompressorAvailable(ce_Lz4)
149+
Case cf_Lz4hc
150+
IsFormatSupported = m_CompressorAvailable(ce_Lz4)
151+
Case cf_Deflate
152+
IsFormatSupported = m_CompressorAvailable(ce_LibDeflate)
153+
Case cf_Gzip
154+
IsFormatSupported = m_CompressorAvailable(ce_LibDeflate)
155+
Case Else
156+
IsFormatSupported = False
157+
End Select
158+
Else
159+
IsFormatSupported = (cmpFormat = cf_None)
160+
End If
157161
End Function
158162

159163
'Compress some arbitrary pointer to a destination array.

Modules/DialogManager.bas

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,7 @@ End Function
383383
'Identical to promptGenericYesNoDialog(), above, with the caveat that only ONE possible outcome can be remembered.
384384
' This is relevant for Yes/No/Cancel situations where No and Cancel prevent a workflow from proceeding. If we allowed
385385
' those values to be stored, the user could never proceed with an operation in the future!
386-
Public Function PromptGenericYesNoDialog_SingleOutcome(ByVal questionID As String, ByRef questionText As String, ByRef yesButtonText As String, ByRef noButtonText As String, ByRef cancelButtonText As String, ByRef rememberCheckBoxText As String, ByRef dialogTitleText As String, Optional ByVal choiceAllowedToRemember As VbMsgBoxResult = vbYes, Optional ByVal icon As SystemIconConstants = IDI_QUESTION, Optional ByVal defaultAnswer As VbMsgBoxResult = vbCancel, Optional ByVal defaultRemember As Boolean = False) As VbMsgBoxResult
386+
Public Function PromptGenericYesNoDialog_SingleOutcome(ByVal questionID As String, ByRef questionText As String, ByRef yesButtonText As String, ByRef noButtonText As String, ByRef cancelButtonText As String, ByRef rememberCheckBoxText As String, ByRef dialogTitleText As String, Optional ByVal choiceAllowedToRemember As VbMsgBoxResult = vbYes, Optional ByVal useIcon As SystemIconConstants = IDI_QUESTION, Optional ByVal defaultAnswer As VbMsgBoxResult = vbCancel, Optional ByVal defaultRemember As Boolean = False) As VbMsgBoxResult
387387

388388
'Convert the questionID to its XML-safe equivalent
389389
Dim xmlEngine As pdXML
@@ -399,7 +399,7 @@ Public Function PromptGenericYesNoDialog_SingleOutcome(ByVal questionID As Strin
399399
'The user has not saved a previous answer. Display the full dialog.
400400
Else
401401

402-
dialog_GenericMemory.ShowDialog questionText, yesButtonText, noButtonText, cancelButtonText, rememberCheckBoxText, dialogTitleText, icon, defaultAnswer, defaultRemember
402+
dialog_GenericMemory.ShowDialog questionText, yesButtonText, noButtonText, cancelButtonText, rememberCheckBoxText, dialogTitleText, useIcon, defaultAnswer, defaultRemember
403403

404404
'Retrieve the user's answer
405405
PromptGenericYesNoDialog_SingleOutcome = dialog_GenericMemory.DialogResult

0 commit comments

Comments
 (0)