update for HEAD-2003091401
[reactos.git] / subsys / system / explorer / Seashell / SeaShellExt / UIStatusBar.cpp
1 //*******************************************************************************
2 // COPYRIGHT NOTES
3 // ---------------
4 // You may use this source code, compile or redistribute it as part of your application 
5 // for free. You cannot redistribute it as a part of a software development 
6 // library without the agreement of the author. If the sources are 
7 // distributed along with the application, you should leave the original 
8 // copyright notes in the source code without any changes.
9 // This code can be used WITHOUT ANY WARRANTIES at your own risk.
10 // 
11 // For the latest updates to this code, check this site:
12 // http://www.masmex.com 
13 // after Sept 2000
14 // 
15 // Copyright(C) 2000 Philip Oldaker <email: philip@masmex.com>
16 //*******************************************************************************
17
18 #include "stdafx.h"
19 #include "UIStatusBar.h"
20
21 #ifdef _DEBUG
22 #define new DEBUG_NEW
23 #undef THIS_FILE
24 static char THIS_FILE[] = __FILE__;
25 #endif
26
27 ///////////////////////////////////
28 //
29 // IMStatusBar
30 //
31 ///////////////////////////////////
32 IMPLEMENT_SERIAL(CUIStatusBar, CStatusBar, 0)
33 IMPLEMENT_SERIAL(CStatusBarPane, CObject, 0)
34
35 BEGIN_MESSAGE_MAP(CUIStatusBar, CStatusBar)
36         //{{AFX_MSG_MAP(CUIStatusBar)
37         ON_WM_CONTEXTMENU()
38         ON_WM_LBUTTONDOWN()
39         ON_WM_SETCURSOR()
40         //}}AFX_MSG_MAP
41 END_MESSAGE_MAP()
42
43 LPCTSTR CUIStatusBar::szSection = _T("Settings\\StatusBar");
44 LPCTSTR CUIStatusBar::szPaneEntry = _T("Pane");
45
46 CStatusBarPane::CStatusBarPane(const CStatusBarPane &rOther)
47 {
48         DoCopy(rOther);
49 }
50
51 CStatusBarPane &CStatusBarPane::operator=(const CStatusBarPane &rOther)
52 {
53         if (this == &rOther)
54                 return *this;
55         DoCopy(rOther);
56         return *this;
57 }
58
59 void CStatusBarPane::DoCopy(const CStatusBarPane &rOther)
60 {
61         m_nID = rOther.m_nID;
62         m_nStyle = rOther.m_nStyle;
63         m_bActive = rOther.m_bActive;
64 //      m_listImageIndex = rOther.m_listImageIndex;
65 }
66
67 void CStatusBarPane::Serialize(CArchive &ar)
68 {
69         if (ar.IsStoring())
70         {
71                 ar << m_nID;
72                 ar << m_nStyle;
73                 ar << m_bActive;
74         }
75         else
76         {
77                 ar >> m_nID;
78                 ar >> m_nStyle;
79                 ar >> m_bActive;
80         }
81 }
82
83 void CUIStatusBar::OnContextMenu(CWnd *pWnd, CPoint point)
84 {
85 /*      CMenu Menu;
86
87         // Build the popup menu
88         Menu.CreatePopupMenu();
89         CStatusBarPane *pPane = NULL;
90         CString strText;
91         for(POSITION pos = m_PaneList.GetTailPosition();pos != NULL;) 
92         {
93                 pPane = m_PaneList.GetPrev(pos);
94                 if (pPane->GetCommandID() != ID_SEPARATOR && pPane->GetCommandID() != ID_INDICATOR_MAIN) 
95                 {
96                         strText.LoadString(pPane->GetCommandID());
97                         Menu.AppendMenu(MF_STRING,pPane->GetCommandID(),strText);
98                 }
99         }
100         // and display using main frame as message window
101         Menu.TrackPopupMenu(TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_LEFTALIGN,point.x,point.y,theApp.m_pMainWnd);
102         theApp.m_pMainWnd->SetFocus();
103 */
104 }
105 ////////////////////////////////////////////////////////////
106
107 CUIStatusBar::CUIStatusBar()
108 {
109         Init();
110 }
111
112 CUIStatusBar::~CUIStatusBar()
113 {
114         Clear();
115 }
116
117 void CUIStatusBar::Reset()
118 {
119         Clear();
120         Init();
121 }
122
123 void CUIStatusBar::Init()
124 {
125         m_nStatusPane1Width = -1;
126         m_nStatusPane1Style = SBPS_STRETCH;
127         m_bMenuSelect = FALSE;
128         m_nMinHeight = GetSystemMetrics(SM_CYSMICON)+4;
129         m_pImageList = new CImageList;
130 }
131
132 void CUIStatusBar::Clear()
133 {
134         CStatusBarPane *pPane;  
135         while (!m_PaneList.IsEmpty()) 
136         {
137                         pPane = m_PaneList.RemoveTail();
138                         delete pPane;
139         }
140         delete m_pImageList;
141         m_pImageList = NULL;
142 }
143
144 CUIStatusBar &CUIStatusBar::operator=(const CUIStatusBar &rOther)
145 {
146         if (this == &rOther)
147                 return *this;
148         for(POSITION pos=rOther.m_PaneList.GetHeadPosition();pos != NULL;) 
149         {
150                 CStatusBarPane *pPane = new CStatusBarPane;
151                 *pPane = *rOther.m_PaneList.GetNext(pos);
152                 m_PaneList.AddTail(pPane);
153         }
154         m_nStatusPane1ID = rOther.m_nStatusPane1ID;
155         m_nStatusPane1Style = rOther.m_nStatusPane1Style;
156         m_nStatusPane1Width = rOther.m_nStatusPane1Width;
157         m_bMenuSelect = rOther.m_bMenuSelect;
158         return *this;
159 }
160
161 void CUIStatusBar::UpdatePane(int nIndex)
162 {
163         CRect rect;
164         GetStatusBarCtrl().GetRect(nIndex,&rect);
165         InvalidateRect(rect);
166         UpdateWindow();
167 }
168
169 CStatusBarPane *CUIStatusBar::GetPane(UINT nPaneID) const
170 {
171         if (nPaneID == 0)
172         {
173                 nPaneID = ((CUIStatusBar*)this)->GetPaneID(0);
174         }
175         CStatusBarPane *pPane = NULL;
176         for (POSITION pos=m_PaneList.GetHeadPosition();pos != NULL;) 
177         {
178                 pPane = m_PaneList.GetNext(pos);
179                 if (pPane->GetCommandID() == nPaneID)
180                         break;
181         }
182         return((pPane && nPaneID == pPane->GetCommandID()) ? pPane : NULL);
183 }
184
185 void CUIStatusBar::RemoveAllIcons(UINT nPaneID)
186 {
187         CStatusBarPane *pPane = GetPane(nPaneID);
188         ASSERT(pPane);
189         pPane->RemoveAllImages();
190         UpdatePane(GetPaneIndex(nPaneID));
191 }
192
193 void CUIStatusBar::RemoveIcon(UINT nPaneID,UINT nImageID,bool bUpdate)
194 {       
195         if (nPaneID == 0)
196         {
197                 nPaneID = GetPaneID(0);
198         }
199         CStatusBarPane *pPane = GetPane(nPaneID);
200         ASSERT(pPane);
201         RemoveIcon(nImageID,pPane,bUpdate);
202 }
203
204 void CUIStatusBar::RemoveIcon(UINT nImageID,CStatusBarPane *pPane,bool bUpdate)
205 {       
206         int nImageIndex=-1;
207         if (m_mapImageIndex.Lookup(nImageID,nImageIndex))
208                 pPane->RemoveImage(nImageIndex);
209         if (bUpdate)
210                 UpdatePane(nImageIndex);
211 }
212
213 void CUIStatusBar::AddIcon(UINT nPaneID,UINT nImageID,bool bUpdate)
214 {
215         int nIndex = -1;
216         if (!m_mapImageIndex.Lookup(nImageID,nIndex))
217                 nIndex = AddIcon(nImageID);
218         // Possibly wrong id using pane index 0
219         if (nPaneID == 0)
220         {
221                 nPaneID = GetPaneID(0);
222         }
223         AddImageIndex(nPaneID,nIndex,bUpdate);
224 }
225
226 // add an image to list of images that will be displayed
227 // nIndex into the image list
228 void CUIStatusBar::AddImageIndex(UINT nPaneID,int nImageIndex,bool bUpdate)
229 {
230         CStatusBarPane *pPane = GetPane(nPaneID);
231         ASSERT(pPane);
232         int nPaneIndex = GetPaneIndex(nPaneID);
233         // Pane 0 can have only one icon
234         if (nPaneIndex == 0)
235         {
236                 pPane->RemoveAllImages();
237         }
238         if (!pPane->FindImage(nImageIndex))
239         {
240                 pPane->AddImage(nImageIndex);
241         }
242         UINT nStyle;
243         int nWidth;
244         GetPaneInfo(nPaneIndex,nPaneID,nStyle,nWidth);
245         // Make sure it's owner draw
246         if (!(nStyle & SBT_OWNERDRAW))
247         {
248                 nStyle |= SBT_OWNERDRAW;
249                 SetPaneInfo(nPaneIndex,nPaneID,nStyle,nWidth);
250                 pPane->SetStyle(nStyle);
251         }
252         if (bUpdate)
253                 UpdatePane(GetPaneIndex(nPaneID));
254 }
255
256 int CUIStatusBar::AddIcon(UINT nID)
257 {
258         if (m_pImageList->m_hImageList == NULL)
259                 CreateImageList();
260         ASSERT(m_pImageList->m_hImageList);
261         HICON hIcon = (HICON)::LoadImage(AfxGetInstanceHandle(),MAKEINTRESOURCE(nID),IMAGE_ICON,16,16,LR_DEFAULTCOLOR);
262         if (hIcon)
263         {
264                 int nIndex = m_pImageList->Add(hIcon);
265                 m_mapImageIndex[nID] = nIndex;
266                 return nIndex;
267         }
268         return -1;
269 }
270
271 // set image list from a bitmap id
272 void CUIStatusBar::SetImageList(UINT nBitmapID)
273 {
274         delete m_pImageList;
275         m_pImageList = NULL;
276         m_pImageList = new CImageList;
277         m_pImageList->Create(nBitmapID,::GetSystemMetrics(SM_CXSMICON),0,::GetSysColor(COLOR_BTNFACE));
278 }
279
280 void CUIStatusBar::CreateImageList()
281 {
282         delete m_pImageList;
283         m_pImageList = new CImageList;
284         m_pImageList->Create(::GetSystemMetrics(SM_CXSMICON),::GetSystemMetrics(SM_CYSMICON),ILC_MASK | ILC_COLOR16,0,1);
285         m_pImageList->SetBkColor(CLR_NONE);
286 }
287
288 void CUIStatusBar::SetImageList(CImageList *pImageList)
289 {
290         CreateImageList();
291         // if one passed in copy it
292         if (pImageList)
293         {
294                 int count = pImageList->GetImageCount();
295                 for(int i=0;i < count;i++)
296                 {
297                         HICON hIcon = pImageList->ExtractIcon(i);
298                         m_pImageList->Add(hIcon);
299                 }
300         }
301 }
302
303 void CUIStatusBar::AddPane(UINT nID,BOOL bActive)
304 {
305         CStatusBarPane *pPane = new CStatusBarPane(nID,bActive);
306         pPane->SetStyle(SBT_OWNERDRAW);
307         m_PaneList.AddTail(pPane);
308 }
309
310 BOOL CUIStatusBar::SetPanes(BOOL bSave)
311 {
312         int nSize = 0;
313         CStatusBarPane *pPane = NULL;
314         for(POSITION pos = m_PaneList.GetTailPosition();pos != NULL;) 
315         {
316                 pPane = m_PaneList.GetPrev(pos);
317                 nSize += pPane->IsPaneActive();
318         }
319         UINT *pIndicators = new UINT[nSize];
320
321         int nIndex = 0;
322         for(pos = m_PaneList.GetHeadPosition();pos != NULL;) 
323         {
324                 pPane = m_PaneList.GetNext(pos);
325                 if (pPane->IsPaneActive()) 
326                 {
327                         pIndicators[nIndex++] = pPane->GetCommandID();
328                 }
329         }
330         BOOL ret = SetIndicators(pIndicators, nSize);
331         delete[] pIndicators;
332
333         UINT nID, nStyle;
334         int nWidth;
335         for(pos = m_PaneList.GetTailPosition();pos != NULL;) 
336         {
337                 pPane = m_PaneList.GetPrev(pos);
338                 if (pPane->IsPaneActive() && pPane->GetCommandID() != ID_SEPARATOR) 
339                 {
340                         int nIndex = GetPaneIndex(pPane->GetCommandID());
341                         GetPaneInfo(nIndex,nID,nStyle,nWidth);
342                         SetPaneInfo(nIndex,pPane->GetCommandID(),nStyle | pPane->GetStyle(),nWidth);
343                         SetPaneText(nIndex,_T(""));
344                 }
345         }
346         GetPaneInfo(0,nID,nStyle,nWidth);
347         // First pane has its own style
348         SetPaneInfo(0,nID,m_nStatusPane1Style,nWidth);
349         if (bSave) 
350         {
351                 // save to registry
352                 Save();
353         }
354         return ret;
355 }
356
357 void CUIStatusBar::Load()
358 {
359         CWinApp *pApp = AfxGetApp();
360         CString strPane;
361         CStatusBarPane *pPane = NULL;
362         int i=0;
363         for(POSITION pos = m_PaneList.GetTailPosition();pos != NULL;i++) 
364         {
365                 pPane = m_PaneList.GetPrev(pos);
366                 strPane.Format(_T("%s%d"),szPaneEntry,i);
367                 pPane->SetPaneActive(pApp->GetProfileInt(szSection,strPane,pPane->IsPaneActive()));      
368         }
369 }
370
371 void CUIStatusBar::Save()
372 {
373         CWinApp *pApp = AfxGetApp();
374         CString strPane;
375         CStatusBarPane *pPane = NULL;
376         int i=0;
377         for(POSITION pos = m_PaneList.GetTailPosition();pos != NULL;i++) 
378         {
379                 pPane = m_PaneList.GetPrev(pos);
380                 strPane.Format(_T("%s%d"),szPaneEntry,i);
381                 pApp->WriteProfileInt(szSection,strPane,pPane->IsPaneActive());
382         }
383 }
384
385 void CUIStatusBar::TogglePane(UINT nID)
386 {
387         CStatusBarPane *pPane = GetPane(nID);
388         if (pPane) 
389         {
390                 pPane->SetPaneActive(!pPane->IsPaneActive());
391                 SetPanes(TRUE);
392         }
393 }
394
395 void CUIStatusBar::SetText(UINT nPaneID,LPCTSTR szText,bool bUpdate)
396 {
397         const CStatusBarPane *pPane = GetPane(nPaneID);
398         ASSERT(pPane);
399         SetTextPane(pPane,szText,bUpdate);
400 }
401
402 void CUIStatusBar::SetTextPane(const CStatusBarPane *pPane,LPCTSTR szText,bool bUpdate)
403 {
404         if (!pPane->IsPaneActive())
405                 return;
406
407         int nIndex = GetPaneIndex(pPane->GetCommandID());
408         UINT nStyle;
409         UINT nPaneID=pPane->GetCommandID();
410         int nWidth;
411         GetPaneInfo(nIndex, nPaneID, nStyle, nWidth);
412         nStyle |= SBT_OWNERDRAW;
413         if (nIndex != 0)
414         {
415                 HGDIOBJ hOldFont = NULL;
416                 HFONT hFont = (HFONT)SendMessage(WM_GETFONT);
417                 CClientDC dc(NULL);
418                 if (hFont != NULL) 
419                         hOldFont = dc.SelectObject(hFont);
420                 CSize size = dc.GetTextExtent(szText);
421                 if (hOldFont != NULL) 
422                         dc.SelectObject(hOldFont);
423                 nWidth = size.cx;
424         }
425         SetPaneInfo(nIndex, nPaneID, nStyle, nWidth);
426         SetPaneText(nIndex, szText, bUpdate);
427         if (bUpdate)
428                 UpdateWindow();
429 }
430
431 void CUIStatusBar::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
432 {
433         CStatusBarPane *pPane = GetPane(GetPaneID(lpDrawItemStruct->itemID));
434         if (pPane) 
435         {
436                 // Get the pane rectangle and calculate text coordinates
437                 CRect rect(&lpDrawItemStruct->rcItem);
438                 CDC *pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
439                 COLORREF oldBkColor = pDC->SetBkColor(::GetSysColor(COLOR_BTNFACE));
440                 // draw the image
441                 CListImages &listImages = pPane->GetImageIndex();
442                 // make sure there is an image
443                 if (!listImages.IsEmpty()) 
444                 {
445                         for(POSITION pos=listImages.GetTailPosition();pos != NULL;)
446                         {
447                                 m_pImageList->Draw(pDC,listImages.GetPrev(pos),CPoint(rect.left,rect.top),ILD_NORMAL);
448                                 rect.left += ::GetSystemMetrics(SM_CXSMICON);
449                                 rect.left += 5;
450                         }
451                 }
452                 // draw the text
453                 LPCTSTR pszText = (LPCTSTR)lpDrawItemStruct->itemData;
454                 // make sure there is text
455                 if (pszText)
456                 {
457                         UINT nFormat = DT_LEFT | DT_SINGLELINE | DT_EXPANDTABS | DT_NOPREFIX | DT_VCENTER;
458 //                      if (pPane->GetStyle() & SBPS_POPOUT)
459 //                              nFormat |= DT_VCENTER;
460 //                      else
461 //                              nFormat |= DT_BOTTOM;
462                         pDC->DrawText(pszText,lstrlen(pszText),rect,nFormat);
463                 }
464                 pDC->SetBkColor(oldBkColor);
465         }
466 }
467
468 void CUIStatusBar::Serialize(CArchive &ar)
469 {
470         CStatusBar::Serialize(ar);
471         m_PaneList.Serialize(ar);
472 }
473
474 template <> void AFXAPI SerializeElements <CStatusBarPane*> (CArchive& ar, CStatusBarPane **ppPane, int nCount)
475 {
476     for (int i=0;i < nCount;i++,ppPane++)
477     {
478                 if (ar.IsLoading())
479                 {
480                         ar >> *ppPane;
481                 }
482                 else
483                 {
484                         ar << *ppPane;
485                 }
486     }
487 }
488
489
490 void CUIStatusBar::OnLButtonDown(UINT nFlags, CPoint point) 
491 {
492         // TODO: Add your message handler code here and/or call default
493         CStatusBar::OnLButtonDown(nFlags, point);
494 }
495
496 BOOL CUIStatusBar::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) 
497 {
498         // TODO: Add your message handler code here and/or call default
499 /*      if (theApp.IsLoading())
500         {
501                 CPoint point;
502                 ::GetCursorPos(&point);
503                 ScreenToClient(&point);
504                 CRect rect;
505                 GetItemRect(4,&rect);
506                 if (rect.PtInRect(point))
507                 {
508                         SetCursor(::LoadCursor(NULL,IDC_CROSS));
509                         return TRUE;
510                 }
511         }
512 */      
513         return CStatusBar::OnSetCursor(pWnd, nHitTest, message);
514 }
515
516 ////////////////////////////////////////////////////////////////////////
517 IMPLEMENT_DYNCREATE(CProgressBar, CProgressCtrl)
518         
519 BEGIN_MESSAGE_MAP(CProgressBar, CProgressCtrl)
520         //{{AFX_MSG_MAP(CProgressBar)
521         ON_WM_ERASEBKGND()
522         //}}AFX_MSG_MAP
523 END_MESSAGE_MAP()
524
525 CProgressBar::CProgressBar() : m_nPaneIndex(-1), m_pStatusBar(NULL)
526 {
527 }
528
529 CProgressBar::CProgressBar(int nPaneID, CUIStatusBar *pStatusBar, int MaxValue /* = 100 */)
530 {
531         Create(nPaneID, pStatusBar, MaxValue);
532 }
533
534 CProgressBar::~CProgressBar()
535 {
536         Clear();
537 }       
538
539 // Create the CProgressCtrl as a child of the status bar 
540 BOOL CProgressBar::Create(int nPaneID, CUIStatusBar *pStatusBar, int MaxValue)
541 {       
542         m_pStatusBar = pStatusBar;
543         m_nPaneIndex = pStatusBar->GetPaneIndex(nPaneID);
544         if (m_nPaneIndex == -1)
545                 return FALSE;
546
547         // Create the progress bar
548         if (!CProgressCtrl::Create(WS_CHILD | WS_VISIBLE | PBS_SMOOTH, CRect(0,0,0,0), pStatusBar, 1))
549                 return FALSE;
550
551         // Set range and step
552         SetRange(0, MaxValue);
553         SetStep(1);
554
555         // Resize the control to its desired width
556         Resize();
557
558         return TRUE;
559 }
560
561 void CProgressBar::Clear()
562 {
563 }
564
565 void CProgressBar::SetRange(int nLower, int nUpper, int nStep /* = 1 */)        
566 {
567         CProgressCtrl::SetRange(nLower, nUpper);
568         CProgressCtrl::SetStep(nStep);
569 }
570
571 int CProgressBar::SetPos(int nPos)       
572 {
573         if (m_hWnd == NULL)
574                 return -1;
575         ModifyStyle(0,WS_VISIBLE);
576         return CProgressCtrl::SetPos(nPos);
577 }
578
579 int  CProgressBar::OffsetPos(int nPos) 
580
581         if (m_hWnd == NULL)
582                 return -1;
583         ModifyStyle(0,WS_VISIBLE);
584         return CProgressCtrl::OffsetPos(nPos);
585 }
586
587 int  CProgressBar::SetStep(int nStep)
588
589         if (m_hWnd == NULL)
590                 return -1;
591         ModifyStyle(0,WS_VISIBLE);
592         return CProgressCtrl::SetStep(nStep);   
593 }
594
595 int  CProgressBar::StepIt()                      
596
597         if (m_hWnd == NULL)
598                 return -1;
599         ModifyStyle(0,WS_VISIBLE);
600         return CProgressCtrl::StepIt(); 
601 }
602
603 void CProgressBar::Resize() 
604 {       
605         ASSERT(m_pStatusBar);
606         ASSERT(m_nPaneIndex != -1);
607
608         if (!m_pStatusBar) 
609                 return;
610
611         // Now get the rectangle in which we will draw the progress bar
612         CRect rc;
613         m_pStatusBar->GetItemRect (m_nPaneIndex, rc);   
614         // Resize the window
615         if (::IsWindow(m_hWnd))
616             MoveWindow(&rc);
617 }
618
619 BOOL CProgressBar::OnEraseBkgnd(CDC* pDC) 
620 {
621         Resize();
622         return CProgressCtrl::OnEraseBkgnd(pDC);
623 }