root/Mulberry/branches/users/shared/v4.1d1/Win32/Sources/Support/Toolbars/CToolbar.cp @ 316

Revision 316, 34.5 kB (checked in by svnusers, 6 months ago)

md: merged revisions 276 to 313 (inclusive) from http://svn.mulberrymail.com/mulberry/Mulberry/branches/v4.1d1

Line 
1/*
2    Copyright (c) 2007-2009 Cyrus Daboo. All rights reserved.
3   
4    Licensed under the Apache License, Version 2.0 (the "License");
5    you may not use this file except in compliance with the License.
6    You may obtain a copy of the License at
7   
8        http://www.apache.org/licenses/LICENSE-2.0
9   
10    Unless required by applicable law or agreed to in writing, software
11    distributed under the License is distributed on an "AS IS" BASIS,
12    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13    See the License for the specific language governing permissions and
14    limitations under the License.
15*/
16
17
18// Source for CToolbar class
19
20#include "CToolbar.h"
21
22#include "CBaseView.h"
23#include "CCommander.h"
24#include "CDrawUtils.h"
25#include "CFilterManager.h"
26#include "CIconMenu.h"
27#include "CIconWnd.h"
28#include "CMailboxToolbarPopup.h"
29#include "CMulberryApp.h"
30#include "CMulberryCommon.h"
31#include "CPopupButton.h"
32#include "CPreferences.h"
33#include "CSelectPopup.h"
34#include "CServerViewPopup.h"
35#include "CSMTPAccountPopup.h"
36#include "CTextButton.h"
37#include "CToolbarButton.h"
38#include "CToolbarPopupButton.h"
39#include "CToolbarView.h"
40#include "CXstringResources.h"
41
42#include "StValueChanger.h"
43
44#include <algorithm>
45
46// Static members
47
48CToolbar::CToolbarList CToolbar::sToolbars;
49
50BEGIN_MESSAGE_MAP(CToolbar, CContainerWnd)
51        ON_WM_CREATE()
52        ON_WM_SIZE()
53        ON_WM_KEYDOWN()
54        ON_WM_LBUTTONDOWN()
55        ON_WM_RBUTTONDOWN()
56        ON_WM_CONTEXTMENU()
57        ON_WM_MOUSEMOVE()
58        ON_WM_PAINT()
59END_MESSAGE_MAP()
60
61const int cToolbarWidth = 128;
62const int cToolbarHeight = 45;
63const int cBtnStart = 8;
64const int cLargeIconBtnSize = 32;
65const int cSmallIconBtnSize = 20;
66const int cCaptionXtraBtnSize = 14;
67const int cClickAndPopupXtraBtnSize = 12;
68const int cPopupXtraBtnSize = 8;
69const int cTextBtnHeight = 18;
70
71const int cDropCursorWidth = 4;
72
73const int cSpaceWidth = 16;
74const int cExpandSpaceMinWidth = 4;
75const int cSeparatorWidth = 8;
76const int cPopupWidth = 200;
77const int cPopupTitleWidth = 64;
78
79enum
80{
81        ePopup_RemoveButton = 0,
82        ePopup_MoveButton,
83        //ePopup_Separator1,
84        ePopup_AddButton,
85        //ePopup_Separator2,
86        ePopup_ResetButtons
87};
88
89// C O N S T R U C T I O N / D E S T R U C T I O N  M E T H O D S
90
91// Default constructor
92CToolbar::CToolbar()
93{
94        mIs3Pane = false;
95        mShowIt = true;
96        mSmallIcons = CPreferences::sPrefs->mToolbarSmallIcons.GetValue();
97        mShowIcons = CPreferences::sPrefs->mToolbarShowIcons.GetValue();
98        mShowCaptions = CPreferences::sPrefs->mToolbarShowCaptions.GetValue();
99        mLeftJustOffset = cBtnStart;
100        mLastCommander = NULL;
101        mDragIndex = 0xFFFFFFFF;
102       
103        sToolbars.push_back(this);
104}
105
106// Default destructor
107CToolbar::~CToolbar()
108{
109        sToolbars.erase(remove(sToolbars.begin(), sToolbars.end(), this), sToolbars.end());
110}
111
112// O T H E R  M E T H O D S ____________________________________________________________________________
113
114void CToolbar::PrefsChanged()
115{
116        // Rebuild each toolbar
117        for(CToolbarList::iterator iter = sToolbars.begin(); iter != sToolbars.end(); iter++)
118        {
119                (*iter)->ResetButtons(false);
120        }
121}
122
123bool CToolbar::RulesChanged()
124{
125        bool result = false;
126
127        // Rebuild each toolbar
128        for(CToolbarList::iterator iter = sToolbars.begin(); iter != sToolbars.end(); iter++)
129        {
130                result |= (*iter)->UpdateRulesButtons();
131        }
132       
133        return result;
134}
135
136void CToolbar::InitToolbar(bool is_3pane, CToolbarView* parent)
137{
138        mIs3Pane = is_3pane;
139       
140        DWORD dwStyle = AFX_WS_DEFAULT_VIEW;
141        dwStyle &= ~WS_BORDER;
142       
143        // Create this
144        CRect rect(0, 0, cToolbarWidth, GetBtnSize().cy + 1);
145        Create(NULL, NULL, dwStyle, rect, parent, IDC_STATIC);
146}
147
148int CToolbar::OnCreate(LPCREATESTRUCT lpCreateStruct)
149{
150        if (CContainerWnd::OnCreate(lpCreateStruct) == -1)
151                return -1;
152
153        return 0;
154}
155
156
157void CToolbar::OnPaint()
158{
159        // Fill the middle
160        CPaintDC dc(this);
161        CRect client;
162        GetClientRect(client);
163        dc.FillSolidRect(client, afxData.clrBtnFace);
164}
165
166void CToolbar::BuildToolbar()
167{
168        // Get the toolbar items
169        const CToolbarItem::CToolbarPtrItems& items = CToolbarManager::sToolbarManager.GetToolbarItems(GetType());
170       
171        // Add each one
172        UINT paneid = IDC_TOOLBAR_BTN1; // Double this for every button as click-and-popup buttons use up two message ids
173        for(CToolbarItem::CToolbarPtrItems::const_iterator iter = items.begin(); iter != items.end(); iter++, paneid += 2)
174        {
175                // Double-check we have something valid
176                if ((*iter).GetItem() == NULL)
177                {
178                        // Force entire reset
179                        ResetButtons(true);
180                        return;
181                };
182
183                // Separator is special cased as its not derived from toolbar button class
184                if ((*iter).GetItem()->GetType() == CToolbarItem::eSeparator)
185                {
186                        CRect rect1(0, 0, cSeparatorWidth, 44);
187                        CGrayBackground* sep_container = new CGrayBackground;
188                        sep_container->Create(_T(""), WS_CHILD | WS_VISIBLE, rect1, this, paneid);
189
190                        CRect rect2(cSeparatorWidth/2 - 2, 2, cSeparatorWidth/2, 40);
191                        CStatic* sep = new CStatic;
192                        sep->Create(_T(""), WS_CHILD | WS_VISIBLE | SS_ETCHEDVERT, rect2, sep_container, IDC_STATIC);
193                        sep_container->AddAlignment(new CWndAlignment(sep, CWndAlignment::eAlign_LeftHeight));
194
195                        AddItem(sep_container, *iter);
196                }
197                else if (((*iter).GetItem()->GetType() == CToolbarItem::eSpace) ||
198                                        ((*iter).GetItem()->GetType() == CToolbarItem::eExpandSpace))
199                {
200                        CRect rect(0, 0, cSpaceWidth, 44);
201                        CStatic* sep = new CStatic;
202                        sep->Create(_T(""), WS_CHILD | WS_VISIBLE, rect, this, paneid);
203                        AddItem(sep, *iter);
204                }
205                // Popup menu is special cased as its not derived from toolbar button class
206                else if ((*iter).GetItem()->GetType() == CToolbarItem::ePopupMenu)
207                {
208                        CRect rect1(0, 10, cPopupWidth, 20);
209                        CGrayBackground* popup_container = new CGrayBackground;
210                        popup_container->Create(_T(""), WS_CHILD | WS_VISIBLE, rect1, this, paneid);
211
212                        CRect rect2(0, 0, cPopupTitleWidth, 2);
213                        CStatic* title = new CStatic;
214                        CString s = cdustring(CToolbarManager::sToolbarManager.GetTitle((*iter).GetItem()->GetTitleID()));
215                        title->Create(s, WS_CHILD | WS_VISIBLE, rect2, popup_container, IDC_STATIC);
216                        title->SetFont(CMulberryApp::sAppFont);
217
218                        CRect rect3(cPopupTitleWidth, 0, cPopupWidth - cPopupTitleWidth, 20);
219                        CPopupButton* popup = new CPopupButton;
220                        popup->Create(_T(""), rect3, popup_container, paneid, IDC_STATIC, IDI_POPUPBTN);
221                        popup->SetMenu((*iter).GetItem()->GetPopupMenu());
222                        popup->SetFont(CMulberryApp::sAppFont);
223
224                        AddItem(popup, *iter);
225                }
226                // Popup menu is special cased as its not derived from toolbar button class
227                else if ((*iter).GetItem()->GetType() == CToolbarItem::eSMTPAccountPopup)
228                {
229                        const int small_offset = CMulberryApp::sLargeFont ? 4 : 0;
230                        CRect rect(0, 0, 212, 22 + small_offset);
231                        CString s = cdustring(CToolbarManager::sToolbarManager.GetTitle((*iter).GetItem()->GetTitleID()));
232                        CSMTPAccountPopup* popup = new CSMTPAccountPopup(paneid, s);
233                        popup->Create(_T(""), WS_CHILD | WS_VISIBLE, rect, this, paneid);
234                        AddItem(popup, *iter);
235                }
236
237                // Icon is special cased as its not derived from toolbar button class
238                else if ((*iter).GetItem()->GetType() == CToolbarItem::eStaticIcon)
239                {
240                        CRect rect(6, 0, 32, 32);
241                        CIconWnd* icon = new CIconWnd;
242                        icon->Create(NULL, WS_CHILD | WS_VISIBLE | SS_ICON, rect, this, paneid);
243                        icon->SetIconID((*iter).GetItem()->GetIconID());
244                        AddItem(icon, *iter);
245                }
246                else
247                {
248                        CRect rect(0, 0, 44, 44);
249
250                        CString title = cdustring(CToolbarManager::sToolbarManager.GetTitle((*iter).GetItem()->GetTitleID()));
251
252                        // Apply rules titles depend on the rule
253                        if ((*iter).GetItem()->GetTitleID() == CToolbarManager::eToolbar_ApplyRules)
254                        {
255                                // The name is actual the uid encoded as a string
256                                unsigned long uid = ::strtoul((*iter).GetExtraInfo(), NULL, 10);
257                               
258                                if (uid > 0)
259                                {
260                                        const CFilterItem* filter = CPreferences::sPrefs->GetFilterManager()->GetManualFilter(uid);
261                                        if (filter)
262                                                title = filter->GetName();
263                                }
264                                else
265                                        title = rsrc::GetString("CToolbarManager::AllRules");
266                        }
267
268                        CToolbarButton* tbtn = NULL;
269                        CToolbarPopupButton* ptbtn = NULL;
270                       
271                        switch((*iter).GetItem()->GetType())
272                        {
273                        case CToolbarItem::ePushButton:
274                        case CToolbarItem::eToggleButton:
275                                tbtn = new CToolbarButton;
276                                break;
277                        case CToolbarItem::ePopupButton:
278                        case CToolbarItem::ePopupPushButton:
279                        case CToolbarItem::ePopupToggleButton:
280                                tbtn = ptbtn = new CToolbarPopupButton;
281                                break;
282                        case CToolbarItem::eCabinetButton:
283                                tbtn = new CServerViewPopup;
284                                break;
285                        case CToolbarItem::eCopyToButton:
286                                tbtn = new CMailboxToolbarPopup;
287                                static_cast<CMailboxToolbarPopup*>(tbtn)->SetClickAndPopup(true);
288                                static_cast<CMailboxToolbarPopup*>(tbtn)->SetCopyTo(true);
289                                break;
290                        case CToolbarItem::eSelectButton:
291                                tbtn = ptbtn = new CSelectPopup;
292                                break;
293                        }
294
295                        tbtn->Create(title, rect, this, paneid, IDC_STATIC, (*iter).GetItem()->GetIconID(), 0, (*iter).GetItem()->IsToggleIcon() ? (*iter).GetItem()->GetIconID() + 1 : 0, 0);
296                        if ((ptbtn != 0) && ((*iter).GetItem()->GetPopupMenu() != 0))
297                                ptbtn->SetMenu((*iter).GetItem()->GetPopupMenu());
298
299                        // Now add to the display
300                        AddButton(tbtn, *iter);
301                }
302        }
303       
304        // We have to reset the toolbar to get the expand item width calculated properly
305        ResetLayout();
306}
307
308// Resize sub-views
309void CToolbar::OnSize(UINT nType, int cx, int cy)
310{
311        CContainerWnd::OnSize(nType, cx, cy);
312        ResetLayout();
313}
314
315unsigned long CToolbar::GetMinimumWidth() const
316{
317        // Size of left area + size of right area plus some space between them
318        return mLeftJustOffset;
319}
320
321unsigned long CToolbar::GetActualWidth() const
322{
323        // Take into account collapsed state
324        return GetMinimumWidth();
325}
326
327CSize CToolbar::GetBtnSize(const CToolbarButton* tb) const
328{
329        const int small_offset = CMulberryApp::sLargeFont ? 4 : 0;
330        const int large_offset = CMulberryApp::sLargeFont ? 12 : 0;
331
332        CSize result;
333
334        // If captions visible, horizontal size is always full size
335        if (mShowCaptions)
336                result.cx = cLargeIconBtnSize + cCaptionXtraBtnSize + large_offset;
337        else
338                result.cx = mSmallIcons ? cSmallIconBtnSize : cLargeIconBtnSize;
339       
340        // No icons => use text button height
341        if (!mShowIcons)
342                result.cy = cTextBtnHeight;
343        else
344        {
345                // Vertical size depends on icon
346                result.cy = mSmallIcons ? cSmallIconBtnSize : cLargeIconBtnSize;
347
348                // If caption visible, vertical size always contains caption extra space
349                if (mShowCaptions)
350                        result.cy += cCaptionXtraBtnSize + small_offset;
351
352        }
353
354        // Special toolbar button sizes
355        if (tb)
356        {
357                // Click-and-popup always has extra space
358                if (tb->GetClickAndPopup())
359                        result.cx += cClickAndPopupXtraBtnSize;
360                // If popup without captions or icons add extra width for popup glyph
361                else if ((!mShowCaptions || !mShowIcons) && tb->HasPopup())
362                        result.cx += cPopupXtraBtnSize;
363        }
364
365        return result;
366}
367
368// Resize after change to buttons size/captions
369void CToolbar::Reset()
370{
371        // First resize the toolbar itself
372        CRect rect;
373        GetWindowRect(rect);
374        GetParent()->ScreenToClient(rect);
375        rect.bottom = rect.top + GetBtnSize().cy + 1;
376        MoveWindow(rect);
377}
378
379// Resize after change to buttons size/captions
380void CToolbar::ResetLayout()
381{
382        CRect rect;
383        GetWindowRect(rect);
384
385        // Resize each button and accumulate total size (excluding additional expand item)
386        unsigned long total_width = 0;
387
388        // Loop over each item
389        for(CItemArray::iterator iter = mItemList.begin(); iter != mItemList.end(); iter++)
390        {
391                // Check for space
392                if ((*iter).mWnd)
393                {
394                        CRect btnrect;
395                        (*iter).mWnd->GetWindowRect(btnrect);
396
397                        switch((*iter).mDetails.GetItem()->GetType())
398                        {
399                        case CToolbarItem::eSeparator:
400                        case CToolbarItem::eSpace:
401                                // Resize height - keep width the same
402                                btnrect.bottom = btnrect.top + GetBtnSize().cy;
403                                (*iter).mWnd->MoveWindow(btnrect);
404                                break;
405                        case CToolbarItem::eExpandSpace:
406                                // Resize height and width to standards - width will be adjusted to expanded size later
407                                btnrect.right = btnrect.left + cExpandSpaceMinWidth;
408                                btnrect.bottom = btnrect.top + GetBtnSize().cy;
409                                (*iter).mWnd->MoveWindow(btnrect);
410                                break;
411                        case CToolbarItem::ePushButton:
412                        case CToolbarItem::eToggleButton:
413                        case CToolbarItem::ePopupButton:
414                        case CToolbarItem::ePopupPushButton:
415                        case CToolbarItem::ePopupToggleButton:
416                        case CToolbarItem::eCabinetButton:
417                        case CToolbarItem::eCopyToButton:
418                        case CToolbarItem::eSelectButton:
419                        // These are all toolbar buttons
420                        {
421                                // See if it is a toolbar button
422                                CToolbarButton* btn = dynamic_cast<CToolbarButton*>((*iter).mWnd);
423                                if (btn)
424                                {
425                                        // Set its size/caption visibility
426                                        btn->SetSmallIcon(mSmallIcons);
427                                        btn->SetShowIcon(mShowIcons);
428                                        btn->SetShowCaption(mShowCaptions);
429                                       
430                                        btnrect.right = btnrect.left + GetBtnSize(btn).cx;
431                                        btnrect.bottom = btnrect.top + GetBtnSize().cy;
432                                        btn->MoveWindow(btnrect);
433                                }
434                                break;
435                        }
436                        default:;
437                        }
438
439                        // Accumalate size
440                        total_width += btnrect.Width();
441                }
442        }
443
444        // Now reposition each button from the start accounting for expansion
445        mLeftJustOffset = cBtnStart;
446        long expand_by = rect.Width() - 2 * cBtnStart - total_width;
447
448        // Loop over each item
449        for(CItemArray::iterator iter = mItemList.begin(); iter != mItemList.end(); iter++)
450        {
451                // Check for space
452                if ((*iter).mWnd)
453                {
454                        // Get current item rect
455                        CRect btnrect;
456                        (*iter).mWnd->GetWindowRect(btnrect);
457
458                        switch((*iter).mDetails.GetItem()->GetType())
459                        {
460                        case CToolbarItem::eExpandSpace:
461                                // Resize width by expand amount if positive
462                                if (expand_by > 0)
463                                {
464                                        btnrect.right = btnrect.left + expand_by;
465                                        (*iter).mWnd->MoveWindow(btnrect);
466                                }
467                                break;
468                        default:;
469                        }
470
471                        // Now reposition it
472                        btnrect.OffsetRect(-btnrect.left, -btnrect.top);
473                        PositionButton(btnrect);
474                        (*iter).mWnd->MoveWindow(btnrect);
475                }
476        }
477       
478        // Tell parent to adjust itself if we are visible
479        if (IsVisible())
480                static_cast<CToolbarView*>(GetParent())->AdjustSize();
481}
482
483void CToolbar::PositionButton(CRect& btnrect)
484{
485        // Center vertically
486        CRect client;
487        GetClientRect(client);
488        int top_offset = (client.Height() - btnrect.Height()) / 2;
489
490        btnrect.OffsetRect(mLeftJustOffset, top_offset);
491        mLeftJustOffset += btnrect.Width();
492}
493
494void CToolbar::AddItem(CWnd* wnd, const CToolbarItem::CToolbarItemInfo& details)
495{
496        // Position appropriately
497        CRect btnrect;
498        wnd->GetWindowRect(btnrect);
499        btnrect.OffsetRect(-btnrect.left, -btnrect.top);
500        PositionButton(btnrect);
501        wnd->MoveWindow(btnrect);
502
503        // Add item to list
504        mItemList.push_back(SItemSpec(wnd, details));
505}
506
507void CToolbar::AddButton(CIconButton* btn, const CToolbarItem::CToolbarItemInfo& details)
508{
509        CRect btnrect;
510        btn->GetWindowRect(btnrect);
511
512        // Set up toolbar button styles
513        CToolbarButton* tbtn = dynamic_cast<CToolbarButton*>(btn);
514        if (tbtn)
515        {
516                tbtn->SetSmallIcon(mSmallIcons);
517                tbtn->SetShowIcon(mShowIcons);
518                tbtn->SetShowCaption(mShowCaptions);
519                               
520                btnrect.right = btnrect.left + GetBtnSize(tbtn).cx;
521                btnrect.bottom = btnrect.top + GetBtnSize().cy;
522        }
523
524        // Position appropriately
525        btnrect.OffsetRect(-btnrect.left, -btnrect.top);
526        PositionButton(btnrect);
527        btn->MoveWindow(btnrect);
528
529        // Add item to list
530        mItemList.push_back(SItemSpec(btn, details));
531}
532
533BOOL CToolbar::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
534{
535        // Handle button message ourselves - we map it to the button's command
536        if ((nCode == CN_COMMAND) && (nID >= IDC_TOOLBAR_BTN1) && (nID <= IDC_TOOLBAR_BTN1 + 100))
537        {
538                // Find the button for this message
539                for(CItemArray::iterator iter = mItemList.begin(); iter != mItemList.end(); iter++)
540                {
541                        if ((*iter).mWnd)
542                        {
543                                if ((*iter).mWnd->GetDlgCtrlID() == nID)
544                                {
545                                        // Adjust pExtra to extra info if present
546                                        if (!(*iter).mDetails.GetExtraInfo().empty())
547                                                pExtra = const_cast<char*>((*iter).mDetails.GetExtraInfo().c_str());
548
549                                        // Determine nature of command (ignore Alt key command - the handler will look for the key down
550                                        // Let super commander handle the command if it wants to
551                                        if (GetCommander() && GetCommander()->OnCmdMsg((*iter).mDetails.GetItem()->GetCommand(), nCode, pExtra, pHandlerInfo))
552                                                return true;
553                                }
554                                else if ((*iter).mWnd->GetDlgCtrlID() + 1 == nID)
555                                {
556                                        // Adjust ioParam to extra info if present
557                                        if (!(*iter).mDetails.GetExtraInfo().empty())
558                                                pExtra = const_cast<char*>((*iter).mDetails.GetExtraInfo().c_str());
559
560                                        // Determine nature of command (ignore Alt key command - the handler will look for the key down
561                                        // Let super commander handle the command if it wants to
562                                        if (GetCommander() && GetCommander()->OnCmdMsg((*iter).mDetails.GetItem()->GetMenuCommand(), nCode, pExtra, pHandlerInfo))
563                                                return true;
564                                }
565                        }
566                }
567        }
568
569        // Let super commander handle the unmapped command if it wants to
570        if (GetCommander() && GetCommander()->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
571                return true;
572       
573        // If the object(s) in the extended command route don't handle
574        // the command, then let the base class OnCmdMsg handle it.
575        BOOL result = CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
576        return result;
577}
578
579void CToolbar::ListenTo_Message(long msg, void* param)
580{
581        switch(msg)
582        {
583        case CBaseView::eBroadcast_ViewActivate:
584                // Broadcast activation to parent
585                Broadcast_Message(eBroadcast_ToolbarActivate, this);
586
587                // Always update state after activation - selection change may not be triggered
588                UpdateToolbarState();
589                break;
590        case CBaseView::eBroadcast_ViewDeactivate:
591                // Broadcast activation to parent
592                Broadcast_Message(eBroadcast_ToolbarDeactivate, this);
593                break;
594        case CBaseView::eBroadcast_ViewSelectionChanged:
595                // Update state
596                UpdateToolbarState();
597                break;
598        }
599}               
600
601// Set the commander to send commands to
602void CToolbar::SetCommander(CCommander* cmdr)
603{
604        // Only if valid
605        if (!cmdr)
606                return;
607
608        // See if already in the list
609        CCommanderArray::const_iterator found = std::find(mCmdrs.begin(), mCmdrs.end(), cmdr);
610        if (found == mCmdrs.end())
611        {
612                // Erase all
613                mCmdrs.clear();
614
615                mCmdrs.push_back(cmdr);
616                // Update state if it changes
617                UpdateToolbarState();
618        }
619}
620
621// Add a commander to send commands to
622void CToolbar::AddCommander(CCommander* cmdr)
623{
624        // Only if valid
625        if (!cmdr)
626                return;
627
628        // See if already in the list
629        CCommanderArray::const_iterator found = std::find(mCmdrs.begin(), mCmdrs.end(), cmdr);
630        if (found == mCmdrs.end())
631        {
632                mCmdrs.push_back(cmdr);
633                // Update state if it changes
634                UpdateToolbarState();
635        }
636}
637
638// Remove a commander to send commands to
639void CToolbar::RemoveCommander(CCommander* cmdr)
640{
641        // Only if valid
642        if (!cmdr)
643                return;
644
645        // See if already in the list
646        mCmdrs.erase(std::remove(mCmdrs.begin(), mCmdrs.end(), cmdr), mCmdrs.end());
647
648        // Update state if it changes
649        UpdateToolbarState();
650}
651
652CWnd* CToolbar::GetCommander() const
653{
654        CCommander* found = NULL;
655        for(CCommanderArray::const_iterator iter = mCmdrs.begin(); iter != mCmdrs.end(); iter++)
656        {
657                // Always use the one which is the current target
658                if ((*iter)->IsTarget())
659                {
660                        found = *iter;
661                        break;
662                }
663
664                // Cache the one on duty and return that if none are targets
665                // Also use the last one if that is found in the array
666                if ((*iter)->IsOnDuty() || (*iter == mLastCommander))
667                        found = *iter;
668        }
669       
670        mLastCommander = found;
671        return dynamic_cast<CWnd*>(found);
672}
673
674void CToolbar::UpdateControl(CWnd* ctrl, UINT cmd, bool enable, bool show)
675{
676        CCmdUI cmdui;
677        cmdui.m_pOther = ctrl;
678        cmdui.m_nID = cmd;
679       
680        // Only if commander available
681        if (GetCommander())
682                cmdui.DoUpdate(GetCommander(), true);
683       
684        // Check for visibility change tied to enable state
685        if (show)
686                ctrl->ShowWindow(ctrl->IsWindowEnabled() ? SW_SHOW : SW_HIDE);
687}
688
689void CToolbar::UpdatePopupControl(CWnd* ctrl)
690{
691        // Must be a toolbar popup button
692        CToolbarPopupButton* popup = dynamic_cast<CToolbarPopupButton*>(ctrl);
693        if (!popup)
694                return;
695       
696        // Do command UI processing for each message in the menu
697        for(UINT i = 0; i < popup->GetPopupMenu()->GetMenuItemCount(); i++)
698        {
699                UINT cmd = popup->GetPopupMenu()->GetMenuItemID(i);
700
701                if ((cmd != 0) && (cmd != 0xFFFFFFFF))
702                {
703                        CCmdUI cmdui;
704                        cmdui.m_pOther = ctrl;
705                        cmdui.m_nID = cmd;
706                        cmdui.m_nIndex = i;
707                        cmdui.m_pMenu = popup->GetPopupMenu();
708                       
709                        // Only if commander available
710                        if (GetCommander())
711                                cmdui.DoUpdate(GetCommander(), true);
712                }
713        }       
714       
715}
716
717bool CToolbar::UpdateRulesButtons()
718{
719        bool result = false;
720
721        // Update each button
722        for(CItemArray::const_iterator iter = mItemList.begin(); iter != mItemList.end(); iter++)
723        {
724                CToolbarButton* tbtn = dynamic_cast<CToolbarButton*>((*iter).mWnd);
725                if ((tbtn != NULL) && ((*iter).mDetails.GetItem()->GetTitleID() == CToolbarManager::eToolbar_ApplyRules))
726                {
727                        // Reset button title
728                        cdstring title;
729
730                        // The name is actual the uid encoded as a string
731                        unsigned long uid = ::strtoul((*iter).mDetails.GetExtraInfo(), NULL, 10);
732                       
733                        if (uid > 0)
734                        {
735                                const CFilterItem* filter = CPreferences::sPrefs->GetFilterManager()->GetManualFilter(uid);
736                                if (filter)
737                                        title = filter->GetName();
738                        }
739                        else
740                                title = rsrc::GetString("CToolbarManager::AllRules");
741                       
742                        cdstring newtitle(title);
743                        cdstring oldtitle;
744                        tbtn->GetTitle(oldtitle);
745                        if (newtitle != oldtitle)
746                        {
747                                tbtn->SetTitle(newtitle);
748                                result = true;
749                        }
750                       
751                }
752        }
753       
754        return result;
755}
756
757// Display and track context menu
758void CToolbar::OnContextMenu(CWnd* wnd, CPoint point)
759{
760        // Convert event point to a local point
761        CPoint client_point(point);
762        ScreenToClient(&client_point);
763
764        // Find the item under the mouse
765        CWnd* pane = ChildWindowFromPoint(client_point, CWP_ALL);
766        if (pane == this)
767                pane = NULL;
768       
769        // Always make sure fly-over acti vation is disabled when doing context
770        if (pane != NULL)
771                pane->SendMessage(WM_MOUSELEAVE);
772
773        // Create popup menu
774        CMenu popup;
775        popup.LoadMenu(IDR_POPUP_CONTEXT_TOOLBAR);
776        CMenu* pPopup = popup.GetSubMenu(0);
777       
778        // Fill add menu with items
779        CIconMenu* submenu = new CIconMenu;
780        submenu->CreatePopupMenu();
781        CString old_str;
782        pPopup->GetMenuString(3, old_str, MF_BYPOSITION);
783        pPopup->ModifyMenu(3, MF_STRING | MF_BYPOSITION | MF_POPUP, (UINT) submenu->m_hMenu, old_str);
784       
785        // Place holder for apply rules popup if present
786        CIconMenu* apply_rules = NULL;
787       
788        // Get the allowed toolbar items
789        const CToolbarItem::CToolbarPtrItems& items = CToolbarManager::sToolbarManager.GetAllowedToolbarItems(GetType());
790       
791        // Add each one
792        UINT pos = IDM_TOOLBAR_ADD_Start;
793        unsigned long apply_rules_index = 0;
794        for(CToolbarItem::CToolbarPtrItems::const_iterator iter = items.begin(); iter != items.end(); iter++, pos++)
795        {
796                // Insert menu item
797                cdstring temp = CToolbarManager::sToolbarManager.GetDescriptor((*iter).GetItem()->GetTitleID());
798
799                // Look for apply rules sub menu and treat differently
800                if ((*iter).GetItem()->GetTitleID() == CToolbarManager::eToolbar_ApplyRules)
801                {
802                        apply_rules_index = pos;
803
804                        if (apply_rules == NULL)
805                        {
806                                apply_rules = new CIconMenu;
807                                apply_rules->CreatePopupMenu();
808                                submenu->AppendMenu(MF_BYPOSITION | MF_POPUP | MF_OWNERDRAW, (UINT) apply_rules->m_hMenu,
809                                                                                (const TCHAR*)submenu->AddData(new CIconMenu::SIconMenuData(temp, IDI_RULESICON)));
810                        }
811                       
812                        // Add All item
813                        apply_rules->AppendMenu(MF_BYPOSITION | MF_OWNERDRAW, IDM_TOOLBAR_RULES_All, (const TCHAR*)apply_rules->AddData(new CIconMenu::SIconMenuData(rsrc::GetString("CToolbarManager::AllRules"), IDI_RULESICON)));
814                        apply_rules->AppendMenu(MF_SEPARATOR, 0, (TCHAR*) NULL);
815
816                        // Disable All item if already in the toolbar
817                        cdstring temp(0UL);
818                        if (GetButton(CToolbarManager::eToolbar_ApplyRules, temp) != NULL)
819                                apply_rules->EnableMenuItem(IDM_TOOLBAR_RULES_All, MF_BYCOMMAND | MF_GRAYED);
820                       
821                        // Now fill the menu with apply rules items
822
823                        // Get all manual filters
824                        cdstrvect items;
825                        CPreferences::sPrefs->GetFilterManager()->GetManualFilters(items);
826                       
827                        // Add each one to menu
828                        UINT rules_pos = IDM_TOOLBAR_RULES_Start;
829                        for(cdstrvect::const_iterator iter2 = items.begin(); iter2 != items.end(); iter2++, rules_pos++)
830                        {
831                               
832                                apply_rules->AppendMenu(MF_BYPOSITION | MF_OWNERDRAW, rules_pos, (const TCHAR*)apply_rules->AddData(new CIconMenu::SIconMenuData(*iter2, IDI_RULESICON)));
833                               
834                                // Get filter UID for rule
835                                const CFilterItem* filter = CPreferences::sPrefs->GetFilterManager()->GetFilter(CFilterItem::eLocal, *iter2);
836                                if (filter != NULL)
837                                {
838                                        cdstring temp(filter->GetUID());
839
840                                        // Disable ones already in the toolbar
841                                        if (GetButton(CToolbarManager::eToolbar_ApplyRules, temp) != NULL)
842                                                apply_rules->EnableMenuItem(rules_pos, MF_BYCOMMAND | MF_GRAYED);
843                                }
844                        }
845                }
846                else
847                {
848                        submenu->AppendMenu(MF_STRING | MF_BYPOSITION | MF_OWNERDRAW, pos,
849                                                                        (const TCHAR*)submenu->AddData(new CIconMenu::SIconMenuData(temp, (*iter).GetItem()->GetIconID())));
850                       
851                        // See whether item is already present (allow multiple separators and ordinary space)
852                        if (((*iter).GetItem()->GetType() != CToolbarItem::eSeparator) &&
853                                ((*iter).GetItem()->GetType() != CToolbarItem::eSpace) &&
854                                (GetItem(static_cast<CToolbarManager::EToolbarItem>((*iter).GetItem()->GetTitleID())) != NULL))
855                                submenu->EnableMenuItem(pos, MF_BYCOMMAND | MF_GRAYED);
856                }
857        }
858
859        // Remove button specific items if not over a button
860        CRect portRect;
861        bool drawing = false;
862        if (pane == NULL)
863        {
864                pPopup->DeleteMenu(0, MF_BYPOSITION);
865                pPopup->DeleteMenu(0, MF_BYPOSITION);
866                pPopup->DeleteMenu(0, MF_BYPOSITION);
867        }
868        else
869        {
870                // Adjust titles of menu items
871                const CToolbarItem* details = mItemList.at(GetItemIndex(pane)).mDetails.GetItem();
872                cdstring btnname = CToolbarManager::sToolbarManager.GetTitle(details->GetTitleID());
873                {
874                        CString old_str;
875                        pPopup->GetMenuString(IDM_TOOLBAR_REMOVE, old_str, MF_BYCOMMAND);
876                        cdstring temp(old_str);
877                        temp.Substitute(btnname);
878                        pPopup->ModifyMenu(IDM_TOOLBAR_REMOVE, MF_BYCOMMAND | MF_STRING, IDM_TOOLBAR_REMOVE, temp.win_str());
879                }
880                {
881                        CString old_str;
882                        pPopup->GetMenuString(IDM_TOOLBAR_MOVE, old_str, MF_BYCOMMAND);
883                        cdstring temp(old_str);
884                        temp.Substitute(btnname);
885                        pPopup->ModifyMenu(IDM_TOOLBAR_MOVE, MF_BYCOMMAND | MF_STRING, IDM_TOOLBAR_MOVE, temp.win_str());
886                }
887
888                // Draw insert marker
889               
890                // Is click to left or right side of current item
891                bool left = true;
892                pane->GetWindowRect(portRect);
893                left = (point.x < (portRect.left + portRect.right) / 2);
894               
895                if (left)
896                {
897                        portRect.left -= cDropCursorWidth/2;
898                        portRect.right = portRect.left + cDropCursorWidth;
899                }
900                else
901                {
902                        portRect.right += cDropCursorWidth/2;
903                        portRect.left = portRect.right - cDropCursorWidth;
904                }
905               
906                ScreenToClient(portRect);
907                CRect myPort;
908                GetClientRect(myPort);
909                portRect.top = myPort.top;
910                portRect.bottom = myPort.bottom;
911               
912                // Now draw the rect
913                CDC* pDC = GetDC();
914                StDCState save(pDC);
915
916                CPen pen;
917                pen.CreatePen(PS_SOLID | PS_INSIDEFRAME, 3, CDrawUtils::sDkGrayColor);
918
919                // Hilite outline
920                pDC->SelectObject(&pen);
921                pDC->Rectangle(portRect);
922
923                drawing = true;
924        }
925
926        // Do popup menu of suggestions
927        UINT popup_result = pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD, point.x, point.y, this);
928
929        // Remove any drawn cursor
930        if (drawing)
931        {
932                RedrawWindow(portRect);
933        }
934
935        if (popup_result != 0)
936        {
937                bool handled = false;
938                switch(popup_result)
939                {
940                case IDM_TOOLBAR_REMOVE:
941                        RemoveButton(pane);
942                        break;
943                case IDM_TOOLBAR_MOVE:
944                        MoveButton(pane);
945                        break;
946                case IDM_TOOLBAR_RESET:
947                        ResetButtons(true);
948                        break;
949                default:
950                        if ((popup_result >= IDM_TOOLBAR_ADD_Start) && (popup_result <= IDM_TOOLBAR_ADD_End))
951                        {
952                                // Get the item
953                                CToolbarManager::sToolbarManager.AddItemAt(GetType(), popup_result - IDM_TOOLBAR_ADD_Start, GetItemIndex(pane));
954
955                                // Rebuild the toolbar
956                                ResetButtons(false);
957                        }
958                        else if ((popup_result >= IDM_TOOLBAR_RULES_All) && (popup_result <= IDM_TOOLBAR_RULES_End))
959                        {
960                                // Get uid for item
961                                unsigned long uid = (popup_result == IDM_TOOLBAR_RULES_All) ? 0 : CPreferences::sPrefs->GetFilterManager()->GetManualUID(popup_result - IDM_TOOLBAR_RULES_Start);
962                                cdstring uid_txt(uid);
963
964                                // Get the item
965                                CToolbarManager::sToolbarManager.AddItemAt(GetType(), apply_rules_index - IDM_TOOLBAR_ADD_Start, GetItemIndex(pane), uid_txt);
966
967                                // Rebuild the toolbar
968                                ResetButtons(false);
969                        }
970                        break;
971                }
972
973        }
974}
975
976CToolbarButton* CToolbar::GetButton(CToolbarManager::EToolbarItem item) const
977{
978        // Find the button of this type
979        for(CItemArray::const_iterator iter = mItemList.begin(); iter != mItemList.end(); iter++)
980        {
981                CToolbarButton* tbtn = dynamic_cast<CToolbarButton*>((*iter).mWnd);
982                if ((tbtn != NULL) && static_cast<CToolbarManager::EToolbarItem>((*iter).mDetails.GetItem()->GetTitleID()) == item)
983                        return tbtn;
984        }
985       
986        return NULL;
987}
988
989CToolbarButton* CToolbar::GetButton(CToolbarManager::EToolbarItem item, const cdstring& extra) const
990{
991        // Find the button of this type with the same extra data
992        for(CItemArray::const_iterator iter = mItemList.begin(); iter != mItemList.end(); iter++)
993        {
994                CToolbarButton* tbtn = dynamic_cast<CToolbarButton*>((*iter).mWnd);
995                if ((tbtn != NULL) && (static_cast<CToolbarManager::EToolbarItem>((*iter).mDetails.GetItem()->GetTitleID()) == item) &&
996                        ((*iter).mDetails.GetExtraInfo() == extra))
997                        return tbtn;
998        }
999       
1000        return NULL;
1001}
1002
1003CWnd* CToolbar::GetItem(CToolbarManager::EToolbarItem item) const
1004{
1005        // Find the button for this message
1006        for(CItemArray::const_iterator iter = mItemList.begin(); iter != mItemList.end(); iter++)
1007        {
1008                if (((*iter).mDetails.GetItem() != NULL) && (static_cast<CToolbarManager::EToolbarItem>((*iter).mDetails.GetItem()->GetTitleID()) == item))
1009                        return (*iter).mWnd;
1010        }
1011       
1012        return NULL;
1013}
1014
1015unsigned long CToolbar::GetItemIndex(CWnd* item) const
1016{
1017        // Find index of pane in item list
1018        unsigned long index = 0;
1019        for(CItemArray::const_iterator iter = mItemList.begin(); iter != mItemList.end(); iter++, index++)
1020        {
1021                if ((*iter).mWnd == item)
1022                {
1023                        break;
1024                }
1025        }
1026       
1027        return index;
1028}
1029
1030void CToolbar::RemoveButton(CWnd* pane)
1031{
1032        // Find index of pane in item list
1033        unsigned long index = 0;
1034        for(CItemArray::iterator iter = mItemList.begin(); iter != mItemList.end(); iter++, index++)
1035        {
1036                if ((*iter).mWnd == pane)
1037                {
1038                        // Remove from toolbar manager prefs
1039                        CToolbarManager::sToolbarManager.RemoveItemAt(GetType(), index);
1040
1041                        // Delete the button object
1042                        delete (*iter).mWnd;
1043                        mItemList.erase(iter);
1044                       
1045                        // Reset the toolbar
1046                        ResetLayout();
1047                        return;
1048                }
1049        }
1050}
1051
1052void CToolbar::MoveButton(CWnd* pane)
1053{
1054        TrackStart(pane);
1055}
1056
1057void CToolbar::TrackStart(CWnd* pane)
1058{
1059        mDragIndex = GetItemIndex(pane);
1060
1061        SetCapture();
1062
1063        // Tell each control to be active
1064        for(CItemArray::const_iterator iter = mItemList.begin(); iter != mItemList.end(); iter++)
1065        {
1066                if ((*iter).mWnd != NULL)
1067                {
1068                        (*iter).mWnd->EnableWindow(true);
1069                        CToolbarButton* tbtn = dynamic_cast<CToolbarButton*>((*iter).mWnd);
1070                        if (tbtn != NULL)
1071                                tbtn->SetDragMode(true);
1072                }
1073        }
1074       
1075        TrackHighlight();
1076}
1077
1078void CToolbar::TrackStop()
1079{
1080        // Tell each control no longer dragging
1081        for(CItemArray::const_iterator iter = mItemList.begin(); iter != mItemList.end(); iter++)
1082        {
1083                if ((*iter).mWnd != NULL)
1084                {
1085                        CToolbarButton* tbtn = dynamic_cast<CToolbarButton*>((*iter).mWnd);
1086                        if (tbtn != NULL)
1087                                tbtn->SetDragMode(false);
1088                }
1089        }
1090
1091        mDragIndex = 0xFFFFFFFF;
1092
1093        // Always reset state
1094        UpdateToolbarState();
1095        RedrawWindow();
1096
1097        ReleaseCapture();
1098}
1099
1100void CToolbar::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
1101{
1102        if (mDragIndex != 0xFFFFFFFF)
1103        {
1104                TrackStop();
1105        }
1106        else
1107                CContainerWnd::OnKeyDown(nChar, nRepCnt, nFlags);
1108}
1109
1110void CToolbar::OnLButtonDown(UINT nFlags, CPoint point)
1111{
1112        if (mDragIndex != 0xFFFFFFFF)
1113        {
1114                TrackStop();
1115        }
1116        else
1117                CContainerWnd::OnLButtonDown(nFlags, point);
1118}
1119
1120// Clicked somewhere
1121void CToolbar::OnRButtonDown(UINT nFlags, CPoint point)
1122{
1123        if (mDragIndex != 0xFFFFFFFF)
1124        {
1125                TrackStop();
1126        }
1127        else
1128        {
1129                // Do context menu
1130                ClientToScreen(&point);
1131                OnContextMenu(NULL, point);     
1132        }
1133}
1134
1135void CToolbar::OnMouseMove(UINT nFlags, CPoint point)
1136{
1137        if (mDragIndex != 0xFFFFFFFF)
1138        {
1139                TrackMouseMove(point);
1140        }
1141        else
1142                CContainerWnd::OnMouseMove(nFlags, point);
1143}
1144
1145void CToolbar::TrackMouseMove(CPoint point)
1146{
1147        // Find the item under the mouse
1148        unsigned long new_index = mDragIndex;
1149        CWnd* new_pane = ChildWindowFromPoint(point, CWP_ALL);
1150        if (new_pane != NULL)
1151        {
1152                new_index = GetItemIndex(new_pane);
1153
1154                // Apply hysteresis to movement to ensure panes with different sizes do not cause
1155                // rapid switches
1156                if (new_index != mDragIndex)
1157                {
1158                        CRect old_portRect;
1159                        mItemList.at(mDragIndex).mWnd->GetWindowRect(old_portRect);
1160                        ScreenToClient(old_portRect);
1161                               
1162                        CRect new_portRect;
1163                        mItemList.at(new_index).mWnd->GetWindowRect(new_portRect);
1164                        ScreenToClient(new_portRect);
1165                       
1166                        if (new_index < mDragIndex)
1167                        {
1168                                // Only use new index if the mouse is within the old button size of the left edge of the new button
1169                                if (point.x >= new_portRect.left + (old_portRect.right - old_portRect.left))
1170                                        new_index = mDragIndex;
1171                        }
1172                        else
1173                        {
1174                                // Only use new index if the mouse is within the old button size of the right edge of the new button
1175                                if (point.x < new_portRect.right - (old_portRect.right - old_portRect.left))
1176                                        new_index = mDragIndex;
1177                        }
1178                }
1179        }
1180
1181        if (new_index != mDragIndex)
1182        {
1183                // Determine index of start/end panes
1184                CToolbarManager::sToolbarManager.MoveItemAt(GetType(), mDragIndex, new_index);
1185               
1186                SItemSpec temp = mItemList.at(mDragIndex);
1187                mItemList.erase(mItemList.begin() + mDragIndex);
1188                mItemList.insert(mItemList.begin() + new_index, temp);
1189                ResetLayout();
1190                RedrawWindow();
1191               
1192                mDragIndex = new_index;
1193        }
1194               
1195        // Draw highlight around moved button
1196        TrackHighlight();
1197}
1198
1199void CToolbar::TrackHighlight()
1200{
1201        CRect portRect;
1202        mItemList.at(mDragIndex).mWnd->GetWindowRect(portRect);
1203        ScreenToClient(portRect);
1204
1205        // Now draw the rect
1206        CDC* pDC = GetDC();
1207        StDCState save(pDC);
1208
1209        // Hilite outline
1210        for(int i = 0; i < 4; i++)
1211        {
1212                pDC->FrameRect(portRect, &CDrawUtils::sDkGrayBrush);
1213                portRect.DeflateRect(1, 1);
1214        }
1215}
1216
1217void CToolbar::ResetButtons(bool use_default)
1218{
1219        // Remove all buttons
1220        for(CItemArray::iterator iter = mItemList.begin(); iter != mItemList.end(); iter++)
1221        {
1222                // Delete the button object
1223                delete (*iter).mWnd;
1224        }
1225        mItemList.clear();
1226       
1227        // Reset to default state
1228        if (use_default)
1229                CToolbarManager::sToolbarManager.ResetToolbar(GetType());
1230       
1231        // Clear positions
1232        mLeftJustOffset = cBtnStart;
1233       
1234        // Rebuild the toolbar
1235        BuildToolbar();
1236        UpdateToolbarState();
1237        RedrawWindow();
1238}
1239
1240// Force update of state if items visible
1241void CToolbar::UpdateToolbarState()
1242{
1243        // Do actual update only if items are visible
1244        DoUpdateToolbarState();
1245}
1246
1247// Force update of state
1248void CToolbar::DoUpdateToolbarState()
1249{
1250        // Update each button
1251        for(CItemArray::const_iterator iter = mItemList.begin(); iter != mItemList.end(); iter++)
1252        {
1253                CToolbarButton* tbtn = dynamic_cast<CToolbarButton*>((*iter).mWnd);
1254                if (tbtn)
1255                        UpdateControlState(tbtn, (*iter).mDetails.GetItem()->GetCommand());
1256        }
1257}
1258
1259void CToolbar::ShowToolbar(bool show)
1260{
1261        // Only do if different
1262        if (show ^ mShowIt)
1263        {
1264                mShowIt = show;
1265                ShowWindow(show ? SW_SHOW : SW_HIDE);
1266        }
1267}
1268
1269void CToolbar::SmallIcons(bool small_icon)
1270{
1271        if (mSmallIcons ^ small_icon)
1272        {
1273                mSmallIcons = small_icon;
1274                Reset();
1275        }
1276}
1277
1278void CToolbar::ShowIcons(bool show)
1279{
1280        if (mShowIcons ^ show)
1281        {
1282                mShowIcons = show;
1283                Reset();
1284        }
1285}
1286
1287void CToolbar::ShowCaptions(bool show)
1288{
1289        if (mShowCaptions ^ show)
1290        {
1291                mShowCaptions = show;
1292                Reset();
1293        }
1294}
Note: See TracBrowser for help on using the browser.