1 /* 2 * Copyright 2003, 2004, 2005 Martin Fuchs 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 */ 18 19 20 // 21 // Explorer clone 22 // 23 // quicklaunch.cpp 24 // 25 // Martin Fuchs, 22.08.2003 26 // 27 28 29 #include <precomp.h> 30 31 #include "quicklaunch.h" 32 33 34 QuickLaunchEntry::QuickLaunchEntry() 35 { 36 _hbmp = 0; 37 } 38 39 QuickLaunchMap::~QuickLaunchMap() 40 { 41 while(!empty()) { 42 iterator it = begin(); 43 DeleteBitmap(it->second._hbmp); 44 erase(it); 45 } 46 } 47 48 49 QuickLaunchBar::QuickLaunchBar(HWND hwnd) 50 : super(hwnd) 51 { 52 CONTEXT("QuickLaunchBar::QuickLaunchBar()"); 53 54 _dir = NULL; 55 _next_id = IDC_FIRST_QUICK_ID; 56 _btn_dist = 20; 57 _size = 0; 58 59 HWND hwndToolTip = (HWND) SendMessage(hwnd, TB_GETTOOLTIPS, 0, 0); 60 61 SetWindowStyle(hwndToolTip, GetWindowStyle(hwndToolTip)|TTS_ALWAYSTIP); 62 63 // delay refresh to some time later 64 PostMessage(hwnd, PM_REFRESH, 0, 0); 65 } 66 67 QuickLaunchBar::~QuickLaunchBar() 68 { 69 delete _dir; 70 } 71 72 HWND QuickLaunchBar::Create(HWND hwndParent) 73 { 74 CONTEXT("QuickLaunchBar::Create()"); 75 76 ClientRect clnt(hwndParent); 77 78 HWND hwnd = CreateToolbarEx(hwndParent, 79 WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS|WS_CLIPCHILDREN| 80 CCS_TOP|CCS_NODIVIDER|CCS_NOPARENTALIGN|CCS_NORESIZE| 81 TBSTYLE_TOOLTIPS|TBSTYLE_WRAPABLE|TBSTYLE_FLAT, 82 IDW_QUICKLAUNCHBAR, 0, 0, 0, NULL, 0, 0, 0, 16, 16, sizeof(TBBUTTON)); 83 84 if (hwnd) 85 new QuickLaunchBar(hwnd); 86 87 return hwnd; 88 } 89 90 void QuickLaunchBar::AddShortcuts() 91 { 92 CONTEXT("QuickLaunchBar::AddShortcuts()"); 93 94 WaitCursor wait; 95 96 try { 97 TCHAR path[MAX_PATH]; 98 99 SpecialFolderFSPath app_data(CSIDL_APPDATA, _hwnd); ///@todo perhaps also look into CSIDL_COMMON_APPDATA ? 100 101 _stprintf(path, TEXT("%s\\")QUICKLAUNCH_FOLDER, (LPCTSTR)app_data); 102 103 RecursiveCreateDirectory(path); 104 _dir = new ShellDirectory(GetDesktopFolder(), path, _hwnd); 105 106 _dir->smart_scan(SORT_NAME); 107 108 // immediatelly extract the shortcut icons 109 for(Entry*entry=_dir->_down; entry; entry=entry->_next) 110 entry->_icon_id = entry->safe_extract_icon(ICF_NORMAL); 111 } catch(COMException&) { 112 return; 113 } 114 115 116 ShellFolder desktop_folder; 117 WindowCanvas canvas(_hwnd); 118 119 COLORREF bk_color = GetSysColor(COLOR_BTNFACE); 120 HBRUSH bk_brush = GetSysColorBrush(COLOR_BTNFACE); 121 122 AddButton(ID_MINIMIZE_ALL, g_Globals._icon_cache.get_icon(ICID_MINIMIZE).create_bitmap(bk_color, bk_brush, canvas), ResString(IDS_MINIMIZE_ALL), NULL); 123 AddButton(ID_EXPLORE, g_Globals._icon_cache.get_icon(ICID_EXPLORER).create_bitmap(bk_color, bk_brush, canvas), ResString(IDS_TITLE), NULL); 124 125 TBBUTTON sep = {0, -1, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0}; 126 SendMessage(_hwnd, TB_INSERTBUTTON, INT_MAX, (LPARAM)&sep); 127 128 int cur_desktop = g_Globals._desktops._current_desktop; 129 ResString desktop_fmt(IDS_DESKTOP_NUM); 130 131 HDC hdc = CreateCompatibleDC(canvas); 132 DWORD size = SendMessage(_hwnd, TB_GETBUTTONSIZE, 0, 0); 133 int cx = LOWORD(size); 134 int cy = HIWORD(size); 135 RECT rect = {0, 0, cx, cy}; 136 RECT textRect = {0, 0, cx-7, cy-7}; 137 138 for(int i=0; i<DESKTOP_COUNT; ++i) { 139 HBITMAP hbmp = CreateCompatibleBitmap(canvas, cx, cy); 140 HBITMAP hbmp_old = SelectBitmap(hdc, hbmp); 141 142 FontSelection font(hdc, GetStockFont(ANSI_VAR_FONT)); 143 FmtString num_txt(TEXT("%d"), i+1); 144 TextColor color(hdc, RGB(64,64,64)); 145 BkMode mode(hdc, TRANSPARENT); 146 FillRect(hdc, &rect, GetSysColorBrush(COLOR_BTNFACE)); 147 DrawText(hdc, num_txt, num_txt.length(), &textRect, DT_CENTER|DT_VCENTER|DT_SINGLELINE); 148 149 SelectBitmap(hdc, hbmp_old); 150 151 AddButton(ID_SWITCH_DESKTOP_1+i, hbmp, FmtString(desktop_fmt, i+1), NULL, cur_desktop==i?TBSTATE_ENABLED|TBSTATE_PRESSED:TBSTATE_ENABLED); 152 } 153 DeleteDC(hdc); 154 155 for(Entry*entry=_dir->_down; entry; entry=entry->_next) { 156 // hide files like "desktop.ini" 157 if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) 158 continue; 159 160 // hide subfolders 161 if (!(entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { 162 HBITMAP hbmp = g_Globals._icon_cache.get_icon(entry->_icon_id).create_bitmap(bk_color, bk_brush, canvas); 163 164 AddButton(_next_id++, hbmp, entry->_display_name, entry); //entry->_etype==ET_SHELL? desktop_folder.get_name(static_cast<ShellEntry*>(entry)->_pidl): entry->_display_name); 165 } 166 } 167 168 _btn_dist = LOWORD(SendMessage(_hwnd, TB_GETBUTTONSIZE, 0, 0)); 169 _size = _entries.size() * _btn_dist; 170 171 SendMessage(GetParent(_hwnd), PM_RESIZE_CHILDREN, 0, 0); 172 } 173 174 void QuickLaunchBar::AddButton(int id, HBITMAP hbmp, LPCTSTR name, Entry* entry, int flags) 175 { 176 TBADDBITMAP ab = {0, (UINT_PTR)hbmp}; 177 int bmp_idx = SendMessage(_hwnd, TB_ADDBITMAP, 1, (LPARAM)&ab); 178 179 QuickLaunchEntry qle; 180 181 qle._hbmp = hbmp; 182 qle._title = name; 183 qle._entry = entry; 184 185 _entries[id] = qle; 186 187 TBBUTTON btn = {0, 0, (BYTE)flags, BTNS_BUTTON|BTNS_NOPREFIX, {0, 0}, 0, 0}; 188 189 btn.idCommand = id; 190 btn.iBitmap = bmp_idx; 191 192 SendMessage(_hwnd, TB_INSERTBUTTON, INT_MAX, (LPARAM)&btn); 193 } 194 195 void QuickLaunchBar::UpdateDesktopButtons(int desktop_idx) 196 { 197 for(int i=0; i<DESKTOP_COUNT; ++i) { 198 TBBUTTONINFO tbi = {sizeof(TBBUTTONINFO), TBIF_STATE, 0, 0, (BYTE)(desktop_idx==i? TBSTATE_ENABLED|TBSTATE_PRESSED: TBSTATE_ENABLED)}; 199 200 SendMessage(_hwnd, TB_SETBUTTONINFO, ID_SWITCH_DESKTOP_1+i, (LPARAM)&tbi); 201 } 202 } 203 204 LRESULT QuickLaunchBar::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam) 205 { 206 switch(nmsg) { 207 case PM_REFRESH: 208 AddShortcuts(); 209 break; 210 211 case PM_GET_WIDTH: { 212 // take line wrapping into account 213 int btns = SendMessage(_hwnd, TB_BUTTONCOUNT, 0, 0); 214 int rows = SendMessage(_hwnd, TB_GETROWS, 0, 0); 215 216 if (rows<2 || rows==btns) 217 return _size; 218 219 RECT rect; 220 int max_cx = 0; 221 222 for(QuickLaunchMap::const_iterator it=_entries.begin(); it!=_entries.end(); ++it) { 223 SendMessage(_hwnd, TB_GETRECT, it->first, (LPARAM)&rect); 224 225 if (rect.right > max_cx) 226 max_cx = rect.right; 227 } 228 229 return max_cx;} 230 231 case PM_UPDATE_DESKTOP: 232 UpdateDesktopButtons(wparam); 233 break; 234 235 case WM_CONTEXTMENU: { 236 TBBUTTON btn; 237 QuickLaunchMap::iterator it; 238 Point screen_pt(lparam), clnt_pt=screen_pt; 239 ScreenToClient(_hwnd, &clnt_pt); 240 241 Entry* entry = NULL; 242 int idx = SendMessage(_hwnd, TB_HITTEST, 0, (LPARAM)&clnt_pt); 243 244 if (idx>=0 && 245 SendMessage(_hwnd, TB_GETBUTTON, idx, (LPARAM)&btn)!=-1 && 246 (it=_entries.find(btn.idCommand))!=_entries.end()) { 247 entry = it->second._entry; 248 } 249 250 if (entry) { // entry is NULL for desktop switch buttons 251 HRESULT hr = entry->do_context_menu(_hwnd, screen_pt, _cm_ifs); 252 253 if (!SUCCEEDED(hr)) 254 CHECKERROR(hr); 255 } else 256 goto def; 257 break;} 258 259 default: def: 260 return super::WndProc(nmsg, wparam, lparam); 261 } 262 263 return 0; 264 } 265 266 int QuickLaunchBar::Command(int id, int code) 267 { 268 CONTEXT("QuickLaunchBar::Command()"); 269 270 if ((id&~0xFF) == IDC_FIRST_QUICK_ID) { 271 QuickLaunchEntry& qle = _entries[id]; 272 273 if (qle._entry) { 274 qle._entry->launch_entry(_hwnd); 275 return 0; 276 } 277 } 278 279 return 0; // Don't return 1 to avoid recursion with DesktopBar::Command() 280 } 281 282 int QuickLaunchBar::Notify(int id, NMHDR* pnmh) 283 { 284 switch(pnmh->code) { 285 case TTN_GETDISPINFO: { 286 NMTTDISPINFO* ttdi = (NMTTDISPINFO*) pnmh; 287 288 int id = ttdi->hdr.idFrom; 289 ttdi->lpszText = _entries[id]._title.str(); 290 #ifdef TTF_DI_SETITEM 291 ttdi->uFlags |= TTF_DI_SETITEM; 292 #endif 293 294 // enable multiline tooltips (break at CR/LF and for very long one-line strings) 295 SendMessage(pnmh->hwndFrom, TTM_SETMAXTIPWIDTH, 0, 400); 296 297 break;} 298 299 return super::Notify(id, pnmh); 300 } 301 302 return 0; 303 } 304