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.

311 lines
11KB

  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. #ifndef PROJUCER_LOGINFORM_H_INCLUDED
  18. #define PROJUCER_LOGINFORM_H_INCLUDED
  19. class LoginForm : public Component,
  20. public ButtonListener,
  21. private TextEditor::Listener,
  22. private ProjucerLicences::LoginCallback
  23. {
  24. public:
  25. LoginForm()
  26. : cancelButton (TRANS("Cancel")),
  27. loginButton (TRANS("Login")),
  28. registerButton (TRANS("Register")),
  29. userIDEditor ("User ID text editor"),
  30. passwordEditor ("Password TextEditor", juce_wchar (0x2022)),
  31. userIDLabel ("User-ID Label", TRANS("Username")),
  32. passwordLabel ("Password Label", TRANS("Password")),
  33. errorLabel ("Error Label", String()),
  34. rememberLoginCheckbox (TRANS("Remember login")),
  35. forgotPasswordButton (TRANS("Forgotten your password?"),
  36. URL (getServerURL() + "reset_password?referer=projucer")),
  37. rememberLogin (true)
  38. {
  39. setLookAndFeel (&lookAndFeel);
  40. ScopedPointer<XmlElement> svg (XmlDocument::parse (BinaryData::projucer_login_bg_svg));
  41. backgroundImage = Drawable::createFromSVG (*svg);
  42. initialiseTextField (passwordEditor, passwordLabel);
  43. addAndMakeVisible (passwordEditor);
  44. initialiseTextField (userIDEditor, userIDLabel);
  45. addAndMakeVisible (userIDEditor);
  46. String userName = ProjucerLicences::getInstance()->getLoginName();
  47. userIDEditor.setText (userName.isEmpty() ? getLastUserName() : userName);
  48. initialiseLabel (errorLabel, Font::plain, ProjucerDialogLookAndFeel::getErrorTextColour());
  49. addChildComponent (errorLabel);
  50. addChildComponent (spinner);
  51. rememberLoginCheckbox.setColour (ToggleButton::textColourId, Colours::white);
  52. rememberLoginCheckbox.setColour (TextEditor::focusedOutlineColourId, Colours::transparentBlack);
  53. rememberLoginCheckbox.setToggleState (rememberLogin, dontSendNotification);
  54. addAndMakeVisible (rememberLoginCheckbox);
  55. rememberLoginCheckbox.addListener (this);
  56. forgotPasswordButton.setColour (HyperlinkButton::textColourId, Colours::white);
  57. forgotPasswordButton.setFont (ProjucerDialogLookAndFeel::getDialogFont().withHeight (lookAndFeel.labelFontSize), false, Justification::topLeft);
  58. addAndMakeVisible (forgotPasswordButton);
  59. initialiseButton (loginButton, KeyPress::returnKey);
  60. addAndMakeVisible (loginButton);
  61. initialiseButton (registerButton);
  62. addAndMakeVisible (registerButton);
  63. initialiseButton (cancelButton, KeyPress::escapeKey);
  64. addAndMakeVisible (cancelButton);
  65. cancelButton.getProperties().set ("isSecondaryButton", true);
  66. centreWithSize (425, 685);
  67. }
  68. ~LoginForm()
  69. {
  70. ProjucerApplication::getApp().hideLoginForm();
  71. }
  72. //==============================================================================
  73. void paint (Graphics& g) override
  74. {
  75. g.fillAll (Colour (0xff4d4d4d));
  76. g.setColour (Colours::black);
  77. backgroundImage->drawWithin (g, getLocalBounds().toFloat(), RectanglePlacement::centred, 1.0f);
  78. }
  79. void resized() override
  80. {
  81. const int xMargin = 81;
  82. const int yMargin = 132;
  83. const int labelHeight = 24;
  84. const int textFieldHeight = 33;
  85. Rectangle<int> r = getLocalBounds().reduced (xMargin, yMargin);
  86. r.setWidth (r.getWidth() + 1);
  87. Point<int> labelOffset = Point<int> (-6, 4);
  88. userIDLabel.setBounds (r.removeFromTop (labelHeight) + labelOffset);
  89. userIDEditor.setBounds (r.removeFromTop (textFieldHeight));
  90. passwordLabel.setBounds (r.removeFromTop (labelHeight) + labelOffset);
  91. passwordEditor.setBounds (r.removeFromTop (textFieldHeight));
  92. r.removeFromTop (6);
  93. rememberLoginCheckbox.setBounds (r.removeFromTop (labelHeight) + Point<int> (-4, 0));
  94. r.removeFromTop (8);
  95. errorLabel.setBounds (r.removeFromTop (43).withTrimmedLeft (15));
  96. spinner.setBounds (errorLabel.getBounds().withSizeKeepingCentre (20, 20) + Point<int> (-7, -10));
  97. const int buttonHeight = 40;
  98. const int buttonMargin = 13;
  99. loginButton.setBounds (r.removeFromTop (buttonHeight));
  100. r.removeFromTop (buttonMargin);
  101. registerButton.setBounds (r.withHeight (buttonHeight).removeFromLeft ((r.getWidth() - buttonMargin) / 2));
  102. cancelButton.setBounds (r.withHeight (buttonHeight).removeFromRight ((r.getWidth() - buttonMargin) / 2));
  103. r.removeFromTop (45);
  104. forgotPasswordButton.setBounds (r.withHeight (labelHeight) + Point<int> (-2, 0));
  105. }
  106. private:
  107. //==============================================================================
  108. struct Spinner : public Component,
  109. private Timer
  110. {
  111. Spinner()
  112. {
  113. setInterceptsMouseClicks (false, false);
  114. }
  115. void paint (Graphics& g) override
  116. {
  117. getLookAndFeel().drawSpinningWaitAnimation (g, Colours::white, 0, 0, getWidth(), getHeight());
  118. startTimer (50);
  119. }
  120. void timerCallback() override
  121. {
  122. if (isVisible())
  123. repaint();
  124. else
  125. stopTimer();
  126. }
  127. };
  128. //==============================================================================
  129. void initialiseTextField (TextEditor& textField, Label& associatedLabel)
  130. {
  131. textField.setColour (TextEditor::focusedOutlineColourId, Colours::transparentWhite);
  132. textField.setColour (TextEditor::highlightColourId, ProjucerDialogLookAndFeel::getErrorTextColour());
  133. textField.setFont (ProjucerDialogLookAndFeel::getDialogFont().withHeight (17));
  134. textField.addListener (this);
  135. associatedLabel.setColour (Label::textColourId, Colours::white);
  136. addAndMakeVisible (associatedLabel);
  137. }
  138. void initialiseButton (TextButton& button, const int associatedKeyPress = 0)
  139. {
  140. if (associatedKeyPress != 0)
  141. button.addShortcut (KeyPress (associatedKeyPress));
  142. button.addListener (this);
  143. }
  144. void initialiseLabel (Label& label, Font::FontStyleFlags fontFlags, Colour textColour)
  145. {
  146. label.setFont (Font (15.0f, fontFlags));
  147. label.setJustificationType (Justification::topLeft);
  148. label.setColour (Label::textColourId, textColour);
  149. }
  150. //==============================================================================
  151. void buttonClicked (Button* button) override
  152. {
  153. if (button == &cancelButton) cancelButtonClicked();
  154. if (button == &loginButton) loginButtonClicked();
  155. if (button == &registerButton) registerButtonClicked();
  156. if (button == &rememberLoginCheckbox) rememberLoginCheckboxClicked();
  157. }
  158. void cancelButtonClicked()
  159. {
  160. if (DialogWindow* parentDialog = findParentComponentOfClass<DialogWindow>())
  161. parentDialog->exitModalState (-1);
  162. }
  163. void loginButtonClicked()
  164. {
  165. loginName = userIDEditor.getText();
  166. getGlobalProperties().setValue ("lastUserName", loginName);
  167. password = passwordEditor.getText();
  168. if (! isValidEmail (loginName) || password.isEmpty())
  169. {
  170. handleInvalidLogin();
  171. return;
  172. }
  173. loginButton.setEnabled (false);
  174. cancelButton.setEnabled (false);
  175. registerButton.setEnabled (false);
  176. errorLabel.setVisible (false);
  177. spinner.setVisible (true);
  178. ProjucerLicences::getInstance()->login (loginName, password, rememberLogin, this);
  179. }
  180. void registerButtonClicked()
  181. {
  182. URL (getServerURL() + "projucer_trial").launchInDefaultBrowser();
  183. }
  184. void textEditorReturnKeyPressed (TextEditor&) override
  185. {
  186. loginButtonClicked();
  187. }
  188. void rememberLoginCheckboxClicked()
  189. {
  190. rememberLogin = rememberLoginCheckbox.getToggleState();
  191. }
  192. String getLastUserName() const
  193. {
  194. return getGlobalProperties().getValue ("lastUserName");
  195. }
  196. void handleInvalidLogin()
  197. {
  198. if (!isValidEmail (loginName))
  199. loginError (TRANS ("Please enter a valid e-mail address"), true);
  200. if (password.isEmpty())
  201. loginError (TRANS ("Please specify a valid password"), false);
  202. }
  203. bool isValidEmail (const String& email)
  204. {
  205. return email.isNotEmpty();
  206. }
  207. void loginError (const String& errorMessage, bool hiliteUserID) override
  208. {
  209. spinner.setVisible (false);
  210. errorLabel.setText (errorMessage, dontSendNotification);
  211. errorLabel.setVisible (true);
  212. TextEditor& field = hiliteUserID ? userIDEditor : passwordEditor;
  213. field.setColour (TextEditor::focusedOutlineColourId, Colour (0x84F08080));
  214. field.toFront (true);
  215. loginButton.setEnabled (true);
  216. cancelButton.setEnabled (true);
  217. registerButton.setEnabled (true);
  218. ProjucerApplication::getApp().updateAllBuildTabs();
  219. }
  220. void loginSuccess (const String& username, const String& apiKey) override
  221. {
  222. ignoreUnused (username, apiKey);
  223. spinner.setVisible (false);
  224. if (DialogWindow* parentDialog = findParentComponentOfClass<DialogWindow>())
  225. {
  226. parentDialog->exitModalState (0);
  227. ProjucerApplication::getApp().updateAllBuildTabs();
  228. }
  229. }
  230. TextButton cancelButton, loginButton, registerButton;
  231. TextEditor userIDEditor, passwordEditor;
  232. Label userIDLabel, passwordLabel, errorLabel;
  233. ToggleButton rememberLoginCheckbox;
  234. HyperlinkButton forgotPasswordButton;
  235. Spinner spinner;
  236. String loginName, password;
  237. bool rememberLogin;
  238. ScopedPointer<Drawable> backgroundImage;
  239. ProjucerDialogLookAndFeel lookAndFeel;
  240. static String getServerURL() { return "https://my.roli.com/"; }
  241. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LoginForm)
  242. };
  243. #endif // PROJUCER_LOGINFORM_H_INCLUDED