# Row Sum (Σ) Formula Validation

## Recommended Posts

Much work still needs to be done on my current project, but design concepts often benefit more from early criticism. Although there may be nothing particularly innovative about this project, user experience is everything. I would like you to look at the behaviour of the controls on this GUI. Unless you type something really awful, it allows you to finish typing the formula before testing the input. When typing into an edit control, pressing the enter key activates the okay button.

The program itself, mainly consists of a listview control, which you can't see - just imagine it looks like a stone age version of Excel with a nice paint job, but no bells or whistles. What Row Sum (Σ) is intended to do is loop through all the rows, calculate a sum and print the output in a newly created column. The user is prompted to type a formula into the following GUI. Please try to figure it out, and break it any way you can.

#include <GUIConstants.au3>
#include <GuiEdit.au3>
#include <Misc.au3>

Global \$g_iAvailableCols = 24 ; arbitary dev variable [column count will eventually be read from a listview control]

; missing several thousand lines of code...

Formula()

; caution about including columns containing empty fields in the formula
; empty fields are treated as zero
; with addition and subtraction there is never any problem
; multiplication by an empty field (or by zero) returns zero
; division by an empty field (or by zero) returns an empty field [unless - see exception]
; use of the power operator is limited to rows in which all referenced fields contain numbers
; imaginary roots of negative numbers return an empty field [unless - see exception]
; exception: infinity (or an imaginary number) to the power of zero returns a meaningless number

Func FormulaSyntax()
MsgBox(BitOR(64, 8192), "Row Sum (" & ChrW(0x03A3) & ") : Syntax To Use", _ ; \$MB_ICONINFORMATION, \$MB_TASKMODAL
" mathematical operators :" & @TAB & "+ - * / ^" & @CRLF & _
" column numbers :" & @TAB & @TAB & "c1, c2, c3  etc..." & @CRLF & _
" decimal digits :" & @TAB & @TAB & "0 to 9 and ." & @CRLF & _
" parenthesis :" & @TAB & @TAB & "( )" & @CRLF & _
" minus sign :" & @TAB & @TAB & "-1, -c2, -(c3)  etc..." & @CRLF & _
" example :" & @TAB & @TAB  & @TAB & "c1 +c2 -c3")
EndFunc ;==> FormulaSyntax

Func Formula() ; (\$hParent, \$idListView, \$hListView) ; [missing parent window]
Local \$sTitle = "Row Sum (" & ChrW(0x03A3) & ")", _
\$iStyle = BitOR(\$WS_CAPTION, \$WS_POPUP, \$WS_SYSMENU), _
\$iExStyle = BitOR(\$WS_EX_MDICHILD, \$WS_EX_TOOLWINDOW, \$WS_EX_TOPMOST)

Local \$hChild = GUICreate(\$sTitle, 334 +25, 105 +1, Default + 100, Default + 100); , \$iStyle, \$iExStyle, \$hParent)

Local \$hLabel = GUICtrlCreateLabel("Formula :", 8, 8, 55, 18)
GUICtrlSetFont(-1, 10)

Local \$hSyntax = GUICtrlCreateButton("???", 72, 7, 40, 20)

Local \$hLabel = GUICtrlCreateLabel("Header :", 127, 8, 49, 18)
GUICtrlSetFont(-1, 10)

Local \$hHeader = GUICtrlCreateInput("", 182, 7, 170, 20)
GUICtrlSetFont(-1, 10)

Local \$hInput = GUICtrlCreateInput("", 7, 33, 320 +25, 40, BitOR(\$WS_TABSTOP, \$ES_MULTILINE))
GUICtrlSetFont(-1, 10)

Local \$hCheckBox = GUICtrlCreateCheckbox(" Round to", 7, 79, 75, 20)
GUICtrlSetFont(-1, 10)

Local \$hPlaces = GUICtrlCreateInput("2", 86, 79 +1, 20, 20, BitOR(\$WS_TABSTOP, \$ES_CENTER, \$ES_NUMBER))
GUICtrlCreateLabel("decimal places", 114 -2, 79 +2, 92, 18)
GUICtrlSetFont(-1, 10)

Local \$hCancel = GUICtrlCreateButton("Cancel", 210, 79 +1, 66, 20)

Local \$hOkay = GUICtrlCreateButton("OK", 285, 79 +1, 66, 20)
GUISetState(@SW_SHOW)

Local \$sInput = "", \$aArray, \$iError = 0, \$iCols = \$g_iAvailableCols ; \$iCols = _GUICtrlListView_GetColumnCount(\$hListView), _ ; >>> CHANGE THIS LATER
;\$iRows = _GUICtrlListView_GetItemCount(\$hListView), \$aColOrder = _GUICtrlListView_GetColumnOrderArray(\$hListView)

Local \$vTemp, \$msg2, \$iPlaces = '2'
While 1
\$msg2 = GUIGetMsg()
If \$msg2 = \$hCancel Or \$msg2 = \$GUI_EVENT_CLOSE Then ExitLoop

If \$msg2 = \$hSyntax Then
FormulaSyntax()
ContinueLoop
EndIf

If \$vTemp <> \$iPlaces Then
If \$vTemp > 14 Then
GUICtrlSetData(\$hPlaces, 14)
\$iPlaces = 14
_GUICtrlEdit_SetSel(\$hPlaces, 0, -1)
ElseIf Not \$vTemp Then
GUICtrlSetData(\$hPlaces ,'0')
\$iPlaces = '0'
_GUICtrlEdit_SetSel(\$hPlaces, 0, -1)
EndIf
EndIf

If BitAND(GUICtrlRead(\$hCheckBox), \$GUI_CHECKED) == \$GUI_CHECKED _
And BitAND(GUICtrlGetState(\$hPlaces), \$GUI_DISABLE) == \$GUI_DISABLE Then
GUICtrlSetState(\$hPlaces, \$GUI_ENABLE)
ElseIf BitAND(GUICtrlRead(\$hCheckBox), \$GUI_CHECKED) <> \$GUI_CHECKED _
And BitAND(GUICtrlGetState(\$hPlaces), \$GUI_ENABLE) == \$GUI_ENABLE Then
GUICtrlSetState(\$hPlaces, \$GUI_DISABLE)
EndIf

If \$sFormula <> \$sInput Then
If StringRegExp(\$sFormula, '[^ ]') Then ; spaces between components are ignored

If Not ValidSyntax(\$sFormula, \$iCols) Then
If @extended < 5 Then
If \$iError = 0 Then GUICtrlSetBkColor(\$hInput, 0xFFA090)
\$iError = 1
ElseIf \$iError Then
GUICtrlSetBkColor(\$hInput, 0xFFFFFF)
\$iError = 0
EndIf

ElseIf \$iError Then
GUICtrlSetBkColor(\$hInput, 0xFFFFFF)
\$iError = 0
EndIf

ElseIf \$iError Then
GUICtrlSetBkColor(\$hInput, 0xFFFFFF)
\$iError = 0
EndIf
\$sInput = \$sFormula
EndIf

;  BitAND(WinGetState(\$hChild), \$WIN_STATE_ACTIVE) = 8
If \$msg2 = \$hOkay Or (_IsPressed("0D") And BitAND(WinGetState(\$hChild), 8) = 8 And (ControlGetFocus(\$hChild) = "Edit2" Or ControlGetFocus(\$hChild) = "Edit1")) Then
If StringRegExp(\$sFormula, '[^ ]') And ValidSyntax(\$sFormula, \$iCols) Then
; missing formula execution code

MsgBox(0, "VALID SYNTAX", "Well done, your formula can safely be executed, but" & @CRLF & "can't find parent window.")
ExitLoop
Else
Switch @extended
Case 1
\$vTemp = "The formula contains illegal characters."
Case 2
\$vTemp = "No such column exists."
Case 3
\$vTemp = "The formula contains a syntax error."
Case 4
\$vTemp = "The formula is missing opening parenthesis."
Case 5
\$vTemp = "The formula is unterminated"
case 6
\$vTemp = "The formula is missing closing parenthesis."
EndSwitch

MsgBox(262160, "uh-uh!", StringRegExp(\$sFormula, '[^ ]') ? \$vTemp : "Please enter a formula.")
While _IsPressed("0D")
Sleep(50)
WEnd
;\$iError = 1
EndIf
EndIf
WEnd
GUIDelete(\$hChild)
EndFunc ; formula

Func ValidSyntax(\$sFormula, \$iMax) ; [currently requires external check that string <> ""]
; quick test for accepted characters
If StringRegExp(\$sFormula, '(?i)[^c \d\.\+\-\*/\^\(\)]') Then Return SetExtended(1, False) ; illegal characters
If StringRegExp(\$sFormula, '(?i)\.\D|c[0\D]|\d\s+[\.\d]') Then Return SetExtended(3, False) ; syntax

\$sFormula = StringStripWS(\$sFormula, 8) ; strip all spaces

; split to separate formula components
Local \$aFormula = StringRegExp(\$sFormula, '(?i)\-?c\d+|\-?c|\-?\d*\.\d*|\-?\d+|\-\(|[\+\-\*/\^\(\)]|.+', 3), _ ; create array [ADDED] ==> |.+
\$iLast, \$sTest, \$sExpect = '(?i)\-?\(|\-?c\d+|\-?c|\-?\d*\.\d*|\-?\d+|\-', _ ; valid first component
\$iBracket = 0, \$bSyntax = False, \$bNoSuch = False, \$bTermination = False ; error tracking variables

For \$i = 0 To UBound(\$aFormula) -1
If Not StringRegExp(\$aFormula[\$i], \$sExpect) Then ; unexpected code sequence
\$bSyntax = True
ExitLoop
EndIf

If StringRegExp(\$aFormula[\$i], '(?i)\-?c\d+') Then ; column number
\$sTest = StringRegExpReplace(\$aFormula[\$i], '(?i)[\-c]+', '')
If \$sTest > \$iMax Or \$sTest == 0 Then ; no such column exists
\$bNoSuch = True
ExitLoop
EndIf
\$sExpect = '[\+\-\*/\^\)]' ; operators / closing brackets

ElseIf StringRegExp(\$aFormula[\$i], '\-?\d*\.\d*') Then ; decimal
If \$aFormula[\$i] == '.' Or \$aFormula[\$i] == '-.' Then
If \$i = UBound(\$aFormula) -1 Then
\$bTermination = True
ExitLoop
EndIf
\$bSyntax = True ; badly formated decimal
ExitLoop
EndIf
\$sExpect = '[\+\-\*/\^\)]' ; as above

ElseIf StringRegExp(\$aFormula[\$i], '\-?\d+') Then ; integer
\$sExpect = '[\+\-\*/\^\)]'

ElseIf StringRegExp(\$aFormula[\$i], '\A[\+\-\*/\^]\z') Then ; operator
\$iLast = UBound(\$aFormula) -1
If \$i = \$iLast Or (\$i = \$iLast -1 And \$aFormula[\$iLast] == '-') Then
\$bTermination = True
ExitLoop
EndIf
\$sExpect = '(?i)\-?\(|\-?c\d+|\-?c|\-?\d*\.\d*|\-?\d+'

ElseIf \$aFormula[\$i] == '(' Or \$aFormula[\$i] == '-(' Then ; opening bracket
\$iBracket += 1
\$sExpect = '(?i)\-?\(|\-?c\d+|\-?c|\-?\d*\.\d*|\-?\d+|\-'

ElseIf \$aFormula[\$i] == ')' Then ; closing bracket
\$iBracket -= 1
\$sExpect = '[\+\-\*/\^\)]'

ElseIf \$aFormula[\$i] = 'c' Or \$aFormula[\$i] = '-c' Then ; unterminated column number
If \$i = UBound(\$aFormula) -1 Then
\$bTermination = True
Else
\$bSyntax = True
ExitLoop
EndIf

Else ; unexpected exception [this should never happen]
\$bSyntax = True
ExitLoop
EndIf
If \$iBracket < 0 Then ExitLoop ; closing (unopened) parenthesis error

; [formula looks okay so far]
Next

; better to be a bit wordy [for clarity]
If \$bNoSuch Then Return SetExtended(2, False) ; no such column exists
If \$bSyntax Then Return SetExtended(3, False) ; syntax error
If \$iBracket < 0 Then Return SetExtended(4, False) ; missing opening parenthesis
If \$bTermination Then Return SetExtended(5, False) ; formula may not terminate with operator or c
If \$iBracket > 0 Then Return SetExtended(6, False) ; missing closing parenthesis
; ConsoleWrite('valid' & @LF)
Return True ; formula is correct
EndFunc ;==> ValidSyntax

Edited by czardas

##### Share on other sites

Just did a quick test.
You stated that "user experience is everything". I, as a user, would like to see the general error message "The formula you entered contains errors." replaced by helpful error messages like "no such column exists" etc.

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2020-10-10 - Version 1.5.2.1) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2020-12-15 - Version 1.6.3.1) - Download - General Help & Support - Example Scripts - Wiki
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
PowerPoint (2017-06-06 - Version 0.0.5.0) - Download - General Help & Support
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki, WebDriver - Wiki

##### Share on other sites

Thanks water , how very true. I should have added that part: all the information is returned by ValidSyntax() with the @extended flag. I was just too lazy to add the final code (or distracted by other concerns). I was more wondering if I might have missed something while testing formula syntax.

##### Share on other sites

Just noticed that there is a limit of 24 columns. Would be fine to have this described in the help function

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2020-10-10 - Version 1.5.2.1) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2020-12-15 - Version 1.6.3.1) - Download - General Help & Support - Example Scripts - Wiki
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
PowerPoint (2017-06-06 - Version 0.0.5.0) - Download - General Help & Support
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki, WebDriver - Wiki

##### Share on other sites

The limit is a temporary measure. You can change it to any number you like > 0. Modify this line:

Global \$g_iAvailableCols = 24 ; arbitary dev variable [column count will eventually be read from a listview control]

Edited by czardas

##### Share on other sites

I mean: Modify the help page to

" column numbers :" & @TAB & @TAB & "c1, c2, c3  etc. maximum is c" & \$g_iAvailableCols & @CRLF & _

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2020-10-10 - Version 1.5.2.1) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2020-12-15 - Version 1.6.3.1) - Download - General Help & Support - Example Scripts - Wiki
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
PowerPoint (2017-06-06 - Version 0.0.5.0) - Download - General Help & Support
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki, WebDriver - Wiki

##### Share on other sites

If the # of decimal places exceeds 14 then it is set to the # of allowed columns (now 24).
Is this intended by you?

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2020-10-10 - Version 1.5.2.1) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2020-12-15 - Version 1.6.3.1) - Download - General Help & Support - Example Scripts - Wiki
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
PowerPoint (2017-06-06 - Version 0.0.5.0) - Download - General Help & Support
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki, WebDriver - Wiki

##### Share on other sites

Maybe, I get what you are saying. There will be a help menu topic. I wanted to know if it is possible to figure out what's going on without the need to refer to help topics. There has to be a quick syntax reference though. I'm just about to update the first post to include a more detailed error report.

##### Share on other sites

Oops, I missed your last question about decimal places (post #7): an error crept in on my first edit which I have now fixed. I also notice that the final error message doesn't entirely like the enter key when an edit control has focus. It's an easy fix.

Edit: The enter key issue has also been fixed now.

Edited by czardas

##### Share on other sites

Another validation bugfix, although you probably won't notice any difference. In theory it should be easy to quickly learn how to type a formula with just the information available. How easy do you think this is? Does the colour change assist you or annoy you?

Edited by czardas

##### Share on other sites

I like the colour change because it immediately tells me that the last letter/number I entered was wrong.

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2020-10-10 - Version 1.5.2.1) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2020-12-15 - Version 1.6.3.1) - Download - General Help & Support - Example Scripts - Wiki
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
PowerPoint (2017-06-06 - Version 0.0.5.0) - Download - General Help & Support
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki, WebDriver - Wiki

##### Share on other sites

@water I couldn't ask for a better critic after all the work you have done creating the Excel UDF. I really appreciate you taking the time to try it.

##### Share on other sites

Thanks

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2020-10-10 - Version 1.5.2.1) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2020-12-15 - Version 1.6.3.1) - Download - General Help & Support - Example Scripts - Wiki
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
PowerPoint (2017-06-06 - Version 0.0.5.0) - Download - General Help & Support
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki, WebDriver - Wiki

##### Share on other sites

I've made some small improvements to the code in first post. I may change it to allow rounding up to 15 decimal places. Once I implement this code, it may become unrecognizable. While this may not be the most exciting topic of discussion, I'm also posting the code I've just written for rounding and formatting the executed formula, since it is part of the same module: it might also be of inspiration to someone. It is currently intended that the formula will return a double. The following code runs with all the safeties turned off (potentially returning up to 17 significant digits along with a load of zeros). The user will be advised (not forced) to remain within 15 significant figures when rounding. Trailing zero padding is added by default.

MsgBox(0, "", DecimalPlaces(Execute('0.30000000000000099'), 15))
MsgBox(0, "", DecimalPlaces(Execute('2/-3'), 15))
MsgBox(0, "", DecimalPlaces(Execute('-0.000000000000011 *3'), 15))
MsgBox(0, "", DecimalPlaces(Execute('10000000000000.01000000000000000'), 15))
MsgBox(0, "", DecimalPlaces(Execute('-123456789012345.6199123458989'), 3))
MsgBox(0, "", DecimalPlaces(1.8734176520787252e+004, 12)) ; lucky number!
MsgBox(0, "", DecimalPlaces(Execute('-000222222222222222922222222222222222222200.888888888888888*2'), 14))

; accepts doubles
Func DecimalPlaces(\$fNumber, \$iPlaces = 2) ;, \$bTrailingZeros = True) ; [add this option later along with program settings]
; error checks [magnitude maybe]
\$iPlaces = Int(\$iPlaces) ; max = 15
\$fNumber = Number(\$fNumber, 3) ; convert to double (just in case) [more complex routines could also be written: BigNum etc...]

Local \$bNeg = False
If StringLeft(\$fNumber, 1) == '-' Then
\$bNeg = True
\$fNumber = Abs(\$fNumber)
EndIf

\$fNumber = Round(\$fNumber, \$iPlaces)

Local \$nDigits, \$iExponent, \$nOutput, \$iLen, \$iDot = StringInStr(\$fNumber, '.')
If StringInStr(\$fNumber, 'e') Then
\$nDigits = StringReplace(StringRegExpReplace(\$fNumber, 'e[\+\-]\d+\z', ''), '.', '')
\$iLen = StringLen(\$nDigits)
\$iExponent = StringRight(\$fNumber, 4)
If \$iLen = 15 Then ; [uh-uh - rounding had no discernible effect on length]
\$iLen = \$iExponent + \$iPlaces +1
\$nDigits = __FloatToDigits(\$fNumber, ((\$iLen < 16) ? \$iLen : 16)) ; return all 17 digits of the rounded double [it makes sense]
\$iExponent = @extended
\$iLen = StringLen(\$nDigits)
Else
\$iExponent += (1 -\$iLen)
EndIf

ElseIf \$iDot And StringLen(\$fNumber) < 16 Then
\$nOutput = StringLeft(\$fNumber & '000000000000000', \$iDot + \$iPlaces)
If \$bNeg Then \$nOutput = '-' & \$nOutput
Return \$nOutput

Else
\$iLen =  (\$iDot ? \$iDot : StringLen(\$fNumber)) + \$iPlaces
\$nDigits = __FloatToDigits(\$fNumber, ((\$iLen < 16) ? \$iLen : 16))
\$iExponent = @extended
\$iLen = StringLen(\$nDigits)
EndIf

Local \$sZeros = '000000000000000'
If \$iExponent < 0 Then
Local \$iGap = \$iLen + \$iExponent
If \$iGap < 1 Then
\$nOutput = '0.' & StringLeft(\$sZeros, Abs(\$iGap)) & \$nDigits
Else
\$nOutput = StringLeft(\$nDigits, \$iGap) & '.' & StringRight(\$nDigits, \$iLen -\$iGap)
EndIf

\$iGap = \$iLen -\$iGap
If \$iGap < \$iPlaces Then
\$nOutput &= StringLeft(\$sZeros, \$iPlaces -\$iGap)

ElseIf \$iGap > \$iPlaces Then ; this one slipped through the net
Local \$bAddOne = (StringMid(\$nOutput, StringInStr(\$nOutput, '.') +\$iPlaces +1, 1) >= 5) ? True : False ; round up
\$nOutput = StringTrimRight(\$nOutput, \$iGap -\$iPlaces)

If \$bAddOne Then ; when all else fails, use the old fashioned method
Local \$vNext, \$nRound
For \$i = StringLen(\$nOutput) To 1 Step -1
\$vNext = StringMid(\$nOutput, \$i, 1)
If \$vNext = '.' Then
\$nRound &= '.'
Else
\$vNext += 1
If \$vNext < 10 Then
\$nRound &= \$vNext
\$nOutput = StringLeft(\$nOutput, \$i -1) & StringReverse(\$nRound)
ExitLoop ; this should happen on the first run [does this loop ever actually repeat?]
EndIf
\$nRound &= '0'
EndIf
Next
If \$bAddOne Then \$nOutput = '1' & StringReverse(\$nRound)
EndIf
EndIf

Else
While StringLen(\$sZeros) < \$iExponent
\$sZeros &= '000000000000000'
WEnd

\$nOutput = \$nDigits & StringLeft(\$sZeros, \$iExponent) & '.' & StringLeft('000000000000000', \$iPlaces)
EndIf

If \$iPlaces = 0 Then \$nOutput = StringReplace(\$nOutput, '.', '')
If \$bNeg And StringRegExp(\$nOutput, '[1-9]') Then \$nOutput = '-' & \$nOutput

Return \$nOutput
EndFunc ;==> DecimalPlaces

; function taken from : Fraction.au3
; #INTERNAL_USE_ONLY# ==========================================================================================================
; Name...........: __FloatToDigits
; Description ...: Extracts a specified number of digits from a float.
; Syntax.........: __FloatToDigits(\$fFloat, \$iDigits)
; Parameters.....; \$fFloat - The float to extract the digits from.
;                  \$iDigits - The number of digits to extract after the floating point (exponential representation).
; Return values .: Success - Returns a 32-bit or 64-bit signed integer.
;                  Sets @extended to the decimal exponent. ==> \$fFloat = return value * 10 ^ exponent
;                  Failure sets @error to 1 if the input is not a float or undefined.
; Author ........: czardas
; ==============================================================================================================================
Func __FloatToDigits(\$fFloat, \$iDigits = 14)
If VarGetType(\$fFloat) <> 'Double' Or StringInStr(\$fFloat, '#') Then Return SetError(1)
Local \$iSign = (\$fFloat < 0) ? -1 : 1
; machine epsilon = 5 × 10^-15, so the final two digits (16 and 17) could be highly innacurate
\$fFloat = StringFormat('%.' & \$iDigits & 'e', \$fFloat) ; rounds to the specified number of decimal places

Local \$aFloat = StringSplit(\$fFloat, "e", 2) ; zero-based array
If \$iSign < 0 Then \$aFloat[0] = StringTrimLeft(\$aFloat[0], 1) ; remove the minus sign

; remove the decimal point and trailing zeros
\$aFloat[0] = StringLeft(\$aFloat[0], 1) & StringRegExpReplace(StringRight(\$aFloat[0], \$iDigits), '(0+\z)', '')
\$aFloat[1] += 1 - StringLen(\$aFloat[0]) ; adjust the exponent to accommodate changes

Return SetExtended(\$aFloat[1], Int(\$aFloat[0]) * \$iSign) ; add back the minus sign
EndFunc ;==> __FloatToDigits

There may yet be some superfluous (and therefore dubious) lines of code in the above example. I'll try removing them later, and see if it breaks anything. Which is worse, broken code or fuzzy human logic?

Edited by czardas
code tidying

##### Share on other sites

Oh my! The worst is broken code with fuzzy human logic. I'm sure there must be a trick I can use like adding '.0' and just throwing the value into some engine designed by someone who can read the mind of the user.

##### Share on other sites

The above code has now been implemented and seems to work like a charm. I was also thinking of adding a column ratio feature, but I'm not sure how useful it might be. Here someone asks how to do this: http://stackoverflow.com/questions/472989/how-do-i-display-a-ratio-in-excel-in-the-format-ab , and I want to know why. Can you think of any practical applications?

Edited by czardas

##### Share on other sites

No, not really

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2020-10-10 - Version 1.5.2.1) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2020-12-15 - Version 1.6.3.1) - Download - General Help & Support - Example Scripts - Wiki
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
PowerPoint (2017-06-06 - Version 0.0.5.0) - Download - General Help & Support
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki, WebDriver - Wiki

##### Share on other sites

I suppose application may be limited, but I think it looks nice. It can be useful in music theory or calculating betting odds, or if you just want to annoy people on stackoverflow.

## Create an account

Register a new account

• ### Similar Content

• By paw
I use SetSoundDevice to control my audio devices but the UI was either

blurry like this:
or unusable like this:

so I made this horrible thing to add scaling to the GUI:
#Region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_Change2CUI=y #AutoIt3Wrapper_Res_HiDpi=y #AutoIt3Wrapper_AU3Check_Parameters=-w 3 -w 4 -w 5 #AutoIt3Wrapper_Run_Au3Stripper=y #Au3Stripper_Parameters=/sf /sv /rm #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** #include <File.au3> ;~ _convertGUI("") If \$CmdLine[0] <> 0 Then _convertGUI(\$CmdLine[1]) Func _convertGUI(\$sFilePath) If \$sFilePath <> "" Then Local \$aArray = FileReadToArray(\$sFilePath) Else ;TEST DATA Local \$aArray[6] = ['\$H_Res_Language = GUICtrlCreateProgress(5, 120, 210 + 25, 480, 20, BitOR(\$GUI_SS_DEFAULT_COMBO, \$CBS_SIMPLE)) ; \$CBS_DROPDOWNLIST)', _ 'Local \$h_Ok = GUICtrlCreateButton("Ok", 72, 224, 81, 33, 0)', _ 'GUICreate(\$Warning_TiTle, 700, 310, -1, -1, \$WS_SIZEBOX + \$WS_SYSMENU + \$WS_MINIMIZEBOX)', _ 'GUICtrlCreateLabel("Output type: ", 30, 130, 65, 20) ;, \$SS_RIGHT)', _ '\$H_FieldNameEdit = GUICtrlCreateEdit(\$INP_FieldNameEdit, 100,260+25, 500, 150 - 25) ;comment', 'Local \$H_CANCEL = GUICtrlCreateGraphic("Cancel", 224, 224, 97, 33, 0)'] EndIf Local \$hTimer = TimerInit(), \$iGUIElementCount = 0, \$sResult = "", \$sFileName = "", \$sDrive = "", \$sDir = "", \$sExtension = "" If @Compiled Then _PathSplit(\$sFilePath, \$sDrive, \$sDir, \$sFileName, \$sExtension) \$sFileName = StringRegExpReplace(\$sFilePath, "^.*\\", "") EndIf For \$i = 0 To (UBound(\$aArray) - 1) If StringRegExp(\$aArray[\$i], "GUICtrlCreate|GUICreate") Then \$sResult = _splitComma(\$aArray[\$i]) If Not @error Then \$aArray[\$i] = \$sResult \$iGUIElementCount += 1 EndIf Next ConsoleWrite("t = " & TimerDiff(\$hTimer) & " GUI elements = " & \$iGUIElementCount & " lines = " & (UBound(\$aArray) - 1) & @CRLF) If \$sFileName <> "" Then Local \$hFile = FileOpen("edited." & \$sFileName, 2) _FileWriteFromArray("edited." & \$sFileName, \$aArray) FileClose(\$hFile) EndIf Exit EndFunc ;==>_convertGUI Func _splitComma(\$sString) Local \$sSplitResult = "", \$sTrimmedR = "", \$sTrimmedL = "" Local \$aSplit = StringSplit(\$sString, ',') If Not @error Then \$sTrimmedR = "" \$sTrimmedL = "" For \$j = 1 To \$aSplit[0] If StringRegExp(\$aSplit[1], "(?:.GUICtrlCreateGraphic|GUICtrlCreateProgress|GUICtrlCreateSlider|GUICtrlCreateTab|GUICtrlCreateTreeView)") Then If \$j = 1 Then While StringLeft(\$aSplit[\$j], 1) <> '(' \$sTrimmedL &= StringLeft(\$aSplit[\$j], 1) \$aSplit[\$j] = StringTrimLeft(\$aSplit[\$j], 1) WEnd \$aSplit[\$j] = StringTrimLeft(\$aSplit[\$j], 1) EndIf EndIf If \$j = \$aSplit[0] Then While StringRight(\$aSplit[\$j], 1) <> ')' \$sTrimmedR &= StringRight(\$aSplit[\$j], 1) \$aSplit[\$j] = StringTrimRight(\$aSplit[\$j], 1) WEnd \$aSplit[\$j] = StringTrimRight(\$aSplit[\$j], 1) EndIf If StringRegExp(\$aSplit[\$j], "[0-9]") And \$aSplit[\$j] <> -1 And \$aSplit[\$j] <> 0 And \$aSplit[\$j] <> 1 And Not StringInStr(\$aSplit[\$j], ')') Then If StringRegExp(\$aSplit[\$j], "\-|\+") Then ;put parenthesis around + or - \$aSplit[\$j] = '(' & \$aSplit[\$j] & ")*\$g_DPI" Else \$aSplit[\$j] = \$aSplit[\$j] & "*\$g_DPI" EndIf EndIf If \$j < \$aSplit[0] Then \$sSplitResult &= \$aSplit[\$j] & ',' ElseIf \$j = \$aSplit[0] Then \$sSplitResult &= \$aSplit[\$j] & ')' Else \$sSplitResult &= \$aSplit[\$j] EndIf Next If \$sTrimmedR <> "" Then \$sSplitResult &= StringReverse(\$sTrimmedR) If \$sTrimmedL <> "" Then \$sSplitResult = \$sTrimmedL & '(' & \$sSplitResult Else SetError(1) Return EndIf ConsoleWrite(\$sSplitResult & @CRLF) Return \$sSplitResult EndFunc ;==>_splitComma
And now it looks good:
but it doesn't work on everything, for example the "GUICtrlCreateLabel("Output type: ", 30, 130, 65, 20) ;, \$SS_RIGHT)" (from the autoit3wrapper gui)
because the comment contains a parenthesis and it would break completely if there were variables as parameters..
Is there some kind of parser around that I could use instead or maybe someone who has already done something like this?
• By TXTechie
Hello Everyone,
I've developed my own GUI using AutoIt and I'm allowing users to minimize the GUI, but I also want to include some kind of timer so that it will automatically restore the GUI after something like 30 minutes or an hour. However, I also want them to be able to manually restore the GUI by clicking the application's icon in the taskbar.
I've searched through the forums, but I'm not sure how to get started.
Any ideas or functions to research are appreciated!
Regards,
TX Techie
• By Rskm
Hi, recently i created a GUI for some calculations in AutoIT.  The GUI has 2 tabs and on the first tab, it has few inputboxes where i use to click with mouse and start entering the inputs. i recently made some changes in the position of these textboxes. I made this by changing the autoit code file instead of making changes in KODA. Now i cannot click inside these textboxes with mouse. However, i can use TAB key to cycle through/enter input in these input boxes. what could have made the inputboxes not responding to mouseclicks. thanks

• Hi everyone,
I am bit stumped as to why I am not able to set the time in the Date control
#include <DateTimeConstants.au3> #include <GUIConstantsEx.au3> #include <MsgBoxConstants.au3> Example() Func Example() GUICreate("My GUI get date", 200, 200, 800, 200) Local \$idDate = GUICtrlCreateDate("1953/04/25", 10, 10, 185, 20, \$DTS_TIMEFORMAT) ; to select a specific default format Local \$sStyle = "HH:mm:ss" GUICtrlSendMsg(\$idDate, \$DTM_SETFORMATW, 0, \$sStyle) ; Set time Local \$iRet = GUICtrlSetData(\$idDate, '13:33:37') ConsoleWrite('GUICtrlSetData returned ' & (\$iRet = 1 ? 'success' : 'failure') & @CRLF) GUISetState(@SW_SHOW) ; Loop until the user exits. While GUIGetMsg() <> \$GUI_EVENT_CLOSE WEnd MsgBox(\$MB_SYSTEMMODAL, "Time", GUICtrlRead(\$idDate)) EndFunc ;==>Example The documentation for GUICtrlSetData clearly mentions that it uses the same format as GUICtrlRead:
But I get failure
What gives?
Thanks for the help in advance!

• Introduction
ImGui is a popular library written by ocornut, it can make awesome user interface based on directx. It is being used by many big apps/games.  The UI is nice and flexible, easy to use because of frame-by-frame drawing. So I decided to convert the entire ImGui library to AutoIt
At first it's just an experiment, i converted some basic draw functions of imgui, compile to a dll, then using DllCall in autoit to call the functions. I was testing to see how much FPS i can get in autoit, and i was expected a low FPS, since autoit is slow. Suprisingly, the FPS turned out to be so high, it works really fast, even when drawing 1000 buttons at the same time. Features
More than +270 functions converted from ImGui (compiled dll). Has 90% of the capability of what you can do in C++; Usable ImGuiIO and ImGuiStyle, so you can set whatever configurations you like. Preview

Usage
#include <WinAPI.au3> #include "ImGui.au3" ; Create a window Local \$hwnd = _ImGui_GUICreate("AutoIt ImGui", 1024, 768) _WinAPI_ShowWindow(\$hwnd) ; Set style color _ImGui_StyleColorsLight() ;~ _ImGui_StyleColorsDark() Local \$f_value = 5 While 1 ; when the user click close button on the window, this will return false if Not _ImGui_PeekMsg() Then Exit ; must call _ImGui_BeginFrame() _ImGui_Begin("Another window") _ImGui_Text("Hello there..") If _ImGui_Button("click me") Then \$f_value = 5 _ImGui_SliderFloat("slider", \$f_value, 2, 20) If _ImGui_IsItemHovered() Then _ImGui_ToolTip("what r u doing?") _ImGui_End() ; must call _ImGui_EndFrame() Wend
Remark
Most of the functions were converted automatically. I haven't tested all of them yet, if some function doesn't work for you, please tell me. Still missing some features of ImGui, please tell me if you needed any. Run \tools\imgui-au3-setup.au3 to add _ImGui functions to SciTE auto-complete. Source Code
Require: DirectX GitHub: imgui-autoit
×

• Wiki

• Back

• #### Beta

• Git
• FAQ
• Our Picks
×
• Create New...