menu_window.cpp
来自「ncbi源码」· C++ 代码 · 共 1,678 行 · 第 1/4 页
CPP
1,678 行
/* * =========================================================================== * PRODUCTION $Log: menu_window.cpp,v $ * PRODUCTION Revision 1000.0 2004/06/01 21:29:21 gouriano * PRODUCTION PRODUCTION: IMPORTED [GCC34_MSVC7] Dev-tree R1.7 * PRODUCTION * =========================================================================== *//* $Id: menu_window.cpp,v 1000.0 2004/06/01 21:29:21 gouriano Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE * National Center for Biotechnology Information * * This software/database is a "United States Government Work" under the * terms of the United States Copyright Act. It was written as part of * the author's official duties as a United States Government employee and * thus cannot be copyrighted. This software/database is freely available * to the public for use. The National Library of Medicine and the U.S. * Government have not placed any restriction on its use or reproduction. * * Although all reasonable efforts have been taken to ensure the accuracy * and reliability of the software and data, the NLM and the U.S. * Government do not and cannot warrant the performance or results that * may be obtained by using this software or data. The NLM and the U.S. * Government disclaim all warranties, express or implied, including * warranties of performance, merchantability or fitness for any particular * purpose. * * Please cite the author in any work or product based on this material. * * =========================================================================== * * Authors: Andrey Yazhuk * */#include <ncbi_pch.hpp>#include <corelib/ncbistd.hpp>#include <algorithm>#include <gui/utils/accel_table.hpp>#include <gui/widgets/fl/menu_window.hpp>#include <FL/fl_draw.H>#include <FL/Fl_Image.H>#include <FL/Enumerations.H>#include <FL/Fl.H>#include <math.h>BEGIN_NCBI_SCOPE////////////////////////////////////////////////////////////////////////////////// CMenuPropertiesCMenu::CProperties::CProperties(){ m_FontType = FL_HELVETICA; m_FontSize = 12; m_Colors[eBack] = fl_rgb_color(216, 216, 216); m_Colors[eFocusedBack] = fl_rgb_color(192, 192, 216); m_Colors[eCheckedBack] = fl_rgb_color(200, 200, 216); m_Colors[ePushedBack] = fl_rgb_color(128, 128, 192); m_Colors[ePopupBack] = fl_rgb_color(248, 248, 255); m_Colors[eFrame] = fl_rgb_color(64, 64, 64); m_Colors[eText] = fl_rgb_color(0, 0, 0); m_Colors[eDisabledText] = fl_rgb_color(196, 196, 196); m_Colors[eFocusedDisabledText] = fl_rgb_color(224, 224, 224); m_Colors[ePushedText] = fl_rgb_color(255, 255, 255); m_Colors[eFocusedFrame] = fl_rgb_color(0, 0, 128); m_Colors[eIconArea] = fl_rgb_color(232, 232, 240); m_Colors[eBorder] = fl_rgb_color(255, 255, 255);}const static int kDefaultIconSize = 16;const static int kCheckSize = 16;const static int kRadioSize = 16;const static int kSubMarkerH = 7; // submenu marker height const static int kSubMarkerOffset = 7; // submenu marker offset from the rightconst static int kSubMarkerW = 12; // submenu marker widthconst static int kBorderSize = 3; // menu borderconst static int kSpace = 2; // spacing around icons, labelsconst static int kAccelSpace = 8; // spacing between item label and accelerator labelconst static int kItemOffsetY = 3;const static int kItemOffsetX = 4; // horz spacing between items const static int kSubmenuOffsetX = 8; // horz spacing between submenusconst static int kSeparatorSize = 1 + 2 * kItemOffsetX;const static char kAccessKeyMarker = '&';const static double kMenuDelay = 0.4;////////////////////////////////////////////////////////////////////////////////// class CMenu - base class for all menusCMenu::CProperties CMenu::sm_Props;CRef<CResourceManager> CMenu::sm_ResManager; CRef<CResourceManager> CMenu::GetResourceManager(void){ return sm_ResManager;}CMenu::TCmdToHintMap CMenu::sm_CmdToHint;void CMenu::SetResourceManager(CRef<CResourceManager> manager){ sm_ResManager = manager; if(sm_ResManager) { manager->RegisterAlias("menu::check", "check.png"); manager->RegisterAlias("menu::radio", "radio.png"); }}void CMenu::SetCmdHint(TCmdID cmd, const string& hint){ sm_CmdToHint[cmd] = hint;}string CMenu::GetCmdHint(TCmdID cmd){ TCmdToHintMap::iterator it = sm_CmdToHint.find(cmd); return (it != sm_CmdToHint.end()) ? it->second : "";}CMenu::CMenu(): m_RootItem(NULL), m_bOwnItems(false), m_CmdTarget(NULL), m_Listener(NULL), m_Width(0), m_Height(0), m_Border(0), m_IconSize(kDefaultIconSize), m_MaxLabelW(0), m_BackColor(eBack), m_Selected(NULL), m_PushedItem(NULL), m_bKeyActivated(false){}CMenu::~CMenu(){ x_Clear();}void CMenu::SetCmdTarget(CCommandTarget* target){ m_CmdTarget = target;}CCommandTarget* CMenu::GetCmdTarget(void){ return m_CmdTarget;}void CMenu::SetItemImageSize(int size){ _ASSERT(size >= 0 && size < 100); m_IconSize = size;}bool CMenu::x_IsKeyActivated() const{ return m_bKeyActivated;}/// Creates a menu described by array of SMenuItem-s. CMenuBar creates a separate/// copy of a menu, so that it can be modified at run-time.void CMenu::SetItems(const SMenuItemRec* items){ CMenuItem* root = CreateMenuItems(items); x_SetItems(root, true);}void CMenu::SetItems(CMenuItem* root_item){ x_SetItems(root_item, true);}void CMenu::SetHintListener(IMenuHintListener* listener){ m_Listener = listener;}IMenuHintListener* CMenu::GetHintListener(){ return m_Listener;}void CMenu::x_SetItems(CMenuItem* root_item, bool take_ownership){ x_Clear(); m_RootItem = root_item; m_bOwnItems = take_ownership; if(m_RootItem) { CResourceManager* manager = GetResourceManager(); _ASSERT(manager); m_hCheckIcon = manager->GetImage("menu::check"); m_hRadioIcon = manager->GetImage("menu::radio"); for(CMenuItem::TChildItem_CI it = m_RootItem->SubItemsBegin(); it != m_RootItem->SubItemsEnd(); ++it) { CMenuItem* item = (*it)->GetValue(); // create entry for a menu item SItemEntry entry; entry.m_Item = item; if(item->HasImage()) { entry.m_hIcon = manager->GetImage(item->GetImageAlias()); // preloading images } entry.m_Size = 0; // create access key entry const string& label = item->GetLabel(); string::size_type pos = label.find(kAccessKeyMarker); if(pos != string::npos && pos + 1 < label.size()) { char ch = label[pos + 1]; ch = tolower(ch); TAccessKeyToItemMap::const_iterator it = m_AccessKeyToItem.find(ch); if(it == m_AccessKeyToItem.end()) { // OK m_AccessKeyToItem[ch] = item; } else { ERR_POST("CMenuItem \"" << label << "\" specifies accelerator that is already defined in this menu."); } } // lookup item accelerator if(item->IsItem()) { TCmdID cmd = item->GetCommand(); int accel = 0; if(CAccelTable::GetAccelByCommand(cmd, accel)) { entry.m_AccelLabel = CAccelTable::GetAccelLabel(accel); } } m_Entries.push_back(entry); } } x_Layout(); }void CMenu::x_Clear(void){ m_AccessKeyToItem.clear(); m_Entries.clear(); m_Selected = NULL; if(m_bOwnItems) { delete m_RootItem; } m_RootItem = NULL;}void CMenu::x_UpdateItems(void){ CCommandTarget* target = GetCmdTarget(); if(target) { NON_CONST_ITERATE(TEntries, it, m_Entries) { CMenuItem& item = *it->m_Item; if(item.IsItem()) { CMenuCmdUI CmdUI(item); target->OnUpdateCommand(item.GetCommand(), &CmdUI); } } }}// all coordinates calculated are relative to widget's originvoid CMenu::x_Layout(void){ m_Width = 0; m_Height = 0; m_MaxLabelW = 0; int text_w = 0; int marker_w = 0; fl_font(sm_Props.m_FontType, sm_Props.m_FontSize); const int item_h = max(m_IconSize, fl_height()) + kItemOffsetY * 2; bool b_horz = x_IsHorizontal(); int i = 0; // iterate by items ITERATE(TEntries, it, m_Entries) { const CMenuItem& item = *it->m_Item; x_MeasureItem(*it, text_w); // measure text length if(b_horz) { int icon_space = m_Entries[i].m_hIcon ? (m_IconSize + kSpace) : 0; int w = item.IsSeparator() ? kSeparatorSize : (icon_space + text_w + 2 * (item.IsItem() ? kItemOffsetX : kSubmenuOffsetX)); m_Entries[i].m_Size = w; m_Width += w; } else { // vertical orientation int h = 0; if(item.IsSeparator()) { h = kSeparatorSize; } else { if(item.IsSubmenu()) { marker_w = kSubMarkerW; } m_MaxLabelW = max(m_MaxLabelW, text_w); h = item_h; } m_Entries[i].m_Size = h; m_Height += h; } i++; } if(b_horz) { m_Height = item_h; } else { m_Width = (m_IconSize + 2 * kSpace) + kSpace + m_MaxLabelW + (marker_w + 2 * kSpace) + 2 * kItemOffsetX; } m_Width += 2 * m_Border; m_Height += 2 * m_Border;}CPoint CMenu::GetPreferredSize(void) const{ return CPoint(m_Width, m_Height);}void CMenu::SetSelected(CMenuItem* item){ if(m_Selected != item) { m_Selected = item; GetWidget().damage(FL_DAMAGE_OVERLAY);//redraw(); }}CMenuItem* CMenu::GetRootItem(void){ return m_RootItem;}int CMenu::GetBorder(void) const{ return m_Border;}void CMenu::x_Draw(int x, int y){ Fl_Widget& wid = GetWidget(); int w = wid.w(), h = wid.h(); fl_clip(x, y, w, h); if(m_Border > 0) { // draw frame and border fl_color(sm_Props.GetColor(eFrame)); fl_rect(x, y, w, h); // frame fl_color(sm_Props.GetColor(eBorder)); for( int i = 1; i < m_Border; i++ ) { // border fl_rect(i, i, w - 2 * i, h - 2 * i); } } // fill background not filled by items fl_color(sm_Props.GetColor(m_BackColor)); // fill the right part int x_off = m_Width - m_Border; fl_rectf(x + x_off, y + m_Border, w - m_Border - x_off, h - 2 * m_Border); // fill the bottom part int y_off = m_Height - m_Border; fl_rectf(x + m_Border, y + y_off, m_Width - 2 * m_Border, h - m_Border - y_off); x_DrawItems(x + m_Border, y + m_Border); fl_pop_clip();}void CMenu::x_DrawItems(int x, int y) { bool b_horz = x_IsHorizontal(); if(m_RootItem) { fl_font(sm_Props.m_FontType, sm_Props.m_FontSize); int i = 0; NON_CONST_ITERATE(TEntries, it, m_Entries) { int size = it->m_Size; if(b_horz) { x_DrawItem(*it, x, y, size, m_Height - 2 * m_Border); x += size; } else { x_DrawItem(*it, x, y, m_Width - 2 * m_Border, size); y += size; } i++; } }}/// draw single menu item in the given rectangular areavoid CMenu::x_DrawItem(CMenu::SItemEntry& entry, int x, int y, int w, int h){ CMenuItem& item = *entry.m_Item; bool b_icon = (bool)(entry.m_hIcon); int icon_w = x_IsHorizontal() ? (m_IconSize + kSpace) : (m_IconSize + 2 * kSpace); bool b_focused = false;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?