Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Problem] User cannot select a font for ShapeString creation. Only a font file #9458

Open
2 tasks done
sliptonic opened this issue May 2, 2023 · 25 comments
Open
2 tasks done
Labels
UI/UX WB Draft Related to the Draft Workbench

Comments

@sliptonic
Copy link
Member

Is there an existing issue for this?

  • I have searched the existing issues

Version

0.21 (Development)

Full version info

[code]
OS: Linux Mint 20 (i3/i3)
Word size of FreeCAD: 64-bit
Version: 0.21.0.33029 +1 (Git)
Build type: Unknown
Branch: (HEAD detached at upstream/pr/9418)
Hash: bfcc5d029f2dfbce0be1c240363ef015dbd7d3c4
Python 3.8.10, Qt 5.12.8, Coin 4.0.0, Vtk 7.1.1, OCC 7.5.2
Locale: English/United States (en_US)
Installed mods: 
  * DynamicData 2.46.0
  * Assembly4 0.12.5
  * fasteners 0.4.55
  * Behave-Dark-Colors 0.1.1
  * 3DfindIT 1.2.0
  * Render 2023.2.2
  * ProDarkThemePreferencePack 1.0.0
  * sheetmetal 0.2.59
  * QuickMeasure 2022.10.28
  * Nodes 0.1.36
  * FeedsAndSpeeds 0.5.0
  * Assembly3 0.11.4
  * ExtremeProDark 2.6.4
  * FeedsAndSpeeds.bak
  * Curves 0.6.5
  * A2plus 0.4.60k
  * Dracula 0.0.2
[/code]

Subproject(s) affected?

Draft

Problem description

When creating a ShapeString, the user is expected to select a font file. This requires browsing the file sytem to find the font files and then picking one.

The UI should allow the user to pick a font using a typical font selection widget that displays the fonts.

Anything else?

https://forum.freecad.org/viewtopic.php?t=77718

Code of Conduct

  • I agree to follow this project's Code of Conduct
@Roy-043
Copy link
Contributor

Roy-043 commented May 2, 2023

Relate forum post:
https://forum.freecad.org/viewtopic.php?t=77718#p676954

Apart from the issue mentioned in the forum post, there is the problem that a single TTF file can contain multiple font definitions. ShapeString is only able to use the first defined font from such a file.

@Roy-043 Roy-043 added the WB Draft Related to the Draft Workbench label May 2, 2023
@yorikvanhavre
Copy link
Member

We definitely need to convert the font file selection field to a proper font selector.
And we therefore need a system to give us a font file from a font name.
Matplotlib has one, but it would add an annoying dependency...
matplotlib.font_manager.findfont('Gnuolane')

Maybe the code they use could be extracted and reimplemented?

@sliptonic
Copy link
Member Author

@0penBrain
Copy link
Contributor

Why not just https://doc.qt.io/qt-5/qfontdialog.html ?
If one want to display it in FC

from PySide2 import QtWidgets
QtWidgets.QFontDialog.getFont()

@yorikvanhavre
Copy link
Member

It will retun a QFont but there is no way to obtain the actual file path from a QFont...

@0penBrain
Copy link
Contributor

It will retun a QFont but there is no way to obtain the actual file path from a QFont...

Which is a problem only if you consider you need the path. 😃

@yorikvanhavre
Copy link
Member

We need it at the moment, because that's what FreeType needs. Of course one could think to replace it, but we'd need something else that can give us bspline contours here: https://github.com/FreeCAD/FreeCAD/blob/master/src/Mod/Part/App/FT2FC.cpp

@0penBrain
Copy link
Contributor

I don't know if something like this is possible with QRawFont or QGlyphRun 😕

@WandererFan
Copy link
Contributor

Put two selectors in the UI.

One that uses QFontDialog and searches for best match file in C:/Windows/Fonts, /usr/share/fonts or [osx standard file location] (note, you can't necessarily get the ttf file from the font name/QFont/QFontInfo, so we need a guessing algo). This becomes the general use case for most users.

The second one uses a QFileDialog and lets the user select a file in non-standard locations or that has an un-guessable name.

@yorikvanhavre
Copy link
Member

that's not a bad idea at all, actually

@0penBrain
Copy link
Contributor

C:/Windows/Fonts, /usr/share/fonts or [osx standard file location]

Maybe locations can be obtained using https://doc.qt.io/qt-5/qstandardpaths.html#standardLocations with FontsLocation

@wandrewkeech
Copy link

you can't necessarily get the ttf file from the font name/QFont/QFontInfo, so we need a guessing algo

not sure it's helpful, but I've been looking around at other projects which are C++ Qt and deal with fonts, Calligra Words imports and makes calls to fontconfig in their Character Style code
https://invent.kde.org/office/calligra/-/blob/master/libs/text/styles/KoCharacterStyle.cpp#L239

@FlachyJoe
Copy link
Contributor

I don't know if something like this is possible with QRawFont or QGlyphRun confused

QRawFont can give a QPainterPath which is very similar to a FreeType FT_Outline.

@yorikvanhavre
Copy link
Member

yorikvanhavre commented Jun 8, 2023

What about something like this:

  • We create a "font finder" module more or less in the lines of https://github.com/matplotlib/matplotlib/blob/v3.7.1/lib/matplotlib/font_manager.py (where we can easily manually add paths for appimages, etc)
  • The shapestring has two properties: a font property, and a hidden filepath property
  • When changing the font property, it updates the filepath property using the font finder module
  • The user can still change/override the filepath property manually if needed

@benj5378
Copy link
Contributor

benj5378 commented Aug 7, 2023

@benj5378
Copy link
Contributor

I made this PR #10335 some time ago, using Qt to find fontpaths. I haven't tested it on Mac or Windows, but seems good enough.

For font path retrieval, we can either move forward with this solution or make another solution.

Some notes I have taken while doing extensive research on Qt font handling:

  • Qt saves all fonts in it's own font database using FreeType. For some reason, there is no API to retrieve this and I gave up figuring out how to retrieve it using hax
  • QFontDialog only shows those fonts saved in it's own font database. For some reason it's not possible adding one's own fonts, seems weirdly rigid... but it should be possible using hax to use QFontDialogPrivate to display custom fonts. Other options is to not use QFontDialog or to hope that all the fonts in Qt's own font database can also by our own font retrieval solution
  • QRawFont allows retrieving data tables from the font... but it seems overly complicated and maybe it applies to TrueType only?

@yorikvanhavre
Copy link
Member

I think most, if not all, GUI apps that use fonts rely on having fonts "installed" on the system and will only consider those. Only GIMP I think allows to provide custom font paths... Maybe we could live with it?

@WandererFan
Copy link
Contributor

fontconfig is available on *nix, Win and Mac. It takes care of finding the fonts (and the files containing the fonts). This would be the ideal solution (I think).

The other choice would be some sort of home made font finder that checks the normal locations for fonts on the current platform.

Not sure that either solution will handle the case where a desired font lives in some obscure directory.

@benj5378
Copy link
Contributor

benj5378 commented Aug 28, 2023

I would surely live with only using installed fonts. If external are needed, they could just be installed onto the system.

fontconfig is available on *nix, Win and Mac. It takes care of finding the fonts (and the files containing the fonts). This would be the ideal solution (I think).

The other choice would be some sort of home made font finder that checks the normal locations for fonts on the current platform.

Fontconfig is not built-in on Windows as with Linux, so it would be an additional dependency. What about the Qt that I propose in my draft PR, would that be good enough?

@WandererFan
Copy link
Contributor

PR#10335 looks like it generates a list of font location directories, so it is a step in the right direction, but we ultimately need a map of font name to font file.
We could load each file into FreeType and then get the font family and style from the face object to build the map. Could be time consuming, so we'd need to do it at start up?

Not sure if fontconfig would be faster.

@yorikvanhavre
Copy link
Member

I would go forward with this PR. It seems to me the best solution overall.

@benj5378
Copy link
Contributor

benj5378 commented Sep 2, 2023

Not sure if fontconfig would be faster.

AFAIK, (please double check), then Qt uses fontconfig.

PR#10335 looks like it generates a list of font location directories, so it is a step in the right direction, but we ultimately need a map of font name to font file.

True... we could test how long loading into FreeType would take...

But then, should we store all the fonts in a data structure and retrieve then upon usage (so we don't load the same font twice), or should we only load into FreeType to retrieve the name, and then destroy the FreeType object? I guess the last option would be the best with the amount of usage fonts have? Okay, maybe this is just pointless micro-improvements.

A second attempt by someone else could also be to try use hax getting the Qt database of FreeType load-ins. IIRC, it's something with QFontDatabasePrivate... but the load-in function bounces around a lot and multiple times, I somehow got into a wrong route, with the save function being a void function - this might have been due to being a parent class for child classes specific for OS (I encountered child specific classes for OS multiple times).

@Roy-043
Copy link
Contributor

Roy-043 commented Dec 4, 2023

FWIW Some remarks:

The Fem and Plot module already have a dependency on Matplotlib.

Qt and matplotlib find a different number of fonts:

from matplotlib import font_manager
len(font_manager.get_font_names()) => 168
import PySide.QtGui as QtGui
db = QtGui.QFontDatabase()
len(db.families()) => 213

# After loading TechDraw (which adds fonts to the Qt database):
len(db.families()) => 216

A Qt font has style information:

from PySide2 import QtWidgets
res = QtWidgets.QFontDialog.getFont()
print(res) => (True, <PySide2.QtGui.QFont(Arial,12,-1,5,75,0,0,0,0,0,Vet) at 0x0000009B62810C00>)
res[1].style() => PySide2.QtGui.QFont.Style.StyleNormal
res[1].weight() => 75
res[1].bold() => True
res[1].italic() => False

Matplotlib's font_manager can find files based on style information:

font_manager.findfont('Arial:style=normal:variant=normal:weight=bold:stretch=normal:size=10.0')
=> 'C:\\Windows\\Fonts\\arialbd.ttf'

Version:

OS: Windows 8 build 9600
Word size of FreeCAD: 64-bit
Version: 0.22.0dev.35274 (Git)
Build type: Release
Branch: main
Hash: dc063eabec61bffc72c92595c66a4649f25fe381
Python 3.10.13, Qt 5.15.8, Coin 4.0.0, Vtk 9.2.6, OCC 7.6.3
Locale: Dutch/Netherlands (nl_NL)
Installed mods:

@Roy-043
Copy link
Contributor

Roy-043 commented Dec 6, 2023

Mario52 has created a nice macro that may provide inspiration:
https://wiki.freecad.org/Macro_Fonts_Win10_PYMP

@Roy-043
Copy link
Contributor

Roy-043 commented Jan 23, 2024

Related forum topic:
https://forum.freecad.org/viewtopic.php?t=28900

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
UI/UX WB Draft Related to the Draft Workbench
Projects
None yet
Development

No branches or pull requests

9 participants