ChooseFont dialog: munges font name fails to reload it - c++

I've found some slightly odd, and more importantly, inconsistent behavior from Win32 ChooseFont() API.
LOGFONT lf = { 0 };
strcopy(lf.lfFaceName, m_face_name);
const int ppi = GetDeviceCaps(pView, LOGPIXELSY);
lf.lfHeight = -MulDiv(m_font_height, ppi, 72);
CFontDialog fd(&lf);
if (fd.DoModal() != IDOK)
return;
m_face_name = fd.GetFaceName();
m_font_height = lf.lfHeight;
Assuming that the first time though, face name is "Segoe UI", this works.
But if the user changes the dialog to be "Segoe UI", "Light", "9", (face, style, height), and we go through the above a second time, then the font choose common dialog fails to select "Segoe UI" as the face name. Instead, I get the Font: field as blank.
This is not a problem if the user selects a style of "Regular", "Italic", "Bold", "Bold Italic", as those are stored in the style bits, and don't munge the name. I discard them for the second run, because I'm ignoring them (I would disable Font Style: if there were a way to easily do so - I don't wish to subclass CFontDialog for this - that's a whole 'nother level of time & effort that this moment doesn't allow for).
I've tried creating a font based on the previous specifics from the dialog, and then tried pulling the LOGFONT back out of that. No dice.
Similarly, I've tried querying the dialog for the FontStyle() - but that returns blank - so nothing to strip from the font name here...
This just seems like a bug with MS's dialog - it tells me one thing, but then cannot use it's own output to correctly initialize itself the second time through (granted, I'm only persisting some, not all, of the LOGFONT in this situation).
Does anyone know WTH is up with this? Or an approach I might use to (short of hard coding looking for " Light" on the end of a font name - YUCK!)?

Developments in font design has significantly outstripped the legacy api's ability to keep up. OpenType happened, for one. There are additional font styles beyond what LOGFONT can support. For Segoe UI, properties that control boldness can be Light and Semibold. For other fonts, font stretch is another property, common ones are Condensed and Expanded. With the font being able to implement a dedicated font file to make these styles look good and not depend on synthesizing the style from an existing font as it was done in the olden days. Review the WPF FontStretch and FontWeight enumeration types for possible values.
These are properties that LOGFONT can't express. There's a compatibility hack to deal with this, type face names get mapped. So "Segoe UI" with a style of "Light" becomes "Segoe UI Light". And the Windows font mapper will pick the right true-type font file from such a name. What however doesn't work is initialize LOGFONT.lfFaceName with "Segoe UI Light". Not actually sure why, it was probably avoided to not have to deal with the ambiguity. Or just plain flubbed. A possible workaround is to recognize these appended style names in the font face name, but that's not perfect either.
GDI is running out of gas. Much like User32.

First, when you initialize your LOGFONT in your proc, you can't just set it to 0
ala "= { 0 };"
Use something like
memset(&lf, 0, sizeof(lf));
Otherwise your lf in your proc contains random crap. Secondly, what's the big deal about not saving all the settings of the LOGFONT structure? It you're using MFC, it's not because it would be too much overhead. If fixing the initialization of lf doesn't work, just save the entire LOGFONT.

Related

MSHTML editing - changing the text selection color

I use MSHTML (TWebBrowser control) in Design (edit) mode. I use TEmbeddedWB but slowly moving away from that component and implementing my own interface. When a block of text is selected, so when typing into the editor and then selecting a block of text it is in black color for the background color.
Instead I'd like to use blue.
I know that it has something to do with the selection range but not sure how to modify it in designer mode. The code below is of course when it is not in design mode.
IHTMLSelectionObject currentSelection = document.selection;
IHTMLTxtRange range = currentSelection.createRange() as IHTMLTxtRange;
if (range != null)
{
range.execCommand("BackColor", false, "0000FF");
}
Any ideas? Do I have to use event sinking? Or maybe QueryCommandValue? I tried some things with HiliteColor without success yet (according to Mozilla documentation this is not supported by Internet Explorer).
I use C++ Builder or Delphi, but code example in any language is welcome, I can (probably) translate it.

How can I adjust the size of a QDialog according to its title length?

One of my dialog window's title is shortened (like "My Dialogt..."). If the dialog was slightly wider, the whole title would be completely displayed, which would look nicer.
It seems as if there is no setting in Qt to do that. I have found a hack for a QMessageBox here: Can QMessageBox::about adjust size to title length?, but it is not general. For example it would have to take also the sizes of the icons to the left and to the right of the window title into account to compute a really good minimal size where still the title is completely shown.
Is there a general way to accomplish that? Is there also a simple way to do that? Or is this overengineering?
Not only this goal is questionable (see vahanco comment) but it is hard to achieve, because the window title bar is not Qt territory at all: apart from being able to set its text and manage to show or hide close/min/max button using window flags, there is little else in control, there.
By the way, a very raw way to set a dialog minimum width which could (could) make room to the whole text is the following:
const QString text = "Very very very very very very very very very very very very very long window title";
setWindowTitle(text);
QFontMetrics metrics(font(), this);
setMinimumWidth( metrics.horizontalAdvance(text));
This won't work out of the box, and it's very likely that the text stay cut, because the font used is supposed to be the same used in the title bar (which usually isn't) and we're not taking into account the frame width, the icon width, the title bar buttons width, and everything else which is owned by the window manager and is totally unknown to Qt.
So, you can figure out how much extra space is needed by all these stuff, and adjust the width with a totally arbitrary extra padding like
setMinimumWidth( metrics.horizontalAdvance(text) + 256);
and maybe get what you wanted in the first place (if you still really want it).
The accepted answer did not work for me.
The below code works in QT 5.15. According to the documentation after you call setMinumumWidth() you must call updateGeometry() update geometry docs. Setting minimumWidth should update the sizeHint. That was not happening for me. Also QFontMetrics::horizontalAdvance was not returning the width of the text. I had to use QFontMetrics::boundingRect({title_string}).width().
Calling resize on the dialog is what finally got it working for me. If the accepted answer doesn't work for you give this a try.
QString message = "Message for the user";
QInputDialog dialog = QInputDialog(this);
dialog.setLabelText(message);
QString longTitle = QString("Super long test title for making sure the widget will show all of the stupid long title.");
dialog.setWindowTitle(longTitle);
dialog.setInputMode(QInputDialog::TextInput);
auto fontMetrics = dialog.fontMetrics();
auto width = fontMetrics.boundingRect(longTitle).width();
dialog.resize(width + 200, dialog.rect().height());
const int ret = dialog.exec();

linux, C++, xft : how to use it?

I try to use Xft, the tutorial, well let them calling that a tutorial... looks like it was written in a north korean camp... I also found this one. So let me try to do a step-by-step :
// g++ XftTest.cc -lX11 -lXft `pkg-config --cflags freetype2`
#include<unistd.h>
#include<X11/Xlib.h>
#include<X11/Xutil.h>
#include<X11/Xft/Xft.h>
int main()
{
Display *display;
XftFont *font;
XftDraw *xftdraw;
XRenderColor xrcolor;
XftColor xftcolor;
display = XOpenDisplay(0);
Window XP = XCreateSimpleWindow(display,DefaultRootWindow(display),0,0,360,90,0,0,0);
XMapWindow(display,XP);
font = NULL; /* added 6/16 */
//font = XftFontOpenName(display,0,"NorthKorea-50"); // how to check if this is good ?
font = XftFontOpenName(display,0,"") /* added 6/16 */
if (!font) return 1;
xftdraw = XftDrawCreate(display,XP,DefaultVisual(display,0),DefaultColormap(display,0));
xrcolor.red =65535;
xrcolor.green=0;
xrcolor.blue =0;
xrcolor.alpha=65535;
XftColorAllocValue(display,DefaultVisual(display,0),DefaultColormap(display,0),&xrcolor,&xftcolor);
XftDrawString8(xftdraw, &xftcolor, font, 20,70 , (XftChar8 *)"Joe Dalton", 10);
XFlush(display);
sleep(2);
XftDrawDestroy(xftdraw);
XftColorFree(display,DefaultVisual(display,0),DefaultColormap(display,0),&xftcolor);
return 0;
}
as you can see, in the XftFontOpenName :
XftFontOpenName(display,0,"NorthKorea-50")
if you write a bullshit, like I did, there is no error or something to tell me that I don't have a font called NorthKorea. That make sense since XftFontOpenName returns the nearest font from the string.
So, how can I check if my font match or not ? how can I use a font like arial? I tried XftFontOpenName(display,0,"arial-50"), I got nothing different.
On my system, I have these folders in my fonts folder :
$ls /usr/share/fonts/
100dpi 75dpi cyrillic encodings misc OTF TTF Type1 util
can I use any font in these folders by the same way ?
if you guys have some nice internet links, it would be a pleasure for me to take a look.
n.b. : there is no xft tag...
update 6/16
I'm still stuck with dat stuff...
I don't understand, if I replace
font = XftFontOpenName(display,0,"NorthKorea-50");
by
font = XftFontOpenName(display,0,"");
it still loading a font...
xlsfonts return a lot of stuff, like dat one :
-monotype-courier new-bold-r-normal--0-0-0-0-m-0-iso8859-10
but passing this as argument to XftFontOpenName changes nothing; I try to load a font with XftFontOpenXlfd too, it returns always NULL...
xft uses fontconfig for font discovery. xlsfonts is a way to query the old X core fonts system fontconfig replaced. xlsfonts results won't map in any reliable way way to the fontconfig state.
So:
forget about any shortcut where xft work sort-of like the X core font system documented in last centuries tech books. It is completely different. It is not X core fonts with antialiasing and truetype support. It is something that can use modern fonts and do antialiasing, but definitely not X core fonts in any form
Read the fontconfig documentation, the fontconfig configuration files on your system, and use fontconfig utilities (fc-query, fc-list, etc) to query the fontconfig state
as the people who maintain xorg (both x core fonts and fontconfig) already told you, do not try to use xft directly. xft is the product of the first attempt to write a new font stack. Its capabilities are not sufficient to manage modern text and modern fonts. The part dealing with modern font format complexities has been spun out in pango a long time ago (because it was proving complex enough it deserved a separate project). If you try to use xft alone, you'll hit the deficiencies in pre-pango code sooner or later, and no one will be interested in fixing your problems because the same code has already been subjected to a decade of fixes pango-side. Avoiding pango is not a shortcut. Avoiding pango is trying to rely of an half-finished, abandonned for years project.
forget about matching a specific font file. fontconfig will actively fight any attempt to work this way. In the post-core-fonts world, you give the font system a font pattern, and it will build a matching font for you. If the result is not the font file you expected that's because the file was evaluated and found lacking. If you want fontconfig to use this file you will have to fix the font file (add the missing glyphs, the missing font styles, etc), not write code to try to force it anyway. Fontconfig considers that it's more important to render a text your users can read, than to only render the parts your pet font can do. And yes that's now how you're used to think about it on other systems. fontconfig is different. Nothing short of a rewrite will make it behave like you expect. No one is interested in this rewrite because by and large fontconfig has been quite successful those past years.
fonts opentype text-rendering fontconfig linux
You should not pass an empty string to XftFontOpenName and expect to match a font. Xft provides support for core fonts and the structure nested within XftFont is a union of XFontStruct and XftFontStruct. X11 fills in the default font in the XFontStruct when creating new instances, so in the case of empty string you are likely getting the default core font.
In the simplest approach, one can hard code a font name like this:
const char *font_name = "Arial-20";
XftFont *font = XftFontOpenName (display, DefaultScreen(display), font_name);
Or you could use XftFontMatch and check the "results" before passing the pattern to XftFontOpenPattern. See http://keithp.com/~keithp/talks/xtc2001/paper/xft.html#sec-editing
Note that XCloseDisplay is missing.

What Uxtheme function I must use to get the default size of the minimize, Maximize and close buttons?

I'm using the DrawThemeBackground function to draw some system elements on a canvas, And I need draw the title buttons of a form, the only part that i missed is how i can get the default sizes of the title buttons. Exist any Uxtheme function to get that info?
Looks like this is more difficult then it sounds.
First there's GetThemeMetric or GetThemeInt. But you'll see a lot of references that these functions return a 0x8007490, some "element not found", when you try to retrieve properties of caption buttons.
Then there's GetThemePartSize. This one seems to work some. That is it works ok for instance for WP_CLOSEBUTTON, but it returns nonsense for instance for WP_MINBUTTON. I would not suggest this function's use anyway since it retrieves the default dimensions of the button. If the user has changed the title size for instance, you won't get correct values. Anyway, it could be called like this:
uses
uxtheme, themes;
...
var
Err: HRESULT;
Size: TSize;
begin
Err := GetThemePartSize(ThemeServices.Theme[teWindow], 0,
WP_CLOSEBUTTON, CBS_NORMAL, nil, TS_TRUE, Size);
I have no idea what the former two functions would return if they worked (the dimensions of buttons for current title bar size or the default title bar size).
The only possible way to get an accurate result seems to be to use the WM_GETTITLEBARINFOEX message. But there's a drawback; it works only for Vista and up. You may need to define the message and the struct it uses depending on the Delphi version you use (D2007 here).
const
CCHILDREN_TITLEBAR = 5;
WM_GETTITLEBARINFOEX = $033F;
type
tagTITLEBARINFOEX = record
cbSize: DWORD;
rcTitleBar: TRect;
rgstate: array[0..CCHILDREN_TITLEBAR] of DWORD;
rgrect: array [0..CCHILDREN_TITLEBAR] of TRect;
end;
TITLEBARINFOEX = tagTITLEBARINFOEX;
TTitleBarInfoEx = tagTITLEBARINFOEX;
PTitleBarInfoEx = ^TTitleBarInfoEx;
...
var
TitleInfo: TTitleBarInfoEx;
begin
SendMessage(Handle, WM_GETTITLEBARINFOEX, 0, NativeInt(#TitleInfo));
Then, you can get the size for the close button from the rect TitleInfo.rgrect[5]. See "TITLEBARINFOEX structure" for details. Notice the values are in screen coordinates.
If you need to support XP and/or below, I suggest you to use the good old GetSystemMetrics(SM_CXSIZE) and GetSystemMetrics(SM_CYSIZE) ("The width of a button in a window caption or title bar, in pixels"). You'd need to workout some approximations depending on if themes are enabled, if aero is enabled etc..
I think SystemParametersInfo with SPI_GETNONCLIENTMETRICS is what you're looking for. I guess the minimize and maximize buttons use NONCLIENTMETRICS.iSmCaptionWidth while close uses iCaptionWidth to determine width.

How to create a bold and italic label in MFC?

Please do not mark it as a dupe of this question just yet:
Bold labels in MFC
That question does not help me; for some reason I do not see the rich edit control. Instead I believe I have to do it in code. here is a sample I found:
http://www.tech-archive.net/Archive/VC/microsoft.public.vc.mfc/2006-10/msg00245.html
My problem is that I prefer not to re-invent the wheel and test for errors myself or through QA.
Someone must have implemented this before. Please share your code.
What I would like to do is:
Keep the same font size, family, etc. as in the already created label, but make it bold and italic as well.
Keep the memory footprint reasonably low (do not create any new unnecessary objects), but do not get the app into an inconsistent state either.
I appreciate your help.
You will want to do the following before the static text control is shown on the parent window.
Get a handle to the window: CWnd * pwnd = GetDlgItem(IDC_LABEL);
Get the current font for the static text: CFont * pfont = pwnd->GetFont();
Get the characteristics of the font: LOGFONT lf; pfont->GetLogFont(&lf);
Change the lfWeight and lfItalic fields in lf.
Put a CFont object in your parent window, so it will exist for the entire lifetime of the child window.
Initialize the CFont: m_font.CreateFontIndirect(&lf);
Set the font into the static text window: pwnd->SetFont(&m_font);