Main.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. // Framework includes
  2. #include "BsApplication.h"
  3. #include "Resources/BsResources.h"
  4. #include "Resources/BsBuiltinResources.h"
  5. #include "Material/BsMaterial.h"
  6. #include "Components/BsCCamera.h"
  7. #include "GUI/BsCGUIWidget.h"
  8. #include "GUI/BsGUIPanel.h"
  9. #include "GUI/BsGUILayoutX.h"
  10. #include "GUI/BsGUILayoutY.h"
  11. #include "GUI/BsGUILabel.h"
  12. #include "GUI/BsGUIButton.h"
  13. #include "GUI/BsGUIInputBox.h"
  14. #include "GUI/BsGUIListBox.h"
  15. #include "GUI/BsGUIToggle.h"
  16. #include "GUI/BsGUIScrollArea.h"
  17. #include "GUI/BsGUISpace.h"
  18. #include "RenderAPI/BsRenderAPI.h"
  19. #include "RenderAPI/BsRenderWindow.h"
  20. #include "Scene/BsSceneObject.h"
  21. #include "BsExampleFramework.h"
  22. #include "Image/BsSpriteTexture.h"
  23. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  24. // This example demonstrates how to set up a graphical user interface. It demoes a variety of common GUI elements, as well
  25. // as demonstrating the capability of layouts. It also shows how to customize the look of GUI elements.
  26. //
  27. // The example starts off by setting up a camera, which is required for any kind of rendering, including GUI. It then
  28. // proceeds to demonstrate a set of basic controls, while using manual positioning. It then shows how to create a custom
  29. // style and apply it to a GUI element. It follows to demonstrate the concept of layouts that automatically position
  30. // and size elements, as well as scroll areas. Finally, it demonstrates a more complex example of creating a custom style,
  31. // by creating a button with custom textures and font.
  32. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  33. namespace bs
  34. {
  35. UINT32 windowResWidth = 1280;
  36. UINT32 windowResHeight = 720;
  37. /** Set up the GUI elements and the camera. */
  38. void setUpGUI()
  39. {
  40. /************************************************************************/
  41. /* CAMERA */
  42. /************************************************************************/
  43. // In order something to render on screen we need at least one camera.
  44. // Like before, we create a new scene object at (0, 0, 0).
  45. HSceneObject sceneCameraSO = SceneObject::create("SceneCamera");
  46. // Get the primary render window we need for creating the camera.
  47. SPtr<RenderWindow> window = gApplication().getPrimaryWindow();
  48. // Add a Camera component that will output whatever it sees into that window
  49. // (You could also use a render texture or another window you created).
  50. HCamera sceneCamera = sceneCameraSO->addComponent<CCamera>();
  51. sceneCamera->getViewport()->setTarget(window);
  52. // Pick a prettier background color
  53. Color gray = Color(51/255.0f, 51/255.0f, 51/255.0f);
  54. sceneCamera->getViewport()->setClearColorValue(gray);
  55. // Let the camera know it will be used for overlay rendering only. This stops the renderer from running potentially
  56. // expensive effects that ultimately don't effect anything. It also allows us to use a linear-space color for the
  57. // camera background (normal rendering expects colors in gamma space, which is unintuitive for aspects such as
  58. // GUI).
  59. const SPtr<RenderSettings>& renderSettings = sceneCamera->getRenderSettings();
  60. renderSettings->overlayOnly = true;
  61. sceneCamera->setRenderSettings(renderSettings);
  62. /************************************************************************/
  63. /* GUI */
  64. /************************************************************************/
  65. // Add a GUIWidget component we will use for rendering the GUI
  66. HSceneObject guiSO = SceneObject::create("GUI");
  67. HGUIWidget gui = guiSO->addComponent<CGUIWidget>(sceneCamera);
  68. // Retrieve the primary panel onto which to attach GUI elements to. Panels allow free placement of elements in
  69. // them (unlike layouts), and can also have depth, meaning you can overlay multiple panels over one another.
  70. GUIPanel* mainPanel = gui->getPanel();
  71. ////////////////////// Add a variety of GUI controls /////////////////////
  72. // Clickable button with a textual label
  73. GUIButton* button = mainPanel->addNewElement<GUIButton>(HString("Click me!"));
  74. button->onClick.connect([]()
  75. {
  76. // Log a message when the user clicks the button
  77. LOGDBG("Button clicked!");
  78. });
  79. button->setPosition(10, 50);
  80. button->setSize(100, 30);
  81. // Toggleable button
  82. GUIToggle* toggle = mainPanel->addNewElement<GUIToggle>(HString(""));
  83. toggle->onToggled.connect([](bool enabled)
  84. {
  85. // Log a message when the user toggles the button
  86. if(enabled)
  87. {
  88. LOGDBG("Toggle turned on");
  89. }
  90. else
  91. {
  92. LOGDBG("Toggle turned off");
  93. }
  94. });
  95. toggle->setPosition(10, 90);
  96. // Add non-interactable label next to the toggle
  97. GUILabel* toggleLabel = mainPanel->addNewElement<GUILabel>(HString("Toggle me!"));
  98. toggleLabel->setPosition(30, 92);
  99. // Single-line box in which user can input text into
  100. GUIInputBox* inputBox = mainPanel->addNewElement<GUIInputBox>();
  101. inputBox->onValueChanged.connect([](const String& value)
  102. {
  103. // Log a message when the user enters new text in the input box
  104. LOGDBG("User entered: \"" + value + "\"");
  105. });
  106. inputBox->setText("Type in me...");
  107. inputBox->setPosition(10, 115);
  108. inputBox->setWidth(100);
  109. // List box allowing you to select one of the specified elements
  110. Vector<HString> listBoxElements =
  111. {
  112. HString("Blue"),
  113. HString("Black"),
  114. HString("Green"),
  115. HString("Orange")
  116. };
  117. GUIListBox* listBox = mainPanel->addNewElement<GUIListBox>(listBoxElements);
  118. listBox->onSelectionToggled.connect([listBoxElements](UINT32 idx, bool enabled)
  119. {
  120. // Log a message when the user selects a new element
  121. LOGDBG("User selected element: \"" + listBoxElements[idx].getValue() + "\"");
  122. });
  123. listBox->setPosition(10, 140);
  124. listBox->setWidth(100);
  125. // Add a button with an image
  126. HTexture icon = ExampleFramework::loadTexture(ExampleTexture::GUIBansheeIcon, false, false, false, false);
  127. HSpriteTexture iconSprite = SpriteTexture::create(icon);
  128. // Create a GUI content object that contains an icon to display on the button. Also an optional text and tooltip.
  129. GUIContent buttonContent(iconSprite);
  130. GUIButton* iconButton = mainPanel->addNewElement<GUIButton>(buttonContent);
  131. iconButton->setPosition(10, 170);
  132. iconButton->setSize(70, 70);
  133. /////////////////////////// Header label /////////////////////////////////
  134. // Create a custom style for a label we'll used for headers. Then add a header
  135. // for the controls we added in the previous section.
  136. // Create a new style
  137. GUIElementStyle headerLabelStyle;
  138. // Make it use a custom font with size 30
  139. headerLabelStyle.font = ExampleFramework::loadFont(ExampleFont::SegoeUISemiBold, { 24 });
  140. headerLabelStyle.fontSize = 24;
  141. // Set the default text color
  142. headerLabelStyle.normal.textColor = Color::White;
  143. // Grab the default GUI skin to which we'll append the new style to. You could also create a new GUI skin and
  144. // add the style to it, but that would also require adding default styles for all the GUI element types.
  145. HGUISkin skin = gBuiltinResources().getGUISkin();
  146. skin->setStyle("HeaderLabelStyle", headerLabelStyle);
  147. // Create and position the label
  148. GUILabel* basicControlsLbl = mainPanel->addNewElement<GUILabel>(HString("Basic controls"), "HeaderLabelStyle");
  149. basicControlsLbl->setPosition(10, 10);
  150. /////////////////////////// vertical layout /////////////////////////
  151. // Use a vertical layout to automatically position GUI elements. This is unlike above where we position and
  152. // sized all elements manually.
  153. GUILayoutY* vertLayout = mainPanel->addNewElement<GUILayoutY>();
  154. // Add five buttons to the layout
  155. for(UINT32 i = 0; i < 5; i++)
  156. {
  157. vertLayout->addNewElement<GUIButton>(HString("Click me!"));
  158. // Add a 10 pixel spacing between each button
  159. vertLayout->addNewElement<GUIFixedSpace>(10);
  160. }
  161. // Add a flexible space ensuring all the elements get pushed to the top of the layout
  162. vertLayout->addNewElement<GUIFlexibleSpace>();
  163. // Position the layout relative to the main panel, and limit width to 100 pixels
  164. vertLayout->setPosition(350, 50);
  165. vertLayout->setWidth(100);
  166. // Add a header
  167. GUILabel* vertLayoutLbl = mainPanel->addNewElement<GUILabel>(HString("Vertical layout"), "HeaderLabelStyle");
  168. vertLayoutLbl->setPosition(300, 10);
  169. ////////////////////////// Horizontal layout ///////////////////////
  170. // Use a horizontal layout to automatically position GUI elements
  171. GUILayoutX* horzLayout = mainPanel->addNewElement<GUILayoutX>();
  172. horzLayout->addNewElement<GUIFlexibleSpace>();
  173. // Add vive buttons to the layout
  174. for(UINT32 i = 0; i < 5; i++)
  175. {
  176. horzLayout->addNewElement<GUIButton>(HString("Click me!"));
  177. horzLayout->addNewElement<GUIFlexibleSpace>();
  178. }
  179. // Position the layout relative to the main panel, and limit the height to 30 pixels
  180. horzLayout->setPosition(0, 340);
  181. horzLayout->setHeight(30);
  182. // Add a header
  183. GUILabel* horzLayoutLbl = mainPanel->addNewElement<GUILabel>(HString("Horizontal layout"), "HeaderLabelStyle");
  184. horzLayoutLbl->setPosition(10, 300);
  185. //////////////////////////// Scroll area ///////////////////////
  186. // Container GUI element that allows scrolling if the number of elements inside the area are larger than the visible
  187. // area
  188. GUIScrollArea* scrollArea = mainPanel->addNewElement<GUIScrollArea>();
  189. // Scroll areas have a vertical layout we can append elements to, same as with a normal layout
  190. GUILayout& scrollLayout = scrollArea->getLayout();
  191. for(UINT32 i = 0; i < 15; i++)
  192. scrollLayout.addNewElement<GUIButton>(HString("Click me!"));
  193. scrollArea->setPosition(565, 50);
  194. scrollArea->setSize(130, 200);
  195. // Add a header
  196. GUILabel* scrollAreaLbl = mainPanel->addNewElement<GUILabel>(HString("Scroll area"), "HeaderLabelStyle");
  197. scrollAreaLbl->setPosition(550, 10);
  198. ///////////////////////////// Button using a custom style ///////////////////
  199. HTexture buttonNormalTex = ExampleFramework::loadTexture(ExampleTexture::GUIExampleButtonNormal, false, false,
  200. false, false);
  201. HTexture buttonHoverTex = ExampleFramework::loadTexture(ExampleTexture::GUIExampleButtonHover, false, false,
  202. false, false);
  203. HTexture buttonActiveTex = ExampleFramework::loadTexture(ExampleTexture::GUIExampleButtonActive, false, false,
  204. false, false);
  205. // Create a new style
  206. GUIElementStyle customBtnStyle;
  207. // Set custom textures for 'normal', 'hover' and 'active' states of the button
  208. customBtnStyle.normal.texture = SpriteTexture::create(buttonNormalTex);
  209. customBtnStyle.hover.texture = SpriteTexture::create(buttonHoverTex);
  210. customBtnStyle.active.texture = SpriteTexture::create(buttonActiveTex);
  211. // Button size is fixed, and should match the size of the texture's we're using
  212. customBtnStyle.fixedHeight = true;
  213. customBtnStyle.fixedWidth = true;
  214. customBtnStyle.width = buttonNormalTex->getProperties().getWidth();
  215. customBtnStyle.height = buttonNormalTex->getProperties().getHeight();
  216. // Make the button use a custom font for text
  217. customBtnStyle.font = ExampleFramework::loadFont(ExampleFont::SegoeUILight, { 24 });
  218. customBtnStyle.fontSize = 24;
  219. // Offset the position of the text within the button, to match the texture
  220. customBtnStyle.contentOffset.top = 20;
  221. customBtnStyle.contentOffset.left = 15;
  222. customBtnStyle.contentOffset.right = 65;
  223. skin->setStyle("CustomButtonStyle", customBtnStyle);
  224. // Create the button that uses the custom style
  225. GUIButton* customButton = mainPanel->addNewElement<GUIButton>(HString("Click me!"), "CustomButtonStyle");
  226. customButton->setPosition(800, 50);
  227. // Add a header
  228. GUILabel* customButtonLbl = mainPanel->addNewElement<GUILabel>(HString("Custom button"), "HeaderLabelStyle");
  229. customButtonLbl->setPosition(800, 10);
  230. }
  231. }
  232. /** Main entry point into the application. */
  233. #if BS_PLATFORM == BS_PLATFORM_WIN32
  234. #include <windows.h>
  235. int CALLBACK WinMain(
  236. _In_ HINSTANCE hInstance,
  237. _In_ HINSTANCE hPrevInstance,
  238. _In_ LPSTR lpCmdLine,
  239. _In_ int nCmdShow
  240. )
  241. #else
  242. int main()
  243. #endif
  244. {
  245. using namespace bs;
  246. // Initializes the application and creates a window with the specified properties
  247. VideoMode videoMode(windowResWidth, windowResHeight);
  248. Application::startUp(videoMode, "Example", false);
  249. // Load a resource manifest so previously saved Fonts can find their child Texture resources
  250. ExampleFramework::loadResourceManifest();
  251. // Set up the GUI elements
  252. setUpGUI();
  253. // Save the manifest, in case we did any asset importing during the setup stage
  254. ExampleFramework::saveResourceManifest();
  255. // Runs the main loop that does most of the work. This method will exit when user closes the main
  256. // window or exits in some other way.
  257. Application::instance().runMainLoop();
  258. // When done, clean up
  259. Application::shutDown();
  260. return 0;
  261. }