From c5521ad9a3e0dc3fbcc88cc03a961ead07d1f9c7 Mon Sep 17 00:00:00 2001 From: Jaidyn Ann Date: Sun, 11 Jul 2021 15:22:49 -0500 Subject: [PATCH] (purple) RequestAction dialogs First progress in support for purple's Request dialogs --- protocols/purple/PurpleApp.cpp | 101 +++++++++++++++++++++++++++- protocols/purple/PurpleApp.h | 53 ++++++++++++++- protocols/purple/PurpleDialog.cpp | 106 ++++++++++++++++++++++++++++++ protocols/purple/PurpleDialog.h | 47 +++++++++++++ 4 files changed, 303 insertions(+), 4 deletions(-) create mode 100644 protocols/purple/PurpleDialog.cpp create mode 100644 protocols/purple/PurpleDialog.h diff --git a/protocols/purple/PurpleApp.cpp b/protocols/purple/PurpleApp.cpp index ad5e4e7..fc5a9a3 100644 --- a/protocols/purple/PurpleApp.cpp +++ b/protocols/purple/PurpleApp.cpp @@ -23,7 +23,6 @@ #include #include -#include #include #include @@ -36,6 +35,7 @@ #include #include "Purple.h" +#include "PurpleDialog.h" #include "PurpleMessages.h" @@ -900,10 +900,27 @@ static PurpleEventLoopUiOps _ui_op_eventloops = }; +static PurpleRequestUiOps _ui_op_request = +{ + ui_op_request_input, + ui_op_request_choice, + ui_op_request_action, + ui_op_request_fields, + ui_op_request_file, + NULL, + ui_op_request_folder, + ui_op_request_action_with_icon, + NULL, + NULL, + NULL +}; + + void init_ui_ops() { purple_eventloop_set_ui_ops(&_ui_op_eventloops); + purple_request_set_ui_ops(&_ui_op_request); } @@ -1176,6 +1193,88 @@ ui_op_input_add(gint fd, PurpleInputCondition condition, } +static void* +ui_op_request_input(const char* title, const char* primary, + const char* secondary, const char* default_value, gboolean multiline, + gboolean masked, gchar* hint, const char* ok_text, GCallback ok_cb, + const char* cancel_text, GCallback cancel_cb, PurpleAccount* account, + const char* who, PurpleConversation* conv, void* user_data) +{ + std::cerr << "request input: " << title << std::endl; + return NULL; +} + + +static void* +ui_op_request_choice(const char* title, const char* primary, + const char* secondary, int default_value, const char* ok_text, + GCallback ok_cb, const char* cancel_text, GCallback cancel_cb, + PurpleAccount* account, const char* who, PurpleConversation* conv, + void* user_data, va_list choices) +{ + std::cerr << "request choice: " << title << std::endl; + return NULL; +} + + +static void* +ui_op_request_action(const char* title, const char* primary, + const char* secondary, int default_action, PurpleAccount* account, + const char* who, PurpleConversation* conv, void* user_data, + size_t action_count, va_list actions) +{ + PurpleDialog* win = + new PurpleDialog(title, primary, secondary, account, actions, + action_count, user_data); + win->Show(); + return NULL; +} + + +static void* +ui_op_request_fields(const char* title, const char* primary, + const char* secondary, PurpleRequestFields* fields, const char* ok_text, + GCallback ok_cb, const char* cancel_text, GCallback cancel_cb, + PurpleAccount* account, const char* who, PurpleConversation* conv, + void* user_data) +{ + std::cerr << "request fields from " << purple_account_get_username(account) + << ": " << primary << std::endl; + return NULL; +} + + +static void* +ui_op_request_file(const char* title, const char* filename, gboolean savedialog, + GCallback ok_cb, GCallback cancel_cb, PurpleAccount* account, + const char* who, PurpleConversation* conv, void* user_data) +{ + std::cerr << "request file: " << title << std::endl; + return NULL; +} + + +static void* +ui_op_request_folder(const char* title, const char* dirname, GCallback ok_cb, + GCallback cancel_cb, PurpleAccount* account, const char* who, + PurpleConversation* conv, void* user_data) +{ + std::cerr << "request folder: " << title << std::endl; + return NULL; +} + + +static void* +ui_op_request_action_with_icon(const char* title, const char* primary, + const char* secondary, int default_action, PurpleAccount* account, + const char* who, PurpleConversation* conv, gconstpointer icon_data, + gsize icon_size, void* user_data, size_t action_count, va_list actions) +{ + std::cerr << "request action with icon: " << title << std::endl; + return NULL; +} + + bool is_own_user(PurpleAccount* account, const char* name) { diff --git a/protocols/purple/PurpleApp.h b/protocols/purple/PurpleApp.h index 4d2746d..a1a30e8 100644 --- a/protocols/purple/PurpleApp.h +++ b/protocols/purple/PurpleApp.h @@ -141,18 +141,65 @@ private: static void signal_chat_buddy_joined(PurpleConversation* conv, const char* name, PurpleConvChatBuddyFlags flags, gboolean new_arrival); - static void signal_chat_invited(PurpleAccount* account, + static void signal_chat_invited(PurpleAccount* account, const char* inviter, const char* chat, const char* message, const GHashTable* components); - static void signal_chat_buddy_flags(PurpleConversation* conv, + static void signal_chat_buddy_flags(PurpleConversation* conv, const char* name, PurpleConvChatBuddyFlags oldflags, PurpleConvChatBuddyFlags newflags); // EventLoop ui ops - static guint ui_op_input_add(gint fd, + static guint ui_op_input_add(gint fd, PurpleInputCondition condition, PurpleInputFunction function, gpointer data); +// Request ui ops + static void* ui_op_request_input(const char* title, + const char* primary, const char* secondary, + const char* default_value, gboolean multiline, + gboolean masked, gchar* hint, const char* ok_text, + GCallback ok_cb, const char* cancel_text, + GCallback cancel_cb, PurpleAccount* account, + const char* who, PurpleConversation* conv, + void* user_data); + static void* ui_op_request_choice(const char* title, + const char* primary, const char* secondary, + int default_value, const char* ok_text, + GCallback ok_cb, const char* cancel_text, + GCallback cancel_cb, PurpleAccount* account, + const char* who, PurpleConversation* conv, + void* user_data, va_list choices); + static void* ui_op_request_action(const char* title, + const char* primary, const char* secondary, + int default_action, PurpleAccount* account, + const char* who, PurpleConversation* conv, + void* user_data, size_t action_count, + va_list actions); + static void* ui_op_request_fields(const char* title, + const char* primary, const char* secondary, + PurpleRequestFields* fields, const char* ok_text, + GCallback ok_cb, const char* cancel_text, + GCallback cancel_cb, PurpleAccount* account, + const char* who, PurpleConversation* conv, + void* user_data); + static void* ui_op_request_file(const char* title, + const char* filename, gboolean savedialog, + GCallback ok_cb, GCallback cancel_cb, + PurpleAccount* account, const char* who, + PurpleConversation* conv, void* user_data); + static void* ui_op_request_folder(const char* title, + const char* dirname, GCallback ok_cb, + GCallback cancel_cb, PurpleAccount* account, + const char* who, PurpleConversation* conv, + void* user_data); + static void* ui_op_request_action_with_icon(const char* title, + const char* primary, const char* secondary, + int default_action, PurpleAccount* account, + const char* who, PurpleConversation* conv, + gconstpointer icon_data, gsize icon_size, + void* user_data, size_t action_count, + va_list actions); + // Util bool is_own_user(PurpleAccount* account, const char* name); diff --git a/protocols/purple/PurpleDialog.cpp b/protocols/purple/PurpleDialog.cpp new file mode 100644 index 0000000..66fff84 --- /dev/null +++ b/protocols/purple/PurpleDialog.cpp @@ -0,0 +1,106 @@ +/* + * Copyright 2021, Jaidyn Levesque + * All rights reserved. Distributed under the terms of the MIT license. + */ + +#include "PurpleDialog.h" + +#include + +#include +#include +#include +#include + + +PurpleDialog::PurpleDialog(const char* title, const char* primary, + const char* secondary, PurpleAccount* account, va_list actions, + size_t action_count, void* user_data) + : + BWindow(BRect(BPoint(-1000, -1000), BSize(300, 250)),title, + B_FLOATING_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL, + B_AUTO_UPDATE_SIZE_LIMITS), + fUserData(user_data) +{ + CenterOnScreen(); + _ParseActions(actions, action_count, PURPLE_REQUEST_ACTION); + _InitActionInterface(primary, secondary); +} + + +void +PurpleDialog::MessageReceived(BMessage* msg) +{ + switch (msg->what) + { + case ACTION_BUTTON: + { + int32 id; + if (msg->FindInt32("index", &id) != B_OK) break; + + PurpleRequestActionCb cb = fActions.ItemAt(0)->callback.action; + cb(fUserData, fActions.ItemAt(0)->index); + Quit(); + break; + } + default: + BWindow::MessageReceived(msg); + } +} + + +void +PurpleDialog::_InitActionInterface(const char* label, const char* desc) +{ + BStringView* primaryLabel = new BStringView("primaryText", label); + primaryLabel->SetExplicitAlignment( + BAlignment(B_ALIGN_CENTER, B_ALIGN_TOP)); + + BTextView* secondaryLabel = new BTextView("secondaryText"); + secondaryLabel->SetViewUIColor(B_PANEL_BACKGROUND_COLOR); + secondaryLabel->MakeEditable(false); + secondaryLabel->SetWordWrap(true); + secondaryLabel->SetText(desc); + + // Init buttons view + BView* buttonsView = new BView("actionButtons", 0); + BLayoutBuilder::Group<>(buttonsView, B_HORIZONTAL); + for (int i = 0; i < fActions.CountItems(); i++) { + RequestAction* action = fActions.ItemAt(i); + BMessage* msg = new BMessage(ACTION_BUTTON); + msg->AddInt32("index", action->index); + + BButton* button = new BButton(action->name.String(), msg); + buttonsView->AddChild(button); + } + + // Main layout + BLayoutBuilder::Group<>(this, B_VERTICAL) + .SetInsets(B_USE_DEFAULT_SPACING) + .Add(primaryLabel) + .Add(secondaryLabel) + .Add(buttonsView) + .AddGlue() + .End(); +} + + +void +PurpleDialog::_ParseActions(va_list actions, int32 count, + PurpleRequestType type) +{ + for (int i = 0; i < count; i++) { + RequestAction* action = new RequestAction; + action->name = va_arg(actions, const char*); + action->index = i; + action->type = type; + + switch (type) { + case PURPLE_REQUEST_ACTION: + action->callback.action = va_arg(actions, PurpleRequestActionCb); + break; + } + fActions.AddItem(action); + } + +} diff --git a/protocols/purple/PurpleDialog.h b/protocols/purple/PurpleDialog.h new file mode 100644 index 0000000..352d946 --- /dev/null +++ b/protocols/purple/PurpleDialog.h @@ -0,0 +1,47 @@ +/* + * Copyright 2021, Jaidyn Levesque + * All rights reserved. Distributed under the terms of the MIT license. + */ +#ifndef _PURPLE_DIALOG_H +#define _PURPLE_DIALOG_H + +#include + +#include +#include + + +const uint32 ACTION_BUTTON = 'PDab'; + + +struct RequestAction +{ + BString name; + PurpleRequestType type; + int32 index; + + union { + PurpleRequestActionCb action; + } callback; +}; + + +class PurpleDialog : public BWindow { +public: + // PURPLE_REQUEST_ACTION + PurpleDialog(const char* title, const char* primary, + const char* secondary, PurpleAccount* account, + va_list actions, size_t action_count, void* user_data); + + virtual void MessageReceived(BMessage* msg); + +private: + void _InitActionInterface(const char* label, const char* desc); + void _ParseActions(va_list actions, int32 count, + PurpleRequestType type); + + BObjectList fActions; + void* fUserData; +}; + +#endif // _PURPLE_DIALOG_H