The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
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.

671 lines
26KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2015 - ROLI Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. #include "JuceDemoHeader.h"
  18. //==============================================================================
  19. struct AlphabeticDemoSorter
  20. {
  21. static int compareElements (const JuceDemoTypeBase* first, const JuceDemoTypeBase* second)
  22. {
  23. return first->name.compare (second->name);
  24. }
  25. };
  26. JuceDemoTypeBase::JuceDemoTypeBase (const String& demoName) : name (demoName)
  27. {
  28. AlphabeticDemoSorter sorter;
  29. getDemoTypeList().addSorted (sorter, this);
  30. }
  31. JuceDemoTypeBase::~JuceDemoTypeBase()
  32. {
  33. getDemoTypeList().removeFirstMatchingValue (this);
  34. }
  35. Array<JuceDemoTypeBase*>& JuceDemoTypeBase::getDemoTypeList()
  36. {
  37. static Array<JuceDemoTypeBase*> list;
  38. return list;
  39. }
  40. //==============================================================================
  41. #if JUCE_WINDOWS || JUCE_LINUX || JUCE_MAC
  42. // Just add a simple icon to the Window system tray area or Mac menu bar..
  43. class DemoTaskbarComponent : public SystemTrayIconComponent,
  44. private Timer
  45. {
  46. public:
  47. DemoTaskbarComponent()
  48. {
  49. setIconImage (ImageCache::getFromMemory (BinaryData::juce_icon_png, BinaryData::juce_icon_pngSize));
  50. setIconTooltip ("Juce Demo App!");
  51. }
  52. void mouseDown (const MouseEvent&) override
  53. {
  54. // On OSX, there can be problems launching a menu when we're not the foreground
  55. // process, so just in case, we'll first make our process active, and then use a
  56. // timer to wait a moment before opening our menu, which gives the OS some time to
  57. // get its act together and bring our windows to the front.
  58. Process::makeForegroundProcess();
  59. startTimer (50);
  60. }
  61. // This is invoked when the menu is clicked or dismissed
  62. static void menuInvocationCallback (int chosenItemID, DemoTaskbarComponent*)
  63. {
  64. if (chosenItemID == 1)
  65. JUCEApplication::getInstance()->systemRequestedQuit();
  66. }
  67. private:
  68. void timerCallback() override
  69. {
  70. stopTimer();
  71. PopupMenu m;
  72. m.addItem (1, "Quit the Juce demo");
  73. // It's always better to open menus asynchronously when possible.
  74. m.showMenuAsync (PopupMenu::Options(),
  75. ModalCallbackFunction::forComponent (menuInvocationCallback, this));
  76. }
  77. };
  78. #endif
  79. bool juceDemoRepaintDebuggingActive = false;
  80. //==============================================================================
  81. class ContentComponent : public Component,
  82. public ListBoxModel,
  83. public ApplicationCommandTarget
  84. {
  85. public:
  86. ContentComponent()
  87. {
  88. // set lookAndFeel colour properties
  89. lookAndFeelV3.setColour (Label::textColourId, Colours::white);
  90. lookAndFeelV3.setColour (Label::textColourId, Colours::white);
  91. lookAndFeelV3.setColour (ToggleButton::textColourId, Colours::white);
  92. LookAndFeel::setDefaultLookAndFeel (&lookAndFeelV3);
  93. demoList.setModel (this);
  94. demoList.setColour (ListBox::backgroundColourId, Colour::greyLevel (0.2f));
  95. demoList.selectRow (0);
  96. addAndMakeVisible (demoList);
  97. }
  98. void clearCurrentDemo()
  99. {
  100. currentDemo = nullptr;
  101. }
  102. void resized() override
  103. {
  104. Rectangle<int> r (getLocalBounds());
  105. if (r.getWidth() > 600)
  106. {
  107. demoList.setBounds (r.removeFromLeft (210));
  108. demoList.setRowHeight (20);
  109. }
  110. else
  111. {
  112. demoList.setBounds (r.removeFromLeft (130));
  113. demoList.setRowHeight (30);
  114. }
  115. if (currentDemo != nullptr)
  116. currentDemo->setBounds (r);
  117. }
  118. int getNumRows() override
  119. {
  120. return JuceDemoTypeBase::getDemoTypeList().size();
  121. }
  122. void paintListBoxItem (int rowNumber, Graphics& g, int width, int height, bool rowIsSelected) override
  123. {
  124. if (rowIsSelected)
  125. g.fillAll (Colours::deepskyblue);
  126. if (JuceDemoTypeBase* type = JuceDemoTypeBase::getDemoTypeList() [rowNumber])
  127. {
  128. String name (type->name.trimCharactersAtStart ("0123456789").trimStart());
  129. AttributedString a;
  130. a.setJustification (Justification::centredLeft);
  131. String category;
  132. if (name.containsChar (':'))
  133. {
  134. category = name.upToFirstOccurrenceOf (":", true, false);
  135. name = name.fromFirstOccurrenceOf (":", false, false).trim();
  136. if (height > 20)
  137. category << "\n";
  138. else
  139. category << " ";
  140. }
  141. if (category.isNotEmpty())
  142. a.append (category, Font (10.0f), Colour::greyLevel (0.5f));
  143. a.append (name, Font (13.0f), Colours::white.withAlpha (0.9f));
  144. a.draw (g, Rectangle<int> (width + 10, height).reduced (6, 0).toFloat());
  145. }
  146. }
  147. void selectedRowsChanged (int lastRowSelected) override
  148. {
  149. if (JuceDemoTypeBase* selectedDemoType = JuceDemoTypeBase::getDemoTypeList() [lastRowSelected])
  150. {
  151. currentDemo = nullptr;
  152. addAndMakeVisible (currentDemo = selectedDemoType->createComponent());
  153. currentDemo->setName (selectedDemoType->name);
  154. resized();
  155. }
  156. }
  157. MouseCursor getMouseCursorForRow (int /*row*/) override
  158. {
  159. return MouseCursor::PointingHandCursor;
  160. }
  161. int getCurrentPageIndex() const noexcept
  162. {
  163. if (currentDemo == nullptr)
  164. return -1;
  165. Array<JuceDemoTypeBase*>& demos (JuceDemoTypeBase::getDemoTypeList());
  166. for (int i = demos.size(); --i >= 0;)
  167. if (demos.getUnchecked (i)->name == currentDemo->getName())
  168. return i;
  169. return -1;
  170. }
  171. void moveDemoPages (int numPagesToMove)
  172. {
  173. const int newIndex = negativeAwareModulo (getCurrentPageIndex() + numPagesToMove,
  174. JuceDemoTypeBase::getDemoTypeList().size());
  175. demoList.selectRow (newIndex);
  176. // we have to go through our demo list here or it won't be updated to reflect the current demo
  177. }
  178. bool isShowingOpenGLDemo() const
  179. {
  180. return currentDemo != nullptr
  181. && currentDemo->getName().contains ("OpenGL")
  182. && ! isShowingOpenGL2DDemo();
  183. }
  184. bool isShowingOpenGL2DDemo() const
  185. {
  186. return currentDemo != nullptr && currentDemo->getName().contains ("OpenGL 2D");
  187. }
  188. private:
  189. ListBox demoList;
  190. ScopedPointer<Component> currentDemo;
  191. LookAndFeel_V1 lookAndFeelV1;
  192. LookAndFeel_V2 lookAndFeelV2;
  193. LookAndFeel_V3 lookAndFeelV3;
  194. //==============================================================================
  195. // The following methods implement the ApplicationCommandTarget interface, allowing
  196. // this window to publish a set of actions it can perform, and which can be mapped
  197. // onto menus, keypresses, etc.
  198. ApplicationCommandTarget* getNextCommandTarget() override
  199. {
  200. // this will return the next parent component that is an ApplicationCommandTarget (in this
  201. // case, there probably isn't one, but it's best to use this method in your own apps).
  202. return findFirstTargetParentComponent();
  203. }
  204. void getAllCommands (Array<CommandID>& commands) override
  205. {
  206. // this returns the set of all commands that this target can perform..
  207. const CommandID ids[] = { MainAppWindow::showPreviousDemo,
  208. MainAppWindow::showNextDemo,
  209. MainAppWindow::welcome,
  210. MainAppWindow::componentsAnimation,
  211. MainAppWindow::componentsDialogBoxes,
  212. MainAppWindow::componentsKeyMappings,
  213. MainAppWindow::componentsMDI,
  214. MainAppWindow::componentsPropertyEditors,
  215. MainAppWindow::componentsTransforms,
  216. MainAppWindow::componentsWebBrowsers,
  217. MainAppWindow::componentsWidgets,
  218. MainAppWindow::useLookAndFeelV1,
  219. MainAppWindow::useLookAndFeelV2,
  220. MainAppWindow::useLookAndFeelV3,
  221. MainAppWindow::toggleRepaintDebugging,
  222. #if ! JUCE_LINUX
  223. MainAppWindow::goToKioskMode,
  224. #endif
  225. MainAppWindow::useNativeTitleBar
  226. };
  227. commands.addArray (ids, numElementsInArray (ids));
  228. const CommandID engineIDs[] = { MainAppWindow::renderingEngineOne,
  229. MainAppWindow::renderingEngineTwo,
  230. MainAppWindow::renderingEngineThree };
  231. StringArray renderingEngines (MainAppWindow::getMainAppWindow()->getRenderingEngines());
  232. commands.addArray (engineIDs, renderingEngines.size());
  233. }
  234. void getCommandInfo (CommandID commandID, ApplicationCommandInfo& result) override
  235. {
  236. const String generalCategory ("General");
  237. const String demosCategory ("Demos");
  238. switch (commandID)
  239. {
  240. case MainAppWindow::showPreviousDemo:
  241. result.setInfo ("Previous Demo", "Shows the previous demo in the list", demosCategory, 0);
  242. result.addDefaultKeypress ('-', ModifierKeys::commandModifier);
  243. break;
  244. case MainAppWindow::showNextDemo:
  245. result.setInfo ("Next Demo", "Shows the next demo in the list", demosCategory, 0);
  246. result.addDefaultKeypress ('=', ModifierKeys::commandModifier);
  247. break;
  248. case MainAppWindow::welcome:
  249. result.setInfo ("Welcome Demo", "Shows the 'Welcome' demo", demosCategory, 0);
  250. result.addDefaultKeypress ('1', ModifierKeys::commandModifier);
  251. break;
  252. case MainAppWindow::componentsAnimation:
  253. result.setInfo ("Animation Demo", "Shows the 'Animation' demo", demosCategory, 0);
  254. result.addDefaultKeypress ('2', ModifierKeys::commandModifier);
  255. break;
  256. case MainAppWindow::componentsDialogBoxes:
  257. result.setInfo ("Dialog Boxes Demo", "Shows the 'Dialog Boxes' demo", demosCategory, 0);
  258. result.addDefaultKeypress ('3', ModifierKeys::commandModifier);
  259. break;
  260. case MainAppWindow::componentsKeyMappings:
  261. result.setInfo ("Key Mappings Demo", "Shows the 'Key Mappings' demo", demosCategory, 0);
  262. result.addDefaultKeypress ('4', ModifierKeys::commandModifier);
  263. break;
  264. case MainAppWindow::componentsMDI:
  265. result.setInfo ("Multi-Document Demo", "Shows the 'Multi-Document' demo", demosCategory, 0);
  266. result.addDefaultKeypress ('5', ModifierKeys::commandModifier);
  267. break;
  268. case MainAppWindow::componentsPropertyEditors:
  269. result.setInfo ("Property Editor Demo", "Shows the 'Property Editor' demo", demosCategory, 0);
  270. result.addDefaultKeypress ('6', ModifierKeys::commandModifier);
  271. break;
  272. case MainAppWindow::componentsTransforms:
  273. result.setInfo ("Component Transforms Demo", "Shows the 'Transforms' demo", demosCategory, 0);
  274. result.addDefaultKeypress ('7', ModifierKeys::commandModifier);
  275. break;
  276. case MainAppWindow::componentsWebBrowsers:
  277. result.setInfo ("Web Browser Demo", "Shows the 'Web Browser' demo", demosCategory, 0);
  278. result.addDefaultKeypress ('8', ModifierKeys::commandModifier);
  279. break;
  280. case MainAppWindow::componentsWidgets:
  281. result.setInfo ("Widgets Demo", "Shows the 'Widgets' demo", demosCategory, 0);
  282. result.addDefaultKeypress ('9', ModifierKeys::commandModifier);
  283. break;
  284. case MainAppWindow::renderingEngineOne:
  285. case MainAppWindow::renderingEngineTwo:
  286. case MainAppWindow::renderingEngineThree:
  287. {
  288. MainAppWindow& mainWindow = *MainAppWindow::getMainAppWindow();
  289. const StringArray engines (mainWindow.getRenderingEngines());
  290. const int index = commandID - MainAppWindow::renderingEngineOne;
  291. result.setInfo ("Use " + engines[index], "Uses the " + engines[index] + " engine to render the UI", generalCategory, 0);
  292. result.setTicked (mainWindow.getActiveRenderingEngine() == index);
  293. result.addDefaultKeypress ('1' + index, ModifierKeys::noModifiers);
  294. break;
  295. }
  296. case MainAppWindow::useLookAndFeelV1:
  297. result.setInfo ("Use LookAndFeel_V1", String::empty, generalCategory, 0);
  298. result.addDefaultKeypress ('i', ModifierKeys::commandModifier);
  299. result.setTicked (isLookAndFeelSelected<LookAndFeel_V1>());
  300. break;
  301. case MainAppWindow::useLookAndFeelV2:
  302. result.setInfo ("Use LookAndFeel_V2", String::empty, generalCategory, 0);
  303. result.addDefaultKeypress ('o', ModifierKeys::commandModifier);
  304. result.setTicked (isLookAndFeelSelected<LookAndFeel_V2>());
  305. break;
  306. case MainAppWindow::useLookAndFeelV3:
  307. result.setInfo ("Use LookAndFeel_V3", String::empty, generalCategory, 0);
  308. result.addDefaultKeypress ('p', ModifierKeys::commandModifier);
  309. result.setTicked (isLookAndFeelSelected<LookAndFeel_V3>());
  310. break;
  311. case MainAppWindow::toggleRepaintDebugging:
  312. result.setInfo ("Toggle repaint display", String::empty, generalCategory, 0);
  313. result.addDefaultKeypress ('r', ModifierKeys());
  314. result.setTicked (juceDemoRepaintDebuggingActive);
  315. break;
  316. case MainAppWindow::useNativeTitleBar:
  317. {
  318. result.setInfo ("Use native window title bar", String::empty, generalCategory, 0);
  319. result.addDefaultKeypress ('n', ModifierKeys::commandModifier);
  320. bool nativeTitlebar = false;
  321. if (MainAppWindow* map = MainAppWindow::getMainAppWindow())
  322. nativeTitlebar = map->isUsingNativeTitleBar();
  323. result.setTicked (nativeTitlebar);
  324. break;
  325. }
  326. #if ! JUCE_LINUX
  327. case MainAppWindow::goToKioskMode:
  328. result.setInfo ("Show full-screen kiosk mode", String::empty, generalCategory, 0);
  329. result.addDefaultKeypress ('f', ModifierKeys::commandModifier);
  330. result.setTicked (Desktop::getInstance().getKioskModeComponent() != 0);
  331. break;
  332. #endif
  333. default:
  334. break;
  335. }
  336. }
  337. bool perform (const InvocationInfo& info) override
  338. {
  339. MainAppWindow* mainWindow = MainAppWindow::getMainAppWindow();
  340. if (mainWindow == nullptr)
  341. return true;
  342. switch (info.commandID)
  343. {
  344. case MainAppWindow::showPreviousDemo: moveDemoPages (-1); break;
  345. case MainAppWindow::showNextDemo: moveDemoPages ( 1); break;
  346. case MainAppWindow::welcome:
  347. case MainAppWindow::componentsAnimation:
  348. case MainAppWindow::componentsDialogBoxes:
  349. case MainAppWindow::componentsKeyMappings:
  350. case MainAppWindow::componentsMDI:
  351. case MainAppWindow::componentsPropertyEditors:
  352. case MainAppWindow::componentsTransforms:
  353. case MainAppWindow::componentsWebBrowsers:
  354. case MainAppWindow::componentsWidgets:
  355. demoList.selectRow (info.commandID - MainAppWindow::welcome);
  356. break;
  357. case MainAppWindow::renderingEngineOne:
  358. case MainAppWindow::renderingEngineTwo:
  359. case MainAppWindow::renderingEngineThree:
  360. mainWindow->setRenderingEngine (info.commandID - MainAppWindow::renderingEngineOne);
  361. break;
  362. case MainAppWindow::useLookAndFeelV1: LookAndFeel::setDefaultLookAndFeel (&lookAndFeelV1); break;
  363. case MainAppWindow::useLookAndFeelV2: LookAndFeel::setDefaultLookAndFeel (&lookAndFeelV2); break;
  364. case MainAppWindow::useLookAndFeelV3: LookAndFeel::setDefaultLookAndFeel (&lookAndFeelV3); break;
  365. case MainAppWindow::toggleRepaintDebugging:
  366. juceDemoRepaintDebuggingActive = ! juceDemoRepaintDebuggingActive;
  367. mainWindow->repaint();
  368. break;
  369. case MainAppWindow::useNativeTitleBar:
  370. mainWindow->setUsingNativeTitleBar (! mainWindow->isUsingNativeTitleBar());
  371. break;
  372. #if ! JUCE_LINUX
  373. case MainAppWindow::goToKioskMode:
  374. {
  375. Desktop& desktop = Desktop::getInstance();
  376. if (desktop.getKioskModeComponent() == nullptr)
  377. desktop.setKioskModeComponent (getTopLevelComponent());
  378. else
  379. desktop.setKioskModeComponent (nullptr);
  380. break;
  381. }
  382. #endif
  383. default:
  384. return false;
  385. }
  386. return true;
  387. }
  388. template <typename LookAndFeelType>
  389. bool isLookAndFeelSelected()
  390. {
  391. LookAndFeel& lf = getLookAndFeel();
  392. return typeid (LookAndFeelType) == typeid (lf);
  393. }
  394. };
  395. //==============================================================================
  396. static ScopedPointer<ApplicationCommandManager> applicationCommandManager;
  397. static ScopedPointer<AudioDeviceManager> sharedAudioDeviceManager;
  398. MainAppWindow::MainAppWindow()
  399. : DocumentWindow (JUCEApplication::getInstance()->getApplicationName(),
  400. Colours::lightgrey,
  401. DocumentWindow::allButtons)
  402. {
  403. setUsingNativeTitleBar (true);
  404. setResizable (true, false);
  405. setResizeLimits (400, 400, 10000, 10000);
  406. #if JUCE_IOS || JUCE_ANDROID
  407. setFullScreen (true);
  408. #else
  409. setBounds ((int) (0.1f * getParentWidth()),
  410. (int) (0.1f * getParentHeight()),
  411. jmax (850, (int) (0.5f * getParentWidth())),
  412. jmax (600, (int) (0.7f * getParentHeight())));
  413. #endif
  414. contentComponent = new ContentComponent();
  415. setContentNonOwned (contentComponent, false);
  416. setVisible (true);
  417. // this lets the command manager use keypresses that arrive in our window to send out commands
  418. addKeyListener (getApplicationCommandManager().getKeyMappings());
  419. #if JUCE_WINDOWS || JUCE_LINUX || JUCE_MAC
  420. taskbarIcon = new DemoTaskbarComponent();
  421. #endif
  422. #if JUCE_ANDROID
  423. setOpenGLRenderingEngine();
  424. #endif
  425. triggerAsyncUpdate();
  426. }
  427. MainAppWindow::~MainAppWindow()
  428. {
  429. contentComponent->clearCurrentDemo();
  430. clearContentComponent();
  431. contentComponent = nullptr;
  432. applicationCommandManager = nullptr;
  433. sharedAudioDeviceManager = nullptr;
  434. #if JUCE_OPENGL
  435. openGLContext.detach();
  436. #endif
  437. }
  438. void MainAppWindow::closeButtonPressed()
  439. {
  440. JUCEApplication::getInstance()->systemRequestedQuit();
  441. }
  442. ApplicationCommandManager& MainAppWindow::getApplicationCommandManager()
  443. {
  444. if (applicationCommandManager == nullptr)
  445. applicationCommandManager = new ApplicationCommandManager();
  446. return *applicationCommandManager;
  447. }
  448. AudioDeviceManager& MainAppWindow::getSharedAudioDeviceManager()
  449. {
  450. if (sharedAudioDeviceManager == nullptr)
  451. {
  452. sharedAudioDeviceManager = new AudioDeviceManager();
  453. sharedAudioDeviceManager->initialise (2, 2, 0, true, String(), 0);
  454. }
  455. return *sharedAudioDeviceManager;
  456. }
  457. MainAppWindow* MainAppWindow::getMainAppWindow()
  458. {
  459. for (int i = TopLevelWindow::getNumTopLevelWindows(); --i >= 0;)
  460. if (MainAppWindow* maw = dynamic_cast<MainAppWindow*> (TopLevelWindow::getTopLevelWindow (i)))
  461. return maw;
  462. return nullptr;
  463. }
  464. void MainAppWindow::handleAsyncUpdate()
  465. {
  466. // This registers all of our commands with the command manager but has to be done after the window has
  467. // been created so we can find the number of rendering engines available
  468. ApplicationCommandManager& commandManager = MainAppWindow::getApplicationCommandManager();
  469. commandManager.registerAllCommandsForTarget (contentComponent);
  470. commandManager.registerAllCommandsForTarget (JUCEApplication::getInstance());
  471. }
  472. void MainAppWindow::showMessageBubble (const String& text)
  473. {
  474. currentBubbleMessage = new BubbleMessageComponent (500);
  475. getContentComponent()->addChildComponent (currentBubbleMessage);
  476. AttributedString attString;
  477. attString.append (text, Font (15.0f));
  478. currentBubbleMessage->showAt (Rectangle<int> (getLocalBounds().getCentreX(), 10, 1, 1),
  479. attString,
  480. 500, // numMillisecondsBeforeRemoving
  481. true, // removeWhenMouseClicked
  482. false); // deleteSelfAfterUse
  483. }
  484. static const char* openGLRendererName = "OpenGL Renderer";
  485. StringArray MainAppWindow::getRenderingEngines() const
  486. {
  487. StringArray renderingEngines;
  488. if (ComponentPeer* peer = getPeer())
  489. renderingEngines = peer->getAvailableRenderingEngines();
  490. #if JUCE_OPENGL
  491. renderingEngines.add (openGLRendererName);
  492. #endif
  493. return renderingEngines;
  494. }
  495. void MainAppWindow::setRenderingEngine (int index)
  496. {
  497. showMessageBubble (getRenderingEngines()[index]);
  498. #if JUCE_OPENGL
  499. if (getRenderingEngines()[index] == openGLRendererName
  500. && contentComponent != nullptr
  501. && ! contentComponent->isShowingOpenGLDemo())
  502. {
  503. openGLContext.attachTo (*getTopLevelComponent());
  504. return;
  505. }
  506. openGLContext.detach();
  507. #endif
  508. if (ComponentPeer* peer = getPeer())
  509. peer->setCurrentRenderingEngine (index);
  510. }
  511. void MainAppWindow::setOpenGLRenderingEngine()
  512. {
  513. setRenderingEngine (getRenderingEngines().indexOf (openGLRendererName));
  514. }
  515. int MainAppWindow::getActiveRenderingEngine() const
  516. {
  517. #if JUCE_OPENGL
  518. if (openGLContext.isAttached())
  519. return getRenderingEngines().indexOf (openGLRendererName);
  520. #endif
  521. if (ComponentPeer* peer = getPeer())
  522. return peer->getCurrentRenderingEngine();
  523. return 0;
  524. }
  525. Path MainAppWindow::getJUCELogoPath()
  526. {
  527. return Drawable::parseSVGPath (
  528. "M250,301.3c-37.2,0-67.5-30.3-67.5-67.5s30.3-67.5,67.5-67.5s67.5,30.3,67.5,67.5S287.2,301.3,250,301.3zM250,170.8c-34.7,0-63,28.3-63,63s28.3,63,63,63s63-28.3,63-63S284.7,170.8,250,170.8z"
  529. "M247.8,180.4c0-2.3-1.8-4.1-4.1-4.1c-0.2,0-0.3,0-0.5,0c-10.6,1.2-20.6,5.4-29,12c-1,0.8-1.5,1.8-1.6,2.9c-0.1,1.2,0.4,2.3,1.3,3.2l32.5,32.5c0.5,0.5,1.4,0.1,1.4-0.6V180.4z"
  530. "M303.2,231.6c1.2,0,2.3-0.4,3.1-1.2c0.9-0.9,1.3-2.1,1.1-3.3c-1.2-10.6-5.4-20.6-12-29c-0.8-1-1.9-1.6-3.2-1.6c-1.1,0-2.1,0.5-3,1.3l-32.5,32.5c-0.5,0.5-0.1,1.4,0.6,1.4L303.2,231.6z"
  531. "M287.4,191.3c-0.1-1.1-0.6-2.2-1.6-2.9c-8.4-6.6-18.4-10.8-29-12c-0.2,0-0.3,0-0.5,0c-2.3,0-4.1,1.9-4.1,4.1v46c0,0.7,0.9,1.1,1.4,0.6l32.5-32.5C287,193.6,287.5,192.5,287.4,191.3z"
  532. "M252.2,287.2c0,2.3,1.8,4.1,4.1,4.1c0.2,0,0.3,0,0.5,0c10.6-1.2,20.6-5.4,29-12c1-0.8,1.5-1.8,1.6-2.9c0.1-1.2-0.4-2.3-1.3-3.2l-32.5-32.5c-0.5-0.5-1.4-0.1-1.4,0.6V287.2z"
  533. "M292.3,271.2L292.3,271.2c1.2,0,2.4-0.6,3.2-1.6c6.6-8.4,10.8-18.4,12-29c0.1-1.2-0.3-2.4-1.1-3.3c-0.8-0.8-1.9-1.2-3.1-1.2l-45.9,0c-0.7,0-1.1,0.9-0.6,1.4l32.5,32.5C290.2,270.8,291.2,271.2,292.3,271.2z"
  534. "M207.7,196.4c-1.2,0-2.4,0.6-3.2,1.6c-6.6,8.4-10.8,18.4-12,29c-0.1,1.2,0.3,2.4,1.1,3.3c0.8,0.8,1.9,1.2,3.1,1.2l45.9,0c0.7,0,1.1-0.9,0.6-1.4l-32.5-32.5C209.8,196.8,208.8,196.4,207.7,196.4z"
  535. "M242.6,236.1l-45.9,0c-1.2,0-2.3,0.4-3.1,1.2c-0.9,0.9-1.3,2.1-1.1,3.3c1.2,10.6,5.4,20.6,12,29c0.8,1,1.9,1.6,3.2,1.6c1.1,0,2.1-0.5,3-1.3c0,0,0,0,0,0l32.5-32.5C243.7,236.9,243.4,236.1,242.6,236.1z"
  536. "M213.8,273.1L213.8,273.1c-0.9,0.9-1.3,2-1.3,3.2c0.1,1.1,0.6,2.2,1.6,2.9c8.4,6.6,18.4,10.8,29,12c0.2,0,0.3,0,0.5,0h0c1.2,0,2.3-0.5,3.1-1.4c0.7-0.8,1-1.8,1-2.9v-45.9c0-0.7-0.9-1.1-1.4-0.6l-13.9,13.9L213.8,273.1z"
  537. "M197.2,353c-4.1,0-7.4-1.5-10.4-5.4l4-3.5c2,2.6,3.9,3.6,6.4,3.6c4.4,0,7.4-3.3,7.4-8.3v-24.7h5.6v24.7C210.2,347.5,204.8,353,197.2,353z"
  538. "M232.4,353c-8.1,0-15-6-15-15.8v-22.5h5.6v22.2c0,6.6,3.9,10.8,9.5,10.8c5.6,0,9.5-4.3,9.5-10.8v-22.2h5.6v22.5C247.5,347,240.5,353,232.4,353z"
  539. "M272,353c-10.8,0-19.5-8.6-19.5-19.3c0-10.8,8.8-19.3,19.5-19.3c4.8,0,9,1.6,12.3,4.4l-3.3,4.1c-3.4-2.4-5.7-3.2-8.9-3.2c-7.7,0-13.8,6.2-13.8,14.1c0,7.9,6.1,14.1,13.8,14.1c3.1,0,5.6-1,8.8-3.2l3.3,4.1C280.1,351.9,276.4,353,272,353z"
  540. "M290.4,352.5v-37.8h22.7v5H296v11.2h16.5v5H296v11.6h17.2v5H290.4z");
  541. };