mirror of
https://github.com/reactos/reactos.git
synced 2025-08-02 23:46:28 +00:00
lazy icon extraction for start menu
svn path=/trunk/; revision=7422
This commit is contained in:
parent
b1f2f1ed55
commit
7fbcfcbc71
10 changed files with 188 additions and 78 deletions
|
@ -51,3 +51,4 @@ If you search for more information, look into the CVS repository.
|
|||
20.12.2003 m. fuchs context menu implementation for desktop window
|
||||
01.01.2004 m. fuchs integrated icons of Everaldo (http://www.everaldo.com) into the start menu.
|
||||
02.01.2004 m. fuchs reimplemented start menu as light weight version
|
||||
03.01.2004 m. fuchs lazy icon extraction for start menu
|
||||
|
|
|
@ -126,17 +126,17 @@ Entry* Entry::read_tree(const void* path, SORT_ORDER sortOrder)
|
|||
}
|
||||
|
||||
|
||||
void Entry::read_directory(SORT_ORDER sortOrder)
|
||||
void Entry::read_directory(SORT_ORDER sortOrder, bool read_icons)
|
||||
{
|
||||
CONTEXT("Entry::read_directory(SORT_ORDER)");
|
||||
|
||||
// call into subclass
|
||||
read_directory();
|
||||
read_directory(read_icons);
|
||||
|
||||
if (g_Globals._prescan_nodes) {
|
||||
if (g_Globals._prescan_nodes) { //@todo _prescan_nodes should not be used for filling the start menu.
|
||||
for(Entry*entry=_down; entry; entry=entry->_next)
|
||||
if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
entry->read_directory();
|
||||
entry->read_directory(read_icons);
|
||||
entry->sort_directory(sortOrder);
|
||||
}
|
||||
}
|
||||
|
@ -284,13 +284,13 @@ void Entry::sort_directory(SORT_ORDER sortOrder)
|
|||
}
|
||||
|
||||
|
||||
void Entry::smart_scan()
|
||||
void Entry::smart_scan(bool read_icons)
|
||||
{
|
||||
CONTEXT("Entry::smart_scan()");
|
||||
|
||||
if (!_scanned) {
|
||||
free_subentries();
|
||||
read_directory(SORT_NAME); // we could use IShellFolder2::GetDefaultColumn to determine sort order
|
||||
read_directory(SORT_NAME, read_icons); // we could use IShellFolder2::GetDefaultColumn to determine sort order
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -73,12 +73,12 @@ public:
|
|||
|
||||
void free_subentries();
|
||||
|
||||
void read_directory(SORT_ORDER sortOrder);
|
||||
void read_directory(SORT_ORDER sortOrder, bool read_icons=true);
|
||||
Entry* read_tree(const void* path, SORT_ORDER sortOrder);
|
||||
void sort_directory(SORT_ORDER sortOrder);
|
||||
void smart_scan();
|
||||
void smart_scan(bool read_icons=true);
|
||||
|
||||
virtual void read_directory() {}
|
||||
virtual void read_directory(bool read_icons=true) {}
|
||||
virtual const void* get_next_path_component(const void*) {return NULL;}
|
||||
virtual Entry* find_entry(const void*) {return NULL;}
|
||||
virtual void get_path(PTSTR path) const = 0;
|
||||
|
|
|
@ -501,12 +501,14 @@ void Pane::draw_item(LPDRAWITEMSTRUCT dis, Entry* entry, int calcWidthCol)
|
|||
if (cx > IMAGE_WIDTH)
|
||||
cx = IMAGE_WIDTH;
|
||||
|
||||
if (entry->_hIcon && entry->_hIcon!=(HICON)-1)
|
||||
DrawIconEx(dis->hDC, img_pos, dis->rcItem.top, entry->_hIcon, cx, GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
|
||||
else
|
||||
ImageList_DrawEx(_himl, img, dis->hDC,
|
||||
img_pos, dis->rcItem.top, cx,
|
||||
IMAGE_HEIGHT, bkcolor, CLR_DEFAULT, ILD_NORMAL);
|
||||
if (entry->_hIcon != (HICON)-1) {
|
||||
if (entry->_hIcon)
|
||||
DrawIconEx(dis->hDC, img_pos, dis->rcItem.top, entry->_hIcon, cx, GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
|
||||
else
|
||||
ImageList_DrawEx(_himl, img, dis->hDC,
|
||||
img_pos, dis->rcItem.top, cx,
|
||||
IMAGE_HEIGHT, bkcolor, CLR_DEFAULT, ILD_NORMAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -234,8 +234,25 @@ static HICON extract_icon(IShellFolder* folder, LPCITEMIDLIST pidl)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static HICON extract_icon(IShellFolder* folder, LPCITEMIDLIST pidl, ShellEntry* entry)
|
||||
{
|
||||
HICON hIcon = extract_icon(folder, pidl);
|
||||
|
||||
void ShellDirectory::read_directory()
|
||||
if (!hIcon) {
|
||||
ShellPath pidl_abs = static_cast<ShellEntry*>(entry)->create_absolute_pidl();
|
||||
LPCITEMIDLIST pidl = pidl_abs;
|
||||
|
||||
SHFILEINFO sfi;
|
||||
|
||||
if (SHGetFileInfo((LPCTSTR)pidl, 0, &sfi, sizeof(sfi), SHGFI_PIDL|SHGFI_ICON|SHGFI_SMALLICON))
|
||||
entry->_hIcon = sfi.hIcon;
|
||||
}
|
||||
|
||||
return hIcon;
|
||||
}
|
||||
|
||||
|
||||
void ShellDirectory::read_directory(bool read_icons)
|
||||
{
|
||||
CONTEXT("ShellDirectory::read_directory()");
|
||||
|
||||
|
@ -328,23 +345,15 @@ void ShellDirectory::read_directory()
|
|||
// get display icons for files and virtual objects
|
||||
if (!(entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ||
|
||||
!(attribs & SFGAO_FILESYSTEM)) {
|
||||
entry->_hIcon = extract_icon(_folder, pidls[n]/*, (ShellEntry*)entry*/);
|
||||
|
||||
if (!entry->_hIcon) {
|
||||
if (!entry->_hIcon) {
|
||||
ShellPath pidl_abs = static_cast<ShellEntry*>(entry)->create_absolute_pidl();
|
||||
LPCITEMIDLIST pidl = pidl_abs;
|
||||
|
||||
SHFILEINFO sfi;
|
||||
|
||||
if (SHGetFileInfo((LPCTSTR)pidl, 0, &sfi, sizeof(sfi), SHGFI_PIDL|SHGFI_ICON|SHGFI_SMALLICON))
|
||||
entry->_hIcon = sfi.hIcon;
|
||||
}
|
||||
if (read_icons) {
|
||||
entry->_hIcon = extract_icon(_folder, pidls[n], static_cast<ShellEntry*>(entry));
|
||||
|
||||
if (!entry->_hIcon)
|
||||
entry->_hIcon = (HICON)-1; // don't try again later
|
||||
}
|
||||
}
|
||||
} else
|
||||
entry->_hIcon = 0;
|
||||
} else
|
||||
entry->_hIcon = (HICON)-1; // don't try again later
|
||||
|
||||
entry->_down = NULL;
|
||||
entry->_expanded = false;
|
||||
|
@ -385,11 +394,31 @@ Entry* ShellDirectory::find_entry(const void* p)
|
|||
LPITEMIDLIST pidl = (LPITEMIDLIST) p;
|
||||
|
||||
for(Entry*entry=_down; entry; entry=entry->_next) {
|
||||
ShellEntry* e = static_cast<ShellEntry*>(entry);
|
||||
ShellEntry* se = static_cast<ShellEntry*>(entry);
|
||||
|
||||
if (e->_pidl && e->_pidl->mkid.cb==pidl->mkid.cb && !memcmp(e->_pidl, pidl, e->_pidl->mkid.cb))
|
||||
if (se->_pidl && se->_pidl->mkid.cb==pidl->mkid.cb && !memcmp(se->_pidl, pidl, se->_pidl->mkid.cb))
|
||||
return entry;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ShellDirectory::extract_icons()
|
||||
{
|
||||
int cnt = 0;
|
||||
|
||||
for(Entry*entry=_down; entry; entry=entry->_next) {
|
||||
ShellEntry* se = static_cast<ShellEntry*>(entry);
|
||||
|
||||
if (!se->_hIcon) {
|
||||
se->_hIcon = extract_icon(_folder, se->_pidl, static_cast<ShellEntry*>(se));
|
||||
|
||||
if (entry->_hIcon)
|
||||
++cnt;
|
||||
else
|
||||
entry->_hIcon = (HICON)-1; // don't try again later
|
||||
}
|
||||
}
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
|
|
@ -97,12 +97,14 @@ struct ShellDirectory : public ShellEntry, public Directory
|
|||
pFolder->Release();
|
||||
}
|
||||
|
||||
virtual void read_directory();
|
||||
virtual void read_directory(bool read_icons=true);
|
||||
virtual const void* get_next_path_component(const void*);
|
||||
virtual Entry* find_entry(const void* p);
|
||||
|
||||
virtual void get_path(PTSTR path) const;
|
||||
|
||||
int extract_icons();
|
||||
|
||||
ShellFolder _folder;
|
||||
HWND _hwnd;
|
||||
|
||||
|
|
|
@ -119,7 +119,7 @@ int ScanNTFSStreams(Entry* entry, HANDLE hFile)
|
|||
}
|
||||
|
||||
|
||||
void WinDirectory::read_directory()
|
||||
void WinDirectory::read_directory(bool read_icons)
|
||||
{
|
||||
Entry* first_entry = NULL;
|
||||
Entry* last = NULL;
|
||||
|
|
|
@ -59,7 +59,7 @@ struct WinDirectory : public WinEntry, public Directory
|
|||
_path = NULL;
|
||||
}
|
||||
|
||||
virtual void read_directory();
|
||||
virtual void read_directory(bool read_icons=true);
|
||||
virtual const void* get_next_path_component(const void*);
|
||||
virtual Entry* find_entry(const void*);
|
||||
};
|
||||
|
|
|
@ -167,6 +167,10 @@ LRESULT StartMenu::Init(LPCREATESTRUCT pcs)
|
|||
#ifdef _LIGHT_STARTMENU
|
||||
ResizeToButtons();
|
||||
#endif
|
||||
|
||||
#ifdef _LAZY_ICONEXTRACT
|
||||
PostMessage(_hwnd, PM_UPDATE_ICONS, 0, 0);
|
||||
#endif
|
||||
} catch(COMException& e) {
|
||||
HandleException(e, pcs->hwndParent); // destroys the start menu window while switching focus
|
||||
}
|
||||
|
@ -183,7 +187,11 @@ void StartMenu::AddEntries()
|
|||
if (!dir._scanned) {
|
||||
WaitCursor wait;
|
||||
|
||||
dir.smart_scan();
|
||||
#ifdef _LAZY_ICONEXTRACT
|
||||
dir.smart_scan(false); // lazy icon extraction
|
||||
#else
|
||||
dir.smart_scan(true);
|
||||
#endif
|
||||
}
|
||||
|
||||
AddShellEntries(dir, -1, smd._subfolders);
|
||||
|
@ -324,6 +332,12 @@ LRESULT StartMenu::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
|
|||
break;}
|
||||
#endif
|
||||
|
||||
#ifdef _LAZY_ICONEXTRACT
|
||||
case PM_UPDATE_ICONS:
|
||||
UpdateIcons();
|
||||
break;
|
||||
#endif
|
||||
|
||||
case PM_STARTENTRY_LAUNCHED:
|
||||
if (GetWindowStyle(_hwnd) & WS_CAPTION) // don't automatically close floating menus
|
||||
return 0;
|
||||
|
@ -345,47 +359,6 @@ LRESULT StartMenu::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
|
|||
}
|
||||
|
||||
|
||||
void StartMenu::Paint(PaintCanvas& canvas)
|
||||
{
|
||||
if (_border_top)
|
||||
DrawFloatingButton(canvas);
|
||||
|
||||
#ifdef _LIGHT_STARTMENU
|
||||
ClientRect clnt(_hwnd);
|
||||
RECT rect = {_border_left, _border_top, clnt.right, STARTMENU_LINE_HEIGHT};
|
||||
|
||||
int sep_width = rect.right-rect.left - 4;
|
||||
|
||||
FontSelection font(canvas, GetStockFont(DEFAULT_GUI_FONT));
|
||||
BkMode bk_mode(canvas, TRANSPARENT);
|
||||
|
||||
for(SMBtnVector::const_iterator it=_buttons.begin(); it!=_buttons.end(); ++it) {
|
||||
const SMBtnInfo& info = *it;
|
||||
|
||||
if (rect.top > canvas.rcPaint.bottom)
|
||||
break;
|
||||
|
||||
if (info._id == -1) { // a separator?
|
||||
rect.bottom = rect.top + STARTMENU_SEP_HEIGHT;
|
||||
|
||||
BrushSelection brush_sel(canvas, GetSysColorBrush(COLOR_BTNSHADOW));
|
||||
PatBlt(canvas, rect.left+2, rect.top+STARTMENU_SEP_HEIGHT/2-1, sep_width, 1, PATCOPY);
|
||||
|
||||
SelectBrush(canvas, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
|
||||
PatBlt(canvas, rect.left+2, rect.top+STARTMENU_SEP_HEIGHT/2, sep_width, 1, PATCOPY);
|
||||
} else {
|
||||
rect.bottom = rect.top + STARTMENU_LINE_HEIGHT;
|
||||
|
||||
if (rect.top >= canvas.rcPaint.top)
|
||||
DrawStartMenuButton(canvas, rect, info._title, info._hIcon,
|
||||
info._hasSubmenu, info._enabled, info._id==_selected_id, false);
|
||||
}
|
||||
|
||||
rect.top = rect.bottom;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _LIGHT_STARTMENU
|
||||
|
||||
int StartMenu::ButtonHitTest(POINT pt)
|
||||
|
@ -521,6 +494,97 @@ void StartMenu::GetFloatingButonRect(LPRECT prect)
|
|||
}
|
||||
|
||||
|
||||
void StartMenu::Paint(PaintCanvas& canvas)
|
||||
{
|
||||
if (_border_top)
|
||||
DrawFloatingButton(canvas);
|
||||
|
||||
#ifdef _LIGHT_STARTMENU
|
||||
ClientRect clnt(_hwnd);
|
||||
RECT rect = {_border_left, _border_top, clnt.right, STARTMENU_LINE_HEIGHT};
|
||||
|
||||
int sep_width = rect.right-rect.left - 4;
|
||||
|
||||
FontSelection font(canvas, GetStockFont(DEFAULT_GUI_FONT));
|
||||
BkMode bk_mode(canvas, TRANSPARENT);
|
||||
|
||||
for(SMBtnVector::const_iterator it=_buttons.begin(); it!=_buttons.end(); ++it) {
|
||||
const SMBtnInfo& info = *it;
|
||||
|
||||
if (rect.top > canvas.rcPaint.bottom)
|
||||
break;
|
||||
|
||||
if (info._id == -1) { // a separator?
|
||||
rect.bottom = rect.top + STARTMENU_SEP_HEIGHT;
|
||||
|
||||
BrushSelection brush_sel(canvas, GetSysColorBrush(COLOR_BTNSHADOW));
|
||||
PatBlt(canvas, rect.left+2, rect.top+STARTMENU_SEP_HEIGHT/2-1, sep_width, 1, PATCOPY);
|
||||
|
||||
SelectBrush(canvas, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
|
||||
PatBlt(canvas, rect.left+2, rect.top+STARTMENU_SEP_HEIGHT/2, sep_width, 1, PATCOPY);
|
||||
} else {
|
||||
rect.bottom = rect.top + STARTMENU_LINE_HEIGHT;
|
||||
|
||||
if (rect.top >= canvas.rcPaint.top)
|
||||
DrawStartMenuButton(canvas, rect, info._title, info._hIcon,
|
||||
info._hasSubmenu, info._enabled, info._id==_selected_id, false);
|
||||
}
|
||||
|
||||
rect.top = rect.bottom;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _LAZY_ICONEXTRACT
|
||||
void StartMenu::UpdateIcons()
|
||||
{
|
||||
UpdateWindow(_hwnd);
|
||||
|
||||
int icons_extracted = 0;
|
||||
int icons_refreshed = 0;
|
||||
|
||||
for(StartMenuShellDirs::iterator it=_dirs.begin(); it!=_dirs.end(); ++it) {
|
||||
ShellDirectory& dir = it->_dir;
|
||||
|
||||
icons_extracted += dir.extract_icons();
|
||||
}
|
||||
|
||||
if (icons_extracted) {
|
||||
for(ShellEntryMap::iterator it1=_entries.begin(); it1!=_entries.end(); ++it1) {
|
||||
StartMenuEntry& sme = it1->second;
|
||||
|
||||
if (!sme._hIcon) {
|
||||
sme._hIcon = (HICON)-1;
|
||||
|
||||
for(ShellEntrySet::const_iterator it2=sme._entries.begin(); it2!=sme._entries.end(); ++it2) {
|
||||
const ShellEntry* sm_entry = *it2;
|
||||
|
||||
if (sm_entry->_hIcon) {
|
||||
sme._hIcon = sm_entry->_hIcon;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(SMBtnVector::iterator it=_buttons.begin(); it!=_buttons.end(); ++it) {
|
||||
SMBtnInfo& info = *it;
|
||||
|
||||
if (info._id>0 && !info._hIcon) {
|
||||
info._hIcon = _entries[info._id]._hIcon;
|
||||
++icons_refreshed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (icons_refreshed) {
|
||||
InvalidateRect(_hwnd, NULL, TRUE);
|
||||
UpdateWindow(_hwnd);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// resize child button controls to accomodate for new window size
|
||||
void StartMenu::ResizeButtons(int cx)
|
||||
{
|
||||
|
@ -1441,6 +1505,10 @@ void SearchMenu::AddEntries()
|
|||
|
||||
void RecentStartMenu::AddEntries()
|
||||
{
|
||||
|
||||
///@todo A cache would really speed up processing of long recent doc lists.
|
||||
///@todo Alternativelly we could also use direct file system access instead of iterating in shell namespace.
|
||||
|
||||
for(StartMenuShellDirs::iterator it=_dirs.begin(); it!=_dirs.end(); ++it) {
|
||||
StartMenuDirectory& smd = *it;
|
||||
ShellDirectory& dir = smd._dir;
|
||||
|
@ -1448,7 +1516,11 @@ void RecentStartMenu::AddEntries()
|
|||
if (!dir._scanned) {
|
||||
WaitCursor wait;
|
||||
|
||||
dir.smart_scan();
|
||||
#ifdef _LAZY_ICONEXTRACT
|
||||
dir.smart_scan(false); // lazy icon extraction
|
||||
#else
|
||||
dir.smart_scan(true);
|
||||
#endif
|
||||
}
|
||||
|
||||
dir.sort_directory(SORT_DATE);
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
|
||||
#define _LIGHT_STARTMENU
|
||||
#define _LAZY_ICONEXTRACT
|
||||
|
||||
|
||||
#define CLASSNAME_STARTMENU TEXT("ReactosStartmenuClass")
|
||||
|
@ -47,6 +48,8 @@
|
|||
#define PM_STARTENTRY_FOCUSED (WM_APP+0x13)
|
||||
#endif
|
||||
|
||||
#define PM_UPDATE_ICONS (WM_APP+0x15)
|
||||
|
||||
|
||||
/// StartMenuDirectory is used to store the base directory of start menus.
|
||||
struct StartMenuDirectory
|
||||
|
@ -273,6 +276,7 @@ protected:
|
|||
void GetFloatingButonRect(LPRECT prect);
|
||||
|
||||
void Paint(PaintCanvas& canvas);
|
||||
void UpdateIcons();
|
||||
};
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue