diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -46,6 +46,7 @@ #include "network/network_gui.h" #include "network/network_survey.h" #include "video/video_driver.hpp" +#include "social_integration.h" #include "safeguards.h" @@ -170,6 +171,184 @@ static const std::map _vo { 127, STR_GAME_OPTIONS_VOLUME_100 }, }; +static const NWidgetPart _nested_social_plugins_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_FRAME, COLOUR_GREY, WID_GO_SOCIAL_PLUGIN_TITLE), SetDataTip(STR_JUST_STRING2, STR_NULL), + NWidget(NWID_HORIZONTAL), SetPIP(0, WidgetDimensions::unscaled.hsep_normal, 0), + NWidget(WWT_TEXT, COLOUR_GREY), SetMinimalSize(0, 12), SetFill(1, 0), SetDataTip(STR_GAME_OPTIONS_SOCIAL_PLUGIN_PLATFORM, STR_NULL), + NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_SOCIAL_PLUGIN_PLATFORM), SetMinimalSize(100, 12), SetDataTip(STR_JUST_RAW_STRING, STR_NULL), SetAlignment(SA_RIGHT), + EndContainer(), + NWidget(NWID_HORIZONTAL), SetPIP(0, WidgetDimensions::unscaled.hsep_normal, 0), + NWidget(WWT_TEXT, COLOUR_GREY), SetMinimalSize(0, 12), SetFill(1, 0), SetDataTip(STR_GAME_OPTIONS_SOCIAL_PLUGIN_STATE, STR_NULL), + NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_SOCIAL_PLUGIN_STATE), SetMinimalSize(100, 12), SetDataTip(STR_JUST_STRING1, STR_NULL), SetAlignment(SA_RIGHT), + EndContainer(), + EndContainer(), + EndContainer(), +}; + +static const NWidgetPart _nested_social_plugins_none_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_TEXT, COLOUR_GREY), SetMinimalSize(0, 12), SetFill(1, 0), SetDataTip(STR_GAME_OPTIONS_SOCIAL_PLUGINS_NONE, STR_NULL), + EndContainer(), +}; + +class NWidgetSocialPlugins : public NWidgetVertical { +public: + NWidgetSocialPlugins() + { + this->plugins = SocialIntegration::GetPlugins(); + + if (this->plugins.empty()) { + auto widget = MakeNWidgets(std::begin(_nested_social_plugins_none_widgets), std::end(_nested_social_plugins_none_widgets), nullptr); + this->Add(std::move(widget)); + } else { + for (size_t i = 0; i < this->plugins.size(); i++) { + auto widget = MakeNWidgets(std::begin(_nested_social_plugins_widgets), std::end(_nested_social_plugins_widgets), nullptr); + this->Add(std::move(widget)); + } + } + + this->SetPIP(0, WidgetDimensions::unscaled.vsep_wide, 0); + } + + void FillWidgetLookup(WidgetLookup &widget_lookup) override + { + widget_lookup[WID_GO_SOCIAL_PLUGINS] = this; + NWidgetVertical::FillWidgetLookup(widget_lookup); + } + + void SetupSmallestSize(Window *w) override + { + this->current_index = -1; + NWidgetVertical::SetupSmallestSize(w); + } + + /** + * Find of all the plugins the one where the member is the widest (in pixels). + * + * @param member The member to check with. + * @return The plugin that has the widest value (in pixels) for the given member. + */ + template + std::string &GetWidestPlugin(T SocialIntegrationPlugin::*member) const + { + std::string *longest = &(this->plugins[0]->*member); + int longest_length = 0; + + for (auto *plugin : this->plugins) { + int length = GetStringBoundingBox(plugin->*member).width; + if (length > longest_length) { + longest_length = length; + longest = &(plugin->*member); + } + } + + return *longest; + } + + void SetStringParameters(int widget) const + { + switch (widget) { + case WID_GO_SOCIAL_PLUGIN_TITLE: + /* For SetupSmallestSize, use the longest string we have. */ + if (this->current_index < 0) { + SetDParamStr(0, GetWidestPlugin(&SocialIntegrationPlugin::name)); + SetDParamStr(1, GetWidestPlugin(&SocialIntegrationPlugin::version)); + break; + } + + if (this->plugins[this->current_index]->name.empty()) { + SetDParam(0, STR_JUST_RAW_STRING); + SetDParamStr(1, this->plugins[this->current_index]->basepath); + } else { + SetDParam(0, STR_GAME_OPTIONS_SOCIAL_PLUGIN_TITLE); + SetDParamStr(1, this->plugins[this->current_index]->name); + SetDParamStr(2, this->plugins[this->current_index]->version); + } + break; + + case WID_GO_SOCIAL_PLUGIN_PLATFORM: + /* For SetupSmallestSize, use the longest string we have. */ + if (this->current_index < 0) { + SetDParamStr(0, GetWidestPlugin(&SocialIntegrationPlugin::social_platform)); + break; + } + + SetDParamStr(0, this->plugins[this->current_index]->social_platform); + break; + + case WID_GO_SOCIAL_PLUGIN_STATE: { + static const std::pair state_to_string[] = { + { SocialIntegrationPlugin::RUNNING, STR_GAME_OPTIONS_SOCIAL_PLUGIN_STATE_RUNNING }, + { SocialIntegrationPlugin::FAILED, STR_GAME_OPTIONS_SOCIAL_PLUGIN_STATE_FAILED }, + { SocialIntegrationPlugin::PLATFORM_NOT_RUNNING, STR_GAME_OPTIONS_SOCIAL_PLUGIN_STATE_PLATFORM_NOT_RUNNING }, + { SocialIntegrationPlugin::UNLOADED, STR_GAME_OPTIONS_SOCIAL_PLUGIN_STATE_UNLOADED }, + { SocialIntegrationPlugin::DUPLICATE, STR_GAME_OPTIONS_SOCIAL_PLUGIN_STATE_DUPLICATE }, + { SocialIntegrationPlugin::UNSUPPORTED_API, STR_GAME_OPTIONS_SOCIAL_PLUGIN_STATE_UNSUPPORTED_API }, + { SocialIntegrationPlugin::INVALID_SIGNATURE, STR_GAME_OPTIONS_SOCIAL_PLUGIN_STATE_INVALID_SIGNATURE }, + }; + + /* For SetupSmallestSize, use the longest string we have. */ + if (this->current_index < 0) { + auto longest_plugin = GetWidestPlugin(&SocialIntegrationPlugin::social_platform); + + /* Set the longest plugin when looking for the longest status. */ + SetDParamStr(0, longest_plugin); + + StringID longest = STR_NULL; + int longest_length = 0; + for (auto state : state_to_string) { + int length = GetStringBoundingBox(state.second).width; + if (length > longest_length) { + longest_length = length; + longest = state.second; + } + } + + SetDParam(0, longest); + SetDParamStr(1, longest_plugin); + break; + } + + auto plugin = this->plugins[this->current_index]; + + /* Default string, in case no state matches. */ + SetDParam(0, STR_GAME_OPTIONS_SOCIAL_PLUGIN_STATE_FAILED); + SetDParamStr(1, plugin->social_platform); + + /* Find the string for the state. */ + for (auto state : state_to_string) { + if (plugin->state == state.first) { + SetDParam(0, state.second); + break; + } + } + } + break; + } + } + + void Draw(const Window *w) override + { + this->current_index = 0; + + for (auto &wid : this->children) { + wid->Draw(w); + this->current_index++; + } + } + +private: + int current_index = -1; + std::vector plugins; +}; + +/** Construct nested container widget for managing the list of social plugins. */ +std::unique_ptr MakeNWidgetSocialPlugins() +{ + return std::make_unique(); +} + struct GameOptionsWindow : Window { GameSettings *opt; bool reload; @@ -348,6 +527,16 @@ struct GameOptionsWindow : Window { } break; } + + case WID_GO_SOCIAL_PLUGIN_TITLE: + case WID_GO_SOCIAL_PLUGIN_PLATFORM: + case WID_GO_SOCIAL_PLUGIN_STATE: { + const NWidgetSocialPlugins *plugin = this->GetWidget(WID_GO_SOCIAL_PLUGINS); + assert(plugin != nullptr); + + plugin->SetStringParameters(widget); + break; + } } } @@ -390,7 +579,7 @@ struct GameOptionsWindow : Window { void SetTab(WidgetID widget) { - this->SetWidgetsLoweredState(false, WID_GO_TAB_GENERAL, WID_GO_TAB_GRAPHICS, WID_GO_TAB_SOUND); + this->SetWidgetsLoweredState(false, WID_GO_TAB_GENERAL, WID_GO_TAB_GRAPHICS, WID_GO_TAB_SOUND, WID_GO_TAB_SOCIAL); this->LowerWidget(widget); GameOptionsWindow::active_tab = widget; @@ -399,6 +588,7 @@ struct GameOptionsWindow : Window { case WID_GO_TAB_GENERAL: pane = 0; break; case WID_GO_TAB_GRAPHICS: pane = 1; break; case WID_GO_TAB_SOUND: pane = 2; break; + case WID_GO_TAB_SOCIAL: pane = 3; break; default: NOT_REACHED(); } @@ -493,6 +683,7 @@ struct GameOptionsWindow : Window { case WID_GO_TAB_GENERAL: case WID_GO_TAB_GRAPHICS: case WID_GO_TAB_SOUND: + case WID_GO_TAB_SOCIAL: this->SetTab(widget); break; @@ -814,6 +1005,7 @@ static constexpr NWidgetPart _nested_gam NWidget(WWT_TEXTBTN, COLOUR_YELLOW, WID_GO_TAB_GENERAL), SetMinimalTextLines(2, 0), SetDataTip(STR_GAME_OPTIONS_TAB_GENERAL, STR_GAME_OPTIONS_TAB_GENERAL_TT), SetFill(1, 0), NWidget(WWT_TEXTBTN, COLOUR_YELLOW, WID_GO_TAB_GRAPHICS), SetMinimalTextLines(2, 0), SetDataTip(STR_GAME_OPTIONS_TAB_GRAPHICS, STR_GAME_OPTIONS_TAB_GRAPHICS_TT), SetFill(1, 0), NWidget(WWT_TEXTBTN, COLOUR_YELLOW, WID_GO_TAB_SOUND), SetMinimalTextLines(2, 0), SetDataTip(STR_GAME_OPTIONS_TAB_SOUND, STR_GAME_OPTIONS_TAB_SOUND_TT), SetFill(1, 0), + NWidget(WWT_TEXTBTN, COLOUR_YELLOW, WID_GO_TAB_SOCIAL), SetMinimalTextLines(2, 0), SetDataTip(STR_GAME_OPTIONS_TAB_SOCIAL, STR_GAME_OPTIONS_TAB_SOCIAL_TT), SetFill(1, 0), EndContainer(), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY), @@ -969,6 +1161,11 @@ static constexpr NWidgetPart _nested_gam EndContainer(), EndContainer(), EndContainer(), + + /* Social tab */ + NWidget(NWID_VERTICAL), SetPadding(WidgetDimensions::unscaled.sparse), SetPIP(0, WidgetDimensions::unscaled.vsep_wide, 0), + NWidgetFunction(MakeNWidgetSocialPlugins), + EndContainer(), EndContainer(), EndContainer(), };