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