[Library] Fnt v3.0 - Do Stuff With Fonts

Post your working scripts, libraries and tools
User avatar
jballi
Posts: 568
Joined: 29 Sep 2013, 17:34

[Library] Fnt v3.0 - Do Stuff With Fonts

25 Aug 2014, 21:18

Post History
This library was first released on the original AutoHotkey forum. You can find the original post here.

Introduction
AutoHotkey handles most of our font needs via the gui Font and GUIControl Font commands. The Fnt library was created to expand on what can be done with fonts.

Fnt Library
Key features:
  • Create fonts. Create and delete logical fonts as needed. Yes, this is one way to get around the AutoHotkey upper limit of 200 fonts. Starting with v0.6, creating any of the standard non-client fonts (Ex: Menu font) is a snap.
  • Calculate the size of GUI controls before creating them. Or after changing the font of a GUI control. New functions introduced in v3.0 make it even easier to accurately calculate the size for some GUI controls.
  • Calculate the tab stops on Edit, Rich Edit, or ListBox controls. New functions released in v0.6 make it much easier to set the tab stops based on actual data.
  • Get the default GUI margins. The original reason I started this project. Useful for spacing multiple GUI controls when the margins are unknown.
The Code
The pertinent files are as follows:
  • Project: Fnt.zip (Includes the Fnt library and example scripts)
  • Documentation: Fnt Library
Compatibility
Starting with v2.0, this library is designed to work on all versions of AutoHotkey v1.1+.

Issues/Considerations
A few considerations:
  • Windows compatibility. The library is designed to run on all versions of Windows >= Windows XP. The reality is that I only have one machine to test this software on. If you experience any problems with your version of Windows, please let me know. I will try to correct the problem.
  • Preview functions. A few functions in the library are experimental/preview. These functions are documented as such. These functions can be modified or deleted at any time.
  • DPIScale. The DPIScale feature (AutoHotkey v1.1.11+) can be incompatible with the Fnt library. See the library documentation for more information.
  • Tooltips. Recent updates to Windows 7 (it appears to be other versions of Windows as well) has changed how the tooltip control responds to certain messages. The tooltip may no longer automatically redraw when the WM_SETFONT message is sent. Worse yet, if the Redraw option of the WM_SETFONT message is set to TRUE, the tooltip may be deactivated (hidden but not destroyed). Starting with v0.9, the Fnt_UpdateTooltip function was added to work in conjunction with the Fnt_SetFont function when used on a tooltip control. See the documentation in the Fnt_SetFont function for more information.
  • Examples. If any of the examples don't work as expected, please let me know. I will try to correct the problem. Also, the examples have been written for the most common screen resolutions - 1920x1080 or higher. Screens with resolutions at least 1280x768 should work fine but there might be a few exceptions. For screens with a resolution less than 1280x768, there may be more than than a few examples that don't display well. If you experience a problem with an example because of screen resolution, let me know. I will try to correct the problem.
References
Release Notes
Last edited by jballi on 02 Jan 2018, 00:31, edited 9 times in total.
User avatar
jballi
Posts: 568
Joined: 29 Sep 2013, 17:34

Re: Library] Fnt v0.6 (Preview) - Do Stuff With Fonts

25 Aug 2014, 21:21

v0.6 (Preview)
Bug fixes, enhancements, and a bunch of new functions. See the bottom of the first post for the details.
User avatar
joedf
Posts: 7189
Joined: 29 Sep 2013, 17:08
Facebook: J0EDF
Google: +joedf
GitHub: joedf
Location: Canada
Contact:

Re: [Library] Fnt v0.6 (Preview) - Do Stuff With Fonts

26 Aug 2014, 19:39

Great! Im happy to see this library "alive" again :D
Image Image Image Image Image
Windows 10 x64 Professional, Intel i5-8500 @ 4.00 GHz, 2x8GB DDR4 2733 MHz, NVIDIA GTX 1060 6GB | [About Me] | [ASPDM - StdLib Distribution]
[Populate the AHK MiniCity!] | [Qonsole - Quake-like console emulator] | [LibCon - Autohotkey Console Library] | [About the AHK Foundation]
User avatar
jballi
Posts: 568
Joined: 29 Sep 2013, 17:34

Re: [Library] Fnt v0.6 (Preview) - Do Stuff With Fonts

02 Sep 2014, 11:49

Dialog Template Units

Introduction
The latest release of the Fnt library introduces functions that convert to and from Dialog Template Units. This topic can be confusing and sometimes frustrating and so I created this document in an attempt to generate a better understanding of the subject.

Stuff To Know
This document discusses "dialog base units" and "dialog template units". Be careful. These terms look very similar but they describe different types of measurement. To help differentiate the terms, I've given them different colors so that dialog base units won't be easily confused with dialog template units. This document may look a bit like a coloring book but I hope that it helps.

These terms are often prepended with "horizontal" or "vertical". For example: horizontal dialog template units. "Horizontal" refers to the width or x-Axis of the measurement. "Vertical" refers to the height or y-Axis of the measurement.

Background and Executive Summary
Someone a long time ago figured out that the font used in a window can be used to determine the size of the window and/or the size of objects in the window. The original idea was a means of controlling the size of system dialogs. If the system font was small, then the dialog window was created to be one size. If the system font was large, then the same dialog was created to be a larger size to accommodate for the larger font.

Dialog Template Units are font-based units of measurement. They are used to specify the size (width and/or height) of a window or GUI control without knowing the font or font size that will be used to populate the text within the window and/or GUI control. The unfortunate name is a result of defining a unit of measurement within dialog box templates which are structures used by the DialogBox and CreateDialog functions.

Dialog Base Units
Everything is "based" on Dialog Base Units.

A horizontal dialog base unit is the average width, in pixels, of all of the uppercase and lowercase Roman characters of a font, i.e. the average width of this string: "AaBbCc...Zz". A vertical dialog base unit is equal to the height, in pixels, of the font.

Dialog Template Units
Dialog Template Units are just smaller units of Dialog Base Units.

There are 4 horizontal dialog template units for each horizontal dialog base units. There are 8 vertical dialog template units for each vertical dialog base units.

Improving Understanding
There are a few facts and mnemonics that should make it a bit easier to understand how to convert to or from dialog template units.

Horizontal
Horizontal dialog template units are based on horizontal dialog base units which are based on the width of a average character of a font. So, instead of horizontal dialog template units, think of the number of "average characters" of a font.

There are 4 horizontal dialog template units for every "average character" of a font. So, to convert "average characters" to dialog template units, multiply the number of "average characters" by 4. For example, to create a GUI control that is 60 "average characters" in width, specify 240 (60 times 4) horizontal dialog template units.

To convert horizontal dialog template units back into "average characters", divide by 4. For example, 500 horizontal dialog template units is equal to 125 (500 divided by 4) "average characters".

Vertical
Don't worry too much about vertical dialog template units. They are equal to factor (8:1) of the height of the font. When measuring a single line of text, the value will always be 8. For two lines of text, the value will always be 16. And so on. This measurement is not as valuable because 1) the height of the font is always available and 2) calculating the height of a control is a little more complicated than knowing the height of the font.

When converting from vertical dialog template units, just divide by 8. For example, 80 vertical dialog template units is equal to 10 vertical dialog base units which is equal to the height of 10 characters of a font.

Uses
Dialog template units are rarely used outside of the dialog template structure but the methodology used to convert to/from them does provide value. In general, the library functions can be used to calculate the size of a GUI control before it is created or after the font is changed on the control. Also, the functions can be used to set the tab stops on an Edit or Rich Edit control which are set in dialog template units. I originally created these functions to support this feature.

The Fnt library includes a few examples that use the dialog template units functions. They include:

Code: Select all

Example - Dialog Template Units.ahk
Example - Set Tab Stops on Edit Control.ahk
I've modified several other library examples to use the dialog template units functions to help format the data that is displayed as a part of the output of the example.
arcticir
Posts: 576
Joined: 17 Nov 2013, 11:32

Re: [Library] Fnt v0.6 (Preview) - Do Stuff With Fonts

28 Sep 2014, 23:08

I ask, why do I use Fnt_GetStringWidth () Gets the width is not uniform it?
such as unified menu width:

Image

Code: Select all

f:=StrSplit(".;[email protected]|9ESDFKOOI")
Loop 10
{
    b:=""
    Loop 500
    {
        Random, d, 1, f.MaxIndex()
        b.=f[d]
	a:=Fnt_GetStringWidth(0,b)
	if (a>=400)
	Break
    }

    Menu, Test, Add, % b, Test
}
Menu, Test, Show
Test:
Thanks.
arcticir
Posts: 576
Joined: 17 Nov 2013, 11:32

Re: [Library] Fnt v0.6 (Preview) - Do Stuff With Fonts

28 Sep 2014, 23:36

Does not seem to get the default font, more unified:
Image

Code: Select all

f:=StrSplit(".;[email protected]|sdfSdf无可奈何花落去士大夫9ESDFKOOI")
Loop 10
{
    b:=""
    Loop 
    {
        Random, d, 1, f.MaxIndex()
        b.=f[d]
	a:=Fnt_GetStringSize(1,b)
	if (a>=400)
	  {
		b:=a "  " b
		Break
	  }
    }


    Menu, Test, Add, % b "...", Test
}
Menu, Test, Show
Test:
Return

Fnt_GetStringSize(hFont,p_String)
    {
    Static Dummy6596
          ,DEFAULT_GUI_FONT:=17
          ,HWND_DESKTOP    :=0
          ,SIZE
    PtrType:=(A_PtrSize=8) ? "Ptr":"UInt"

    ;-- If needed, get the handle to the default GUI font
    if not hFont
        hFont:=DllCall("GetStockObject","Int",DEFAULT_GUI_FONT)

    ;-- Select the font into the device context for the desktop
    hDC      :=DllCall("GetDC",PtrType,HWND_DESKTOP)
    hFont_Old:=DllCall("SelectObject",PtrType,hDC,PtrType,hFont)

    ;-- Get string size
    VarSetCapacity(SIZE,8,0)
    RC:=DllCall("GetTextExtentPoint32"
        ,PtrType,hDC                                    ;-- hDC
        ,"Str",p_String                                 ;-- lpString
        ,"Int",StrLen(p_String)                         ;-- c (string length)
        ,PtrType,&SIZE)                                 ;-- lpSize

    ;-- Housekeeping
    DllCall("SelectObject",PtrType,hDC,PtrType,hFont_Old)
        ;-- Necessary to avoid memory leak

    DllCall("ReleaseDC",PtrType,HWND_DESKTOP,PtrType,hDC)

    ;-- Return to sender
    if RC
        Return NumGet(SIZE,0,"Int")

    }
User avatar
jballi
Posts: 568
Joined: 29 Sep 2013, 17:34

Re: [Library] Fnt v0.6 (Preview) - Do Stuff With Fonts

29 Sep 2014, 00:14

arcticir wrote:I ask, why do I use Fnt_GetStringWidth () Gets the width is not uniform it?
such as unified menu width:
Hey arcticir,

With a double-byte character set, you are definitely getting into an area that is out of my league but I'm hoping that it's just an apples vs. oranges problem. You are testing the width of a string using the default GUI font but using the system Menu font to display the string. Try this.

Code: Select all

hMenuFont:=Fnt_CreateMenuFont()
f:=StrSplit(".;[email protected]|9ESDFKOOI")
Loop 10
{
    b:=""
    Loop 500
    {
        Random, d, 1, f.MaxIndex()
        b.=f[d]
    a:=Fnt_GetStringWidth(hMenuFont,b)
    if (a>=400)
    Break
    }

    Menu, Test, Add, % b, Test
}
Fnt_DeleteFont(hMenuFont)
Menu, Test, Show
Test:
return
I hope this helps.
arcticir
Posts: 576
Joined: 17 Nov 2013, 11:32

Re: [Library] Fnt v0.6 (Preview) - Do Stuff With Fonts

29 Sep 2014, 01:09

Thank you, it solved my problems. :D

In addition, I ask, in addition to calculating the width of each word, there is any way to get the character within the width of it?
For example:

Code: Select all

a:=Fnt_XXX(hMenuFont,"ASFDSFDSGSDFASDF",40)
User avatar
jballi
Posts: 568
Joined: 29 Sep 2013, 17:34

Re: [Library] Fnt v0.6 (Preview) - Do Stuff With Fonts

29 Sep 2014, 08:00

arcticir wrote:In addition to calculating the width of each word, there is any way to get the character within the width of it?
For example:

Code: Select all

a:=Fnt_XXX(hMenuFont,"ASFDSFDSGSDFASDF",40)
I'm sorry, I'm going to need a little more help with this one. When you say, "calculate the width of each word", what does a "word" represent? In your example, 1) what does the "40" represent and 2) what is returned?, i.e. what is stored in the "a" variable? It would be very helpful if you could give me a more detailed example and/or more information on what you you are trying to accomplish. Thanks.
arcticir
Posts: 576
Joined: 17 Nov 2013, 11:32

Re: [Library] Fnt v0.6 (Preview) - Do Stuff With Fonts

29 Sep 2014, 08:38

Sorry, my negligence.

Now need to calculate each character

Code: Select all

f:="ASFDSFDSGSDFASDF"
Loop, parse, f
{
b.=A_LoopField
    a:=Fnt_GetStringWidth(hMenuFont,b)
    if (a>=40)
    Break
}

I think the character width can get within a specified
Do not use the "Loop"

Code: Select all

a:=Fnt_GetStringWidth(hMenuFont,"ASFDSFDSGSDFASDF")
if     if (a>40)
b:=Fnt_XXX(hMenuFont,"ASFDSFDSGSDFASDF",40)  ;Such as Return "ASFD"
User avatar
jballi
Posts: 568
Joined: 29 Sep 2013, 17:34

Re: [Library] Fnt v0.6 (Preview) - Do Stuff With Fonts

29 Sep 2014, 16:12

If I read this requirement correctly, it reads something like, "Give me the portion of a string that is less than or equal to a specified number of pixels of a specified font."

I do see something like a Fnt_TruncateStringToFit function in the future (thanks for the idea) but I don't have anything for now. It's not very efficient, but a brute-force method (checking one character at a time) like your example is the fastest thing to program and will probably return the value in a very reasonable amount of time. I'm sorry I couldn't be more helpful.
arcticir
Posts: 576
Joined: 17 Nov 2013, 11:32

Re: [Library] Fnt v0.6 (Preview) - Do Stuff With Fonts

29 Sep 2014, 22:42

Thank you, you have helped me a lot.

----------------------

I extracted Fnt.ahk some code, write a small function to accelerate. I hope you do not mind.

Code: Select all

sw:=StringWidth()
f:=StrSplit(".;[email protected]|9ESDFKOOI")
Loop 10
{
    b:=""
    Loop 500
    {
        Random, d, 1, f.MaxIndex()
        b.=f[d]
    }
	b:=sw.Width(b,400)
    Menu, Test, Add, % b, Test
}

Menu, Test, Show
Test:
return
 

Code: Select all

StringWidth(h:=""){
	Return New StringWidth(h)
}

Class StringWidth {
	__New(hFont){
		PtrType:=(A_PtrSize=8) ? "Ptr":"UInt"
		if !This.hFont:=hFont
			This.Font:=hFont:=Fnt_CreateMenuFont()
		This.DC		:=DllCall("GetDC",PtrType,0)
		This.Old	:=DllCall("SelectObject",PtrType,This.DC,PtrType,hFont)
	}

	Width(String,StrLen,fs:="..."){
		Static PtrType:=(A_PtrSize=8) ? "Ptr":"UInt",SIZE,ss:=VarSetCapacity(SIZE,8,0)
		RC:=DllCall("GetTextExtentPoint32",PtrType,This.DC ,"Str",String ,"Int",StrLen(String),PtrType,&SIZE)
		if (NumGet(SIZE,0,"Int") >= StrLen)
			{
				Loop, parse, String
				{
					b.=A_LoopField,RC:=DllCall("GetTextExtentPoint32",PtrType,This.DC ,"Str",b,"Int",A_Index,PtrType,&SIZE)
					if (NumGet(SIZE,0,"Int") >= StrLen)
					{			
						b.=fs
						Break 
					}			
				}
			}
			else	b:=String
		Return b
	}
	__Delete(){
		PtrType:=(A_PtrSize=8) ? "Ptr":"UInt"
		if This.Font
			Fnt_DeleteFont(This.Font)
		DllCall("SelectObject",PtrType,This.DC,PtrType,This.Old),DllCall("ReleaseDC",PtrType,0,PtrType,This.DC)
	}

}
User avatar
jballi
Posts: 568
Joined: 29 Sep 2013, 17:34

Re: [Library] Fnt v0.6 (Preview) - Do Stuff With Fonts

30 Sep 2014, 14:35

arcticir, I've written a general purpose function to do the job. I've named it Fnt_TruncateStringToFit for now. It was designed to try to make the smallest number of calls to external functions, specifically Fnt_GetStringSize, as possible. After the methodology has been vetted (and if merited), I will update it for additional efficiency.

Since you have a real-life use for this function, I will PM you a copy of the function for your review. Please give it try at your convenience. Be aware that the version I'm posting is in full debug mode. If you have a debug viewer, you can see what's going on in the background. If you have any additional questions, problems, or comments on this topic, please PM me.
User avatar
jballi
Posts: 568
Joined: 29 Sep 2013, 17:34

Re: [Library] Fnt v0.7 (Preview) - Do Stuff With Fonts

08 Oct 2014, 22:54

v0.7 (Preview)
A bug fix, several enhancements, and some new functions. See the bottom of the first post for the details.
arcticir
Posts: 576
Joined: 17 Nov 2013, 11:32

Re: [Library] Fnt v0.7 (Preview) - Do Stuff With Fonts

01 Nov 2014, 05:36

I added a parameter.

Code: Select all

Fnt_TruncateStringToFit(hFont,p_String,p_MaxStringW,Ellipsis:=""){
………
Return l_String Ellipsis  ;"…"
}

Thank you for giving us such a good library.
User avatar
jballi
Posts: 568
Joined: 29 Sep 2013, 17:34

Re: [Library] Fnt v0.8 (Preview) - Do Stuff With Fonts

06 Jan 2015, 03:50

v0.8 (Preview)
A few new functions. See the bottom of the first post for the details.
User avatar
jballi
Posts: 568
Joined: 29 Sep 2013, 17:34

Re: [Library] Fnt v0.9 (Preview) - Do Stuff With Fonts

19 Aug 2015, 01:57

v0.9 (Preview)
New font options "helper" functions and a few new miscellaneous functions. See the Release Notes section of the first post for the details.
User avatar
jballi
Posts: 568
Joined: 29 Sep 2013, 17:34

Re: [Library] Fnt v1.0 - Do Stuff With Fonts

04 Nov 2015, 21:20

v1.0
A bug fix, a new function, and a few new/updated examples. See the Release Notes section of the first post for the details.

Please note that this version will be last version of the library to support all versions of AutoHotkey. Future versions (if any) will only support AutoHotkey v1.1+.
User avatar
jballi
Posts: 568
Joined: 29 Sep 2013, 17:34

Status Bar Font

04 May 2016, 00:42

Status Bar Font

I've noticed this several times over the years but because the status bar is an easily-forgotten component of a window, I did not put two and two together until recently.

AutoHotkey sets the font for the text displayed in the status bar. If the developer does not specify a font or the gui Font command is used without parameters before the status bar is added, the default GUI font is used. Otherwise, the last font set before the status bar is added is used.

The thing is, the font used to draw the text in the status bar is supposed to be a component of Non-client Metrics. These are system-wide parameters used by all windows. "Non-client" refers to all components of the window that are not part of the client. They include the border, caption, menu, status bar, etc. From a font perspective, this includes the caption font, menu font, status font (status bar and tooltips) and message font (MsgBox dialog).

Non-client attributes like the status bar font are set by default when the user selects a theme and text size (DPI). If desired, the user can customize one or more of these items by going to the Control Panel (Window Color and Appearance dialog) and change the font, size, color, etc. Non-client attributes can also be set programmatically (one example here) although I haven't been able to come up with an real-life reason to do so.

So, what's wrong with using the default GUI font for the status bar? Absolutely nothing. It's a very readable font and because the font size is smaller on many themes, you can fit a lot of text in small amount of space. The problem is that it's not the font selected by the user when they selected the theme, DPI, or when they customized it in the Control Panel. For many themes, the non-client font used for the status bar is a bit larger and easier to read than the default GUI font.

Instructing AutoHotkey to use the system non-client font for the status bar is easy with the Fnt library. The best time to do it is when the status bar is added to the GUI. For example:

Code: Select all

gui Font,% "s" . Fnt_GetStatusFontSize(),% Fnt_GetStatusFontName()
gui Add,StatusBar
This method uses the standard Autohotkey gui Font command to establish the correct font before the status bar is added.

If needed, the font can be set after the status bar has been added. For example:

Code: Select all

hSBFont:=Fnt_CreateStatusFont()
Fnt_SetFont(hSB,hSBFont,True)
  ;-- This assumes that hSB is the handle to the status bar
I recently started making these changes to some of my scripts that have a GUI with a status bar. For my theme and DPI, the font size is a bit larger and easier to read than the default GUI font. In addition, it matches the menu font.
User avatar
jballi
Posts: 568
Joined: 29 Sep 2013, 17:34

Re: [Library] Fnt v2.0 - Do Stuff With Fonts

05 May 2016, 05:53

v2.0
Minor bug fix, several enhancements, several new functions, and new and updated examples. See the Release Notes section of the first post for the details.

This and future versions of the library will only run on AutoHotkey v1.1+.

Return to “Scripts and Functions”

Who is online

Users browsing this forum: Frosti, robodesign and 36 guests