Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

350 lines
9.2 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #define PROTECTED_THINGS_DISABLE
  8. #include <vgui/IPanel.h>
  9. #include <vgui/IInput.h>
  10. #include <vgui/ISurface.h>
  11. #include <KeyValues.h>
  12. #include <vgui/IVGui.h>
  13. #include <vgui_controls/Controls.h>
  14. #include <vgui_controls/MenuButton.h>
  15. #include <vgui_controls/Menu.h>
  16. #include <vgui_controls/TextImage.h>
  17. // memdbgon must be the last include file in a .cpp file!!!
  18. #include <tier0/memdbgon.h>
  19. using namespace vgui;
  20. DECLARE_BUILD_FACTORY_DEFAULT_TEXT( MenuButton, MenuButton );
  21. //-----------------------------------------------------------------------------
  22. // Purpose: Constructor
  23. //-----------------------------------------------------------------------------
  24. MenuButton::MenuButton(Panel *parent, const char *panelName, const char *text) : Button(parent, panelName, text)
  25. {
  26. m_pMenu = NULL;
  27. m_iDirection = Menu::DOWN;
  28. m_pDropMenuImage = NULL;
  29. m_nImageIndex = -1;
  30. _openOffsetY = 0;
  31. m_bDropMenuButtonStyle = true; // set to true so SetDropMenuButtonStyle() forces real init.
  32. SetDropMenuButtonStyle( false );
  33. SetUseCaptureMouse( false );
  34. SetButtonActivationType( ACTIVATE_ONPRESSED );
  35. }
  36. //-----------------------------------------------------------------------------
  37. // Purpose: Destructor
  38. //-----------------------------------------------------------------------------
  39. MenuButton::~MenuButton()
  40. {
  41. delete m_pDropMenuImage;
  42. }
  43. //-----------------------------------------------------------------------------
  44. // Purpose: attaches a menu to the menu button
  45. //-----------------------------------------------------------------------------
  46. void MenuButton::SetMenu(Menu *menu)
  47. {
  48. m_pMenu = menu;
  49. if (menu)
  50. {
  51. m_pMenu->SetVisible(false);
  52. m_pMenu->AddActionSignalTarget(this);
  53. m_pMenu->SetParent(this);
  54. }
  55. }
  56. //-----------------------------------------------------------------------------
  57. // Purpose: Never draw a focus border
  58. //-----------------------------------------------------------------------------
  59. void MenuButton::DrawFocusBorder(int tx0, int ty0, int tx1, int ty1)
  60. {
  61. }
  62. //-----------------------------------------------------------------------------
  63. // Purpose: Sets the direction from the menu button the menu should open
  64. //-----------------------------------------------------------------------------
  65. void MenuButton::SetOpenDirection(Menu::MenuDirection_e direction)
  66. {
  67. m_iDirection = direction;
  68. }
  69. //-----------------------------------------------------------------------------
  70. // Purpose: hides the menu
  71. //-----------------------------------------------------------------------------
  72. void MenuButton::HideMenu(void)
  73. {
  74. if (!m_pMenu)
  75. return;
  76. // hide the menu
  77. m_pMenu->SetVisible(false);
  78. // unstick the button
  79. BaseClass::ForceDepressed(false);
  80. Repaint();
  81. OnHideMenu(m_pMenu);
  82. }
  83. //-----------------------------------------------------------------------------
  84. // Purpose: Called when the menu button loses focus; hides the menu
  85. //-----------------------------------------------------------------------------
  86. void MenuButton::OnKillFocus( KeyValues *pParams )
  87. {
  88. VPANEL hPanel = (VPANEL)pParams->GetPtr( "newPanel" );
  89. if ( m_pMenu && !m_pMenu->HasFocus() && hPanel != m_pMenu->GetVPanel() )
  90. {
  91. HideMenu();
  92. }
  93. BaseClass::OnKillFocus();
  94. }
  95. //-----------------------------------------------------------------------------
  96. // Purpose: Called when the menu is closed
  97. //-----------------------------------------------------------------------------
  98. void MenuButton::OnMenuClose()
  99. {
  100. HideMenu();
  101. PostActionSignal(new KeyValues("MenuClose"));
  102. }
  103. //-----------------------------------------------------------------------------
  104. // Purpose: Sets the offset from where menu would normally be placed
  105. // Only is used if menu is ALIGN_WITH_PARENT
  106. //-----------------------------------------------------------------------------
  107. void MenuButton::SetOpenOffsetY(int yOffset)
  108. {
  109. _openOffsetY = yOffset;
  110. }
  111. //-----------------------------------------------------------------------------
  112. // Purpose:
  113. //-----------------------------------------------------------------------------
  114. bool MenuButton::CanBeDefaultButton(void)
  115. {
  116. return false;
  117. }
  118. //-----------------------------------------------------------------------------
  119. // Purpose: Handles hotkey accesses
  120. //-----------------------------------------------------------------------------
  121. void MenuButton::DoClick()
  122. {
  123. if ( IsDropMenuButtonStyle() &&
  124. m_pDropMenuImage )
  125. {
  126. int mx, my;
  127. // force the menu to appear where the mouse button was pressed
  128. input()->GetCursorPos( mx, my );
  129. ScreenToLocal( mx, my );
  130. int contentW, contentH;
  131. m_pDropMenuImage->GetContentSize( contentW, contentH );
  132. int drawX = GetWide() - contentW - 2;
  133. if ( mx <= drawX || !OnCheckMenuItemCount() )
  134. {
  135. // Treat it like a "regular" button click
  136. BaseClass::DoClick();
  137. return;
  138. }
  139. }
  140. if ( !m_pMenu )
  141. {
  142. return;
  143. }
  144. // menu is already visible, hide the menu
  145. if (m_pMenu->IsVisible())
  146. {
  147. HideMenu();
  148. return;
  149. }
  150. // do nothing if menu is not enabled
  151. if (!m_pMenu->IsEnabled())
  152. {
  153. return;
  154. }
  155. // force the menu to compute required width/height
  156. m_pMenu->PerformLayout();
  157. // Now position it so it can fit in the workspace
  158. m_pMenu->PositionRelativeToPanel(this, m_iDirection, _openOffsetY );
  159. // make sure we're at the top of the draw order (and therefore our children as well)
  160. MoveToFront();
  161. // notify
  162. OnShowMenu(m_pMenu);
  163. // keep the button depressed
  164. BaseClass::ForceDepressed(true);
  165. // show the menu
  166. m_pMenu->SetVisible(true);
  167. // bring to focus
  168. m_pMenu->RequestFocus();
  169. }
  170. //-----------------------------------------------------------------------------
  171. // Purpose:
  172. //-----------------------------------------------------------------------------
  173. void MenuButton::OnKeyCodeTyped(KeyCode code)
  174. {
  175. bool shift = (input()->IsKeyDown(KEY_LSHIFT) || input()->IsKeyDown(KEY_RSHIFT));
  176. bool ctrl = (input()->IsKeyDown(KEY_LCONTROL) || input()->IsKeyDown(KEY_RCONTROL));
  177. bool alt = (input()->IsKeyDown(KEY_LALT) || input()->IsKeyDown(KEY_RALT));
  178. if (!shift && !ctrl && !alt)
  179. {
  180. switch (code)
  181. {
  182. case KEY_ENTER:
  183. {
  184. if ( !IsDropMenuButtonStyle() )
  185. {
  186. DoClick();
  187. }
  188. break;
  189. }
  190. }
  191. }
  192. BaseClass::OnKeyCodeTyped(code);
  193. }
  194. //-----------------------------------------------------------------------------
  195. // Purpose:
  196. //-----------------------------------------------------------------------------
  197. void MenuButton::OnCursorEntered()
  198. {
  199. Button::OnCursorEntered();
  200. // post a message to the parent menu.
  201. // forward the message on to the parent of this menu.
  202. KeyValues *msg = new KeyValues ("CursorEnteredMenuButton");
  203. // tell the parent this menuitem is the one that was entered so it can open the menu if it wants
  204. msg->SetInt("VPanel", GetVPanel());
  205. ivgui()->PostMessage(GetVParent(), msg, NULL);
  206. }
  207. // This style is like the IE "back" button where the left side acts like a regular button, the the right side has a little
  208. // combo box dropdown indicator and presents and submenu
  209. void MenuButton::SetDropMenuButtonStyle( bool state )
  210. {
  211. bool changed = m_bDropMenuButtonStyle != state;
  212. m_bDropMenuButtonStyle = state;
  213. if ( !changed )
  214. return;
  215. if ( state )
  216. {
  217. m_pDropMenuImage = new TextImage( "u" );
  218. IScheme *pScheme = scheme()->GetIScheme( GetScheme() );
  219. m_pDropMenuImage->SetFont(pScheme->GetFont("Marlett", IsProportional()));
  220. // m_pDropMenuImage->SetContentAlignment(Label::a_west);
  221. // m_pDropMenuImage->SetTextInset(3, 0);
  222. m_nImageIndex = AddImage( m_pDropMenuImage, 0 );
  223. }
  224. else
  225. {
  226. ResetToSimpleTextImage();
  227. delete m_pDropMenuImage;
  228. m_pDropMenuImage = NULL;
  229. m_nImageIndex = -1;
  230. }
  231. }
  232. void MenuButton::ApplySchemeSettings( IScheme *pScheme )
  233. {
  234. BaseClass::ApplySchemeSettings( pScheme );
  235. if ( m_pDropMenuImage )
  236. {
  237. SetImageAtIndex( 1, m_pDropMenuImage, 0 );
  238. }
  239. }
  240. void MenuButton::PerformLayout()
  241. {
  242. BaseClass::PerformLayout();
  243. if ( !IsDropMenuButtonStyle() )
  244. return;
  245. Assert( m_nImageIndex >= 0 );
  246. if ( m_nImageIndex < 0 || !m_pDropMenuImage )
  247. return;
  248. int w, h;
  249. GetSize( w, h );
  250. int contentW, contentH;
  251. m_pDropMenuImage->ResizeImageToContent();
  252. m_pDropMenuImage->GetContentSize( contentW, contentH );
  253. SetImageBounds( m_nImageIndex, w - contentW - 2, contentW );
  254. }
  255. bool MenuButton::IsDropMenuButtonStyle() const
  256. {
  257. return m_bDropMenuButtonStyle;
  258. }
  259. void MenuButton::Paint(void)
  260. {
  261. BaseClass::Paint();
  262. if ( !IsDropMenuButtonStyle() )
  263. return;
  264. int contentW, contentH;
  265. m_pDropMenuImage->GetContentSize( contentW, contentH );
  266. m_pDropMenuImage->SetColor( IsEnabled() ? GetButtonFgColor() : GetDisabledFgColor1() );
  267. int drawX = GetWide() - contentW - 2;
  268. surface()->DrawSetColor( IsEnabled() ? GetButtonFgColor() : GetDisabledFgColor1() );
  269. surface()->DrawFilledRect( drawX, 3, drawX + 1, GetTall() - 3 );
  270. }
  271. void MenuButton::OnCursorMoved( int x, int y )
  272. {
  273. BaseClass::OnCursorMoved( x, y );
  274. if ( !IsDropMenuButtonStyle() )
  275. return;
  276. int contentW, contentH;
  277. m_pDropMenuImage->GetContentSize( contentW, contentH );
  278. int drawX = GetWide() - contentW - 2;
  279. if ( x <= drawX || !OnCheckMenuItemCount() )
  280. {
  281. SetButtonActivationType(ACTIVATE_ONPRESSEDANDRELEASED);
  282. SetUseCaptureMouse(true);
  283. }
  284. else
  285. {
  286. SetButtonActivationType(ACTIVATE_ONPRESSED);
  287. SetUseCaptureMouse(false);
  288. }
  289. }
  290. Menu *MenuButton::GetMenu()
  291. {
  292. Assert( m_pMenu );
  293. return m_pMenu;
  294. }