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