⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 startmenu.cpp

📁 winNT技术操作系统,国外开放的原代码和LIUX一样
💻 CPP
📖 第 1 页 / 共 4 页
字号:
	if (id == -1)
		return false;

	if (id == _selected_id)
		return true;

	InvalidateSelection();

	const SMBtnInfo* btn = GetButtonInfo(id);

	if (btn && btn->_enabled) {
		_selected_id = id;

		InvalidateSelection();

		 // automatically open submenus
		if (btn->_hasSubmenu) {
			if (open_sub)
				OpenSubmenu();
		} else
			CloseOtherSubmenus();	// close any open submenu

		return true;
	} else {
		_selected_id = -1;
		return false;
	}
}

bool StartMenu::OpenSubmenu(bool select_first)
{
	if (_selected_id == -1)
		return false;

	InvalidateSelection();

	const SMBtnInfo* btn = GetButtonInfo(_selected_id);

	 // automatically open submenus
	if (btn->_hasSubmenu) {
		//@@ allows destroying of startmenu when processing PM_UPDATE_ICONS -> GPF
		UpdateWindow(_hwnd);	// draw focused button before waiting on submenu creation
		Command(_selected_id, BN_CLICKED);

		if (select_first && _submenu)
			SendMessage(_submenu, PM_SELECT_ENTRY, (WPARAM)false, 0);

		return true;
	} else
		return false;
}


int StartMenu::GetSelectionIndex()
{
	if (_selected_id == -1)
		return -1;

	for(int i=0; i<(int)_buttons.size(); ++i)
		if (_buttons[i]._id == _selected_id)
			return i;

	return -1;
}

bool StartMenu::SelectButtonIndex(int idx, bool open_sub)
{
	if (idx>=0 && idx<(int)_buttons.size())
		return SelectButton(_buttons[idx]._id, open_sub);
	else
		return false;
}

void StartMenu::ProcessKey(int vk)
{
	switch(vk) {
	  case VK_RETURN:
		if (_selected_id)
			Command(_selected_id, BN_CLICKED);
		break;

	  case VK_UP:
		Navigate(-1);
		break;

	  case VK_DOWN:
		Navigate(+1);
		break;

	  case VK_HOME:
		SelectButtonIndex(0, false);
		break;

	  case VK_END:
		SelectButtonIndex(_buttons.size()-1, false);
		break;

	  case VK_LEFT:
		if (_submenu)
			CloseOtherSubmenus();
		else if (!(GetWindowStyle(_hwnd) & WS_CAPTION))	// don't automatically close floating menus
			DestroyWindow(_hwnd);
		break;

	  case VK_RIGHT:
		OpenSubmenu(true);
		break;

	  case VK_ESCAPE:
		CloseStartMenu();
		break;

	  default:
		if (vk>='0' && vk<='Z')
			JumpToNextShortcut(vk);
	}
}

bool StartMenu::Navigate(int step)
{
	int idx = GetSelectionIndex();

	if (idx == -1)
		if (step > 0)
			idx = 0 - step;
		else
			idx = _buttons.size() - step;

	for(;;) {
		idx += step;

		if (_buttons.size()<=1 && (idx<0 || idx>(int)_buttons.size()))
			break;

		if (idx < 0)
			idx += _buttons.size();

		if (idx > (int)_buttons.size())
			idx -= _buttons.size()+1;

		if (SelectButtonIndex(idx, false))
			return true;
	}

	return false;
}

bool StartMenu::JumpToNextShortcut(char c)
{
	int cur_idx = GetSelectionIndex();

	if (cur_idx == -1)
		cur_idx = 0;

	int first_found = 0;
	int found_more = 0;

	SMBtnVector::const_iterator cur_it = _buttons.begin();
	cur_it += cur_idx + 1;

	 // first search down from current item...
	SMBtnVector::const_iterator it = cur_it;
	for(; it!=_buttons.end(); ++it) {
		const SMBtnInfo& btn = *it;

		if (!btn._title.empty() && toupper((TBYTE)btn._title.at(0)) == c) {
			if (!first_found)
				first_found = btn._id;
			else
				++found_more;
		}
	}

	 // ...now search from top to the current item
	it = _buttons.begin();
	for(; it!=_buttons.end() && it!=cur_it; ++it) {
		const SMBtnInfo& btn = *it;

		if (!btn._title.empty() && toupper((TBYTE)btn._title.at(0)) == c) {
			if (!first_found)
				first_found = btn._id;
			else
				++found_more;
		}
	}

	if (first_found) {
		SelectButton(first_found);

		if (!found_more)
			Command(first_found, BN_CLICKED);

		return true;
	} else
		return false;
}

#endif // _LIGHT_STARTMENU


bool StartMenu::GetButtonRect(int id, PRECT prect) const
{
#ifdef _LIGHT_STARTMENU
	ClientRect clnt(_hwnd);
	const int icon_size = _icon_size;
	RECT rect = {_border_left, _border_top, clnt.right, STARTMENU_LINE_HEIGHT(icon_size)};

	for(SMBtnVector::const_iterator it=_buttons.begin()+_scroll_pos; it!=_buttons.end(); ++it) {
		const SMBtnInfo& info = *it;

		rect.bottom = rect.top + (info._id==-1? STARTMENU_SEP_HEIGHT(icon_size): STARTMENU_LINE_HEIGHT(icon_size));

		if (info._id == id) {
			*prect = rect;
			return true;
		}

		rect.top = rect.bottom;
	}

	return false;
#else
	HWND btn = GetDlgItem(_hwnd, id);

	if (btn) {
		GetWindowRect(btn, prect);
		ScreenToClient(_hwnd, prect);

		return true;
	} else
		return false;
#endif
}


void StartMenu::DrawFloatingButton(HDC hdc)
{
	static ResIconEx floatingIcon(IDI_FLOATING, 8, 4);

	ClientRect clnt(_hwnd);

	DrawIconEx(hdc, clnt.right-12, 0, floatingIcon, 8, 4, 0, 0, DI_NORMAL);
}

void StartMenu::GetFloatingButtonRect(LPRECT prect)
{
	GetClientRect(_hwnd, prect);

	prect->right -= 4;
	prect->left = prect->right - 8;
	prect->bottom = 4;
}


void StartMenu::DrawArrows(HDC hdc, int icon_size)
{
	int cx = icon_size / 2;
	int cy = icon_size / 4;

	ResIconEx arrowUpIcon(IDI_ARROW_UP, cx, cy);
	ResIconEx arrowDownIcon(IDI_ARROW_DOWN, cx, cy);

	ClientRect clnt(_hwnd);

	DrawIconEx(hdc, clnt.right/2-cx/2, _floating_btn?3:1, arrowUpIcon, cx, cy, 0, 0, DI_NORMAL);
	DrawIconEx(hdc, clnt.right/2-cx/2, clnt.bottom-cy-1, arrowDownIcon, cx, cy, 0, 0, DI_NORMAL);
}

void StartMenu::GetArrowButtonRects(LPRECT prect_up, LPRECT prect_down, int icon_size)
{
	int cx = icon_size / 2;
	int cy = icon_size / 4;

	GetClientRect(_hwnd, prect_up);
	*prect_down = *prect_up;

//	prect_up->left = prect_up->right/2 - cx/2;
//	prect_up->right = prect_up->left + cy;
	prect_up->right -= cx;
	prect_up->top = _floating_btn? cy-1: 1;
	prect_up->bottom = prect_up->top + cy;

//	prect_down->left = prect_down->right/2 - cx/2;
//	prect_down->right = prect_down->left + cy;
	prect_down->right -= cx;
	prect_down->top = prect_down->bottom - cy - 1;
}


void StartMenu::Paint(PaintCanvas& canvas)
{
	if (_floating_btn)
		DrawFloatingButton(canvas);

#ifdef _LIGHT_STARTMENU
	if (_arrow_btns)
		DrawArrows(canvas, _icon_size);

	ClientRect clnt(_hwnd);
	const int icon_size = _icon_size;
	RECT rect = {_border_left, _border_top, clnt.right, STARTMENU_LINE_HEIGHT(icon_size)};

	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()+_scroll_pos; it!=_buttons.end(); ++it) {
		const SMBtnInfo& btn = *it;

		if (rect.top > canvas.rcPaint.bottom)
			break;

		if (btn._id == -1) {	// a separator?
			rect.bottom = rect.top + STARTMENU_SEP_HEIGHT(icon_size);

			if (rect.bottom > _bottom_max)
				break;

			BrushSelection brush_sel(canvas, GetSysColorBrush(COLOR_BTNSHADOW));
			PatBlt(canvas, rect.left+2, rect.top+STARTMENU_SEP_HEIGHT(icon_size)/2-1, sep_width, 1, PATCOPY);

			SelectBrush(canvas, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
			PatBlt(canvas, rect.left+2, rect.top+STARTMENU_SEP_HEIGHT(icon_size)/2, sep_width, 1, PATCOPY);
		} else {
			rect.bottom = rect.top + STARTMENU_LINE_HEIGHT(icon_size);

			if (rect.bottom > _bottom_max)
				break;

			if (rect.top >= canvas.rcPaint.top)
				DrawStartMenuButton(canvas, rect, btn._title, btn, btn._id==_selected_id, false, _icon_size);
		}

		rect.top = rect.bottom;
	}
#endif
}

#ifdef _LAZY_ICONEXTRACT
void StartMenu::UpdateIcons(/*int idx*/)
{
	UpdateWindow(_hwnd);

#ifdef _SINGLE_ICONEXTRACT

	//if (idx >= 0)
	int idx = _scroll_pos;

	for(; idx<(int)_buttons.size(); ++idx) {
		SMBtnInfo& btn = _buttons[idx];

		if (btn._icon_id==ICID_UNKNOWN && btn._id>0) {
			StartMenuEntry& sme = _entries[btn._id];

			btn._icon_id = ICID_NONE;

			for(ShellEntrySet::iterator it=sme._entries.begin(); it!=sme._entries.end(); ++it) {
				Entry* entry = *it;

				if (entry->_icon_id == ICID_UNKNOWN)
					entry->_icon_id = entry->safe_extract_icon(ICF_FROM_ICON_SIZE(_icon_size));

				if (entry->_icon_id > ICID_NONE) {
					btn._icon_id = (ICON_ID)/*@@*/ entry->_icon_id;

					RECT rect;

					GetButtonRect(btn._id, &rect);

					if (rect.bottom > _bottom_max)
						break;

					WindowCanvas canvas(_hwnd);
					DrawStartMenuButton(canvas, rect, NULL, btn, btn._id==_selected_id, false, _icon_size);

					//InvalidateRect(_hwnd, &rect, FALSE);
					//UpdateWindow(_hwnd);
					//break;

					break;
				}
			}
		}
	}

//	if (++idx < (int)_buttons.size())
//		PostMessage(_hwnd, PM_UPDATE_ICONS, idx, 0);

#else

	int icons_extracted = 0;
	int icons_updated = 0;

	for(StartMenuShellDirs::iterator it=_dirs.begin(); it!=_dirs.end(); ++it) {
		ShellDirectory& dir = it->_dir;

		icons_extracted += dir.extract_icons(icon_size);
	}

	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 Entry* 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_updated;
			}
		}
	}

	if (icons_updated) {
		InvalidateRect(_hwnd, NULL, FALSE);
		UpdateWindow(_hwnd);
	}
#endif
}
#endif


 // resize child button controls to accomodate for new window size
void StartMenu::ResizeButtons(int cx)
{
	HDWP hdwp = BeginDeferWindowPos(10);

	for(HWND ctrl=GetWindow(_hwnd,GW_CHILD); ctrl; ctrl=GetNextWindow(ctrl,GW_HWNDNEXT)) {
		ClientRect rt(ctrl);

		if (rt.right != cx) {
			int height = rt.bottom - rt.top;

			 // special handling for separator controls
			if (!height && (GetWindowStyle(ctrl)&SS_TYPEMASK)==SS_ETCHEDHORZ)
				height = 2;

			hdwp = DeferWindowPos(hdwp, ctrl, 0, 0, 0, cx, height, SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE);
		}
	}

	EndDeferWindowPos(hdwp);
}


int StartMenu::Command(int id, int code)
{
#ifndef _LIGHT_STARTMENU
	switch(id) {
	  case IDCANCEL:
		CloseStartMenu(id);
		break;

	  default: {
#endif
		ShellEntryMap::iterator found = _entries.find(id);

		if (found != _entries.end()) {
			ActivateEntry(id, found->second._entries);
			return 0;
		}

		return super::Command(id, code);
#ifndef _LIGHT_STARTMENU
	  }
	}

	return 0;
#endif
}


ShellEntryMap::iterator StartMenu::AddEntry(const String& title, ICON_ID icon_id, Entry* entry)
{
	 // search for an already existing subdirectory entry with the same name
	if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
		for(ShellEntryMap::iterator it=_entries.begin(); it!=_entries.end(); ++it) {
			StartMenuEntry& sme = it->second;

			if (!_tcsicmp(sme._title, title))	///@todo speed up by using a map indexed by name
				for(ShellEntrySet::iterator it2=sme._entries.begin(); it2!=sme._entries.end(); ++it2) {
					if ((*it2)->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
						 // merge the new shell entry with the existing of the same name
						sme._entries.insert(entry);

						return it;
					}
				}
		}

	ShellEntryMap::iterator sme = AddEntry(title, icon_id);

	sme->second._entries.insert(entry);

	return sme;
}

ShellEntryMap::iterator StartMenu::AddEntry(const String& title, ICON_ID icon_id, int id)
{
	if (id == -1)
		id = ++_next_id;

	StartMenuEntry sme;

	sme._title = title;
	sme._icon_id = icon_id;

	ShellEntryMap::iterator it = _entries.insert(make_pair(id, sme)).first;

	return it;
}

ShellEntryMap::iterator StartMenu::AddEntry(const ShellFolder folder, ShellEntry* entry)
{
	ICON_ID icon_id;

	if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
		icon_id = ICID_APPS;
	else
		icon_id = (ICON_ID)/*@@*/ entry->_icon_id;

	return AddEntry(folder.get_name(entry->_pidl), icon_id, entry);
}

ShellEntryMap::iterator StartMenu::AddEntry(const ShellFolder folder, Entry* entry)
{
	ICON_ID icon_id;

	if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
		icon_id = ICID_APPS;
	else
		icon_id = (ICON_ID)/*@@*/ entry->_icon_id;

	return AddEntry(entry->_display_name, icon_id, entry);
}


void StartMenu::AddButton(LPCTSTR title, ICON_ID icon_id, bool hasSubmenu, int id, bool enabled)
{
#ifdef _LIGHT_STARTMENU
	_buttons.push_back(SMBtnInfo(title, icon_id, id, hasSubmenu, enabled));
#else
	DWORD style = enabled? WS_VISIBLE|WS_CHILD|BS_OWNERDRAW: WS_VISIBLE|WS_CHILD|BS_OWNERDRAW|WS_DISABLED;

	WindowRect rect(_hwnd);
	ClientRect clnt(_hwnd);

	 // increase window height to make room for the new button
	rect.top -= STARTMENU_LINE_HEIGHT(icon_size);

	 // move down if we are too high now
	if (rect.top < 0) {
		rect.top += STARTMENU_LINE_HEIGHT(icon_size);
		rect.bottom += STARTMENU_LINE_HEIGHT(icon_size);
	}

	WindowCanvas canvas(_hwnd);
	FontSelection font(canvas, GetStockFont(DEFAULT_GUI_FONT));

	 // widen window, if it is too small
	int text_width = GetStartMenuBtnTextWidth(canvas, title, _hwnd) + icon_size + 10/*placeholder*/ + 16/*arrow*/;

	int cx = clnt.right - _border_left;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -