Sync to trunk r65566.
[reactos.git] / base / shell / explorer-old / shell / pane.cpp
1 /*
2 * Copyright 2003, 2004, 2005 Martin Fuchs
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19
20 //
21 // Explorer clone
22 //
23 // pane.cpp
24 //
25 // Martin Fuchs, 23.07.2003
26 //
27
28
29 #include <precomp.h>
30
31 enum IMAGE {
32 IMG_NONE=-1, IMG_FILE=0, IMG_DOCUMENT, IMG_EXECUTABLE,
33 IMG_FOLDER, IMG_OPEN_FOLDER, IMG_FOLDER_PLUS,IMG_OPEN_PLUS, IMG_OPEN_MINUS,
34 IMG_FOLDER_UP, IMG_FOLDER_CUR
35 };
36
37
38 #define IMAGE_WIDTH 16
39 #define IMAGE_HEIGHT 13
40
41
42 static const TCHAR* g_pos_names[COLUMNS] = {
43 TEXT(""), /* symbol */
44 TEXT("Name"),
45 TEXT("Type"),
46 TEXT("Size"),
47 TEXT("CDate"),
48 TEXT("ADate"),
49 TEXT("MDate"),
50 TEXT("Index/Inode"),
51 TEXT("Links"),
52 TEXT("Attributes"),
53 TEXT("Security"),
54 TEXT("Content")
55 };
56
57 static const int g_pos_align[] = {
58 0,
59 HDF_LEFT, /* Name */
60 HDF_LEFT, /* Type */
61 HDF_RIGHT, /* Size */
62 HDF_LEFT, /* CDate */
63 HDF_LEFT, /* ADate */
64 HDF_LEFT, /* MDate */
65 HDF_LEFT, /* Index */
66 HDF_RIGHT, /* Links */
67 HDF_CENTER, /* Attributes */
68 HDF_LEFT, /* Security */
69 HDF_LEFT /* Content / Description */
70 };
71
72
73 Pane::Pane(HWND hparent, int id, int id_header, Entry* root, bool treePane, int visible_cols)
74 : super(CreateWindow(TEXT("ListBox"), TEXT(""), WS_CHILD|WS_VISIBLE|WS_HSCROLL|WS_VSCROLL|
75 LBS_DISABLENOSCROLL|LBS_NOINTEGRALHEIGHT|LBS_OWNERDRAWFIXED|LBS_NOTIFY,
76 0, 0, 0, 0, hparent, (HMENU)id, g_Globals._hInstance, 0)),
77 _root(root),
78 _visible_cols(visible_cols),
79 _treePane(treePane)
80 {
81 // insert entries into listbox
82 Entry* entry = _root;
83
84 if (entry)
85 insert_entries(entry);
86
87 init();
88
89 create_header(hparent, id_header);
90 }
91
92 Pane::~Pane()
93 {
94 ImageList_Destroy(_himl);
95 }
96
97
98 LRESULT Pane::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
99 {
100 switch(nmsg) {
101 case WM_HSCROLL:
102 set_header();
103 break;
104
105 case WM_SETFOCUS: {
106 FileChildWindow* child = (FileChildWindow*) SendMessage(GetParent(_hwnd), PM_GET_FILEWND_PTR, 0, 0);
107
108 child->set_focus_pane(this);
109 ListBox_SetSel(_hwnd, TRUE, 1);
110 /*@todo check menu items */
111 break;}
112
113 case WM_KEYDOWN: {
114 FileChildWindow* child = (FileChildWindow*) SendMessage(GetParent(_hwnd), PM_GET_FILEWND_PTR, 0, 0);
115
116 if (wparam == VK_TAB) {
117 /*@todo SetFocus(g_Globals.hdrivebar) */
118 child->switch_focus_pane();
119 }
120 break;}
121 }
122
123 return super::WndProc(nmsg, wparam, lparam);
124 }
125
126
127 bool Pane::create_header(HWND hparent, int id)
128 {
129 HWND hwnd = CreateWindow(WC_HEADER, 0, WS_CHILD|WS_VISIBLE|HDS_HORZ/*@todo |HDS_BUTTONS + sort orders*/,
130 0, 0, 0, 0, hparent, (HMENU)id, g_Globals._hInstance, 0);
131 if (!hwnd)
132 return false;
133
134 SetWindowFont(hwnd, GetStockFont(DEFAULT_GUI_FONT), FALSE);
135
136 HD_ITEM hdi;
137
138 hdi.mask = HDI_TEXT|HDI_WIDTH|HDI_FORMAT;
139
140 for(int idx=0; idx<COLUMNS; idx++) {
141 hdi.pszText = (TCHAR*)g_pos_names[idx];
142 hdi.fmt = HDF_STRING | g_pos_align[idx];
143 hdi.cxy = _widths[idx];
144 Header_InsertItem(hwnd, idx, &hdi);
145 }
146
147 _hwndHeader = hwnd;
148
149 return true;
150 }
151
152
153 void Pane::init()
154 {
155 _himl = ImageList_LoadBitmap(g_Globals._hInstance, MAKEINTRESOURCE(IDB_IMAGES), 16, 0, RGB(0,255,0));
156
157 SetWindowFont(_hwnd, _out_wrkr._hfont, FALSE);
158
159 // read the color for compressed files from registry
160 HKEY hkeyExplorer = 0;
161 DWORD len = sizeof(_clrCompressed);
162
163 if (RegOpenKey(HKEY_CURRENT_USER, TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer"), &hkeyExplorer) ||
164 RegQueryValueEx(hkeyExplorer, TEXT("AltColor"), 0, NULL, (LPBYTE)&_clrCompressed, &len) || len!=sizeof(_clrCompressed))
165 _clrCompressed = RGB(0,0,255);
166
167 if (hkeyExplorer)
168 RegCloseKey(hkeyExplorer);
169
170 // calculate column widths
171 _out_wrkr.init_output(_hwnd);
172 calc_widths(true);
173 }
174
175
176 // calculate prefered width for all visible columns
177
178 bool Pane::calc_widths(bool anyway)
179 {
180 int col, x, cx, spc=3*_out_wrkr._spaceSize.cx;
181 int entries = ListBox_GetCount(_hwnd);
182 int orgWidths[COLUMNS];
183 int orgPositions[COLUMNS+1];
184 HFONT hfontOld;
185 HDC hdc;
186 int cnt;
187
188 if (!anyway) {
189 memcpy(orgWidths, _widths, sizeof(orgWidths));
190 memcpy(orgPositions, _positions, sizeof(orgPositions));
191 }
192
193 for(col=0; col<COLUMNS; col++)
194 _widths[col] = 0;
195
196 hdc = GetDC(_hwnd);
197 hfontOld = SelectFont(hdc, _out_wrkr._hfont);
198
199 for(cnt=0; cnt<entries; cnt++) {
200 Entry* entry = (Entry*) ListBox_GetItemData(_hwnd, cnt);
201
202 DRAWITEMSTRUCT dis;
203
204 dis.CtlType = 0;
205 dis.CtlID = 0;
206 dis.itemID = 0;
207 dis.itemAction = 0;
208 dis.itemState = 0;
209 dis.hwndItem = _hwnd;
210 dis.hDC = hdc;
211 dis.rcItem.left = 0;
212 dis.rcItem.top = 0;
213 dis.rcItem.right = 0;
214 dis.rcItem.bottom = 0;
215 /*dis.itemData = 0; */
216
217 draw_item(&dis, entry, COLUMNS);
218 }
219
220 SelectObject(hdc, hfontOld);
221 ReleaseDC(_hwnd, hdc);
222
223 x = 0;
224 for(col=0; col<COLUMNS; col++) {
225 _positions[col] = x;
226 cx = _widths[col];
227
228 if (cx) {
229 cx += spc;
230
231 if (cx < IMAGE_WIDTH)
232 cx = IMAGE_WIDTH;
233
234 _widths[col] = cx;
235 }
236
237 x += cx;
238 }
239
240 _positions[COLUMNS] = x;
241
242 ListBox_SetHorizontalExtent(_hwnd, x);
243
244 // no change?
245 if (!memcmp(orgWidths, _widths, sizeof(orgWidths)))
246 return FALSE;
247
248 // don't move, if only collapsing an entry
249 if (!anyway && _widths[0]<orgWidths[0] &&
250 !memcmp(orgWidths+1, _widths+1, sizeof(orgWidths)-sizeof(int))) {
251 _widths[0] = orgWidths[0];
252 memcpy(_positions, orgPositions, sizeof(orgPositions));
253
254 return FALSE;
255 }
256
257 InvalidateRect(_hwnd, 0, TRUE);
258
259 return TRUE;
260 }
261
262
263 static void format_date(const FILETIME* ft, TCHAR* buffer, int visible_cols)
264 {
265 SYSTEMTIME systime;
266 FILETIME lft;
267 int len = 0;
268
269 *buffer = TEXT('\0');
270
271 if (!ft->dwLowDateTime && !ft->dwHighDateTime)
272 return;
273
274 if (!FileTimeToLocalFileTime(ft, &lft))
275 {err: lstrcpy(buffer,TEXT("???")); return;}
276
277 if (!FileTimeToSystemTime(&lft, &systime))
278 goto err;
279
280 if (visible_cols & COL_DATE) {
281 len = GetDateFormat(LOCALE_USER_DEFAULT, 0, &systime, 0, buffer, BUFFER_LEN);
282 if (!len)
283 goto err;
284 }
285
286 if (visible_cols & COL_TIME) {
287 if (len)
288 buffer[len-1] = ' ';
289
290 buffer[len++] = ' ';
291
292 if (!GetTimeFormat(LOCALE_USER_DEFAULT, 0, &systime, 0, buffer+len, BUFFER_LEN-len))
293 buffer[len] = TEXT('\0');
294 }
295 }
296
297
298 void Pane::draw_item(LPDRAWITEMSTRUCT dis, Entry* entry, int calcWidthCol)
299 {
300 TCHAR buffer[BUFFER_LEN];
301 DWORD attrs;
302 int visible_cols = _visible_cols;
303 COLORREF bkcolor, textcolor;
304 RECT focusRect = dis->rcItem;
305 enum IMAGE img;
306 int img_pos, cx;
307 int col = 0;
308
309 if (entry) {
310 attrs = entry->_data.dwFileAttributes;
311
312 if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
313 if (entry->_data.cFileName[0]==TEXT('.') && entry->_data.cFileName[1]==TEXT('.')
314 && entry->_data.cFileName[2]==TEXT('\0'))
315 img = IMG_FOLDER_UP;
316 else if (entry->_data.cFileName[0]==TEXT('.') && entry->_data.cFileName[1]==TEXT('\0'))
317 img = IMG_FOLDER_CUR;
318 else if ((_treePane && (dis->itemState&ODS_FOCUS)))
319 img = IMG_OPEN_FOLDER;
320 else
321 img = IMG_FOLDER;
322 } else {
323 if (attrs & ATTRIBUTE_EXECUTABLE)
324 img = IMG_EXECUTABLE;
325 else if (entry->_type_name)
326 img = IMG_DOCUMENT;
327 else
328 img = IMG_FILE;
329 }
330 } else {
331 attrs = 0;
332 img = IMG_NONE;
333 }
334
335 if (_treePane) {
336 if (entry) {
337 img_pos = dis->rcItem.left + entry->_level*(IMAGE_WIDTH+_out_wrkr._spaceSize.cx);
338
339 if (calcWidthCol == -1) {
340 int x;
341 int y = dis->rcItem.top + IMAGE_HEIGHT/2;
342 Entry* up;
343 RECT rt_clip;
344 HRGN hrgn_org = CreateRectRgn(0, 0, 0, 0);
345 HRGN hrgn;
346
347 rt_clip.left = dis->rcItem.left;
348 rt_clip.top = dis->rcItem.top;
349 rt_clip.right = dis->rcItem.left+_widths[col];
350 rt_clip.bottom = dis->rcItem.bottom;
351
352 hrgn = CreateRectRgnIndirect(&rt_clip);
353
354 if (!GetClipRgn(dis->hDC, hrgn_org)) {
355 DeleteObject(hrgn_org);
356 hrgn_org = 0;
357 }
358
359 //HGDIOBJ holdPen = SelectObject(dis->hDC, GetStockObject(BLACK_PEN));
360 ExtSelectClipRgn(dis->hDC, hrgn, RGN_AND);
361 DeleteObject(hrgn);
362
363 if ((up=entry->_up) != NULL) {
364 MoveToEx(dis->hDC, img_pos-IMAGE_WIDTH/2, y, 0);
365 LineTo(dis->hDC, img_pos-2, y);
366
367 x = img_pos - IMAGE_WIDTH/2;
368
369 do {
370 x -= IMAGE_WIDTH+_out_wrkr._spaceSize.cx;
371
372 if (up->_next) {
373 #ifndef _LEFT_FILES
374 bool following_child = (up->_next->_data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)!=0; // a directory?
375
376 if (!following_child)
377 {
378 for(Entry*n=up->_next; n; n=n->_next)
379 if (n->_down) { // any file with NTFS sub-streams?
380 following_child = true;
381 break;
382 }
383 }
384 if (following_child)
385 #endif
386 {
387 MoveToEx(dis->hDC, x, dis->rcItem.top, 0);
388 LineTo(dis->hDC, x, dis->rcItem.bottom);
389 }
390 }
391 } while((up=up->_up) != NULL);
392 }
393
394 x = img_pos - IMAGE_WIDTH/2;
395
396 MoveToEx(dis->hDC, x, dis->rcItem.top, 0);
397 LineTo(dis->hDC, x, y);
398
399 if (entry->_next) {
400 #ifndef _LEFT_FILES
401 bool following_child = (entry->_next->_data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)!=0; // a directory?
402
403 if (!following_child)
404 {
405 for(Entry*n=entry->_next; n; n=n->_next)
406 if (n->_down) { // any file with NTFS sub-streams?
407 following_child = true;
408 break;
409 }
410 }
411 if (following_child)
412 #endif
413 LineTo(dis->hDC, x, dis->rcItem.bottom);
414 }
415
416 if (entry->_down && entry->_expanded) {
417 x += IMAGE_WIDTH + _out_wrkr._spaceSize.cx;
418 MoveToEx(dis->hDC, x, dis->rcItem.top+IMAGE_HEIGHT, 0);
419 LineTo(dis->hDC, x, dis->rcItem.bottom);
420 }
421
422 SelectClipRgn(dis->hDC, hrgn_org);
423 if (hrgn_org) DeleteObject(hrgn_org);
424 //SelectObject(dis->hDC, holdPen);
425 } else if (calcWidthCol==col || calcWidthCol==COLUMNS) {
426 int right = img_pos + IMAGE_WIDTH - _out_wrkr._spaceSize.cx;
427
428 if (right > _widths[col])
429 _widths[col] = right;
430 }
431 } else {
432 img_pos = dis->rcItem.left;
433 }
434 } else {
435 img_pos = dis->rcItem.left;
436
437 if (calcWidthCol==col || calcWidthCol==COLUMNS)
438 _widths[col] = IMAGE_WIDTH;
439 }
440
441 if (calcWidthCol == -1) {
442 focusRect.left = img_pos -2;
443
444 if (attrs & FILE_ATTRIBUTE_COMPRESSED)
445 textcolor = _clrCompressed;
446 else
447 textcolor = RGB(0,0,0);
448
449 if (dis->itemState & ODS_FOCUS) {
450 textcolor = GetSysColor(COLOR_HIGHLIGHTTEXT);
451 bkcolor = GetSysColor(COLOR_HIGHLIGHT);
452 } else {
453 bkcolor = GetSysColor(COLOR_WINDOW);
454 }
455
456 HBRUSH hbrush = CreateSolidBrush(bkcolor);
457 FillRect(dis->hDC, &focusRect, hbrush);
458 DeleteObject(hbrush);
459
460 SetBkMode(dis->hDC, TRANSPARENT);
461 SetTextColor(dis->hDC, textcolor);
462
463 cx = _widths[col];
464
465 if (cx && img!=IMG_NONE) {
466 if (cx > IMAGE_WIDTH)
467 cx = IMAGE_WIDTH;
468
469 if (entry->_icon_id > ICID_NONE)
470 g_Globals._icon_cache.get_icon(entry->_icon_id).draw(dis->hDC, img_pos, dis->rcItem.top, cx, GetSystemMetrics(SM_CYSMICON), bkcolor, 0);
471 else
472 ImageList_DrawEx(_himl, img, dis->hDC,
473 img_pos, dis->rcItem.top, cx,
474 IMAGE_HEIGHT, bkcolor, CLR_DEFAULT, ILD_NORMAL);
475 }
476 }
477
478 if (!entry)
479 return;
480
481 ++col;
482
483 // output file name
484 if (calcWidthCol == -1)
485 _out_wrkr.output_text(dis, _positions, col, entry->_display_name, 0);
486 else if (calcWidthCol==col || calcWidthCol==COLUMNS)
487 calc_width(dis, col, entry->_display_name);
488 ++col;
489
490 // output type/class name
491 if (visible_cols & COL_TYPE) {
492 if (calcWidthCol == -1)
493 _out_wrkr.output_text(dis, _positions, col, entry->_type_name? entry->_type_name: TEXT(""), 0);
494 else if (calcWidthCol==col || calcWidthCol==COLUMNS)
495 calc_width(dis, col, entry->_type_name? entry->_type_name: TEXT(""));
496 }
497 ++col;
498
499 // display file size
500 if (visible_cols & COL_SIZE) {
501 ULONGLONG size = ((ULONGLONG)entry->_data.nFileSizeHigh << 32) | entry->_data.nFileSizeLow;
502
503 _stprintf(buffer, TEXT("%") LONGLONGARG TEXT("d"), size);
504
505 if (calcWidthCol == -1)
506 _out_wrkr.output_number(dis, _positions, col, buffer);
507 else if (calcWidthCol==col || calcWidthCol==COLUMNS)
508 calc_width(dis, col, buffer); ///@todo not in every case time enough
509 }
510 ++col;
511
512 // display file date
513 if (visible_cols & (COL_DATE|COL_TIME)) {
514 format_date(&entry->_data.ftCreationTime, buffer, visible_cols);
515 if (calcWidthCol == -1)
516 _out_wrkr.output_text(dis, _positions, col, buffer, 0);
517 else if (calcWidthCol==col || calcWidthCol==COLUMNS)
518 calc_width(dis, col, buffer);
519 ++col;
520
521 format_date(&entry->_data.ftLastAccessTime, buffer, visible_cols);
522 if (calcWidthCol == -1)
523 _out_wrkr.output_text(dis,_positions, col, buffer, 0);
524 else if (calcWidthCol==col || calcWidthCol==COLUMNS)
525 calc_width(dis, col, buffer);
526 ++col;
527
528 format_date(&entry->_data.ftLastWriteTime, buffer, visible_cols);
529 if (calcWidthCol == -1)
530 _out_wrkr.output_text(dis, _positions, col, buffer, 0);
531 else if (calcWidthCol==col || calcWidthCol==COLUMNS)
532 calc_width(dis, col, buffer);
533 ++col;
534 } else
535 col += 3;
536
537 if (entry->_bhfi_valid) {
538 ULONGLONG index = ((ULONGLONG)entry->_bhfi.nFileIndexHigh << 32) | entry->_bhfi.nFileIndexLow;
539
540 if (visible_cols & COL_INDEX) {
541 _stprintf(buffer, TEXT("%") LONGLONGARG TEXT("X"), index);
542
543 if (calcWidthCol == -1)
544 _out_wrkr.output_text(dis, _positions, col, buffer, DT_RIGHT);
545 else if (calcWidthCol==col || calcWidthCol==COLUMNS)
546 calc_width(dis, col, buffer);
547
548 ++col;
549 }
550
551 if (visible_cols & COL_LINKS) {
552 wsprintf(buffer, TEXT("%d"), entry->_bhfi.nNumberOfLinks);
553
554 if (calcWidthCol == -1)
555 _out_wrkr.output_text(dis, _positions, col, buffer, DT_RIGHT);
556 else if (calcWidthCol==col || calcWidthCol==COLUMNS)
557 calc_width(dis, col, buffer);
558
559 ++col;
560 }
561 } else
562 col += 2;
563
564 // show file attributes
565 if (visible_cols & COL_ATTRIBUTES) {
566 lstrcpy(buffer, TEXT(" \t \t \t \t \t \t \t \t \t \t \t \t \t \t "));
567
568 if (attrs & FILE_ATTRIBUTE_NORMAL) buffer[ 0] = 'N';
569 else {
570 if (attrs & FILE_ATTRIBUTE_READONLY) buffer[ 2] = 'R';
571 if (attrs & FILE_ATTRIBUTE_HIDDEN) buffer[ 4] = 'H';
572 if (attrs & FILE_ATTRIBUTE_SYSTEM) buffer[ 6] = 'S';
573 if (attrs & FILE_ATTRIBUTE_ARCHIVE) buffer[ 8] = 'A';
574 if (attrs & FILE_ATTRIBUTE_COMPRESSED) buffer[10] = 'C';
575 if (attrs & FILE_ATTRIBUTE_DIRECTORY) buffer[12] = 'D';
576 if (attrs & FILE_ATTRIBUTE_ENCRYPTED) buffer[14] = 'E';
577 if (attrs & FILE_ATTRIBUTE_TEMPORARY) buffer[16] = 'T';
578 if (attrs & FILE_ATTRIBUTE_SPARSE_FILE) buffer[18] = 'P';
579 if (attrs & FILE_ATTRIBUTE_REPARSE_POINT) buffer[20] = 'Q';
580 if (attrs & FILE_ATTRIBUTE_OFFLINE) buffer[22] = 'O';
581 if (attrs & FILE_ATTRIBUTE_NOT_CONTENT_INDEXED) buffer[24] = 'X';
582 if (attrs & ATTRIBUTE_EXECUTABLE) buffer[26] = 'x';
583 if (attrs & ATTRIBUTE_SYMBOLIC_LINK) buffer[28] = 'L';
584 }
585
586 if (calcWidthCol == -1)
587 _out_wrkr.output_tabbed_text(dis, _positions, col, buffer);
588 else if (calcWidthCol==col || calcWidthCol==COLUMNS)
589 calc_tabbed_width(dis, col, buffer);
590 }
591 ++col;
592
593 /*TODO
594 if (flags.security) {
595 DWORD rights = get_access_mask();
596
597 tcscpy(buffer, TEXT(" \t \t \t \t \t \t \t \t \t \t \t "));
598
599 if (rights & FILE_READ_DATA) buffer[ 0] = 'R';
600 if (rights & FILE_WRITE_DATA) buffer[ 2] = 'W';
601 if (rights & FILE_APPEND_DATA) buffer[ 4] = 'A';
602 if (rights & FILE_READ_EA) {buffer[6] = 'entry'; buffer[ 7] = 'R';}
603 if (rights & FILE_WRITE_EA) {buffer[9] = 'entry'; buffer[10] = 'W';}
604 if (rights & FILE_EXECUTE) buffer[12] = 'X';
605 if (rights & FILE_DELETE_CHILD) buffer[14] = 'D';
606 if (rights & FILE_READ_ATTRIBUTES) {buffer[16] = 'a'; buffer[17] = 'R';}
607 if (rights & FILE_WRITE_ATTRIBUTES) {buffer[19] = 'a'; buffer[20] = 'W';}
608 if (rights & WRITE_DAC) buffer[22] = 'C';
609 if (rights & WRITE_OWNER) buffer[24] = 'O';
610 if (rights & SYNCHRONIZE) buffer[26] = 'S';
611
612 output_text(dis, col++, buffer, DT_LEFT, 3, psize);
613 }
614
615 if (flags.description) {
616 get_description(buffer);
617 output_text(dis, col++, buffer, 0, psize);
618 }
619 */
620 ++col;
621
622 // output content / symbolic link target / comment
623 if (visible_cols & COL_CONTENT) {
624 if (calcWidthCol == -1)
625 _out_wrkr.output_text(dis, _positions, col, entry->_content? entry->_content: TEXT(""), 0);
626 else if (calcWidthCol==col || calcWidthCol==COLUMNS)
627 calc_width(dis, col, entry->_content? entry->_content: TEXT(""));
628 }
629 }
630
631
632 void Pane::calc_width(LPDRAWITEMSTRUCT dis, int col, LPCTSTR str)
633 {
634 RECT rt = {0, 0, 0, 0};
635
636 DrawText(dis->hDC, (LPTSTR)str, -1, &rt, DT_CALCRECT|DT_SINGLELINE|DT_NOPREFIX);
637
638 if (rt.right > _widths[col])
639 _widths[col] = rt.right;
640 }
641
642 void Pane::calc_tabbed_width(LPDRAWITEMSTRUCT dis, int col, LPCTSTR str)
643 {
644 RECT rt = {0, 0, 0, 0};
645
646 /* DRAWTEXTPARAMS dtp = {sizeof(DRAWTEXTPARAMS), 2};
647 DrawTextEx(dis->hDC, (LPTSTR)str, -1, &rt, DT_CALCRECT|DT_SINGLELINE|DT_NOPREFIX|DT_EXPANDTABS|DT_TABSTOP, &dtp);*/
648
649 DrawText(dis->hDC, (LPTSTR)str, -1, &rt, DT_CALCRECT|DT_SINGLELINE|DT_EXPANDTABS|DT_TABSTOP|(2<<8));
650
651 if (rt.right > _widths[col])
652 _widths[col] = rt.right;
653 }
654
655
656 // insert listbox entries after index idx
657
658 int Pane::insert_entries(Entry* dir, int idx)
659 {
660 Entry* entry = dir;
661
662 if (!entry)
663 return idx;
664
665 for(; entry; entry=entry->_next) {
666 #ifndef _LEFT_FILES
667 if (_treePane &&
668 !(entry->_data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) && // not a directory?
669 !entry->_down) // not a file with NTFS sub-streams?
670 continue;
671 #endif
672
673 // don't display entries "." and ".." in the left pane
674 if (_treePane && (entry->_data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
675 && entry->_data.cFileName[0]==TEXT('.'))
676 if (entry->_data.cFileName[1]==TEXT('\0') ||
677 (entry->_data.cFileName[1]==TEXT('.') && entry->_data.cFileName[2]==TEXT('\0')))
678 continue;
679
680 if (idx != -1)
681 ++idx;
682
683 ListBox_InsertItemData(_hwnd, idx, entry);
684
685 if (_treePane && entry->_expanded)
686 idx = insert_entries(entry->_down, idx);
687 }
688
689 return idx;
690 }
691
692
693 void Pane::set_header()
694 {
695 HD_ITEM item;
696 int scroll_pos = GetScrollPos(_hwnd, SB_HORZ);
697 int i=0, x=0;
698
699 item.mask = HDI_WIDTH;
700 item.cxy = 0;
701
702 for(; i<COLUMNS; i++) {
703 if (x + _widths[i] >= scroll_pos)
704 break;
705
706 x += _widths[i];
707 Header_SetItem(_hwndHeader, i, &item);
708 }
709
710 if (i < COLUMNS) {
711 x += _widths[i];
712 item.cxy = x - scroll_pos;
713 Header_SetItem(_hwndHeader, i++, &item);
714
715 for(; i<COLUMNS; i++) {
716 item.cxy = _widths[i];
717 x += _widths[i];
718 Header_SetItem(_hwndHeader, i, &item);
719 }
720 }
721 }
722
723
724 // calculate one prefered column width
725
726 void Pane::calc_single_width(int col)
727 {
728 HFONT hfontOld;
729 int x, cx;
730 int cnt;
731 HDC hdc;
732
733 int entries = ListBox_GetCount(_hwnd);
734
735 _widths[col] = 0;
736
737 hdc = GetDC(_hwnd);
738 hfontOld = SelectFont(hdc, _out_wrkr._hfont);
739
740 for(cnt=0; cnt<entries; cnt++) {
741 Entry* entry = (Entry*) ListBox_GetItemData(_hwnd, cnt);
742
743 DRAWITEMSTRUCT dis;
744
745 dis.CtlType = 0;
746 dis.CtlID = 0;
747 dis.itemID = 0;
748 dis.itemAction = 0;
749 dis.itemState = 0;
750 dis.hwndItem = _hwnd;
751 dis.hDC = hdc;
752 dis.rcItem.left = 0;
753 dis.rcItem.top = 0;
754 dis.rcItem.right = 0;
755 dis.rcItem.bottom = 0;
756 /*dis.itemData = 0; */
757
758 draw_item(&dis, entry, col);
759 }
760
761 SelectObject(hdc, hfontOld);
762 ReleaseDC(_hwnd, hdc);
763
764 cx = _widths[col];
765
766 if (cx) {
767 cx += 3*_out_wrkr._spaceSize.cx;
768
769 if (cx < IMAGE_WIDTH)
770 cx = IMAGE_WIDTH;
771 }
772
773 _widths[col] = cx;
774
775 x = _positions[col] + cx;
776
777 for(; col<COLUMNS; col++) {
778 _positions[col+1] = x;
779 x += _widths[col];
780 }
781
782 ListBox_SetHorizontalExtent(_hwnd, x);
783 }
784
785
786 int Pane::Notify(int id, NMHDR* pnmh)
787 {
788 switch(pnmh->code) {
789 case HDN_TRACK:
790 case HDN_ENDTRACK: {
791 HD_NOTIFY* phdn = (HD_NOTIFY*) pnmh;
792 int idx = phdn->iItem;
793 int dx = phdn->pitem->cxy - _widths[idx];
794 int i;
795
796 ClientRect clnt(_hwnd);
797
798 // move immediate to simulate HDS_FULLDRAG (for now [04/2000] not realy needed with WINELIB)
799 Header_SetItem(_hwndHeader, idx, phdn->pitem);
800
801 _widths[idx] += dx;
802
803 for(i=idx; ++i<=COLUMNS; )
804 _positions[i] += dx;
805
806 {
807 int scroll_pos = GetScrollPos(_hwnd, SB_HORZ);
808 RECT rt_scr;
809 RECT rt_clip;
810
811 rt_scr.left = _positions[idx+1]-scroll_pos;
812 rt_scr.top = 0;
813 rt_scr.right = clnt.right;
814 rt_scr.bottom = clnt.bottom;
815
816 rt_clip.left = _positions[idx]-scroll_pos;
817 rt_clip.top = 0;
818 rt_clip.right = clnt.right;
819 rt_clip.bottom = clnt.bottom;
820
821 if (rt_scr.left < 0) rt_scr.left = 0;
822 if (rt_clip.left < 0) rt_clip.left = 0;
823
824 ScrollWindowEx(_hwnd, dx, 0, &rt_scr, &rt_clip, 0, 0, SW_INVALIDATE);
825
826 rt_clip.right = _positions[idx+1];
827 RedrawWindow(_hwnd, &rt_clip, 0, RDW_INVALIDATE|RDW_UPDATENOW);
828
829 if (pnmh->code == HDN_ENDTRACK) {
830 ListBox_SetHorizontalExtent(_hwnd, _positions[COLUMNS]);
831
832 if (GetScrollPos(_hwnd, SB_HORZ) != scroll_pos)
833 set_header();
834 }
835 }
836
837 return 0;
838 }
839
840 case HDN_DIVIDERDBLCLICK: {
841 HD_NOTIFY* phdn = (HD_NOTIFY*) pnmh;
842 HD_ITEM item;
843
844 calc_single_width(phdn->iItem);
845 item.mask = HDI_WIDTH;
846 item.cxy = _widths[phdn->iItem];
847
848 Header_SetItem(_hwndHeader, phdn->iItem, &item);
849 InvalidateRect(_hwnd, 0, TRUE);
850 break;}
851
852 default:
853 return super::Notify(id, pnmh);
854 }
855
856 return 0;
857 }
858
859
860 OutputWorker::OutputWorker()
861 {
862 _hfont = CreateFont(-MulDiv(8,GetDeviceCaps(WindowCanvas(0),LOGPIXELSY),72), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, TEXT("MS Sans Serif"));
863 }
864
865 void OutputWorker::init_output(HWND hwnd)
866 {
867 TCHAR b[16];
868
869 WindowCanvas canvas(hwnd);
870
871 if (GetNumberFormat(LOCALE_USER_DEFAULT, 0, TEXT("1000"), 0, b, 16) > 4)
872 _num_sep = b[1];
873 else
874 _num_sep = TEXT('.');
875
876 FontSelection font(canvas, _hfont);
877 GetTextExtentPoint32(canvas, TEXT(" "), 1, &_spaceSize);
878 }
879
880
881 void OutputWorker::output_text(LPDRAWITEMSTRUCT dis, int* positions, int col, LPCTSTR str, DWORD flags)
882 {
883 int x = dis->rcItem.left;
884 RECT rt;
885
886 rt.left = x+positions[col]+_spaceSize.cx;
887 rt.top = dis->rcItem.top;
888 rt.right = x+positions[col+1]-_spaceSize.cx;
889 rt.bottom = dis->rcItem.bottom;
890
891 DrawText(dis->hDC, (LPTSTR)str, -1, &rt, DT_SINGLELINE|DT_NOPREFIX|flags);
892 }
893
894 void OutputWorker::output_tabbed_text(LPDRAWITEMSTRUCT dis, int* positions, int col, LPCTSTR str)
895 {
896 int x = dis->rcItem.left;
897 RECT rt;
898
899 rt.left = x+positions[col]+_spaceSize.cx;
900 rt.top = dis->rcItem.top;
901 rt.right = x+positions[col+1]-_spaceSize.cx;
902 rt.bottom = dis->rcItem.bottom;
903
904 /* DRAWTEXTPARAMS dtp = {sizeof(DRAWTEXTPARAMS), 2};
905 DrawTextEx(dis->hDC, (LPTSTR)str, -1, &rt, DT_SINGLELINE|DT_NOPREFIX|DT_EXPANDTABS|DT_TABSTOP, &dtp);*/
906
907 DrawText(dis->hDC, (LPTSTR)str, -1, &rt, DT_SINGLELINE|DT_EXPANDTABS|DT_TABSTOP|(2<<8));
908 }
909
910 void OutputWorker::output_number(LPDRAWITEMSTRUCT dis, int* positions, int col, LPCTSTR str)
911 {
912 int x = dis->rcItem.left;
913 RECT rt;
914 LPCTSTR s = str;
915 TCHAR b[128];
916 LPTSTR d = b;
917 int pos;
918
919 rt.left = x+positions[col]+_spaceSize.cx;
920 rt.top = dis->rcItem.top;
921 rt.right = x+positions[col+1]-_spaceSize.cx;
922 rt.bottom = dis->rcItem.bottom;
923
924 if (*s)
925 *d++ = *s++;
926
927 // insert number separator characters
928 pos = lstrlen(s) % 3;
929
930 while(*s)
931 if (pos--)
932 *d++ = *s++;
933 else {
934 *d++ = _num_sep;
935 pos = 3;
936 }
937
938 DrawText(dis->hDC, b, d-b, &rt, DT_RIGHT|DT_SINGLELINE|DT_NOPREFIX|DT_END_ELLIPSIS);
939 }
940
941
942 BOOL Pane::command(UINT cmd)
943 {
944 switch(cmd) {
945 case ID_VIEW_NAME:
946 if (_visible_cols) {
947 _visible_cols = 0;
948 calc_widths(true);
949 set_header();
950 InvalidateRect(_hwnd, 0, TRUE);
951 MenuInfo* menu_info = Frame_GetMenuInfo(GetParent(_hwnd));
952 if (menu_info) {
953 CheckMenuItem(menu_info->_hMenuView, ID_VIEW_NAME, MF_BYCOMMAND|MF_CHECKED);
954 CheckMenuItem(menu_info->_hMenuView, ID_VIEW_ALL_ATTRIBUTES, MF_BYCOMMAND);
955 CheckMenuItem(menu_info->_hMenuView, ID_VIEW_SELECTED_ATTRIBUTES, MF_BYCOMMAND);
956 }
957 }
958 break;
959
960 case ID_VIEW_ALL_ATTRIBUTES:
961 if (_visible_cols != COL_ALL) {
962 _visible_cols = COL_ALL;
963 calc_widths(true);
964 set_header();
965 InvalidateRect(_hwnd, 0, TRUE);
966 MenuInfo* menu_info = Frame_GetMenuInfo(GetParent(_hwnd));
967 if (menu_info) {
968 CheckMenuItem(menu_info->_hMenuView, ID_VIEW_NAME, MF_BYCOMMAND);
969 CheckMenuItem(menu_info->_hMenuView, ID_VIEW_ALL_ATTRIBUTES, MF_BYCOMMAND|MF_CHECKED);
970 CheckMenuItem(menu_info->_hMenuView, ID_VIEW_SELECTED_ATTRIBUTES, MF_BYCOMMAND);
971 }
972 }
973 break;
974
975 case ID_PREFERED_SIZES: {
976 calc_widths(true);
977 set_header();
978 InvalidateRect(_hwnd, 0, TRUE);
979 break;}
980
981 /*@todo more command ids... */
982
983 default:
984 return FALSE;
985 }
986
987 return TRUE;
988 }
989
990 MainFrameBase* Pane::get_frame()
991 {
992 HWND owner = GetParent(_hwnd);
993
994 return (MainFrameBase*)owner;
995 }