Jump to content

Inconsistent results from using GUICtrlSetFont


TimRude
 Share

Recommended Posts

When using the GUICtrlSetFont (or GUISetFont), different results occur if you use Default vs "" vs omitting the fontname parameter.

When a control is created and no GUICtrlSetFont command is issued for it (and no GUISetFont setting is in place), the font used is the logical font 'MS Shell Dlg'. This translates (on my Windows 10 system) to the 'Microsoft Sans Serif' font, although this can evidently be changed via the registry settings at 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontSubstitutes'.

If GUICtrlSetFont is used and the Default keyword is used for the fontname parameter, the same thing occurs (i.e. 'MS Shell Dlg' getting translated into 'Microsoft Sans Serif').

However, if GUICtrlSetFont is used and you specify "" as the fontname parameter, the fontname is set to blank. That gets translated by the system to a different font than 'Microsoft Sans Serif'. On my system, it evidently translates to 'Arial' and changes the Quality setting to 255. (I determined it was "Arial" by trying different fonts in the fontname parameter until I got the one that matched the appearance.)

If you use GUICtrlSetFont and you don't specify a fontname parameter at all [i.e. you only specify the font size for example, as in GUICtrlSetFont(-1, 10)], it also evidently translates to 'Arial' but it changes the Quality setting to 2.

Here's a test script illustrating this, followed by a screenshot of the results:

#NoTrayIcon
#include <APIConstants.au3>
#include <WinAPIGdiDC.au3>
#include <SendMessage.au3>
#include <Array.au3>

Local $sText = "AutoIt v3 is a freeware BASIC-like scripting language designed for " & _
        "automating the Windows GUI and general scripting. It uses a combination of " & _
        "simulated keystrokes, mouse movement and window/control manipulation in order " & _
        "to automate tasks in a way not possible or reliable with other languages (e.g. " & _
        "VBScript and SendKeys). AutoIt is also very small, self-contained and will run " & _
        "on all versions of Windows out-of-the-box with no annoying 'runtimes' required!" & _
        @CRLF & @CRLF & _
        "AutoIt was initially designed for PC 'roll out' situations to reliably automate " & _
        "and configure thousands of PCs. Over time it has become a powerful language that " & _
        "supports complex expressions, user functions, loops and everything else that " & _
        "veteran scripters would expect."

GUICreate("Test GUI", 400, 550)
GUICtrlCreateLabel($sText, 10, 10, 380, 125)
GUICtrlSetBkColor(-1, 0xDDDDFF)
ConsoleWrite("Label 1 (no GUICtrlSetFont used at all):" & @TAB)
Local $aFont = _GUICtrlGetFont(-1)
Local $iSize = $aFont[0] ; remember the size for use in the rest of the labels

GUICtrlCreateLabel($sText, 10, 145, 380, 125)
GUICtrlSetBkColor(-1, 0xFFDDFF)
GUICtrlSetFont(-1, $iSize, Default, Default, Default, Default)
ConsoleWrite("Label 2 (using 'Default' for font name):" & @TAB)
_GUICtrlGetFont(-1)

GUICtrlCreateLabel($sText, 10, 280, 380, 125)
GUICtrlSetBkColor(-1, 0xFFFFDD)
GUICtrlSetFont(-1, $iSize, Default, Default, "", Default)
ConsoleWrite('Label 3 (specifying "" for font name):   ' & @TAB)
_GUICtrlGetFont(-1)

GUICtrlCreateLabel($sText, 10, 415, 380, 125)
GUICtrlSetBkColor(-1, 0xDDFFDD)
GUICtrlSetFont(-1, $iSize)
ConsoleWrite("Label 4 (omitting font name parameter):   " & @TAB)
_GUICtrlGetFont(-1)

GUISetState(@SW_SHOW)

While GUIGetMsg() <> $GUI_EVENT_CLOSE
WEnd

Exit

Func _GUICtrlGetFont($id_or_hWnd) ; accepts either Control ID or hWnd

    ; If successful, returns 1D array consisting of:
    ;
    ;   [0] - Size
    ;   [1] - Weight
    ;   [2] - Attribute
    ;   [3] - Name
    ;   [4] - Quality
    ;
    ; If unsuccessful, returns 0 with @error set to non-zero

    If IsHWnd($id_or_hWnd) Then
        Local $hWnd = $id_or_hWnd
    Else
        Local $hWnd = GUICtrlGetHandle($id_or_hWnd)
    EndIf
    If $hWnd = 0 Then Return SetError(1, 1, 0)
    Local $hDC = _WinAPI_GetDC($hWnd)
    Local $iLPY = _WinAPI_GetDeviceCaps($hDC, $LOGPIXELSY)
    _WinAPI_ReleaseDC($hWnd, $hDC)
    Local $tFont = DllStructCreate($tagLOGFONT)
    Local $hFont = _SendMessage($hWnd, $WM_GETFONT)
    If @error Then Return SetError(@error, 2, 0)
    Local $iRet = _WinAPI_GetObject($hFont, DllStructGetSize($tFont), $tFont)
    If $iRet <> 0 Then
        Local $aFont[5]
        $aFont[0] = Abs(Round(DllStructGetData($tFont, 'Height') / $iLPY * 72, 1))
        $aFont[1] = DllStructGetData($tFont, 'Weight')
        $aFont[2] = BitOR( _
                ((DllStructGetData($tFont, "Italic")) ? $GUI_FONTITALIC : 0), _
                ((DllStructGetData($tFont, "Underline")) ? $GUI_FONTUNDER : 0), _
                ((DllStructGetData($tFont, "Strikeout")) ? $GUI_FONTSTRIKE : 0))
        $aFont[3] = StringStripWS(DllStructGetData($tFont, 'FaceName'), BitOR($STR_STRIPLEADING, $STR_STRIPTRAILING))
        $aFont[4] = DllStructGetData($tFont, 'Quality')

        ConsoleWrite("Size = " & $aFont[0] & @TAB & _
                "Weight = " & $aFont[1] & @TAB & _
                "Attrib = " & $aFont[2] & @TAB & _
                "Font Name = " & $aFont[3] & @TAB & _
                "Quality = " & $aFont[4] & @CRLF)

        Return $aFont
    Else
        Return SetError(1, 3, 0)
    EndIf

EndFunc   ;==>_GUICtrlGetFont

image.thumb.png.c5732cf84a45bd75097ade292bbb5f5d.png

Why is this an issue?

Well, consider someone creating a GUI and using the standard font settings. But on some of the controls they want to use bold, underlining, italics, etc. If they have controls created with no GUISetFont or GUICtrlSetFont modifying them, the font on those controls will be Microsoft Sans Serif. But if they then intend to change a control's text to bold print using something like GUICtrlSetFont(-1, Default, $FW_BOLD) they just unwittingly also changed the font on that control to the Arial typeface.

Anyone else ever noticed this?

 

Edited by TimRude
Link to comment
Share on other sites

Hi TimRude :)
I found some indications here & there, hope they'll be useful.

Concerning the Default keyword you use for the GUICtrlSetFont parameters, how do you know what will be its exact behavior ?

Depending on the function, AutoIt help file mentions when Default can be used. If nothing is stipulated in the topic, then the word "Default" should be avoided, as discussed in this post where I exposed my "Default issue" and @Melba23 explained why just after.

Concerning Yashied's great function GUICtrlGetFont() found in this link (I'm wondering why this function isn't part of AutoIt) . It's great you reworked it a bit and used it in your script above. If I understood correctly, it's based on :

* message $WM_GETFONT (which returns a handle to the font used by the control)
* GetObjectW function (in _WinAPI_GetObject) which uses the font handle as 1st parameter
* LOGFONTW structure (filled because a font handle was passed to GetObjectW)

On 2/23/2023 at 7:02 AM, TimRude said:

However, if GUICtrlSetFont is used and you specify "" as the fontname parameter, the fontname is set to blank.

Here is what we read on msdn, first in GetObjectW function :

If hgdiobj is a handle to a font, the LOGFONT that is returned is the LOGFONT used to create the font. If Windows had to make some interpolation of the font because the precise LOGFONT could not be represented, the interpolation will not be reflected in the LOGFONT. For example, if you ask for a vertical version of a font that doesn't support vertical painting, the LOGFONT indicates the font is vertical, but Windows will paint it horizontally.

Then in LOGFONTW structure :

lfFaceName[LF_FACESIZE]
A null-terminated string that specifies the typeface name of the font. The length of this string must not exceed 32 TCHAR values, including the terminating NULL. The EnumFontFamiliesEx function can be used to enumerate the typeface names of all currently available fonts. If lfFaceName is an empty string, GDI uses the first font that matches the other specified attributes.

This could explain why the fontname returned in the LOGFONTW structure is set to blank when you specify "" as the fontname parameter ("no interpolation reflected in the LOGFONT")

On 2/23/2023 at 7:02 AM, TimRude said:

Well, consider someone creating a GUI and using the standard font settings. But on some of the controls they want to use bold, underlining, italics, etc. If they have controls created with no GUISetFont or GUICtrlSetFont modifying them, the font on those controls will be Microsoft Sans Serif. But if they then intend to change a control's text to bold print using something like GUICtrlSetFont(-1, Default, $FW_BOLD) they just unwittingly also changed the font on that control to the Arial typeface.

The solution in this case could be :
1) Use GUICtrlGetFont() to retrieve the correct font informations for the control, including its font name (which will never be blank because the user didn't set the font using GUICtrlSetFont). Let's say this is retrieved :

Size = 8.3    Weight = 400    Attrib = 0    Font Name = MS Shell Dlg    Quality = 0

2) Then use GUICtrlSetFont to alter what you want for the control (altering the weight, below) :

GUICtrlSetFont($idCtrl, 8.3, 700, 0, "MS Shell Dlg", 0)

I just did that in your code, adding these 2 lines just after GUISetState(@SW_SHOW) and it worked fine, the control re-displaying its text in bold after 5s, using the same fontname :

Sleep(5000)
GUICtrlSetFont($idCtrl, 8.3, 700, 0, "MS Shell Dlg", 0) ; $idCtrl being the $id of your 1st label control

It shouldn't be a lot of code... if the function GUICtrlGetFont... was part of AutoIt.

I also found an interesting post from Melba23 where he retrieved "the default GUI font of the machine", using the GetStockObject function, well done M23, this could be useful :)
 

Link to comment
Share on other sites

@pixelsearch Thanks for giving this some attention. And you're right, if all of the parameters are specified whenever you use the GUICtrlSetFont function, the problem is alleviated.

But since most of the parameters of GUICtrlSetFont are defined as optional, it would logically seem that if you choose to omit one or more optional parameters, they shouldn't be applied to the end result. The only required parameters are the control id and the point size. So if only those two parameters are specified, one would logically expect that the other items of the font (weight, attributes, font name, and quality) would be left unchanged. But they are not. So, if you have to specify something for each parameter in order to keep your font settings intact, then none of the parameters are really optional.

In many functions, I can understand where an optional parameter would be assigned a predetermined value if it's not specified. However, in this function where you're using it to set one or more specific font aspects for a control that already has all of those aspects established (at minimum, the control when created inherits all of its font settings from either those defined by GUISetFont or the defaults used by AutoIt), my argument is that leaving an optional parameter unspecified should be interpreted to mean "leave this setting as is", not "update this setting to something else".

1 hour ago, pixelsearch said:

Concerning the Default keyword you use for the GUICtrlSetFont parameters, how do you know what will be its exact behavior ?

Depending on the function, AutoIt help file mentions when Default can be used. If nothing is stipulated in the topic, then the word "Default" should be avoided, as discussed in this post where I exposed my "Default issue" and @Melba23 explained why just after.

Yes, I guess I was operating on the erroneous assumption that Default meant whatever the default value of an optional parameter was. But that would make too much sense apparently. 🙄

In the case of the GUICtrlSetFont function, using Default for each parameter ended up with all of the font settings the same as they were before calling the function since Label 1 and Label 2 matched, but that could just mean that Default was ignored as an invalid setting. I dunno.

Link to comment
Share on other sites

Just my thoughts on "Default". If you look at some UDF functions that allow 'Default', you'll see something like:

Func _ArrayToString(Const ByRef $aArray, $sDelim_Col = "|", $iStart_Row = Default, $iEnd_Row = Default, $sDelim_Row = @CRLF, $iStart_Col = Default, $iEnd_Col = Default)
    If $sDelim_Col = Default Then $sDelim_Col = "|"
    If $sDelim_Row = Default Then $sDelim_Row = @CRLF
    If $iStart_Row = Default Then $iStart_Row = -1
    If $iEnd_Row = Default Then $iEnd_Row = -1
    If $iStart_Col = Default Then $iStart_Col = -1
    If $iEnd_Col = Default Then $iEnd_Col = -1

If you actually test what "Default" is with something like this:

ConsoleWrite('Default, Type: ' & VarGetType(Default) & ', Value: ' & Default & @CRLF)

You get: 

Default, Type: Keyword, Value: Default

So, default isn't and/or doesn't mean "use the default value in the function declaration for that parameter", it's literally a "Keyword" with the value of "Default". So as @pixelsearch mentions, 

12 hours ago, pixelsearch said:

AutoIt help file mentions when Default can be used. If nothing is stipulated in the topic, then the word "Default" should be avoided

Which you get now, obviously.

 

Here's another little 'Default' test:

ConsoleWrite('Default, Type: ' & VarGetType(Default) & ', Value: ' & Default & @CRLF)
_DefaultTest_NoDeclaration()
_DefaultTest_Declaration()
_DefaultTest_ValueWithDefault()
_DefaultTest_ValueWithDefault(Default)

Func _DefaultTest_NoDeclaration($vVar = Default)
    ConsoleWrite('_DefaultTest_NoDeclaration $vVar, Type: ' & VarGetType($vVar) & ', Value: ' & $vVar & @CRLF)
EndFunc

Func _DefaultTest_Declaration($vVar = Default)
    If $vVar == Default Then $vVar = 'Meow'
    ConsoleWrite('_DefaultTest_Declaration $vVar, Type: ' & VarGetType($vVar) & ', Value: ' & $vVar & @CRLF)
EndFunc

Func _DefaultTest_ValueWithDefault($vVar = 'Woof')
    If $vVar == Default Then $vVar = 'WoofDefault'
    ConsoleWrite('_DefaultTest_ValueWithDefault $vVar, Type: ' & VarGetType($vVar) & ', Value: ' & $vVar & @CRLF)
EndFunc

And the output:

Default, Type: Keyword, Value: Default
_DefaultTest_NoDeclaration $vVar, Type: Keyword, Value: Default
_DefaultTest_Declaration $vVar, Type: String, Value: Meow
_DefaultTest_ValueWithDefault $vVar, Type: String, Value: Woof
_DefaultTest_ValueWithDefault $vVar, Type: String, Value: WoofDefault

 

Edited by mistersquirrle

We ought not to misbehave, but we should look as though we could.

Link to comment
Share on other sites

Well, we've strayed a bit from my original topic about GUICtrlSetFont, but since we now seem to be discussing the Default keyword...

In VB6/VBA, when you create a Function with optional parameters, you can leave any or all of those optional parameters blank when calling the function like this:

Sub Main()
    Debug.Print MyFunc(10, , , "Widgets") 'supplied only the first and last parameters
    Debug.Print MyFunc(5)                 'supplied only the first parameter
    Debug.Print MyFunc                    'didn't supply any of the parameters
End Sub

Function MyFunc(Optional A As Integer = 1, Optional B As Integer = 2, _
        Optional C As Integer = 3, Optional S As String = "Items") As String
    Debug.Print A, B, C, S
    MyFunc = Str(A + B + C) & " " & S
End Function

If you supply a parameter's value in the function call, it uses what you supplied. Otherwise if you leave an optional parameter blank (but include the separating comma), or don't bother to specify one or more of the right-most optional parameters, it uses the predefined default value for any of the missing parameters.

So the output of running Main in VB would be: 

 10            2             3            Widgets
 15 Widgets
 5             2             3            Items
 10 Items
 1             2             3            Items
 6 Items

 So the question becomes: What equivalent functionality is there in AutoIt?

Let's say you rewrite the VB code above as AutoIt code:

Main()
Exit

Func Main()
    ; ConsoleWrite(MyFunc(10, , , "Widgets") & @CRLF) ; <-- Improper syntax
    ConsoleWrite(MyFunc(5) & @CRLF)
    ConsoleWrite(MyFunc() & @CRLF)
EndFunc

Func MyFunc($A = 1, $B = 2, $C = 3, $S = "Items")
    ConsoleWrite($A & @TAB & $B & @TAB & $C & @TAB & $S & @CRLF)
    Return ($A + $B + $C) & " " & $S
EndFunc

The first line of Main calling MyFunc(10, , , "Widgets") is commented out because it's not valid AutoIt syntax and the script won't run with it uncommented.

The other two lines in Main calling MyFunc work as expected, producing output equivalent to the VB code:

5    2    3    Items
10 Items
1    2    3    Items
6 Items

Let's assume that the user who uses MyFunc doesn't know or care what the predefined values are for the various parameters. They just want to use MyFunc and plug in values for the parameters they do care about and let the function use it's predefined values for any parameters they don't specify.

It seems to me that unless the writer of MyFunc jumps through the hoops of adding code to MyFunc to explicitly allow the user to specify Default as a parameter value and then replacing Default with the predefined value, there is no way to do this. Otherwise, the only time the predefined parameter value(s) would be used is if the user truncated the function call and didn't provide anything for those parameters. Then the missing parameters get assigned the predefined values. But it seems you can only have missing parameters at the end of the function parameter list. There's no way to leave missing parameters in the middle of the parameter list and then supply a value for parameter in the list after the missing ones.

Am I wrong? Is there a way for the user to call MyFunc as it's written, and pass only the first ($A) and last ($S) parameters while telling MyFunc to use whatever predefined values it has for $B and $C? If so, how would that first (commented out) line of Main be written?

Link to comment
Share on other sites

If you think there's more to discuss on your main topic for GUICtrlSetFont just bring it up, I don't mean to derail your thread, but I think that pixelsearch pretty much covered it. 

 

For the recent question, you're not wrong, it's just how AutoIt works. While it may not make a lot of sense to someone who has written in languages where you can skip parameters, or reference them by name for just the ones you want (and don't have to do , , , , , to get to them), that's just not how AutoIt was developed is the answer I suppose.

Here's some official information on the behaviour: https://www.autoitscript.com/autoit3/docs/function_notes.htm

Quote

Many functions contain optional parameters that can be omitted. If you wish to specify an optional parameter, however, all preceding parameters must be specified!
For example, consider Run ( "filename", ["workingdir" [, flag]] ). If you wish to specify the flag, you must specify a workingdir.

When an optional parameter needs to be defined and is preceded by one or more optional parameters, the default value must be given for that parameter. Generally speaking functions should accept the Default keyword when you wish to use the default parameter.

And then the Default keywords own page: https://www.autoitscript.com/autoit3/docs/keywords/Default.htm

Quote

For UDF's, it is the scripter's responsibility to check if the parameter has been set to Default and to perform the desired behavior in this situation.
If used, the passed parameter will be set to the Default keyword and not to an optional parameter value, if defined.

I don't disagree with you on how Default probably should work, but we're not the ones writing the language :) You can always try submitting it as a feature request (https://www.autoitscript.com/trac/autoit/)

We ought not to misbehave, but we should look as though we could.

Link to comment
Share on other sites

No worries. I wasn't complaining, just segueing into my further questions about Default. Since it seems odd to me how the Default keyword is used haphazardly in AutoIt, I was legitimately wondering if I was just missing something. Apparently not. Oh well.

BUT, since it bugs me the way GUISetFont and GUICtrlSetFont presently work when optional parameters are omitted at the end, and since I wanted to add a little extra functionality to them, I'm working on putting together enhanced (in my opinion) wrappers for them. I'll post it when I get the kinks all worked out them.

Link to comment
Share on other sites

OK, for anyone who is interested at all, here's the _GUIGetSetFont UDF.

_GUISetFontEx and _GUICtrlSetFontEx are enhanced in that they allow you specify a basefont (which can be either the GUI or control's existing font settings, one of the system fonts, or an array of font settings from the _GUIGetFont or _GUICtrlGetFont functions) and then use the Default keyword to leave any of the base settings intact while specifying any desired overrides to individual settings.

_GUIGetFont and _GUICtrlGetFont retrieve the font settings of a GUI or control as an array.

_GetSystemFont retrieves one of the system font settings as an array.

_GUIMatchFont and _GUICtrlMatchFont allow easy copying of font settings from one GUI to another, or one control to another.

_GUIGetHandle retrieves the handle of the 'current' GUI.

_GUICtrlDefaultID retrieves the ID of the last created control if possible, and tries to work around it when ID -1 isn't valid.

 

A few usage examples:

_GUISetFontEx($TMT_MSGBOXFONT) - sets all of the font characteristics for the 'current' GUI to match all of the system msgbox font settings.

_GUISetFontEx($TMT_MSGBOXFONT, 12) - sets all of the font characteristics for the 'current' GUI to match the system msgbox font settings, but overriding the size to 12 point.

_GUICtrlSetFontEx(Default, Default, $FW_BOLD) - updates the font for the last created control to Bold without changing anything else.

_GUICtrlMatchFont($idLabel1) - sets the font for the last created control (default since target isn't specified) to match the font settings of $idLabel1.

_GUICtrlSetFontEx(_GUIGetFont($hOtherGUI), $idButtonOK) - sets the font for control $idButtonOK to match the font settings of GUI with handle $hOtherGUI, even if the button isn't on that GUI.

ConsoleWrite("Current GUI Handle = " & _GUIGetHandle() & @CRLF) - report the handle of the 'current GUI'.

ConsoleWrite("Current Control ID = " & _GUICtrlDefaultID() & @CRLF) - report the ID of the last created control (if possible).

 

; ==================== 
;  _GUIGetSetFont.au3 
; ==================== 

#include-once
#include <FontConstants.au3> ; for $LOGPIXELSY
#include <GUIConstantsEx.au3> ; for $GUI_FONTITALIC, $GUI_FONTUNDER, $GUI_FONTSTRIKE
#include <WindowsConstants.au3> ; for $WM_GETFONT
#include <WinAPISys.au3> ; for _WinAPI_GetParent, _WinAPI_GetDC, _WinAPI_GetDeviceCaps, _WinAPI_ReleaseDC, _SendMessage, _WinAPI_GetObject
#include <WinAPITheme.au3> ; for _WinAPI_GetThemeSysFont

; FUNCTIONS INCLUDED:
;
; _GUISetFontEx ( [basefont [,size [, weight [, attribute [, fontname [, winhandle [, quality]]]]]]] ) - Enhancement to GUISetFont
; _GUICtrlSetFontEx ( [basefont [, controlid [,size [, weight [, attribute [, fontname [, winhandle [, quality]]]]]]]] ) - Enhancement to GUICtrlSetFont
; _GUIMatchFont ( sourceGUI, targetGUI ) - Sets font for targetGUI to match sourceGUI
; _GUICtrlMatchFont ( sourceID [, targetID] ) - Sets font for control with targetID to match control with sourceID
; _GUIGetFont ( [hGUI] ) - Method for non-existent GUISetFont function, retrieves GUI font settings to an array
; _GUICtrlGetFont ( [controlID] ) - Method for non-existent GUISetFont function, retrieves GUI Control font settings to an array
; _GetSystemFont ( fontID ) - Retrieves system font settings to an array
; _GUIGetHandle ( ) - Returns handle (hWnd) for 'current' GUI
; _GUICtrlDefaultID ( ) - Returns id for 'current' GUI control -- should be used instead of -1 in GUICtrl... or _GUICtrl... function calls
;
; Notes: Don't try to use *ANY* of these functions on controls that don't have a handle (see the help for GUICtrlGetHandle).
;        Some functions are based on portions of code and ideas found in various posts in the AutoIt forums.


; #FUNCTION# ====================================================================================================================
; Name ..........: _GUISetFontEx
; Description ...: Sets the GUI font characteristics to match either current or one of the system fonts, while allowing selected
;                  items to be overridden.
; Syntax ........: _GUISetFontEx([$vBaseFont = Default[, $iSize = Default[, $iWeight = Default[, $iAttribute = Default[,
;                  $sFontname = Default[, $hGUI = Default[, $iQuality = Default]]]]]]])
; Parameters ....: $vBaseFont    - [optional] can be a 5-element font array as returned from the _GUIGetFont or
;                                                  _GUICtrlGetFont functions,
;                                             -OR- can be $TMT_CAPTIONFONT, $TMT_SMALLCAPTIONFONT, $TMT_MENUFONT, $TMT_STATUSFONT,
;                                                  $TMT_MSGBOXFONT, or $TMT_ICONTITLEFONT to use specified system font info,
;                                             -OR- anything else (including Default) = settings based on GUI's current font.
;                  $iSize        - [optional] point size of font. Default = use setting from $vBaseFont.
;                  $iWeight      - [optional] weight of font 0-1000. Default = use setting from $vBaseFont.
;                  $iAttribute   - [optional] italic, underline, strikeout. Default = use setting from $vBaseFont.
;                  $sFontname    - [optional] name of font to use. Default = use setting from $vBaseFont.
;                  $hGUI         - [optional] handle of GUI. Default = 'current' GUI window handle.
;                  $iQuality     - [optional] font quality desired. Default = use setting from $vBaseFont.
; Return values .: 1 if successful, 0 with @error set to non-zero if unsuccessful.
; Author ........: TimRude
; Modified ......:
; Remarks .......: For $iSize, $iWeight, $iAttribute, $sFontName, and $iQuality settings details, see help for GUISetFont.
; ===============================================================================================================================
Func _GUISetFontEx($vBaseFont = Default, $iSize = Default, $iWeight = Default, $iAttribute = Default, $sFontname = Default, $hGUI = Default, $iQuality = Default)

    Local $aFont
    If IsArray($vBaseFont) Then
        If UBound($vBaseFont, $UBOUND_DIMENSIONS) <> 1 Then Return SetError(1, 0, 0) ; must be 1D array
        If UBound($vBaseFont) <> 5 Then Return SetError(1, 0, 0) ; must have exactly 5 elements ([0] - [4])
        $aFont = $vBaseFont
    Else
        Switch $vBaseFont
            Case $TMT_CAPTIONFONT, $TMT_SMALLCAPTIONFONT, $TMT_MENUFONT, $TMT_STATUSFONT, $TMT_MSGBOXFONT, $TMT_ICONTITLEFONT
                $aFont = _GetSystemFont($vBaseFont)
            Case Else
                $aFont = _GUIGetFont($hGUI)
        EndSwitch
    EndIf
    If Not @error Then
        If $iSize = Default Then $iSize = $aFont[0]
        $iSize += 0.05 ; add a tiny bit to prevent rounding issues
        If $iWeight = Default Then $iWeight = $aFont[1]
        If $iAttribute = Default Then $iAttribute = $aFont[2]
        If $sFontname = Default Then $sFontname = $aFont[3]
        If $iQuality = Default Then $iQuality = $aFont[4]
        If $hGUI = Default Then
            $hGUI = _GUIGetHandle()
            If @error Then Return SetError(1, 0, 0)
        EndIf
        GUISetFont($iSize, $iWeight, $iAttribute, $sFontname, $hGUI, $iQuality)
        Return 1
    Else
        Return SetError(1, 0, 0)
    EndIf

EndFunc   ;==>_GUISetFontEx


; #FUNCTION# ====================================================================================================================
; Name ..........: _GUICtrlSetFontEx
; Description ...: Sets the GUI control font characteristics to match either current or one of the system fonts, while allowing
;                  selected items to be overridden.
; Syntax ........: _GUICtrlSetFontEx([$vBaseFont = Default[, $idControl = Default[, $iSize = Default[, $iWeight = Default[,
;                  $iAttribute = Default[, $sFontname = Default[, $iQuality = Default]]]]]]])
; Parameters ....: $vBaseFont    - [optional] can be a 5-element font array as returned from the _GUIGetFont or
;                                                  _GUICtrlGetFont functions,
;                                             -OR- can be $TMT_CAPTIONFONT, $TMT_SMALLCAPTIONFONT, $TMT_MENUFONT, $TMT_STATUSFONT,
;                                                  $TMT_MSGBOXFONT, or $TMT_ICONTITLEFONT to use specified system font info,
;                                             -OR- anything else (including Default) = settings based on control's current font.
;                  $idControl    - [optional] ID of control. Default = last control created.
;                  $iSize        - [optional] point size of font. Default = use setting from $vBaseFont.
;                  $iWeight      - [optional] weight of font 0-1000. Default = use setting from $vBaseFont.
;                  $iAttribute   - [optional] italic, underline, strikeout. Default = use setting from $vBaseFont.
;                  $sFontname    - [optional] name of font to use. Default = use setting from $vBaseFont.
;                  $iQuality     - [optional] font quality desired. Default = use setting from $vBaseFont.
; Return values .: 1 if successful, 0 with @error set to non-zero if unsuccessful.
; Author ........: TimRude
; Modified ......:
; Remarks .......: For $iSize, $iWeight, $iAttribute, $sFontName, and $iQuality settings details, see help for GUICtrlSetFont.
; ===============================================================================================================================
Func _GUICtrlSetFontEx($vBaseFont = Default, $idControl = Default, $iSize = Default, $iWeight = Default, $iAttribute = Default, $sFontname = Default, $iQuality = Default)

    If $idControl = Default Or $idControl = -1 Then $idControl = _GUICtrlDefaultID()

    Local $aFont
    If IsArray($vBaseFont) Then
        If UBound($vBaseFont, $UBOUND_DIMENSIONS) <> 1 Then Return SetError(1, 0, 0) ; must be 1D array
        If UBound($vBaseFont) <> 5 Then Return SetError(1, 0, 0) ; must have exactly 5 elements ([0] - [4])
        $aFont = $vBaseFont
    Else
        Switch $vBaseFont
            Case $TMT_CAPTIONFONT, $TMT_SMALLCAPTIONFONT, $TMT_MENUFONT, $TMT_STATUSFONT, $TMT_MSGBOXFONT, $TMT_ICONTITLEFONT
                $aFont = _GetSystemFont($vBaseFont)
            Case Else
                $aFont = _GUICtrlGetFont($idControl)
        EndSwitch
    EndIf
    If Not @error Then
        If $iSize = Default Then $iSize = $aFont[0]
        $iSize += 0.05 ; add a tiny bit to prevent rounding issues
        If $iWeight = Default Then $iWeight = $aFont[1]
        If $iAttribute = Default Then $iAttribute = $aFont[2]
        If $sFontname = Default Then $sFontname = $aFont[3]
        If $iQuality = Default Then $iQuality = $aFont[4]
        GUICtrlSetFont($idControl, $iSize, $iWeight, $iAttribute, $sFontname, $iQuality)
        Return 1
    Else
        Return SetError(1, 0, 0)
    EndIf

EndFunc   ;==>_GUICtrlSetFontEx


; #FUNCTION# ====================================================================================================================
; Name ..........: _GUIMatchFont
; Description ...: Sets all font attributes for one GUI to match another one.
; Syntax ........: _GUIMatchFont($hSource[, $hTarget = Default])
; Parameters ....: $hSource      - handle of the GUI whose font settings are to be copied.
;                  $hTarget      - [optional] handle of GUI to receive copied settings. Default = 'current' GUI.
; Return values .: 1 if successful, 0 with @error set to non-zero if unsuccessful.
; Author ........: TimRude
; Modified ......:
; Remarks .......: After using this function, the $hTarget GUI becomes the 'current' GUI.
;                  This function calls the GUIGetHandle and/or GUIGetFont functions, which have the side effect of making -1 be
;                  no longer valid as a control ID.
; ===============================================================================================================================
Func _GUIMatchFont($hSource, $hTarget = Default)

    If $hTarget = Default Then
        $hTarget = _GUIGetHandle()
        If @error Then Return SetError(1, 0, 0)
    EndIf
    If $hSource = $hTarget Then Return SetError(1, 0, 0) ; same GUI, signal failure
    Local $aFont = _GUIGetFont($hSource)
    If @error Then Return SetError(@error, 0, 0)
    If GUISetFont($aFont[0] + 0.05, $aFont[1], $aFont[2], $aFont[3], $hTarget, $aFont[4]) Then
        Return 1
    Else
        Return SetError(1, 0, 0)
    EndIf

EndFunc   ;==>_GUIMatchFont


; #FUNCTION# ====================================================================================================================
; Name ..........: _GUICtrlMatchFont
; Description ...: Sets all font attributes for one GUI control to match another one.
; Syntax ........: _GUICtrlMatchFont($idSource[, $idTarget = Default])
; Parameters ....: $idSource     - ID of control whose font settings are to be copied.
;                  $idTarget     - [optional] ID of control to receive copied settings. Default is last created control (i.e. -1)
; Return values .: 1 if successful, 0 with @error set to non-zero if unsuccessful.
; Author ........: TimRude
; Modified ......:
; ===============================================================================================================================
Func _GUICtrlMatchFont($idSource, $idTarget = Default)

    If $idTarget = Default Or $idTarget = -1 Then $idTarget = _GUICtrlDefaultID()
    If $idSource = Default Or $idSource = -1 Then $idSource = _GUICtrlDefaultID()
    If $idSource = $idTarget Then Return SetError(1, 0, 0) ; same control, signal failure
    Local $aFont = _GUICtrlGetFont($idSource)
    If @error Then Return SetError(@error, 0, 0)
    If GUICtrlSetFont($idTarget, $aFont[0] + 0.05, $aFont[1], $aFont[2], $aFont[3], $aFont[4]) Then
        Return 1
    Else
        Return SetError(1, 0, 0)
    EndIf

EndFunc   ;==>_GUICtrlMatchFont


; #FUNCTION# ====================================================================================================================
; Name ..........: _GUIGetFont
; Description ...: Gets the font settings of the specified (or 'current') GUI, as would be set by GUISetFont.
; Syntax ........: _GUIGetFont([$hGUI = Default])
; Parameters ....: $hGUI         - [optional] handle of GUI. Default is 'current' GUI.
; Return values .: Successful:   0-based array with 5 elements: [0] size, [1] weight, [2] attribute, [3] fontname, [4] quality
;                  Unsuccessful: returns 0 with @error set to non-zero.
; Author ........: TimRude
; Modified ......:
; Remarks .......: Does not change the 'current' GUI.
;                  A side effect of this function is that right after using it, -1 is no longer valid as a control ID.
;                  This is because this function creates and then deletes a new control, and -1 points to the last
;                  created control (which at this point no longer exists).
;                  As a workaround, this function first calls _GUICtrlDefaultID() to save the current ID for later use.
; ===============================================================================================================================
Func _GUIGetFont($hGUI = Default)

    _GUICtrlDefaultID()
    If $hGUI <> Default Then
        If Not IsHWnd($hGUI) Then Return SetError(1, 0, 0) ; bad GUI hWnd specified
        Local $hPriorGUI = GUISwitch($hGUI) ; try to switch to specified GUI
        If $hPriorGUI = 0 Then Return SetError(1, 0, 0) ; non-GUI hWnd specified
        Local $id = GUICtrlCreateLabel("", 0, 0, 0, 0) ; create a temporary invisible label control
        If $id = 0 Then Return SetError(1, 0, 0) ; couldn't create control, evidently no GUI exists
        Local $aFont = _GUICtrlGetFont($id) ; newly created control will have GUI's set font defaults
        GUICtrlDelete($id) ; remove temporary control
        GUISwitch($hPriorGUI) ; switch back to the original GUI (if different)
    Else
        Local $id = GUICtrlCreateLabel("", 0, 0, 0, 0) ; create a temporary invisible label control
        If $id = 0 Then Return SetError(1, 0, 0) ; couldn't create control, evidently no GUI exists
        Local $aFont = _GUICtrlGetFont($id) ; newly created control will have GUI's set font defaults
        GUICtrlDelete($id) ; remove temporary control
    EndIf
    Return $aFont

EndFunc   ;==>_GUIGetFont


; #FUNCTION# ====================================================================================================================
; Name ..........: _GUICtrlGetFont
; Description ...: Gets the font settings of the specified GUI Control, as would be set by GUICtrlSetFont.
; Syntax ........: _GUICtrlGetFont([$id_or_hWnd = Default])
; Parameters ....: $id_or_hWnd   - [optional] either ID or handle of control. Default is last created control (i.e. -1).
; Return values .: Successful:   0-based array with 5 elements: [0] size, [1] weight, [2] attribute, [3] fontname, [4] quality
;                  Unsuccessful: returns 0 with @error set to non-zero.
; Author ........: TimRude
; Modified ......:
; ===============================================================================================================================
Func _GUICtrlGetFont($id_or_hWnd = Default) ; accepts either Control ID or hWnd

    If $id_or_hWnd = Default Or $id_or_hWnd = -1 Then $id_or_hWnd = _GUICtrlDefaultID()
    If IsHWnd($id_or_hWnd) Then
        Local $hWnd = $id_or_hWnd
    Else
        Local $hWnd = GUICtrlGetHandle($id_or_hWnd)
    EndIf
    If $hWnd = 0 Then Return SetError(1, 0, 0)
    Local $hDC = _WinAPI_GetDC($hWnd)
    Local $iLPY = _WinAPI_GetDeviceCaps($hDC, $LOGPIXELSY)
    _WinAPI_ReleaseDC($hWnd, $hDC)
    Local $tFont = DllStructCreate($tagLOGFONT)
    Local $hFont = _SendMessage($hWnd, $WM_GETFONT)
    If @error Then Return SetError(@error, 0, 0)
    Local $iRet = _WinAPI_GetObject($hFont, DllStructGetSize($tFont), $tFont)
    If $iRet = 0 Then
        Return SetError(1, 0, 0)
    Else
        Local $aFont[5]
        $aFont[0] = Abs((DllStructGetData($tFont, 'Height') / $iLPY) * 72)
        $aFont[1] = DllStructGetData($tFont, 'Weight')
        $aFont[2] = BitOR( _
                ((DllStructGetData($tFont, "Italic")) ? $GUI_FONTITALIC : 0), _
                ((DllStructGetData($tFont, "Underline")) ? $GUI_FONTUNDER : 0), _
                ((DllStructGetData($tFont, "Strikeout")) ? $GUI_FONTSTRIKE : 0))
        $aFont[3] = DllStructGetData($tFont, 'FaceName')
        $aFont[4] = DllStructGetData($tFont, 'Quality')
        Return $aFont
    EndIf

EndFunc   ;==>_GUICtrlGetFont


; #FUNCTION# ====================================================================================================================
; Name ..........: _GetSystemFont
; Description ...: Gets the specified system font settings using _WinAPI_GetThemeSysFont.
; Syntax ........: _GetSystemFont($iFontID)
; Parameters ....: $iFontID      - $TMT_CAPTIONFONT, $TMT_SMALLCAPTIONFONT, $TMT_MENUFONT, $TMT_STATUSFONT, $TMT_MSGBOXFONT,
;                                  or $TMT_ICONTITLEFONT
; Return values .: Successful:   0-based array with 5 elements: [0] size, [1] weight, [2] attribute, [3] fontname, [4] quality
;                  Unsuccessful: returns 0 with @error set to non-zero.
; Author ........: TimRude
; Modified ......:
; ===============================================================================================================================
Func _GetSystemFont($iFontID)

    Local $hDC = _WinAPI_GetDC(0)
    Local $iLPY = _WinAPI_GetDeviceCaps($hDC, $LOGPIXELSY)
    _WinAPI_ReleaseDC(0, $hDC)
    Local $tFont = DllStructCreate($tagLOGFONT)
    $tFont = _WinAPI_GetThemeSysFont(0, $iFontID)
    If @error Then
        Return SetError(@error, 0, 0)
    Else
        Local $aFont[5]
        $aFont[0] = Abs((DllStructGetData($tFont, 'Height') / $iLPY) * 72)
        $aFont[1] = DllStructGetData($tFont, 'Weight')
        $aFont[2] = BitOR( _
                ((DllStructGetData($tFont, "Italic")) ? $GUI_FONTITALIC : 0), _
                ((DllStructGetData($tFont, "Underline")) ? $GUI_FONTUNDER : 0), _
                ((DllStructGetData($tFont, "Strikeout")) ? $GUI_FONTSTRIKE : 0))
        $aFont[3] = DllStructGetData($tFont, 'FaceName')
        $aFont[4] = DllStructGetData($tFont, 'Quality')
        Return $aFont
    EndIf

EndFunc   ;==>_GetSystemFont


; #FUNCTION# ====================================================================================================================
; Name ..........: _GUIGetHandle
; Description ...:
; Syntax ........: _GUIGetHandle()
; Parameters ....: None
; Return values .: If successful, returns handle of 'current' GUI. If no GUI exists, returns 0.
; Author ........: Tim Rude
; Modified ......:
; Remarks .......: A side effect of this function is that right after using it, -1 is no longer valid as a control ID.
;                  This is because this function creates and then deletes a new control, and -1 points to the last
;                  created control (which at this point no longer exists).
;                  As a workaround, this function first calls _GUICtrlDefaultID() to save the current ID for later use.
; ===============================================================================================================================
Func _GUIGetHandle()

    _GUICtrlDefaultID()
    Local $id = GUICtrlCreateLabel("", 0, 0, 0, 0)
    If $id = 0 Then Return SetError(1, 0, 0) ; couldn't create control, evidently no GUI exists
    Local $hGUI = _WinAPI_GetParent(GUICtrlGetHandle($id))
    GUICtrlDelete($id)
    Return $hGUI

EndFunc   ;==>_GUIGetHandle


; #FUNCTION# ====================================================================================================================
; Name ..........: _GUICtrlDefaultID
; Description ...: Workaround method for _GUIGet... functions that destroy the -1 default control ID.
; Syntax ........: _GUICtrlDefaultID()
; Parameters ....: None
; Return values .: If -1 points to a valid control, stores and returns actual ID of control.
;                  Otherwise returns stored ID of last created control when function was previously called.
; Author ........: TimRude
; Modified ......:
; Remarks .......:  The idea is that functions that destroy the -1 ID should first call this function to store the -1 actual ID.
;                   Then a function that would normally use -1 as the ID can call this function to either get the actual ID of
;                   the last created control or, if it's been wiped out, retrieve the previously stored ID.
;                   So functions within this UDF redirect control ID references of -1 to use this function instead.
;                   When calling GUI functions not in this UDF, you can do the same.
;                   i.e., use GUICtrl...(_GUICtrlDefaultID(), ...) instead of GUICtrl...(-1, ...)
; ===============================================================================================================================
Func _GUICtrlDefaultID()

    Static $idDefault = -1
    Local $id = _WinAPI_GetDlgCtrlID(GUICtrlGetHandle(-1))
    If $id > 0 Then $idDefault = $id
    Return $idDefault

EndFunc   ;==>_GUICtrlDefaultID

 

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...