Stuck trying to draw horizontal line in console emulator - winapi

Windows, using Win32 API calls directly.
I am trying to create a windows app that emulates the behavior of a console app. So I am using Cascadia Mono, the nice new font that comes with Windows Terminal (makes no difference to my problem if I use Courier New or Consolas). The app that is asking me to write things is trying to draw a box using the line drawing characters. The horizontal line char it uses is u2500, the standard light horizontal line
In my app I have calculated the width and height for the font and draw each character one at a time in my WM_PAINT message handling
for row in 0..ws.rows {
for col in 0..ws.cols {
let ch = sb.buffer[offset];
trace!("paint {:?}", ch);
offset += 1;
if ch.ch != ' ' {
if ch.fg == Color::Reset {
SetTextColor(hdc, RGB(255, 255, 255));
} else {
let rgb = color(ch.fg);
SetTextColor(hdc, rgb);
}
let u = ch.ch.encode_utf16(&mut b);
trace!("ch = {0:0x} ", u[0]);
assert!(
TextOutW(hdc, col * ws.ch_width, row * ws.ch_height, u.as_ptr(), 1)
!= 0
);
}
}
}
(sorry that this is rust , not C++, but you can see what calls I am making). All works fine but the horizontal lines come out wrong. Here is a screen shot of 3 screens stack on top of each other.
Top is my app,
next is the original console app in windows terminal
Last a cut and paste of the text from Windows terminal into notepad.
You can see that in my app the dashes are chopped off at either end so I get a dashed line. You can also see that the top left corner abuts right up to the first 'k' in the real things but in mine there is a definite gap. Also note that the right hand side of the last 'k' on mine is chopped off by the invisible bounding box of the first dash.
I cannot reduce the character pitch in my code to squash the dashes together because then the other characters will overlap.
I am very much a novice at font and character handling so I am at a loss. I have checked and I am for sure emitting 0x2500 as the character. My naive expectation is that all the characters in a fixed pitch font are the same and that they all stay nicely inside that bounding box.
NOTE : that rust utf16 call is taking the character thats in utf32 format (rusts standard char internal representation) and converting it to utf16.
EDIT: here is a simple no code winforms c# app screen, the same text is copied from the console app and pasted into the text box. Note that the glyphs are full width
And here is chrome displaying the same chars, full width \e2\94\80 is utf8 for 2500. Seem everybody knows a trick I dont

Related

AMCharts bullets converted to gibberish on small charts

I've searched through the entire AMCharts 4 bullet documentation as well as numerous Google pages, but I am yet to find the answer. When chart is squeezed to a mobile screen, bullet labels above bars get updated to some complete gibberish (as in the example below left). Those are suppose to be various numeric values (example on the right), including some with a decimal point. No percentage or other symbols.
The text actually gets swapped from normal numbers to the 'processed food' as the screen is being resized. Logic dictates that I must be missing some setting that prevents this sort of undesirable behaviour.
Any help is highly appreciated!
The "gibberish" is supposed to be an ellipsis. It's likely that your page isn't encoded to UTF-8 or the font you're using does not have the Unicode character for an ellipsis.
You can either double-check your encoding, or, if you don't want the ellipsis as at all, disable truncate on your labels. Assuming you're using a LabelBullet for your column labels:
var valueLabel = series.bullets.push(new am4charts.LabelBullet());
// ...
valueLabel.label.truncate = false;
For me the only way to get it show properly was setting value as workingValue
var bullet = series.bullets.push(new am4charts.LabelBullet());
bullet.label.text = "{valueY.workingValue.formatNumber('#')}";
bullet.label.truncate = false;

How are progress bars programmed in Conky and how can I apply this in my own custom one?

I'm trying to customize my progress bars in Conky (battery_bar, fs_bar...) in order to have a layout other than the default one, which looks like:
Following this answer I managed to create a filesystem usage bar, and with some code modifying, a battery status one, looking like this.
This bar is generated following the following script, a variation of the one suggested for in the previous answer:
#!/bin/bash
cat /sys/class/power_supply/BAT0/capacity | awk 'NR==1{
n = ($1+0)/2; yellow = 20; red = 40;
if(n>=red) {
r = "${color ff0000}";
for(;n>=red;n--)
r = r "\\#"
}
if(n>=yellow){
y = "${color ffff00}";
for(;n>=yellow;n--)
y = y "\\#"
}
g = "${color 00ff00}";
for(;n>0;n--)
g = g "\\#";
print g y r
}'
My problem is that the bar's length is constant, and it will constantly resize the Conky window until it's able to show the 100% of its capacity, full size. This obviously forces my Conky window size to be at least the length of those custom bars, deforming the screen.
As far as I have experimented, I can see that Conky's default bars are 'responsive' to the windows size they are given, and never cause problems in this aspect; as they resize themselves without a problem. I would like to know how are they programmed in order to apply the same algorithm to my code the cleanest way.
One thing you can do fairly easily is add some programming in lua to change the font size just before drawing the bar. The size would be calculated from the window width divided by 50. If using proportional fonts you might need some small scale factor to account for the fact that a font of a given size might have a # character of a different width.
Create a file to hold the lua script, say ~/mylua.lua with the following
-- called with (50) return "${font DejaVu Sans Mono:size=13.6}"
function conky_mysetfont(numchars)
if conky_window.width<=0 then return "" end
fontname = "DejaVu Sans Mono"
scale = 1.2
fontsize = conky_window.text_width/tonumber(numchars)*scale
-- print("result=",fontsize) -- debug
return "${font "..fontname..":size="..fontsize.."}"
end
The -- starts a comment. If you remove the one in front of print, you
should see something like result= 13.6 on stdout if you run conky
from the terminal. The function takes a parameter, the length of your bar,
ie 50 characters. It returns a conky command string like ${font
somefont:size=13.6}. .. is a concatenation operator. The above choses a fixed-width font DejaVu Sans Mono and an approximate scale of 1.2.
In your ~/.conkyrc, add in the conky.config = {...} part (for 1.10) a line
lua_load = '~/mylua.lua',
to load in your code. In the conky.text = [[...]] part, replace the line
where call your script, eg
${execpi 30 ~/mydf /}
with
${lua_parse conky_mysetfont 50}
${execpi 30 ~/mydf /}
$font
i.e. call your lua function, passing the number of characters, your
original script, then reset the original default font and size.
In conky 1.9 when you resize the window with the mouse, this code
will change the font size to match, but in 1.10 the size changes only when
the window changes size due to some internal trigger. It seems this is a
regression.
Note that many people don't have problems with resizing because they
display conky on their fixed-size desktop background.
Also, once you start using lua, an alternative to using text for bars
is to get lua to draw any sort of graphics such as coloured lines and
boxes. You can read about this in the wiki, and see amazing
examples
of what is possible.
possibly not 100% an answer to your question but you may give it a try
I am using conky 1.10.6 on a raspberry pi with KDE Desktop.
I am using one line to display most of the file systems (vfat partition excluded with option -x).
${execpi 60 df -h --output=source,target -x vfat| grep '^/dev/' | cut --characters=6- | awk '{ print $1," ", $2,"${alignr}${fs_size " $2 "}","${alignr}${color blue}${fs_bar 11,100 " $2"}\n\n\n,${alignr}${voffset -39}${color white}${fs_used_perc " $2 "}%" }'}
Result:
cheers

Differences between GetDC() and BeginPaint()?

I am having trouble with some of my owner drawn listboxes on High DPI monitors on Windows 10 in a dialog box. The text is chopped off at the bottom. We saw the problem on Windows 7 and were able to fix it. It is not necessarily High DPI, but when the user sets a different text scaling. I solved the problem, so I thought (!), by using a CClientDC (wrapper around GetDC()) and calling GetTextMetrics() to determine the text height. Previously, our icons had always been taller than our text so it was not a problem. With larger DPI monitors we saw some customers reporting problems when they scaled the text.
Now we are getting new reports under Windows 10. The former problem is fine under Windows 7--but Windows 7 only scales to 100, 125, and 150 percent. Windows 10 (and maybe 8? -- but no customer reports) allows user defined scaling.
So, I tracked down the problem somewhat... I knew what the font height was when I called GetTextMetrics() during WM_MEASUREITEM. I went and put some code in to debug what GetTextMetrics() was during my WM_DRAWITEM. Well, they were different--20 pixels high during WM_MEASUREITEM, and 25 pixels high during WM_DRAWITEM. Obviously, that is a problem. I want the GetTextMetrics() to have the same results in both places.
My thought was that the only real difference I could think of was that during WM_MEASUREITEM I am calling GetDC() via CClientDC constructor, and that during WM_DRAWITEM I am using an already constructed HDC (which probably was from a return of GetPaint() inside GDI32.dll or another system DLL).
I thought maybe the BeginPaint() does something like select the windows HFONT into the HDC...
So, inside my WM_MEASUREITEM after getting the DC, I select the font of the listbox into the HDC, and then I call GetTextMetrics(). Lo and behold, the numbers match now in WM_MEASUREITEM and WM_DRAWITEM.
However, I don't know if I just got lucky. It's all just guesswork at this point.
Does BeginPaint() select the window font into the DC whereas GetDC() does not? Does the default handler of WM_PAINT for an owner drawn LISTBOX or COMBOBOX do something like select the window font into the paint DC?
BOOL DpiAwareMeasureGraphItem(LPMEASUREITEMSTRUCT lpM, CWnd* pWnd)
{
int iItemHeight = INTERG_BITMAP_HEIGHT + 4;
if (pWnd)
{
CClientDC dc(pWnd);
if (dc.GetSafeHdc())
{
CFont* pOldFont = dc.SelectObject(pWnd->GetFont()); // seems to fix it on Windows 10, but is it luck?
TEXTMETRIC tm;
memset(&tm, 0, sizeof(tm));
dc.GetTextMetrics(&tm);
LONG tmHeight = tm.tmHeight + 4; //pad
iItemHeight = max(iItemHeight, tmHeight);
dc.SelectObject(pOldFont);
}
}
lpM->itemHeight = iItemHeight;
return (TRUE);
}
Neither GetDC() or BeginPaint() initialise the DC they return with anything other than the default system font. But WM_DRAWITEM is different - it gives you an already-initialised DC to draw into.
The method you stumbled across is the right one. WM_MEASUREITEM doesn't supply a DC at all, so if you need one for size calculations you're responsible for obtaining it and setting it up with the appropriate font.

How to draw vertical text in Windows GUI?

I need to draw a column of vertical text (in Japanese language - it is drawn top-to-bottom instead of left-to-right) in my native C++ Win32 GUI application. I've looked through MSDN and only found how to draw right-to-left text.
How do I output top-to-bottom text except drawing each character separately?
The straight Win32 API has no way to draw (unrotated) vertical text (with an arbitrary font) in that way except 1 character at at time.
You can do more complex text output with GDI+
But that probably isn't what you want either, since the text will be vertical, but the characters will also be rotated.
Similarly, you can use CreateFont with an lfEscapement value of 900 or 2700 to get rotated text, but this will rotate everything. So that doesn't help either.
To do Japanese Top to Bottom drawing, you want the characters to be unrotated, but the placment of each character to advance in Y but not in X. Windows has no API that does this for all fonts. (you can do right-to-left and left-to-right, but not top-to-bottom).
In theory creating a font with an Orientation of 900 and an escapement of 2700 would do what you want, but it appears that if you set the escapement, then the orientation is ignored for most fonts. It's possible that for Japanese fonts, this will work differently. It's worth spending some time to play with. (see the addendum for more information on this)
I think your best bet is a probably a loop drawing one character at a time with ExtTextOut which gives you full control over the placement of each character.
If you use ETO_OPAQUE to draw the first character in a column, and not with all of the others, then you will be permitted to kern the characters vertically if you need to.
Addendum
Roygbiv points to an interesting article that says that fonts whose names begin with an # behave differently then other fonts when you use CreateFont a font with an lfEscapement value of 2700, These special fonts produce upright characters while still advancing down the page. So while there is no way to do what you want for arbitrary fonts, you may be able to get it working using certain fonts.
Options for Displaying Text
Out of curiosity, i wrote a small console app to enum fonts and list the names. My Windows Server 2003 machine has not fonts with names beginning with #. But my Windows 7 machine has a few. All seem to be Chinese fonts though, I see no Japanese fonts in the default Windows 7 Ultimate install.
The correct answer is:
There are three methods to do this:
Using the Edit or RichEdit controls to render your text
Using the Uniscribe API
Using the TextOut function with a font face name that begins with an at sign (#).
Here is an article that discusses some of these approaches.
Fortunately, with Win32 you do not need to write code to rotate characters. To display text vertically on Windows 2000 and Windows XP, enumerate the available fonts as usual, and select a font whose font face name begins with the at sign (#). Then create a LOGFONT structure, setting both the escapement and the orientation to 270 degrees. Calls to TextOut are the same as for horizontal text.
In Win32, use the lfEscapement member of a LOGFONT structure to define the rotation of a font:
LOGFONT LogFont
LogFont.lfEscapement = 900; // 90 degreees rotated text
... // Many more initializations
HFONT newFont = CreateFontIndirect(LogFont);
SelectObject(hdc, newFont);
char tx[255];
strcpy(tx, "vertical text");
TextOut(hdc, x, y, tx, strlen(tx)); // draw a vertical font
For More Information see the online Help of LOGFONT structure and of the CreateFontIndirect Function
HFONT gui_font = CreateFont( -MulDiv( 9, GetDeviceCaps( GetDC( hWnd ), LOGPIXELSY ), 72 ),
0,
900, // here
0,
FW_THIN, 0, 0, 0,
DEFAULT_CHARSET,
OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, FF_MODERN | FIXED_PITCH,
L"Segoe UI" );
Using lfEscapement (and if necessary lfOrientation) is superior in many ways to making the rectangle minimally wide (for instance: the dutch word 'wij' would have the 'i' and 'j' next to each other, because their combined width is less than the 'w'), or inserting a newline after each character.
The method this library uses sounds slow, but if do want it, it appears source code is provided:
http://www.ucancode.net/faq/CDC-DrawText-Drawing-Vertical-Text.htm
You may also find this discussion useful - http://www.eggheadcafe.com/forumarchives/win32programmergdi/Aug2005/post23542233.asp - apparently you need a vertical font (one beginning with #) and the API will take care of the rest.
As a quick hack type of answer, what happens if you use a standard control (CEdit for instance) and insert a new-line after every character typed?
Just an idea:
Did you try using DrawText or DrawTextEx using a very narrow rectangle that just fits the widest character?

OpenGL text position under Windows

I am developing an OpenGL application that has two working modes: windowed mode and full screen.
The app displays several graphic objects using OpenGL and writes some text strings using that same API. The program displays the texts strings in its intended positions when running as a windowed application, but when running full screen the text strings are displayed in an upper position that its intended position.
The app creates the fonts using wglUseFontBitmap and displays the text strings with glCallLists (it sets the text position using glRasterPos2i). Before the text is displayed I adjust the text position adding an offset to the Y coord. I get that offset using the GetDCOrgEx Win32 API call.
I think you have to call GetDCOrgEx again after getting in fullscreen mode, or do you already do this? It would help if you could post the code where you call GetDCOrgEx and calculate the Y offset.
EDIT: Another idea: Could it be that you can use the same Y offset, but negative? Or perhaps calculate Y position and then use height-ypos? There's some source code here that uses glRasterPos2i different when in fullScreen:
if(!state->fullScreen)
// if fullScreen (don't forget the image/GL y-coord vertical flip)
glRasterPos2i((w - state->img->cols())/2, (h - state->img->rows())/2);
else
// for non-fullscreen images
glRasterPos2i(0,h);
Schnaader, thanks a lot for your answers.
I have solved the problem modifying how I calculate the offset that I need to add to the Y coord. Now the offset is calculated with the following code:
m_iYOffset = GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYBORDER);
The above code solves the problem for my application.
Here's the code to calculate the Y offset:
POINT vOffset;
m_hdc = GetDC(m_hWnd);
if (m_hdc)
{
GetDCOrgEx(m_hdc, &vOffset);
m_iYOffset = vOffset.y;
}
The above code is called once the program has set up full screen mode. I tried to call GetDCOrgEx every time I need to write a text string, but the text is written at the same positions that when GetDCOrgEx is called only once.

Resources