Updated with progress work.
[reactos.git] / rosapps / winfile / draw.c
1 /*
2 * ReactOS winfile
3 *
4 * draw.c
5 *
6 * Copyright (C) 2002 Robert Dickenson <robd@reactos.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #ifdef _MSC_VER
24 #include "stdafx.h"
25 #else
26 #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
27 #include <windows.h>
28 #include <commctrl.h>
29 #include <stdlib.h>
30 #include <malloc.h>
31 #include <memory.h>
32 #include <tchar.h>
33 #include <process.h>
34 #include <stdio.h>
35 #endif
36
37 #include "winfile.h"
38 #include "utils.h"
39 #include "draw.h"
40
41
42 #define COLOR_COMPRESSED RGB(0,0,255)
43 #define COLOR_SELECTION RGB(0,0,128)
44
45
46 static void format_date(const FILETIME* ft, TCHAR* buffer, int visible_cols)
47 {
48 SYSTEMTIME systime;
49 FILETIME lft;
50 int len = 0;
51
52 *buffer = _T('\0');
53
54 if (!ft->dwLowDateTime && !ft->dwHighDateTime)
55 return;
56
57 if (!FileTimeToLocalFileTime(ft, &lft))
58 {err: _tcscpy(buffer,_T("???")); return;}
59
60 if (!FileTimeToSystemTime(&lft, &systime))
61 goto err;
62
63 if (visible_cols & COL_DATE) {
64 len = GetDateFormat(LOCALE_USER_DEFAULT, 0, &systime, 0, buffer, BUFFER_LEN);
65 if (!len)
66 goto err;
67 }
68
69 if (visible_cols & COL_TIME) {
70 if (len)
71 buffer[len-1] = ' ';
72
73 buffer[len++] = ' ';
74
75 if (!GetTimeFormat(LOCALE_USER_DEFAULT, 0, &systime, 0, buffer+len, BUFFER_LEN-len))
76 buffer[len] = _T('\0');
77 }
78 }
79
80
81 static void calc_width(Pane* pane, LPDRAWITEMSTRUCT dis, int col, LPCTSTR str)
82 {
83 RECT rt = {0};
84
85 DrawText(dis->hDC, (LPTSTR)str, -1, &rt, DT_CALCRECT|DT_SINGLELINE|DT_NOPREFIX);
86
87 if (rt.right > pane->widths[col])
88 pane->widths[col] = rt.right;
89 }
90
91 static void calc_tabbed_width(Pane* pane, LPDRAWITEMSTRUCT dis, int col, LPCTSTR str)
92 {
93 RECT rt = {0};
94
95 /* DRAWTEXTPARAMS dtp = {sizeof(DRAWTEXTPARAMS), 2};
96 DrawTextEx(dis->hDC, (LPTSTR)str, -1, &rt, DT_CALCRECT|DT_SINGLELINE|DT_NOPREFIX|DT_EXPANDTABS|DT_TABSTOP, &dtp);*/
97
98 DrawText(dis->hDC, (LPTSTR)str, -1, &rt, DT_CALCRECT|DT_SINGLELINE|DT_EXPANDTABS|DT_TABSTOP|(2<<8));
99 //@@ rt (0,0) ???
100
101 if (rt.right > pane->widths[col])
102 pane->widths[col] = rt.right;
103 }
104
105
106 static void output_text(Pane* pane, LPDRAWITEMSTRUCT dis, int col, LPCTSTR str, DWORD flags)
107 {
108 int x = dis->rcItem.left;
109 RECT rt = {x+pane->positions[col]+Globals.spaceSize.cx, dis->rcItem.top, x+pane->positions[col+1]-Globals.spaceSize.cx, dis->rcItem.bottom};
110
111 DrawText(dis->hDC, (LPTSTR)str, -1, &rt, DT_SINGLELINE|DT_NOPREFIX|flags);
112 }
113
114 static void output_tabbed_text(Pane* pane, LPDRAWITEMSTRUCT dis, int col, LPCTSTR str)
115 {
116 int x = dis->rcItem.left;
117 RECT rt = {x+pane->positions[col]+Globals.spaceSize.cx, dis->rcItem.top, x+pane->positions[col+1]-Globals.spaceSize.cx, dis->rcItem.bottom};
118
119 /* DRAWTEXTPARAMS dtp = {sizeof(DRAWTEXTPARAMS), 2};
120 DrawTextEx(dis->hDC, (LPTSTR)str, -1, &rt, DT_SINGLELINE|DT_NOPREFIX|DT_EXPANDTABS|DT_TABSTOP, &dtp);*/
121
122 DrawText(dis->hDC, (LPTSTR)str, -1, &rt, DT_SINGLELINE|DT_EXPANDTABS|DT_TABSTOP|(2<<8));
123 }
124
125 static void output_number(Pane* pane, LPDRAWITEMSTRUCT dis, int col, LPCTSTR str)
126 {
127 int x = dis->rcItem.left;
128 RECT rt = {x+pane->positions[col]+Globals.spaceSize.cx, dis->rcItem.top, x+pane->positions[col+1]-Globals.spaceSize.cx, dis->rcItem.bottom};
129 LPCTSTR s = str;
130 TCHAR b[128];
131 LPTSTR d = b;
132 int pos;
133
134 if (*s)
135 *d++ = *s++;
136
137 // insert number separator characters
138 pos = lstrlen(s) % 3;
139
140 while(*s)
141 if (pos--)
142 *d++ = *s++;
143 else {
144 *d++ = Globals.num_sep;
145 pos = 3;
146 }
147
148 DrawText(dis->hDC, b, d-b, &rt, DT_RIGHT|DT_SINGLELINE|DT_NOPREFIX|DT_END_ELLIPSIS);
149 }
150
151
152 void draw_item(Pane* pane, LPDRAWITEMSTRUCT dis, Entry* entry, int calcWidthCol)
153 {
154 #if 0
155 TCHAR buffer[BUFFER_LEN];
156 DWORD attrs;
157 int visible_cols = pane->visible_cols;
158 COLORREF bkcolor, textcolor;
159 RECT focusRect = dis->rcItem;
160 HBRUSH hbrush;
161 enum IMAGE img;
162 #ifndef _NO_EXTENSIONS
163 QWORD index;
164 #endif
165 int img_pos, cx;
166 int col = 0;
167
168 if (entry) {
169 attrs = entry->data.dwFileAttributes;
170
171 if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
172 if (entry->data.cFileName[0]==_T('.') && entry->data.cFileName[1]==_T('.')
173 && entry->data.cFileName[2]==_T('\0'))
174 img = IMG_FOLDER_UP;
175 #ifndef _NO_EXTENSIONS
176 else if (entry->data.cFileName[0]==_T('.') && entry->data.cFileName[1]==_T('\0'))
177 img = IMG_FOLDER_CUR;
178 #endif
179 else if (
180 #ifdef _NO_EXTENSIONS
181 entry->expanded ||
182 #endif
183 (pane->treePane && (dis->itemState&ODS_FOCUS)))
184 img = IMG_OPEN_FOLDER;
185 else
186 img = IMG_FOLDER;
187 } else {
188 LPCTSTR ext = _tcsrchr(entry->data.cFileName, '.');
189 if (!ext)
190 ext = _T("");
191
192 if (is_exe_file(ext))
193 img = IMG_EXECUTABLE;
194 else if (is_registered_type(ext))
195 img = IMG_DOCUMENT;
196 else
197 img = IMG_FILE;
198 }
199 } else {
200 attrs = 0;
201 img = IMG_NONE;
202 }
203
204 if (pane->treePane) {
205 if (entry) {
206 img_pos = dis->rcItem.left + entry->level*(IMAGE_WIDTH+Globals.spaceSize.cx);
207
208 if (calcWidthCol == -1) {
209 int x;
210 int y = dis->rcItem.top + IMAGE_HEIGHT/2;
211 Entry* up;
212 RECT rt_clip = {dis->rcItem.left, dis->rcItem.top, dis->rcItem.left+pane->widths[col], dis->rcItem.bottom};
213 HRGN hrgn_org = CreateRectRgn(0, 0, 0, 0);
214 HRGN hrgn = CreateRectRgnIndirect(&rt_clip);
215
216 if (!GetClipRgn(dis->hDC, hrgn_org)) {
217 DeleteObject(hrgn_org);
218 hrgn_org = 0;
219 }
220
221 // HGDIOBJ holdPen = SelectObject(dis->hDC, GetStockObject(BLACK_PEN));
222 ExtSelectClipRgn(dis->hDC, hrgn, RGN_AND);
223 DeleteObject(hrgn);
224
225 if ((up=entry->up) != NULL) {
226 MoveToEx(dis->hDC, img_pos-IMAGE_WIDTH/2, y, 0);
227 LineTo(dis->hDC, img_pos-2, y);
228
229 x = img_pos - IMAGE_WIDTH/2;
230
231 do {
232 x -= IMAGE_WIDTH+Globals.spaceSize.cx;
233
234 if (up->next
235 #ifndef _LEFT_FILES
236 && (up->next->data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
237 #endif
238 ) {
239 MoveToEx(dis->hDC, x, dis->rcItem.top, 0);
240 LineTo(dis->hDC, x, dis->rcItem.bottom);
241 }
242 } while((up=up->up) != NULL);
243 }
244
245 x = img_pos - IMAGE_WIDTH/2;
246
247 MoveToEx(dis->hDC, x, dis->rcItem.top, 0);
248 LineTo(dis->hDC, x, y);
249
250 if (entry->next
251 #ifndef _LEFT_FILES
252 && (entry->next->data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
253 #endif
254 )
255 LineTo(dis->hDC, x, dis->rcItem.bottom);
256
257 if (entry->down && entry->expanded) {
258 x += IMAGE_WIDTH+Globals.spaceSize.cx;
259 MoveToEx(dis->hDC, x, dis->rcItem.top+IMAGE_HEIGHT, 0);
260 LineTo(dis->hDC, x, dis->rcItem.bottom);
261 }
262
263 SelectClipRgn(dis->hDC, hrgn_org);
264 if (hrgn_org) DeleteObject(hrgn_org);
265 // SelectObject(dis->hDC, holdPen);
266 } else if (calcWidthCol==col || calcWidthCol==COLUMNS) {
267 int right = img_pos + IMAGE_WIDTH - Globals.spaceSize.cx;
268
269 if (right > pane->widths[col])
270 pane->widths[col] = right;
271 }
272 } else {
273 img_pos = dis->rcItem.left;
274 }
275 } else {
276 img_pos = dis->rcItem.left;
277
278 if (calcWidthCol==col || calcWidthCol==COLUMNS)
279 pane->widths[col] = IMAGE_WIDTH;
280 }
281
282 if (calcWidthCol == -1) {
283 focusRect.left = img_pos -2;
284
285 #ifdef _NO_EXTENSIONS
286 if (pane->treePane && entry) {
287 RECT rt = {0};
288
289 DrawText(dis->hDC, entry->data.cFileName, -1, &rt, DT_CALCRECT|DT_SINGLELINE|DT_NOPREFIX);
290
291 focusRect.right = dis->rcItem.left+pane->positions[col+1]+Globals.spaceSize.cx + rt.right +2;
292 }
293 #else
294
295 if (attrs & FILE_ATTRIBUTE_COMPRESSED)
296 textcolor = COLOR_COMPRESSED;
297 else
298 #endif
299 textcolor = RGB(0,0,0);
300
301 if (dis->itemState & ODS_FOCUS) {
302 textcolor = RGB(255,255,255);
303 bkcolor = COLOR_SELECTION;
304 } else {
305 bkcolor = RGB(255,255,255);
306 }
307
308 hbrush = CreateSolidBrush(bkcolor);
309 FillRect(dis->hDC, &focusRect, hbrush);
310 DeleteObject(hbrush);
311
312 SetBkMode(dis->hDC, TRANSPARENT);
313 SetTextColor(dis->hDC, textcolor);
314
315 cx = pane->widths[col];
316
317 if (cx && img!=IMG_NONE) {
318 if (cx > IMAGE_WIDTH)
319 cx = IMAGE_WIDTH;
320
321 ImageList_DrawEx(Globals.himl, img, dis->hDC,
322 img_pos, dis->rcItem.top, cx,
323 IMAGE_HEIGHT, bkcolor, CLR_DEFAULT, ILD_NORMAL);
324 }
325 }
326
327 if (!entry)
328 return;
329
330 #ifdef _NO_EXTENSIONS
331 if (img >= IMG_FOLDER_UP)
332 return;
333 #endif
334
335 col++;
336
337 // ouput file name
338 if (calcWidthCol == -1)
339 output_text(pane, dis, col, entry->data.cFileName, 0);
340 else if (calcWidthCol==col || calcWidthCol==COLUMNS)
341 calc_width(pane, dis, col, entry->data.cFileName);
342
343 col++;
344
345 #ifdef _NO_EXTENSIONS
346 if (!pane->treePane) {
347 #endif
348
349 // display file size
350 if (visible_cols & COL_SIZE) {
351 #ifdef _NO_EXTENSIONS
352 if (!(attrs&FILE_ATTRIBUTE_DIRECTORY))
353 #endif
354 {
355 QWORD size;
356
357 *(DWORD*)(&size) = entry->data.nFileSizeLow; //TODO: platform spefific
358 *(((DWORD*)&size)+1) = entry->data.nFileSizeHigh;
359
360 _stprintf(buffer, _T("%") LONGLONGARG _T("d"), size);
361
362 if (calcWidthCol == -1)
363 output_number(pane, dis, col, buffer);
364 else if (calcWidthCol==col || calcWidthCol==COLUMNS)
365 calc_width(pane, dis, col, buffer);//TODO: not ever time enough
366 }
367
368 col++;
369 }
370
371 // display file date
372 if (visible_cols & (COL_DATE|COL_TIME)) {
373 #ifndef _NO_EXTENSIONS
374 format_date(&entry->data.ftCreationTime, buffer, visible_cols);
375 if (calcWidthCol == -1)
376 output_text(pane, dis, col, buffer, 0);
377 else if (calcWidthCol==col || calcWidthCol==COLUMNS)
378 calc_width(pane, dis, col, buffer);
379 col++;
380
381 format_date(&entry->data.ftLastAccessTime, buffer, visible_cols);
382 if (calcWidthCol == -1)
383 output_text(pane, dis, col, buffer, 0);
384 else if (calcWidthCol==col || calcWidthCol==COLUMNS)
385 calc_width(pane, dis, col, buffer);
386 col++;
387 #endif
388
389 format_date(&entry->data.ftLastWriteTime, buffer, visible_cols);
390 if (calcWidthCol == -1)
391 output_text(pane, dis, col, buffer, 0);
392 else if (calcWidthCol==col || calcWidthCol==COLUMNS)
393 calc_width(pane, dis, col, buffer);
394 col++;
395 }
396
397 #ifndef _NO_EXTENSIONS
398 if (entry->bhfi_valid) {
399 ((DWORD*)&index)[0] = entry->bhfi.nFileIndexLow; //TODO: platform spefific
400 ((DWORD*)&index)[1] = entry->bhfi.nFileIndexHigh;
401
402 if (visible_cols & COL_INDEX) {
403 _stprintf(buffer, _T("%") LONGLONGARG _T("X"), index);
404 if (calcWidthCol == -1)
405 output_text(pane, dis, col, buffer, DT_RIGHT);
406 else if (calcWidthCol==col || calcWidthCol==COLUMNS)
407 calc_width(pane, dis, col, buffer);
408 col++;
409 }
410
411 if (visible_cols & COL_LINKS) {
412 wsprintf(buffer, _T("%d"), entry->bhfi.nNumberOfLinks);
413 if (calcWidthCol == -1)
414 output_text(pane, dis, col, buffer, DT_CENTER);
415 else if (calcWidthCol==col || calcWidthCol==COLUMNS)
416 calc_width(pane, dis, col, buffer);
417 col++;
418 }
419 } else
420 col += 2;
421 #endif
422
423 // show file attributes
424 if (visible_cols & COL_ATTRIBUTES) {
425 #ifdef _NO_EXTENSIONS
426 _tcscpy(buffer, _T(" \t \t \t \t "));
427 #else
428 _tcscpy(buffer, _T(" \t \t \t \t \t \t \t \t \t \t \t "));
429 #endif
430
431 if (attrs & FILE_ATTRIBUTE_NORMAL) buffer[ 0] = 'N';
432 else {
433 if (attrs & FILE_ATTRIBUTE_READONLY) buffer[ 2] = 'R';
434 if (attrs & FILE_ATTRIBUTE_HIDDEN) buffer[ 4] = 'H';
435 if (attrs & FILE_ATTRIBUTE_SYSTEM) buffer[ 6] = 'S';
436 if (attrs & FILE_ATTRIBUTE_ARCHIVE) buffer[ 8] = 'A';
437 if (attrs & FILE_ATTRIBUTE_COMPRESSED) buffer[10] = 'C';
438 #ifndef _NO_EXTENSIONS
439 if (attrs & FILE_ATTRIBUTE_DIRECTORY) buffer[12] = 'D';
440 if (attrs & FILE_ATTRIBUTE_ENCRYPTED) buffer[14] = 'E';
441 if (attrs & FILE_ATTRIBUTE_TEMPORARY) buffer[16] = 'T';
442 if (attrs & FILE_ATTRIBUTE_SPARSE_FILE) buffer[18] = 'P';
443 if (attrs & FILE_ATTRIBUTE_REPARSE_POINT) buffer[20] = 'Q';
444 if (attrs & FILE_ATTRIBUTE_OFFLINE) buffer[22] = 'O';
445 if (attrs & FILE_ATTRIBUTE_NOT_CONTENT_INDEXED) buffer[24] = 'X';
446 #endif
447 }
448
449 if (calcWidthCol == -1)
450 output_tabbed_text(pane, dis, col, buffer);
451 else if (calcWidthCol==col || calcWidthCol==COLUMNS)
452 calc_tabbed_width(pane, dis, col, buffer);
453
454 col++;
455 }
456
457 /*TODO
458 if (flags.security) {
459 DWORD rights = get_access_mask();
460
461 tcscpy(buffer, _T(" \t \t \t \t \t \t \t \t \t \t \t "));
462
463 if (rights & FILE_READ_DATA) buffer[ 0] = 'R';
464 if (rights & FILE_WRITE_DATA) buffer[ 2] = 'W';
465 if (rights & FILE_APPEND_DATA) buffer[ 4] = 'A';
466 if (rights & FILE_READ_EA) {buffer[6] = 'entry'; buffer[ 7] = 'R';}
467 if (rights & FILE_WRITE_EA) {buffer[9] = 'entry'; buffer[10] = 'W';}
468 if (rights & FILE_EXECUTE) buffer[12] = 'X';
469 if (rights & FILE_DELETE_CHILD) buffer[14] = 'D';
470 if (rights & FILE_READ_ATTRIBUTES) {buffer[16] = 'a'; buffer[17] = 'R';}
471 if (rights & FILE_WRITE_ATTRIBUTES) {buffer[19] = 'a'; buffer[20] = 'W';}
472 if (rights & WRITE_DAC) buffer[22] = 'C';
473 if (rights & WRITE_OWNER) buffer[24] = 'O';
474 if (rights & SYNCHRONIZE) buffer[26] = 'S';
475
476 output_text(dis, col++, buffer, DT_LEFT, 3, psize);
477 }
478
479 if (flags.description) {
480 get_description(buffer);
481 output_text(dis, col++, buffer, 0, psize);
482 }
483 */
484
485 #ifdef _NO_EXTENSIONS
486 }
487
488 // draw focus frame
489 if ((dis->itemState&ODS_FOCUS) && calcWidthCol==-1) {
490 // Currently [04/2000] Wine neither behaves exactly the same
491 // way as WIN 95 nor like Windows NT...
492 #ifdef WINELIB
493 DrawFocusRect(dis->hDC, &focusRect);
494 #else
495 HGDIOBJ lastBrush;
496 HPEN lastPen;
497 HPEN hpen;
498
499 if (!(GetVersion() & 0x80000000)) { // Windows NT?
500 LOGBRUSH lb = {PS_SOLID, RGB(255,255,255)};
501 hpen = ExtCreatePen(PS_COSMETIC|PS_ALTERNATE, 1, &lb, 0, 0);
502 } else
503 hpen = CreatePen(PS_DOT, 0, RGB(255,255,255));
504
505 lastPen = SelectPen(dis->hDC, hpen);
506 lastBrush = SelectObject(dis->hDC, GetStockObject(HOLLOW_BRUSH));
507 SetROP2(dis->hDC, R2_XORPEN);
508 Rectangle(dis->hDC, focusRect.left, focusRect.top, focusRect.right, focusRect.bottom);
509 SelectObject(dis->hDC, lastBrush);
510 SelectObject(dis->hDC, lastPen);
511 DeleteObject(hpen);
512 #endif
513 }
514 #endif
515 #endif
516 }
517
518
519
520 #ifdef _NO_EXTENSIONS
521
522 void draw_splitbar(HWND hwnd, int x)
523 {
524 RECT rt;
525 HDC hdc = GetDC(hwnd);
526
527 GetClientRect(hwnd, &rt);
528 rt.left = x - SPLIT_WIDTH/2;
529 rt.right = x + SPLIT_WIDTH/2+1;
530 InvertRect(hdc, &rt);
531 ReleaseDC(hwnd, hdc);
532 }
533
534 #endif
535