Jump to content

Yet another function interrupt desperate call for help


Mbee
 Share

Recommended Posts

Hi!  I've read and presumably understood :blink:  the very fine Interrupting a running function wiki and @Melba23's  example solutions to this dilemma, but I need additional help to solve my problems.,,

What may be happening is that certain button clicks are being either repeated or lost. In practice, I'll press a button to display the next or previous image (which takes a moderate amount of time), but on moderately rare and unpredictable cases, the same image is displayed instead. The next/previous functions increment or decrement  an index into an array, then display the new image, but curiously that must not be happening. because the displayed image stays the same. But there's no other code path to displaying any image, so I figure the only way that can happen is if next/previous click is being lost.  (I'm using Event Mode)

I'm assured that Windows button click events are queued, but that seems not to be happening in this case.  So I tried to queue these button events myself, which may or may not be happening (it seems not).  So that's when I studied the wiki page above, suspecting that these occasional clicks are being lost because the inc/dec & display function is still running when the new click occurs.

As Melba23 and the Wiki (kinda) suggested, I'm using a dummy accelerator as the interrupt handler and a logical flag to indicate that an interrupt occurred. But I obviously I didn't get the setting and clearing of the flag right, because as soon as one of the two functions are called, it enters an infinite loop waiting for the flag to be cleared.  But I can't figure out the correct solution.

At last, here's some code samples...

; The following is in the Main code

$G_DummyAccelCtrlID = GUICtrlCreateDummy()
GUICtrlSetOnEvent($G_DummyAccelCtrlID, "_AdvanceBtn_AccelHandler")
Local $L_AccelKeyAra[1][2] = [["!+z", $G_DummyAccelCtrlID]]
GUISetAccelerators( $L_AccelKeyAra, <the correct GUI window handle> )


Func ExampleAdvanceFunc()   ; _NextClick() or _PreviousClick()
    
    If $G_AdvanceClickActive Then
        _QueuePicAdv( $Gc_NextClicked )                         ; Queue a Next Click
        While $G_AdvanceClickActive
            Sleep (50)
        WEnd
    EndIf

    $G_AdvanceClickActive = True

;   <Code to adjust index and display image>

    $Lf_Stat = _DeQueuePicAdv()                     ; Checks if another advance button was queued
    If $Lf_Stat <> -1 Then                          ; -1 = Nothing queued
        If $Lf_Stat = $Gc_NextClicked Then          ; If another Next button was queued...
            $G_AdvanceClickActive = False
            _NextClick()
        Else
            $G_AdvanceClickActive = False
            _PreviousClick()
        EndIf
    EndIf

    $G_AdvanceClickActive = False
    Return

EndFunc


Func _QueuePicAdv( $arg_PicAdvanceDirection )

    If $G_PicAdvClickQueueIdx < $Gc_PicAdvClickQueueMax Then
        $G_PicAdvClickQueue[$G_PicAdvClickQueueIdx] = $arg_PicAdvanceDirection
        $G_PicAdvClickQueueIdx += 1
    Else
        MsgBox($MB_OK, "title", "_QueuePicAdv -- Pic Advance Queue Overrun! - Exiting")
        Exit
    EndIf
    Return
EndFunc

Func _DeQueuePicAdv()

    Local $Lf_AdvanceDirection = -1     ; Default is nothing queued

    If $G_PicAdvClickQueueIdx > 1 Then
        $G_PicAdvClickQueueIdx -= 1
        $Lf_AdvanceDirection = $G_PicAdvClickQueue[$G_PicAdvClickQueueIdx]
    EndIf
    Return $Lf_AdvanceDirection
EndFunc

Func _AdvanceBtn_AccelHandler()

    $G_AdvanceClickActive = True
    Return

EndFunc

Please let me know what I'm doing wrong and how to fix it.

Thanks!

Link to comment
Share on other sites

Oh, sorry, I forgot to at least try to make the code runnable.  The following runs, but does NOT reproduce the problem!  Anyway, here ya go...

#include <MsgBoxConstants.au3>
#include <GuiButton.au3>
#include <GUIConstants.au3>

Opt( "GUICloseOnESC", 1 )
Opt( "GUIOnEventMode", 1 )

; The following is in the Main code
Global Const $Gc_PicAdvClickQueueMax = 10, $Gc_PreviousClicked = 1, $Gc_NextClicked = 2


Global $G_Index = 0, $G_AdvanceClickActive = False
Global $G_PicAdvClickQueue[$Gc_PicAdvClickQueueMax], $G_PicAdvClickQueueSize=0, $G_PicAdvClickQueueIdx=0
Global $G_GuiHandle, $G_NextBtnID, $G_PreviousBtnID


Global $G_DummyAccelCtrlID = GUICtrlCreateDummy()
GUICtrlSetOnEvent($G_DummyAccelCtrlID, "_AdvanceBtn_AccelHandler")
Local $L_AccelKeyAra[1][2] = [["!+z", $G_DummyAccelCtrlID]]
GUISetAccelerators( $L_AccelKeyAra )

$G_GuiHandle = GUICreate( "ClickTestGUI", 120, 100 )
GUISetOnEvent( $GUI_EVENT_CLOSE, "_GUIWinClose", $G_GuiHandle )

$G_NextBtnID = GUICtrlCreateButton( "Next", 10, 50 )
GUICtrlSetOnEvent(-1,"_NextClick")
$G_PreviousBtnID = GUICtrlCreateButton( "Previous", 50, 50 )
GUICtrlSetOnEvent(-1,"_PreviousClick")
GUISetState( @SW_SHOW )

While True
    Sleep( 100 )
WEnd
Exit


Func _NextClick()

    ConsoleWrite( @CRLF & "Next called - Current Index = " & $G_Index )

    If $G_AdvanceClickActive Then
        ConsoleWrite( @CRLF & "Next called while $G_AdvanceClickActive is True" )
        _QueuePicAdv( $Gc_NextClicked )             ; Queue a Next Click
        While $G_AdvanceClickActive
            Sleep (50)
        WEnd
    EndIf

    $G_AdvanceClickActive = True

;   <Code to adjust index and display image>

    $G_Index += 1

    $Lf_Stat = _DeQueuePicAdv()                     ; Checks if another advance button was queued
    If $Lf_Stat <> -1 Then                          ; -1 = Nothing queued
        If $Lf_Stat = $Gc_NextClicked Then          ; If another Next button was queued...
            ConsoleWrite( @CRLF & "A Queued Next Click was Dequeued in _NextClick()" )
            $G_AdvanceClickActive = False
            _NextClick()
        Else
            ConsoleWrite( @CRLF & "A Queued Previous Click was Dequeued in _NextClick()" )
            $G_AdvanceClickActive = False
            _PreviousClick()
        EndIf
    EndIf

    $G_AdvanceClickActive = False
    Return

EndFunc


Func _PreviousClick()   ; _NextClick() or _PreviousClick()

    ConsoleWrite( @CRLF & "Previous called - Current Index = " & $G_Index )

    If $G_AdvanceClickActive Then
        ConsoleWrite( @CRLF & "Previous called while $G_AdvanceClickActive is True" )
        _QueuePicAdv( $Gc_PreviousClicked )             ; Queue a Previous Click
        While $G_AdvanceClickActive
            Sleep (50)
        WEnd
    EndIf

    $G_AdvanceClickActive = True

;   <Code to adjust index and display image>

    If $G_Index > 0 Then $G_Index -= 1

    $Lf_Stat = _DeQueuePicAdv()                     ; Checks if another advance button was queued
    If $Lf_Stat <> -1 Then                          ; -1 = Nothing queued
        If $Lf_Stat = $Gc_NextClicked Then          ; If another Next button was queued...
            ConsoleWrite( @CRLF & "A Queued Next Click was Dequeued in _PreviousClick()" )
            $G_AdvanceClickActive = False
            _NextClick()
        Else
            ConsoleWrite( @CRLF & "A Queued Previous Click was Dequeued in _PreviousClick()" )
            $G_AdvanceClickActive = False
            _PreviousClick()
        EndIf
    EndIf

    $G_AdvanceClickActive = False
    Return

EndFunc

Func _QueuePicAdv( $arg_PicAdvanceDirection )

    If $G_PicAdvClickQueueIdx < $Gc_PicAdvClickQueueMax Then
        $G_PicAdvClickQueue[$G_PicAdvClickQueueIdx] = $arg_PicAdvanceDirection
        $G_PicAdvClickQueueIdx += 1
    Else
        MsgBox($MB_OK, "title", "_QueuePicAdv -- Pic Advance Queue Overrun! - Exiting")
        Exit
    EndIf
    Return
EndFunc

Func _DeQueuePicAdv()

    Local $Lf_AdvanceDirection = -1     ; Default is nothing queued

    If $G_PicAdvClickQueueIdx > 1 Then
        $G_PicAdvClickQueueIdx -= 1
        $Lf_AdvanceDirection = $G_PicAdvClickQueue[$G_PicAdvClickQueueIdx]
    EndIf
    Return $Lf_AdvanceDirection
EndFunc

Func _AdvanceBtn_AccelHandler()

    $G_AdvanceClickActive = True
    Return

EndFunc


Func _GUIWinClose()
    Exit
EndFunc

But since the above doesn't reproduce the problem, and since my code is about 10,000 lines of code, so I cannot post it, I don't know how to proceed...

 

Link to comment
Share on other sites

  • Moderators

Mbee,

That code is severely recursive - you are calling functions from within themselves - and I would hazard a guess that is where you are "losing" events as AutoIt really does queue them for you. Try recasting the code so that you return to your idle loop before calling any function - and certainly the same one.

This simple example allows to see that AutoIt does indeed queue button events - it counts up and down quite nicely for me:

#include <GUIConstantsEx.au3>

Opt( "GUIOnEventMode", 1 )

Global $iClickCounter = 1

$G_GuiHandle = GUICreate( "ClickTestGUI", 120, 100 )
GUISetOnEvent( $GUI_EVENT_CLOSE, "_GUIWinClose", $G_GuiHandle )

$G_NextBtnID = GUICtrlCreateButton( "Next", 10, 50 )
GUICtrlSetOnEvent(-1,"_NextClick")
$G_PreviousBtnID = GUICtrlCreateButton( "Previous", 50, 50 )
GUICtrlSetOnEvent(-1,"_PreviousClick")

GUISetState( @SW_SHOW )

While True
    Sleep(10)
WEnd

Func _NextClick()

    $iClickCounter += 1
    If $iClickCounter > 10 Then $iClickCounter = 10

    ConsoleWrite("Counter: " & $iClickCounter & @CRLF)

    Sleep(2000) ; Simulate the delay while the new picture is displayed

EndFunc

Func _PreviousClick()

    $iClickCounter -= 1
    If $iClickCounter < 1 Then $iClickCounter = 1

    ConsoleWrite("Counter: " & $iClickCounter & @CRLF)

    Sleep(2000) ; Simulate the delay while the new picture is displayed

EndFunc

Func _GUIWinClose()
    Exit
EndFunc

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

Aach! What a dummy I am! Thanks, Melba!  I totally spaced on the stupid crazy recursion :'(  Ninny! Why didn't I see that? :>

As I was falling asleep a short time ago (I often think more clearly then than while active), I recalled from the Wiki tutorial and your code elsewhere about the need to do part of the code in the main Main routine, as you pointed again just now. You wrote: "Try recasting the code so that you return to your idle loop before calling any function - and certainly the same one."  But I don't know how to adapt my code to do that, since I absolutely need On Event Mode, thus no event loop. Do I switch modes when necessary? And under what situations?  Or is this one of the situations which AutoIt can't deal with as far as interrupting a running function?

As far as my blinkered recursion errors, off the top of my head it occurs to me that instead of those recursive calls, perhaps I could send an appropriate Windows message to simulate a next/previous click which would get queued and eventually trigger the appropriate button click handler (unless there's a better way).

Well, I better go back to bed.  I'll check in tomorrow.  Thanks again!

Link to comment
Share on other sites

  • Moderators

Mbee,

You still have an idle loop even in OnEvent mode - or else the script would just end!

; OnEvent idle loop
While True
    Sleep(10)
WEnd

So you need to make sure that you return to this loop - i.e. terminate a function before you recall the same function.

And I still fail to see why you need to send any Windows messages - AutoIt is quite happy dealing with the standard Windows message stream and will happily queue events for you, as the example script I posted above shows. I get the impression that you are serious overthinking this problem when a perfectly simple solution is out there waiting for you to stumble over it. Logically I see it as something like this:

Global _ImageToShowNext variable
Global _ImageShowingNow variable

Advance button       fires _Advance function
Previous button      fires _Previous function

Start of idle loop keeping script alive
    Sleep(10)
    
    Look to see if _ImageToShowNext is different to _ImageShowingNow
        If it is - show the required picture via the _ShowImage function
        Match the 2 variables

End of idle loop

_Advance function
    Increase the _ImageToShowNext variable - what else do you need to do?
    
_Previous function
    Decrease the _ImageToShowNext variable - what else do you need to do?
    
_ShowImage function
    Show whatever image has been passed as a parameter

That would seem to do the trick. Multiple rapid presses of the buttons should be queued and then processed in turn as the previous _ShowImage function ends.

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

You're absolutely right, of course. My only excuse is that I started writing this thing 3-4 years ago when I was an even more ignorant newb than I am today!  And not very long later I stopped development for a number of reasons, including the fact that the code was always, always crashing in a GDI+ function that no one understood.

But fairly recently I contacted you for help on the code that was calling that GDI+ function, which was trying to calculate the maximum number of characters that would fit into a text field of a given number of pixels and all the font information. That's when I had a flash insight about how to do that (technically, estimate that) extremely easily, by a combination of your StringSize and simple division.  So that's when I finally resumed development again, by which point I was substantially  more experienced and knowledgeable on AutoIt and all the various UDFs.  And I figured that I'd leave as much as I had done years ago largely alone, which obviously was a mistake.

Anyway, with your gracious advice and assistance, the seemingly "missing" click events no longer happen, and I'm a very happy camper.

Thank you enormously for your patience and generosity!

Link to comment
Share on other sites

Damn!  It actually is still losing clicks after all! How do I know? I created a folder of 60 images whose names are just numbers in sequential order. Then I started viewing them and clicked Next fairly fast, while counting the number of times I clicked it.  If no Next clicks were being lost, then when I finished clicking, the file name/number should be exactly equal the number of times I clicked + 1. But when I test it, the final file number being displayed is anywhere from 5 to 15 lower than it should be -- it never caught up, demonstrating that clicks are being lost. NOTE that I tested this first without any queuing/dequeuing. But when that was such a failure, I added that capability (as seen below), which actually undeniably helped, but not enough.

If I click slowly enough, everything's fine.  But when I click even moderately fast such that I click Next while a previous image is being displayed (which can take a while, especially for animated GIFs), some Next clicks certainly appear to not be queued.

So I added some code to watch Next and Previous clicks and queue them myself if needed, such that I would dequeue them in the main loop. But again, the following code does not reproduce the problem.

 

#include <MsgBoxConstants.au3>
#include <GuiButton.au3>
#include <GUIConstants.au3>

;   The following included UDF can be found here: https://www.autoitscript.com/forum/topic/64738-mouseonevent-udf/
;   I'm showing the standard include, but because I want X64 mode and the standard UDF doesn't work in X64, I added the
;   workaround code provided by "LarsJ" on the very last page of that thread and called it ""MouseOnEvent64.au3",
;~ #include "MouseOnEvent.au3"
#include "MouseOnEvent64.au3"

Opt( "GUICloseOnESC", 1 )
Opt( "GUIOnEventMode", 1 )

Global Const $Gc_PicAdvClickQueueMax=10, $Gc_PreviousClicked=1, $Gc_NextClicked=2
Global $G_PicAdvClickQueueIdx=0, $G_PicAdvClickQueue[$Gc_PicAdvClickQueueMax]
Global $G_AdvanceClickActive = False, $G_CurFileIndex = 0, $G_LastFileIndex = 0, $G_CUR_PICADV_INDEX=0, $G_TOTAL_PICADV_CLICK_COUNT=0


Global $G_GuiHandle = GUICreate( "ClickTestGUI", 120, 100 )
GUISetOnEvent( $GUI_EVENT_CLOSE, "_GUIWinClose", $G_GuiHandle )

Global $G_NextBtnID = GUICtrlCreateButton( "Next", 10, 50 )
GUICtrlSetOnEvent(-1,"_NextClick")

Global $G_PreviousBtnID = GUICtrlCreateButton( "Previous", 50, 50 )
GUICtrlSetOnEvent(-1,"_PreviousClick")
GUISetState( @SW_SHOW )

Local $Lf_Stat = _MouseSetOnEvent($MOUSE_PRIMARYUP_EVENT, "_MyLeftClickHandler" )

While True

    Sleep(20)                                       ; Sleep for 20 milliseconds

    If $G_CurFileIndex <> $G_LastFileIndex Then
        If $G_CurFileIndex > $G_LastFileIndex Then
            _NextClick()
        Else
            _PreviousClick()
        EndIf
    EndIf

    $Lf_Stat = _DeQueuePicAdv()                     ; Checks if another pic advance button was queued
    If $Lf_Stat <> -1 Then                          ; -1 = Nothing queued
        If $Lf_Stat = $Gc_NextClicked Then          ; If another Next button was queued...
            ConsoleWrite( @CRLF & "Main -- Found a QUEUED 'NEXT' Click'" )
            _NextClick()
        Else
            ConsoleWrite( @CRLF & "Main -- Found a QUEUED 'PREVIOUS' Click'" )
            _PreviousClick()
        EndIf
    EndIf

WEnd

;   =   =   =   =   =   =   =   =   =   =   =   =   =   =   =   =   =   =   =

Func _NextClick()

    $G_AdvanceClickActive = True                            ; We're currently processing an advance click

    ConsoleWrite( @CRLF & "Next called - Current Index = " & $G_CurFileIndex )

    $G_CurFileIndex += 1 ; Try the next index
    $G_LastFileIndex = $G_CurFileIndex

    For $i = 0 To 10000                                     ; Simulate the CPU time needed to display the image
        Local $Lf_Junk = Cos( Random( 0.1, 360.0 ) )
    Next

    $G_AdvanceClickActive = False
    Return

EndFunc   ;==>NextClick
;   =   =   =   =   =   =   =   =   =   =   =   =   =   =   =   =   =   =   =
Func _PreviousClick()

    $G_AdvanceClickActive = True

    ConsoleWrite( @CRLF & "Previous called - Current Index = " & $G_CurFileIndex )

    If $G_CurFileIndex > 0 Then
        $G_CurFileIndex -= 1 ; Try the previous index
        $G_LastFileIndex = $G_CurFileIndex
        For $i = 0 To 10000                                     ; Simulate the CPU time needed to display the image
            Local $Lf_Junk = Cos( Random( 0.1, 360.0 ) )
        Next
    EndIf

    $G_AdvanceClickActive = False
    Return

EndFunc
;   =   =   =   =   =   =   =   =   =   =   =   =   =   =   =   =   =   =   =
Func _QueuePicAdv( $arg_PicAdvanceDirection )

    If $G_PicAdvClickQueueIdx < $Gc_PicAdvClickQueueMax Then
        $G_PicAdvClickQueue[$G_PicAdvClickQueueIdx] = $arg_PicAdvanceDirection
        $G_PicAdvClickQueueIdx += 1
    Else
        ConsoleWrite( @CRLF & "_QueuePicAdv -- Pic Advance Queue Overrun! - Exiting")
        Exit
    EndIf
    Return
EndFunc
;   =   =   =   =   =   =   =   =   =   =   =   =   =   =   =   =   =   =   =
Func _DeQueuePicAdv()

    Local $Lf_AdvanceDirection = -1     ; Default is nothing queued

    If $G_PicAdvClickQueueIdx > 1 Then
        $G_PicAdvClickQueueIdx -= 1
        $Lf_AdvanceDirection = $G_PicAdvClickQueue[$G_PicAdvClickQueueIdx]
    EndIf
    Return $Lf_AdvanceDirection
EndFunc
;   =   =   =   =   =   =   =   =   =   =   =   =   =   =   =   =   =   =   =
Func _MyLeftClickHandler()

    Local $Lf_ControlID

    Local $Lf_CursorInfo = GUIGetCursorInfo()

    $Lf_ControlID = $Lf_CursorInfo[4]

    If ($Lf_ControlID = $G_PreviousBtnID) Or ($Lf_ControlID = $G_NextBtnId) Then

        $G_TOTAL_PICADV_CLICK_COUNT += 1

        If $G_AdvanceClickActive Then
            If $Lf_ControlID = $G_PreviousBtnId Then
                $G_CUR_PICADV_INDEX -= 1
                _QueuePicAdv( $Gc_PreviousClicked )
            Else
                $G_CUR_PICADV_INDEX += 1
                _QueuePicAdv( $Gc_NextClicked )
            EndIf
        EndIf

    EndIf

    Return $MOE_RUNDEFPROC
EndFunc
;   =   =   =   =   =   =   =   =   =   =   =   =   =   =   =   =   =   =   =
Func _GUIWinClose()
    Exit
EndFunc

Please let me know if I've made more stupid mistakes...

Download Modified MouseOnEvent for x64 mode: MouseOnEvent64.au3

Unfortunately, I don't know how to give you runnable code that does reproduce the problem.

Edited by Mbee
Link to comment
Share on other sites

  • Moderators

Mbee,

The fact you are having problems getting a reproducer script to demonstrate the effect makes me pretty sure that you are removing these events from the message queue in a section of your code somewhere in the original larger script. AutoIt does not eat events - or else we would have many such complaints, which we do not. Unless you can provide some code which does show the same effect - or let us see the whole script (and pray we can spot something) - I am afraid that we cannot really help you any further.

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...