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