JUCE_Template/Source/UserInteraction.h

361 lines
14 KiB
Objective-C

#ifndef USER_INTERACTION_H
#define USER_INTERACTION_H
#include "JuceHeader.h"
/**
@file UserInteraction.h
@author DustVoice
@class UserInteraction
A Wrapper class for AlertWindows that enables the caller to quickly and efficiently interact with the user,
without the hassle of handling the AlertWindow itself.
*/
class UserInteraction
{
public:
/**
@returns Button Colour for the default option, for example the "OK" button.
*/
static Colour getDefaultButtonColour()
{
return Colour(static_cast<uint8>(0x00), static_cast<uint8>(0xb0 - 40), static_cast<uint8>(0xb9 - 40), static_cast<uint8>(0xff));
}
/**
@returns The normal Button Colour
*/
static Colour getStandardButtonColour()
{
const Colour buttonColour = TextButton().findColour(TextButton::ColourIds::buttonColourId);
return Colour(buttonColour.getRed(), buttonColour.getGreen(), buttonColour.getBlue());
}
/**
@class UserInputTextFieldMeta
Holds metadata for custom TextFields in an AlertWindow.
User input can be obtained by calling getResult().
@see showUserInput()
*/
struct UserInputTextFieldMeta
{
public:
UserInputTextFieldMeta(const String& name, const String& initialContents = String(), const String& onScreenLabel = String(), const bool isPasswordBox = false) : name(name), initialContents(initialContents), onScreenLabel(onScreenLabel), isPasswordBox(isPasswordBox){};
~UserInputTextFieldMeta() = default;
UserInputTextFieldMeta(const UserInputTextFieldMeta& other) : name(other.name), initialContents(other.initialContents), onScreenLabel(other.onScreenLabel), isPasswordBox(other.isPasswordBox)
{
this->setResult(other.getResult());
}
UserInputTextFieldMeta(const UserInputTextFieldMeta&& other) noexcept : name(other.name), initialContents(other.initialContents), onScreenLabel(other.onScreenLabel), isPasswordBox(other.isPasswordBox)
{
this->setResult(other.getResult());
}
UserInputTextFieldMeta& operator=(const UserInputTextFieldMeta& other)
{
name = other.name;
initialContents = other.initialContents;
onScreenLabel = other.onScreenLabel;
isPasswordBox = other.isPasswordBox;
setResult(other.getResult());
return *this;
}
UserInputTextFieldMeta& operator=(UserInputTextFieldMeta&& other) noexcept
{
if (this != &other)
{
name = other.name;
initialContents = other.initialContents;
onScreenLabel = other.onScreenLabel;
isPasswordBox = other.isPasswordBox;
setResult(other.getResult());
}
return *this;
}
String name;
String initialContents;
String onScreenLabel;
bool isPasswordBox;
void setResult(const String& newResult) { result = newResult; }
String getResult() const { return result; }
private:
String result;
};
/**
Displays a little message box with a single button.
@param title The title of the msgBox
@param message Show the user a message
@param alertIcon The AlertIconType to display within the AlertWindow @see AlertWindow::AlertIconType
@see AlertWindow::runModalLoop
*/
static void showUserInfo(const String& title, const String& message, AlertWindow::AlertIconType alertIcon = AlertWindow::InfoIcon)
{
auto alertWindow = make_unique<AlertWindow>(title, message, alertIcon);
alertWindow->addButton(TRANS(L"Verstanden"), 0, KeyPress(KeyPress::returnKey));
const Array<Component*> comp_arr = alertWindow->getChildren();
auto ok = dynamic_cast<TextButton*>(comp_arr[0]);
if (ok)
{
ok->setColour(TextButton::ColourIds::buttonColourId, getDefaultButtonColour());
}
alertWindow->setVisible(true);
#ifdef JUCE_ANDROID
unique_ptr<Component> alertComponent = move(alertWindow);
alertComponent->setAlwaysOnTop(true);
alertComponent->enterModalState(true, ModalCallbackFunction::create([](int) {}), true);
alertComponent.release();
#else
const int i = alertWindow->runModalLoop();
#endif
}
/**
Displays a little confirmation box with a yes and no button.
@param title The title of the msgBox
@param message Show the user a message
@param alertIcon The AlertIconType to display within the AlertWindow @see AlertWindow::AlertIconType
@param async Launch msgBox asynchronously
@param callback Only effective when launched asynchronously. Handle "return" value here.
@return Returns true if user clicked on yes and false if user clicked on no. Returns always true, when launched asynchronously. In this case handle rerturn value through the callback function.
@see AlertWindow::runModalLoop
*/
static bool showUserConfirm(const String& title, const String& message, AlertWindow::AlertIconType alertIcon = AlertWindow::InfoIcon, bool async = false, function<void(bool)> callback = 0)
{
auto alertWindow = make_unique<AlertWindow>(title, message, alertIcon);
alertWindow->addButton(TRANS(L"Ja, fortfahren"), 0, KeyPress(KeyPress::returnKey));
alertWindow->addButton(TRANS(L"Nein, abbrechen"), 1, KeyPress(KeyPress::escapeKey));
const Array<Component*> comp_arr = alertWindow->getChildren();
auto ok = dynamic_cast<TextButton*>(comp_arr[0]);
if (ok)
{
ok->setColour(TextButton::ColourIds::buttonColourId, getDefaultButtonColour());
}
auto cancel = dynamic_cast<TextButton*>(comp_arr[1]);
if (cancel)
{
cancel->setColour(TextButton::ColourIds::buttonColourId, getStandardButtonColour());
}
alertWindow->setVisible(true);
if (!async)
{
#ifdef JUCE_ANDROID
/** Seems like you were trying to use a synchronous Alert under Android.
This is NOT allowed!
*/
jassert(false);
#else
return (alertWindow->runModalLoop() == 0);
#endif
}
else
{
unique_ptr<Component> alertComponent = move(alertWindow);
alertComponent->setAlwaysOnTop(true);
alertComponent->enterModalState(true, ModalCallbackFunction::create([callback](int result) {
if (callback)
{
callback(result == 0);
}
}),
true);
alertComponent.release();
}
return true;
}
/**
Displays a little message box with custom buttons.
@param title The title of the msgBox
@param message Show the user a message
@param options A vector of Strings containing a name for each button you want to add
@param defaultOption Makes the button with this index value the default button. This means, it is highlighted and assigned the returnKey
@param defaultEscapeOption Makes the button with this index value the default cancel button by assigning it the escapeKey
@param alertIcon The AlertIconType to display within the AlertWindow @see AlertWindow::AlertIconType
@return Returns the index of the clicked button: @code
vector<String> options = { L"Ok", L"Not Ok", L"Cancel" };
if (UserInteraction::showUserOptions(L"Is it ok?", L"Long text...", options, 0, 2, AlertWindow::QuestionIcon) == 1)
{
// User clicked Not Ok
(...)
}
@endcode
@see AlertWindow::runModalLoop()
*/
static int showUserOptions(const String& title, const String& message, vector<String> options, const AlertWindow::AlertIconType alertIcon = AlertWindow::InfoIcon, const int defaultOption = 0, const int defaultEscapeOption = -1, bool async = false, function<void(int)> callback = 0)
{
auto alertWindow = make_unique<AlertWindow>(title, message, alertIcon);
for (int i = 0; i < options.size(); ++i)
{
KeyPress kp = KeyPress();
if (i == defaultOption)
{
kp = KeyPress(KeyPress::returnKey);
}
else if (i == defaultEscapeOption)
{
kp = KeyPress(KeyPress::escapeKey);
}
alertWindow->addButton(options.at(i), i, kp);
}
const Array<Component*> comp_arr = alertWindow->getChildren();
for (int i = 0; i < comp_arr.size(); ++i)
{
auto tb = dynamic_cast<TextButton*>(comp_arr[i]);
if (tb)
{
if (i == defaultOption)
{
tb->setColour(TextButton::ColourIds::buttonColourId, getDefaultButtonColour());
}
else
{
tb->setColour(TextButton::ColourIds::buttonColourId, getStandardButtonColour());
}
}
}
alertWindow->setVisible(true);
if (!async)
{
#ifdef JUCE_ANDROID
/** Seems like you were trying to use a synchronous Alert under Android.
This is NOT allowed!
*/
jassert(false);
#else
const int i = alertWindow->runModalLoop();
return i;
#endif
}
else
{
unique_ptr<Component> alertComponent = move(alertWindow);
alertComponent->setAlwaysOnTop(true);
alertComponent->enterModalState(true, ModalCallbackFunction::create([callback](int result) {
callback(result);
}),
true);
alertComponent.release();
}
return -1;
}
/**
Displays a little message box with custom buttons and text fields.
@see UserInteraction::UserInputTextFieldMeta
@param title The title of the msgBox
@param message Show the user a message
@param options A vector of Strings containing a name for each button you want to add
@param options A vector of custom text fields metadata of the custom struct UserInputTextFieldMeta. On return, the user input can be obtained by calling getResult() on the UserInputTextFieldMeta. @see UserInputTextFieldMeta
@param defaultOption Makes the button with this index value the default button. This means, it is highlighted and assigned the returnKey
@param defaultEscapeOption Makes the button with this index value the default cancel button by assigning it the escapeKey
@param alertIcon The AlertIconType to display within the AlertWindow @see AlertWindow::AlertIconType
@return Returns the index of the clicked button: @code
vector<String> options = { L"Ok", L"Not Ok", L"Cancel" };
if (UserInteraction::showUserOptions(L"Is it ok?", L"Long text...", options, 0, 2, AlertWindow::QuestionIcon) == 1)
{
// User clicked Not Ok
(...)
}
@endcode
@see AlertWindow::runModalLoop
*/
static int showUserInput(const String& title, const String& message, vector<String> options, vector<UserInputTextFieldMeta>& userInputTextFields, AlertWindow::AlertIconType alertIcon = AlertWindow::InfoIcon, const int defaultOption = 0, int defaultEscapeOption = -1)
{
auto alertWindow = make_unique<AlertWindow>(title, message, alertIcon);
for (UserInputTextFieldMeta tf : userInputTextFields)
{
alertWindow->addTextEditor(tf.name, tf.initialContents, tf.onScreenLabel, tf.isPasswordBox);
}
for (int i = 0; i < options.size(); ++i)
{
KeyPress kp = KeyPress();
if (i == defaultOption)
{
kp = KeyPress(KeyPress::returnKey);
}
else if (i == defaultEscapeOption)
{
kp = KeyPress(KeyPress::escapeKey);
}
alertWindow->addButton(options.at(i), i, kp);
}
const Array<Component*> comp_arr = alertWindow->getChildren();
for (int i = 0, j = 0; i < comp_arr.size(); ++i)
{
auto tb = dynamic_cast<TextButton*>(comp_arr[i]);
if (tb)
{
if (j == defaultOption)
{
tb->setColour(TextButton::ColourIds::buttonColourId, Colour(static_cast<uint8>(0x00), static_cast<uint8>(0xb0 - 40), static_cast<uint8>(0xb9 - 40), static_cast<uint8>(0xff)));
}
else
{
tb->setColour(TextButton::ColourIds::buttonColourId, getStandardButtonColour());
}
++j;
}
}
alertWindow->setVisible(true);
#ifdef JUCE_ANDROID
/** Seems like you were trying to use a UserInteraction::showUserInput under Android.
This is NOT allowed!
*/
jassert(false);
#else
const int i = alertWindow->runModalLoop();
vector<String> textEditorContents;
for (UserInputTextFieldMeta& tf : userInputTextFields)
{
tf.setResult(alertWindow->getTextEditorContents(tf.name));
}
return i;
#endif
}
};
#endif