Skip to content

Commit 651faa1

Browse files
committed
Improved DiskMap unicode support
1 parent 6ee18ff commit 651faa1

2 files changed

Lines changed: 80 additions & 32 deletions

File tree

src/plugins/diskmap/DiskMap/GUI.DirectoryLine.h

Lines changed: 67 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,18 @@ class CDirectoryLine : public CChildWindow
7171
// string for storing a copy of the path with an ellipsis
7272
TCHAR _pathtemp[MAX_PATH + 3];
7373

74+
// Wide-char versions of path fields for GDI rendering.
75+
// Paths are stored internally as UTF-8 (char), but GDI ANSI functions
76+
// use the system ANSI code page and cannot render UTF-8 correctly.
77+
// These wide versions are kept in sync with _path/_rootLen and are used
78+
// exclusively for measuring and drawing text via the W GDI variants.
79+
wchar_t _pathW[MAX_PATH + 4];
80+
int _pathWLen;
81+
int _rootLenW;
82+
wchar_t _pathtempW[MAX_PATH + 3];
83+
wchar_t const* _pathstrW;
84+
int _pathlenW;
85+
7486
// Cached values - colors: active/inactive
7587
COLORREF _backColor;
7688
COLORREF _rootColor;
@@ -132,6 +144,13 @@ class CDirectoryLine : public CChildWindow
132144
this->_nodeCount = nodeid;
133145
this->_nodes[this->_nodeCount].xright = LAST_NODEX;
134146

147+
// Build wide-char version of path for GDI rendering (paths are UTF-8 internally)
148+
this->_pathWLen = MultiByteToWideChar(CP_UTF8, 0, this->_path->GetString(), (int)this->_path->GetLength(), this->_pathW, ARRAYSIZE(this->_pathW) - 1);
149+
if (this->_pathWLen < 0)
150+
this->_pathWLen = 0;
151+
this->_pathW[this->_pathWLen] = L'\0';
152+
this->_rootLenW = MultiByteToWideChar(CP_UTF8, 0, this->_path->GetString(), this->_rootLen, NULL, 0);
153+
135154
this->_sizeCached = FALSE;
136155
this->Repaint();
137156
}
@@ -193,11 +212,13 @@ class CDirectoryLine : public CChildWindow
193212
SIZE sz;
194213
int sizewidth = 0;
195214
int pathwidth = 0;
215+
// dx holds per-wide-char pixel positions; wide length <= UTF-8 byte length
196216
int dx[MAX_PATH + 3];
197-
GetTextExtentExPoint(hdc, this->_path->GetString(), (int)this->_path->GetLength(), 0, NULL, dx, &sz);
217+
GetTextExtentExPointW(hdc, this->_pathW, this->_pathWLen, 0, NULL, dx, &sz);
198218
pathwidth = sz.cx;
199219
if (this->_disksize >= 0)
200220
{
221+
// Size strings are ASCII-only formatted numbers; ANSI call is correct here
201222
GetTextExtentPoint32(hdc, this->_sizestrlong->GetString(), (int)this->_sizestrlong->GetLength(), &sz);
202223
sizewidth = sz.cx + 2;
203224

@@ -228,50 +249,60 @@ class CDirectoryLine : public CChildWindow
228249
}*/
229250
}
230251

252+
// Map each node's UTF-8 byte offset to its wide-char position for dx indexing.
253+
// Backslashes are always single-byte ASCII in UTF-8 so the positions differ only
254+
// when non-ASCII characters appear before the backslash.
255+
const char* utf8path = this->_path->GetString();
256+
int nodeWPos[MAX_PATH / 2 + 1];
257+
for (int i = 0; i < this->_nodeCount; i++)
258+
{
259+
nodeWPos[i] = MultiByteToWideChar(CP_UTF8, 0, utf8path, this->_nodes[i].strpos, NULL, 0);
260+
}
261+
231262
if (pathwidth <= width)
232263
{
233-
this->_pathstr = this->_path->GetString();
234-
this->_pathlen = (int)this->_path->GetLength();
264+
this->_pathstrW = this->_pathW;
265+
this->_pathlenW = this->_pathWLen;
235266

236-
this->_rootX = dx[this->_rootLen - 1] + rct.left;
267+
this->_rootX = dx[this->_rootLenW - 1] + rct.left;
237268

238269
for (int i = 0; i < this->_nodeCount; i++)
239270
{
240-
int ppos = this->_nodes[i].strpos;
241-
this->_nodes[i].xright = dx[ppos - 1] + rct.left;
271+
int wpos = nodeWPos[i];
272+
this->_nodes[i].xright = dx[wpos - 1] + rct.left;
242273
}
243274
}
244275
else
245276
{
246-
TCHAR* ostr = this->_pathtemp;
277+
wchar_t* ostr = this->_pathtempW;
247278
int ostrlen = 0;
248279
if (width > this->_dotsWidth)
249280
{
250-
TCHAR const* str = this->_path->GetString();
251-
int strlen = (int)this->_path->GetLength();
281+
wchar_t const* str = this->_pathW;
282+
int strlen = this->_pathWLen;
252283

253284
int remwidth = width - this->_dotsWidth;
254285

255286
int p = 0;
256-
while (p < strlen && dx[p] <= remwidth && str[p] != TEXT('\\'))
287+
while (p < strlen && dx[p] <= remwidth && str[p] != L'\\')
257288
{
258289
ostr[p] = str[p];
259290
p++;
260291
ostrlen++;
261292
}
262-
BOOL found = (str[p] == TEXT('\\'));
293+
BOOL found = (str[p] == L'\\');
263294

264-
while (p < strlen && dx[p] <= remwidth && str[p] == TEXT('\\'))
295+
while (p < strlen && dx[p] <= remwidth && str[p] == L'\\')
265296
{
266297
ostr[p] = str[p];
267298
p++;
268299
ostrlen++;
269300
}
270-
BOOL whole = (str[p] != TEXT('\\'));
301+
BOOL whole = (str[p] != L'\\');
271302

272-
ostr[ostrlen++] = TEXT('.');
273-
ostr[ostrlen++] = TEXT('.');
274-
ostr[ostrlen++] = TEXT('.');
303+
ostr[ostrlen++] = L'.';
304+
ostr[ostrlen++] = L'.';
305+
ostr[ostrlen++] = L'.';
275306

276307
if (found && whole)
277308
{
@@ -287,20 +318,20 @@ class CDirectoryLine : public CChildWindow
287318
{
288319
ostr[ostrlen++] = str[i];
289320
}
290-
if (this->_rootLen > rp)
321+
if (this->_rootLenW > rp)
291322
{
292-
this->_rootX = dx[this->_rootLen - 1] + rct.left - dx[rp] + this->_dotsWidth + dx[p - 1];
323+
this->_rootX = dx[this->_rootLenW - 1] + rct.left - dx[rp] + this->_dotsWidth + dx[p - 1];
293324
}
294325
else
295326
{
296327
this->_rootX = dx[p - 1] + rct.left;
297328
}
298329
for (i = 0; i < this->_nodeCount; i++)
299330
{
300-
int ppos = this->_nodes[i].strpos;
301-
if (ppos > rp)
331+
int wpos = nodeWPos[i];
332+
if (wpos > rp)
302333
{
303-
this->_nodes[i].xright = dx[ppos - 1] + rct.left - dx[rp] + this->_dotsWidth + dx[p - 1];
334+
this->_nodes[i].xright = dx[wpos - 1] + rct.left - dx[rp] + this->_dotsWidth + dx[p - 1];
304335
}
305336
else
306337
{
@@ -322,12 +353,12 @@ class CDirectoryLine : public CChildWindow
322353
//TODO: node clean - nothing!
323354
this->_nodes[0].xright = LAST_NODEX;
324355
}
325-
ostr[ostrlen] = TEXT('\0');
326-
this->_pathstr = ostr;
327-
this->_pathlen = ostrlen;
356+
ostr[ostrlen] = L'\0';
357+
this->_pathstrW = ostr;
358+
this->_pathlenW = ostrlen;
328359
}
329360

330-
if ((size_t)this->_rootLen == this->_path->GetLength())
361+
if (this->_rootLenW == this->_pathWLen)
331362
{
332363
this->_rootX = -1;
333364
}
@@ -479,7 +510,7 @@ class CDirectoryLine : public CChildWindow
479510
{
480511
//root string
481512
trct.right = this->_rootX;
482-
ExtTextOut(hdc, rct.left + 1, rct.top + texttop, ETO_OPAQUE | ETO_CLIPPED, &trct, this->_pathstr, this->_pathlen, NULL);
513+
ExtTextOutW(hdc, rct.left + 1, rct.top + texttop, ETO_OPAQUE | ETO_CLIPPED, &trct, this->_pathstrW, this->_pathlenW, NULL);
483514
trct.right = rct.right;
484515
}
485516
trct.left = this->_rootX;
@@ -496,27 +527,27 @@ class CDirectoryLine : public CChildWindow
496527
int oR = trct.right;
497528
int nr = this->_nodes[this->_mouseNode].xright;
498529
trct.right = nr;
499-
ExtTextOut(hdc, rct.left + 1, rct.top + texttop, ETO_OPAQUE | ETO_CLIPPED, &trct, this->_pathstr, this->_pathlen, NULL);
530+
ExtTextOutW(hdc, rct.left + 1, rct.top + texttop, ETO_OPAQUE | ETO_CLIPPED, &trct, this->_pathstrW, this->_pathlenW, NULL);
500531
trct.left = nr;
501532
trct.right = oR;
502533
}
503534
else
504535
{
505536
//whole string highlighted
506-
ExtTextOut(hdc, rct.left + 1, rct.top + texttop, ETO_OPAQUE | ETO_CLIPPED, &trct, this->_pathstr, this->_pathlen, NULL);
537+
ExtTextOutW(hdc, rct.left + 1, rct.top + texttop, ETO_OPAQUE | ETO_CLIPPED, &trct, this->_pathstrW, this->_pathlenW, NULL);
507538
}
508539
}
509540
if (!isLastNodeHighlighted)
510541
{
511542
//normal - remaining part
512543
SetTextColor(hdc, this->_textColor);
513-
ExtTextOut(hdc, rct.left + 1, rct.top + texttop, ETO_OPAQUE | ETO_CLIPPED, &trct, this->_pathstr, this->_pathlen, NULL);
544+
ExtTextOutW(hdc, rct.left + 1, rct.top + texttop, ETO_OPAQUE | ETO_CLIPPED, &trct, this->_pathstrW, this->_pathlenW, NULL);
514545
}
515546
}
516547
else
517548
{
518549
//root string only
519-
ExtTextOut(hdc, rct.left + 1, rct.top + texttop, ETO_OPAQUE | ETO_CLIPPED, &rct, this->_pathstr, this->_pathlen, NULL);
550+
ExtTextOutW(hdc, rct.left + 1, rct.top + texttop, ETO_OPAQUE | ETO_CLIPPED, &rct, this->_pathstrW, this->_pathlenW, NULL);
520551
}
521552

522553
SelectFont(hdc, hfold);
@@ -618,6 +649,12 @@ class CDirectoryLine : public CChildWindow
618649
this->_dotsWidth = 0;
619650
this->_id = 0;
620651

652+
this->_pathW[0] = L'\0';
653+
this->_pathWLen = 0;
654+
this->_rootLenW = 0;
655+
this->_pathstrW = this->_pathW;
656+
this->_pathlenW = 0;
657+
621658
this->_connector = NULL;
622659

623660
this->OnSystemChange();

src/plugins/diskmap/DiskMap/GUI.ToolTip.h

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,9 @@ class CFileInfoTooltip : public CFrameWindow
109109

110110
TCHAR _stitle[2 * MAX_PATH + 1];
111111
size_t _stitlelen;
112+
// Wide version of _stitle for GDI rendering (path is UTF-8 internally)
113+
wchar_t _stitleW[2 * MAX_PATH + 1];
114+
size_t _stitlelenW;
112115
TCHAR _sftype[MAX_TYPELEN];
113116
size_t _sftypelen;
114117

@@ -159,6 +162,8 @@ class CFileInfoTooltip : public CFrameWindow
159162
{
160163
this->_stitle[0] = TEXT('\0');
161164
this->_stitlelen = 0;
165+
this->_stitleW[0] = L'\0';
166+
this->_stitlelenW = 0;
162167
return;
163168
}
164169

@@ -189,6 +194,10 @@ class CFileInfoTooltip : public CFrameWindow
189194
{
190195
this->_stitlelen = this->_file->GetFullName(this->_stitle, ARRAYSIZE(this->_stitle));
191196
}
197+
198+
// Convert the UTF-8 path title to wide for GDI rendering
199+
this->_stitlelenW = (size_t)MultiByteToWideChar(CP_UTF8, 0, this->_stitle, (int)this->_stitlelen, this->_stitleW, ARRAYSIZE(this->_stitleW) - 1);
200+
this->_stitleW[this->_stitlelenW] = L'\0';
192201
}
193202

194203
void MakeDirty()
@@ -219,6 +228,8 @@ class CFileInfoTooltip : public CFrameWindow
219228
this->_sFormatter = NULL;
220229

221230
this->_stitlelen = 0;
231+
this->_stitleW[0] = L'\0';
232+
this->_stitlelenW = 0;
222233
this->_sftypelen = 0;
223234

224235
this->_headers[TT_LID_CREATETIME] = new CZResourceString(IDS_DISKMAP_TTIP_TIMECREATE);
@@ -414,7 +425,7 @@ class CFileInfoTooltip : public CFrameWindow
414425

415426
HFONT hfold;
416427
hfold = SelectFont(hdc, this->_hftitle);
417-
GetTextExtentPoint32(hdc, this->_stitle, (int)this->_stitlelen, &sz);
428+
GetTextExtentPoint32W(hdc, this->_stitleW, (int)this->_stitlelenW, &sz);
418429
wsz.cx = max(sz.cx + 32 + TT_MARGIN_X + TT_MARGIN_X, wsz.cx);
419430
this->_headerheight += sz.cy;
420431

@@ -563,7 +574,7 @@ class CFileInfoTooltip : public CFrameWindow
563574
int linepos = TT_MARGIN_Y + max(16, szc.cy + TT_MARGIN_Y / 2);
564575
RECT rct = oR;
565576
rct.bottom = linepos + 1;
566-
ExtTextOut(hdc, TT_MARGIN_X + TT_MARGIN_X + 32 + TT_MARGIN_X / 2, TT_MARGIN_Y + 0, ETO_OPAQUE, &rct, this->_stitle, (UINT)this->_stitlelen, NULL);
577+
ExtTextOutW(hdc, TT_MARGIN_X + TT_MARGIN_X + 32 + TT_MARGIN_X / 2, TT_MARGIN_Y + 0, ETO_OPAQUE, &rct, this->_stitleW, (UINT)this->_stitlelenW, NULL);
567578

568579
//Dividing line
569580
MoveToEx(hdc, TT_MARGIN_X + TT_MARGIN_X + 32, linepos, NULL);

0 commit comments

Comments
 (0)